diff options
-rw-r--r-- | gs/base/gdevdrop.c | 9 | ||||
-rw-r--r-- | gs/base/gdevmpla.c | 256 | ||||
-rw-r--r-- | gs/base/gsropt.h | 8 | ||||
-rw-r--r-- | gs/base/gxcht.c | 4 | ||||
-rw-r--r-- | gs/base/gxp1fill.c | 2 | ||||
-rw-r--r-- | gs/doc/Drivers.htm | 79 |
6 files changed, 239 insertions, 119 deletions
diff --git a/gs/base/gdevdrop.c b/gs/base/gdevdrop.c index a6ff9351b..45e0708cc 100644 --- a/gs/base/gdevdrop.c +++ b/gs/base/gdevdrop.c @@ -544,6 +544,11 @@ mem_default_strip_copy_rop(gx_device * dev, GB_COLORS_NATIVE | GB_ALPHA_NONE | GB_DEPTH_ALL | GB_PACKING_CHUNKY | GB_RETURN_ALL | GB_ALIGN_STANDARD | GB_OFFSET_0 | GB_OFFSET_ANY | GB_RASTER_STANDARD; + const gx_bitmap_format_t no_expand_t_options = + GB_COLORS_NATIVE | GB_ALPHA_NONE | GB_DEPTH_ALL | + GB_RETURN_ALL | GB_ALIGN_STANDARD | + GB_OFFSET_0 | GB_OFFSET_ANY | GB_RASTER_STANDARD | + ((lop & lop_t_is_planar) ? GB_PACKING_PLANAR : GB_PACKING_CHUNKY); const gx_bitmap_format_t expand_options = (rop_depth > 8 ? GB_COLORS_RGB : GB_COLORS_GRAY) | GB_ALPHA_NONE | GB_DEPTH_8 | @@ -578,6 +583,7 @@ mem_default_strip_copy_rop(gx_device * dev, gs_get_bits_params_t bit_params; gs_get_bits_params_t expand_params; gs_get_bits_params_t no_expand_params; + gs_get_bits_params_t no_expand_t_params; int max_height; int block_height, loop_height; int code; @@ -637,6 +643,7 @@ mem_default_strip_copy_rop(gx_device * dev, expand_s = scolors == 0 && uses_s; expand_t = tcolors == 0 && uses_t; no_expand_params.options = no_expand_options; + no_expand_t_params.options = no_expand_t_options; if (expand_t) { /* * We don't want to wrap around more than once in Y when @@ -710,7 +717,7 @@ mem_default_strip_copy_rop(gx_device * dev, rect.q.y = py + loop_height; expand_params.data[0] = texture_row; gx_get_bits_copy(dev, 0, textures->rep_width, loop_height, - &expand_params, &no_expand_params, + &expand_params, &no_expand_t_params, textures->data + rep_y * textures->raster, textures->raster); /* diff --git a/gs/base/gdevmpla.c b/gs/base/gdevmpla.c index 46c0eb360..955efe58b 100644 --- a/gs/base/gdevmpla.c +++ b/gs/base/gdevmpla.c @@ -1524,6 +1524,100 @@ plane_strip_copy_rop(gx_device_memory * mdev, return code; } +/* + * Repack planar into chunky format. This is an internal procedure that + * implements the straightforward chunky case of get_bits_rectangle, and + * is also used for the general cases. + */ +static int +planar_to_chunky(gx_device_memory *mdev, int x, int y, int w, int h, + int offset, uint draster, byte *dest, byte **line_ptrs, + int plane_height) +{ + int num_planes = mdev->num_planes; + sample_load_declare(sptr[GX_DEVICE_COLOR_MAX_COMPONENTS], + sbit[GX_DEVICE_COLOR_MAX_COMPONENTS]); + sample_store_declare(dptr, dbit, dbbyte); + int ddepth = mdev->color_info.depth; + int direct = + (mdev->color_info.depth != num_planes * mdev->plane_depth ? 0 : + mdev->planes[0].shift == 0 ? -mdev->plane_depth : mdev->plane_depth); + int pi, ix, iy; + + /* Check whether the planes are of equal size and sequential. */ + /* If direct != 0, we already know they exactly fill the depth. */ + if (direct < 0) { + for (pi = 0; pi < num_planes; ++pi) + if (mdev->planes[pi].shift != pi * -direct) { + direct = 0; break; + } + } else if (direct > 0) { + for (pi = 0; pi < num_planes; ++pi) + if (mdev->planes[num_planes - 1 - pi].shift != pi * direct) { + direct = 0; break; + } + } + for (iy = y; iy < y + h; ++iy) { + byte **line_ptr = line_ptrs + iy; + + for (pi = 0; pi < num_planes; ++pi, line_ptr += plane_height) { + int plane_depth = mdev->planes[pi].depth; + int xbit = x * plane_depth; + + sptr[pi] = *line_ptr + (xbit >> 3); + sample_load_setup(sbit[pi], xbit & 7, plane_depth); + } + { + int xbit = offset * ddepth; + + dptr = dest + (iy - y) * draster + (xbit >> 3); + sample_store_setup(dbit, xbit & 7, ddepth); + } + if (direct == -8) { + /* 1 byte per component, lsb first. */ + switch (num_planes) { + case 3: { + const byte *p0 = sptr[2]; + const byte *p1 = sptr[1]; + const byte *p2 = sptr[0]; + + for (ix = w; ix > 0; --ix, dptr += 3) { + dptr[0] = *p0++; + dptr[1] = *p1++; + dptr[2] = *p2++; + } + } + continue; + case 4: + for (ix = w; ix > 0; --ix, dptr += 4) { + dptr[0] = *sptr[3]++; + dptr[1] = *sptr[2]++; + dptr[2] = *sptr[1]++; + dptr[3] = *sptr[0]++; + } + continue; + default: + break; + } + } + sample_store_preload(dbbyte, dptr, dbit, ddepth); + for (ix = w; ix > 0; --ix) { + gx_color_index color = 0; + + for (pi = 0; pi < num_planes; ++pi) { + int plane_depth = mdev->planes[pi].depth; + uint value; + + sample_load_next16(value, sptr[pi], sbit[pi], plane_depth); + color |= (gx_color_index)value << mdev->planes[pi].shift; + } + sample_store_next_any(color, dptr, dbit, ddepth, dbbyte); + } + sample_store_flush(dptr, dbit, ddepth, dbbyte); + } + return 0; +} + static byte cmykrop[256] = { 255,127,191,63,223,95,159,31,239,111,175,47,207,79,143,15, @@ -1557,6 +1651,69 @@ mem_planar_strip_copy_rop(gx_device * dev, gx_device_memory * const mdev = (gx_device_memory *)dev; int plane, code; + if (lop & lop_t_is_planar) { + /* T is in planar format; expand it to a temporary buffer, then + * call ourselves back with a modified rop to use it, then free + * the temporary buffer, and return. */ + /* Make a temporary buffer that contains both the raster and the line + * pointers for the buffer. For now, for the sake of sanity, we + * convert whole lines of t, but only as many lines as we have to + * (unless it loops). */ + /* We assume that tcolors == NULL here */ + int ty, i; + uint chunky_t_raster; + uint chunky_t_height; + uint nbytes; + byte **line_ptrs; + byte *tbuf, *buf; + gx_strip_bitmap newtex; + + ty = (y + phase_y) % textures->rep_height; + chunky_t_raster = bitmap_raster(textures->rep_width * mdev->color_info.depth); + if (ty + height <= textures->rep_height) { + chunky_t_height = height; + phase_y = -y; + } else { + ty = 0; + chunky_t_height = textures->rep_height; + } + nbytes = chunky_t_height * chunky_t_raster; + buf = gs_alloc_bytes(mdev->memory, nbytes, "mem_planar_strip_copy_rop(buf)"); + if (buf == NULL) { + return gs_note_error(gs_error_VMerror); + } + nbytes = sizeof(byte *) * mdev->num_planes * textures->rep_height; + line_ptrs = (byte **)gs_alloc_bytes(mdev->memory, nbytes, "mem_planar_strip_copy_rop(line_ptrs)"); + if (line_ptrs == NULL) { + gs_free_object(mdev->memory, buf, "mem_planar_strip_copy_rop(buf)"); + return gs_note_error(gs_error_VMerror); + } + tbuf = textures->data; + for (i = textures->rep_height * mdev->num_planes; i > 0; i--) { + *line_ptrs++ = tbuf; + tbuf += textures->raster; + } + line_ptrs -= textures->rep_height * mdev->num_planes; + planar_to_chunky(mdev, 0, ty, textures->rep_width, chunky_t_height, + 0, chunky_t_raster, buf, line_ptrs, textures->rep_height); + gs_free_object(mdev->memory, line_ptrs, "mem_planar_strip_copy_rop(line_ptrs)"); + for (i = 0; i < chunky_t_height * chunky_t_raster; i++) { + if ((((buf[i] & 0x01) == 0) && ((buf[i] & 0x0e) != 0)) || + (((buf[i] & 0x10) == 0) && ((buf[i] & 0xee) != 0))) { + dlprintf("ass!\n"); + } + } + newtex = *textures; + newtex.data = buf; + newtex.raster = chunky_t_raster; + code = mem_planar_strip_copy_rop(dev, sdata, sourcex, sraster, + id, scolors, &newtex, tcolors, + x, y, width, height, phase_x, phase_y, + lop & ~lop_t_is_planar); + gs_free_object(mdev->memory, buf, "mem_planar_strip_copy_rop(buf)"); + return code; + } + if ((lop & lop_planar) == 0) { /* Not doing a planar lop. If we carry on down the default path here, * we'll end up doing a planar_to_chunky; we may be able to sidestep @@ -1629,99 +1786,6 @@ mem_planar_strip_copy_rop(gx_device * dev, phase_x, phase_y, lop, plane); } -/* - * Repack planar into chunky format. This is an internal procedure that - * implements the straightforward chunky case of get_bits_rectangle, and - * is also used for the general cases. - */ -static int -planar_to_chunky(gx_device_memory *mdev, int x, int y, int w, int h, - int offset, uint draster, byte *dest) -{ - int num_planes = mdev->num_planes; - sample_load_declare(sptr[GX_DEVICE_COLOR_MAX_COMPONENTS], - sbit[GX_DEVICE_COLOR_MAX_COMPONENTS]); - sample_store_declare(dptr, dbit, dbbyte); - int ddepth = mdev->color_info.depth; - int direct = - (mdev->color_info.depth != num_planes * mdev->plane_depth ? 0 : - mdev->planes[0].shift == 0 ? -mdev->plane_depth : mdev->plane_depth); - int pi, ix, iy; - - /* Check whether the planes are of equal size and sequential. */ - /* If direct != 0, we already know they exactly fill the depth. */ - if (direct < 0) { - for (pi = 0; pi < num_planes; ++pi) - if (mdev->planes[pi].shift != pi * -direct) { - direct = 0; break; - } - } else if (direct > 0) { - for (pi = 0; pi < num_planes; ++pi) - if (mdev->planes[num_planes - 1 - pi].shift != pi * direct) { - direct = 0; break; - } - } - for (iy = y; iy < y + h; ++iy) { - byte **line_ptr = mdev->line_ptrs + iy; - - for (pi = 0; pi < num_planes; ++pi, line_ptr += mdev->height) { - int plane_depth = mdev->planes[pi].depth; - int xbit = x * plane_depth; - - sptr[pi] = *line_ptr + (xbit >> 3); - sample_load_setup(sbit[pi], xbit & 7, plane_depth); - } - { - int xbit = offset * ddepth; - - dptr = dest + (iy - y) * draster + (xbit >> 3); - sample_store_setup(dbit, xbit & 7, ddepth); - } - if (direct == -8) { - /* 1 byte per component, lsb first. */ - switch (num_planes) { - case 3: { - const byte *p0 = sptr[2]; - const byte *p1 = sptr[1]; - const byte *p2 = sptr[0]; - - for (ix = w; ix > 0; --ix, dptr += 3) { - dptr[0] = *p0++; - dptr[1] = *p1++; - dptr[2] = *p2++; - } - } - continue; - case 4: - for (ix = w; ix > 0; --ix, dptr += 4) { - dptr[0] = *sptr[3]++; - dptr[1] = *sptr[2]++; - dptr[2] = *sptr[1]++; - dptr[3] = *sptr[0]++; - } - continue; - default: - break; - } - } - sample_store_preload(dbbyte, dptr, dbit, ddepth); - for (ix = w; ix > 0; --ix) { - gx_color_index color = 0; - - for (pi = 0; pi < num_planes; ++pi) { - int plane_depth = mdev->planes[pi].depth; - uint value; - - sample_load_next16(value, sptr[pi], sbit[pi], plane_depth); - color |= (gx_color_index)value << mdev->planes[pi].shift; - } - sample_store_next_any(color, dptr, dbit, ddepth, dbbyte); - } - sample_store_flush(dptr, dbit, ddepth, dbbyte); - } - return 0; -} - /* Copy bits back from a planar memory device. */ static int mem_planar_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect, @@ -1841,7 +1905,8 @@ mem_planar_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect, (options & GB_RASTER_SPECIFIED ? params->raster : bitmap_raster((offset + w) * mdev->color_info.depth)); - planar_to_chunky(mdev, x, y, w, h, offset, draster, params->data[0]); + planar_to_chunky(mdev, x, y, w, h, offset, draster, params->data[0], + mdev->line_ptrs, mdev->height); } else { /* * Do the transfer through an intermediate buffer. @@ -1895,7 +1960,8 @@ mem_planar_get_bits_rectangle(gx_device * dev, const gs_int_rect * prect, ch = min(bh, y + h - cy); for (cx = x; cx < x + w; cx += cw) { cw = min(bw, x + w - cx); - planar_to_chunky(mdev, cx, cy, cw, ch, 0, br, buf.b); + planar_to_chunky(mdev, cx, cy, cw, ch, 0, br, buf.b, + mdev->line_ptrs, mdev->height); code = gx_get_bits_copy(dev, 0, cw, ch, &dest_params, ©_params, buf.b, br); if (code < 0) diff --git a/gs/base/gsropt.h b/gs/base/gsropt.h index 095b51ab8..fc06aa7de 100644 --- a/gs/base/gsropt.h +++ b/gs/base/gsropt.h @@ -212,11 +212,15 @@ typedef enum { /* Also, we abuse the lop even further, by allowing it to specify a specific * plane for an operation to work on (in a planar device context). To specify - * a particularp plane, set lop_planar, and then or in the plane number + * a particular plane, set lop_planar, and then or in the plane number * shifted up by lop_planar_shift. */ #define lop_planar 0x800 -#define lop_planar_shift 12 +#define lop_planar_shift 13 + +/* And one final abuse; in strip_copy_rop, we allow the lop to have another + * flag bit, indicating that the texture is already in planar format. */ +#define lop_t_is_planar 0x1000 typedef uint gs_logical_operation_t; diff --git a/gs/base/gxcht.c b/gs/base/gxcht.c index c6b9f90b4..9716c4679 100644 --- a/gs/base/gxcht.c +++ b/gs/base/gxcht.c @@ -26,6 +26,7 @@ #include "gxistate.h" #include "gzht.h" #include "gsserial.h" +#include "gxdevsop.h" /* Define whether to force use of the slow code, for testing. */ #define USE_SLOW_CODE 0 @@ -583,8 +584,7 @@ gx_dc_ht_colored_fill_rectangle(const gx_device_color * pdevc, #if USE_SLOW_CODE set_ht_colors_gt_4 #else - (dev_proc(dev, map_cmyk_color) == gx_default_encode_color && - dev->color_info.depth == 4) ? + (dev_proc(dev, dev_spec_op)(dev, gxdso_is_std_cmyk_1bit, NULL, 0) > 0) ? set_cmyk_1bit_colors : nplanes <= 4 ? set_ht_colors_le_4 : set_ht_colors_gt_4 diff --git a/gs/base/gxp1fill.c b/gs/base/gxp1fill.c index 95d824e39..18ae9cc4c 100644 --- a/gs/base/gxp1fill.c +++ b/gs/base/gxp1fill.c @@ -281,7 +281,7 @@ tile_colored_fill(const tile_fill_state_t * ptfs, x, y, w, h, imod(xoff - x, data_tile.rep_width), imod(yoff - y, data_tile.rep_height), - lop); + lop | (ptfs->num_planes > 0 ? lop_t_is_planar : 0)); } return code; } diff --git a/gs/doc/Drivers.htm b/gs/doc/Drivers.htm index 3521bdffd..717436040 100644 --- a/gs/doc/Drivers.htm +++ b/gs/doc/Drivers.htm @@ -804,10 +804,35 @@ used in new code. Here is a copy of the relevant part of the file: * W and a repetition height of H, the pixel at coordinate (X,Y) * corresponds to halftone pixel (X mod W, Y mod H), ignoring phase; * for a shifted halftone with shift S, the pixel at (X,Y) corresponds - * to halftone pixel ((X + S * floor(Y/H)) mod W, Y mod H). Requirements: - * strip_shift < rep_width - * strip_height % rep_height = 0 - * shift = (strip_shift * (size.y / strip_height)) % rep_width + * to halftone pixel ((X + S * floor(Y/H)) mod W, Y mod H). In other words, + * each Y increment of H shifts the strip left by S pixels. + * + * As for non-shifted tiles, a strip bitmap may include multiple copies + * in X or Y to reduce loop overhead. In this case, we must distinguish: + * - The height of an individual strip, which is the same as + * the height of the bitmap being replicated (rep_height, H); + * - The height of the entire bitmap (size.y). + * Similarly, we must distinguish: + * - The shift per strip (rep_shift, S); + * - The shift for the entire bitmap (shift). + * Note that shift = (rep_shift * size.y / rep_height) mod rep_width, + * so the shift member of the structure is only an accelerator. It is, + * however, an important one, since it indicates whether the overall + * bitmap requires shifting or not. + * + * Note that for shifted tiles, size.y is the size of the stored bitmap + * (1 or more strips), and NOT the height of the actual tile. The latter + * is not stored in the structure at all: it can be computed as H * W / + * gcd(S, W). + * + * If the bitmap consists of a multiple of W / gcd(S, W) copies in Y, the + * effective shift is zero, reducing it to a tile. For simplicity, we + * require that if shift is non-zero, the bitmap height be less than H * W / + * gcd(S, W). I.e., we don't allow strip bitmaps that are large enough to + * include a complete tile but that don't include an integral number of + * tiles. Requirements: + * rep_shift < rep_width + * shift = (rep_shift * (size.y / rep_height)) % rep_width */ typedef struct gx_strip_bitmap_s { byte *data; @@ -815,8 +840,7 @@ typedef struct gx_strip_bitmap_s { gs_int_point size; /* width, height */ gx_bitmap_id id; ushort rep_width, rep_height; /* true size of tile */ - ushort strip_height; - ushort strip_shift; + ushort rep_shift; ushort shift; } gx_strip_bitmap;</pre> </blockquote> @@ -1753,11 +1777,30 @@ replicated or clipped as needed. <tr valign=top> <td>9 <td> <td>0 if texture opaque, 1 if texture transparent -<tr valign=top> <td>?-10 +<tr valign=top> <td>10 + <td> + <td>1 if pdf transparency is in use, 0 otherwise. This makes no +difference to the rendering, but forces the raster operation to be considered +non-idempotent by internal routines. +<tr valign=top> <td>11 <td> - <td>unused, must be 0 + <td>1 if the target of this operation is a specific plane, rather +than all planes. The plane in question is given by bits 13 upwards. This +is only used by the planar device. +<tr valign=top> <td>12 + <td> + <td>1 if the texture plane (T) of this operation is in planar format, +rather than the default chunky format. This is only used by the planar device. +<tr valign=top> <td>13- + <td> + <td>If bit 12 = 1, then bits 13 upwards give the plane number to +operate on. Otherwise, should be set to 0. </table></blockquote> +<p>In general most devices should just check to see that bits they do not +handle (11 and above typically) are zero, and should jump to the default +implementation, or return an error otherwise. + <p> The raster operation follows the Microsoft and H-P specification. It is an 8-element truth table that specifies the output value for each of the @@ -2011,7 +2054,7 @@ components in the device (process) color model. <dd> The implementation fills entire triangle. The filling rule is same as for <a href="#Polygon_level_drawing">Polygon-level drawing</a>. -A color for each pixel within the triangle to be computed as a linear interpolation +The color of each pixel within the triangle is computed as a linear interpolation of vertex colors. <dd> The implementation may reject the request if the area or the color appears too complex @@ -2022,12 +2065,12 @@ into smaller triangles and call the function again with smaller areas. <b><em>Important note :</em></b> Do not try to decompose the area within the implementation of <code> fill_linear_color_triangle</code>, because it can break the plane coverage contiguity and cause a dropout. -Instead request that graphics library to perform the decomposition. +Instead request that the graphics library should perform the decomposition. The graphics libary is smart enough to do that properly. <dd> <b><em>Important note :</em></b> The implementation must handle a special case, when only 2 colors are specified. -It happens if <code>p3</code> one is <code>NULL</code>. +It happens if <code>p2</code> is <code>NULL</code>. This means that the color does not depend on the X coordinate, i.e. it forms a linear gradient along the Y axis. The implementation must not reject (return 0) such cases. @@ -2041,7 +2084,7 @@ fist drop (ignore) the sign bit, then drop least significant bits - so many ones as you need to fit the device color precision. <dd> <b><em>Important note :</em></b> The <code>fa</code> argument may contain -the <code>swap_axes</code> bit set. In this case the implementation must swap (transpoze) +the <code>swap_axes</code> bit set. In this case the implementation must swap (transpose) <code>X</code> and <code>Y</code> axes. <dd> <b><em>Important note :</em></b> The implementation must not paint outside the @@ -2049,7 +2092,7 @@ clipping rectangle specified in the <code>fa</code> argument. If <code>fa->swap_axes</code> is true, the clipping rectangle is transposed. <dd> See <code> gx_default_fill_linear_color_triangle </code> -in <code>gdevddrw.c</code> as a sample code. +in <code>gdevddrw.c</code> for sample code. </dl> @@ -2066,9 +2109,9 @@ in <code>gdevddrw.c</code> as a sample code. The default implementation of <code> fill_linear_color_triangle </code> calls this function 1-2 times per triangle. Besides that, this function may be called by the graphics library for other special cases, -when a decomposition into triangles appears undiserable. +when a decomposition into triangles appears undesirable. <dd> -Rather the prototype can specify a bilinear color, +While the prototype can specify a bilinear color, we assume that the implementation handles linear colors only. This means that the implementation can ignore any of <code> c0, c1, c2, c3 </code>. The graphics library takes a special care of the color linearity @@ -2076,12 +2119,12 @@ when calling this function. The reason for passing all 4 color arguments is to avoid color precision problems. <dd> Similarly to <code> fill_linear_color_triangle </code>, -this function may be called with only 2 colors, and may reject too comple areas. +this function may be called with only 2 colors, and may reject areas as being too complex. All those important notes are applicable here. <dd> -A sample code may be found in in <code>gxdtfill.h</code>, rather it's a kind of complicated. +Sample code may be found in in <code>gxdtfill.h</code>; be aware it's rather complicated. A linear color function is generated from it as <code> gx_fill_trapezoid_ns_lc </code> -with the following template parametres : +with the following template parameters : <pre> #define LINEAR_COLOR 1 |