<p dir="ltr">The event doesn't limit the number of outstanding jobs. It's like a fence - you can wait for it or you don't. The limitation is that you must have exactly one event instance for each active job. util_queue_fence is a better name IMO. I don't plan to extend the feature set beyond that.</p>
<p dir="ltr">Marek </p>
<div class="gmail_quote">On Jun 14, 2016 1:26 PM, "Nicolai Hähnle" <<a href="mailto:nhaehnle@gmail.com">nhaehnle@gmail.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 13.06.2016 19:34, Marek Olšák wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
From: Marek Olšák <<a href="mailto:marek.olsak@amd.com" target="_blank">marek.olsak@amd.com</a>><br>
<br>
---<br>
  src/gallium/auxiliary/Makefile.sources        |   2 +<br>
  src/gallium/auxiliary/util/u_queue.c          | 129 ++++++++++++++++++++++++++<br>
  src/gallium/auxiliary/util/u_queue.h          |  80 ++++++++++++++++<br>
  src/gallium/winsys/amdgpu/drm/amdgpu_cs.c     |  23 ++---<br>
  src/gallium/winsys/amdgpu/drm/amdgpu_cs.h     |   4 +-<br>
  src/gallium/winsys/amdgpu/drm/amdgpu_winsys.c |  63 +------------<br>
  src/gallium/winsys/amdgpu/drm/amdgpu_winsys.h |  11 +--<br>
  7 files changed, 229 insertions(+), 83 deletions(-)<br>
  create mode 100644 src/gallium/auxiliary/util/u_queue.c<br>
  create mode 100644 src/gallium/auxiliary/util/u_queue.h<br>
<br>
diff --git a/src/gallium/auxiliary/Makefile.sources b/src/gallium/auxiliary/Makefile.sources<br>
index 7b3853e..ab58358 100644<br>
--- a/src/gallium/auxiliary/Makefile.sources<br>
+++ b/src/gallium/auxiliary/Makefile.sources<br>
@@ -274,6 +274,8 @@ C_SOURCES := \<br>
        util/u_pstipple.c \<br>
        util/u_pstipple.h \<br>
        util/u_pwr8.h \<br>
+       util/u_queue.c \<br>
+       util/u_queue.h \<br>
        util/u_range.h \<br>
        util/u_rect.h \<br>
        util/u_resource.c \<br>
diff --git a/src/gallium/auxiliary/util/u_queue.c b/src/gallium/auxiliary/util/u_queue.c<br>
new file mode 100644<br>
index 0000000..311b591<br>
--- /dev/null<br>
+++ b/src/gallium/auxiliary/util/u_queue.c<br>
@@ -0,0 +1,129 @@<br>
+/*<br>
+ * Copyright © 2016 Advanced Micro Devices, Inc.<br>
+ * All Rights Reserved.<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining<br>
+ * a copy of this software and associated documentation files (the<br>
+ * "Software"), to deal in the Software without restriction, including<br>
+ * without limitation the rights to use, copy, modify, merge, publish,<br>
+ * distribute, sub license, and/or sell copies of the Software, and to<br>
+ * permit persons to whom the Software is furnished to do so, subject to<br>
+ * the following conditions:<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,<br>
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES<br>
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND<br>
+ * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS<br>
+ * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,<br>
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE<br>
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the<br>
+ * next paragraph) shall be included in all copies or substantial portions<br>
+ * of the Software.<br>
+ */<br>
+<br>
+#include "u_queue.h"<br>
+<br>
+static PIPE_THREAD_ROUTINE(util_queue_thread_func, param)<br>
+{<br>
+   struct util_queue *queue = (struct util_queue*)param;<br>
+   unsigned i;<br>
+<br>
+   while (1) {<br>
+      struct util_queue_job job;<br>
+<br>
+      pipe_semaphore_wait(&queue->queued);<br>
+      if (queue->kill_thread)<br>
+         break;<br>
+<br>
+      pipe_mutex_lock(queue->lock);<br>
+      job = queue->jobs[0];<br>
+      for (i = 1; i < queue->num_jobs; i++)<br>
+         queue->jobs[i - 1] = queue->jobs[i];<br>
+      queue->jobs[--queue->num_jobs].job = NULL;<br>
+      pipe_mutex_unlock(queue->lock);<br>
+<br>
+      pipe_semaphore_signal(&queue->has_space);<br>
+<br>
+      if (job.job) {<br>
+         queue->execute_job(job.job);<br>
+         pipe_semaphore_signal(&job.event->done);<br>
+      }<br>
+   }<br>
+<br>
+   /* signal remaining jobs before terminating */<br>
+   pipe_mutex_lock(queue->lock);<br>
+   for (i = 0; i < queue->num_jobs; i++) {<br>
+      pipe_semaphore_signal(&queue->jobs[i].event->done);<br>
+      queue->jobs[i].job = NULL;<br>
+   }<br>
+   queue->num_jobs = 0;<br>
+   pipe_mutex_unlock(queue->lock);<br>
+   return 0;<br>
+}<br>
+<br>
+void<br>
+util_queue_init(struct util_queue *queue,<br>
+                void (*execute_job)(void *))<br>
+{<br>
+   memset(queue, 0, sizeof(*queue));<br>
+   queue->execute_job = execute_job;<br>
+   pipe_mutex_init(queue->lock);<br>
+   pipe_semaphore_init(&queue->has_space, ARRAY_SIZE(queue->jobs));<br>
+   pipe_semaphore_init(&queue->queued, 0);<br>
+   queue->thread = pipe_thread_create(util_queue_thread_func, queue);<br>
+}<br>
+<br>
+void<br>
+util_queue_destroy(struct util_queue *queue)<br>
+{<br>
+   queue->kill_thread = 1;<br>
+   pipe_semaphore_signal(&queue->queued);<br>
+   pipe_thread_wait(queue->thread);<br>
+   pipe_semaphore_destroy(&queue->has_space);<br>
+   pipe_semaphore_destroy(&queue->queued);<br>
+   pipe_mutex_destroy(queue->lock);<br>
+}<br>
+<br>
+void<br>
+util_queue_event_init(struct util_queue_event *event)<br>
+{<br>
+   pipe_semaphore_init(&event->done, 1);<br>
+}<br>
+<br>
+void<br>
+util_queue_event_destroy(struct util_queue_event *event)<br>
+{<br>
+   pipe_semaphore_destroy(&event->done);<br>
+}<br>
+<br>
+void<br>
+util_queue_add_job(struct util_queue *queue,<br>
+                   void *job,<br>
+                   struct util_queue_event *event)<br>
+{<br>
+   /* Set the semaphore to "busy". */<br>
+   pipe_semaphore_wait(&event->done);<br>
+<br>
+   /* if the queue is full, wait until there is space */<br>
+   pipe_semaphore_wait(&queue->has_space);<br>
+<br>
+   pipe_mutex_lock(queue->lock);<br>
+   assert(queue->num_jobs < ARRAY_SIZE(queue->jobs));<br>
+   queue->jobs[queue->num_jobs].job = job;<br>
+   queue->jobs[queue->num_jobs].event = event;<br>
+   queue->num_jobs++;<br>
+   pipe_mutex_unlock(queue->lock);<br>
+   pipe_semaphore_signal(&queue->queued);<br>
+}<br>
+<br>
+void<br>
+util_queue_job_wait(struct util_queue_event *event)<br>
+{<br>
+   /* wait and set the semaphore to "busy" */<br>
+   pipe_semaphore_wait(&event->done);<br>
+   /* set the semaphore to "idle" */<br>
+   pipe_semaphore_signal(&event->done);<br>
+}<br>
diff --git a/src/gallium/auxiliary/util/u_queue.h b/src/gallium/auxiliary/util/u_queue.h<br>
new file mode 100644<br>
index 0000000..b7c1f44<br>
--- /dev/null<br>
+++ b/src/gallium/auxiliary/util/u_queue.h<br>
@@ -0,0 +1,80 @@<br>
+/*<br>
+ * Copyright © 2016 Advanced Micro Devices, Inc.<br>
+ * All Rights Reserved.<br>
+ *<br>
+ * Permission is hereby granted, free of charge, to any person obtaining<br>
+ * a copy of this software and associated documentation files (the<br>
+ * "Software"), to deal in the Software without restriction, including<br>
+ * without limitation the rights to use, copy, modify, merge, publish,<br>
+ * distribute, sub license, and/or sell copies of the Software, and to<br>
+ * permit persons to whom the Software is furnished to do so, subject to<br>
+ * the following conditions:<br>
+ *<br>
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,<br>
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES<br>
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND<br>
+ * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS<br>
+ * AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER<br>
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,<br>
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE<br>
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.<br>
+ *<br>
+ * The above copyright notice and this permission notice (including the<br>
+ * next paragraph) shall be included in all copies or substantial portions<br>
+ * of the Software.<br>
+ */<br>
+<br>
+/* Job queue with execution in a separate thread.<br>
+ *<br>
+ * Jobs can be added from any thread. After that, the wait call can be used<br>
+ * to wait for completion of the job.<br>
+ */<br>
+<br>
+#ifndef U_QUEUE_H<br>
+#define U_QUEUE_H<br>
+<br>
+#include "os/os_thread.h"<br>
+<br>
+/* Job completion event.<br>
+ * Put this into your job structure.<br>
+ */<br>
+struct util_queue_event {<br>
+   pipe_semaphore done;<br>
+};<br>
+<br>
+struct util_queue_job {<br>
+   void *job;<br>
+   struct util_queue_event *event;<br>
+};<br>
+<br>
+/* Put this into your context. */<br>
+struct util_queue {<br>
+   pipe_mutex lock;<br>
+   pipe_semaphore has_space;<br>
+   pipe_semaphore queued;<br>
+   pipe_thread thread;<br>
+   int kill_thread;<br>
+   int num_jobs;<br>
+   struct util_queue_job jobs[8];<br>
+   void (*execute_job)(void *job);<br>
+};<br>
+<br>
+void util_queue_init(struct util_queue *queue,<br>
+                     void (*execute_job)(void *));<br>
+void util_queue_destroy(struct util_queue *queue);<br>
+void util_queue_event_init(struct util_queue_event *event);<br>
+void util_queue_event_destroy(struct util_queue_event *event);<br>
+<br>
+void util_queue_add_job(struct util_queue *queue,<br>
+                        void *job,<br>
+                        struct util_queue_event *event);<br>
+void util_queue_job_wait(struct util_queue_event *event);<br>
</blockquote>
<br>
I think the util_queue_event part of the interface is basically impossible to understand without knowledge of the code. It does two things:<br>
<br>
- limit the number of outstanding jobs<br>
- wait for outstanding jobs to finish<br>
<br>
I think it should be called util_queue_writer for this reason (or perhaps _submitter, but _writer is shorter):<br>
<br>
void util_queue_writer_init(struct util_queue_writer *writer);<br>
void util_queue_writer_destroy(struct util_queue_writer *writer);<br>
void util_queue_writer_wait(struct util_queue_writer *writer);<br>
<br>
void util_queue_add_job(struct util_queue *queue,<br>
                        struct util_queue_writer *writer,<br>
                        void *job);<br>
<br>
This would also logically allow a future extension where each writer can have multiple jobs outstanding. In that case, the _writer structure would live outside the job structure.<br>
<br>
[An alternative that occurs to me now is to rename util_queue_event to util_queue_job and expect users of this utility to use that as a "base struct" for their job structure. That would simplify util_queue_add_job to take only one parameter. I think both alternatives have some merit.]<br>
<br>
Nicolai<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+/* util_queue needs to be cleared to zeroes for this to work */<br>
+static inline bool<br>
+util_queue_is_initialized(struct util_queue *queue)<br>
+{<br>
+   return queue->thread != 0;<br>
+}<br>
+<br>
+#endif<br>
diff --git a/src/gallium/winsys/amdgpu/drm/amdgpu_cs.c b/src/gallium/winsys/amdgpu/drm/amdgpu_cs.c<br>
index fefa5d6..737f0c4 100644<br>
--- a/src/gallium/winsys/amdgpu/drm/amdgpu_cs.c<br>
+++ b/src/gallium/winsys/amdgpu/drm/amdgpu_cs.c<br>
@@ -605,7 +605,7 @@ amdgpu_cs_create(struct radeon_winsys_ctx *rwctx,<br>
        return NULL;<br>
     }<br>
<br>
-   pipe_semaphore_init(&cs->flush_completed, 1);<br>
+   util_queue_event_init(&cs->flush_completed);<br>
<br>
     cs->ctx = ctx;<br>
     cs->flush_cs = flush;<br>
@@ -872,8 +872,9 @@ static void amdgpu_add_fence_dependencies(struct amdgpu_cs *acs)<br>
     }<br>
  }<br>
<br>
-void amdgpu_cs_submit_ib(struct amdgpu_cs *acs)<br>
+void amdgpu_cs_submit_ib(void *job)<br>
  {<br>
+   struct amdgpu_cs *acs = (struct amdgpu_cs*)job;<br>
     struct amdgpu_winsys *ws = acs->ctx->ws;<br>
     struct amdgpu_cs_context *cs = acs->cst;<br>
     int i, r;<br>
@@ -957,14 +958,11 @@ cleanup:<br>
  void amdgpu_cs_sync_flush(struct radeon_winsys_cs *rcs)<br>
  {<br>
     struct amdgpu_cs *cs = amdgpu_cs(rcs);<br>
+   struct amdgpu_winsys *ws = cs->ctx->ws;<br>
<br>
     /* Wait for any pending ioctl of this CS to complete. */<br>
-   if (cs->ctx->ws->thread) {<br>
-      /* wait and set the semaphore to "busy" */<br>
-      pipe_semaphore_wait(&cs->flush_completed);<br>
-      /* set the semaphore to "idle" */<br>
-      pipe_semaphore_signal(&cs->flush_completed);<br>
-   }<br>
+   if (util_queue_is_initialized(&ws->cs_queue))<br>
+      util_queue_job_wait(&cs->flush_completed);<br>
  }<br>
<br>
  DEBUG_GET_ONCE_BOOL_OPTION(noop, "RADEON_NOOP", FALSE)<br>
@@ -1052,10 +1050,9 @@ static void amdgpu_cs_flush(struct radeon_winsys_cs *rcs,<br>
        cs->cst = cur;<br>
<br>
        /* Submit. */<br>
-      if (ws->thread && (flags & RADEON_FLUSH_ASYNC)) {<br>
-         /* Set the semaphore to "busy". */<br>
-         pipe_semaphore_wait(&cs->flush_completed);<br>
-         amdgpu_ws_queue_cs(ws, cs);<br>
+      if ((flags & RADEON_FLUSH_ASYNC) &&<br>
+          util_queue_is_initialized(&ws->cs_queue)) {<br>
+         util_queue_add_job(&ws->cs_queue, cs, &cs->flush_completed);<br>
        } else {<br>
           amdgpu_cs_submit_ib(cs);<br>
        }<br>
@@ -1077,7 +1074,7 @@ static void amdgpu_cs_destroy(struct radeon_winsys_cs *rcs)<br>
     struct amdgpu_cs *cs = amdgpu_cs(rcs);<br>
<br>
     amdgpu_cs_sync_flush(rcs);<br>
-   pipe_semaphore_destroy(&cs->flush_completed);<br>
+   util_queue_event_destroy(&cs->flush_completed);<br>
     p_atomic_dec(&cs->ctx->ws->num_cs);<br>
     pb_reference(&cs->main.big_ib_buffer, NULL);<br>
     FREE(cs->main.base.prev);<br>
diff --git a/src/gallium/winsys/amdgpu/drm/amdgpu_cs.h b/src/gallium/winsys/amdgpu/drm/amdgpu_cs.h<br>
index cc1516c..ff50345 100644<br>
--- a/src/gallium/winsys/amdgpu/drm/amdgpu_cs.h<br>
+++ b/src/gallium/winsys/amdgpu/drm/amdgpu_cs.h<br>
@@ -111,7 +111,7 @@ struct amdgpu_cs {<br>
     void (*flush_cs)(void *ctx, unsigned flags, struct pipe_fence_handle **fence);<br>
     void *flush_data;<br>
<br>
-   pipe_semaphore flush_completed;<br>
+   struct util_queue_event flush_completed;<br>
  };<br>
<br>
  struct amdgpu_fence {<br>
@@ -218,6 +218,6 @@ bool amdgpu_fence_wait(struct pipe_fence_handle *fence, uint64_t timeout,<br>
                         bool absolute);<br>
  void amdgpu_cs_sync_flush(struct radeon_winsys_cs *rcs);<br>
  void amdgpu_cs_init_functions(struct amdgpu_winsys *ws);<br>
-void amdgpu_cs_submit_ib(struct amdgpu_cs *cs);<br>
+void amdgpu_cs_submit_ib(void *job);<br>
<br>
  #endif<br>
diff --git a/src/gallium/winsys/amdgpu/drm/amdgpu_winsys.c b/src/gallium/winsys/amdgpu/drm/amdgpu_winsys.c<br>
index 7016221..7ef3529 100644<br>
--- a/src/gallium/winsys/amdgpu/drm/amdgpu_winsys.c<br>
+++ b/src/gallium/winsys/amdgpu/drm/amdgpu_winsys.c<br>
@@ -308,14 +308,9 @@ static void amdgpu_winsys_destroy(struct radeon_winsys *rws)<br>
  {<br>
     struct amdgpu_winsys *ws = (struct amdgpu_winsys*)rws;<br>
<br>
-   if (ws->thread) {<br>
-      ws->kill_thread = 1;<br>
-      pipe_semaphore_signal(&ws->cs_queued);<br>
-      pipe_thread_wait(ws->thread);<br>
-   }<br>
-   pipe_semaphore_destroy(&ws->cs_queue_has_space);<br>
-   pipe_semaphore_destroy(&ws->cs_queued);<br>
-   pipe_mutex_destroy(ws->cs_queue_lock);<br>
+   if (util_queue_is_initialized(&ws->cs_queue))<br>
+      util_queue_destroy(&ws->cs_queue);<br>
+<br>
     pipe_mutex_destroy(ws->bo_fence_lock);<br>
     pb_cache_deinit(&ws->bo_cache);<br>
     pipe_mutex_destroy(ws->global_bo_list_lock);<br>
@@ -400,53 +395,7 @@ static int compare_dev(void *key1, void *key2)<br>
     return key1 != key2;<br>
  }<br>
<br>
-void amdgpu_ws_queue_cs(struct amdgpu_winsys *ws, struct amdgpu_cs *cs)<br>
-{<br>
-   pipe_semaphore_wait(&ws->cs_queue_has_space);<br>
-<br>
-   pipe_mutex_lock(ws->cs_queue_lock);<br>
-   assert(ws->num_enqueued_cs < ARRAY_SIZE(ws->cs_queue));<br>
-   ws->cs_queue[ws->num_enqueued_cs++] = cs;<br>
-   pipe_mutex_unlock(ws->cs_queue_lock);<br>
-   pipe_semaphore_signal(&ws->cs_queued);<br>
-}<br>
-<br>
-static PIPE_THREAD_ROUTINE(amdgpu_cs_thread_func, param)<br>
-{<br>
-   struct amdgpu_winsys *ws = (struct amdgpu_winsys *)param;<br>
-   struct amdgpu_cs *cs;<br>
-   unsigned i;<br>
-<br>
-   while (1) {<br>
-      pipe_semaphore_wait(&ws->cs_queued);<br>
-      if (ws->kill_thread)<br>
-         break;<br>
-<br>
-      pipe_mutex_lock(ws->cs_queue_lock);<br>
-      cs = ws->cs_queue[0];<br>
-      for (i = 1; i < ws->num_enqueued_cs; i++)<br>
-         ws->cs_queue[i - 1] = ws->cs_queue[i];<br>
-      ws->cs_queue[--ws->num_enqueued_cs] = NULL;<br>
-      pipe_mutex_unlock(ws->cs_queue_lock);<br>
-<br>
-      pipe_semaphore_signal(&ws->cs_queue_has_space);<br>
-<br>
-      if (cs) {<br>
-         amdgpu_cs_submit_ib(cs);<br>
-         pipe_semaphore_signal(&cs->flush_completed);<br>
-      }<br>
-   }<br>
-   pipe_mutex_lock(ws->cs_queue_lock);<br>
-   for (i = 0; i < ws->num_enqueued_cs; i++) {<br>
-      pipe_semaphore_signal(&ws->cs_queue[i]->flush_completed);<br>
-      ws->cs_queue[i] = NULL;<br>
-   }<br>
-   pipe_mutex_unlock(ws->cs_queue_lock);<br>
-   return 0;<br>
-}<br>
-<br>
  DEBUG_GET_ONCE_BOOL_OPTION(thread, "RADEON_THREAD", TRUE)<br>
-static PIPE_THREAD_ROUTINE(amdgpu_cs_thread_func, param);<br>
<br>
  static bool amdgpu_winsys_unref(struct radeon_winsys *rws)<br>
  {<br>
@@ -541,14 +490,10 @@ amdgpu_winsys_create(int fd, radeon_screen_create_t screen_create)<br>
<br>
     LIST_INITHEAD(&ws->global_bo_list);<br>
     pipe_mutex_init(ws->global_bo_list_lock);<br>
-   pipe_mutex_init(ws->cs_queue_lock);<br>
     pipe_mutex_init(ws->bo_fence_lock);<br>
<br>
-   pipe_semaphore_init(&ws->cs_queue_has_space, ARRAY_SIZE(ws->cs_queue));<br>
-   pipe_semaphore_init(&ws->cs_queued, 0);<br>
-<br>
     if (sysconf(_SC_NPROCESSORS_ONLN) > 1 && debug_get_option_thread())<br>
-      ws->thread = pipe_thread_create(amdgpu_cs_thread_func, ws);<br>
+      util_queue_init(&ws->cs_queue, amdgpu_cs_submit_ib);<br>
<br>
     /* Create the screen at the end. The winsys must be initialized<br>
      * completely.<br>
diff --git a/src/gallium/winsys/amdgpu/drm/amdgpu_winsys.h b/src/gallium/winsys/amdgpu/drm/amdgpu_winsys.h<br>
index d6734f7..b13a17e 100644<br>
--- a/src/gallium/winsys/amdgpu/drm/amdgpu_winsys.h<br>
+++ b/src/gallium/winsys/amdgpu/drm/amdgpu_winsys.h<br>
@@ -35,7 +35,7 @@<br>
  #include "pipebuffer/pb_cache.h"<br>
  #include "gallium/drivers/radeon/radeon_winsys.h"<br>
  #include "addrlib/addrinterface.h"<br>
-#include "os/os_thread.h"<br>
+#include "util/u_queue.h"<br>
  #include <amdgpu.h><br>
<br>
  struct amdgpu_cs;<br>
@@ -59,13 +59,7 @@ struct amdgpu_winsys {<br>
     struct radeon_info info;<br>
<br>
     /* multithreaded IB submission */<br>
-   pipe_mutex cs_queue_lock;<br>
-   pipe_semaphore cs_queue_has_space;<br>
-   pipe_semaphore cs_queued;<br>
-   pipe_thread thread;<br>
-   int kill_thread;<br>
-   int num_enqueued_cs;<br>
-   struct amdgpu_cs *cs_queue[8];<br>
+   struct util_queue cs_queue;<br>
<br>
     struct amdgpu_gpu_info amdinfo;<br>
     ADDR_HANDLE addrlib;<br>
@@ -84,7 +78,6 @@ amdgpu_winsys(struct radeon_winsys *base)<br>
     return (struct amdgpu_winsys*)base;<br>
  }<br>
<br>
-void amdgpu_ws_queue_cs(struct amdgpu_winsys *ws, struct amdgpu_cs *cs);<br>
  void amdgpu_surface_init_functions(struct amdgpu_winsys *ws);<br>
  ADDR_HANDLE amdgpu_addr_create(struct amdgpu_winsys *ws);<br>
<br>
<br>
</blockquote>
</blockquote></div>