r300g: decide whether a flush should be asynchronous when calling it
authorMarek Olšák <maraeo@gmail.com>
Tue, 8 Mar 2011 07:20:31 +0000 (08:20 +0100)
committerMarek Olšák <maraeo@gmail.com>
Tue, 8 Mar 2011 07:23:29 +0000 (08:23 +0100)
Thread offloading is not sometimes desirable, e.g. when mapping a buffer.

src/gallium/drivers/r300/r300_blit.c
src/gallium/drivers/r300/r300_context.c
src/gallium/drivers/r300/r300_context.h
src/gallium/drivers/r300/r300_emit.c
src/gallium/drivers/r300/r300_flush.c
src/gallium/drivers/r300/r300_render.c
src/gallium/drivers/r300/r300_transfer.c
src/gallium/drivers/r300/r300_winsys.h
src/gallium/winsys/radeon/drm/radeon_drm_bo.c
src/gallium/winsys/radeon/drm/radeon_drm_cs.c
src/gallium/winsys/radeon/drm/radeon_drm_cs.h

index 6391ea7f3be7c46d4be7fce7045dcf21deb2c869..6682b2bad4429a10208241e4f75babd389acce50 100644 (file)
@@ -263,7 +263,7 @@ static void r300_clear(struct pipe_context* pipe,
 
         /* Reserve CS space. */
         if (dwords > (R300_MAX_CMDBUF_DWORDS - r300->cs->cdw)) {
-            r300->context.flush(&r300->context, 0, NULL);
+            r300_flush(&r300->context, R300_FLUSH_ASYNC, NULL);
         }
 
         /* Emit clear packets. */
index 48a595981be6288ce46d711f4516ffd9d4daa036..720d666d98c7253180f5c6ad8976731e09aabc6e 100644 (file)
@@ -139,11 +139,11 @@ static void r300_destroy_context(struct pipe_context* context)
     FREE(r300);
 }
 
-void r300_flush_cb(void *data)
+static void r300_flush_callback(void *data, unsigned flags)
 {
     struct r300_context* const cs_context_copy = data;
 
-    cs_context_copy->context.flush(&cs_context_copy->context, 0, NULL);
+    r300_flush(&cs_context_copy->context, flags, NULL);
 }
 
 #define R300_INIT_ATOM(atomname, atomsize) \
@@ -453,7 +453,7 @@ struct pipe_context* r300_create_context(struct pipe_screen* screen,
     r300_init_render_functions(r300);
     r300_init_states(&r300->context);
 
-    rws->cs_set_flush(r300->cs, r300_flush_cb, r300);
+    rws->cs_set_flush(r300->cs, r300_flush_callback, r300);
 
     /* The KIL opcode needs the first texture unit to be enabled
      * on r3xx-r4xx. In order to calm down the CS checker, we bind this
index 1e28221326dfabc4a21253733048296f11007c41..76ea5ee2517ee1f788a9af2a50b53ad867fc297f 100644 (file)
@@ -665,8 +665,6 @@ static INLINE void r300_mark_atom_dirty(struct r300_context *r300,
 struct pipe_context* r300_create_context(struct pipe_screen* screen,
                                          void *priv);
 
-void r300_flush_cb(void *data);
-
 /* Context initialization. */
 struct draw_stage* r300_draw_stage(struct r300_context* r300);
 void r300_init_blit_functions(struct r300_context *r300);
@@ -681,6 +679,11 @@ void r300_decompress_zmask(struct r300_context *r300);
 void r300_decompress_zmask_locked_unsafe(struct r300_context *r300);
 void r300_decompress_zmask_locked(struct r300_context *r300);
 
+/* r300_flush.c */
+void r300_flush(struct pipe_context *pipe,
+                unsigned flags,
+                struct pipe_fence_handle **fence);
+
 /* r300_hyperz.c */
 void r300_update_hyperz_state(struct r300_context* r300);
 
index 60f83058569094b936156a9bacc0b553c5794d12..b28be9367f18e3b3b845bc80e67068858c676880 100644 (file)
@@ -1218,7 +1218,7 @@ validate:
         if (flushed)
             return FALSE;
 
-        r300->context.flush(&r300->context, 0, NULL);
+        r300_flush(&r300->context, R300_FLUSH_ASYNC, NULL);
         flushed = TRUE;
         goto validate;
     }
index 9c41a1383ced7d5ba9e9d809c8edb1b456a7009c..fa0926868be550770315d32466ef4826016d98b3 100644 (file)
 #include "r300_cs.h"
 #include "r300_emit.h"
 
-static void r300_flush(struct pipe_context* pipe,
-                       unsigned flags,
-                       struct pipe_fence_handle** fence)
+
+void r300_flush(struct pipe_context *pipe,
+                unsigned flags,
+                struct pipe_fence_handle **fence)
 {
     struct r300_context *r300 = r300_context(pipe);
     struct r300_atom *atom;
@@ -61,7 +62,7 @@ static void r300_flush(struct pipe_context* pipe,
             r500_emit_index_bias(r300, 0);
 
         r300->flush_counter++;
-        r300->rws->cs_flush(r300->cs);
+        r300->rws->cs_flush(r300->cs, flags);
         r300->dirty_hw = 0;
 
         /* New kitchen sink, baby. */
@@ -83,20 +84,24 @@ static void r300_flush(struct pipe_context* pipe,
              * and we cannot emit an empty CS. We must write some regs then. */
             CS_LOCALS(r300);
             OUT_CS_REG(RB3D_COLOR_CHANNEL_MASK, 0);
-            r300->rws->cs_flush(r300->cs);
+            r300->rws->cs_flush(r300->cs, flags);
         } else {
             /* Even if hw is not dirty, we should at least reset the CS in case
              * the space checking failed for the first draw operation. */
-            r300->rws->cs_flush(r300->cs);
+            r300->rws->cs_flush(r300->cs, flags);
         }
     }
+}
 
-    if (flags & PIPE_FLUSH_FRAME) {
-        r300->rws->cs_sync_flush(r300->cs);
-    }
+static void r300_flush_wrapped(struct pipe_context *pipe,
+                               unsigned flags,
+                               struct pipe_fence_handle **fence)
+{
+    /* don't use the flags param, it means something else */
+    r300_flush(pipe, 0, fence);
 }
 
 void r300_init_flush_functions(struct r300_context* r300)
 {
-    r300->context.flush = r300_flush;
+    r300->context.flush = r300_flush_wrapped;
 }
index 300cb86acfe6afd429fb9be7c6c36f0cfed447c7..26594dabe4201cbf8a8d4e12a0cba9f52d2d7f60 100644 (file)
@@ -219,7 +219,7 @@ static boolean r300_reserve_cs_dwords(struct r300_context *r300,
 
     /* Reserve requested CS space. */
     if (cs_dwords > (R300_MAX_CMDBUF_DWORDS - r300->cs->cdw)) {
-        r300->context.flush(&r300->context, 0, NULL);
+        r300_flush(&r300->context, R300_FLUSH_ASYNC, NULL);
         flushed = TRUE;
     }
 
index 0b73162abd9f6995bb82bf2ca2cbb573388746e6..928c86be0c59cef545dd60db2e44602dd75da061 100644 (file)
@@ -72,6 +72,7 @@ static void r300_copy_into_tiled_texture(struct pipe_context *ctx,
                               transfer->box.x, transfer->box.y, transfer->box.z,
                               &r300transfer->linear_texture->b.b.b, 0, &src_box);
 
+    /* XXX remove this. */
     ctx->flush(ctx, 0, NULL);
 }
 
@@ -152,7 +153,7 @@ r300_texture_get_transfer(struct pipe_context *ctx,
             if (!trans->linear_texture) {
                 /* Oh crap, the thing can't create the texture.
                  * Let's flush and try again. */
-                ctx->flush(ctx, 0, NULL);
+                r300_flush(ctx, 0, NULL);
 
                 trans->linear_texture = r300_resource(
                    ctx->screen->resource_create(ctx->screen,
@@ -176,13 +177,7 @@ r300_texture_get_transfer(struct pipe_context *ctx,
             assert(!trans->linear_texture->tex.microtile &&
                    !trans->linear_texture->tex.macrotile[0]);
 
-            /* Set the stride.
-            *
-            * Even though we are using an internal texture for this,
-            * the transfer level, box and usage parameters still reflect
-            * the arguments received to get_transfer.  We just do the
-            * right thing internally.
-            */
+            /* Set the stride. */
             trans->transfer.stride =
                     trans->linear_texture->tex.stride_in_bytes[0];
 
@@ -192,7 +187,7 @@ r300_texture_get_transfer(struct pipe_context *ctx,
                 r300_copy_from_tiled_texture(ctx, trans);
 
                 /* Always referenced in the blit. */
-                ctx->flush(ctx, 0, NULL);
+                r300_flush(ctx, 0, NULL);
             }
             return &trans->transfer;
         }
@@ -202,8 +197,9 @@ r300_texture_get_transfer(struct pipe_context *ctx,
         trans->transfer.stride = tex->tex.stride_in_bytes[level];
         trans->offset = r300_texture_get_offset(tex, level, box->z);
 
-        if (referenced_cs)
-            ctx->flush(ctx, PIPE_FLUSH_RENDER_CACHE, NULL);
+        if (referenced_cs &&
+            !(usage & PIPE_TRANSFER_UNSYNCHRONIZED))
+            r300_flush(ctx, 0, NULL);
         return &trans->transfer;
     }
     return NULL;
index c0b66899f8b5754aa0c00b60f54e06f880c98951..3a6798a54233addd2bb77ad0a05dfd32738e622d 100644 (file)
@@ -35,6 +35,7 @@
 #include "pipe/p_state.h"
 
 #define R300_MAX_CMDBUF_DWORDS (16 * 1024)
+#define R300_FLUSH_ASYNC       (1 << 0)
 
 struct winsys_handle;
 struct r300_winsys_screen;
@@ -265,15 +266,9 @@ struct r300_winsys_screen {
      * Flush a command stream.
      *
      * \param cs        A command stream to flush.
+     * \param flags,    R300_FLUSH_ASYNC or 0.
      */
-    void (*cs_flush)(struct r300_winsys_cs *cs);
-
-    /**
-     * Wait until the last flush is completed.
-     *
-     * \param cs        A command stream.
-     */
-    void (*cs_sync_flush)(struct r300_winsys_cs *cs);
+    void (*cs_flush)(struct r300_winsys_cs *cs, unsigned flags);
 
     /**
      * Set a flush callback which is called from winsys when flush is
@@ -284,7 +279,7 @@ struct r300_winsys_screen {
      * \param user      A user pointer that will be passed to the flush callback.
      */
     void (*cs_set_flush)(struct r300_winsys_cs *cs,
-                         void (*flush)(void *),
+                         void (*flush)(void *ctx, unsigned flags),
                          void *user);
 
     /**
index 3094337a3cd3a980cc48df6baf403b5d025791dc..9eb833454df1308f0aee0aac73af292806bdda7d 100644 (file)
@@ -172,7 +172,7 @@ static void *radeon_bo_map_internal(struct pb_buffer *_buf,
         /* DONTBLOCK doesn't make sense with UNSYNCHRONIZED. */
         if (flags & PB_USAGE_DONTBLOCK) {
             if (radeon_bo_is_referenced_by_cs(cs, bo)) {
-                cs->flush_cs(cs->flush_data);
+                cs->flush_cs(cs->flush_data, R300_FLUSH_ASYNC);
                 return NULL;
             }
 
@@ -181,7 +181,11 @@ static void *radeon_bo_map_internal(struct pb_buffer *_buf,
             }
         } else {
             if (radeon_bo_is_referenced_by_cs(cs, bo)) {
-                cs->flush_cs(cs->flush_data);
+                cs->flush_cs(cs->flush_data, 0);
+            } else {
+                /* Try to avoid busy-waiting in radeon_bo_wait. */
+                if (p_atomic_read(&bo->num_active_ioctls))
+                    radeon_drm_cs_sync_flush(cs);
             }
 
             radeon_bo_wait((struct r300_winsys_bo*)bo);
@@ -406,8 +410,7 @@ static void radeon_bo_set_tiling(struct r300_winsys_bo *_buf,
     /* Tiling determines how DRM treats the buffer data.
      * We must flush CS when changing it if the buffer is referenced. */
     if (cs && radeon_bo_is_referenced_by_cs(cs, bo)) {
-        radeon_drm_cs_flush(rcs);
-        radeon_drm_cs_sync_flush(rcs);
+        cs->flush_cs(cs->flush_data, 0);
     }
 
     while (p_atomic_read(&bo->num_active_ioctls)) {
index 9ee800f5950b7328c213bf332cf238302ab35d5f..951791a17270ee3fd890d05fdab6c295394812c7 100644 (file)
@@ -355,10 +355,8 @@ static PIPE_THREAD_ROUTINE(radeon_drm_cs_emit_ioctl, param)
     return NULL;
 }
 
-void radeon_drm_cs_sync_flush(struct r300_winsys_cs *rcs)
+void radeon_drm_cs_sync_flush(struct radeon_drm_cs *cs)
 {
-    struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
-
     /* Wait for any pending ioctl to complete. */
     if (cs->thread) {
         pipe_thread_wait(cs->thread);
@@ -368,12 +366,12 @@ void radeon_drm_cs_sync_flush(struct r300_winsys_cs *rcs)
 
 DEBUG_GET_ONCE_BOOL_OPTION(thread, "RADEON_THREAD", TRUE)
 
-void radeon_drm_cs_flush(struct r300_winsys_cs *rcs)
+static void radeon_drm_cs_flush(struct r300_winsys_cs *rcs, unsigned flags)
 {
     struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
     struct radeon_cs_context *tmp;
 
-    radeon_drm_cs_sync_flush(rcs);
+    radeon_drm_cs_sync_flush(cs);
 
     /* If the CS is not empty, emit it in a newly-spawned thread. */
     if (cs->base.cdw) {
@@ -384,7 +382,8 @@ void radeon_drm_cs_flush(struct r300_winsys_cs *rcs)
         for (i = 0; i < crelocs; i++)
             p_atomic_inc(&cs->csc->relocs_bo[i]->num_active_ioctls);
 
-        if (cs->ws->num_cpus > 1 && debug_get_option_thread()) {
+        if (cs->ws->num_cpus > 1 && debug_get_option_thread() &&
+            (flags & R300_FLUSH_ASYNC)) {
             cs->thread = pipe_thread_create(radeon_drm_cs_emit_ioctl, cs->csc);
             assert(cs->thread);
         } else {
@@ -407,7 +406,7 @@ void radeon_drm_cs_flush(struct r300_winsys_cs *rcs)
 static void radeon_drm_cs_destroy(struct r300_winsys_cs *rcs)
 {
     struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
-    radeon_drm_cs_sync_flush(rcs);
+    radeon_drm_cs_sync_flush(cs);
     radeon_cs_context_cleanup(&cs->csc1);
     radeon_cs_context_cleanup(&cs->csc2);
     p_atomic_dec(&cs->ws->num_cs);
@@ -417,7 +416,8 @@ static void radeon_drm_cs_destroy(struct r300_winsys_cs *rcs)
 }
 
 static void radeon_drm_cs_set_flush(struct r300_winsys_cs *rcs,
-                                    void (*flush)(void *), void *user)
+                                    void (*flush)(void *ctx, unsigned flags),
+                                    void *user)
 {
     struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
     cs->flush_cs = flush;
@@ -441,7 +441,6 @@ void radeon_drm_cs_init_functions(struct radeon_drm_winsys *ws)
     ws->base.cs_validate = radeon_drm_cs_validate;
     ws->base.cs_write_reloc = radeon_drm_cs_write_reloc;
     ws->base.cs_flush = radeon_drm_cs_flush;
-    ws->base.cs_sync_flush = radeon_drm_cs_sync_flush;
     ws->base.cs_set_flush = radeon_drm_cs_set_flush;
     ws->base.cs_is_buffer_referenced = radeon_bo_is_referenced;
 }
index 4cc97f37e09ed38c27f2726f1ff90efe45873f28..dfaa161c3189eaf70fc1bb4575f9dddb6bdd0c5b 100644 (file)
@@ -70,7 +70,7 @@ struct radeon_drm_cs {
     struct radeon_drm_winsys *ws;
 
     /* Flush CS. */
-    void (*flush_cs)(void *);
+    void (*flush_cs)(void *ctx, unsigned flags);
     void *flush_data;
 
     pipe_thread thread;
@@ -96,8 +96,7 @@ static INLINE boolean radeon_bo_is_referenced_by_any_cs(struct radeon_bo *bo)
     return bo->num_cs_references;
 }
 
-void radeon_drm_cs_flush(struct r300_winsys_cs *rcs);
-void radeon_drm_cs_sync_flush(struct r300_winsys_cs *rcs);
+void radeon_drm_cs_sync_flush(struct radeon_drm_cs *cs);
 void radeon_drm_cs_init_functions(struct radeon_drm_winsys *ws);
 
 #endif