[Mesa-dev] [PATCH 16/16] nine: Implement threadpool
David Heidelberger
david.heidelberger at ixit.cz
Sat Oct 18 04:55:06 PDT 2014
From: Axel Davy <axel.davy at ens.fr>
Useful for PRIME setups.
Signed-off-by: Axel Davy <axel.davy at ens.fr>
Signed-off-by: David Heidelberger <david.heidelberger at ixit.cz>
---
include/d3dadapter/present.h | 7 +-
src/gallium/state_trackers/nine/Makefile.am | 1 +
src/gallium/state_trackers/nine/adapter9.h | 1 +
src/gallium/state_trackers/nine/swapchain9.c | 111 +++++++++----
src/gallium/state_trackers/nine/swapchain9.h | 7 +
src/gallium/state_trackers/nine/threadpool.c | 202 ++++++++++++++++++++++++
src/gallium/state_trackers/nine/threadpool.h | 55 +++++++
src/gallium/targets/d3dadapter9/drm.c | 16 +-
src/mesa/drivers/dri/common/xmlpool/t_options.h | 5 +
9 files changed, 368 insertions(+), 37 deletions(-)
create mode 100644 src/gallium/state_trackers/nine/threadpool.c
create mode 100644 src/gallium/state_trackers/nine/threadpool.h
diff --git a/include/d3dadapter/present.h b/include/d3dadapter/present.h
index c302638..803513d 100644
--- a/include/d3dadapter/present.h
+++ b/include/d3dadapter/present.h
@@ -56,9 +56,7 @@ typedef struct ID3DPresentVtbl
/* After presenting a buffer to the window system, the buffer
* may be used as is (no copy of the content) by the window system.
* You must not use a non-released buffer, else the user may see undefined content. */
- HRESULT (WINAPI *IsBufferReleased)(ID3DPresent *This, D3DWindowBuffer *buffer, BOOL *bReleased);
- /* It is possible buffers are not released in order */
- HRESULT (WINAPI *WaitOneBufferReleased)(ID3DPresent *This);
+ HRESULT (WINAPI *WaitBufferReleased)(ID3DPresent *This, D3DWindowBuffer *buffer);
HRESULT (WINAPI *FrontBufferCopy)(ID3DPresent *This, D3DWindowBuffer *buffer);
/* It is possible to do partial copy, but impossible to do resizing, which must
* be done by the client after checking the front buffer size */
@@ -88,8 +86,7 @@ struct ID3DPresent
#define ID3DPresent_SetPresentParameters(p,a) (p)->lpVtbl->SetPresentParameters(p,a)
#define ID3DPresent_NewD3DWindowBufferFromDmaBuf(p,a,b,c,d,e,f,g) (p)->lpVtbl->NewD3DWindowBufferFromDmaBuf(p,a,b,c,d,e,f,g)
#define ID3DPresent_DestroyD3DWindowBuffer(p,a) (p)->lpVtbl->DestroyD3DWindowBuffer(p,a)
-#define ID3DPresent_IsBufferReleased(p,a,b) (p)->lpVtbl->IsBufferReleased(p,a,b)
-#define ID3DPresent_WaitOneBufferReleased(p) (p)->lpVtbl->WaitOneBufferReleased(p)
+#define ID3DPresent_WaitBufferReleased(p,a) (p)->lpVtbl->WaitBufferReleased(p,a)
#define ID3DPresent_FrontBufferCopy(p,a) (p)->lpVtbl->FrontBufferCopy(p,a)
#define ID3DPresent_PresentBuffer(p,a,b,c,d,e,f) (p)->lpVtbl->PresentBuffer(p,a,b,c,d,e,f)
#define ID3DPresent_GetRasterStatus(p,a) (p)->lpVtbl->GetRasterStatus(p,a)
diff --git a/src/gallium/state_trackers/nine/Makefile.am b/src/gallium/state_trackers/nine/Makefile.am
index c8d5bdb..6018ab6 100644
--- a/src/gallium/state_trackers/nine/Makefile.am
+++ b/src/gallium/state_trackers/nine/Makefile.am
@@ -37,6 +37,7 @@ libninetracker_la_SOURCES = \
swapchain9.c \
swapchain9ex.c \
texture9.c \
+ threadpool.c \
vertexbuffer9.c \
vertexdeclaration9.c \
vertexshader9.c \
diff --git a/src/gallium/state_trackers/nine/adapter9.h b/src/gallium/state_trackers/nine/adapter9.h
index c0fe14c..4522c99 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 vsync_force;
+ 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 3195cc6..ea95cef 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)
@@ -69,6 +71,7 @@ NineSwapChain9_ctor( struct NineSwapChain9 *This,
params.hDeviceWindow = hFocusWindow;
This->rendering_done = FALSE;
+ This->pool = NULL;
return NineSwapChain9_Resize(This, ¶ms);
}
@@ -217,6 +220,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;
@@ -434,6 +452,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]));
@@ -532,6 +553,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,
@@ -634,21 +689,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;
@@ -664,8 +724,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);
@@ -699,6 +759,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:
@@ -714,28 +779,12 @@ NineSwapChain9_Present( struct NineSwapChain9 *This,
/* XXX not implemented */
break;
}
- /* Because d3d9 has a render ahead queue,
- * we either copy right away the buffer on the screen,
- * or we schedule flips with never more than 1 buffer
- * per vblank. With standard X Present extension we should always
- * have This->buffers[0] released here (it means the server has
- * finished all work with it). However slightly different behaviour
- * can occur in the future when Present will allow the compositor
- * to manage what happens, or with XWayland.
- * Then wait here This->buffers[0] is released.
- * However in Copy mode we'll ignore if the buffer is released,
- * since if the buffer is used for flip it might never be released.
- * The Copy mode will have tearings, but that's expected
- * Note: the Copy mode doesn't render to the buffer presented,
- * it only copies to it. Thus we can't have glitches here. Only tearings.*/
- if (This->params.SwapEffect != D3DSWAPEFFECT_COPY) {
- ID3DPresent_IsBufferReleased(This->present, This->present_handles[0], &released);
- while (!released) {
- UNTESTED(6);
- ID3DPresent_WaitOneBufferReleased(This->present);
- ID3DPresent_IsBufferReleased(This->present, This->present_handles[0], &released);
- }
- }
+
+ 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;
nine_update_state(This->base.device, NINE_STATE_FB);
diff --git a/src/gallium/state_trackers/nine/swapchain9.h b/src/gallium/state_trackers/nine/swapchain9.h
index 8d42462..b9fda62 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;
@@ -67,7 +69,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 0000000..2979fc7
--- /dev/null
+++ b/src/gallium/state_trackers/nine/threadpool.c
@@ -0,0 +1,202 @@
+/*
+ * 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));
+ struct sched_param sched_param;
+ pthread_attr_t attr;
+ int s;
+
+ if (!pool)
+ return NULL;
+
+ pthread_mutex_init(&pool->m, NULL);
+ pthread_cond_init(&pool->new_work, NULL);
+
+ /* we use only one thread to allow the execution order predictable.
+ * We put maximum priority on it */
+ s = pthread_attr_init(&attr);
+ if (!s) {
+ s |= pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+ s |= pthread_attr_setschedpolicy(&attr, SCHED_RR);
+ sched_param.sched_priority = 99;
+ s |= pthread_attr_setschedparam(&attr, &sched_param);
+ if (s != 0)
+ pthread_attr_destroy(&attr);
+ }
+ if (s != 0)
+ pthread_create(&pool->thread, NULL, threadpool_worker, pool);
+ else {
+ pthread_create(&pool->thread, &attr, threadpool_worker, pool);
+ pthread_attr_destroy(&attr);
+ }
+
+ 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 0000000..00ad25e
--- /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 c1af702..fbd3b80 100644
--- a/src/gallium/targets/d3dadapter9/drm.c
+++ b/src/gallium/targets/d3dadapter9/drm.c
@@ -55,6 +55,7 @@ DRI_CONF_BEGIN
DRI_CONF_SECTION_NINE
DRI_CONF_NINE_VSYNC(0)
DRI_CONF_NINE_THROTTLE(-2)
+ DRI_CONF_NINE_THREADSUBMIT("false")
DRI_CONF_SECTION_END
DRI_CONF_END;
@@ -236,7 +237,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;
const char *paths[] = {
getenv("D3D9_DRIVERS_PATH"),
@@ -304,6 +305,19 @@ drm_create_adapter( int fd,
if (driCheckOption(&userInitOptions, "vsync_force", DRI_ENUM))
ctx->base.vsync_force = driQueryOptioni(&userInitOptions, "vsync_force");
+ 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 e93341b..5bf7aab 100644
--- a/src/mesa/drivers/dri/common/xmlpool/t_options.h
+++ b/src/mesa/drivers/dri/common/xmlpool/t_options.h
@@ -362,3 +362,8 @@ DRI_CONF_OPT_END
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 additionnal thread to submit buffers.")) \
+DRI_CONF_OPT_END
--
2.1.2
More information about the mesa-dev
mailing list