aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gallium/state_trackers/nine/Makefile.sources2
-rw-r--r--src/gallium/state_trackers/nine/adapter9.h1
-rw-r--r--src/gallium/state_trackers/nine/swapchain9.c86
-rw-r--r--src/gallium/state_trackers/nine/swapchain9.h7
-rw-r--r--src/gallium/state_trackers/nine/threadpool.c183
-rw-r--r--src/gallium/state_trackers/nine/threadpool.h55
-rw-r--r--src/gallium/targets/d3dadapter9/drm.c16
-rw-r--r--src/mesa/drivers/dri/common/xmlpool/t_options.h5
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