r300g: fix crash when flushing ZMASK
authorMarek Olšák <maraeo@gmail.com>
Sun, 9 Jan 2011 04:34:36 +0000 (05:34 +0100)
committerMarek Olšák <maraeo@gmail.com>
Sun, 9 Jan 2011 05:14:23 +0000 (06:14 +0100)
https://bugs.freedesktop.org/show_bug.cgi?id=32912

The fix is to call update_derived_state before user buffer uploads.
I've also moved some code around.

Unfortunately, there are still some ZMASK-related bugs which cause
misrendering, i.e. flushing doesn't always work and glean/fbo fails.

src/gallium/drivers/r300/r300_blit.c
src/gallium/drivers/r300/r300_context.h
src/gallium/drivers/r300/r300_render.c
src/gallium/drivers/r300/r300_state_derived.c
src/gallium/drivers/r300/r300_state_derived.h [deleted file]

index 017db48485b944bd3c33b06a4bfa92b1703162ac..a43e83c0d363c11db33a984b700b8fa3d84809e0 100644 (file)
@@ -179,6 +179,12 @@ static void r300_clear(struct pipe_context* pipe,
     boolean can_hyperz = r300->rws->get_value(r300->rws, R300_CAN_HYPERZ);
     uint32_t hyperz_dcv = hyperz->zb_depthclearvalue;
 
+    /* Decompress zbuffers that are bound as textures. If we didn't flush here,
+     * it would happen inside the blitter when updating derived state,
+     * causing a blitter operation to be called from inside the blitter,
+     * which would overwrite saved states and they would never get restored. */
+    r300_flush_depth_textures(r300);
+
     /* Enable fast Z clear.
      * The zbuffer must be in micro-tiled mode, otherwise it locks up. */
     if ((buffers & PIPE_CLEAR_DEPTHSTENCIL) && can_hyperz) {
@@ -274,6 +280,12 @@ static void r300_clear_render_target(struct pipe_context *pipe,
 {
     struct r300_context *r300 = r300_context(pipe);
 
+    /* Decompress zbuffers that are bound as textures. If we didn't flush here,
+     * it would happen inside the blitter when updating derived state,
+     * causing a blitter operation to be called from inside the blitter,
+     * which would overwrite saved states and they would never get restored. */
+    r300_flush_depth_textures(r300);
+
     r300_blitter_begin(r300, R300_CLEAR_SURFACE);
     util_blitter_clear_render_target(r300->blitter, dst, rgba,
                                      dstx, dsty, width, height);
@@ -291,6 +303,12 @@ static void r300_clear_depth_stencil(struct pipe_context *pipe,
 {
     struct r300_context *r300 = r300_context(pipe);
 
+    /* Decompress zbuffers that are bound as textures. If we didn't flush here,
+     * it would happen inside the blitter when updating derived state,
+     * causing a blitter operation to be called from inside the blitter,
+     * which would overwrite saved states and they would never get restored. */
+    r300_flush_depth_textures(r300);
+
     r300_blitter_begin(r300, R300_CLEAR_SURFACE);
     util_blitter_clear_depth_stencil(r300->blitter, dst, clear_flags, depth, stencil,
                                      dstx, dsty, width, height);
@@ -298,10 +316,10 @@ static void r300_clear_depth_stencil(struct pipe_context *pipe,
 }
 
 /* Flush a depth stencil buffer. */
-void r300_flush_depth_stencil(struct pipe_context *pipe,
-                              struct pipe_resource *dst,
-                              unsigned level,
-                              unsigned layer)
+static void r300_flush_depth_stencil(struct pipe_context *pipe,
+                                     struct pipe_resource *dst,
+                                     unsigned level,
+                                     unsigned layer)
 {
     struct r300_context *r300 = r300_context(pipe);
     struct pipe_surface *dstsurf, surf_tmpl;
@@ -320,6 +338,7 @@ void r300_flush_depth_stencil(struct pipe_context *pipe,
     dstsurf = pipe->create_surface(pipe, dst, &surf_tmpl);
 
     r300->z_decomp_rd = TRUE;
+
     r300_blitter_begin(r300, R300_CLEAR_SURFACE);
     util_blitter_flush_depth_stencil(r300->blitter, dstsurf);
     r300_blitter_end(r300);
@@ -329,6 +348,39 @@ void r300_flush_depth_stencil(struct pipe_context *pipe,
     pipe_surface_reference(&dstsurf, NULL);
 }
 
+/* We can't use compressed zbuffers as samplers. */
+void r300_flush_depth_textures(struct r300_context *r300)
+{
+    struct r300_textures_state *state =
+        (struct r300_textures_state*)r300->textures_state.state;
+    unsigned i, level;
+    unsigned count = MIN2(state->sampler_view_count,
+                          state->sampler_state_count);
+
+    if (r300->z_decomp_rd)
+        return;
+
+    for (i = 0; i < count; i++)
+        if (state->sampler_views[i] && state->sampler_states[i]) {
+            struct pipe_resource *tex = state->sampler_views[i]->base.texture;
+
+            if (tex->target == PIPE_TEXTURE_3D ||
+                tex->target == PIPE_TEXTURE_CUBE)
+                continue;
+
+            /* Ignore non-depth textures.
+             * Also ignore reinterpreted depth textures, e.g. resource_copy. */
+            if (!util_format_is_depth_or_stencil(tex->format))
+                continue;
+
+            for (level = 0; level <= tex->last_level; level++)
+                if (r300_texture(tex)->zmask_in_use[level]) {
+                    /* We don't handle 3D textures and cubemaps yet. */
+                    r300_flush_depth_stencil(&r300->context, tex, level, 0);
+                 }
+        }
+}
+
 /* Copy a block of pixels from one surface to another using HW. */
 static void r300_hw_copy_region(struct pipe_context* pipe,
                                 struct pipe_resource *dst,
@@ -360,6 +412,7 @@ static void r300_resource_copy_region(struct pipe_context *pipe,
     enum pipe_format old_format = dst->format;
     enum pipe_format new_format = old_format;
     boolean is_depth;
+
     if (!pipe->screen->is_format_supported(pipe->screen,
                                            old_format, src->target,
                                            src->nr_samples,
@@ -390,6 +443,7 @@ static void r300_resource_copy_region(struct pipe_context *pipe,
     if (is_depth) {
         r300_flush_depth_stencil(pipe, src, src_level, src_box->z);
     }
+
     if (old_format != new_format) {
         r300_texture_reinterpret_format(pipe->screen,
                                         dst, new_format);
index 1a14d2b79e5f7bcfec07e0c9e51e3eb3af9b5961..e09cf87f733eac04572145cfa2f7a6c3f9e68475 100644 (file)
@@ -656,6 +656,22 @@ static INLINE struct r300_fragment_shader *r300_fs(struct r300_context *r300)
     return (struct r300_fragment_shader*)r300->fs.state;
 }
 
+static INLINE void r300_mark_atom_dirty(struct r300_context *r300,
+                                        struct r300_atom *atom)
+{
+    atom->dirty = TRUE;
+
+    if (!r300->first_dirty) {
+        r300->first_dirty = atom;
+        r300->last_dirty = atom+1;
+    } else {
+        if (atom < r300->first_dirty)
+            r300->first_dirty = atom;
+        else if (atom+1 > r300->last_dirty)
+            r300->last_dirty = atom+1;
+    }
+}
+
 struct pipe_context* r300_create_context(struct pipe_screen* screen,
                                          void *priv);
 
@@ -672,10 +688,7 @@ void r300_init_state_functions(struct r300_context* r300);
 void r300_init_resource_functions(struct r300_context* r300);
 
 /* r300_blit.c */
-void r300_flush_depth_stencil(struct pipe_context *pipe,
-                              struct pipe_resource *dst,
-                              unsigned level,
-                              unsigned layer);
+void r300_flush_depth_textures(struct r300_context *r300);
 
 /* r300_query.c */
 void r300_resume_query(struct r300_context *r300,
@@ -710,21 +723,8 @@ void r300_mark_fb_state_dirty(struct r300_context *r300,
                               enum r300_fb_state_change change);
 void r300_mark_fs_code_dirty(struct r300_context *r300);
 
-static INLINE void r300_mark_atom_dirty(struct r300_context *r300,
-                                        struct r300_atom *atom)
-{
-    atom->dirty = TRUE;
-
-    if (!r300->first_dirty) {
-        r300->first_dirty = atom;
-        r300->last_dirty = atom+1;
-    } else {
-        if (atom < r300->first_dirty)
-            r300->first_dirty = atom;
-        if (atom+1 > r300->last_dirty)
-            r300->last_dirty = atom+1;
-    }
-}
+/* r300_state_derived.c */
+void r300_update_derived_state(struct r300_context* r300);
 
 /* r300_debug.c */
 void r500_dump_rs_block(struct r300_rs_block *rs);
index e660ca68f1b0e5de11ebabc4a5f6112d3f350db2..b35822c82f83e37e785ffd34f95f9cbae8f95f31 100644 (file)
@@ -39,7 +39,6 @@
 #include "r300_screen_buffer.h"
 #include "r300_emit.h"
 #include "r300_reg.h"
-#include "r300_state_derived.h"
 
 #include <limits.h>
 
@@ -569,8 +568,6 @@ static void r300_draw_range_elements(struct pipe_context* pipe,
     r300_translate_index_buffer(r300, &indexBuffer, &indexSize, index_offset,
                                 &start, count);
 
-    r300_update_derived_state(r300);
-
     /* Fallback for misaligned ushort indices. */
     if (indexSize == 2 && (start & 1) &&
         !r300_is_user_buffer(indexBuffer)) {
@@ -643,8 +640,6 @@ static void r300_draw_arrays(struct pipe_context* pipe, unsigned mode,
                             r300->rws->get_value(r300->rws, R300_VID_DRM_2_3_0);
     unsigned short_count;
 
-    r300_update_derived_state(r300);
-
     if (immd_is_good_idea(r300, count)) {
         r300_emit_draw_arrays_immediate(r300, mode, start, count);
     } else {
@@ -720,6 +715,8 @@ static void r300_draw_vbo(struct pipe_context* pipe,
             return;
         }
 
+        r300_update_derived_state(r300);
+
         /* Set up the fallback for an incompatible vertex layout if needed. */
         if (r300->incompatible_vb_layout || r300->velems->incompatible_layout) {
             r300_begin_vertex_translate(r300, real_min_index, real_max_index);
@@ -737,6 +734,8 @@ static void r300_draw_vbo(struct pipe_context* pipe,
         min_index = MAX2(min_index, info->start);
         max_index = MIN2(max_index, info->start + count - 1);
 
+        r300_update_derived_state(r300);
+
         /* Set up the fallback for an incompatible vertex layout if needed. */
         if (r300->incompatible_vb_layout || r300->velems->incompatible_layout) {
             r300_begin_vertex_translate(r300, min_index, max_index);
index d3985c11aa8fc2d2127374969bd268f646566238..95be7849f8f976380a366d5e105e5b99519a9288 100644 (file)
@@ -32,7 +32,6 @@
 #include "r300_hyperz.h"
 #include "r300_screen.h"
 #include "r300_shader_semantics.h"
-#include "r300_state_derived.h"
 #include "r300_state_inlines.h"
 #include "r300_texture.h"
 #include "r300_vs.h"
@@ -863,39 +862,6 @@ static void r300_merge_textures_and_samplers(struct r300_context* r300)
     }
 }
 
-/* We can't use compressed zbuffers as samplers. */
-static void r300_flush_depth_textures(struct r300_context *r300)
-{
-    struct r300_textures_state *state =
-        (struct r300_textures_state*)r300->textures_state.state;
-    unsigned i, level;
-    unsigned count = MIN2(state->sampler_view_count,
-                          state->sampler_state_count);
-
-    if (r300->z_decomp_rd)
-        return;
-
-    for (i = 0; i < count; i++)
-        if (state->sampler_views[i] && state->sampler_states[i]) {
-            struct pipe_resource *tex = state->sampler_views[i]->base.texture;
-
-            if (tex->target == PIPE_TEXTURE_3D ||
-                tex->target == PIPE_TEXTURE_CUBE)
-                continue;
-
-            /* Ignore non-depth textures.
-             * Also ignore reinterpreted depth textures, e.g. resource_copy. */
-            if (!util_format_is_depth_or_stencil(tex->format))
-                continue;
-
-            for (level = 0; level <= tex->last_level; level++)
-                if (r300_texture(tex)->zmask_in_use[level]) {
-                    /* We don't handle 3D textures and cubemaps yet. */
-                    r300_flush_depth_stencil(&r300->context, tex, level, 0);
-                 }
-        }
-}
-
 void r300_update_derived_state(struct r300_context* r300)
 {
     r300_flush_depth_textures(r300);
diff --git a/src/gallium/drivers/r300/r300_state_derived.h b/src/gallium/drivers/r300/r300_state_derived.h
deleted file mode 100644 (file)
index 71a4a47..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2008 Corbin Simpson <MostAwesomeDude@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * on the rights to use, copy, modify, merge, publish, distribute, sub
- * license, and/or sell copies of the Software, and to permit persons to whom
- * the Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
- * USE OR OTHER DEALINGS IN THE SOFTWARE. */
-
-#ifndef R300_STATE_DERIVED_H
-#define R300_STATE_DERIVED_H
-
-struct r300_context;
-
-void r300_update_derived_state(struct r300_context* r300);
-
-#endif /* R300_STATE_DERIVED_H */