[gs-cvs] rev 7120 - trunk/gs/src
leonardo at ghostscript.com
leonardo at ghostscript.com
Tue Oct 24 08:13:04 PDT 2006
Author: leonardo
Date: 2006-10-24 08:13:03 -0700 (Tue, 24 Oct 2006)
New Revision: 7120
Modified:
trunk/gs/src/gdevpdfi.c
trunk/gs/src/gsimage.c
trunk/gs/src/gsimage.h
trunk/gs/src/gsptype1.c
trunk/gs/src/gsptype2.c
trunk/gs/src/gxacpath.c
trunk/gs/src/gxccache.c
trunk/gs/src/gxcpath.c
trunk/gs/src/gxcpath.h
trunk/gs/src/gxdevcli.h
trunk/gs/src/gzacpath.h
trunk/gs/src/lib.mak
trunk/gs/src/zimage.c
Log:
Fix (imagemask) : An optimization for imagemask with a shading color.
DETAILS :
This is a partial performance fix for 09-47L.PS .
It fixes the biggest performance flaw,
but a further optimization is still wanted.
The patch converts the image into a clipping path and then
renders entire shading at once through the clipping path.
The old code rendered entire shading color many times for
each rectangle of the mask.
1. The clip list accumulator device is made publicly accessible.
2. Provided a garbager descriptor for clip list accumulator device structure.
3. When an imagemask needs to render with a shading color,
gs_image_begin_typed replaces the target device with
the clip list accumulator device.
4. To provide a correct work of (3),
inserted a hook into gx_dc_pattern2_fill_rectangle,
which forwards the operation back to the device method.
It is done because normally that function calls
copy_mono with imagemak. Instead that, we need to accumulate
rectangles for the clipping path.
5. Introduced a new signal pattern_manage__is_cpath_accum,
which is used to detect the clip path accumulator device
under a forwarding device. Such case happens in (4)
when it renders a cached character with a shading color.
6. gs_image_cleanup performs the main work for rendering
the shading color through the clipping path.
Note that we need to pass the device color to it,
therefore it gets a new gs_state argument.
(Well, one may think that it can be passed
in a new field of gs_image_enum.
Actually that's not safe because an erroneus Postscript program
can change the current graphic state and
release the old one. After that the pointer
will point to the released structure and
cause a heap inconsistency).
EXPECTED DIFFERENCES :
None.
Modified: trunk/gs/src/gdevpdfi.c
===================================================================
--- trunk/gs/src/gdevpdfi.c 2006-10-24 12:22:14 UTC (rev 7119)
+++ trunk/gs/src/gdevpdfi.c 2006-10-24 15:13:03 UTC (rev 7120)
@@ -1390,6 +1390,8 @@
return 1;
case pattern_manage__shading_area:
return 0;
+ case pattern_manage__is_cpath_accum:
+ return 0;
}
return_error(gs_error_unregistered);
}
Modified: trunk/gs/src/gsimage.c
===================================================================
--- trunk/gs/src/gsimage.c 2006-10-24 12:22:14 UTC (rev 7119)
+++ trunk/gs/src/gsimage.c 2006-10-24 15:13:03 UTC (rev 7120)
@@ -25,6 +25,9 @@
#include "gxiparam.h"
#include "gxpath.h" /* for gx_effective_clip_path */
#include "gzstate.h"
+#include "gzacpath.h"
+#include "gzpath.h"
+#include "gzcpath.h"
/*
@@ -153,6 +156,7 @@
gx_device *dev = gs_currentdevice(pgs);
gx_clip_path *pcpath;
int code = gx_effective_clip_path(pgs, &pcpath);
+ gx_device *dev2 = dev;
if (code < 0)
return code;
@@ -162,7 +166,35 @@
if (code < 0)
return code;
}
- return gx_device_begin_typed_image(dev, (const gs_imager_state *)pgs,
+ /* Imagemask with shading color needs a special optimization
+ with converting the image into a clipping.
+ Check for such case after gs_state_color_load is done,
+ because it can cause interpreter callout.
+ */
+ if (pic->type->begin_typed_image == &gx_begin_image1) {
+ gs_image_t *image = (gs_image_t *)pic;
+
+ if(image->ImageMask) {
+ if (gx_dc_is_pattern2_color(pgs->dev_color)) {
+ if (!dev_proc(pgs->device, pattern_manage)(dev, gs_no_id, NULL, pattern_manage__can_accum)) {
+ extern_st(st_device_cpath_accum);
+ gs_memory_t *mem = pgs->memory;
+ gx_device_cpath_accum *pcdev = gs_alloc_struct(mem,
+ gx_device_cpath_accum, &st_device_cpath_accum, "gs_image_begin_typed");
+ gs_fixed_rect cbox;
+
+ if (pcdev == NULL)
+ return_error(gs_error_VMerror);
+ gx_cpath_accum_begin(pcdev, mem);
+ gx_cpath_outer_box(pcpath, &cbox);
+ gx_cpath_accum_set_cbox(pcdev, &cbox);
+ gx_device_retain((gx_device *)pcdev, true);
+ dev2 = (gx_device *)pcdev;
+ }
+ }
+ }
+ }
+ return gx_device_begin_typed_image(dev2, (const gs_imager_state *)pgs,
NULL, pic, NULL, pgs->dev_color, pcpath, pgs->memory, ppie);
}
@@ -552,24 +584,53 @@
}
/* Clean up after processing an image. */
+/* Public for ghotpcl. */
int
-gs_image_cleanup(gs_image_enum * penum)
+gs_image_cleanup(gs_image_enum * penum, gs_state *pgs)
{
- int code = 0;
+ int code = 0, code1;
free_row_buffers(penum, penum->num_planes, "gs_image_cleanup(row)");
- if (penum->info != 0)
- code = gx_image_end(penum->info, !penum->error);
+ if (penum->info != 0) {
+ if (dev_proc(penum->info->dev, pattern_manage)(penum->info->dev,
+ gs_no_id, NULL, pattern_manage__is_cpath_accum)) {
+ /* Performing a conversion of imagemask into a clipping path. */
+ gx_device_cpath_accum *pcdev = (gx_device_cpath_accum *)penum->info->dev;
+ gx_clip_path cpath;
+ gx_device_clip cdev;
+
+ code = gx_image_end(penum->info, !penum->error); /* Releases penum->info . */
+ gx_cpath_init_local(&cpath, pcdev->memory);
+ code1 = gx_cpath_accum_end(pcdev, &cpath);
+ if (code == 0)
+ code = code1;
+ gx_make_clip_path_device(&cdev, &cpath);
+ cdev.target = penum->dev;
+ (*dev_proc(&cdev, open_device)) ((gx_device *) & cdev);
+ code1 = gx_device_color_fill_rectangle(pgs->dev_color,
+ pcdev->bbox.p.x, pcdev->bbox.p.y,
+ pcdev->bbox.q.x - pcdev->bbox.p.x,
+ pcdev->bbox.q.y - pcdev->bbox.p.y,
+ (gx_device *)&cdev, lop_default, 0);
+ if (code == 0)
+ code = code1;
+ gx_device_retain((gx_device *)pcdev, false);
+ gx_cpath_free(&cpath, "s_image_cleanup");
+ } else
+ code = gx_image_end(penum->info, !penum->error);
+ }
/* Don't free the local enumerator -- the client does that. */
+
return code;
}
/* Clean up after processing an image and free the enumerator. */
int
-gs_image_cleanup_and_free_enum(gs_image_enum * penum)
+gs_image_cleanup_and_free_enum(gs_image_enum * penum, gs_state *pgs)
{
- int code = gs_image_cleanup(penum);
+ int code = gs_image_cleanup(penum, pgs);
gs_free_object(penum->memory, penum, "gs_image_cleanup_and_free_enum");
return code;
}
+
Modified: trunk/gs/src/gsimage.h
===================================================================
--- trunk/gs/src/gsimage.h 2006-10-24 12:22:14 UTC (rev 7119)
+++ trunk/gs/src/gsimage.h 2006-10-24 15:13:03 UTC (rev 7120)
@@ -131,6 +131,10 @@
# define gx_device_DEFINED
typedef struct gx_device_s gx_device;
#endif
+#ifndef gx_device_color_DEFINED
+# define gx_device_color_DEFINED
+typedef struct gx_device_color_s gx_device_color;
+#endif
/* Initialize the common part of the image class */
int gs_image_common_init(gs_image_enum * penum,
@@ -190,9 +194,9 @@
uint dsize, uint * pused);
/* Clean up after processing an image. */
-int gs_image_cleanup(gs_image_enum * penum);
+int gs_image_cleanup(gs_image_enum * penum, gs_state *pgs);
/* Clean up after processing an image and free the enumerator. */
-int gs_image_cleanup_and_free_enum(gs_image_enum * penum);
+int gs_image_cleanup_and_free_enum(gs_image_enum * penum, gs_state *pgs);
#endif /* gsimage_INCLUDED */
Modified: trunk/gs/src/gsptype1.c
===================================================================
--- trunk/gs/src/gsptype1.c 2006-10-24 12:22:14 UTC (rev 7119)
+++ trunk/gs/src/gsptype1.c 2006-10-24 15:13:03 UTC (rev 7120)
@@ -694,7 +694,7 @@
else
for (n = pim->Height; n > 0 && code >= 0; dp += raster, --n)
code = gs_image_next(pen, dp, nbytes, &used);
- code1 = gs_image_cleanup_and_free_enum(pen);
+ code1 = gs_image_cleanup_and_free_enum(pen, pgs);
if (code >= 0 && code1 < 0)
code = code1;
return code;
Modified: trunk/gs/src/gsptype2.c
===================================================================
--- trunk/gs/src/gsptype2.c 2006-10-24 12:22:14 UTC (rev 7119)
+++ trunk/gs/src/gsptype2.c 2006-10-24 15:13:03 UTC (rev 7120)
@@ -224,12 +224,19 @@
gs_logical_operation_t lop,
const gx_rop_source_t * source)
{
- gs_fixed_rect rect;
- rect.p.x = int2fixed(x);
- rect.p.y = int2fixed(y);
- rect.q.x = int2fixed(x + w);
- rect.q.y = int2fixed(y + h);
- return gx_dc_pattern2_fill_path(pdevc, NULL, &rect, dev);
+ if (dev_proc(dev, pattern_manage)(dev, gs_no_id, NULL, pattern_manage__is_cpath_accum)) {
+ /* Performing a conversion of imagemask into a clipping path.
+ Fall back to the device procedure. */
+ return dev_proc(dev, fill_rectangle)(dev, x, y, w, h, (gx_color_index)0/*any*/);
+ } else {
+ gs_fixed_rect rect;
+
+ rect.p.x = int2fixed(x);
+ rect.p.y = int2fixed(y);
+ rect.q.x = int2fixed(x + w);
+ rect.q.y = int2fixed(y + h);
+ return gx_dc_pattern2_fill_path(pdevc, NULL, &rect, dev);
+ }
}
/* Compare two PatternType 2 colors for equality. */
Modified: trunk/gs/src/gxacpath.c
===================================================================
--- trunk/gs/src/gxacpath.c 2006-10-24 12:22:14 UTC (rev 7119)
+++ trunk/gs/src/gxacpath.c 2006-10-24 15:13:03 UTC (rev 7120)
@@ -28,16 +28,33 @@
#include "gzacpath.h"
/* Device procedures */
-private dev_proc_open_device(accum_open);
+private dev_proc_open_device(accum_open_device);
private dev_proc_close_device(accum_close);
private dev_proc_fill_rectangle(accum_fill_rectangle);
+private dev_proc_pattern_manage(accum_pattern_manage);
+/* GC information */
+extern_st(st_clip_list);
+private
+ENUM_PTRS_WITH(device_cpath_accum_enum_ptrs, gx_device_cpath_accum *pdev)
+ if (index > st_device_max_ptrs)
+ return ENUM_USING(st_clip_list, &pdev->list, sizeof(gx_clip_list), index - st_device_max_ptrs);
+ ENUM_PREFIX(st_device, 0);
+ENUM_PTRS_END
+private
+RELOC_PTRS_WITH(device_cpath_accum_reloc_ptrs, gx_device_cpath_accum *pdev)
+{ RELOC_PREFIX(st_device);
+ RELOC_USING(st_clip_list, &pdev->list, size);
+} RELOC_PTRS_END
+
+public_st_device_cpath_accum();
+
/* The device descriptor */
/* Many of these procedures won't be called; they are set to NULL. */
private const gx_device_cpath_accum gs_cpath_accum_device =
{std_device_std_body(gx_device_cpath_accum, 0, "clip list accumulator",
0, 0, 1, 1),
- {accum_open,
+ {accum_open_device,
NULL,
NULL,
NULL,
@@ -81,15 +98,16 @@
NULL,
gx_default_text_begin,
gx_default_finish_copydevice,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL
+ NULL, /* begin_transparency_group */
+ NULL, /* end_transparency_group */
+ NULL, /* begin_transparency_mask */
+ NULL, /* end_transparency_mask */
+ NULL, /* discard_transparency_layer */
+ NULL, /* get_color_mapping_procs */
+ NULL, /* get_color_comp_index */
+ NULL, /* encode_color */
+ NULL, /* decode_color */
+ accum_pattern_manage
}
};
@@ -229,8 +247,8 @@
#endif /* DEBUG */
/* Initialize the accumulation device. */
-private int
-accum_open(register gx_device * dev)
+int
+accum_open_device(register gx_device * dev)
{
gx_device_cpath_accum * const adev = (gx_device_cpath_accum *)dev;
@@ -272,6 +290,21 @@
return 0;
}
+
+/*
+ The pattern management device method.
+ See gxdevcli.h about return codes.
+ */
+int
+accum_pattern_manage(gx_device *pdev1, gx_bitmap_id id,
+ gs_pattern1_instance_t *pinst, pattern_manage_t function)
+{
+ if (function == pattern_manage__is_cpath_accum)
+ return 1;
+ return 0;
+}
+
+
/* Accumulate one rectangle. */
/* Allocate a rectangle to be added to the list. */
static const gx_clip_rect clip_head_rect = {
Modified: trunk/gs/src/gxccache.c
===================================================================
--- trunk/gs/src/gxccache.c 2006-10-24 12:22:14 UTC (rev 7119)
+++ trunk/gs/src/gxccache.c 2006-10-24 15:13:03 UTC (rev 7120)
@@ -453,7 +453,7 @@
code = gs_image_next(pie, bits + iy * raster,
(w + 7) >> 3, &used);
}
- code1 = gs_image_cleanup_and_free_enum(pie);
+ code1 = gs_image_cleanup_and_free_enum(pie, pgs);
if (code >= 0 && code1 < 0)
code = code1;
}
Modified: trunk/gs/src/gxcpath.c
===================================================================
--- trunk/gs/src/gxcpath.c 2006-10-24 12:22:14 UTC (rev 7119)
+++ trunk/gs/src/gxcpath.c 2006-10-24 15:13:03 UTC (rev 7120)
@@ -32,7 +32,7 @@
/* Other structure types */
public_st_clip_rect();
-private_st_clip_list();
+public_st_clip_list();
public_st_clip_path();
private_st_clip_rect_list();
public_st_device_clip();
Modified: trunk/gs/src/gxcpath.h
===================================================================
--- trunk/gs/src/gxcpath.h 2006-10-24 12:22:14 UTC (rev 7119)
+++ trunk/gs/src/gxcpath.h 2006-10-24 15:13:03 UTC (rev 7120)
@@ -74,8 +74,8 @@
/* head or tail */
};
-#define private_st_clip_list() /* in gxcpath.c */\
- gs_private_st_ptrs2(st_clip_list, gx_clip_list, "clip_list",\
+#define public_st_clip_list() /* in gxcpath.c */\
+ gs_public_st_ptrs2(st_clip_list, gx_clip_list, "clip_list",\
clip_list_enum_ptrs, clip_list_reloc_ptrs, head, tail)
#define st_clip_list_max_ptrs 2 /* head, tail */
#define clip_list_is_rectangle(clp) ((clp)->count <= 1)
Modified: trunk/gs/src/gxdevcli.h
===================================================================
--- trunk/gs/src/gxdevcli.h 2006-10-24 12:22:14 UTC (rev 7119)
+++ trunk/gs/src/gxdevcli.h 2006-10-24 15:13:03 UTC (rev 7120)
@@ -1231,7 +1231,8 @@
pattern_manage__start_accum,
pattern_manage__finish_accum,
pattern_manage__load,
- pattern_manage__shading_area
+ pattern_manage__shading_area,
+ pattern_manage__is_cpath_accum
} pattern_manage_t;
#define dev_t_proc_pattern_manage(proc, dev_t)\
Modified: trunk/gs/src/gzacpath.h
===================================================================
--- trunk/gs/src/gzacpath.h 2006-10-24 12:22:14 UTC (rev 7119)
+++ trunk/gs/src/gzacpath.h 2006-10-24 15:13:03 UTC (rev 7120)
@@ -18,6 +18,8 @@
#ifndef gzacpath_INCLUDED
# define gzacpath_INCLUDED
+#include "gxcpath.h"
+
/*
* Device for accumulating a rectangle list. This device can clip
* the list being accumulated with a clipping rectangle on the fly:
@@ -32,6 +34,11 @@
gx_clip_list list;
} gx_device_cpath_accum;
+#define public_st_device_cpath_accum()\
+ gs_public_st_complex_only(st_device_cpath_accum, gx_device_cpath_accum,\
+ "gx_device_cpath_accum", 0, device_cpath_accum_enum_ptrs,\
+ device_cpath_accum_reloc_ptrs, gx_device_finalize)
+
/* Start accumulating a clipping path. */
void gx_cpath_accum_begin(gx_device_cpath_accum * padev, gs_memory_t * mem);
@@ -51,4 +58,7 @@
int gx_cpath_intersect_path_slow(gx_clip_path *, gx_path *, int,
gs_imager_state *, const gx_fill_params *);
+int cpath_accum_fill_rect_with(gx_device_cpath_accum *pcdev, gx_device *tdev,
+ gx_device_color *pdevc);
+
#endif /* gzacpath_INCLUDED */
Modified: trunk/gs/src/lib.mak
===================================================================
--- trunk/gs/src/lib.mak 2006-10-24 12:22:14 UTC (rev 7119)
+++ trunk/gs/src/lib.mak 2006-10-24 15:13:03 UTC (rev 7120)
@@ -447,7 +447,7 @@
gsstate_h=$(GLSRC)gsstate.h\
$(gscolor_h) $(gscpm_h) $(gscsel_h) $(gsdevice_h) $(gsht_h) $(gsline_h)
-gzacpath_h=$(GLSRC)gzacpath.h
+gzacpath_h=$(GLSRC)gzacpath.h $(GLSRC)gxcpath.h
gzcpath_h=$(GLSRC)gzcpath.h $(gxcpath_h)
gzht_h=$(GLSRC)gzht.h $(gscsel_h)\
$(gxdht_h) $(gxfmap_h) $(gxht_h) $(gxhttile_h)
@@ -545,7 +545,7 @@
$(gscencs_h) $(gxfixed_h) $(gxmatrix_h)\
$(gzstate_h) $(gzpath_h) $(gxdevice_h) $(gxdevmem_h)\
$(gzcpath_h) $(gxchar_h) $(gxfont_h) $(gxfcache_h)\
- $(gxxfont_h) $(gscspace_h) $(gximage_h) $(gxhttile_h)
+ $(gxxfont_h) $(gscspace_h) $(gsimage_h) $(gxhttile_h)
$(GLCC) $(GLO_)gxccache.$(OBJ) $(C_) $(GLSRC)gxccache.c
$(GLOBJ)gxccman.$(OBJ) : $(GLSRC)gxccman.c $(GXERR) $(memory__h) $(gpcheck_h)\
@@ -815,8 +815,9 @@
$(GLCC) $(GLO_)gshtscr.$(OBJ) $(C_) $(GLSRC)gshtscr.c
$(GLOBJ)gsimage.$(OBJ) : $(GLSRC)gsimage.c $(GXERR) $(memory__h)\
- $(gscspace_h) $(gsimage_h) $(gsmatrix_h) $(gsstruct_h)\
- $(gxarith_h) $(gxdevice_h) $(gxiparam_h) $(gxpath_h) $(gzstate_h)
+ $(gscspace_h) $(gsimage_h) $(gsmatrix_h) $(gsstruct_h) $(gsptype2_h)\
+ $(gxarith_h) $(gxdevice_h) $(gxiparam_h) $(gxpath_h) $(gzstate_h)\
+ $(gzacpath_h) $(gzpath_h) $(gzcpath_h)
$(GLCC) $(GLO_)gsimage.$(OBJ) $(C_) $(GLSRC)gsimage.c
$(GLOBJ)gsimpath.$(OBJ) : $(GLSRC)gsimpath.c $(GXERR)\
Modified: trunk/gs/src/zimage.c
===================================================================
--- trunk/gs/src/zimage.c 2006-10-24 12:22:14 UTC (rev 7119)
+++ trunk/gs/src/zimage.c 2006-10-24 15:13:03 UTC (rev 7120)
@@ -313,7 +313,7 @@
return_error(e_VMerror);
code = gs_image_enum_init(penum, pie, (const gs_data_image_t *)pim, igs);
if (code != 0) { /* error, or empty image */
- int code1 = gs_image_cleanup_and_free_enum(penum);
+ int code1 = gs_image_cleanup_and_free_enum(penum, igs);
if (code >= 0) /* empty image */
pop(npop);
@@ -565,7 +565,7 @@
es_ptr ep_top = esp + NUM_PUSH(EBOT_NUM_SOURCES(esp)->value.intval);
gs_image_enum *penum = r_ptr(ep_top, gs_image_enum);
- return gs_image_cleanup_and_free_enum(penum);
+ return gs_image_cleanup_and_free_enum(penum, igs);
}
/* ------ Initialization procedure ------ */
More information about the gs-cvs
mailing list