From: Ken Raeburn Date: Sat, 3 Oct 2015 04:18:50 +0000 (-0400) Subject: Reduce color allocation/query traffic in the TrueColor case. X-Git-Tag: emacs-25.0.90~1198 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=e23ed19ff933c35111f3a806b4104fee8ef42f55;p=emacs.git Reduce color allocation/query traffic in the TrueColor case. When working with an X visual with TrueColor class, pixel values can be generated from the RGB values according to mask value provided by the server on connection. Some of the image-handling code was already doing this. * src/xterm.h (x_make_truecolor_pixel): New function; code taken from lookup_rgb_color. (x_mutable_colormap): New function. * src/image.c (lookup_rgb_color): Move pixel composition code to x_make_truecolor_pixel. (x_kill_gs_process): Call x_mutable_colormap. * src/xfaces.c (x_free_colors, x_free_dpy_colors): Call x_mutable_colormap. * src/xftfont.c (xftfont_get_colors): Call x_query_colors. * src/xterm.c (x_query_colors): For a TrueColor display, decompose the pixel value into RGB values directly, and don't send a request to the server. (x_alloc_nearest_color): For a TrueColor display, construct the pixel value with x_make_truecolor_pixel. (x_copy_color): For an immutable color map, just return the provided pixel value. --- diff --git a/src/image.c b/src/image.c index 79bf21e8865..401689e940a 100644 --- a/src/image.c +++ b/src/image.c @@ -4442,15 +4442,7 @@ lookup_rgb_color (struct frame *f, int r, int g, int b) r = color.red, g = color.green, b = color.blue; } - /* Scale down RGB values to the visual's bits per RGB, and shift - them to the right position in the pixel color. Note that the - original RGB values are 16-bit values, as usual in X. */ - pr = (r >> (16 - dpyinfo->red_bits)) << dpyinfo->red_offset; - pg = (g >> (16 - dpyinfo->green_bits)) << dpyinfo->green_offset; - pb = (b >> (16 - dpyinfo->blue_bits)) << dpyinfo->blue_offset; - - /* Assemble the pixel color. */ - return pr | pg | pb; + return x_make_truecolor_pixel (dpyinfo, r, g, b); } for (p = ct_table[i]; p; p = p->next) @@ -9542,7 +9534,6 @@ void x_kill_gs_process (Pixmap pixmap, struct frame *f) { struct image_cache *c = FRAME_IMAGE_CACHE (f); - int class; ptrdiff_t i; struct image *img; @@ -9568,8 +9559,7 @@ x_kill_gs_process (Pixmap pixmap, struct frame *f) /* On displays with a mutable colormap, figure out the colors allocated for the image by looking at the pixels of an XImage for img->pixmap. */ - class = FRAME_X_VISUAL (f)->class; - if (class != StaticColor && class != StaticGray && class != TrueColor) + if (x_mutable_colormap (FRAME_X_VISUAL (f))) { XImagePtr ximg; diff --git a/src/xfaces.c b/src/xfaces.c index 8cf0b427799..a3d122fbf46 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -454,11 +454,9 @@ DEFUN ("dump-colors", Fdump_colors, Sdump_colors, 0, 0, 0, void x_free_colors (struct frame *f, unsigned long *pixels, int npixels) { - int class = FRAME_DISPLAY_INFO (f)->visual->class; - /* If display has an immutable color map, freeing colors is not necessary and some servers don't allow it. So don't do it. */ - if (class != StaticColor && class != StaticGray && class != TrueColor) + if (x_mutable_colormap (FRAME_X_VISUAL (f))) { #ifdef DEBUG_X_COLORS unregister_colors (pixels, npixels); @@ -471,7 +469,7 @@ x_free_colors (struct frame *f, unsigned long *pixels, int npixels) #ifdef USE_X_TOOLKIT -/* Free colors used on frame F. PIXELS is an array of NPIXELS pixel +/* Free colors used on display DPY. PIXELS is an array of NPIXELS pixel color values. Interrupt input must be blocked when this function is called. */ @@ -480,11 +478,10 @@ x_free_dpy_colors (Display *dpy, Screen *screen, Colormap cmap, unsigned long *pixels, int npixels) { struct x_display_info *dpyinfo = x_display_info_for_display (dpy); - int class = dpyinfo->visual->class; /* If display has an immutable color map, freeing colors is not necessary and some servers don't allow it. So don't do it. */ - if (class != StaticColor && class != StaticGray && class != TrueColor) + if (x_mutable_colormap (dpyinfo->visual)) { #ifdef DEBUG_X_COLORS unregister_colors (pixels, npixels); diff --git a/src/xftfont.c b/src/xftfont.c index a1846e8d461..851edb69fa0 100644 --- a/src/xftfont.c +++ b/src/xftfont.c @@ -111,8 +111,7 @@ xftfont_get_colors (struct frame *f, struct face *face, GC gc, colors[0].pixel = fg->pixel = xgcv.foreground; if (bg) colors[1].pixel = bg->pixel = xgcv.background; - XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, - bg ? 2 : 1); + x_query_colors (f, colors, bg ? 2 : 1); fg->color.alpha = 0xFFFF; fg->color.red = colors[0].red; fg->color.green = colors[0].green; diff --git a/src/xterm.c b/src/xterm.c index 6065f964063..8be893eca6f 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -2197,6 +2197,50 @@ x_query_colors (struct frame *f, XColor *colors, int ncolors) { struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); + if (dpyinfo->red_bits > 0) + { + /* For TrueColor displays, we can decompose the RGB value + directly. */ + int i; + unsigned int rmult, gmult, bmult; + unsigned int rmask, gmask, bmask; + + rmask = (1 << dpyinfo->red_bits) - 1; + gmask = (1 << dpyinfo->green_bits) - 1; + bmask = (1 << dpyinfo->blue_bits) - 1; + /* If we're widening, for example, 8 bits in the pixel value to + 16 bits for the separate-color representation, we want to + extrapolate the lower bits based on those bits available -- + in other words, we'd like 0xff to become 0xffff instead of + the 0xff00 we'd get by just zero-filling the lower bits. + + We generate a 32-bit scaled-up value and shift it, in case + the bit count doesn't divide 16 evently (e.g., when dealing + with a 3-3-2 bit RGB display), to get more of the lower bits + correct. + + Should we cache the multipliers in dpyinfo? Maybe + special-case the 8-8-8 common case? */ + rmult = 0xffffffff / rmask; + gmult = 0xffffffff / gmask; + bmult = 0xffffffff / bmask; + + for (i = 0; i < ncolors; ++i) + { + unsigned int r, g, b; + unsigned long pixel = colors[i].pixel; + + r = (pixel >> dpyinfo->red_offset) & rmask; + g = (pixel >> dpyinfo->green_offset) & gmask; + b = (pixel >> dpyinfo->blue_offset) & bmask; + + colors[i].red = (r * rmult) >> 16; + colors[i].green = (g * gmult) >> 16; + colors[i].blue = (b * bmult) >> 16; + } + return; + } + if (dpyinfo->color_cells) { int i; @@ -2207,9 +2251,10 @@ x_query_colors (struct frame *f, XColor *colors, int ncolors) eassert (dpyinfo->color_cells[pixel].pixel == pixel); colors[i] = dpyinfo->color_cells[pixel]; } + return; } - else - XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors); + + XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors); } @@ -2341,15 +2386,27 @@ x_alloc_nearest_color_1 (Display *dpy, Colormap cmap, XColor *color) } -/* Allocate the color COLOR->pixel on frame F, colormap CMAP. If an - exact match can't be allocated, try the nearest color available. - Value is true if successful. Set *COLOR to the color - allocated. */ +/* Allocate the color COLOR->pixel on frame F, colormap CMAP, after + gamma correction. If an exact match can't be allocated, try the + nearest color available. Value is true if successful. Set *COLOR + to the color allocated. */ bool x_alloc_nearest_color (struct frame *f, Colormap cmap, XColor *color) { + struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); + gamma_correct (f, color); + + if (dpyinfo->red_bits > 0) + { + color->pixel = x_make_truecolor_pixel (dpyinfo, + color->red, + color->green, + color->blue); + return true; + } + return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color); } @@ -2363,8 +2420,16 @@ x_copy_color (struct frame *f, unsigned long pixel) { XColor color; + /* If display has an immutable color map, freeing colors is not + necessary and some servers don't allow it. Since we won't free a + color once we've allocated it, we don't need to re-allocate it to + maintain the server's reference count. */ + if (!x_mutable_colormap (FRAME_X_VISUAL (f))) + return pixel; + color.pixel = pixel; block_input (); + /* The color could still be found in the color_cells array. */ x_query_color (f, &color); XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color); unblock_input (); diff --git a/src/xterm.h b/src/xterm.h index 300a8b769f2..d8edbc208f4 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -1085,6 +1085,33 @@ x_display_set_last_user_time (struct x_display_info *dpyinfo, Time t) dpyinfo->last_user_time = t; } +INLINE unsigned long +x_make_truecolor_pixel (struct x_display_info *dpyinfo, int r, int g, int b) +{ + unsigned long pr, pg, pb; + + /* Scale down RGB values to the visual's bits per RGB, and shift + them to the right position in the pixel color. Note that the + original RGB values are 16-bit values, as usual in X. */ + pr = (r >> (16 - dpyinfo->red_bits)) << dpyinfo->red_offset; + pg = (g >> (16 - dpyinfo->green_bits)) << dpyinfo->green_offset; + pb = (b >> (16 - dpyinfo->blue_bits)) << dpyinfo->blue_offset; + + /* Assemble the pixel color. */ + return pr | pg | pb; +} + +/* If display has an immutable color map, freeing colors is not + necessary and some servers don't allow it, so we won't do it. That + also allows us to make other optimizations relating to server-side + reference counts. */ +INLINE bool +x_mutable_colormap (Visual *visual) +{ + int class = visual->class; + return (class != StaticColor && class != StaticGray && class != TrueColor); +} + extern void x_set_sticky (struct frame *, Lisp_Object, Lisp_Object); extern bool x_wm_supports (struct frame *, Atom); extern void x_wait_for_event (struct frame *, int);