/* 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.
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 */
}
}
}
+
+ /* 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
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)
pipe_sampler_view_reference(&tex_handle->view, view);
+ r600_resource(sview->base.texture)->texture_handle_allocated = true;
+
return handle;
}
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);
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);
+ }
}
}
util_copy_image_view(&img_handle->view, view);
+ r600_resource(view->resource)->image_handle_allocated = true;
+
return handle;
}
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);
}
+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
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);
}
sctx->descriptors_dirty &= ~mask;
+
+ si_upload_bindless_descriptors(sctx);
+
return true;
}
sctx->descriptors_dirty &= ~mask;
+ si_upload_bindless_descriptors(sctx);
+
return true;
}