1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2    All Rights Reserved.
3 
4    This software is provided AS-IS with no warranty, either express or
5    implied.
6 
7    This software is distributed under license and may not be copied, modified
8    or distributed except as expressly authorized under the terms of that
9    license.  Refer to licensing information at http://www.artifex.com/
10    or contact Artifex Software, Inc.,  7 Mt. Lassen Drive - Suite A-134,
11    San Rafael, CA  94903, U.S.A., +1(415)492-9861, for further information.
12 */
13 
14 /* $Id: gdevprna.h 8022 2007-06-05 22:23:38Z giles $ */
15 /* Generic asynchronous printer driver support */
16 
17 /* Initial version 2/1/1998 by John Desrosiers (soho@crl.com) */
18 /* 7/28/98 ghost@aladdin.com - Updated to Ghostscript coding standards. */
19 
20 #ifndef gdevprna_INCLUDED
21 # define gdevprna_INCLUDED
22 
23 # include "gdevprn.h"
24 # include "gxsync.h"
25 
26 /*
27  * General
28  * -------
29  * Async drivers actually create two separate instances of the device at
30  * the same time. The first (the writer instance) is only used in the
31  * interpretation operation; it feeds rendering commands into the command
32  * lists. The second device instance is used only for rendering the
33  * commands placed into the command list by the writer.
34 
35  * The writer builds a command list for an entire page; the command list
36  * is only queued for rendering once a page's command list is completely
37  * built. The only exception to this rule is when the interpreter runs
38  * out of memory, or when no free command list memory is available. In
39  * such cases, the interpreter queues a "partial page" consisting of all
40  * command list data written so far, plus a command indicating that the
41  * page description is not complete. After queuing the partial page, the
42  * interpereter waits until the rendering process has freed enough
43  * command list memory to enable the interpreter to proceed.
44 
45  * To avoid deadlocks when the system runs out of memory, special
46  * memory allocation provisions are made on both the writer and
47  * renderer sides. On the writer side, enough "reserve" bandlist
48  * memory is set aside at startup time to cover the needs of queuing a
49  * partial page to the renderer. The renderer operates out of a fixed
50  * memory space; that way, it can always complete rendering pages with
51  * the memory it has. To this end, the writer protects the renderer
52  * from consuming unbounded amounts of memory by a) never putting
53  * complex paths into the command list, b) pre-clipping any output
54  * unless the clip path consists of a single rectangle, c) never putting
55  * high-level images into the clip path unless the image in question
56  * meets some very stringent requirements, such as only being rotated by
57  * even multiples of 90 degrees and having source-image data rows which
58  * fit into the command buffer in one piece. These restrictions are what
59  * dictate the "restricted bandlist format."
60 
61  * Note that the renderer's instance of the device driver uses the
62  * renderer's memory. That implies that it must also operate in a small,
63  * fixed amount of memory, and must do all memory allocation using the
64  * memory allocator pointed to by the render device's ->memory member.
65 
66  * Opening the Device
67  * ------------------
68  * The writer instance is opened first. This occurs when the system
69  * calls the "standard" open procedure via the device's procedure
70  * vector. The driver must implement the open function, but must call
71  * down to gdev_prn_async_write_open instead of calling down to
72  * gdev_prn_open. Before calling down to gdev_prn_async_write_open, the
73  * driver must:
74  *  a - init several procedure vectors, to wit: start_render_thread,
75  *      buffer_page, print_page_copies,
76  *  b - init space_params.band.BandWidth, space_params.band.BandHeight,
77  *      space_params.BufferSpace (see extended comments in gdevasyn.c
78  *      for details on computing appropriate values).
79  *  c - if it implements those functions, the driver must init the
80  *      procedure vectors for: put_params, get_hardware_params,
81  *      output_page, open_render_device.
82  * Notice that there are two procedure vectors: the usual std_procs, and
83  * the printer-specific printer_procs.
84 
85  * Since partial page support imposes extra requirements on drivers,
86  * such support can be disabled by zeroing out (in the async writer open
87  * routine, after calling down to gdev_prn_async_write_open) the
88  * free_up_bandlist_memory member of the driver structure. Doing so
89  * will, of course, cause interpretation to fail if memory runs out.
90 
91  * Once the driver calls down to gdev_prn_async_write_open, the async
92  * support logic will create a second instance of the driver for
93  * rendering, but will not open it just yet. Instead, the async logic
94  * will attempt to synchronize the two device instances.
95 
96  * Synchrnonizing the instances
97  * ----------------------------
98  * While still in the gdev_prn_async_write_open routine, the async logic
99  * will call printer_procs.start_render_thread (which the driver is
100  * required to implement). start_render_thread must somehow either start a new
101  * thread or rendez-vous with an existing thread for use in rendering,
102  * then return. start_render_thread must also have caused the render thread
103  * to call gdev_prn_async_render_thread, passing it as an argument a magic
104  * cookie passed to start_render_thread. start_render_thread will only
105  * return once the device has been closed and all renering has been
106  * completed.
107 
108  * The render device will be opened on the render device's thread, by
109  * calling printer_procs.open_render_device.
110 
111  * Rendering Operation
112  * -------------------
113  * During rendering, the device will not see rendering operations -- the
114  * first "rendering" operations the driver will see is when the renderer
115  * instance's print_page_copies or buffer_page routines get called. In
116  * both cases, the appropriate routine must then perform get_bits calls
117  * on the async logic in order to retrieve rendered bits, then transmit
118  * them to the appropriate device buffers.
119 
120  * The complication that is introduced is that which is related to partial
121  * pages: A buffer_page call instructs the driver to grab the rendered bits,
122  * but to keep the rendered bits available for later instead of marking on
123  * media. This implies that a buffer_page call opens a context where
124  * subsequent buffer_page's and print_page_copies' must first initialize the
125  * rendering buffers with the previous rendering results before calling
126  * get_bits. The first print_page_copies closes the context that was opened
127  * by the initial buffer_page -- the driver must go back to normal rendering
128  * until a new buffer_page comes along.
129  */
130 
131 /* -------------- Type declarations --------------- */
132 
133 /* typedef is in gdevprn.h */
134 /* typedef struct gdev_prn_start_render_params_s gdev_prn_start_render_params;*/
135 struct gdev_prn_start_render_params_s {
136     gx_device_printer *writer_device;/* writer dev that points to render dev */
137     gx_semaphore_t *open_semaphore;	/* signal this once open_code is set */
138     int open_code;		/* RETURNS status of open of reader device */
139 };
140 
141 /* -------- Macros used to initialize render-specific structures ------ */
142 
143 #define init_async_render_procs(xpdev, xstart_render_thread,\
144 				xbuffer_page, xprint_page_copies)\
145   BEGIN\
146     (xpdev)->printer_procs.start_render_thread = (xstart_render_thread);\
147     (xpdev)->printer_procs.buffer_page = (xbuffer_page);\
148     (xpdev)->printer_procs.print_page_copies = (xprint_page_copies);\
149   END
150 
151 /* -------------- Global procedure declarations --------- */
152 
153 /* Open this printer device in ASYNC (overlapped) mode.
154  *
155  * This routine is always called by the concrete device's xx_open routine
156  * in lieu of gdev_prn_open.
157  */
158 int gdev_prn_async_write_open(gx_device_printer *pdev, int max_raster,
159 			      int min_band_height, int max_src_image_row);
160 
161 /* Open the render portion of a printer device in ASYNC (overlapped) mode.
162  *
163  * This routine is always called by concrete device's xx_open_render_device
164  * in lieu of gdev_prn_open.
165  */
166 int gdev_prn_async_render_open(gx_device_printer *prdev);
167 
168 /*
169  * Must be called by async device driver implementation (see
170  * gdevprna.h under "Synchronizing the Instances"). This is the
171  * rendering loop, which requires its own thread for as long as
172  * the device is open. This proc only returns after the device is closed.
173  */
174 int	/* rets 0 ok, -ve error code */
175 gdev_prn_async_render_thread(gdev_prn_start_render_params *);
176 
177 #endif				/* gdevprna_INCLUDED */
178