xref: /plan9/sys/src/cmd/gs/src/gdevprna.h (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1998 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gdevprna.h,v 1.5 2002/06/16 07:25:26 lpd Exp $ */
187dd7cddfSDavid du Colombier /* Generic asynchronous printer driver support */
197dd7cddfSDavid du Colombier 
207dd7cddfSDavid du Colombier /* Initial version 2/1/1998 by John Desrosiers (soho@crl.com) */
217dd7cddfSDavid du Colombier /* 7/28/98 ghost@aladdin.com - Updated to Ghostscript coding standards. */
227dd7cddfSDavid du Colombier 
237dd7cddfSDavid du Colombier #ifndef gdevprna_INCLUDED
247dd7cddfSDavid du Colombier # define gdevprna_INCLUDED
257dd7cddfSDavid du Colombier 
267dd7cddfSDavid du Colombier # include "gdevprn.h"
277dd7cddfSDavid du Colombier # include "gxsync.h"
287dd7cddfSDavid du Colombier 
297dd7cddfSDavid du Colombier /*
307dd7cddfSDavid du Colombier  * General
317dd7cddfSDavid du Colombier  * -------
327dd7cddfSDavid du Colombier  * Async drivers actually create two separate instances of the device at
337dd7cddfSDavid du Colombier  * the same time. The first (the writer instance) is only used in the
347dd7cddfSDavid du Colombier  * interpretation operation; it feeds rendering commands into the command
357dd7cddfSDavid du Colombier  * lists. The second device instance is used only for rendering the
367dd7cddfSDavid du Colombier  * commands placed into the command list by the writer.
377dd7cddfSDavid du Colombier 
387dd7cddfSDavid du Colombier  * The writer builds a command list for an entire page; the command list
397dd7cddfSDavid du Colombier  * is only queued for rendering once a page's command list is completely
407dd7cddfSDavid du Colombier  * built. The only exception to this rule is when the interpreter runs
417dd7cddfSDavid du Colombier  * out of memory, or when no free command list memory is available. In
427dd7cddfSDavid du Colombier  * such cases, the interpreter queues a "partial page" consisting of all
437dd7cddfSDavid du Colombier  * command list data written so far, plus a command indicating that the
447dd7cddfSDavid du Colombier  * page description is not complete. After queuing the partial page, the
457dd7cddfSDavid du Colombier  * interpereter waits until the rendering process has freed enough
467dd7cddfSDavid du Colombier  * command list memory to enable the interpreter to proceed.
477dd7cddfSDavid du Colombier 
487dd7cddfSDavid du Colombier  * To avoid deadlocks when the system runs out of memory, special
497dd7cddfSDavid du Colombier  * memory allocation provisions are made on both the writer and
507dd7cddfSDavid du Colombier  * renderer sides. On the writer side, enough "reserve" bandlist
517dd7cddfSDavid du Colombier  * memory is set aside at startup time to cover the needs of queuing a
527dd7cddfSDavid du Colombier  * partial page to the renderer. The renderer operates out of a fixed
537dd7cddfSDavid du Colombier  * memory space; that way, it can always complete rendering pages with
547dd7cddfSDavid du Colombier  * the memory it has. To this end, the writer protects the renderer
557dd7cddfSDavid du Colombier  * from consuming unbounded amounts of memory by a) never putting
567dd7cddfSDavid du Colombier  * complex paths into the command list, b) pre-clipping any output
577dd7cddfSDavid du Colombier  * unless the clip path consists of a single rectangle, c) never putting
587dd7cddfSDavid du Colombier  * high-level images into the clip path unless the image in question
597dd7cddfSDavid du Colombier  * meets some very stringent requirements, such as only being rotated by
607dd7cddfSDavid du Colombier  * even multiples of 90 degrees and having source-image data rows which
617dd7cddfSDavid du Colombier  * fit into the command buffer in one piece. These restrictions are what
627dd7cddfSDavid du Colombier  * dictate the "restricted bandlist format."
637dd7cddfSDavid du Colombier 
647dd7cddfSDavid du Colombier  * Note that the renderer's instance of the device driver uses the
657dd7cddfSDavid du Colombier  * renderer's memory. That implies that it must also operate in a small,
667dd7cddfSDavid du Colombier  * fixed amount of memory, and must do all memory allocation using the
677dd7cddfSDavid du Colombier  * memory allocator pointed to by the render device's ->memory member.
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier  * Opening the Device
707dd7cddfSDavid du Colombier  * ------------------
717dd7cddfSDavid du Colombier  * The writer instance is opened first. This occurs when the system
727dd7cddfSDavid du Colombier  * calls the "standard" open procedure via the device's procedure
737dd7cddfSDavid du Colombier  * vector. The driver must implement the open function, but must call
747dd7cddfSDavid du Colombier  * down to gdev_prn_async_write_open instead of calling down to
757dd7cddfSDavid du Colombier  * gdev_prn_open. Before calling down to gdev_prn_async_write_open, the
767dd7cddfSDavid du Colombier  * driver must:
777dd7cddfSDavid du Colombier  *  a - init several procedure vectors, to wit: start_render_thread,
787dd7cddfSDavid du Colombier  *      buffer_page, print_page_copies,
797dd7cddfSDavid du Colombier  *  b - init space_params.band.BandWidth, space_params.band.BandHeight,
807dd7cddfSDavid du Colombier  *      space_params.BufferSpace (see extended comments in gdevasyn.c
817dd7cddfSDavid du Colombier  *      for details on computing appropriate values).
827dd7cddfSDavid du Colombier  *  c - if it implements those functions, the driver must init the
837dd7cddfSDavid du Colombier  *      procedure vectors for: put_params, get_hardware_params,
847dd7cddfSDavid du Colombier  *      output_page, open_render_device.
857dd7cddfSDavid du Colombier  * Notice that there are two procedure vectors: the usual std_procs, and
867dd7cddfSDavid du Colombier  * the printer-specific printer_procs.
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier  * Since partial page support imposes extra requirements on drivers,
897dd7cddfSDavid du Colombier  * such support can be disabled by zeroing out (in the async writer open
907dd7cddfSDavid du Colombier  * routine, after calling down to gdev_prn_async_write_open) the
917dd7cddfSDavid du Colombier  * free_up_bandlist_memory member of the driver structure. Doing so
927dd7cddfSDavid du Colombier  * will, of course, cause interpretation to fail if memory runs out.
937dd7cddfSDavid du Colombier 
947dd7cddfSDavid du Colombier  * Once the driver calls down to gdev_prn_async_write_open, the async
957dd7cddfSDavid du Colombier  * support logic will create a second instance of the driver for
967dd7cddfSDavid du Colombier  * rendering, but will not open it just yet. Instead, the async logic
977dd7cddfSDavid du Colombier  * will attempt to synchronize the two device instances.
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier  * Synchrnonizing the instances
1007dd7cddfSDavid du Colombier  * ----------------------------
1017dd7cddfSDavid du Colombier  * While still in the gdev_prn_async_write_open routine, the async logic
1027dd7cddfSDavid du Colombier  * will call printer_procs.start_render_thread (which the driver is
1037dd7cddfSDavid du Colombier  * required to implement). start_render_thread must somehow either start a new
1047dd7cddfSDavid du Colombier  * thread or rendez-vous with an existing thread for use in rendering,
1057dd7cddfSDavid du Colombier  * then return. start_render_thread must also have caused the render thread
1067dd7cddfSDavid du Colombier  * to call gdev_prn_async_render_thread, passing it as an argument a magic
1077dd7cddfSDavid du Colombier  * cookie passed to start_render_thread. start_render_thread will only
1087dd7cddfSDavid du Colombier  * return once the device has been closed and all renering has been
1097dd7cddfSDavid du Colombier  * completed.
1107dd7cddfSDavid du Colombier 
1117dd7cddfSDavid du Colombier  * The render device will be opened on the render device's thread, by
1127dd7cddfSDavid du Colombier  * calling printer_procs.open_render_device.
1137dd7cddfSDavid du Colombier 
1147dd7cddfSDavid du Colombier  * Rendering Operation
1157dd7cddfSDavid du Colombier  * -------------------
1167dd7cddfSDavid du Colombier  * During rendering, the device will not see rendering operations -- the
1177dd7cddfSDavid du Colombier  * first "rendering" operations the driver will see is when the renderer
1187dd7cddfSDavid du Colombier  * instance's print_page_copies or buffer_page routines get called. In
1197dd7cddfSDavid du Colombier  * both cases, the appropriate routine must then perform get_bits calls
1207dd7cddfSDavid du Colombier  * on the async logic in order to retrieve rendered bits, then transmit
1217dd7cddfSDavid du Colombier  * them to the appropriate device buffers.
1227dd7cddfSDavid du Colombier 
1237dd7cddfSDavid du Colombier  * The complication that is introduced is that which is related to partial
1247dd7cddfSDavid du Colombier  * pages: A buffer_page call instructs the driver to grab the rendered bits,
1257dd7cddfSDavid du Colombier  * but to keep the rendered bits available for later instead of marking on
1267dd7cddfSDavid du Colombier  * media. This implies that a buffer_page call opens a context where
1277dd7cddfSDavid du Colombier  * subsequent buffer_page's and print_page_copies' must first initialize the
1287dd7cddfSDavid du Colombier  * rendering buffers with the previous rendering results before calling
1297dd7cddfSDavid du Colombier  * get_bits. The first print_page_copies closes the context that was opened
1307dd7cddfSDavid du Colombier  * by the initial buffer_page -- the driver must go back to normal rendering
1317dd7cddfSDavid du Colombier  * until a new buffer_page comes along.
1327dd7cddfSDavid du Colombier  */
1337dd7cddfSDavid du Colombier 
1347dd7cddfSDavid du Colombier /* -------------- Type declarations --------------- */
1357dd7cddfSDavid du Colombier 
1367dd7cddfSDavid du Colombier /* typedef is in gdevprn.h */
1377dd7cddfSDavid du Colombier /* typedef struct gdev_prn_start_render_params_s gdev_prn_start_render_params;*/
1387dd7cddfSDavid du Colombier struct gdev_prn_start_render_params_s {
1397dd7cddfSDavid du Colombier     gx_device_printer *writer_device;/* writer dev that points to render dev */
1407dd7cddfSDavid du Colombier     gx_semaphore_t *open_semaphore;	/* signal this once open_code is set */
1417dd7cddfSDavid du Colombier     int open_code;		/* RETURNS status of open of reader device */
1427dd7cddfSDavid du Colombier };
1437dd7cddfSDavid du Colombier 
1447dd7cddfSDavid du Colombier /* -------- Macros used to initialize render-specific structures ------ */
1457dd7cddfSDavid du Colombier 
1467dd7cddfSDavid du Colombier #define init_async_render_procs(xpdev, xstart_render_thread,\
1477dd7cddfSDavid du Colombier 				xbuffer_page, xprint_page_copies)\
1487dd7cddfSDavid du Colombier   BEGIN\
1497dd7cddfSDavid du Colombier     (xpdev)->printer_procs.start_render_thread = (xstart_render_thread);\
1507dd7cddfSDavid du Colombier     (xpdev)->printer_procs.buffer_page = (xbuffer_page);\
1517dd7cddfSDavid du Colombier     (xpdev)->printer_procs.print_page_copies = (xprint_page_copies);\
1527dd7cddfSDavid du Colombier   END
1537dd7cddfSDavid du Colombier 
1547dd7cddfSDavid du Colombier /* -------------- Global procedure declarations --------- */
1557dd7cddfSDavid du Colombier 
1567dd7cddfSDavid du Colombier /* Open this printer device in ASYNC (overlapped) mode.
1577dd7cddfSDavid du Colombier  *
1587dd7cddfSDavid du Colombier  * This routine is always called by the concrete device's xx_open routine
1597dd7cddfSDavid du Colombier  * in lieu of gdev_prn_open.
1607dd7cddfSDavid du Colombier  */
161*593dc095SDavid du Colombier int gdev_prn_async_write_open(gx_device_printer *pdev, int max_raster,
162*593dc095SDavid du Colombier 			      int min_band_height, int max_src_image_row);
1637dd7cddfSDavid du Colombier 
1647dd7cddfSDavid du Colombier /* Open the render portion of a printer device in ASYNC (overlapped) mode.
1657dd7cddfSDavid du Colombier  *
1667dd7cddfSDavid du Colombier  * This routine is always called by concrete device's xx_open_render_device
1677dd7cddfSDavid du Colombier  * in lieu of gdev_prn_open.
1687dd7cddfSDavid du Colombier  */
169*593dc095SDavid du Colombier int gdev_prn_async_render_open(gx_device_printer *prdev);
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier /*
1727dd7cddfSDavid du Colombier  * Must be called by async device driver implementation (see
1737dd7cddfSDavid du Colombier  * gdevprna.h under "Synchronizing the Instances"). This is the
1747dd7cddfSDavid du Colombier  * rendering loop, which requires its own thread for as long as
1757dd7cddfSDavid du Colombier  * the device is open. This proc only returns after the device is closed.
1767dd7cddfSDavid du Colombier  */
1777dd7cddfSDavid du Colombier int	/* rets 0 ok, -ve error code */
178*593dc095SDavid du Colombier gdev_prn_async_render_thread(gdev_prn_start_render_params *);
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier #endif				/* gdevprna_INCLUDED */
181