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