r300g: skip rendering if CS space validation fails
authorMarek Olšák <maraeo@gmail.com>
Fri, 10 Sep 2010 05:58:07 +0000 (07:58 +0200)
committerMarek Olšák <maraeo@gmail.com>
Mon, 13 Sep 2010 05:49:43 +0000 (07:49 +0200)
radeon_cs_space_check flushes the pipe context on failure, retries
the validation, and returns -1 if it fails again. At that point, there is
nothing we can do, so let's skip draw operations instead of getting stuck
in an infinite loop.

This code path ideally should never be hit.

src/gallium/drivers/r300/r300_emit.c
src/gallium/drivers/r300/r300_emit.h
src/gallium/drivers/r300/r300_render.c

index 232259e21d17b06070f8130f33fb0c67dd9301ad..2583b93c4840de2f055b502cdb754115b7e4ee20 100644 (file)
@@ -1137,9 +1137,9 @@ void r300_emit_texture_cache_inval(struct r300_context* r300, unsigned size, voi
     END_CS;
 }
 
-void r300_emit_buffer_validate(struct r300_context *r300,
-                               boolean do_validate_vertex_buffers,
-                               struct pipe_resource *index_buffer)
+boolean r300_emit_buffer_validate(struct r300_context *r300,
+                                  boolean do_validate_vertex_buffers,
+                                  struct pipe_resource *index_buffer)
 {
     struct pipe_framebuffer_state* fb =
         (struct pipe_framebuffer_state*)r300->fb_state.state;
@@ -1150,7 +1150,6 @@ void r300_emit_buffer_validate(struct r300_context *r300,
     struct pipe_vertex_element *velem = r300->velems->velem;
     struct pipe_resource *pbuf;
     unsigned i;
-    boolean invalid = FALSE;
 
     /* upload buffers first */
     if (r300->screen->caps.has_tcl && r300->any_user_vbs) {
@@ -1161,7 +1160,6 @@ void r300_emit_buffer_validate(struct r300_context *r300,
     /* Clean out BOs. */
     r300->rws->cs_reset_buffers(r300->cs);
 
-validate:
     /* Color buffers... */
     for (i = 0; i < fb->nr_cbufs; i++) {
         tex = r300_texture(fb->cbufs[i]->texture);
@@ -1208,15 +1206,10 @@ validate:
                                  r300_buffer(index_buffer)->domain, 0);
 
     if (!r300->rws->cs_validate(r300->cs)) {
-        r300->context.flush(&r300->context, 0, NULL);
-        if (invalid) {
-            /* Well, hell. */
-            fprintf(stderr, "r300: Stuck in validation loop, gonna quit now.\n");
-            abort();
-        }
-        invalid = TRUE;
-        goto validate;
+        return FALSE;
     }
+
+    return TRUE;
 }
 
 unsigned r300_get_num_dirty_dwords(struct r300_context *r300)
index bae2525634606613789eaaffbaadf886e055f90d..278dbcb4c7cb5c4222a783d03e8d00968cd09059 100644 (file)
@@ -121,8 +121,8 @@ unsigned r300_get_num_cs_end_dwords(struct r300_context *r300);
 /* Emit all dirty state. */
 void r300_emit_dirty_state(struct r300_context* r300);
 
-void r300_emit_buffer_validate(struct r300_context *r300,
-                               boolean do_validate_vertex_buffers,
-                               struct pipe_resource *index_buffer);
+boolean r300_emit_buffer_validate(struct r300_context *r300,
+                                  boolean do_validate_vertex_buffers,
+                                  struct pipe_resource *index_buffer);
 
 #endif /* R300_EMIT_H */
index dd2442a801a3bc020ddd964ad5a93269f1a369cb..aa45ee3abfd0ce4ed6bd88229379c4251fe56870 100644 (file)
@@ -187,12 +187,12 @@ enum r300_prepare_flags {
  * \param aos_offset    The offset passed to emit_aos.
  * \param index_bias    The index bias to emit.
  */
-static void r300_prepare_for_rendering(struct r300_context *r300,
-                                       enum r300_prepare_flags flags,
-                                       struct pipe_resource *index_buffer,
-                                       unsigned cs_dwords,
-                                       int aos_offset,
-                                       int index_bias)
+static boolean r300_prepare_for_rendering(struct r300_context *r300,
+                                          enum r300_prepare_flags flags,
+                                          struct pipe_resource *index_buffer,
+                                          unsigned cs_dwords,
+                                          int aos_offset,
+                                          int index_bias)
 {
     boolean flushed        = FALSE;
     boolean first_draw     = flags & PREP_FIRST_DRAW;
@@ -225,7 +225,13 @@ static void r300_prepare_for_rendering(struct r300_context *r300,
 
     /* Validate buffers and emit dirty state if needed. */
     if (first_draw || flushed) {
-        r300_emit_buffer_validate(r300, flags & PREP_VALIDATE_VBOS, index_buffer);
+        if (!r300_emit_buffer_validate(r300, flags & PREP_VALIDATE_VBOS,
+                                       index_buffer)) {
+            fprintf(stderr, "r300: CS space validation failed. "
+                    "(not enough memory?) Skipping rendering.\n");
+            return FALSE;
+        }
+
         r300_emit_dirty_state(r300);
         if (hw_index_bias) {
             if (r300->screen->caps.has_tcl)
@@ -240,6 +246,8 @@ static void r300_prepare_for_rendering(struct r300_context *r300,
         if (emit_aos_swtcl)
             r300_emit_aos_swtcl(r300, indexed);
     }
+
+    return TRUE;
 }
 
 static boolean immd_is_good_idea(struct r300_context *r300,
@@ -300,11 +308,14 @@ static void r300_emit_draw_arrays_immediate(struct r300_context *r300,
     struct pipe_vertex_element* velem;
     struct pipe_vertex_buffer* vbuf;
     unsigned vertex_element_count = r300->velems->count;
-    unsigned i, v, vbi, dwords;
+    unsigned i, v, vbi;
 
     /* Size of the vertex, in dwords. */
     unsigned vertex_size = r300->velems->vertex_size_dwords;
 
+    /* The number of dwords for this draw operation. */
+    unsigned dwords = 9 + count * vertex_size;
+
     /* Size of the vertex element, in dwords. */
     unsigned size[PIPE_MAX_ATTRIBS];
 
@@ -319,6 +330,9 @@ static void r300_emit_draw_arrays_immediate(struct r300_context *r300,
 
     CS_LOCALS(r300);
 
+    if (!r300_prepare_for_rendering(r300, PREP_FIRST_DRAW, NULL, dwords, 0, 0))
+        return;
+
     /* Calculate the vertex size, offsets, strides etc. and map the buffers. */
     for (i = 0; i < vertex_element_count; i++) {
         velem = &r300->velems->velem[i];
@@ -338,10 +352,6 @@ static void r300_emit_draw_arrays_immediate(struct r300_context *r300,
         mapelem[i] = map[vbi] + (velem->src_offset / 4);
     }
 
-    dwords = 9 + count * vertex_size;
-
-    r300_prepare_for_rendering(r300, PREP_FIRST_DRAW, NULL, dwords, 0, 0);
-
     BEGIN_CS(dwords);
     OUT_CS_REG(R300_GA_COLOR_CONTROL,
             r300_provoking_vertex_fixes(r300, mode));
@@ -517,10 +527,12 @@ static void r300_draw_range_elements(struct pipe_context* pipe,
     r300_upload_index_buffer(r300, &indexBuffer, indexSize, start, count, &new_offset);
 
     start = new_offset;
-    /* 15 dwords for emit_draw_elements */
-    r300_prepare_for_rendering(r300,
-        PREP_FIRST_DRAW | PREP_VALIDATE_VBOS | PREP_EMIT_AOS | PREP_INDEXED,
-        indexBuffer, 15, buffer_offset, indexBias);
+
+    /* 15 dwords for emit_draw_elements. Give up if the function fails. */
+    if (!r300_prepare_for_rendering(r300,
+            PREP_FIRST_DRAW | PREP_VALIDATE_VBOS | PREP_EMIT_AOS |
+            PREP_INDEXED, indexBuffer, 15, buffer_offset, indexBias))
+        goto done;
 
     if (alt_num_verts || count <= 65535) {
         r300_emit_draw_elements(r300, indexBuffer, indexSize,
@@ -537,13 +549,15 @@ static void r300_draw_range_elements(struct pipe_context* pipe,
 
             /* 15 dwords for emit_draw_elements */
             if (count) {
-                r300_prepare_for_rendering(r300,
-                    PREP_VALIDATE_VBOS | PREP_EMIT_AOS | PREP_INDEXED,
-                    indexBuffer, 15, buffer_offset, indexBias);
+                if (!r300_prepare_for_rendering(r300,
+                        PREP_VALIDATE_VBOS | PREP_EMIT_AOS | PREP_INDEXED,
+                        indexBuffer, 15, buffer_offset, indexBias))
+                    goto done;
             }
         } while (count);
     }
 
+done:
     if (indexBuffer != orgIndexBuffer) {
         pipe_resource_reference( &indexBuffer, NULL );
     }
@@ -582,9 +596,11 @@ static void r300_draw_arrays(struct pipe_context* pipe, unsigned mode,
     if (immd_is_good_idea(r300, count)) {
         r300_emit_draw_arrays_immediate(r300, mode, start, count);
     } else {
-        /* 9 spare dwords for emit_draw_arrays. */
-        r300_prepare_for_rendering(r300, PREP_FIRST_DRAW | PREP_VALIDATE_VBOS | PREP_EMIT_AOS,
-                               NULL, 9, start, 0);
+        /* 9 spare dwords for emit_draw_arrays. Give up if the function fails. */
+        if (!r300_prepare_for_rendering(r300,
+                PREP_FIRST_DRAW | PREP_VALIDATE_VBOS | PREP_EMIT_AOS,
+                NULL, 9, start, 0))
+            goto done;
 
         if (alt_num_verts || count <= 65535) {
             r300_emit_draw_arrays(r300, mode, count);
@@ -596,16 +612,18 @@ static void r300_draw_arrays(struct pipe_context* pipe, unsigned mode,
                 start += short_count;
                 count -= short_count;
 
-                /* 9 spare dwords for emit_draw_arrays. */
+                /* 9 spare dwords for emit_draw_arrays. Give up if the function fails. */
                 if (count) {
-                    r300_prepare_for_rendering(r300,
-                        PREP_VALIDATE_VBOS | PREP_EMIT_AOS, NULL, 9,
-                        start, 0);
+                    if (!r300_prepare_for_rendering(r300,
+                            PREP_VALIDATE_VBOS | PREP_EMIT_AOS, NULL, 9,
+                            start, 0))
+                        goto done;
                 }
             } while (count);
         }
     }
 
+done:
     if (translate) {
         r300_end_vertex_translate(r300);
     }
@@ -833,8 +851,10 @@ static void r300_render_draw_arrays(struct vbuf_render* render,
     CS_LOCALS(r300);
     (void) i; (void) ptr;
 
-    r300_prepare_for_rendering(r300, PREP_FIRST_DRAW | PREP_EMIT_AOS_SWTCL,
-                               NULL, dwords, 0, 0);
+    if (!r300_prepare_for_rendering(r300,
+                                    PREP_FIRST_DRAW | PREP_EMIT_AOS_SWTCL,
+                                    NULL, dwords, 0, 0))
+        return;
 
     DBG(r300, DBG_DRAW, "r300: render_draw_arrays (count: %d)\n", count);
 
@@ -885,9 +905,11 @@ static void r300_render_draw_elements(struct vbuf_render* render,
      *
      * Below we manage the CS space manually because there may be more
      * indices than it can fit in CS. */
-    r300_prepare_for_rendering(r300,
-        PREP_FIRST_DRAW | PREP_EMIT_AOS_SWTCL | PREP_INDEXED,
-        NULL, 256, 0, 0);
+    if (!r300_prepare_for_rendering(r300,
+            PREP_FIRST_DRAW | PREP_EMIT_AOS_SWTCL | PREP_INDEXED,
+            NULL, 256, 0, 0))
+        return;
+
     end_cs_dwords = r300_get_num_cs_end_dwords(r300);
 
     while (count) {
@@ -916,9 +938,11 @@ static void r300_render_draw_elements(struct vbuf_render* render,
         count -= short_count;
 
         if (count) {
-            r300_prepare_for_rendering(r300,
-                PREP_EMIT_AOS_SWTCL | PREP_INDEXED,
-                NULL, 256, 0, 0);
+            if (!r300_prepare_for_rendering(r300,
+                    PREP_EMIT_AOS_SWTCL | PREP_INDEXED,
+                    NULL, 256, 0, 0))
+                return;
+
             end_cs_dwords = r300_get_num_cs_end_dwords(r300);
         }
     }
@@ -987,7 +1011,9 @@ void r300_draw_flush_vbuf(struct r300_context *r300)
  *                         End of SW TCL functions                          *
  ***************************************************************************/
 
-/* If we used a quad to draw a rectangle, the pixels on the main diagonal
+/* This functions is used to draw a rectangle for the blitter module.
+ *
+ * If we rendered a quad, the pixels on the main diagonal
  * would be computed and stored twice, which makes the clear/copy codepaths
  * somewhat inefficient. Instead we use a rectangular point sprite. */
 static void r300_blitter_draw_rectangle(struct blitter_context *blitter,
@@ -1017,7 +1043,8 @@ static void r300_blitter_draw_rectangle(struct blitter_context *blitter,
     r300->clip_state.dirty = FALSE;
     r300->viewport_state.dirty = FALSE;
 
-    r300_prepare_for_rendering(r300, PREP_FIRST_DRAW, NULL, dwords, 0, 0);
+    if (!r300_prepare_for_rendering(r300, PREP_FIRST_DRAW, NULL, dwords, 0, 0))
+        goto done;
 
     DBG(r300, DBG_DRAW, "r300: draw_rectangle\n");
 
@@ -1061,6 +1088,7 @@ static void r300_blitter_draw_rectangle(struct blitter_context *blitter,
     }
     END_CS;
 
+done:
     /* Restore the state. */
     r300->clip_state.dirty = TRUE;
     r300->rs_state.dirty = TRUE;