From 3bf19ed84024bf7005e3fe6639d3394405df4867 Mon Sep 17 00:00:00 2001 From: Aleksey Lim Date: Thu, 19 Feb 2009 06:34:10 +0000 Subject: Support 24/32 screen depths in color picker; optimization --- diff --git a/colors.py b/colors.py index 1823620..9d27853 100755 --- a/colors.py +++ b/colors.py @@ -1833,12 +1833,12 @@ class Colors(activity.Activity, ExportedGObject): canvasimage = gtk.gdk.Image(gtk.gdk.IMAGE_FASTEST, gtk.gdk.visual_get_system(), 1200, 800) start = time.time() for i in range(0,100): - canvas.blit_2x(canvasimage, 0, 0, 600, 400) + canvas.blit_2x(canvasimage, 0, 0, 0, 0, 600, 400, False) log.debug("Canvas 2.0x blit benchmark: %f sec", time.time()-start) # Benchmark a Palette object. palette = Palette(500) - paletteimage = gtk.gdk.Image(gtk.gdk.IMAGE_FASTEST, gtk.gdk.visual_get_system(), 500, 500) + paletteimage = gtk.gdk.Image(gtk.gdk.IMAGE_FASTEST, gtk.gdk.visual_get_system(), BrushControlsPanel.PALETTE_SIZE, BrushControlsPanel.PALETTE_SIZE) start = time.time() for i in range(0,100): palette.render_wheel(paletteimage) diff --git a/colorsc/Makefile b/colorsc/Makefile index 87bfff0..eefc014 100644 --- a/colorsc/Makefile +++ b/colorsc/Makefile @@ -2,7 +2,7 @@ CXXFLAGS = $(shell pkg-config --cflags gdk-x11-2.0) \ $(shell pkg-config --cflags gstreamer-0.10) \ $(shell pkg-config --cflags pygtk-2.0) \ $(shell python-config --cflags) \ - -fPIC + -fPIC -O2 LDFLAGS = $(shell pkg-config --libs gdk-x11-2.0) \ $(shell pkg-config --libs gstreamer-0.10) \ $(shell pkg-config --libs pygtk-2.0) \ diff --git a/colorsc/canvas.h b/colorsc/canvas.h index 6877758..7951d65 100644 --- a/colorsc/canvas.h +++ b/colorsc/canvas.h @@ -1042,9 +1042,6 @@ public: // Draws a region of the canvas into a GdkImage for display on the screen, with optional scaling // and darkening. - typedef guint16 depth16_t; - typedef guint32 depth24_t; - inline void to_pixel(guint src, depth16_t *dst) { @@ -1060,18 +1057,70 @@ public: *dst = src & 0xffffff; } - template inline - void fill_pixel(pixel_t **rows, int scale, pixel_t value) + struct scale1_t { - for (int y = scale; y--;) - for (int x = scale; x--;) - *rows[y]++ = value; - } + static const int value = 1; + + template inline static + void fill_pixel(pixel_t **rows, pixel_t value) + { + *rows[0]++ = value; + } + }; + + struct scale2_t + { + static const int value = 2; + + template inline static + void fill_pixel(pixel_t **rows, pixel_t value) + { + *rows[0]++ = value; *rows[0]++ = value; + + *rows[1]++ = value; *rows[1]++ = value; + } + }; + + struct scale4_t + { + static const int value = 4; - template + template inline static + void fill_pixel(pixel_t **rows, pixel_t value) + { + *rows[0]++ = value; *rows[0]++ = value; + *rows[0]++ = value; *rows[0]++ = value; + + *rows[1]++ = value; *rows[1]++ = value; + *rows[1]++ = value; *rows[1]++ = value; + } + }; + + struct scale8_t + { + static const int value = 8; + + template inline static + void fill_pixel(pixel_t **rows, pixel_t value) + { + *rows[0]++ = value; *rows[0]++ = value; + *rows[0]++ = value; *rows[0]++ = value; + *rows[0]++ = value; *rows[0]++ = value; + *rows[0]++ = value; *rows[0]++ = value; + + *rows[1]++ = value; *rows[1]++ = value; + *rows[1]++ = value; *rows[1]++ = value; + *rows[1]++ = value; *rows[1]++ = value; + *rows[1]++ = value; *rows[1]++ = value; + } + }; + + template inline void blit(GdkImage *img, int src_x, int src_y, int dest_x, - int dest_y, int dest_w, int dest_h, bool overlay, int scale) + int dest_y, int dest_w, int dest_h, bool overlay) { + if (scale_t::value != 2) return; + int scale = 2; pixel_t *pixels = (pixel_t*)img->mem; int pitch = img->bpl/sizeof(pixel_t); @@ -1098,14 +1147,14 @@ public: pixel_t* __restrict rows[scale]; rows[0] = &pixels[cdy*pitch+dest_x]; - for (int i = 1; i < scale; ++i) rows[i] = rows[i-1] + pitch; + rows[1] = rows[0] + pitch; if (csy < 0 || csy >= height) { for (int cdx = 0; cdx < dest_w; cdx += scale) { pixel_t p = 0; - fill_pixel((pixel_t**)rows, scale, p); + scale_t::fill_pixel((pixel_t**)rows, p); } } else @@ -1118,7 +1167,7 @@ public: while (csx < 0 && cdx < dest_w) { pixel_t p = 0; - fill_pixel((pixel_t**)rows, scale, p); + scale_t::fill_pixel((pixel_t**)rows, p); src++; csx++; cdx += scale; @@ -1133,7 +1182,7 @@ public: p >>= 2; pixel_t rgb; to_pixel(p, &rgb); - fill_pixel((pixel_t**)rows, scale, rgb); + scale_t::fill_pixel((pixel_t**)rows, rgb); src++; csx++; cdx += scale; @@ -1145,7 +1194,7 @@ public: { pixel_t rgb; to_pixel(*src, &rgb); - fill_pixel((pixel_t**)rows, scale, rgb); + scale_t::fill_pixel((pixel_t**)rows, rgb); src++; csx++; cdx += scale; @@ -1155,7 +1204,7 @@ public: while (cdx < dest_w) { pixel_t p = 0; - fill_pixel((pixel_t**)rows, scale, p); + scale_t::fill_pixel((pixel_t**)rows, p); src++; csx++; cdx += scale; @@ -1166,36 +1215,44 @@ public: } } - inline + template inline void blit_x(GdkImage *img, int src_x, int src_y, int dest_x, int dest_y, - int dest_w, int dest_h, bool overlay, int scale) + int dest_w, int dest_h, bool overlay) { if (img->depth == 16) - blit(img, src_x, src_y, dest_x, dest_y, dest_w, dest_h, - overlay, scale); + blit(img, src_x, src_y, dest_x, dest_y, + dest_w, dest_h, overlay); else - blit(img, src_x, src_y, dest_x, dest_y, dest_w, dest_h, - overlay, scale); + blit(img, src_x, src_y, dest_x, dest_y, + dest_w, dest_h, overlay); } - void blit_1x(GdkImage* img, int src_x, int src_y, int dest_x, int dest_y, int dest_w, int dest_h, bool overlay) + void blit_1x(GdkImage* img, int src_x, int src_y, int dest_x, int dest_y, + int dest_w, int dest_h, bool overlay) { - blit_x(img, src_x, src_y, dest_x, dest_y, dest_w, dest_h, overlay, 1); + blit_x (img, src_x, src_y, dest_x, dest_y, dest_w, dest_h, + overlay); } - void blit_2x(GdkImage* img, int src_x, int src_y, int dest_x, int dest_y, int dest_w, int dest_h, bool overlay) + void blit_2x(GdkImage* img, int src_x, int src_y, int dest_x, int dest_y, + int dest_w, int dest_h, bool overlay) { - blit_x(img, src_x, src_y, dest_x, dest_y, dest_w, dest_h, overlay, 2); + blit(img, src_x, src_y, dest_x, dest_y, dest_w, dest_h, overlay); } - void blit_4x(GdkImage* img, int src_x, int src_y, int dest_x, int dest_y, int dest_w, int dest_h, bool overlay) + void blit_4x(GdkImage* img, int src_x, int src_y, int dest_x, int dest_y, + int dest_w, int dest_h, bool overlay) { - blit_x(img, src_x, src_y, dest_x, dest_y, dest_w, dest_h, overlay, 4); + blit_x (img, src_x, src_y, dest_x, dest_y, dest_w, dest_h, + overlay); } - - void blit_8x(GdkImage* img, int src_x, int src_y, int dest_x, int dest_y, int dest_w, int dest_h, bool overlay) + + + void blit_8x(GdkImage* img, int src_x, int src_y, int dest_x, int dest_y, + int dest_w, int dest_h, bool overlay) { - blit_x(img, src_x, src_y, dest_x, dest_y, dest_w, dest_h, overlay, 8); + blit_x (img, src_x, src_y, dest_x, dest_y, dest_w, dest_h, + overlay); } //--------------------------------------------------------------------------------------------- diff --git a/colorsc/colorsc.h b/colorsc/colorsc.h index 2e4c372..7e4c1fa 100644 --- a/colorsc/colorsc.h +++ b/colorsc/colorsc.h @@ -27,6 +27,9 @@ using namespace std; #include #include +typedef guint16 depth16_t; +typedef guint32 depth24_t; + static const float PI = 3.14159f; inline float sgn(float a) { if (a>0) return 1; if (a<0) return -1; return 0; } @@ -107,6 +110,17 @@ struct Color return c; } unsigned int get_r5g6b5() { return ((r>>3)<<11) | ((g>>2)<<5) | (b>>3); } + + void to_pixel(depth16_t *pixel) + { + *pixel = ((r>>3)<<11) | ((g>>2)<<5) | (b>>3); + } + + void to_pixel(depth24_t *pixel) + { + *pixel = (r<<16) | (g<<8) | b; + } + static Color create_from_r5g6b5(unsigned short v) { Color c; diff --git a/colorsc/palette.h b/colorsc/palette.h index 03d51eb..9bdeb33 100644 --- a/colorsc/palette.h +++ b/colorsc/palette.h @@ -181,10 +181,10 @@ public: *p2 = center + Pos::create_from_angle(palette_h+240.0f, size/2-WHEEL_WIDTH); } - // The wheel never changes, so it can be rendered once here. This also clears the image background. - void render_wheel(GdkImage* image) + template inline + void _render_wheel(GdkImage* image) { - if (image->width != size || image->height != size || image->bits_per_pixel != 16) + if (image->width != size || image->height != size) { fprintf(stderr, "Error: Invalid Palette GdkImage.\n"); return; @@ -196,12 +196,12 @@ public: float ring_min_sqr = sqr(wheel_radius-WHEEL_WIDTH); float ring_max_sqr = sqr(wheel_radius); - unsigned short* pixels = (unsigned short*)image->mem; - int stride = image->bpl/sizeof(unsigned short); + pixel_t* pixels = (pixel_t*)image->mem; + int stride = image->bpl/sizeof(pixel_t); for (int y = 0; y < size; y++) { - unsigned short* row = &pixels[y*stride]; + pixel_t* row = &pixels[y*stride]; for (int x = 0; x < size; x++) { // Get radius from center of palette. @@ -218,28 +218,36 @@ public: while (h>360.0f) h -= 360.0f; float r, g, b; hsv_to_rgb(&r, &g, &b, h, 1.0f, 1.0f); - *row++ = Color::create_from_float(r, g, b, 1).get_r5g6b5(); + Color::create_from_float(r, g, b, 1).to_pixel(row); } else - *row++ = bkg.get_r5g6b5(); + bkg.to_pixel(row); + ++row; } } } - // Clears out the inner circle and redraws the color triangle, as fast as possible. - // Scales up implicitly by 2x to improve performance. - // The appearance was an accident which creates a kind of blobby triangle, like the intersection of three circles. - // But I like the look so I'm keeping it! - void render_triangle(GdkImage* image) + // The wheel never changes, so it can be rendered once here. This also clears the image background. + void render_wheel(GdkImage* image) { - if (image->width != size || image->height != size || image->bits_per_pixel != 16 || (size&1)) + if (image->depth == 16) + _render_wheel(image); + else + _render_wheel(image); + } + + template + void _render_triangle(GdkImage* image) + { + if (image->width != size || image->height != size || (size&1)) { fprintf(stderr, "Error: Invalid Palette GdkImage.\n"); return; } Color bkg(64, 64, 64, 0); - unsigned short bkgc = bkg.get_r5g6b5(); + pixel_t bkgc; + bkg.to_pixel(&bkgc); Pos p0, p1, p2; get_triangle_points(&p0, &p1, &p2); @@ -253,15 +261,15 @@ public: int x0 = WHEEL_WIDTH; int x1 = size-WHEEL_WIDTH; - unsigned short* pixels = (unsigned short*)image->mem; - int stride = image->bpl/sizeof(unsigned short); + pixel_t* pixels = (pixel_t*)image->mem; + int stride = image->bpl/sizeof(pixel_t); Pos p(x0,x0); for (int y = x0; y < x1; y+=2, p.y += 2.0f) { p.x = x0; - unsigned short* __restrict row0 = &pixels[(y+0)*stride+x0]; - unsigned short* __restrict row1 = &pixels[(y+1)*stride+x0]; + pixel_t* __restrict row0 = &pixels[(y+0)*stride+x0]; + pixel_t* __restrict row1 = &pixels[(y+1)*stride+x0]; for (int x = x0; x < x1; x+=2, p.x += 2.0f) { // Calculate position inside triangle. If inside, then use as HSV. @@ -272,7 +280,8 @@ public: { float r, g, b; hsv_to_rgb(&r, &g, &b, palette_h, 1.0f-sqrtf(d0_sqr)*inv_triangle_side, sqrtf(d2_sqr)*inv_triangle_side); - unsigned short c = Color::create_from_float(r, g, b, 1).get_r5g6b5(); + pixel_t c; + Color::create_from_float(r, g, b, 1).to_pixel(&c); row0[0] = c; row0[1] = c; row1[0] = c; @@ -295,6 +304,18 @@ public: } } + // Clears out the inner circle and redraws the color triangle, as fast as possible. + // Scales up implicitly by 2x to improve performance. + // The appearance was an accident which creates a kind of blobby triangle, like the intersection of three circles. + // But I like the look so I'm keeping it! + void render_triangle(GdkImage* image) + { + if (image->depth == 16) + _render_triangle(image); + else + _render_triangle(image); + } + Pos get_wheel_pos() { float a = palette_h*PI/180.0f; @@ -388,9 +409,10 @@ public: { } - void render(GdkImage* image) + template inline + void _render(GdkImage* image) { - if (image->width != size || image->height != size || image->bits_per_pixel != 16 || (size&1)) + if (image->width != size || image->height != size || (size&1)) { fprintf(stderr, "Error: Invalid BrushPreview GdkImage.\n"); return; @@ -410,16 +432,20 @@ public: int opacity = int(round(255.0f * brush.opacity)); - unsigned short* pixels = (unsigned short*)image->mem; - int stride = image->bpl/sizeof(unsigned short); + pixel_t* pixels = (pixel_t*)image->mem; + int stride = image->bpl/sizeof(pixel_t); + + Color bkg(0xff, 0xff, 0xff, 0); + pixel_t bkgc; + bkg.to_pixel(&bkgc); // Interpolate the distance table over the area. For each pixel find the distance, and look the // brush-intensity up in the brush-table for (int y = 0; y < size; y+=2) { float x2b = xb; - unsigned short* __restrict row0 = &pixels[(y+0)*stride]; - unsigned short* __restrict row1 = &pixels[(y+1)*stride]; + pixel_t* __restrict row0 = &pixels[(y+0)*stride]; + pixel_t* __restrict row1 = &pixels[(y+1)*stride]; for (int x = 0; x < size; x+=2) { // Find brush-intensity and mulitply that with incoming opacity @@ -430,7 +456,8 @@ public: Color i = Color::create_from_a8r8g8b8(0xffffffff); //Color i = Color::create_from_a8r8g8b8(image[y*size+x]); i = Color::create_from_lerp(brush.color, i, intensity); - unsigned short c = i.get_r5g6b5(); + pixel_t c; + i.to_pixel(&c); row0[0] = c; row0[1] = c; row1[0] = c; @@ -438,10 +465,10 @@ public: } else { - row0[0] = 0xffff; - row0[1] = 0xffff; - row1[0] = 0xffff; - row1[1] = 0xffff; + row0[0] = bkgc; + row0[1] = bkgc; + row1[0] = bkgc; + row1[1] = bkgc; } row0 += 2; @@ -452,6 +479,14 @@ public: yb += db*2; } } + + void render(GdkImage* image) + { + if (image->depth == 16) + _render(image); + else + _render(image); + } }; #endif -- cgit v0.9.1