swr: Implement fence attached work queues for deferred deletion.

Work can now be added to fences and triggered by fence completion. This
allows for deferred resource deletion, and other asynchronous tasks.

Reviewed-by: George Kyriazis <george.kyriazis@intel.com>
This commit is contained in:
Bruce Cherniak 2016-12-12 19:24:59 -06:00 committed by Tim Rowley
parent 3421b3f5a3
commit 79b66ec05e
9 changed files with 256 additions and 55 deletions

View file

@ -42,6 +42,8 @@ CXX_SOURCES := \
swr_memory.h \
swr_fence.h \
swr_fence.cpp \
swr_fence_work.h \
swr_fence_work.cpp \
swr_query.h \
swr_query.cpp

View file

@ -355,9 +355,6 @@ swr_destroy(struct pipe_context *pipe)
if (ctx->blitter)
util_blitter_destroy(ctx->blitter);
/* Idle core before deleting context */
SwrWaitForIdle(ctx->swrContext);
for (unsigned i = 0; i < PIPE_MAX_COLOR_BUFS; i++) {
pipe_surface_reference(&ctx->framebuffer.cbufs[i], NULL);
}
@ -372,6 +369,10 @@ swr_destroy(struct pipe_context *pipe)
pipe_sampler_view_reference(&ctx->sampler_views[PIPE_SHADER_VERTEX][i], NULL);
}
/* Idle core after destroying buffer resources, but before deleting
* context. Destroying resources has potentially called StoreTiles.*/
SwrWaitForIdle(ctx->swrContext);
if (ctx->swrContext)
SwrDestroyContext(ctx->swrContext);

View file

@ -38,10 +38,13 @@
* to SwrSync call.
*/
static void
swr_sync_cb(uint64_t userData, uint64_t userData2, uint64_t userData3)
swr_fence_cb(uint64_t userData, uint64_t userData2, uint64_t userData3)
{
struct swr_fence *fence = (struct swr_fence *)userData;
/* Complete all work attached to the fence */
swr_fence_do_work(fence);
/* Correct value is in SwrSync data, and not the fence write field. */
fence->read = userData2;
}
@ -56,7 +59,7 @@ swr_fence_submit(struct swr_context *ctx, struct pipe_fence_handle *fh)
fence->write++;
fence->pending = TRUE;
SwrSync(ctx->swrContext, swr_sync_cb, (uint64_t)fence, fence->write, 0);
SwrSync(ctx->swrContext, swr_fence_cb, (uint64_t)fence, fence->write, 0);
}
/*
@ -72,6 +75,7 @@ swr_fence_create()
pipe_reference_init(&fence->reference, 1);
fence->id = fence_id++;
fence->work.tail = &fence->work.head;
return (struct pipe_fence_handle *)fence;
}
@ -80,6 +84,8 @@ swr_fence_create()
static void
swr_fence_destroy(struct swr_fence *fence)
{
/* Complete any work left if fence was not submitted */
swr_fence_do_work(fence);
FREE(fence);
}
@ -101,8 +107,10 @@ swr_fence_reference(struct pipe_screen *screen,
old = NULL;
}
if (pipe_reference(&old->reference, &fence->reference))
if (pipe_reference(&old->reference, &fence->reference)) {
swr_fence_finish(screen, NULL, (struct pipe_fence_handle *) old, 0);
swr_fence_destroy(old);
}
}

View file

@ -25,6 +25,8 @@
#include "pipe/p_state.h"
#include "util/u_inlines.h"
#include "swr_fence_work.h"
struct pipe_screen;
struct swr_fence {
@ -36,6 +38,12 @@ struct swr_fence {
unsigned pending;
unsigned id; /* Just for reference */
struct {
uint32_t count;
struct swr_fence_work head;
struct swr_fence_work *tail;
} work;
};

View file

@ -0,0 +1,148 @@
/****************************************************************************
* Copyright (C) 2016 Intel Corporation. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
***************************************************************************/
#include "swr_context.h"
#include "swr_fence.h"
#include "util/u_inlines.h"
#include "util/u_memory.h"
/*
* Called by swr_fence_cb to complete the work queue
*/
void
swr_fence_do_work(struct swr_fence *fence)
{
struct swr_fence_work *work, *tmp;
if (fence->work.head.next) {
work = fence->work.head.next;
/* Immediately clear the head so any new work gets added to a new work
* queue */
p_atomic_set(&fence->work.head.next, nullptr);
p_atomic_set(&fence->work.tail, &fence->work.head);
p_atomic_set(&fence->work.count, 0);
do {
tmp = work->next;
work->callback(work);
FREE(work);
work = tmp;
} while(work);
}
}
/*
* Called by one of the specialized work routines below
*/
static inline void
swr_add_fence_work(struct pipe_fence_handle *fh,
struct swr_fence_work *work)
{
/* If no fence, just do the work now */
if (!fh) {
work->callback(work);
FREE(work);
return;
}
struct swr_fence *fence = swr_fence(fh);
p_atomic_set(&fence->work.tail->next, work);
p_atomic_set(&fence->work.tail, work);
p_atomic_inc(&fence->work.count);
}
/*
* Generic free/free_aligned, and delete vs/fs
*/
template<bool aligned_free>
static void
swr_free_cb(struct swr_fence_work *work)
{
if (aligned_free)
AlignedFree(work->free.data);
else
FREE(work->free.data);
}
static void
swr_delete_vs_cb(struct swr_fence_work *work)
{
delete work->free.swr_vs;
}
static void
swr_delete_fs_cb(struct swr_fence_work *work)
{
delete work->free.swr_fs;
}
bool
swr_fence_work_free(struct pipe_fence_handle *fence, void *data,
bool aligned_free)
{
struct swr_fence_work *work = CALLOC_STRUCT(swr_fence_work);
if (!work)
return false;
if (aligned_free)
work->callback = swr_free_cb<true>;
else
work->callback = swr_free_cb<false>;
work->free.data = data;
swr_add_fence_work(fence, work);
return true;
}
bool
swr_fence_work_delete_vs(struct pipe_fence_handle *fence,
struct swr_vertex_shader *swr_vs)
{
struct swr_fence_work *work = CALLOC_STRUCT(swr_fence_work);
if (!work)
return false;
work->callback = swr_delete_vs_cb;
work->free.swr_vs = swr_vs;
swr_add_fence_work(fence, work);
return true;
}
bool
swr_fence_work_delete_fs(struct pipe_fence_handle *fence,
struct swr_fragment_shader *swr_fs)
{
struct swr_fence_work *work = CALLOC_STRUCT(swr_fence_work);
if (!work)
return false;
work->callback = swr_delete_fs_cb;
work->free.swr_fs = swr_fs;
swr_add_fence_work(fence, work);
return true;
}

View file

@ -0,0 +1,47 @@
/****************************************************************************
* Copyright (C) 2016 Intel Corporation. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
***************************************************************************/
#ifndef SWR_FENCE_WORK_H
#define SWR_FENCE_WORK_H
typedef void(*SWR_WORK_CALLBACK_FUNC)(struct swr_fence_work *work);
struct swr_fence_work {
SWR_WORK_CALLBACK_FUNC callback;
union {
void *data;
struct swr_vertex_shader *swr_vs;
struct swr_fragment_shader *swr_fs;
} free;
struct swr_fence_work *next;
};
void swr_fence_do_work(struct swr_fence *fence);
bool swr_fence_work_free(struct pipe_fence_handle *fence, void *data,
bool aligned_free = false);
bool swr_fence_work_delete_vs(struct pipe_fence_handle *fence,
struct swr_vertex_shader *swr_vs);
bool swr_fence_work_delete_fs(struct pipe_fence_handle *fence,
struct swr_fragment_shader *swr_vs);
#endif

View file

@ -23,7 +23,9 @@
#include "util/u_memory.h"
#include "swr_context.h"
#include "swr_screen.h"
#include "swr_scratch.h"
#include "swr_fence_work.h"
#include "api.h"
@ -46,18 +48,18 @@ swr_copy_to_scratch_space(struct swr_context *ctx,
/* Need to grow space */
if (max_size_in_flight > space->current_size) {
/* Must idle the pipeline, this is infrequent */
SwrWaitForIdle(ctx->swrContext);
space->current_size = max_size_in_flight;
if (space->base) {
align_free(space->base);
/* defer delete, use aligned-free */
struct swr_screen *screen = swr_screen(ctx->pipe.screen);
swr_fence_work_free(screen->flush_fence, space->base, true);
space->base = NULL;
}
if (!space->base) {
space->base = (uint8_t *)align_malloc(space->current_size, 4);
space->base = (uint8_t *)AlignedMalloc(space->current_size,
sizeof(void *));
space->head = (void *)space->base;
}
}
@ -65,14 +67,6 @@ swr_copy_to_scratch_space(struct swr_context *ctx,
/* Wrap */
if (((uint8_t *)space->head + size)
>= ((uint8_t *)space->base + space->current_size)) {
/*
* TODO XXX: Should add a fence on wrap. Assumption is that
* current_space >> size, and there are at least MAX_DRAWS_IN_FLIGHT
* draws in scratch. So fence would always be met on wrap. A fence
* would ensure that first frame in buffer is done before wrapping.
* If fence ever needs to be waited on, can increase buffer size.
* So far in testing, this hasn't been necessary.
*/
space->head = space->base;
}
@ -103,14 +97,10 @@ swr_destroy_scratch_buffers(struct swr_context *ctx)
struct swr_scratch_buffers *scratch = ctx->scratch;
if (scratch) {
if (scratch->vs_constants.base)
align_free(scratch->vs_constants.base);
if (scratch->fs_constants.base)
align_free(scratch->fs_constants.base);
if (scratch->vertex_buffer.base)
align_free(scratch->vertex_buffer.base);
if (scratch->index_buffer.base)
align_free(scratch->index_buffer.base);
AlignedFree(scratch->vs_constants.base);
AlignedFree(scratch->fs_constants.base);
AlignedFree(scratch->vertex_buffer.base);
AlignedFree(scratch->index_buffer.base);
FREE(scratch);
}
}

View file

@ -869,29 +869,28 @@ swr_resource_destroy(struct pipe_screen *p_screen, struct pipe_resource *pt)
struct swr_resource *spr = swr_resource(pt);
struct pipe_context *pipe = screen->pipe;
/* Only wait on fence if the resource is being used */
if (pipe && spr->status) {
/* But, if there's no fence pending, submit one.
* XXX: Remove once draw timestamps are implmented. */
if (!swr_is_fence_pending(screen->flush_fence))
swr_fence_submit(swr_context(pipe), screen->flush_fence);
swr_fence_finish(p_screen, NULL, screen->flush_fence, 0);
swr_resource_unused(pt);
}
/*
* Free resource primary surface. If resource is display target, winsys
* manages the buffer and will free it on displaytarget_destroy.
*/
if (spr->display_target) {
/* display target */
/* If resource is display target, winsys manages the buffer and will
* free it on displaytarget_destroy. */
swr_fence_finish(p_screen, NULL, screen->flush_fence, 0);
struct sw_winsys *winsys = screen->winsys;
winsys->displaytarget_destroy(winsys, spr->display_target);
} else
AlignedFree(spr->swr.pBaseAddress);
AlignedFree(spr->secondary.pBaseAddress);
} else {
/* For regular resources, if the resource is being used, defer deletion
* (use aligned-free) */
if (pipe && spr->status) {
swr_resource_unused(pt);
swr_fence_work_free(screen->flush_fence,
spr->swr.pBaseAddress, true);
swr_fence_work_free(screen->flush_fence,
spr->secondary.pBaseAddress, true);
} else {
AlignedFree(spr->swr.pBaseAddress);
AlignedFree(spr->secondary.pBaseAddress);
}
}
FREE(spr);
}

View file

@ -372,10 +372,9 @@ swr_delete_vs_state(struct pipe_context *pipe, void *vs)
struct swr_vertex_shader *swr_vs = (swr_vertex_shader *)vs;
FREE((void *)swr_vs->pipe.tokens);
struct swr_screen *screen = swr_screen(pipe->screen);
if (!swr_is_fence_pending(screen->flush_fence))
swr_fence_submit(swr_context(pipe), screen->flush_fence);
swr_fence_finish(pipe->screen, NULL, screen->flush_fence, 0);
delete swr_vs;
/* Defer deletion of vs state */
swr_fence_work_delete_vs(screen->flush_fence, swr_vs);
}
static void *
@ -412,10 +411,9 @@ swr_delete_fs_state(struct pipe_context *pipe, void *fs)
struct swr_fragment_shader *swr_fs = (swr_fragment_shader *)fs;
FREE((void *)swr_fs->pipe.tokens);
struct swr_screen *screen = swr_screen(pipe->screen);
if (!swr_is_fence_pending(screen->flush_fence))
swr_fence_submit(swr_context(pipe), screen->flush_fence);
swr_fence_finish(pipe->screen, NULL, screen->flush_fence, 0);
delete swr_fs;
/* Defer deleton of fs state */
swr_fence_work_delete_fs(screen->flush_fence, swr_fs);
}
@ -912,7 +910,7 @@ swr_update_derived(struct pipe_context *pipe,
const struct pipe_draw_info *p_draw_info)
{
struct swr_context *ctx = swr_context(pipe);
struct swr_screen *screen = swr_screen(ctx->pipe.screen);
struct swr_screen *screen = swr_screen(pipe->screen);
/* Update screen->pipe to current pipe context. */
if (screen->pipe != pipe)