diff options
-rw-r--r-- | src/gallium/state_trackers/nine/Makefile.sources | 2 | ||||
-rw-r--r-- | src/gallium/state_trackers/nine/adapter9.h | 1 | ||||
-rw-r--r-- | src/gallium/state_trackers/nine/swapchain9.c | 86 | ||||
-rw-r--r-- | src/gallium/state_trackers/nine/swapchain9.h | 7 | ||||
-rw-r--r-- | src/gallium/state_trackers/nine/threadpool.c | 183 | ||||
-rw-r--r-- | src/gallium/state_trackers/nine/threadpool.h | 55 | ||||
-rw-r--r-- | src/gallium/targets/d3dadapter9/drm.c | 16 | ||||
-rw-r--r-- | src/mesa/drivers/dri/common/xmlpool/t_options.h | 5 |
8 files changed, 345 insertions, 10 deletions
diff --git a/src/gallium/state_trackers/nine/Makefile.sources b/src/gallium/state_trackers/nine/Makefile.sources index b8219613f6c..99b623a5b59 100644 --- a/src/gallium/state_trackers/nine/Makefile.sources +++ b/src/gallium/state_trackers/nine/Makefile.sources @@ -59,6 +59,8 @@ C_SOURCES := \ swapchain9.h \ texture9.c \ texture9.h \ + threadpool.c \ + threadpool.h \ vertexbuffer9.c \ vertexbuffer9.h \ vertexdeclaration9.c \ diff --git a/src/gallium/state_trackers/nine/adapter9.h b/src/gallium/state_trackers/nine/adapter9.h index 4db4f3cfd53..df85b2dcc28 100644 --- a/src/gallium/state_trackers/nine/adapter9.h +++ b/src/gallium/state_trackers/nine/adapter9.h @@ -38,6 +38,7 @@ struct d3dadapter9_context BOOL throttling; int throttling_value; int vblank_mode; + BOOL thread_submit; void (*destroy)( struct d3dadapter9_context *ctx ); }; diff --git a/src/gallium/state_trackers/nine/swapchain9.c b/src/gallium/state_trackers/nine/swapchain9.c index ce92a3a8966..b6f5ef65782 100644 --- a/src/gallium/state_trackers/nine/swapchain9.c +++ b/src/gallium/state_trackers/nine/swapchain9.c @@ -33,6 +33,8 @@ #include "hud/hud_context.h" #include "state_tracker/drm_driver.h" +#include "threadpool.h" + #define DBG_CHANNEL DBG_SWAPCHAIN #define UNTESTED(n) DBG("UNTESTED point %d. Please tell if it worked\n", n) @@ -70,6 +72,7 @@ NineSwapChain9_ctor( struct NineSwapChain9 *This, pPresentationParameters->hDeviceWindow = hFocusWindow; This->rendering_done = FALSE; + This->pool = NULL; return NineSwapChain9_Resize(This, pPresentationParameters, mode); } @@ -227,6 +230,21 @@ NineSwapChain9_Resize( struct NineSwapChain9 *This, desc.Width = pParams->BackBufferWidth; desc.Height = pParams->BackBufferHeight; + if (This->pool) { + _mesa_threadpool_destroy(This->pool); + This->pool = NULL; + } + This->enable_threadpool = This->actx->thread_submit && (pParams->SwapEffect != D3DSWAPEFFECT_COPY); + if (This->enable_threadpool) + This->pool = _mesa_threadpool_create(); + if (!This->pool) + This->enable_threadpool = FALSE; + + This->tasks = REALLOC(This->tasks, + oldBufferCount * sizeof(struct threadpool_task *), + newBufferCount * sizeof(struct threadpool_task *)); + memset(This->tasks, 0, newBufferCount * sizeof(struct threadpool_task *)); + for (i = 0; i < oldBufferCount; i++) { ID3DPresent_DestroyD3DWindowBuffer(This->present, This->present_handles[i]); This->present_handles[i] = NULL; @@ -444,6 +462,9 @@ NineSwapChain9_dtor( struct NineSwapChain9 *This ) DBG("This=%p\n", This); + if (This->pool) + _mesa_threadpool_destroy(This->pool); + if (This->buffers) { for (i = 0; i < This->params.BackBufferCount; i++) { NineUnknown_Destroy(NineUnknown(This->buffers[i])); @@ -541,6 +562,40 @@ handle_draw_cursor_and_hud( struct NineSwapChain9 *This, struct pipe_resource *r } } +struct end_present_struct { + struct pipe_screen *screen; + struct pipe_fence_handle *fence_to_wait; + ID3DPresent *present; + D3DWindowBuffer *present_handle; + HWND hDestWindowOverride; +}; + +static void work_present(void *data) +{ + struct end_present_struct *work = data; + if (work->fence_to_wait) { + (void) work->screen->fence_finish(work->screen, work->fence_to_wait, PIPE_TIMEOUT_INFINITE); + work->screen->fence_reference(work->screen, &(work->fence_to_wait), NULL); + } + ID3DPresent_PresentBuffer(work->present, work->present_handle, work->hDestWindowOverride, NULL, NULL, NULL, 0); + free(work); +} + +static void pend_present(struct NineSwapChain9 *This, + HWND hDestWindowOverride) +{ + struct end_present_struct *work = calloc(1, sizeof(struct end_present_struct)); + + work->screen = This->screen; + work->fence_to_wait = swap_fences_pop_front(This); + work->present = This->present; + work->present_handle = This->present_handles[0]; + work->hDestWindowOverride = hDestWindowOverride; + This->tasks[0] = _mesa_threadpool_queue_task(This->pool, work_present, work); + + return; +} + static INLINE HRESULT present( struct NineSwapChain9 *This, const RECT *pSourceRect, @@ -642,21 +697,26 @@ bypass_rendering: return D3DERR_WASSTILLDRAWING; } - fence = swap_fences_pop_front(This); - if (fence) { - (void) This->screen->fence_finish(This->screen, fence, PIPE_TIMEOUT_INFINITE); - This->screen->fence_reference(This->screen, &fence, NULL); - } - if (This->present_buffers) resource = This->present_buffers[0]; else resource = This->buffers[0]->base.resource; This->pipe->flush_resource(This->pipe, resource); - hr = ID3DPresent_PresentBuffer(This->present, This->present_handles[0], hDestWindowOverride, pSourceRect, pDestRect, pDirtyRegion, dwFlags); - if (FAILED(hr)) { UNTESTED(3);return hr; } + if (!This->enable_threadpool) { + This->tasks[0]=NULL; + fence = swap_fences_pop_front(This); + if (fence) { + (void) This->screen->fence_finish(This->screen, fence, PIPE_TIMEOUT_INFINITE); + This->screen->fence_reference(This->screen, &fence, NULL); + } + + hr = ID3DPresent_PresentBuffer(This->present, This->present_handles[0], hDestWindowOverride, pSourceRect, pDestRect, pDirtyRegion, dwFlags); + if (FAILED(hr)) { UNTESTED(3);return hr; } + } else { + pend_present(This, hDestWindowOverride); + } This->rendering_done = FALSE; return D3D_OK; @@ -672,8 +732,8 @@ NineSwapChain9_Present( struct NineSwapChain9 *This, { struct pipe_resource *res = NULL; D3DWindowBuffer *handle_temp; + struct threadpool_task *task_temp; int i; - BOOL released; HRESULT hr = present(This, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, dwFlags); @@ -707,6 +767,11 @@ NineSwapChain9_Present( struct NineSwapChain9 *This, This->present_handles[i-1] = This->present_handles[i]; } This->present_handles[This->params.BackBufferCount] = handle_temp; + task_temp = This->tasks[0]; + for (i = 1; i <= This->params.BackBufferCount; i++) { + This->tasks[i-1] = This->tasks[i]; + } + This->tasks[This->params.BackBufferCount] = task_temp; break; case D3DSWAPEFFECT_COPY: @@ -723,6 +788,9 @@ NineSwapChain9_Present( struct NineSwapChain9 *This, break; } + if (This->tasks[0]) + _mesa_threadpool_wait_for_task(This->pool, &(This->tasks[0])); + ID3DPresent_WaitBufferReleased(This->present, This->present_handles[0]); This->base.device->state.changed.group |= NINE_STATE_FB; diff --git a/src/gallium/state_trackers/nine/swapchain9.h b/src/gallium/state_trackers/nine/swapchain9.h index 566f78ab0ed..2afd6ab2954 100644 --- a/src/gallium/state_trackers/nine/swapchain9.h +++ b/src/gallium/state_trackers/nine/swapchain9.h @@ -28,6 +28,8 @@ #include "d3dadapter/d3dadapter9.h" +#include "threadpool.h" + struct NineDevice9; struct NineSurface9; struct nine_winsys_swapchain; @@ -68,7 +70,12 @@ struct NineSwapChain9 struct NineSurface9 *zsbuf; D3DGAMMARAMP gamma; + + struct threadpool *pool; + struct threadpool_task **tasks; + BOOL enable_threadpool; }; + static INLINE struct NineSwapChain9 * NineSwapChain9( void *data ) { diff --git a/src/gallium/state_trackers/nine/threadpool.c b/src/gallium/state_trackers/nine/threadpool.c new file mode 100644 index 00000000000..2a965374305 --- /dev/null +++ b/src/gallium/state_trackers/nine/threadpool.c @@ -0,0 +1,183 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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 "swapchain9.h" +#include "surface9.h" +#include "device9.h" + +#include "nine_helpers.h" +#include "nine_pipe.h" +#include "nine_dump.h" + +#include "util/u_inlines.h" +#include "util/u_surface.h" +#include "hud/hud_context.h" +#include "state_tracker/drm_driver.h" + +#include "os/os_thread.h" +#include "threadpool.h" + +static void * +threadpool_worker(void *data) +{ + struct threadpool *pool = data; + + pthread_mutex_lock(&pool->m); + + while (!pool->shutdown) { + struct threadpool_task *task; + + /* Block (dropping the lock) until new work arrives for us. */ + while (!pool->workqueue && !pool->shutdown) + pthread_cond_wait(&pool->new_work, &pool->m); + + if (pool->shutdown) { + pthread_mutex_unlock(&pool->m); + return NULL; + } + + /* Pull the first task from the list. We don't free it -- it now lacks + * a reference other than the worker creator's, whose responsibility it + * is to call threadpool_wait_for_work() to free it. + */ + task = pool->workqueue; + pool->workqueue = task->next; + + /* Call the task's work func. */ + pthread_mutex_unlock(&pool->m); + task->work(task->data); + pthread_mutex_lock(&pool->m); + task->finished = TRUE; + pthread_cond_broadcast(&task->finish); + } + + pthread_mutex_unlock(&pool->m); + + return NULL; +} + +struct threadpool * +_mesa_threadpool_create(void) +{ + struct threadpool *pool = calloc(1, sizeof(*pool)); + + if (!pool) + return NULL; + + pthread_mutex_init(&pool->m, NULL); + pthread_cond_init(&pool->new_work, NULL); + + pthread_create(&pool->thread, NULL, threadpool_worker, pool); + + return pool; +} + +void +_mesa_threadpool_destroy(struct threadpool *pool) +{ + if (!pool) + return; + + pthread_mutex_lock(&pool->m); + pool->shutdown = TRUE; + pthread_cond_broadcast(&pool->new_work); + pthread_mutex_unlock(&pool->m); + + pthread_join(pool->thread, NULL); + + pthread_cond_destroy(&pool->new_work); + pthread_mutex_destroy(&pool->m); + free(pool); +} + +/** + * Queues a request for the work function to be asynchronously executed by the + * thread pool. + * + * The work func will get the "data" argument as its parameter -- any + * communication between the caller and the work function will occur through + * that. + * + * If there is an error, the work function is called immediately and NULL is + * returned. + */ +struct threadpool_task * +_mesa_threadpool_queue_task(struct threadpool *pool, + threadpool_task_func work, void *data) +{ + struct threadpool_task *task, *previous; + + if (!pool) { + work(data); + return NULL; + } + + task = calloc(1, sizeof(*task)); + if (!task) { + work(data); + return NULL; + } + + task->work = work; + task->data = data; + task->next = NULL; + pthread_cond_init(&task->finish, NULL); + + pthread_mutex_lock(&pool->m); + + if (!pool->workqueue) { + pool->workqueue = task; + } else { + previous = pool->workqueue; + while (previous && previous->next) + previous = previous->next; + + previous->next = task; + } + pthread_cond_signal(&pool->new_work); + pthread_mutex_unlock(&pool->m); + + return task; +} + +/** + * Blocks on the completion of the given task and frees the task. + */ +void +_mesa_threadpool_wait_for_task(struct threadpool *pool, + struct threadpool_task **task_handle) +{ + struct threadpool_task *task = *task_handle; + + if (!pool || !task) + return; + + pthread_mutex_lock(&pool->m); + while (!task->finished) + pthread_cond_wait(&task->finish, &pool->m); + pthread_mutex_unlock(&pool->m); + + pthread_cond_destroy(&task->finish); + free(task); + *task_handle = NULL; +} diff --git a/src/gallium/state_trackers/nine/threadpool.h b/src/gallium/state_trackers/nine/threadpool.h new file mode 100644 index 00000000000..00ad25e1b13 --- /dev/null +++ b/src/gallium/state_trackers/nine/threadpool.h @@ -0,0 +1,55 @@ +/* + * Copyright © 2012 Intel Corporation + * + * 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. + */ + +#ifndef _THREADPOOL_H_ +#define _THREADPOOL_H_ + +#define MAXTHREADS 1 + +struct threadpool { + pthread_mutex_t m; + pthread_cond_t new_work; + + pthread_t thread; + struct threadpool_task *workqueue; + BOOL shutdown; +}; + +typedef void (*threadpool_task_func)(void *data); + +struct threadpool_task { + threadpool_task_func work; + void *data; + struct threadpool_task *next; + pthread_cond_t finish; + BOOL finished; +}; + +struct threadpool *_mesa_threadpool_create(void); +void _mesa_threadpool_destroy(struct threadpool *pool); +struct threadpool_task *_mesa_threadpool_queue_task(struct threadpool *pool, + threadpool_task_func func, + void *data); +void _mesa_threadpool_wait_for_task(struct threadpool *pool, + struct threadpool_task **task); +#endif
\ No newline at end of file diff --git a/src/gallium/targets/d3dadapter9/drm.c b/src/gallium/targets/d3dadapter9/drm.c index a58e16715c0..dd916f1ea73 100644 --- a/src/gallium/targets/d3dadapter9/drm.c +++ b/src/gallium/targets/d3dadapter9/drm.c @@ -59,6 +59,7 @@ DRI_CONF_BEGIN DRI_CONF_SECTION_END DRI_CONF_SECTION_NINE DRI_CONF_NINE_THROTTLE(-2) + DRI_CONF_NINE_THREADSUBMIT("false") DRI_CONF_SECTION_END DRI_CONF_END; @@ -244,7 +245,7 @@ drm_create_adapter( int fd, const struct drm_conf_ret *dmabuf_ret = NULL; driOptionCache defaultInitOptions; driOptionCache userInitOptions; - int throttling_value_user; + int throttling_value_user = -2; #if !GALLIUM_STATIC_TARGETS const char *paths[] = { @@ -322,6 +323,19 @@ drm_create_adapter( int fd, else ctx->base.vblank_mode = 1; + if (driCheckOption(&userInitOptions, "thread_submit", DRI_BOOL)) { + ctx->base.thread_submit = driQueryOptionb(&userInitOptions, "thread_submit"); + if (ctx->base.thread_submit && (throttling_value_user == -2 || throttling_value_user == 0)) { + ctx->base.throttling_value = 0; + } else if (ctx->base.thread_submit) { + DBG("You have set a non standard throttling value in combination with thread_submit." + "We advise to use a throttling value of -2/0"); + } + if (ctx->base.thread_submit && !different_device) + DBG("You have set thread_submit but do not use a different device than the server." + "You should not expect any benefit."); + } + driDestroyOptionCache(&userInitOptions); driDestroyOptionInfo(&defaultInitOptions); diff --git a/src/mesa/drivers/dri/common/xmlpool/t_options.h b/src/mesa/drivers/dri/common/xmlpool/t_options.h index e4f6937d455..4e5a7217ee2 100644 --- a/src/mesa/drivers/dri/common/xmlpool/t_options.h +++ b/src/mesa/drivers/dri/common/xmlpool/t_options.h @@ -353,3 +353,8 @@ DRI_CONF_SECTION_BEGIN \ DRI_CONF_OPT_BEGIN(throttle_value, int, def) \ DRI_CONF_DESC(en,gettext("Define the throttling value. -1 for no throttling, -2 for default (usually 2), 0 for glfinish behaviour")) \ DRI_CONF_OPT_END + +#define DRI_CONF_NINE_THREADSUBMIT(def) \ +DRI_CONF_OPT_BEGIN_B(thread_submit, def) \ + DRI_CONF_DESC(en,gettext("Use an additional thread to submit buffers.")) \ +DRI_CONF_OPT_END |