From 54088f4bb5276c792794fc98df981c35ffc6815c Mon Sep 17 00:00:00 2001 From: Giancarlo Devich Date: Tue, 10 Jan 2023 09:35:39 -0800 Subject: [PATCH] d3d12: Reuse sampler tables inside of a batch If a shader's sampler state is dirty often, the sampler descriptor heap can get used up quickly, forcing flushing. If that happens quickly, we run out of batches and have to wait for batches to finish on the GPU. When this happens, it is often because the sampler state is switching, not because it's truly unique. This change hashes and saves sampler descriptor tables that can be reused in subsequent draws in the same batch, instead of re-copying the same descriptors and consuming the heap. Part-of: --- src/gallium/drivers/d3d12/d3d12_batch.cpp | 27 ++++++++++++++++- src/gallium/drivers/d3d12/d3d12_batch.h | 9 ++++++ src/gallium/drivers/d3d12/d3d12_draw.cpp | 36 ++++++++++++++++------- 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/src/gallium/drivers/d3d12/d3d12_batch.cpp b/src/gallium/drivers/d3d12/d3d12_batch.cpp index 3728df8f42b..40394a0f82d 100644 --- a/src/gallium/drivers/d3d12/d3d12_batch.cpp +++ b/src/gallium/drivers/d3d12/d3d12_batch.cpp @@ -37,6 +37,20 @@ #include + +unsigned d3d12_sampler_desc_table_key_hash(const void* key) +{ + const d3d12_sampler_desc_table_key* table = (d3d12_sampler_desc_table_key*)key; + + return _mesa_hash_data(table->descs, sizeof(table->descs[0]) * table->count); +} +bool d3d12_sampler_desc_table_key_equals(const void* a, const void* b) +{ + const d3d12_sampler_desc_table_key* table_a = (d3d12_sampler_desc_table_key*)a; + const d3d12_sampler_desc_table_key* table_b = (d3d12_sampler_desc_table_key*)b; + return table_a->count == table_b->count && memcmp(table_a->descs, table_b->descs, sizeof(table_a->descs[0]) * table_a->count) == 0; +} + bool d3d12_init_batch(struct d3d12_context *ctx, struct d3d12_batch *batch) { @@ -44,6 +58,8 @@ d3d12_init_batch(struct d3d12_context *ctx, struct d3d12_batch *batch) batch->bos = _mesa_hash_table_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal); + batch->sampler_tables = _mesa_hash_table_create(NULL, d3d12_sampler_desc_table_key_hash, + d3d12_sampler_desc_table_key_equals); batch->sampler_views = _mesa_set_create(NULL, _mesa_hash_pointer, _mesa_key_pointer_equal); batch->surfaces = _mesa_set_create(NULL, _mesa_hash_pointer, @@ -52,7 +68,7 @@ d3d12_init_batch(struct d3d12_context *ctx, struct d3d12_batch *batch) _mesa_hash_pointer, _mesa_key_pointer_equal); - if (!batch->bos || !batch->sampler_views || !batch->surfaces || !batch->objects) + if (!batch->bos || !batch->sampler_tables || !batch->sampler_views || !batch->surfaces || !batch->objects) return false; util_dynarray_init(&batch->zombie_samplers, NULL); @@ -86,6 +102,13 @@ delete_bo(hash_entry *entry) d3d12_bo_unreference(bo); } +static void +delete_sampler_view_table(hash_entry *entry) +{ + FREE((void*)entry->key); + FREE(entry->data); +} + static void delete_sampler_view(set_entry *entry) { @@ -121,6 +144,7 @@ d3d12_reset_batch(struct d3d12_context *ctx, struct d3d12_batch *batch, uint64_t } _mesa_hash_table_clear(batch->bos, delete_bo); + _mesa_hash_table_clear(batch->sampler_tables, delete_sampler_view_table); _mesa_set_clear(batch->sampler_views, delete_sampler_view); _mesa_set_clear(batch->surfaces, delete_surface); _mesa_set_clear(batch->objects, delete_object); @@ -149,6 +173,7 @@ d3d12_destroy_batch(struct d3d12_context *ctx, struct d3d12_batch *batch) d3d12_descriptor_heap_free(batch->sampler_heap); d3d12_descriptor_heap_free(batch->view_heap); _mesa_hash_table_destroy(batch->bos, NULL); + _mesa_hash_table_destroy(batch->sampler_tables, NULL); _mesa_set_destroy(batch->sampler_views, NULL); _mesa_set_destroy(batch->surfaces, NULL); _mesa_set_destroy(batch->objects, NULL); diff --git a/src/gallium/drivers/d3d12/d3d12_batch.h b/src/gallium/drivers/d3d12/d3d12_batch.h index 191fa69978b..db37a2c5676 100644 --- a/src/gallium/drivers/d3d12/d3d12_batch.h +++ b/src/gallium/drivers/d3d12/d3d12_batch.h @@ -26,6 +26,7 @@ #include "util/u_dynarray.h" #include "util/hash_table.h" +#include "pipe/p_state.h" #include #include "d3d12_common.h" @@ -34,10 +35,18 @@ struct d3d12_bo; struct d3d12_descriptor_heap; struct d3d12_fence; + +struct d3d12_sampler_desc_table_key +{ + D3D12_CPU_DESCRIPTOR_HANDLE descs[PIPE_MAX_SHADER_SAMPLER_VIEWS]; + unsigned count; +}; + struct d3d12_batch { struct d3d12_fence *fence; struct hash_table *bos; + struct hash_table *sampler_tables; struct set *sampler_views; struct set *surfaces; struct set *objects; diff --git a/src/gallium/drivers/d3d12/d3d12_draw.cpp b/src/gallium/drivers/d3d12/d3d12_draw.cpp index 58784e61c2e..f9b11bb5ab8 100644 --- a/src/gallium/drivers/d3d12/d3d12_draw.cpp +++ b/src/gallium/drivers/d3d12/d3d12_draw.cpp @@ -191,13 +191,10 @@ fill_sampler_descriptors(struct d3d12_context *ctx, { const struct d3d12_shader *shader = shader_sel->current; struct d3d12_batch *batch = d3d12_current_batch(ctx); - D3D12_CPU_DESCRIPTOR_HANDLE descs[PIPE_MAX_SHADER_SAMPLER_VIEWS]; - struct d3d12_descriptor_handle table_start; + struct d3d12_sampler_desc_table_key view; - d2d12_descriptor_heap_get_next_handle(batch->sampler_heap, &table_start); - - for (unsigned i = shader->begin_srv_binding; i < shader->end_srv_binding; i++) - { + view.count = 0; + for (unsigned i = shader->begin_srv_binding; i < shader->end_srv_binding; i++, view.count++) { struct d3d12_sampler_state *sampler; if (i == shader->pstipple_binding) { @@ -209,15 +206,32 @@ fill_sampler_descriptors(struct d3d12_context *ctx, unsigned desc_idx = i - shader->begin_srv_binding; if (sampler != NULL) { if (sampler->is_shadow_sampler && shader_sel->compare_with_lod_bias_grad) - descs[desc_idx] = sampler->handle_without_shadow.cpu_handle; + view.descs[desc_idx] = sampler->handle_without_shadow.cpu_handle; else - descs[desc_idx] = sampler->handle.cpu_handle; + view.descs[desc_idx] = sampler->handle.cpu_handle; } else - descs[desc_idx] = ctx->null_sampler.cpu_handle; + view.descs[desc_idx] = ctx->null_sampler.cpu_handle; } - d3d12_descriptor_heap_append_handles(batch->sampler_heap, descs, shader->end_srv_binding - shader->begin_srv_binding); - return table_start.gpu_handle; + hash_entry* sampler_entry = + (hash_entry*)_mesa_hash_table_search(batch->sampler_tables, &view); + + if (!sampler_entry) { + d3d12_sampler_desc_table_key* sampler_table_key = MALLOC_STRUCT(d3d12_sampler_desc_table_key); + sampler_table_key->count = view.count; + memcpy(sampler_table_key->descs, &view.descs, view.count * sizeof(view.descs[0])); + + d3d12_descriptor_handle* sampler_table_data = MALLOC_STRUCT(d3d12_descriptor_handle); + d2d12_descriptor_heap_get_next_handle(batch->sampler_heap, sampler_table_data); + + d3d12_descriptor_heap_append_handles(batch->sampler_heap, view.descs, shader->end_srv_binding - shader->begin_srv_binding); + + _mesa_hash_table_insert(batch->sampler_tables, sampler_table_key, sampler_table_data); + + return sampler_table_data->gpu_handle; + } else + return ((d3d12_descriptor_handle*)sampler_entry->data)->gpu_handle; + } static D3D12_UAV_DIMENSION