radeonsi: reduce overhead for resident textures which need depth decompression
[mesa.git] / src / gallium / drivers / radeonsi / si_descriptors.c
index c13cf3d78937395a0323260eac057de85d6329e6..a8f54e0714abb73612afe9c05ba39853a75c3e33 100644 (file)
@@ -1614,6 +1614,35 @@ static void si_set_polygon_stipple(struct pipe_context *ctx,
 
 /* TEXTURE METADATA ENABLE/DISABLE */
 
+static void
+si_resident_handles_update_needs_color_decompress(struct si_context *sctx)
+{
+       util_dynarray_foreach(&sctx->resident_tex_handles,
+                             struct si_texture_handle *, tex_handle) {
+               struct pipe_resource *res = (*tex_handle)->view->texture;
+
+               if (res && res->target != PIPE_BUFFER) {
+                       struct r600_texture *rtex = (struct r600_texture *)res;
+
+                       (*tex_handle)->needs_color_decompress =
+                               color_needs_decompression(rtex);
+               }
+       }
+
+       util_dynarray_foreach(&sctx->resident_img_handles,
+                             struct si_image_handle *, img_handle) {
+               struct pipe_image_view *view = &(*img_handle)->view;
+               struct pipe_resource *res = view->resource;
+
+               if (res && res->target != PIPE_BUFFER) {
+                       struct r600_texture *rtex = (struct r600_texture *)res;
+
+                       (*img_handle)->needs_color_decompress =
+                               color_needs_decompression(rtex);
+               }
+       }
+}
+
 /* CMASK can be enabled (for fast clear) and disabled (for texture export)
  * while the texture is bound, possibly by a different context. In that case,
  * call this function to update needs_*_decompress_masks.
@@ -1625,6 +1654,8 @@ void si_update_needs_color_decompress_masks(struct si_context *sctx)
                si_images_update_needs_color_decompress_mask(&sctx->images[i]);
                si_update_shader_needs_decompress_mask(sctx, i);
        }
+
+       si_resident_handles_update_needs_color_decompress(sctx);
 }
 
 /* BUFFER DISCARD/INVALIDATION */
@@ -1803,6 +1834,53 @@ static void si_rebind_buffer(struct pipe_context *ctx, struct pipe_resource *buf
                        }
                }
        }
+
+       /* Bindless texture handles */
+       if (rbuffer->texture_handle_allocated) {
+               util_dynarray_foreach(&sctx->resident_tex_handles,
+                                     struct si_texture_handle *, tex_handle) {
+                       struct pipe_sampler_view *view = (*tex_handle)->view;
+                       struct si_bindless_descriptor *desc = (*tex_handle)->desc;
+
+                       if (view->texture == buf) {
+                               si_set_buf_desc_address(rbuffer,
+                                                       view->u.buf.offset,
+                                                       &desc->desc_list[4]);
+                               desc->dirty = true;
+                               sctx->bindless_descriptors_dirty = true;
+
+                               radeon_add_to_buffer_list_check_mem(
+                                       &sctx->b, &sctx->b.gfx, rbuffer,
+                                       RADEON_USAGE_READ,
+                                       RADEON_PRIO_SAMPLER_BUFFER, true);
+                       }
+               }
+       }
+
+       /* Bindless image handles */
+       if (rbuffer->image_handle_allocated) {
+               util_dynarray_foreach(&sctx->resident_img_handles,
+                                     struct si_image_handle *, img_handle) {
+                       struct pipe_image_view *view = &(*img_handle)->view;
+                       struct si_bindless_descriptor *desc = (*img_handle)->desc;
+
+                       if (view->resource == buf) {
+                               if (view->access & PIPE_IMAGE_ACCESS_WRITE)
+                                       si_mark_image_range_valid(view);
+
+                               si_set_buf_desc_address(rbuffer,
+                                                       view->u.buf.offset,
+                                                       &desc->desc_list[4]);
+                               desc->dirty = true;
+                               sctx->bindless_descriptors_dirty = true;
+
+                               radeon_add_to_buffer_list_check_mem(
+                                       &sctx->b, &sctx->b.gfx, rbuffer,
+                                       RADEON_USAGE_READWRITE,
+                                       RADEON_PRIO_SAMPLER_BUFFER, true);
+                       }
+               }
+       }
 }
 
 /* Reallocate a buffer a update all resource bindings where the buffer is
@@ -2149,9 +2227,40 @@ si_create_bindless_descriptor(struct si_context *sctx, uint32_t *desc_list,
                                        PIPE_TRANSFER_UNSYNCHRONIZED);
        util_memcpy_cpu_to_le32(ptr + desc->offset, desc_list, size);
 
+       /* Keep track of the initial descriptor especially for buffers
+        * invalidation because we might need to know the previous address.
+        */
+       memcpy(desc->desc_list, desc_list, sizeof(desc->desc_list));
+
        return desc;
 }
 
+static void si_invalidate_bindless_buf_desc(struct si_context *sctx,
+                                           struct si_bindless_descriptor *desc,
+                                           struct pipe_resource *resource,
+                                           uint64_t offset)
+{
+       struct r600_resource *buf = r600_resource(resource);
+       uint32_t *desc_list = desc->desc_list;
+       uint64_t old_desc_va;
+
+       assert(resource->target == PIPE_BUFFER);
+
+       /* Retrieve the old buffer addr from the descriptor. */
+       old_desc_va  = desc_list[0];
+       old_desc_va |= ((uint64_t)G_008F04_BASE_ADDRESS_HI(desc_list[1]) << 32);
+
+       if (old_desc_va != buf->gpu_address + offset) {
+               /* The buffer has been invalidated when the handle wasn't
+                * resident, update the descriptor and the dirty flag.
+                */
+               si_set_buf_desc_address(buf, offset, &desc_list[4]);
+
+               desc->dirty = true;
+               sctx->bindless_descriptors_dirty = true;
+       }
+}
+
 static uint64_t si_create_texture_handle(struct pipe_context *ctx,
                                         struct pipe_sampler_view *view,
                                         const struct pipe_sampler_state *state)
@@ -2199,6 +2308,8 @@ static uint64_t si_create_texture_handle(struct pipe_context *ctx,
 
        pipe_sampler_view_reference(&tex_handle->view, view);
 
+       r600_resource(sview->base.texture)->texture_handle_allocated = true;
+
        return handle;
 }
 
@@ -2237,6 +2348,29 @@ static void si_make_texture_handle_resident(struct pipe_context *ctx,
        sview = (struct si_sampler_view *)tex_handle->view;
 
        if (resident) {
+               if (sview->base.texture->target != PIPE_BUFFER) {
+                       struct r600_texture *rtex =
+                               (struct r600_texture *)sview->base.texture;
+
+                       if (depth_needs_decompression(rtex, sview)) {
+                               util_dynarray_append(
+                                       &sctx->resident_tex_needs_depth_decompress,
+                                       struct si_texture_handle *,
+                                       tex_handle);
+                       }
+
+                       tex_handle->needs_color_decompress =
+                               color_needs_decompression(rtex);
+
+                       if (rtex->dcc_offset &&
+                           p_atomic_read(&rtex->framebuffers_bound))
+                               sctx->need_check_render_feedback = true;
+               } else {
+                       si_invalidate_bindless_buf_desc(sctx, tex_handle->desc,
+                                                       sview->base.texture,
+                                                       sview->base.u.buf.offset);
+               }
+
                /* Add the texture handle to the per-context list. */
                util_dynarray_append(&sctx->resident_tex_handles,
                                     struct si_texture_handle *, tex_handle);
@@ -2257,6 +2391,12 @@ static void si_make_texture_handle_resident(struct pipe_context *ctx,
                util_dynarray_delete_unordered(&sctx->resident_tex_handles,
                                               struct si_texture_handle *,
                                               tex_handle);
+
+               if (sview->base.texture->target != PIPE_BUFFER) {
+                       util_dynarray_delete_unordered(
+                               &sctx->resident_tex_needs_depth_decompress,
+                               struct si_texture_handle *, tex_handle);
+               }
        }
 }
 
@@ -2300,6 +2440,8 @@ static uint64_t si_create_image_handle(struct pipe_context *ctx,
 
        util_copy_image_view(&img_handle->view, view);
 
+       r600_resource(view->resource)->image_handle_allocated = true;
+
        return handle;
 }
 
@@ -2339,6 +2481,25 @@ static void si_make_image_handle_resident(struct pipe_context *ctx,
        view = &img_handle->view;
 
        if (resident) {
+               struct r600_resource *res =
+                       (struct r600_resource *)view->resource;
+
+               if (res->b.b.target != PIPE_BUFFER) {
+                       struct r600_texture *rtex = (struct r600_texture *)res;
+                       unsigned level = view->u.tex.level;
+
+                       img_handle->needs_color_decompress =
+                               color_needs_decompression(rtex);
+
+                       if (vi_dcc_enabled(rtex, level) &&
+                           p_atomic_read(&rtex->framebuffers_bound))
+                               sctx->need_check_render_feedback = true;
+               } else {
+                       si_invalidate_bindless_buf_desc(sctx, img_handle->desc,
+                                                       view->resource,
+                                                       view->u.buf.offset);
+               }
+
                /* Add the image handle to the per-context list. */
                util_dynarray_append(&sctx->resident_img_handles,
                                     struct si_image_handle *, img_handle);
@@ -2364,6 +2525,54 @@ static void si_make_image_handle_resident(struct pipe_context *ctx,
 }
 
 
+void si_all_resident_buffers_begin_new_cs(struct si_context *sctx)
+{
+       unsigned num_resident_tex_handles, num_resident_img_handles;
+
+       num_resident_tex_handles = sctx->resident_tex_handles.size /
+                                  sizeof(struct si_texture_handle *);
+       num_resident_img_handles = sctx->resident_img_handles.size /
+                                  sizeof(struct si_image_handle *);
+
+       /* Skip adding the bindless descriptors when no handles are resident.
+        */
+       if (!num_resident_tex_handles && !num_resident_img_handles)
+               return;
+
+       /* Add all bindless descriptors. */
+       util_dynarray_foreach(&sctx->bindless_descriptors,
+                             struct r600_resource *, desc) {
+
+               radeon_add_to_buffer_list(&sctx->b, &sctx->b.gfx, *desc,
+                                         RADEON_USAGE_READWRITE,
+                                         RADEON_PRIO_DESCRIPTORS);
+       }
+
+       /* Add all resident texture handles. */
+       util_dynarray_foreach(&sctx->resident_tex_handles,
+                             struct si_texture_handle *, tex_handle) {
+               struct si_sampler_view *sview =
+                       (struct si_sampler_view *)(*tex_handle)->view;
+
+               si_sampler_view_add_buffer(sctx, sview->base.texture,
+                                          RADEON_USAGE_READ,
+                                          sview->is_stencil_sampler, false);
+       }
+
+       /* Add all resident image handles. */
+       util_dynarray_foreach(&sctx->resident_img_handles,
+                             struct si_image_handle *, img_handle) {
+               struct pipe_image_view *view = &(*img_handle)->view;
+
+               si_sampler_view_add_buffer(sctx, view->resource,
+                                          RADEON_USAGE_READWRITE,
+                                          false, false);
+       }
+
+       sctx->b.num_resident_handles += num_resident_tex_handles +
+                                       num_resident_img_handles;
+}
+
 /* INIT/DEINIT/UPLOAD */
 
 /* GFX9 has only 4KB of CE, while previous chips had 32KB. In order
@@ -2533,6 +2742,63 @@ void si_init_all_descriptors(struct si_context *sctx)
        si_set_user_data_base(sctx, PIPE_SHADER_FRAGMENT, R_00B030_SPI_SHADER_USER_DATA_PS_0);
 }
 
+static void si_upload_bindless_descriptor(struct si_context *sctx,
+                                         struct si_bindless_descriptor *desc)
+{
+       struct radeon_winsys_cs *cs = sctx->b.gfx.cs;
+       uint64_t va = desc->buffer->gpu_address + desc->offset;
+       unsigned num_dwords = sizeof(desc->desc_list) / 4;
+
+       radeon_emit(cs, PKT3(PKT3_WRITE_DATA, 2 + num_dwords, 0));
+       radeon_emit(cs, S_370_DST_SEL(V_370_TC_L2) |
+                   S_370_WR_CONFIRM(1) |
+                   S_370_ENGINE_SEL(V_370_ME));
+       radeon_emit(cs, va);
+       radeon_emit(cs, va >> 32);
+       radeon_emit_array(cs, desc->desc_list, num_dwords);
+}
+
+static void si_upload_bindless_descriptors(struct si_context *sctx)
+{
+       if (!sctx->bindless_descriptors_dirty)
+               return;
+
+       /* Wait for graphics/compute to be idle before updating the resident
+        * descriptors directly in memory, in case the GPU is using them.
+        */
+       sctx->b.flags |= SI_CONTEXT_PS_PARTIAL_FLUSH |
+                        SI_CONTEXT_CS_PARTIAL_FLUSH;
+       si_emit_cache_flush(sctx);
+
+       util_dynarray_foreach(&sctx->resident_tex_handles,
+                             struct si_texture_handle *, tex_handle) {
+               struct si_bindless_descriptor *desc = (*tex_handle)->desc;
+
+               if (!desc->dirty)
+                       continue;
+
+               si_upload_bindless_descriptor(sctx, desc);
+               desc->dirty = false;
+       }
+
+       util_dynarray_foreach(&sctx->resident_img_handles,
+                             struct si_image_handle *, img_handle) {
+               struct si_bindless_descriptor *desc = (*img_handle)->desc;
+
+               if (!desc->dirty)
+                       continue;
+
+               si_upload_bindless_descriptor(sctx, desc);
+               desc->dirty = false;
+       }
+
+       /* Invalidate L1 because it doesn't know that L2 changed. */
+       sctx->b.flags |= SI_CONTEXT_INV_SMEM_L1;
+       si_emit_cache_flush(sctx);
+
+       sctx->bindless_descriptors_dirty = false;
+}
+
 bool si_upload_graphics_shader_descriptors(struct si_context *sctx)
 {
        const unsigned mask = u_bit_consecutive(0, SI_DESCS_FIRST_COMPUTE);
@@ -2550,6 +2816,9 @@ bool si_upload_graphics_shader_descriptors(struct si_context *sctx)
        }
 
        sctx->descriptors_dirty &= ~mask;
+
+       si_upload_bindless_descriptors(sctx);
+
        return true;
 }
 
@@ -2574,6 +2843,8 @@ bool si_upload_compute_shader_descriptors(struct si_context *sctx)
 
        sctx->descriptors_dirty &= ~mask;
 
+       si_upload_bindless_descriptors(sctx);
+
        return true;
 }