blob: 9621a1f4b50a2285ada9bca905780515e30c5ad9 [file] [log] [blame]
/*
* Copyright 2017 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can
* be found in the LICENSE file.
*
*/
//
// NOTES:
//
// - this particular object only needs a command queue for a short
// time so consider acquiring/releasing the command queue on demand
// but only if command queues are cached and expensive to keep
//
#include "common/cl/assert_cl.h"
#include "styling_cl_12.h"
#include "extent_cl_12.h"
#include "runtime_cl_12.h"
#include "context.h"
#include "styling_types.h"
//
//
//
static
void
skc_styling_unmap_complete(skc_grid_t const grid)
{
struct skc_styling_impl * const impl = skc_grid_get_data(grid);
impl->state = SKC_STYLING_STATE_SEALED;
skc_grid_complete(grid);
}
static
void
skc_styling_unmap_cb(cl_event event, cl_int status, skc_grid_t const grid)
{
SKC_CL_CB(status);
struct skc_styling_impl * const impl = skc_grid_get_data(grid);
struct skc_scheduler * const scheduler = impl->runtime->scheduler;
// as quickly as possible, enqueue next stage in pipeline to context command scheduler
SKC_SCHEDULER_SCHEDULE(scheduler,skc_styling_unmap_complete,grid);
}
static
void
skc_styling_grid_pfn_execute(skc_grid_t const grid)
{
struct skc_styling_impl * const impl = skc_grid_get_data(grid);
struct skc_styling * const styling = impl->styling;
//
// unmap all extents
//
cl_event complete;
skc_extent_phwN_pdrN_unmap(&impl->layers,styling->layers.extent,impl->cq,NULL);
skc_extent_phwN_pdrN_unmap(&impl->groups,styling->groups.extent,impl->cq,NULL);
skc_extent_phwN_pdrN_unmap(&impl->extras,styling->extras.extent,impl->cq,&complete);
// set the event
cl(SetEventCallback(complete,CL_COMPLETE,skc_styling_unmap_cb,grid));
cl(ReleaseEvent(complete));
// flush command queue
cl(Flush(impl->cq));
}
//
//
//
static
void
skc_styling_pfn_seal(struct skc_styling_impl * const impl)
{
// return if sealing or sealed
if (impl->state >= SKC_STYLING_STATE_SEALING)
return;
struct skc_runtime * const runtime = impl->runtime;
struct skc_scheduler * const scheduler = runtime->scheduler;
//
// otherwise, wait for UNSEALING > UNSEALED transition
//
if (impl->state == SKC_STYLING_STATE_UNSEALING)
{
SKC_SCHEDULER_WAIT_WHILE(scheduler,impl->state != SKC_STYLING_STATE_UNSEALED);
}
//
// we're unsealed so we need to seal and start the grid
//
impl->state = SKC_STYLING_STATE_SEALING;
impl->grid = SKC_GRID_DEPS_ATTACH(runtime->deps,
NULL,
impl,
NULL, // no waiting
skc_styling_grid_pfn_execute,
NULL); // no dispose
// no need to force -- styling has no dependencies
skc_grid_start(impl->grid);
}
//
//
//
void
skc_styling_unseal_complete(struct skc_styling_impl * const impl)
{
struct skc_runtime * const runtime = impl->runtime;
// we're now unsealed
impl->state = SKC_STYLING_STATE_UNSEALED;
}
static
void
skc_styling_unseal_cb(cl_event event, cl_int status, struct skc_styling_impl * const impl)
{
SKC_CL_CB(status);
// as quickly as possible, enqueue next stage in pipeline to context command scheduler
SKC_SCHEDULER_SCHEDULE(impl->runtime->scheduler,skc_styling_unseal_complete,impl);
}
static
void
skc_styling_pfn_unseal(struct skc_styling_impl * const impl, skc_bool const block)
{
// return if already unsealed
if (impl->state == SKC_STYLING_STATE_UNSEALED)
return;
//
// otherwise, we're going to need to pump the scheduler
//
struct skc_runtime * const runtime = impl->runtime;
struct skc_scheduler * const scheduler = runtime->scheduler;
//
// wait for UNSEALING > UNSEALED transition
//
if (impl->state == SKC_STYLING_STATE_UNSEALING)
{
if (block) {
SKC_SCHEDULER_WAIT_WHILE(scheduler,impl->state != SKC_STYLING_STATE_UNSEALED);
}
return;
}
//
// otherwise, wait for SEALING > SEALED transition ...
//
if (impl->state == SKC_STYLING_STATE_SEALING)
{
// wait if sealing
SKC_SCHEDULER_WAIT_WHILE(scheduler,impl->state != SKC_STYLING_STATE_SEALED);
}
// wait for rendering locks to be released
SKC_SCHEDULER_WAIT_WHILE(scheduler,impl->lock_count > 0);
// ... and then unseal the styling object
impl->state = SKC_STYLING_STATE_UNSEALING;
// defensively NULL the grid reference
impl->grid = NULL; // defensive
// set styling pointers with mapped extents
cl_event complete;
struct skc_styling * const styling = impl->styling;
styling->layers.extent = skc_extent_phwN_pdrN_map(&impl->layers,impl->cq,NULL);
styling->groups.extent = skc_extent_phwN_pdrN_map(&impl->groups,impl->cq,NULL);
styling->extras.extent = skc_extent_phwN_pdrN_map(&impl->extras,impl->cq,&complete);
cl(SetEventCallback(complete,CL_COMPLETE,skc_styling_unseal_cb,impl));
cl(ReleaseEvent(complete));
// flush it
cl(Flush(impl->cq));
// wait until unsealed...
if (block) {
SKC_SCHEDULER_WAIT_WHILE(scheduler,impl->state != SKC_STYLING_STATE_UNSEALED);
}
}
//
//
//
static
void
skc_styling_pfn_release(struct skc_styling_impl * const impl)
{
if (--impl->styling->ref_count != 0)
return;
//
// otherwise, unmap all resources
//
//
// FIXME -- is it pointless unmap before freeing? The seal
// accomplishes the unmapping.
//
skc_styling_pfn_seal(impl);
struct skc_runtime * const runtime = impl->runtime;
struct skc_scheduler * const scheduler = runtime->scheduler;
// wait until sealed
SKC_SCHEDULER_WAIT_WHILE(scheduler,impl->state != SKC_STYLING_STATE_SEALED);
// wait for locks to drain
SKC_SCHEDULER_WAIT_WHILE(scheduler,impl->lock_count > 0)
//
// styling is now disposable
//
// free styling host
skc_runtime_host_perm_free(runtime,impl->styling);
// release the cq
skc_runtime_release_cq_in_order(runtime,impl->cq);
// free extents
skc_extent_phwN_pdrN_free(runtime,&impl->layers);
skc_extent_phwN_pdrN_free(runtime,&impl->groups);
skc_extent_phwN_pdrN_free(runtime,&impl->extras);
// free styling impl
skc_runtime_host_perm_free(runtime,impl);
}
//
//
//
void
skc_styling_retain_and_lock(struct skc_styling * const styling)
{
skc_styling_retain(styling);
styling->impl->lock_count += 1;
}
void
skc_styling_unlock_and_release(struct skc_styling * const styling)
{
styling->impl->lock_count -= 1;
skc_styling_pfn_release(styling->impl);
}
//
//
//
skc_err
skc_styling_cl_12_create(struct skc_context * const context,
struct skc_styling * * const styling,
skc_uint const layers_count,
skc_uint const groups_count,
skc_uint const extras_count)
{
// retain the context
// skc_context_retain(context);
// allocate the impl
struct skc_runtime * const runtime = context->runtime;
struct skc_styling_impl * const impl = skc_runtime_host_perm_alloc(runtime,SKC_MEM_FLAGS_READ_WRITE,sizeof(*impl));
// allocate styling
(*styling) = skc_runtime_host_perm_alloc(runtime,SKC_MEM_FLAGS_READ_WRITE,sizeof(**styling));
(*styling)->context = context;
(*styling)->impl = impl;
// intialize impl
impl->styling = (*styling);
impl->runtime = runtime;
SKC_ASSERT_STATE_INIT(impl,SKC_STYLING_STATE_SEALED);
impl->lock_count = 0;
impl->cq = skc_runtime_acquire_cq_in_order(runtime);
//
// The styling object is unique in that the API lets the user
// specify resource limits
//
// The styling object is a simple container that can have wildly
// varying resource requirements (but still relatively modest).
//
// Additionally, an advanced SKC programmer may want to create many
// styling and composition objects as they're relatively cheap.
//
skc_extent_phwN_pdrN_alloc(runtime,&impl->layers,sizeof(*(*styling)->layers.extent) * layers_count);
skc_extent_phwN_pdrN_alloc(runtime,&impl->groups,sizeof(*(*styling)->groups.extent) * groups_count);
skc_extent_phwN_pdrN_alloc(runtime,&impl->extras,sizeof(*(*styling)->extras.extent) * extras_count);
// initialize styling
(*styling)->layers.size = layers_count;
(*styling)->groups.size = groups_count;
(*styling)->extras.size = extras_count;
(*styling)->layers.count = 0;
(*styling)->groups.count = 0;
(*styling)->extras.count = 0;
// save pfns
(*styling)->seal = skc_styling_pfn_seal;
(*styling)->unseal = skc_styling_pfn_unseal;
(*styling)->release = skc_styling_pfn_release;
// set ref count
(*styling)->ref_count = 1;
// map the extents by unsealing
skc_styling_pfn_unseal(impl,false);
return SKC_ERR_SUCCESS;
}
//
//
//