From 3af17a671d871e725967a74617e5adb2e985e6ef Mon Sep 17 00:00:00 2001 From: Patrick Rudolph Date: Tue, 25 Oct 2016 18:03:44 +0200 Subject: [PATCH] st/nine: Add nine_queue This queue mechanism will be used for CSMT. Signed-off-by: Patrick Rudolph --- .../state_trackers/nine/Makefile.sources | 2 + src/gallium/state_trackers/nine/nine_queue.c | 251 ++++++++++++++++++ src/gallium/state_trackers/nine/nine_queue.h | 48 ++++ 3 files changed, 301 insertions(+) create mode 100644 src/gallium/state_trackers/nine/nine_queue.c create mode 100644 src/gallium/state_trackers/nine/nine_queue.h diff --git a/src/gallium/state_trackers/nine/Makefile.sources b/src/gallium/state_trackers/nine/Makefile.sources index af80532ce37..12649087e7d 100644 --- a/src/gallium/state_trackers/nine/Makefile.sources +++ b/src/gallium/state_trackers/nine/Makefile.sources @@ -43,6 +43,8 @@ C_SOURCES := \ nine_pipe.h \ nine_quirk.c \ nine_quirk.h \ + nine_queue.c \ + nine_queue.h \ nine_shader.c \ nine_shader.h \ nine_state.c \ diff --git a/src/gallium/state_trackers/nine/nine_queue.c b/src/gallium/state_trackers/nine/nine_queue.c new file mode 100644 index 00000000000..31f9ce77ca8 --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_queue.c @@ -0,0 +1,251 @@ +/* + * Copyright 2016 Patrick Rudolph + * + * 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS 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 "nine_queue.h" +#include "os/os_thread.h" +#include "util/macros.h" +#include "nine_helpers.h" + +#define NINE_CMD_BUF_INSTR (256) + +#define NINE_CMD_BUFS (32) +#define NINE_CMD_BUFS_MASK (NINE_CMD_BUFS - 1) + +#define NINE_QUEUE_SIZE (8192 * 16 + 128) + +#define DBG_CHANNEL DBG_DEVICE + +/* + * Single producer - single consumer pool queue + * + * Producer: + * Calls nine_queue_alloc to get a slice of memory in current cmdbuf. + * Calls nine_queue_flush to flush the queue by request. + * The queue is flushed automatically on insufficient space or once the + * cmdbuf contains NINE_CMD_BUF_INSTR instructions. + * + * nine_queue_flush does block, while nine_queue_alloc doesn't block. + * + * nine_queue_alloc returns NULL on insufficent space. + * + * Consumer: + * Calls nine_queue_wait_flush to wait for a cmdbuf. + * After waiting for a cmdbuf it calls nine_queue_get until NULL is returned. + * + * nine_queue_wait_flush does block, while nine_queue_get doesn't block. + * + * Constrains: + * Only a single consumer and a single producer are supported. + * + */ + +struct nine_cmdbuf { + unsigned instr_size[NINE_CMD_BUF_INSTR]; + unsigned num_instr; + unsigned offset; + void *mem_pool; + BOOL full; +}; + +struct nine_queue_pool { + struct nine_cmdbuf pool[NINE_CMD_BUFS]; + unsigned head; + unsigned tail; + unsigned cur_instr; + BOOL worker_wait; + pipe_condvar event_pop; + pipe_condvar event_push; + pipe_mutex mutex_pop; + pipe_mutex mutex_push; +}; + +/* Consumer functions: */ +void +nine_queue_wait_flush(struct nine_queue_pool* ctx) +{ + struct nine_cmdbuf *cmdbuf = &ctx->pool[ctx->tail]; + + /* wait for cmdbuf full */ + pipe_mutex_lock(ctx->mutex_push); + while (!cmdbuf->full) + { + DBG("waiting for full cmdbuf\n"); + pipe_condvar_wait(ctx->event_push, ctx->mutex_push); + } + DBG("got cmdbuf=%p\n", cmdbuf); + pipe_mutex_unlock(ctx->mutex_push); + + cmdbuf->offset = 0; + ctx->cur_instr = 0; +} + +/* Gets a pointer to the next memory slice. + * Does not block. + * Returns NULL on empty cmdbuf. */ +void * +nine_queue_get(struct nine_queue_pool* ctx) +{ + struct nine_cmdbuf *cmdbuf = &ctx->pool[ctx->tail]; + unsigned offset; + + /* At this pointer there's always a cmdbuf. */ + + if (ctx->cur_instr == cmdbuf->num_instr) { + /* signal waiting producer */ + pipe_mutex_lock(ctx->mutex_pop); + DBG("freeing cmdbuf=%p\n", cmdbuf); + cmdbuf->full = 0; + pipe_condvar_signal(ctx->event_pop); + pipe_mutex_unlock(ctx->mutex_pop); + + ctx->tail = (ctx->tail + 1) & NINE_CMD_BUFS_MASK; + + return NULL; + } + + /* At this pointer there's always a cmdbuf with instruction to process. */ + offset = cmdbuf->offset; + cmdbuf->offset += cmdbuf->instr_size[ctx->cur_instr]; + ctx->cur_instr ++; + + return cmdbuf->mem_pool + offset; +} + +/* Producer functions: */ + +/* Flushes the queue. + * Moves the current cmdbuf to worker thread. + * Blocks until next cmdbuf is free. */ +void +nine_queue_flush(struct nine_queue_pool* ctx) +{ + struct nine_cmdbuf *cmdbuf = &ctx->pool[ctx->head]; + + DBG("flushing cmdbuf=%p instr=%d size=%d\n", + cmdbuf, cmdbuf->num_instr, cmdbuf->offset); + + /* signal waiting worker */ + pipe_mutex_lock(ctx->mutex_push); + cmdbuf->full = 1; + pipe_condvar_signal(ctx->event_push); + pipe_mutex_unlock(ctx->mutex_push); + + ctx->head = (ctx->head + 1) & NINE_CMD_BUFS_MASK; + + cmdbuf = &ctx->pool[ctx->head]; + + /* wait for queue empty */ + pipe_mutex_lock(ctx->mutex_pop); + while (cmdbuf->full) + { + DBG("waiting for empty cmdbuf\n"); + pipe_condvar_wait(ctx->event_pop, ctx->mutex_pop); + } + DBG("got empty cmdbuf=%p\n", cmdbuf); + pipe_mutex_unlock(ctx->mutex_pop); + cmdbuf->offset = 0; + cmdbuf->num_instr = 0; +} + +/* Gets a a pointer to slice of memory with size @space. + * Does block if queue is full. + * Returns NULL on @space > NINE_QUEUE_SIZE. */ +void * +nine_queue_alloc(struct nine_queue_pool* ctx, unsigned space) +{ + unsigned offset; + struct nine_cmdbuf *cmdbuf = &ctx->pool[ctx->head]; + + if (space > NINE_QUEUE_SIZE) + return NULL; + + /* at this pointer there's always a free queue available */ + + if ((cmdbuf->offset + space > NINE_QUEUE_SIZE) || + (cmdbuf->num_instr == NINE_CMD_BUF_INSTR)) { + + nine_queue_flush(ctx); + + cmdbuf = &ctx->pool[ctx->head]; + } + + DBG("cmdbuf=%p space=%d\n", cmdbuf, space); + + /* at this pointer there's always a free queue with sufficient space available */ + + offset = cmdbuf->offset; + cmdbuf->offset += space; + cmdbuf->instr_size[cmdbuf->num_instr] = space; + cmdbuf->num_instr ++; + + return cmdbuf->mem_pool + offset; +} + +struct nine_queue_pool* +nine_queue_create(void) +{ + unsigned i; + struct nine_queue_pool *ctx; + + ctx = CALLOC_STRUCT(nine_queue_pool); + if (!ctx) + goto failed; + + for (i = 0; i < NINE_CMD_BUFS; i++) { + ctx->pool[i].mem_pool = MALLOC(NINE_QUEUE_SIZE); + if (!ctx->pool[i].mem_pool) + goto failed; + } + + pipe_condvar_init(ctx->event_pop); + pipe_mutex_init(ctx->mutex_pop); + + pipe_condvar_init(ctx->event_push); + pipe_mutex_init(ctx->mutex_push); + + /* Block until first cmdbuf has been flushed. */ + ctx->worker_wait = TRUE; + + return ctx; +failed: + if (ctx) { + for (i = 0; i < NINE_CMD_BUFS; i++) { + if (ctx->pool[i].mem_pool) + FREE(ctx->pool[i].mem_pool); + } + FREE(ctx); + } + return NULL; +} + +void +nine_queue_delete(struct nine_queue_pool *ctx) +{ + unsigned i; + pipe_mutex_destroy(ctx->mutex_pop); + pipe_mutex_destroy(ctx->mutex_push); + + for (i = 0; i < NINE_CMD_BUFS; i++) + FREE(ctx->pool[i].mem_pool); + + FREE(ctx); +} diff --git a/src/gallium/state_trackers/nine/nine_queue.h b/src/gallium/state_trackers/nine/nine_queue.h new file mode 100644 index 00000000000..259978e842a --- /dev/null +++ b/src/gallium/state_trackers/nine/nine_queue.h @@ -0,0 +1,48 @@ +/* + * Copyright 2016 Patrick Rudolph + * + * 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 + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS 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 _NINE_QUEUE_H_ +#define _NINE_QUEUE_H_ + +#include "pipe/p_compiler.h" + +struct nine_queue_pool; + +void +nine_queue_wait_flush(struct nine_queue_pool* ctx); + +void * +nine_queue_get(struct nine_queue_pool* ctx); + +void +nine_queue_flush(struct nine_queue_pool* ctx); + +void * +nine_queue_alloc(struct nine_queue_pool* ctx, unsigned space); + +struct nine_queue_pool* +nine_queue_create(void); + +void +nine_queue_delete(struct nine_queue_pool *ctx); + +#endif /* _NINE_QUEUE_H_ */ -- 2.30.2