mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-05-09 05:32:11 -05:00
GTK: faster rendering of X fonts under Cairo
Switching to server-side rendering of X fonts under Cairo turned out to make text rendering much slower, at least on my laptop. This appears to be because PuTTY was asking the X server to render text into a 1-bit-per-pixel (bpp) pixmap before having Cairo composite into the terminal surface. On modern X servers 1bpp pixmaps are slow, being largely un-accelerated. Happily, it is possible to get Cairo to use an 8bpp pixmap instead, and this is rather faster. It's a bit inconvenient, though, because first we have to confirm that that the X Rendering Extensions is present and find the correct picture format. That requires linking in libXrender, which means a bit of CMake faff. For now, I've make libXrender mandatory (for X11 builds), but it and the corresponding Cairo functions could be made optional fairly simply. This hasn't actually made text rendering as much faster as I'd like on my laptop. While creating 1bpp pixmaps is nearly free, creating 8bpp pixmaps takes significant time because they actually involve the GPU. So I think now I need to rework my persistent-pixmap patch to work on top of this one.
This commit is contained in:
parent
a0a92da035
commit
19353dca85
@ -89,7 +89,7 @@ if(GTK_FOUND)
|
||||
list(APPEND CMAKE_REQUIRED_INCLUDES ${GTK_INCLUDE_DIRS})
|
||||
check_include_file(gdk/gdkx.h HAVE_GDK_GDKX_H)
|
||||
|
||||
if(X11_FOUND AND HAVE_GDK_GDKX_H)
|
||||
if(X11_FOUND AND X11_Xrender_FOUND AND HAVE_GDK_GDKX_H)
|
||||
set(NOT_X_WINDOWS OFF PARENT_SCOPE)
|
||||
else()
|
||||
set(NOT_X_WINDOWS ON PARENT_SCOPE)
|
||||
|
@ -153,7 +153,7 @@ if(GTK_FOUND)
|
||||
be_list(pterm pterm)
|
||||
target_link_libraries(pterm
|
||||
guiterminal eventloop settings utils ptermxpms
|
||||
${GTK_LIBRARIES} ${X11_LIBRARIES})
|
||||
${GTK_LIBRARIES} ${X11_LIBRARIES} ${X11_Xrender_LIB})
|
||||
installed_program(pterm)
|
||||
|
||||
if(GTK_VERSION GREATER_EQUAL 3)
|
||||
@ -170,7 +170,7 @@ if(GTK_FOUND)
|
||||
be_list(ptermapp pterm)
|
||||
target_link_libraries(ptermapp
|
||||
guiterminal eventloop settings utils ptermxpms
|
||||
${GTK_LIBRARIES} ${X11_LIBRARIES})
|
||||
${GTK_LIBRARIES} ${X11_LIBRARIES} ${X11_Xrender_LIB})
|
||||
endif()
|
||||
|
||||
add_executable(putty
|
||||
@ -181,7 +181,7 @@ if(GTK_FOUND)
|
||||
target_link_libraries(putty
|
||||
guiterminal eventloop sshclient otherbackends settings
|
||||
network crypto utils puttyxpms
|
||||
${GTK_LIBRARIES} ${X11_LIBRARIES})
|
||||
${GTK_LIBRARIES} ${X11_LIBRARIES} ${X11_Xrender_LIB})
|
||||
set_target_properties(putty
|
||||
PROPERTIES LINK_INTERFACE_MULTIPLICITY 2)
|
||||
installed_program(putty)
|
||||
@ -196,7 +196,7 @@ if(GTK_FOUND)
|
||||
target_link_libraries(puttyapp
|
||||
guiterminal eventloop sshclient otherbackends settings
|
||||
network crypto utils puttyxpms
|
||||
${GTK_LIBRARIES} ${X11_LIBRARIES})
|
||||
${GTK_LIBRARIES} ${X11_LIBRARIES} ${X11_Xrender_LIB})
|
||||
endif()
|
||||
|
||||
add_executable(puttytel
|
||||
@ -213,7 +213,7 @@ if(GTK_FOUND)
|
||||
target_link_libraries(puttytel
|
||||
guiterminal eventloop otherbackends settings network utils
|
||||
puttyxpms
|
||||
${GTK_LIBRARIES} ${X11_LIBRARIES})
|
||||
${GTK_LIBRARIES} ${X11_LIBRARIES} ${X11_Xrender_LIB})
|
||||
|
||||
add_executable(test_lineedit
|
||||
${CMAKE_SOURCE_DIR}/test/test_lineedit.c
|
||||
|
@ -29,6 +29,8 @@
|
||||
#ifndef NOT_X_WINDOWS
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
#include <cairo-xlib.h>
|
||||
#include <cairo-xlib-xrender.h>
|
||||
#include <X11/extensions/Xrender.h>
|
||||
#endif
|
||||
#include <gdk/gdkx.h>
|
||||
#include <X11/Xlib.h>
|
||||
@ -154,6 +156,7 @@ typedef struct x11font_individual {
|
||||
bool allocated;
|
||||
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
XRenderPictFormat *pictformat;
|
||||
GC gc;
|
||||
#endif
|
||||
|
||||
@ -607,7 +610,26 @@ static void x11font_gdk_draw(unifont_drawctx *ctx, x11font_individual *xfi,
|
||||
static void x11font_cairo_setup(
|
||||
unifont_drawctx *ctx, x11font_individual *xfi, Display *disp)
|
||||
{
|
||||
|
||||
/*
|
||||
* To render X fonts under Cairo, we use the usual X font rendering
|
||||
* requests to draw text into a pixmap, make a Cairo surface out
|
||||
* of it, and then use that as a mask to paint the current colour
|
||||
* into the terminal surface. This means that colours are
|
||||
* entirely in the hands of Cairo and we don't have to think about
|
||||
* X colourmaps. But we do need to be able to create that pixmap.
|
||||
*
|
||||
* All X servers are required to support 1bpp pixmaps, and Cairo
|
||||
* can always use one of them as a mask. But on 2025's X servers,
|
||||
* 1bpp font rendering is unaccelerated and hence much slower than
|
||||
* on deeper drawables. So we find out if we can make an 8-bit
|
||||
* alpha-only surface, and only fall back to a 1bpp pixmap if that
|
||||
* fails.
|
||||
*
|
||||
* XRenderFindStandardFormat() will return NULL if the X Rendering
|
||||
* Extension is missing or unusable, so we don't need to check
|
||||
* that in advance.
|
||||
*/
|
||||
xfi->pictformat = XRenderFindStandardFormat(disp, PictStandardA8);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -621,7 +643,7 @@ static void x11font_cairo_init_gc(x11font_individual *xfi, Display *disp,
|
||||
if (xfi->gc == None) {
|
||||
XGCValues gcvals = {
|
||||
.function = GXclear,
|
||||
.foreground = 1,
|
||||
.foreground = 0xffffffff,
|
||||
.background = 0,
|
||||
.font = xfi->xfs->fid,
|
||||
};
|
||||
@ -646,17 +668,27 @@ static void x11font_cairo_draw(
|
||||
&direction, &font_ascent, &font_descent, &bounds);
|
||||
pixwidth = bounds.rbearing - bounds.lbearing;
|
||||
pixheight = bounds.ascent + bounds.descent;
|
||||
if (pixwidth > 0 && pixheight > 0) {
|
||||
pixmap = XCreatePixmap(disp, GDK_DRAWABLE_XID(widgetwin),
|
||||
pixwidth, pixheight, 1);
|
||||
if (pixwidth > 0 && pixheight > 0) {
|
||||
cairo_surface_t *surface;
|
||||
if (xfi->pictformat != NULL) {
|
||||
pixmap = XCreatePixmap(disp, GDK_DRAWABLE_XID(widgetwin),
|
||||
pixwidth, pixheight, 8);
|
||||
surface = cairo_xlib_surface_create_with_xrender_format(
|
||||
disp, pixmap, ScreenOfDisplay(disp, widgetscr),
|
||||
xfi->pictformat, pixwidth, pixheight);
|
||||
} else {
|
||||
pixmap = XCreatePixmap(disp, GDK_DRAWABLE_XID(widgetwin),
|
||||
pixwidth, pixheight, 1);
|
||||
surface = cairo_xlib_surface_create_for_bitmap(
|
||||
disp, pixmap, ScreenOfDisplay(disp, widgetscr),
|
||||
pixwidth, pixheight);
|
||||
}
|
||||
x11font_cairo_init_gc(xfi, disp, pixmap);
|
||||
XFillRectangle(disp, pixmap, xfi->gc, 0, 0, pixwidth, pixheight);
|
||||
XDrawImageString16(disp, pixmap, xfi->gc,
|
||||
-bounds.lbearing, bounds.ascent,
|
||||
string+start, length);
|
||||
cairo_surface_t *surface = cairo_xlib_surface_create_for_bitmap(
|
||||
disp, pixmap, ScreenOfDisplay(disp, widgetscr),
|
||||
pixwidth, pixheight);
|
||||
cairo_surface_mark_dirty(surface);
|
||||
cairo_pattern_t *pattern = cairo_pattern_create_for_surface(surface);
|
||||
/* We really don't want bilinear interpolation of bitmap fonts. */
|
||||
cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST);
|
||||
|
Loading…
x
Reference in New Issue
Block a user