From: Marek Olšák <[email protected]>

The disabling of CMASK is simple, but notifying all contexts about it is not:
- The screen must have a list of all contexts.
- Each context must have a monotonic counter that is incremented only when
  the screen wants to re-emit framebuffer states.
- Each context must check in draw_vbo if the counter has been changed and
  re-emit the framebuffer state accordingly.
---
 src/gallium/drivers/r600/r600_state_common.c  |  9 +++++-
 src/gallium/drivers/radeon/r600_pipe_common.c | 15 ++++++++++
 src/gallium/drivers/radeon/r600_pipe_common.h | 13 +++++++++
 src/gallium/drivers/radeon/r600_texture.c     | 41 +++++++++++++++++++++++++++
 src/gallium/drivers/radeonsi/si_state_draw.c  | 12 +++++++-
 5 files changed, 88 insertions(+), 2 deletions(-)

diff --git a/src/gallium/drivers/r600/r600_state_common.c 
b/src/gallium/drivers/r600/r600_state_common.c
index aa3a085..a1645ee 100644
--- a/src/gallium/drivers/r600/r600_state_common.c
+++ b/src/gallium/drivers/r600/r600_state_common.c
@@ -1672,7 +1672,7 @@ static void r600_draw_vbo(struct pipe_context *ctx, const 
struct pipe_draw_info
        struct radeon_winsys_cs *cs = rctx->b.gfx.cs;
        bool render_cond_bit = rctx->b.render_cond && 
!rctx->b.render_cond_force_off;
        uint64_t mask;
-       unsigned num_patches;
+       unsigned num_patches, dirty_fb_counter;
 
        if (!info.indirect && !info.count && (info.indexed || 
!info.count_from_stream_output)) {
                return;
@@ -1688,6 +1688,13 @@ static void r600_draw_vbo(struct pipe_context *ctx, 
const struct pipe_draw_info
                rctx->b.dma.flush(rctx, RADEON_FLUSH_ASYNC, NULL);
        }
 
+       /* Re-emit the framebuffer state if needed. */
+       dirty_fb_counter = p_atomic_read(&rctx->b.dirty_fb_counter);
+       if (dirty_fb_counter != rctx->b.last_dirty_fb_counter) {
+               rctx->b.last_dirty_fb_counter = dirty_fb_counter;
+               r600_mark_atom_dirty(rctx, &rctx->framebuffer.atom);
+       }
+
        if (!r600_update_derived_state(rctx)) {
                /* useless to render because current rendering command
                 * can't be achieved
diff --git a/src/gallium/drivers/radeon/r600_pipe_common.c 
b/src/gallium/drivers/radeon/r600_pipe_common.c
index ea02827..88e8e8e 100644
--- a/src/gallium/drivers/radeon/r600_pipe_common.c
+++ b/src/gallium/drivers/radeon/r600_pipe_common.c
@@ -322,11 +322,23 @@ bool r600_common_context_init(struct r600_common_context 
*rctx,
                rctx->dma.flush = r600_flush_dma_ring;
        }
 
+       /* Add the new context the the global list. */
+       pipe_mutex_lock(rscreen->context_list_lock);
+       LIST_ADD(&rctx->list_item, &rscreen->context_list);
+       pipe_mutex_unlock(rscreen->context_list_lock);
+
        return true;
 }
 
 void r600_common_context_cleanup(struct r600_common_context *rctx)
 {
+       struct r600_common_screen *rscreen = rctx->screen;
+
+       /* Remove the context from the global list. */
+       pipe_mutex_lock(rscreen->context_list_lock);
+       LIST_DEL(&rctx->list_item);
+       pipe_mutex_unlock(rscreen->context_list_lock);
+
        if (rctx->gfx.cs)
                rctx->ws->cs_destroy(rctx->gfx.cs);
        if (rctx->dma.cs)
@@ -892,6 +904,8 @@ bool r600_common_screen_init(struct r600_common_screen 
*rscreen,
        util_format_s3tc_init();
        pipe_mutex_init(rscreen->aux_context_lock);
        pipe_mutex_init(rscreen->gpu_load_mutex);
+       pipe_mutex_init(rscreen->context_list_lock);
+       LIST_INITHEAD(&rscreen->context_list);
 
        if (((rscreen->info.drm_major == 2 && rscreen->info.drm_minor >= 28) ||
             rscreen->info.drm_major == 3) &&
@@ -949,6 +963,7 @@ void r600_destroy_common_screen(struct r600_common_screen 
*rscreen)
 
        pipe_mutex_destroy(rscreen->gpu_load_mutex);
        pipe_mutex_destroy(rscreen->aux_context_lock);
+       pipe_mutex_destroy(rscreen->context_list_lock);
        rscreen->aux_context->destroy(rscreen->aux_context);
 
        if (rscreen->trace_bo)
diff --git a/src/gallium/drivers/radeon/r600_pipe_common.h 
b/src/gallium/drivers/radeon/r600_pipe_common.h
index 3bbbfbb..daf8798 100644
--- a/src/gallium/drivers/radeon/r600_pipe_common.h
+++ b/src/gallium/drivers/radeon/r600_pipe_common.h
@@ -325,6 +325,10 @@ struct r600_common_screen {
 
        /* Performance counters. */
        struct r600_perfcounters        *perfcounters;
+
+       /* All contexts. */
+       pipe_mutex                      context_list_lock;
+       struct list_head                context_list;
 };
 
 /* This encapsulates a state or an operation which can emitted into the GPU
@@ -382,6 +386,7 @@ struct r600_ring {
 struct r600_common_context {
        struct pipe_context b; /* base class */
 
+       struct list_head                list_item; /* part of the context list 
*/
        struct r600_common_screen       *screen;
        struct radeon_winsys            *ws;
        struct radeon_winsys_ctx        *ctx;
@@ -393,6 +398,14 @@ struct r600_common_context {
        unsigned                        initial_gfx_cs_size;
        unsigned                        gpu_reset_counter;
 
+       /* If pipe_screen wants to re-emit the framebuffer state of all
+        * contexts, it should atomically increment dirty_fb_counter.
+        * Each context will compare the current and last counter before draw
+        * and re-emit the framebuffer state accordingly.
+        */
+       unsigned                        dirty_fb_counter;
+       unsigned                        last_dirty_fb_counter;
+
        struct u_upload_mgr             *uploader;
        struct u_suballocator           *allocator_so_filled_size;
        struct util_slab_mempool        pool_transfers;
diff --git a/src/gallium/drivers/radeon/r600_texture.c 
b/src/gallium/drivers/radeon/r600_texture.c
index ec2f245..395607b 100644
--- a/src/gallium/drivers/radeon/r600_texture.c
+++ b/src/gallium/drivers/radeon/r600_texture.c
@@ -249,6 +249,17 @@ static void r600_texture_init_metadata(struct r600_texture 
*rtex,
        metadata->scanout = (surface->flags & RADEON_SURF_SCANOUT) != 0;
 }
 
+static void r600_dirty_all_framebuffer_states(struct r600_common_screen 
*rscreen)
+{
+       struct r600_common_context *iter;
+
+       pipe_mutex_lock(rscreen->context_list_lock);
+       LIST_FOR_EACH_ENTRY(iter, &rscreen->context_list, list_item) {
+               p_atomic_inc(&iter->dirty_fb_counter);
+       }
+       pipe_mutex_unlock(rscreen->context_list_lock);
+}
+
 static void r600_eliminate_fast_color_clear(struct r600_common_screen *rscreen,
                                      struct r600_texture *rtex)
 {
@@ -260,6 +271,31 @@ static void r600_eliminate_fast_color_clear(struct 
r600_common_screen *rscreen,
        pipe_mutex_unlock(rscreen->aux_context_lock);
 }
 
+static void r600_texture_disable_cmask(struct r600_common_screen *rscreen,
+                                      struct r600_texture *rtex)
+{
+
+       if (!rtex->cmask.size)
+               return;
+
+       assert(rtex->resource.b.b.nr_samples <= 1);
+
+       /* Disable CMASK. */
+       memset(&rtex->cmask, 0, sizeof(rtex->cmask));
+       rtex->cmask.base_address_reg = rtex->resource.gpu_address >> 8;
+
+       if (rscreen->chip_class >= SI)
+               rtex->cb_color_info &= ~SI_S_028C70_FAST_CLEAR(1);
+       else
+               rtex->cb_color_info &= ~EG_S_028C70_FAST_CLEAR(1);
+
+       if (rtex->cmask_buffer != &rtex->resource)
+           pipe_resource_reference((struct 
pipe_resource**)&rtex->cmask_buffer, NULL);
+
+       /* Notify all contexts about the change. */
+       r600_dirty_all_framebuffer_states(rscreen);
+}
+
 static boolean r600_texture_get_handle(struct pipe_screen* screen,
                                       struct pipe_resource *resource,
                                       struct winsys_handle *whandle,
@@ -285,6 +321,11 @@ static boolean r600_texture_get_handle(struct pipe_screen* 
screen,
                        if (!(usage & PIPE_HANDLE_USAGE_EXPLICIT_FLUSH)) {
                                /* Eliminate fast clear (both CMASK and DCC) */
                                r600_eliminate_fast_color_clear(rscreen, rtex);
+
+                               /* Disable CMASK if flush_resource isn't going
+                                * to be called.
+                                */
+                               r600_texture_disable_cmask(rscreen, rtex);
                        }
 
                        r600_texture_init_metadata(rtex, &metadata);
diff --git a/src/gallium/drivers/radeonsi/si_state_draw.c 
b/src/gallium/drivers/radeonsi/si_state_draw.c
index 91ccd07..e901bdc 100644
--- a/src/gallium/drivers/radeonsi/si_state_draw.c
+++ b/src/gallium/drivers/radeonsi/si_state_draw.c
@@ -763,7 +763,7 @@ void si_draw_vbo(struct pipe_context *ctx, const struct 
pipe_draw_info *info)
        struct si_context *sctx = (struct si_context *)ctx;
        struct si_state_rasterizer *rs = sctx->queued.named.rasterizer;
        struct pipe_index_buffer ib = {};
-       unsigned mask;
+       unsigned mask, dirty_fb_counter;
 
        if (!info->count && !info->indirect &&
            (info->indexed || !info->count_from_stream_output))
@@ -782,6 +782,16 @@ void si_draw_vbo(struct pipe_context *ctx, const struct 
pipe_draw_info *info)
                return;
        }
 
+       /* Re-emit the framebuffer state if needed. */
+       dirty_fb_counter = p_atomic_read(&sctx->b.dirty_fb_counter);
+       if (dirty_fb_counter != sctx->b.last_dirty_fb_counter) {
+               sctx->b.last_dirty_fb_counter = dirty_fb_counter;
+               sctx->framebuffer.dirty_cbufs |=
+                       ((1 << sctx->framebuffer.state.nr_cbufs) - 1);
+               sctx->framebuffer.dirty_zsbuf = true;
+               si_mark_atom_dirty(sctx, &sctx->framebuffer.atom);
+       }
+
        si_decompress_textures(sctx);
 
        /* Set the rasterization primitive type.
-- 
2.5.0

_______________________________________________
mesa-dev mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to