diff --git a/src/gallium/drivers/d3d12/d3d12_compiler.cpp b/src/gallium/drivers/d3d12/d3d12_compiler.cpp index 37c705856a6..ff3a105502a 100644 --- a/src/gallium/drivers/d3d12/d3d12_compiler.cpp +++ b/src/gallium/drivers/d3d12/d3d12_compiler.cpp @@ -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); } diff --git a/src/gallium/drivers/d3d12/d3d12_compiler.h b/src/gallium/drivers/d3d12/d3d12_compiler.h index b14f9e39ff7..de16ff23711 100644 --- a/src/gallium/drivers/d3d12/d3d12_compiler.h +++ b/src/gallium/drivers/d3d12/d3d12_compiler.h @@ -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; diff --git a/src/gallium/drivers/d3d12/d3d12_context.cpp b/src/gallium/drivers/d3d12/d3d12_context.cpp index aec5501d721..3a2d6ee3731 100644 --- a/src/gallium/drivers/d3d12/d3d12_context.cpp +++ b/src/gallium/drivers/d3d12/d3d12_context.cpp @@ -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]; diff --git a/src/gallium/drivers/d3d12/d3d12_context.h b/src/gallium/drivers/d3d12/d3d12_context.h index befbbdd0eb7..2fdb5f8d6ba 100644 --- a/src/gallium/drivers/d3d12/d3d12_context.h +++ b/src/gallium/drivers/d3d12/d3d12_context.h @@ -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; diff --git a/src/gallium/drivers/d3d12/d3d12_nir_passes.c b/src/gallium/drivers/d3d12/d3d12_nir_passes.c index e0b30d20545..3532a9dcd05 100644 --- a/src/gallium/drivers/d3d12/d3d12_nir_passes.c +++ b/src/gallium/drivers/d3d12/d3d12_nir_passes.c @@ -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); } diff --git a/src/gallium/drivers/d3d12/d3d12_nir_passes.h b/src/gallium/drivers/d3d12/d3d12_nir_passes.h index 443341c010f..4550dc253a0 100644 --- a/src/gallium/drivers/d3d12/d3d12_nir_passes.h +++ b/src/gallium/drivers/d3d12/d3d12_nir_passes.h @@ -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);