d3d12: Lower uniforms to UBO by nir options

Ubo0 is tricky. It exists if there were any uniforms when
lower_uniforms_to_ubo was run. If we try to run that ourselves,
it might be too late and DCE/remove_dead_variables might've been run,
which removed the uniforms and their accesses, without decrementing
num_uniforms. So we have no good way of knowing whether to declare
ubos from [0, N] or [1, N]. In practice this probably doesn't make
much of a difference but the logic is there so ¯\_(ツ)_/¯

If we use the nir option, then dead code isn't run, and num_uniforms
is a true indicator of whether ubo0 exists or not.

Note that this means we are no longer running this pass for internal
shaders that don't come from the GLSL compiler, so various places are
updated to query the nir info bit that's set by running this pass.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28535>
This commit is contained in:
Jesse Natalie 2024-03-29 20:21:27 -07:00 committed by Marge Bot
parent e80cda0512
commit 33735585a9
8 changed files with 29 additions and 38 deletions

View file

@ -125,12 +125,6 @@ compile_nir(struct d3d12_context *ctx, struct d3d12_shader_selector *sel,
if (key->stage == PIPE_SHADER_VERTEX && key->vs.needs_format_emulation)
dxil_nir_lower_vs_vertex_conversion(nir, key->vs.format_conversion);
uint32_t num_ubos_before_lower_to_ubo = nir->info.num_ubos;
uint32_t num_uniforms_before_lower_to_ubo = nir->num_uniforms;
NIR_PASS_V(nir, nir_lower_uniforms_to_ubo, false, false);
shader->has_default_ubo0 = num_uniforms_before_lower_to_ubo > 0 &&
nir->info.num_ubos > num_ubos_before_lower_to_ubo;
if (key->last_vertex_processing_stage) {
if (key->invert_depth)
NIR_PASS_V(nir, d3d12_nir_invert_depth, key->invert_depth, key->halfz);
@ -150,7 +144,6 @@ compile_nir(struct d3d12_context *ctx, struct d3d12_shader_selector *sel,
struct nir_to_dxil_options opts = {};
opts.interpolate_at_vertex = screen->have_load_at_vertex;
opts.lower_int16 = !screen->opts4.Native16BitShaderOpsSupported;
opts.no_ubo0 = !shader->has_default_ubo0;
opts.last_ubo_is_not_arrayed = shader->num_state_vars > 0;
if (key->stage == PIPE_SHADER_FRAGMENT)
opts.provoking_vertex = key->fs.provoking_vertex;
@ -191,11 +184,9 @@ compile_nir(struct d3d12_context *ctx, struct d3d12_shader_selector *sel,
// Ubo variables
if(nir->info.num_ubos) {
shader->begin_ubo_binding = shader->nir->num_uniforms > 0 || !shader->nir->info.first_ubo_is_default_ubo ? 0 : 1;
// Ignore state_vars ubo as it is bound as root constants
unsigned num_ubo_bindings = nir->info.num_ubos - (shader->state_vars_used ? 1 : 0);
for(unsigned i = shader->has_default_ubo0 ? 0 : 1; i < num_ubo_bindings; ++i) {
shader->cb_bindings[shader->num_cb_bindings++].binding = i;
}
shader->end_ubo_binding = nir->info.num_ubos - (shader->state_vars_used ? 1 : 0);
}
#ifdef _WIN32

View file

@ -208,10 +208,9 @@ struct d3d12_shader {
struct d3d12_varying_info *tess_eval_output_vars;
struct d3d12_varying_info *tess_ctrl_input_vars;
struct {
unsigned binding;
} cb_bindings[PIPE_MAX_CONSTANT_BUFFERS];
size_t num_cb_bindings;
/* UBOs can be sparse, if there's no uniforms then ubo0 is unused, and state vars are an internal ubo */
uint32_t begin_ubo_binding;
uint32_t end_ubo_binding;
struct {
enum d3d12_state_var var;
@ -221,17 +220,18 @@ struct d3d12_shader {
size_t state_vars_size;
bool state_vars_used;
/* Samplers/textures can be sparse for some internal shaders */
struct {
uint32_t dimension;
} srv_bindings[PIPE_MAX_SHADER_SAMPLER_VIEWS];
size_t begin_srv_binding;
size_t end_srv_binding;
uint32_t begin_srv_binding;
uint32_t end_srv_binding;
/* Images and SSBOs are never sparse */
struct {
uint32_t dimension;
} uav_bindings[PIPE_MAX_SHADER_IMAGES];
bool has_default_ubo0;
unsigned pstipple_binding;
struct d3d12_shader_key key;

View file

@ -60,9 +60,8 @@ fill_cbv_descriptors(struct d3d12_context *ctx,
struct d3d12_descriptor_handle table_start;
d2d12_descriptor_heap_get_next_handle(batch->view_heap, &table_start);
for (unsigned i = 0; i < shader->num_cb_bindings; i++) {
unsigned binding = shader->cb_bindings[i].binding;
struct pipe_constant_buffer *buffer = &ctx->cbufs[stage][binding];
for (unsigned i = shader->begin_ubo_binding; i < shader->end_ubo_binding; i++) {
struct pipe_constant_buffer *buffer = &ctx->cbufs[stage][i];
D3D12_CONSTANT_BUFFER_VIEW_DESC cbv_desc = {};
if (buffer && buffer->buffer) {
@ -474,7 +473,7 @@ check_descriptors_left(struct d3d12_context *ctx, bool compute)
if (!shader)
continue;
needed_descs += shader->current->num_cb_bindings;
needed_descs += shader->current->end_ubo_binding;
needed_descs += shader->current->end_srv_binding - shader->current->begin_srv_binding;
needed_descs += shader->current->nir->info.num_ssbos;
needed_descs += shader->current->nir->info.num_images;
@ -514,7 +513,7 @@ update_shader_stage_root_parameters(struct d3d12_context *ctx,
uint64_t dirty = ctx->shader_dirty[stage];
assert(shader);
if (shader->num_cb_bindings > 0) {
if (shader->end_ubo_binding - shader->begin_ubo_binding > 0) {
if (dirty & D3D12_SHADER_DIRTY_CONSTBUF) {
assert(num_root_descriptors < MAX_DESCRIPTOR_TABLES);
root_desc_tables[num_root_descriptors] = fill_cbv_descriptors(ctx, shader, stage);

View file

@ -510,7 +510,7 @@ d3d12_lower_state_vars(nir_shader *nir, struct d3d12_shader *shader)
* exists it will be replaced by using the same binding.
* In the event there are no other UBO's, use binding slot 1 to
* be consistent with other non-default UBO's */
unsigned binding = MAX2(nir->info.num_ubos, 1);
unsigned binding = MAX2(nir->info.num_ubos, nir->info.first_ubo_is_default_ubo ? 1 : 0);
nir_foreach_variable_with_modes_safe(var, nir, nir_var_uniform) {
if (var->num_state_slots == 1 &&

View file

@ -125,13 +125,13 @@ create_root_signature(struct d3d12_context *ctx, struct d3d12_root_signature_key
unsigned stage = key->compute ? PIPE_SHADER_COMPUTE : i;
D3D12_SHADER_VISIBILITY visibility = get_shader_visibility((enum pipe_shader_type)stage);
if (key->stages[i].num_cb_bindings > 0) {
if (key->stages[i].end_cb_bindings - key->stages[i].begin_cb_bindings > 0) {
init_range_root_param(&root_params[num_params++],
&desc_ranges[num_ranges++],
D3D12_DESCRIPTOR_RANGE_TYPE_CBV,
key->stages[i].num_cb_bindings,
key->stages[i].end_cb_bindings - key->stages[i].begin_cb_bindings,
visibility,
key->stages[i].has_default_ubo0 ? 0 : 1,
key->stages[i].begin_cb_bindings,
0);
}
@ -188,7 +188,7 @@ create_root_signature(struct d3d12_context *ctx, struct d3d12_root_signature_key
if (key->stages[i].state_vars_size > 0) {
init_constant_root_param(&root_params[num_params++],
key->stages[i].num_cb_bindings + (key->stages[i].has_default_ubo0 ? 0 : 1),
key->stages[i].end_cb_bindings,
key->stages[i].state_vars_size,
visibility);
}
@ -253,11 +253,11 @@ fill_key(struct d3d12_context *ctx, struct d3d12_root_signature_key *key, bool c
ctx->gfx_pipeline_state.stages[i];
if (shader) {
key->stages[i].num_cb_bindings = shader->num_cb_bindings;
key->stages[i].begin_cb_bindings = shader->begin_ubo_binding;
key->stages[i].end_cb_bindings = shader->end_ubo_binding;
key->stages[i].end_srv_binding = shader->end_srv_binding;
key->stages[i].begin_srv_binding = shader->begin_srv_binding;
key->stages[i].state_vars_size = shader->state_vars_size;
key->stages[i].has_default_ubo0 = shader->has_default_ubo0;
key->stages[i].num_ssbos = shader->nir->info.num_ssbos;
key->stages[i].num_images = shader->nir->info.num_images;

View file

@ -30,13 +30,13 @@ struct d3d12_root_signature_key {
bool compute;
bool has_stream_output;
struct {
unsigned num_cb_bindings;
unsigned begin_cb_bindings;
unsigned end_cb_bindings;
unsigned end_srv_binding;
unsigned begin_srv_binding;
unsigned state_vars_size;
unsigned num_ssbos;
unsigned num_images;
bool has_default_ubo0;
} stages[D3D12_GFX_SHADER_STAGES];
};

View file

@ -152,6 +152,7 @@ nir_options = {
nir_lower_dfloor |
nir_lower_dceil |
nir_lower_dround_even,
.lower_uniforms_to_ubo = true,
.max_unroll_iterations = 32, /* arbitrary */
.force_indirect_unrolling = (nir_var_shader_in | nir_var_shader_out),
.lower_device_index_to_zero = true,
@ -3365,7 +3366,7 @@ get_resource_handle(struct ntd_context *ctx, nir_src *src, enum dxil_resource_cl
* load_vulkan_descriptor handle creation.
*/
unsigned base_binding = 0;
if (ctx->opts->environment == DXIL_ENVIRONMENT_GL &&
if (ctx->shader->info.first_ubo_is_default_ubo &&
class == DXIL_RESOURCE_CLASS_CBV)
base_binding = 1;
@ -5877,16 +5878,17 @@ emit_cbvs(struct ntd_context *ctx)
} else {
if (ctx->shader->info.num_ubos) {
const unsigned ubo_size = 16384 /*4096 vec4's*/;
bool has_ubo0 = !ctx->opts->no_ubo0;
uint array_base = ctx->shader->info.first_ubo_is_default_ubo ? 1 : 0;
bool has_ubo0 = ctx->shader->num_uniforms > 0 && ctx->shader->info.first_ubo_is_default_ubo;
bool has_state_vars = ctx->opts->last_ubo_is_not_arrayed;
unsigned ubo1_array_size = ctx->shader->info.num_ubos -
(has_state_vars ? 2 : 1);
unsigned ubo1_array_size = ctx->shader->info.num_ubos - array_base -
(has_state_vars ? 1 : 0);
if (has_ubo0 &&
!emit_cbv(ctx, 0, 0, ubo_size, 1, "__ubo_uniforms"))
return false;
if (ubo1_array_size &&
!emit_cbv(ctx, 1, 0, ubo_size, ubo1_array_size, "__ubos"))
!emit_cbv(ctx, array_base, 0, ubo_size, ubo1_array_size, "__ubos"))
return false;
if (has_state_vars &&
!emit_cbv(ctx, ctx->shader->info.num_ubos - 1, 0, ubo_size, 1, "__ubo_state_vars"))

View file

@ -79,7 +79,6 @@ struct nir_to_dxil_options {
bool interpolate_at_vertex;
bool lower_int16;
bool disable_math_refactoring;
bool no_ubo0;
bool last_ubo_is_not_arrayed;
unsigned provoking_vertex;
unsigned num_kernel_globals;