winsys/radeon: Create async thread only once
authorMaarten Lankhorst <m.b.lankhorst@gmail.com>
Sat, 27 Aug 2011 20:57:19 +0000 (22:57 +0200)
committerChristian König <deathsimple@vodafone.de>
Tue, 30 Aug 2011 12:01:57 +0000 (14:01 +0200)
I noticed that a thread was created for every time async flush was called, so I moved it and used some semaphores to synch.

Signed-off-by: Maarten Lankhorst <m.b.lankhorst@gmail.com>
Reviewed-by: Marek Olšák <maraeo@gmail.com>
Signed-off-by: Christian König <deathsimple@vodafone.de>
src/gallium/winsys/radeon/drm/radeon_drm_cs.c
src/gallium/winsys/radeon/drm/radeon_drm_cs.h

index c309354785a725cf2f66e801bbd3995179d05d23..2a1de535ea38ffa328a6e8a640301b8e9eb6798f 100644 (file)
@@ -130,6 +130,9 @@ static void radeon_destroy_cs_context(struct radeon_cs_context *csc)
     FREE(csc->relocs);
 }
 
+DEBUG_GET_ONCE_BOOL_OPTION(thread, "RADEON_THREAD", TRUE)
+static PIPE_THREAD_ROUTINE(radeon_drm_cs_emit_ioctl, param);
+
 static struct radeon_winsys_cs *radeon_drm_cs_create(struct radeon_winsys *rws)
 {
     struct radeon_drm_winsys *ws = radeon_drm_winsys(rws);
@@ -139,6 +142,8 @@ static struct radeon_winsys_cs *radeon_drm_cs_create(struct radeon_winsys *rws)
     if (!cs) {
         return NULL;
     }
+    pipe_semaphore_init(&cs->flush_queued, 0);
+    pipe_semaphore_init(&cs->flush_completed, 0);
 
     cs->ws = ws;
 
@@ -158,6 +163,8 @@ static struct radeon_winsys_cs *radeon_drm_cs_create(struct radeon_winsys *rws)
     cs->base.buf = cs->csc->buf;
 
     p_atomic_inc(&ws->num_cs);
+    if (cs->ws->num_cpus > 1 && debug_get_option_thread())
+        cs->thread = pipe_thread_create(radeon_drm_cs_emit_ioctl, cs);
     return &cs->base;
 }
 
@@ -357,9 +364,8 @@ static void radeon_drm_cs_write_reloc(struct radeon_winsys_cs *rcs,
     OUT_CS(&cs->base, index * RELOC_DWORDS);
 }
 
-static PIPE_THREAD_ROUTINE(radeon_drm_cs_emit_ioctl, param)
+static void radeon_drm_cs_emit_ioctl_oneshot(struct radeon_cs_context *csc)
 {
-    struct radeon_cs_context *csc = (struct radeon_cs_context*)param;
     unsigned i;
 
     if (drmCommandWriteRead(csc->fd, DRM_RADEON_CS,
@@ -381,20 +387,32 @@ static PIPE_THREAD_ROUTINE(radeon_drm_cs_emit_ioctl, param)
         p_atomic_dec(&csc->relocs_bo[i]->num_active_ioctls);
 
     radeon_cs_context_cleanup(csc);
+}
+
+static PIPE_THREAD_ROUTINE(radeon_drm_cs_emit_ioctl, param)
+{
+    struct radeon_drm_cs *cs = (struct radeon_drm_cs*)param;
+
+    while (1) {
+        pipe_semaphore_wait(&cs->flush_queued);
+        if (cs->kill_thread)
+            break;
+        radeon_drm_cs_emit_ioctl_oneshot(cs->cst);
+        pipe_semaphore_signal(&cs->flush_completed);
+    }
+    pipe_semaphore_signal(&cs->flush_completed);
     return NULL;
 }
 
 void radeon_drm_cs_sync_flush(struct radeon_drm_cs *cs)
 {
     /* Wait for any pending ioctl to complete. */
-    if (cs->thread) {
-        pipe_thread_wait(cs->thread);
-        cs->thread = 0;
+    if (cs->thread && cs->flush_started) {
+        pipe_semaphore_wait(&cs->flush_completed);
+        cs->flush_started = 0;
     }
 }
 
-DEBUG_GET_ONCE_BOOL_OPTION(thread, "RADEON_THREAD", TRUE)
-
 static void radeon_drm_cs_flush(struct radeon_winsys_cs *rcs, unsigned flags)
 {
     struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
@@ -402,33 +420,33 @@ static void radeon_drm_cs_flush(struct radeon_winsys_cs *rcs, unsigned flags)
 
     radeon_drm_cs_sync_flush(cs);
 
-    /* If the CS is not empty, emit it in a newly-spawned thread. */
+    /* Flip command streams. */
+    tmp = cs->csc;
+    cs->csc = cs->cst;
+    cs->cst = tmp;
+
+    /* If the CS is not empty, emit it in a separate thread. */
     if (cs->base.cdw) {
-        unsigned i, crelocs = cs->csc->crelocs;
+        unsigned i, crelocs = cs->cst->crelocs;
 
-        cs->csc->chunks[0].length_dw = cs->base.cdw;
+        cs->cst->chunks[0].length_dw = cs->base.cdw;
 
         for (i = 0; i < crelocs; i++) {
             /* Update the number of active asynchronous CS ioctls for the buffer. */
-            p_atomic_inc(&cs->csc->relocs_bo[i]->num_active_ioctls);
+            p_atomic_inc(&cs->cst->relocs_bo[i]->num_active_ioctls);
         }
 
-        if (cs->ws->num_cpus > 1 && debug_get_option_thread() &&
+        if (cs->thread &&
             (flags & RADEON_FLUSH_ASYNC)) {
-            cs->thread = pipe_thread_create(radeon_drm_cs_emit_ioctl, cs->csc);
-            assert(cs->thread);
+            cs->flush_started = 1;
+            pipe_semaphore_signal(&cs->flush_queued);
         } else {
-            radeon_drm_cs_emit_ioctl(cs->csc);
+            radeon_drm_cs_emit_ioctl_oneshot(cs->cst);
         }
     } else {
-        radeon_cs_context_cleanup(cs->csc);
+        radeon_cs_context_cleanup(cs->cst);
     }
 
-    /* Flip command streams. */
-    tmp = cs->csc;
-    cs->csc = cs->cst;
-    cs->cst = tmp;
-
     /* Prepare a new CS. */
     cs->base.buf = cs->csc->buf;
     cs->base.cdw = 0;
@@ -438,6 +456,15 @@ static void radeon_drm_cs_destroy(struct radeon_winsys_cs *rcs)
 {
     struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
     radeon_drm_cs_sync_flush(cs);
+    if (cs->thread) {
+        cs->kill_thread = 1;
+        pipe_semaphore_signal(&cs->flush_queued);
+        pipe_semaphore_wait(&cs->flush_completed);
+        pipe_thread_wait(cs->thread);
+        pipe_thread_destroy(cs->thread);
+    }
+    pipe_semaphore_destroy(&cs->flush_queued);
+    pipe_semaphore_destroy(&cs->flush_completed);
     radeon_cs_context_cleanup(&cs->csc1);
     radeon_cs_context_cleanup(&cs->csc2);
     p_atomic_dec(&cs->ws->num_cs);
index fe28532688400a6c5bc276d6fc16d71350a36653..e8e34c2ba164e7b85d50d57850da93b5bf607c59 100644 (file)
@@ -75,6 +75,8 @@ struct radeon_drm_cs {
     void *flush_data;
 
     pipe_thread thread;
+    int flush_started, kill_thread;
+    pipe_semaphore flush_queued, flush_completed;
 };
 
 int radeon_get_reloc(struct radeon_cs_context *csc, struct radeon_bo *bo);