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