[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, &params);
 }
 
@@ -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