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: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20618>
This commit is contained in:
Giancarlo Devich
2023-01-10 09:35:39 -08:00
committed by Marge Bot
parent 32b23d8fb2
commit 54088f4bb5
3 changed files with 60 additions and 12 deletions
+26 -1
View File
@@ -37,6 +37,20 @@
#include <dxguids/dxguids.h>
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);
+9
View File
@@ -26,6 +26,7 @@
#include "util/u_dynarray.h"
#include "util/hash_table.h"
#include "pipe/p_state.h"
#include <stdint.h>
#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;
+25 -11
View File
@@ -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