Exemple #1
0
static void
clist_render_thread(void *data)
{
    clist_render_thread_control_t *thread = (clist_render_thread_control_t *)data;
    gx_device *dev = thread->cdev;
    gx_device_clist *cldev = (gx_device_clist *)dev;
    gx_device_clist_reader *crdev = &cldev->reader;
    gx_device *bdev = thread->bdev;
    gs_int_rect band_rect;
    byte *mdata = crdev->data + crdev->page_tile_cache_size;
    uint raster = bitmap_raster(dev->width * dev->color_info.depth);
    int code;
    int band_height = crdev->page_band_height;
    int band = thread->band;
    int band_begin_line = band * band_height;
    int band_end_line = band_begin_line + band_height;
    int band_num_lines;
#ifdef DEBUG
    long starttime[2], endtime[2];

    gp_get_usertime(starttime);	/* thread start time */
#endif
    if (band_end_line > dev->height)
	band_end_line = dev->height;
    band_num_lines = band_end_line - band_begin_line;

    code = crdev->buf_procs.setup_buf_device
	    (bdev, mdata, raster, NULL, 0, band_num_lines, band_num_lines);
    band_rect.p.x = 0;
    band_rect.p.y = band_begin_line;
    band_rect.q.x = dev->width;
    band_rect.q.y = band_end_line;
    if (code >= 0)
	code = clist_render_rectangle(cldev, &band_rect, bdev, NULL, true);
    /* Reset the band boundaries now */
    crdev->ymin = band_begin_line;
    crdev->ymax = band_end_line;
    crdev->offset_map = NULL;
    if (code < 0)
	thread->status = code;		/* shouldn't happen */
    else
	thread->status = RENDER_THREAD_DONE;	/* OK */

#ifdef DEBUG
    gp_get_usertime(endtime);
    thread->cputime += (endtime[0] - starttime[0]) * 1000 +
	     (endtime[1] - starttime[1]) / 1000000;
#endif
    /*
     * Signal the semaphores. We signal the 'group' first since even if
     * the waiter is released on the group, it still needs to check
     * status on the thread
     */
    gx_semaphore_signal(thread->sema_group);
    gx_semaphore_signal(thread->sema_this);
}
/* After rendering page gotten w/gx_page_queue_dequeue, call this to ack */
void
gx_page_queue_finish_dequeue(
				gx_page_queue_entry_t * entry	/* entry that was retrieved to delete */
)
{
    gx_page_queue_t *queue = entry->queue;

    gx_monitor_enter(queue->monitor);
    if (queue->enable_render_done_signal) {
	queue->enable_render_done_signal = false;
	gx_semaphore_signal(queue->render_done_sema);
    }
    queue->dequeue_in_progress = false;

    /*
     * Delete the previously-allocated entry, do inside monitor in case
     * this is the reserve entry & is the only memory in the universe;
     * in that case gx_page_queue_add_page won't be looking for this
     * until the monitor is exited.
     * In this implementation of the page queue, clist and queue entries
     * are managed together, so free the clist just before freeing the entry.
     */
    gx_page_queue_entry_free_page_info(entry);
    gx_page_queue_entry_free(entry);

    gx_monitor_leave(queue->monitor);
}
void
gsicc_set_link_data(gsicc_link_t *icc_link, void *link_handle, void *contextptr,
               gsicc_hashlink_t hashcode, gx_monitor_t *lock, 
               bool includes_softproof, bool includes_devlink)
{
    gx_monitor_enter(lock);		/* lock the cache while changing data */
    icc_link->contextptr = contextptr;
    icc_link->link_handle = link_handle;
    icc_link->hashcode.link_hashcode = hashcode.link_hashcode;
    icc_link->hashcode.des_hash = hashcode.des_hash;
    icc_link->hashcode.src_hash = hashcode.src_hash;
    icc_link->hashcode.rend_hash = hashcode.rend_hash;
    icc_link->includes_softproof = includes_softproof;
    icc_link->includes_devlink = includes_devlink;
    if ( (hashcode.src_hash == hashcode.des_hash) &&
          !includes_softproof && !includes_devlink) {
        icc_link->is_identity = true;
    } else {
        icc_link->is_identity = false;
    }
    icc_link->valid = true;

    /* Now release any tasks/threads waiting for these contents */
    while (icc_link->num_waiting > 0) {
        gx_semaphore_signal(icc_link->wait);
        icc_link->num_waiting--;
    }
    gx_monitor_leave(lock);	/* done with updating, let everyone run */
}
/* Add an entry to page queue for rendering w/sync to renderer */
void
gx_page_queue_enqueue(
			 gx_page_queue_entry_t * entry	/* entry to add */
)
{
    gx_page_queue_t *queue = entry->queue;

    /* Add the goods to queue, & signal it */
    gx_page_queue_add_last(entry);
    gx_semaphore_signal(queue->render_req_sema);
}
Exemple #5
0
/* This may release elements waiting on a icc_link_cache slot */
void
gsicc_release_link(gsicc_link_t *icclink)
{
    gsicc_link_cache_t *icc_link_cache = icclink->icc_link_cache;

    gx_monitor_enter(icc_link_cache->lock);
    /* Decrement the reference count */
    if (--(icclink->ref_count) == 0) {

	gsicc_link_t *curr, *prev;


	/* Find link in cache, and move it to the end of the list.  */
	/* This way zero ref_count links are found LRU first	*/
	curr = icc_link_cache->head;
	prev = NULL;
	while (curr != icclink) {
	    prev = curr;
	    curr = curr->next;
	};
	if (prev == NULL) {
	    /* this link was the head */
	    icc_link_cache->head = curr->next;
	} else {
	    prev->next = curr->next;		/* de-link this one */
	}
	/* Find the first zero-ref entry on the list */
	curr = icc_link_cache->head;
	prev = NULL;
	while (curr != NULL && curr->ref_count > 0) {
	    prev = curr;
	    curr = curr->next;
	}
	/* Found where to link this one into the tail of the list */
	if (prev == NULL) {
	    icc_link_cache->head = icclink;
	    icclink->next = icc_link_cache->head->next;
	} else {
	    /* link this one in here */
	    prev->next = icclink;
	    icclink->next = curr;
	}

	/* now release any tasks waiting for a cache slot */
        while (icclink->icc_link_cache->num_waiting > 0) {
	    gx_semaphore_signal(icclink->icc_link_cache->wait);
	    icclink->icc_link_cache->num_waiting--;
        }
    }
    gx_monitor_leave(icc_link_cache->lock);
}
/*
 * Must be called by async device driver implementation (see gdevprna.h
 * under "Synchronizing the Instances"). This is the rendering loop, which
 * requires its own thread for as long as the device is open. This proc only
 * returns after the device is closed, or if the open failed. NB that an
 * open error leaves things in a state where the writer thread will not be
 * able to close since it's expecting the renderer to acknowledge its
 * requests before the writer can close.  Ergo, if this routine fails you'll
 * crash unless the caller fixes the problem & successfully retries this.
 */
int				/* rets 0 ok, -ve error code if open failed */
gdev_prn_async_render_thread(
                             gdev_prn_start_render_params * params
)
{
    gx_device_printer *const pwdev = params->writer_device;
    gx_device_printer *const prdev = pwdev->async_renderer;
    gx_page_queue_entry_t *entry;
    int code;

    /* Open device, but don't use default if user didn't override */
    if (prdev->printer_procs.open_render_device ==
          gx_default_open_render_device)
        code = gdev_prn_async_render_open(prdev);
    else
        code = (*prdev->printer_procs.open_render_device) (prdev);
    reinit_printer_into_renderer(prdev);

    /* The cmd list logic assumes reader's & writer's tile caches are same size */
    if (code >= 0 &&
          ((gx_device_clist *) pwdev)->writer.page_tile_cache_size !=
            ((gx_device_clist *) prdev)->writer.page_tile_cache_size) {
        gdev_prn_async_render_close_device(prdev);
        code = gs_note_error(gs_error_VMerror);
    }
    params->open_code = code;
    gx_semaphore_signal(params->open_semaphore);
    if (code < 0)
        return code;

    /* fake open, since not called by gs_opendevice */
    prdev->is_open = true;

    /* Successful open */
    while ((entry = gx_page_queue_start_dequeue(prdev->page_queue))
           && entry->action != GX_PAGE_QUEUE_ACTION_TERMINATE) {
        /* Force printer open again if it mysteriously closed. */
        /* This shouldn't ever happen, but... */
        if (!prdev->is_open) {
            if (prdev->printer_procs.open_render_device ==
                  gx_default_open_render_device)
                code = gdev_prn_async_render_open(prdev);
            else
                code = (*prdev->printer_procs.open_render_device) (prdev);
            reinit_printer_into_renderer(prdev);

            if (code >= 0) {
                prdev->is_open = true;
                gdev_prn_output_page((gx_device *) prdev, 0, true);
            }
        }
        if (prdev->is_open) {
            /* Force retrieved entry onto render device */
            ((gx_device_clist *) prdev)->common.page_info = entry->page_info;

            /* Set up device geometry */
            if (clist_setup_params((gx_device *) prdev) >= 0)
                /* Go this again, since setup_params may have trashed it */
                ((gx_device_clist *) prdev)->common.page_info = entry->page_info;

            /* Call appropriate renderer routine to deal w/buffer */
            /* Ignore status, since we don't know how to deal w/errors! */
            switch (entry->action) {

                case GX_PAGE_QUEUE_ACTION_FULL_PAGE:
                    (*dev_proc(prdev, output_page))((gx_device *) prdev,
                                                    entry->num_copies, true);
                    break;

                case GX_PAGE_QUEUE_ACTION_PARTIAL_PAGE:
                case GX_PAGE_QUEUE_ACTION_COPY_PAGE:
                    (*dev_proc(prdev, output_page))((gx_device *) prdev,
                                                    entry->num_copies, false);
                    break;
            }
            /*
             * gx_page_queue_finish_dequeue will close and free the band
             * list files, so we don't need to call clist_close_output_file.
             */
        }
        /* Finalize dequeue & free retrieved queue entry */
        gx_page_queue_finish_dequeue(entry);
    }

    /* Close device, but don't use default if user hasn't overriden. */
    /* Ignore status, since returning bad status means open failed */
    if (prdev->printer_procs.close_render_device ==
          gx_default_close_render_device)
        gdev_prn_async_render_close_device(prdev);
    else
        (*prdev->printer_procs.close_render_device)(prdev);

    /* undo fake open, since not called by gs_closedevice */
    prdev->is_open = false;

    /* Now that device is closed, acknowledge gx_page_queue_terminate */
    gx_page_queue_finish_dequeue(entry);

    return 0;
}
/* Get the replacement color management link.  It basically needs to store
   the number of components for the source so that we know what we are 
   coming from (e.g. RGB, CMYK, Gray) */
gsicc_link_t*
gsicc_rcm_get_link(const gs_imager_state *pis, gx_device *dev, 
                   gsicc_colorbuffer_t data_cs)
{
    gsicc_link_t *result;
    gsicc_hashlink_t hash;
    rcm_link_t *rcm_link;
    gs_memory_t *mem = dev->memory->non_gc_memory;
    const gx_cm_color_map_procs * cm_procs;
    bool pageneutralcolor = false;
    cmm_dev_profile_t *dev_profile;
    int code;

    /* Need to check if we need to monitor for color */
    if (dev != NULL ) {
        code = dev_proc(dev, get_profile)(dev,  &dev_profile);
        if (code < 0)
            return NULL;
        if (dev_profile != NULL) {
            pageneutralcolor = dev_profile->pageneutralcolor;
        }
     }

    /* If the cm_procs are forwarding due to the overprint device or other
       odd thing, drill down now and get the proper ones */
    if (fwd_uses_fwd_cmap_procs(dev)) {
        cm_procs = fwd_get_target_cmap_procs(dev);
    } else {
        cm_procs = get_color_mapping_procs_subclass(dev);
    }

    hash.rend_hash = gsCMM_REPLACE;
    hash.des_hash = dev->color_info.num_components;
    hash.src_hash = data_cs;
    hash.link_hashcode = data_cs + hash.des_hash * 256 + hash.rend_hash * 4096;

    /* Check the cache for a hit. */
    result = gsicc_findcachelink(hash, pis->icc_link_cache, false, false);
    if (result != NULL) {
        return result;
    }
    /* If not, then lets create a new one.  This may actually return a link if 
       another thread has already created it while we were trying to do so */ 
    if (gsicc_alloc_link_entry(pis->icc_link_cache, &result, hash, false, false)) 
        return result;

    if (result == NULL)
        return result;

    /* Now compute the link contents */
    /* Lock the cache as we alter the procs */
    gx_monitor_enter(pis->icc_link_cache->lock);	

    result->procs.map_buffer = gsicc_rcm_transform_color_buffer;
    result->procs.map_color = gsicc_rcm_transform_color;
    result->procs.free_link = gsicc_rcm_freelink;
    result->hashcode = hash;
    result->is_identity = false;
    rcm_link = (rcm_link_t *) gs_alloc_bytes(mem, sizeof(rcm_link_t),
                                               "gsicc_rcm_get_link");
    if (rcm_link == NULL)
        return NULL;
    result->link_handle = (void*) rcm_link;
    rcm_link->memory = mem;
    rcm_link->num_out = min(dev->color_info.num_components, 
                             GS_CLIENT_COLOR_MAX_COMPONENTS);
    rcm_link->data_cs_in = data_cs;
    rcm_link->cm_procs.map_cmyk = cm_procs->map_cmyk;
    rcm_link->cm_procs.map_rgb = cm_procs->map_rgb;
    rcm_link->cm_procs.map_gray = cm_procs->map_gray;

    switch (data_cs) {
        case gsGRAY:
            rcm_link->num_in = 1;
            break;
        case gsRGB:
        case gsCIELAB:
            rcm_link->num_in = 3;
            break;
        case gsCMYK:
            rcm_link->num_in = 4;
            break;
        default:
            result->procs.free_link(result);
            return NULL;
    }
    /* Likely set if we have something like a table or procs */    
    rcm_link->context = NULL;  

    result->num_input = rcm_link->num_in;
    result->num_output = rcm_link->num_out;
    result->link_handle = rcm_link;
    result->hashcode.link_hashcode = hash.link_hashcode;
    result->hashcode.des_hash = hash.des_hash;
    result->hashcode.src_hash = hash.src_hash;
    result->hashcode.rend_hash = hash.rend_hash;
    result->includes_softproof = false;
    result->includes_devlink = false;
    if (hash.src_hash == hash.des_hash) {
        result->is_identity = true;
    } else {
        result->is_identity = false;
    }
    result->valid = true;

    /* Set up for monitoring non gray color spaces */
    if (pageneutralcolor && data_cs != gsGRAY)
        gsicc_mcm_set_link(result);

    /* Now release any tasks/threads waiting for these contents */
    while (result->num_waiting > 0) {
        gx_semaphore_signal(result->wait);
        result->num_waiting--;
    }
    gx_monitor_leave(pis->icc_link_cache->lock);	/* done with updating, let everyone run */

    return result;
}