[gs-cvs] rev 8076 - trunk/gs/src
ray at ghostscript.com
ray at ghostscript.com
Tue Jun 26 00:08:17 PDT 2007
Author: ray
Date: 2007-06-26 00:08:17 -0700 (Tue, 26 Jun 2007)
New Revision: 8076
Modified:
trunk/gs/src/gdevwts.c
Log:
Add logic for a configurable color lookup cache to the wts* devices.
Currently set to 4K (4096 entries). Testing indicates this is a
reasonable value, adequate for all synthetic/graphics arts pages
and adequate for photos/scanned images.
DETAILS:
The hash function is rather arbitrary, but some experimentation with
more sophisticated hashing doesn't really show much difference since
the color lookup isn't such a high CPU load even on the performance
files which are entirely images. A 4K CLUT achieves 1.4M hits and
even a 64K CLUT size only gets 1.6M hits (out of ~6M pixels) .
EXPECTED DIFFERENCES:
None. (we don't test the wtsimdi device yet).
Modified: trunk/gs/src/gdevwts.c
===================================================================
--- trunk/gs/src/gdevwts.c 2007-06-25 23:56:29 UTC (rev 8075)
+++ trunk/gs/src/gdevwts.c 2007-06-26 07:08:17 UTC (rev 8076)
@@ -89,6 +89,27 @@
byte cmyk[4];
} cached_color;
+#define COLOR_CACHE_SIZE 4096
+/*
+ * Hash function should preserve low bits (for images) and MUST map white and
+ * black to different slots
+ */
+#if COLOR_CACHE_SIZE == 256
+# define COLOR_TO_CACHE_INDEX(color) (((color + 0x000001) ^ (color >> 8) ^ (color >> 16)) & 0xff)
+#elif COLOR_CACHE_SIZE == 4096
+# define COLOR_TO_CACHE_INDEX(color) (((color + 0x010101) ^ (color >> 12)) & 0xfff)
+#elif COLOR_CACHE_SIZE == 8192
+# define COLOR_TO_CACHE_INDEX(color) (((color + 0x010101) ^ (((color << 24) | color) >> 11)) & 0x1fff)
+#elif COLOR_CACHE_SIZE == 16384
+# define COLOR_TO_CACHE_INDEX(color) (((color + 0x010101) ^ (((color << 24) | color) >> 10)) & 0x3fff)
+#elif COLOR_CACHE_SIZE == 32768
+# define COLOR_TO_CACHE_INDEX(color) (((color + 0x010101) ^ (((color << 24) | color) >> 9)) & 0x7fff)
+#elif COLOR_CACHE_SIZE == 65536
+# define COLOR_TO_CACHE_INDEX(color) (((color + 0x010101) ^ (((color << 24) | color) >> 8)) & 0xffff)
+#else
+# define COLOR_TO_CACHE_INDEX(color) 0
+#endif
+
typedef struct gx_device_wtsimdi_s {
gx_device_common;
gx_prn_device_common;
@@ -98,7 +119,9 @@
icc *icco;
icmLuBase *luo;
imdi *mdo;
- cached_color zero, one;
+ cached_color *color_cache;
+ cached_color current_color;
+ long color_cache_hit, color_cache_collision, color_is_current;
} gx_device_wtsimdi;
private const gx_device_procs wtsimdi_procs =
@@ -328,7 +351,8 @@
wtscmyk_print_page(gx_device_printer *pdev, FILE *prn_stream)
{
gx_device_wts *wdev = (gx_device_wts *)pdev;
- int cmyk_bytes = gdev_mem_bytes_per_scan_line((gx_device *) pdev);
+ gx_device_wtsimdi *idev = (gx_device_wtsimdi *)pdev;
+ int cmyk_bytes = gdev_mem_bytes_per_scan_line((gx_device *)pdev);
/* Output bytes have to be padded to 16 bits. */
int y;
byte *cmyk_line = 0;
@@ -338,7 +362,7 @@
int n_planes = pdev->color_info.num_components;
byte *dst;
FILE *ostream[4] = {0};
- int i;
+ int i, unused_color_cache_slots;
/* Initialize the wts halftones. */
wts_init_halftones(wdev, n_planes);
@@ -348,6 +372,12 @@
code = GS_NOTE_ERROR(pdev->memory, gs_error_VMerror);
goto out;
}
+ /* allocate 1 more for sytems that return NULL if requested count is 0 */
+ idev->color_cache = (cached_color *)gs_malloc(idev->memory, COLOR_CACHE_SIZE + 1,
+ sizeof(cached_color), "wtscmyk_print_page(color_cache)");
+ idev->color_cache_hit = idev->color_cache_collision = idev->color_is_current = 0;
+ for (i=0; i<COLOR_CACHE_SIZE; i++) /* clear cache to empty */
+ idev->color_cache[i].color_index = gx_no_color_index;
pbm_bytes = (pdev->width + 7) >> 3;
dst = gs_malloc(pdev->memory, pbm_bytes * n_planes, 1,
"wtscmyk_print_page");
@@ -388,8 +418,15 @@
fwrite(dst + i * pbm_bytes, 1, pbm_bytes, ostream[i]);
}
out:
+ for (i=0,unused_color_cache_slots=0; i<COLOR_CACHE_SIZE; i++)
+ if (idev->color_cache[i].color_index == gx_no_color_index)
+ unused_color_cache_slots++;
+ dprintf4("wtscmyk_print_page: color cache stats: current=%ld, hits=%ld, collisions=%ld, unused_slots=%d\n",
+ idev->color_is_current, idev->color_cache_hit, idev->color_cache_collision, unused_color_cache_slots);
/* Clean up... */
gs_free(pdev->memory, cmyk_line, cmyk_bytes, 1, "wtscmyk_print_page(in)");
+ gs_free(pdev->memory, idev->color_cache, COLOR_CACHE_SIZE + 1, sizeof(cached_color),
+ "wtscmyk_print_page(color_cache)");
gs_free(pdev->memory, dst, pbm_bytes, 1, "wtscmyk_print_page");
for (i = 1; i < n_planes; i++) {
/* Don't close ostream[0], because gdev_prn_close will. */
@@ -486,8 +523,8 @@
idev->icco = icco;
idev->luo = luo;
idev->mdo = mdo;
- idev->zero.color_index = gx_no_color_index;
- idev->one.color_index = gx_no_color_index;
+ idev->color_cache = NULL;
+ idev->current_color.color_index = gx_no_color_index;
/* guarantee the device bands */
((gx_device_printer *)dev)->space_params.banding_type = BandingAlways;
@@ -516,26 +553,38 @@
private int
wtsimdi_resolve_one(gx_device_wtsimdi *idev, gx_color_index color)
{
- if (color != idev->one.color_index) {
- int code;
- int r = (color >> 16) & 0xff;
- int g = (color >> 8) & 0xff;
- int b = color & 0xff;
- double rgb[3];
- double cmyk[4];
+ if (color != idev->current_color.color_index) { /* quick out for same color */
+ int hash = COLOR_TO_CACHE_INDEX(color); /* 24 bits down to cache index */
- rgb[0] = r / 255.0;
- rgb[1] = g / 255.0;
- rgb[2] = b / 255.0;
- code = idev->luo->lookup(idev->luo, cmyk, rgb);
- if (code > 1)
- return_error(gs_error_unknownerror);
- idev->one.color_index = color;
- idev->one.cmyk[0] = cmyk[0] * 255 + 0.5;
- idev->one.cmyk[1] = cmyk[1] * 255 + 0.5;
- idev->one.cmyk[2] = cmyk[2] * 255 + 0.5;
- idev->one.cmyk[3] = cmyk[3] * 255 + 0.5;
- }
+ if (idev->color_cache[hash].color_index == color) {
+ /* cache hit */
+ idev->color_cache_hit++;
+ idev->current_color = idev->color_cache[hash];
+ } else {
+ /* cache collision or empty, fill it */
+ int code;
+ int r = (color >> 16) & 0xff;
+ int g = (color >> 8) & 0xff;
+ int b = color & 0xff;
+ double rgb[3];
+ double cmyk[4];
+
+ idev->color_cache_collision++;
+ rgb[0] = r / 255.0;
+ rgb[1] = g / 255.0;
+ rgb[2] = b / 255.0;
+ code = idev->luo->lookup(idev->luo, cmyk, rgb);
+ if (code > 1)
+ return_error(gs_error_unknownerror);
+ idev->current_color.color_index = color;
+ idev->current_color.cmyk[0] = cmyk[0] * 255 + 0.5;
+ idev->current_color.cmyk[1] = cmyk[1] * 255 + 0.5;
+ idev->current_color.cmyk[2] = cmyk[2] * 255 + 0.5;
+ idev->current_color.cmyk[3] = cmyk[3] * 255 + 0.5;
+ idev->color_cache[hash] = idev->current_color;
+ }
+ } else
+ idev->color_is_current++;
return 0;
}
@@ -580,7 +629,7 @@
width_padded = wch[plane_ix].width_padded;
dst = base + first_byte + plane_ix * halftoned_bytes;
- comp_value = idev->one.cmyk[plane_ix];
+ comp_value = idev->current_color.cmyk[plane_ix];
if (comp_value == 0) {
if (nfill == 0) {
dst[0] &= (0xff << (8 - (x & 7))) |
@@ -703,7 +752,7 @@
width_padded = wch[plane_ix].width_padded;
dst = base + first_byte + plane_ix * halftoned_bytes;
- comp_value = idev->one.cmyk[plane_ix];
+ comp_value = idev->current_color.cmyk[plane_ix];
if (0 && comp_value == 0) {
/* TODO: these cases should be optimized, avoiding a screen */
if (nfill == 0) {
@@ -994,7 +1043,8 @@
byte * halftoned_data;
byte * halftoned_buffer;
int halftoned_bytes, y;
- int code = 0;
+ int i, code = 0;
+ int unused_color_cache_slots;
int width = pdev->width;
int height = pdev->height;
dev_proc_get_bits((*save_get_bits)) = dev_proc(pdev, get_bits);
@@ -1021,6 +1071,12 @@
code = GS_NOTE_ERROR(pdev->memory, gs_error_VMerror);
goto cleanup;
}
+ /* allocate 1 more for sytems that return NULL if requested count is 0 */
+ idev->color_cache = (cached_color *)gs_malloc(idev->memory, COLOR_CACHE_SIZE + 1,
+ sizeof(cached_color), "wtscmyk_print_page(color_cache)");
+ idev->color_cache_hit = idev->color_cache_collision = idev->color_is_current = 0;
+ for (i=0; i<COLOR_CACHE_SIZE; i++) /* clear cache to empty */
+ idev->color_cache[i].color_index = gx_no_color_index;
/* Initialize output file header. */
fprintf(prn_stream, "P6\n%d %d\n", width, height);
@@ -1043,6 +1099,13 @@
#endif
}
cleanup:
+ for (i=0,unused_color_cache_slots=0; i<COLOR_CACHE_SIZE; i++)
+ if (idev->color_cache[i].color_index == gx_no_color_index)
+ unused_color_cache_slots++;
+ dprintf4("wtsimdi_print_page: color cache stats: current=%ld, hits=%ld, collisions=%ld, unused_slots=%d\n",
+ idev->color_is_current, idev->color_cache_hit, idev->color_cache_collision, unused_color_cache_slots);
+ gs_free(pdev->memory, idev->color_cache, COLOR_CACHE_SIZE, sizeof(cached_color),
+ "wtscmyk_print_page(color_cache)");
if (halftoned_buffer != NULL)
gs_free(pdev->memory, halftoned_buffer, halftoned_bytes * n_planes, 1,
"wtsimdi_print_page(halftoned_buffer)");
More information about the gs-cvs
mailing list