r300g: fix a race between CS and SET_TILING ioctls
authorMarek Olšák <maraeo@gmail.com>
Wed, 16 Feb 2011 21:23:23 +0000 (22:23 +0100)
committerMarek Olšák <maraeo@gmail.com>
Wed, 16 Feb 2011 21:23:23 +0000 (22:23 +0100)
src/gallium/drivers/r300/r300_state.c
src/gallium/drivers/r300/r300_texture.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 aa18ab7d1e3d16072c2728c3c818f4c0c168aefc..5d8298341d3c7f1e8f7e8808c710c1fc4d0fed87 100644 (file)
@@ -624,12 +624,7 @@ static void r300_tex_set_tiling_flags(struct r300_context *r300,
      * Skip changing the flags otherwise. */
     if (tex->tex.macrotile[tex->surface_level] !=
         tex->tex.macrotile[level]) {
-        /* Tiling determines how DRM treats the buffer data.
-         * We must flush CS when changing it if the buffer is referenced. */
-        if (r300->rws->cs_is_buffer_referenced(r300->cs, tex->cs_buf))
-            r300->context.flush(&r300->context, 0, NULL);
-
-        r300->rws->buffer_set_tiling(tex->buf,
+        r300->rws->buffer_set_tiling(tex->buf, r300->cs,
                 tex->tex.microtile, tex->tex.macrotile[level],
                 tex->tex.stride_in_bytes[0]);
 
index 45a896d61092f89cd962d4121f1df26809c6659d..354144cac79948673b4a0221f0062c8aeadc2e42 100644 (file)
@@ -800,7 +800,7 @@ r300_texture_create_object(struct r300_screen *rscreen,
 
     tex->cs_buf = rws->buffer_get_cs_handle(tex->buf);
 
-    rws->buffer_set_tiling(tex->buf,
+    rws->buffer_set_tiling(tex->buf, NULL,
             tex->tex.microtile, tex->tex.macrotile[0],
             tex->tex.stride_in_bytes[0]);
 
index 6733253ccc919c05c7a4e066b7f9319d097b9ed3..d5c73585c81e2608e03f3673507b0654b6b2e2d9 100644 (file)
@@ -168,6 +168,7 @@ struct r300_winsys_screen {
      * Set tiling flags describing a memory layout of a buffer object.
      *
      * \param buf       A winsys buffer object to set the flags for.
+     * \param cs        A command stream to flush if the buffer is referenced by it.
      * \param macrotile A macrotile flag.
      * \param microtile A microtile flag.
      * \param stride    A stride of the buffer in bytes, for texturing.
@@ -175,6 +176,7 @@ struct r300_winsys_screen {
      * \note microtile and macrotile are not bitmasks!
      */
     void (*buffer_set_tiling)(struct r300_winsys_bo *buf,
+                              struct r300_winsys_cs *cs,
                               enum r300_buffer_tiling microtile,
                               enum r300_buffer_tiling macrotile,
                               unsigned stride);
index afb8131acbe521a80a7747fa613697ba8ea99654..3094337a3cd3a980cc48df6baf403b5d025791dc 100644 (file)
@@ -394,13 +394,26 @@ static void radeon_bo_get_tiling(struct r300_winsys_bo *_buf,
 }
 
 static void radeon_bo_set_tiling(struct r300_winsys_bo *_buf,
+                                 struct r300_winsys_cs *rcs,
                                  enum r300_buffer_tiling microtiled,
                                  enum r300_buffer_tiling macrotiled,
                                  uint32_t pitch)
 {
     struct radeon_bo *bo = get_radeon_bo(pb_buffer(_buf));
+    struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
     struct drm_radeon_gem_set_tiling args = {};
 
+    /* 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);
+    }
+
+    while (p_atomic_read(&bo->num_active_ioctls)) {
+        sched_yield();
+    }
+
     if (microtiled == R300_BUFFER_TILED)
         args.tiling_flags |= RADEON_BO_FLAGS_MICRO_TILE;
     else if (microtiled == R300_BUFFER_SQUARETILED)
index b4f5c9f6a8879ae91d9c2abc101c39c9d1a7621c..8f6f4a1f35af074ad41f9e3301d50bdb0c110b25 100644 (file)
@@ -330,7 +330,7 @@ static void radeon_drm_cs_write_reloc(struct r300_winsys_cs *rcs,
     OUT_CS(&cs->base, index * RELOC_DWORDS);
 }
 
-static PIPE_THREAD_ROUTINE(radeon_drm_cs_emit_async, param)
+static PIPE_THREAD_ROUTINE(radeon_drm_cs_emit_ioctl, param)
 {
     struct radeon_cs_context *csc = (struct radeon_cs_context*)param;
     unsigned i;
@@ -355,7 +355,7 @@ static PIPE_THREAD_ROUTINE(radeon_drm_cs_emit_async, param)
     return NULL;
 }
 
-static void radeon_drm_cs_sync_flush(struct r300_winsys_cs *rcs)
+void radeon_drm_cs_sync_flush(struct r300_winsys_cs *rcs)
 {
     struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
 
@@ -368,7 +368,7 @@ static void radeon_drm_cs_sync_flush(struct r300_winsys_cs *rcs)
 
 DEBUG_GET_ONCE_BOOL_OPTION(thread, "RADEON_THREAD", TRUE)
 
-static void radeon_drm_cs_emit(struct r300_winsys_cs *rcs)
+void radeon_drm_cs_flush(struct r300_winsys_cs *rcs)
 {
     struct radeon_drm_cs *cs = radeon_drm_cs(rcs);
     struct radeon_cs_context *tmp;
@@ -385,10 +385,10 @@ static void radeon_drm_cs_emit(struct r300_winsys_cs *rcs)
             p_atomic_inc(&cs->csc->relocs_bo[i]->num_active_ioctls);
 
         if (debug_get_option_thread()) {
-            cs->thread = pipe_thread_create(radeon_drm_cs_emit_async, cs->csc);
+            cs->thread = pipe_thread_create(radeon_drm_cs_emit_ioctl, cs->csc);
             assert(cs->thread);
         } else {
-            radeon_drm_cs_emit_async(cs->csc);
+            radeon_drm_cs_emit_ioctl(cs->csc);
         }
     }
 
@@ -440,7 +440,7 @@ void radeon_drm_cs_init_functions(struct radeon_drm_winsys *ws)
     ws->base.cs_add_reloc = radeon_drm_cs_add_reloc;
     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_emit;
+    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 486fd237fc93a3676f7f57e3402f13c48513648a..4cc97f37e09ed38c27f2726f1ff90efe45873f28 100644 (file)
@@ -96,6 +96,8 @@ 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_init_functions(struct radeon_drm_winsys *ws);
 
 #endif