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