diff options
author | Robin Watts <robin.watts@artifex.com> | 2012-02-06 12:01:53 +0000 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2012-02-06 19:13:00 +0000 |
commit | e448aeaf3d3d572bf4e91d9acdf3fa623ed9b6fb (patch) | |
tree | 3dbaa3600a2b196223dce2bdabb1c2de87f8e353 | |
parent | 09a47e5c2b0fff0d2598e38305bc3d0bc050a26f (diff) |
Clipping optimisations; avoid needless clipping device.
When filling a mask, check any clipping path given; if it trivially
includes all the mask, then don't bother creating a clipping
device. If it trivially excludes, then don't bother plotting at all.
If the bbox partially covers the area, then reduce the area
of the mask.
This gives a 6-8% speedup of customer 532's test files; they are
filling a mask with a halftone, which breaks down into lots of
short run, 1 pixel high rectangles. Avoiding the clipping device
avoids lots of function call overhead.
-rw-r--r-- | gs/base/gdevdbit.c | 42 | ||||
-rw-r--r-- | gs/base/gxclip.c | 38 | ||||
-rw-r--r-- | gs/base/gxcpath.h | 1 |
3 files changed, 75 insertions, 6 deletions
diff --git a/gs/base/gdevdbit.c b/gs/base/gdevdbit.c index 99140d5f2..9631517a1 100644 --- a/gs/base/gdevdbit.c +++ b/gs/base/gdevdbit.c | |||
@@ -326,14 +326,44 @@ gx_default_fill_mask(gx_device * orig_dev, | |||
326 | const gx_drawing_color * pdcolor, int depth, | 326 | const gx_drawing_color * pdcolor, int depth, |
327 | gs_logical_operation_t lop, const gx_clip_path * pcpath) | 327 | gs_logical_operation_t lop, const gx_clip_path * pcpath) |
328 | { | 328 | { |
329 | gx_device *dev; | 329 | gx_device *dev = orig_dev; |
330 | gx_device_clip cdev; | 330 | gx_device_clip cdev; |
331 | 331 | ||
332 | if (pcpath != 0) { | 332 | if (w == 0 || h == 0) |
333 | gx_make_clip_device_on_stack(&cdev, pcpath, orig_dev); | 333 | return 0; |
334 | dev = (gx_device *) & cdev; | 334 | |
335 | } else | 335 | if (pcpath != 0) |
336 | dev = orig_dev; | 336 | { |
337 | gs_fixed_rect rect; | ||
338 | int tmp; | ||
339 | |||
340 | rect.p.x = int2fixed(x); | ||
341 | rect.p.y = int2fixed(y); | ||
342 | rect.q.x = int2fixed(x+w); | ||
343 | rect.q.y = int2fixed(y+h); | ||
344 | dev = gx_make_clip_device_on_stack_if_needed(&cdev, pcpath, dev, &rect); | ||
345 | if (dev == NULL) | ||
346 | return 0; | ||
347 | /* Clip region if possible */ | ||
348 | tmp = fixed2int(rect.p.x); | ||
349 | if (tmp > x) | ||
350 | { | ||
351 | dx += tmp-x; | ||
352 | x = tmp; | ||
353 | } | ||
354 | tmp = fixed2int(rect.q.x); | ||
355 | if (tmp < x+w) | ||
356 | w = tmp-x; | ||
357 | tmp = fixed2int(rect.p.y); | ||
358 | if (tmp > y) | ||
359 | { | ||
360 | data += (tmp-y) * raster; | ||
361 | y = tmp; | ||
362 | } | ||
363 | tmp = fixed2int(rect.q.y); | ||
364 | if (tmp < y+h) | ||
365 | h = tmp-y; | ||
366 | } | ||
337 | if (depth > 1) { | 367 | if (depth > 1) { |
338 | /****** CAN'T DO ROP OR HALFTONE WITH ALPHA ******/ | 368 | /****** CAN'T DO ROP OR HALFTONE WITH ALPHA ******/ |
339 | return (*dev_proc(dev, copy_alpha)) | 369 | return (*dev_proc(dev, copy_alpha)) |
diff --git a/gs/base/gxclip.c b/gs/base/gxclip.c index 0350d1eb8..4504d9f26 100644 --- a/gs/base/gxclip.c +++ b/gs/base/gxclip.c | |||
@@ -135,6 +135,44 @@ gx_make_clip_device_on_stack(gx_device_clip * dev, const gx_clip_path *pcpath, g | |||
135 | /* There is no finalization for device on stack so no rc increment */ | 135 | /* There is no finalization for device on stack so no rc increment */ |
136 | (*dev_proc(dev, open_device)) ((gx_device *)dev); | 136 | (*dev_proc(dev, open_device)) ((gx_device *)dev); |
137 | } | 137 | } |
138 | |||
139 | gx_device * | ||
140 | gx_make_clip_device_on_stack_if_needed(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target, gs_fixed_rect *rect) | ||
141 | { | ||
142 | if (pcpath->inner_box.p.x <= rect->p.x && pcpath->inner_box.p.y <= rect->p.y && | ||
143 | pcpath->inner_box.q.x >= rect->q.x && pcpath->inner_box.q.y >= rect->q.y) | ||
144 | { | ||
145 | /* Area is trivially included. No need for clip. */ | ||
146 | return target; | ||
147 | } | ||
148 | else | ||
149 | { | ||
150 | /* Reduce area if possible */ | ||
151 | if (rect->p.x < pcpath->outer_box.p.x) | ||
152 | rect->p.x = pcpath->outer_box.p.x; | ||
153 | if (rect->q.x > pcpath->outer_box.q.x) | ||
154 | rect->q.x = pcpath->outer_box.q.x; | ||
155 | if (rect->p.y < pcpath->outer_box.p.y) | ||
156 | rect->p.y = pcpath->outer_box.p.y; | ||
157 | if (rect->q.y > pcpath->outer_box.q.y) | ||
158 | rect->q.y = pcpath->outer_box.q.y; | ||
159 | /* Check for area being trivially clipped away. */ | ||
160 | if (rect->p.x >= rect->q.x || rect->p.y >= rect->q.y) | ||
161 | return NULL; | ||
162 | } | ||
163 | gx_device_init((gx_device *)dev, (const gx_device *)&gs_clip_device, NULL, true); | ||
164 | dev->list = *gx_cpath_list(pcpath); | ||
165 | dev->translation.x = 0; | ||
166 | dev->translation.y = 0; | ||
167 | dev->HWResolution[0] = target->HWResolution[0]; | ||
168 | dev->HWResolution[1] = target->HWResolution[1]; | ||
169 | dev->sgr = target->sgr; | ||
170 | dev->target = target; | ||
171 | dev->graphics_type_tag = target->graphics_type_tag; /* initialize to same as target */ | ||
172 | /* There is no finalization for device on stack so no rc increment */ | ||
173 | (*dev_proc(dev, open_device)) ((gx_device *)dev); | ||
174 | return (gx_device *)dev; | ||
175 | } | ||
138 | void | 176 | void |
139 | gx_make_clip_device_in_heap(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target, | 177 | gx_make_clip_device_in_heap(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target, |
140 | gs_memory_t *mem) | 178 | gs_memory_t *mem) |
diff --git a/gs/base/gxcpath.h b/gs/base/gxcpath.h index 6bf6bf8da..6eb34d338 100644 --- a/gs/base/gxcpath.h +++ b/gs/base/gxcpath.h | |||
@@ -110,6 +110,7 @@ extern_st(st_device_clip); | |||
110 | "gx_device_clip", device_clip_enum_ptrs, device_clip_reloc_ptrs,\ | 110 | "gx_device_clip", device_clip_enum_ptrs, device_clip_reloc_ptrs,\ |
111 | gx_device_finalize) | 111 | gx_device_finalize) |
112 | void gx_make_clip_device_on_stack(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target); | 112 | void gx_make_clip_device_on_stack(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target); |
113 | gx_device *gx_make_clip_device_on_stack_if_needed(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target, gs_fixed_rect *rect); | ||
113 | void gx_make_clip_device_in_heap(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target, | 114 | void gx_make_clip_device_in_heap(gx_device_clip * dev, const gx_clip_path *pcpath, gx_device *target, |
114 | gs_memory_t *mem); | 115 | gs_memory_t *mem); |
115 | 116 | ||