d3d12: Update depth invert to deal with multi-viewport

Turn the context state and shader key into a bitmask. When lowering
the depth invert into the shader, scan for writes to viewport index.
If found, move position to the end of the function (or current vertex)
and check if the current viewport needs the depth invert before applying.

Reviewed-by: Sil Vilerino <sivileri@microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/14881>
This commit is contained in:
Jesse Natalie 2022-02-04 07:10:54 -08:00 committed by Marge Bot
parent 52b3e6be5f
commit a26f647caa
6 changed files with 68 additions and 20 deletions

View file

@ -165,7 +165,7 @@ compile_nir(struct d3d12_context *ctx, struct d3d12_shader_selector *sel,
if (key->last_vertex_processing_stage) {
if (key->invert_depth)
NIR_PASS_V(nir, d3d12_nir_invert_depth);
NIR_PASS_V(nir, d3d12_nir_invert_depth, key->invert_depth);
NIR_PASS_V(nir, nir_lower_clip_halfz);
NIR_PASS_V(nir, d3d12_lower_yflip);
}

View file

@ -94,7 +94,7 @@ struct d3d12_shader_key {
uint64_t next_varying_inputs;
uint64_t prev_varying_outputs;
unsigned last_vertex_processing_stage : 1;
unsigned invert_depth : 1;
unsigned invert_depth : 16;
unsigned samples_int_textures : 1;
unsigned input_clip_size : 4;
unsigned tex_saturate_s : PIPE_MAX_SAMPLERS;

View file

@ -1300,12 +1300,14 @@ d3d12_set_viewport_states(struct pipe_context *pctx,
float near_depth = state[i].translate[2] - state[i].scale[2];
float far_depth = state[i].translate[2] + state[i].scale[2];
ctx->reverse_depth_range = near_depth > far_depth;
if (ctx->reverse_depth_range) {
bool reverse_depth_range = near_depth > far_depth;
if (reverse_depth_range) {
float tmp = near_depth;
near_depth = far_depth;
far_depth = tmp;
}
ctx->reverse_depth_range |= (1 << (start_slot + i));
} else
ctx->reverse_depth_range &= ~(1 << (start_slot + i));
ctx->viewports[start_slot + i].MinDepth = near_depth;
ctx->viewports[start_slot + i].MaxDepth = far_depth;
ctx->viewport_states[start_slot + i] = state[i];

View file

@ -234,7 +234,7 @@ struct d3d12_context {
unsigned cmdlist_dirty;
ID3D12PipelineState *current_gfx_pso;
ID3D12PipelineState *current_compute_pso;
bool reverse_depth_range;
uint16_t reverse_depth_range;
ID3D12Fence *cmdqueue_fence;
uint64_t fence_value;

View file

@ -388,30 +388,70 @@ d3d12_lower_load_patch_vertices_in(struct nir_shader *nir)
nir_metadata_block_index | nir_metadata_dominance, &var);
}
static void
invert_depth(nir_builder *b, struct nir_instr *instr)
struct invert_depth_state
{
if (instr->type != nir_instr_type_intrinsic)
return;
unsigned viewport_mask;
nir_ssa_def *viewport_index;
nir_instr *store_pos_instr;
};
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
if (intr->intrinsic != nir_intrinsic_store_deref)
return;
static void
invert_depth_impl(nir_builder *b, struct invert_depth_state *state)
{
assert(state->store_pos_instr);
nir_variable *var = nir_intrinsic_get_var(intr, 0);
if (var->data.mode != nir_var_shader_out ||
var->data.location != VARYING_SLOT_POS)
return;
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(state->store_pos_instr);
if (state->viewport_index) {
/* Cursor is assigned before calling. Make sure that storing pos comes
* after computing the viewport.
*/
nir_instr_move(b->cursor, &intr->instr);
}
b->cursor = nir_before_instr(&intr->instr);
nir_ssa_def *pos = nir_ssa_for_src(b, intr->src[1], 4);
if (state->viewport_index) {
nir_push_if(b, nir_i2b1(b, nir_iand_imm(b,
nir_ishl(b, nir_imm_int(b, 1), state->viewport_index),
state->viewport_mask)));
}
nir_ssa_def *def = nir_vec4(b,
nir_channel(b, pos, 0),
nir_channel(b, pos, 1),
nir_fneg(b, nir_channel(b, pos, 2)),
nir_channel(b, pos, 3));
if (state->viewport_index) {
nir_pop_if(b, NULL);
def = nir_if_phi(b, def, pos);
}
nir_instr_rewrite_src(&intr->instr, intr->src + 1, nir_src_for_ssa(def));
state->viewport_index = NULL;
state->store_pos_instr = NULL;
}
static void
invert_depth_instr(nir_builder *b, struct nir_instr *instr, struct invert_depth_state *state)
{
if (instr->type != nir_instr_type_intrinsic)
return;
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
if (intr->intrinsic == nir_intrinsic_store_deref) {
nir_variable *var = nir_intrinsic_get_var(intr, 0);
if (var->data.mode != nir_var_shader_out)
return;
if (var->data.location == VARYING_SLOT_VIEWPORT)
state->viewport_index = intr->src[1].ssa;
if (var->data.location == VARYING_SLOT_POS)
state->store_pos_instr = instr;
} else if (intr->intrinsic == nir_intrinsic_emit_vertex) {
b->cursor = nir_before_instr(instr);
invert_depth_impl(b, state);
}
}
/* In OpenGL the windows space depth value z_w is evaluated according to "s * z_d + b"
@ -420,13 +460,14 @@ invert_depth(nir_builder *b, struct nir_instr *instr)
* to compensate by inverting "z_d' = -z_d" with this lowering pass.
*/
void
d3d12_nir_invert_depth(nir_shader *shader)
d3d12_nir_invert_depth(nir_shader *shader, unsigned viewport_mask)
{
if (shader->info.stage != MESA_SHADER_VERTEX &&
shader->info.stage != MESA_SHADER_TESS_EVAL &&
shader->info.stage != MESA_SHADER_GEOMETRY)
return;
struct invert_depth_state state = { viewport_mask };
nir_foreach_function(function, shader) {
if (function->impl) {
nir_builder b;
@ -434,10 +475,15 @@ d3d12_nir_invert_depth(nir_shader *shader)
nir_foreach_block(block, function->impl) {
nir_foreach_instr_safe(instr, block) {
invert_depth(&b, instr);
invert_depth_instr(&b, instr, &state);
}
}
if (state.store_pos_instr) {
b.cursor = nir_after_block(function->impl->end_block);
invert_depth_impl(&b, &state);
}
nir_metadata_preserve(function->impl, nir_metadata_block_index |
nir_metadata_dominance);
}

View file

@ -88,7 +88,7 @@ bool
d3d12_fix_io_uint_type(struct nir_shader *s, uint64_t in_mask, uint64_t out_mask);
void
d3d12_nir_invert_depth(nir_shader *s);
d3d12_nir_invert_depth(nir_shader *s, unsigned viewport_mask);
bool
d3d12_lower_int_cubmap_to_array(nir_shader *s);