From fccd6e275c3278a5abe814e9a0e535ffca436243 Mon Sep 17 00:00:00 2001 From: Jesse Natalie Date: Mon, 7 Feb 2022 09:49:33 -0800 Subject: [PATCH] d3d12: Support clip halfz Reviewed-by: Giancarlo Devich Part-of: --- docs/features.txt | 2 +- .../drivers/d3d12/ci/d3d12-quick_gl.txt | 7 ++----- src/gallium/drivers/d3d12/d3d12_compiler.cpp | 10 +++++++--- src/gallium/drivers/d3d12/d3d12_compiler.h | 1 + src/gallium/drivers/d3d12/d3d12_context.cpp | 18 +++++++++++++++++- src/gallium/drivers/d3d12/d3d12_nir_passes.c | 14 ++++++++++---- src/gallium/drivers/d3d12/d3d12_nir_passes.h | 2 +- src/gallium/drivers/d3d12/d3d12_screen.cpp | 1 + 8 files changed, 40 insertions(+), 15 deletions(-) diff --git a/docs/features.txt b/docs/features.txt index 47ba684337e..56b8adacdf2 100644 --- a/docs/features.txt +++ b/docs/features.txt @@ -213,7 +213,7 @@ GL 4.4, GLSL 4.40 -- all DONE: i965/gen8+, nvc0, r600, radeonsi, llvmpipe, zink GL 4.5, GLSL 4.50 -- all DONE: nvc0, r600, radeonsi, llvmpipe, zink GL_ARB_ES3_1_compatibility DONE (i965/hsw+, softpipe, virgl) - GL_ARB_clip_control DONE (freedreno, i965, nv50, softpipe, virgl, lima) + GL_ARB_clip_control DONE (freedreno, i965, nv50, softpipe, virgl, lima, d3d12) GL_ARB_conditional_render_inverted DONE (freedreno, i965, nv50, softpipe, virgl, panfrost, d3d12) GL_ARB_cull_distance DONE (freedreno/a6xx, i965, nv50, softpipe, virgl) GL_ARB_derivative_control DONE (i965, nv50, softpipe, virgl) diff --git a/src/gallium/drivers/d3d12/ci/d3d12-quick_gl.txt b/src/gallium/drivers/d3d12/ci/d3d12-quick_gl.txt index c6dbead427b..61c1d393f9f 100644 --- a/src/gallium/drivers/d3d12/ci/d3d12-quick_gl.txt +++ b/src/gallium/drivers/d3d12/ci/d3d12-quick_gl.txt @@ -319,9 +319,6 @@ spec/arb_clear_texture/arb_clear_texture-sized-formats: skip spec/arb_clear_texture/arb_clear_texture-srgb: skip spec/arb_clear_texture/arb_clear_texture-stencil: skip spec/arb_clear_texture/arb_clear_texture-texview: skip -spec/arb_clip_control/arb_clip_control-clip-control: skip -spec/arb_clip_control/arb_clip_control-depth-precision: skip -spec/arb_clip_control/arb_clip_control-viewport: skip spec/arb_compute_shader/compute-and-render-bug-109630: fail spec/arb_copy_image/arb_copy_image-api_errors: skip spec/arb_copy_image/arb_copy_image-format-swizzle: skip @@ -3515,10 +3512,10 @@ wgl/wgl-sanity: skip summary: name: results ---- -------- - pass: 17870 + pass: 17873 fail: 2035 crash: 12 - skip: 1448 + skip: 1445 timeout: 0 warn: 10 incomplete: 0 diff --git a/src/gallium/drivers/d3d12/d3d12_compiler.cpp b/src/gallium/drivers/d3d12/d3d12_compiler.cpp index b88255b1368..d6f9620bedc 100644 --- a/src/gallium/drivers/d3d12/d3d12_compiler.cpp +++ b/src/gallium/drivers/d3d12/d3d12_compiler.cpp @@ -123,8 +123,9 @@ 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, key->invert_depth); - NIR_PASS_V(nir, nir_lower_clip_halfz); + NIR_PASS_V(nir, d3d12_nir_invert_depth, key->invert_depth, key->halfz); + if (!key->halfz) + NIR_PASS_V(nir, nir_lower_clip_halfz); NIR_PASS_V(nir, d3d12_lower_yflip); } NIR_PASS_V(nir, nir_lower_packed_ubo_loads); @@ -790,7 +791,8 @@ d3d12_compare_shader_keys(const d3d12_shader_key *expect, const d3d12_shader_key expect->n_images * sizeof(struct d3d12_image_format_conversion_info))) return false; - if (expect->invert_depth != have->invert_depth) + if (expect->invert_depth != have->invert_depth || + expect->halfz != have->halfz) return false; if (expect->stage == PIPE_SHADER_VERTEX) { @@ -930,6 +932,8 @@ d3d12_fill_shader_key(struct d3d12_selection_context *sel_ctx, (!next || next->stage == PIPE_SHADER_FRAGMENT))) { key->last_vertex_processing_stage = 1; key->invert_depth = sel_ctx->ctx->reverse_depth_range; + key->halfz = sel_ctx->ctx->gfx_pipeline_state.rast ? + sel_ctx->ctx->gfx_pipeline_state.rast->base.clip_halfz : false; if (sel_ctx->ctx->pstipple.enabled && sel_ctx->ctx->gfx_pipeline_state.rast->base.poly_stipple_enable) key->next_varying_inputs |= VARYING_BIT_POS; diff --git a/src/gallium/drivers/d3d12/d3d12_compiler.h b/src/gallium/drivers/d3d12/d3d12_compiler.h index aed79f95c1e..20298e2353f 100644 --- a/src/gallium/drivers/d3d12/d3d12_compiler.h +++ b/src/gallium/drivers/d3d12/d3d12_compiler.h @@ -92,6 +92,7 @@ struct d3d12_shader_key { uint64_t prev_varying_outputs; unsigned last_vertex_processing_stage : 1; unsigned invert_depth : 16; + unsigned halfz : 1; 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 1b84a68d23f..fa4ab2dffca 100644 --- a/src/gallium/drivers/d3d12/d3d12_context.cpp +++ b/src/gallium/drivers/d3d12/d3d12_context.cpp @@ -1313,9 +1313,25 @@ d3d12_set_viewport_states(struct pipe_context *pctx, ctx->viewports[start_slot + i].TopLeftX = state[i].translate[0] - state[i].scale[0]; ctx->viewports[start_slot + i].Width = state[i].scale[0] * 2; - float near_depth = state[i].translate[2] - state[i].scale[2]; + float near_depth = state[i].translate[2]; float far_depth = state[i].translate[2] + state[i].scale[2]; + /* When the rasterizer is configured for "full" depth clipping ([-1, 1]) + * the viewport that we get is set to cover the positive half of clip space. + * E.g. a [0, 1] viewport from the GL API will come to the driver as [0.5, 1]. + * Since we halve clipping space from [-1, 1] to [0, 1], we need to double the + * viewport, treating translate as the center instead of the near plane. When + * the rasterizer is configured for "half" depth clipping ([0, 1]), the viewport + * covers the entire clip range, so no fixup is needed. + * + * Note: If halfz mode changes, both the rasterizer and viewport are dirtied, + * and on the next draw we will get the rasterizer state first, and viewport + * second, because ST_NEW_RASTERIZER comes before ST_NEW_VIEWPORT. + */ + if (ctx->gfx_pipeline_state.rast && !ctx->gfx_pipeline_state.rast->base.clip_halfz) { + near_depth -= state[i].scale[2]; + } + bool reverse_depth_range = near_depth > far_depth; if (reverse_depth_range) { float tmp = near_depth; diff --git a/src/gallium/drivers/d3d12/d3d12_nir_passes.c b/src/gallium/drivers/d3d12/d3d12_nir_passes.c index 9dddadaf9ee..3859abf955d 100644 --- a/src/gallium/drivers/d3d12/d3d12_nir_passes.c +++ b/src/gallium/drivers/d3d12/d3d12_nir_passes.c @@ -391,6 +391,7 @@ d3d12_lower_load_patch_vertices_in(struct nir_shader *nir) struct invert_depth_state { unsigned viewport_mask; + bool clip_halfz; nir_ssa_def *viewport_index; nir_instr *store_pos_instr; }; @@ -415,10 +416,14 @@ invert_depth_impl(nir_builder *b, struct invert_depth_state *state) if (state->viewport_index) { nir_push_if(b, nir_test_mask(b, nir_ishl(b, nir_imm_int(b, 1), state->viewport_index), state->viewport_mask)); } + nir_ssa_def *old_depth = nir_channel(b, pos, 2); + nir_ssa_def *new_depth = nir_fneg(b, old_depth); + if (state->clip_halfz) + new_depth = nir_fadd_imm(b, new_depth, 1.0); 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)), + new_depth, nir_channel(b, pos, 3)); if (state->viewport_index) { nir_pop_if(b, NULL); @@ -453,19 +458,20 @@ invert_depth_instr(nir_builder *b, struct nir_instr *instr, struct invert_depth_ } /* In OpenGL the windows space depth value z_w is evaluated according to "s * z_d + b" - * with "s + (far - near) / 2" (depth clip:minus_one_to_one) [OpenGL 3.3, 2.13.1]. + * with "s = (far - near) / 2" (depth clip:minus_one_to_one) [OpenGL 3.3, 2.13.1]. * When we switch the far and near value to satisfy DirectX requirements we have * to compensate by inverting "z_d' = -z_d" with this lowering pass. + * When depth clip is set zero_to_one, we compensate with "z_d' = 1.0f - z_d" instead. */ void -d3d12_nir_invert_depth(nir_shader *shader, unsigned viewport_mask) +d3d12_nir_invert_depth(nir_shader *shader, unsigned viewport_mask, bool clip_halfz) { 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 }; + struct invert_depth_state state = { viewport_mask, clip_halfz }; nir_foreach_function(function, shader) { if (function->impl) { nir_builder b; diff --git a/src/gallium/drivers/d3d12/d3d12_nir_passes.h b/src/gallium/drivers/d3d12/d3d12_nir_passes.h index 818b12abf31..62034f0b85f 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, unsigned viewport_mask); +d3d12_nir_invert_depth(nir_shader *s, unsigned viewport_mask, bool clip_halfz); bool nir_lower_packed_ubo_loads(struct nir_shader *nir); diff --git a/src/gallium/drivers/d3d12/d3d12_screen.cpp b/src/gallium/drivers/d3d12/d3d12_screen.cpp index 88f8209709a..11dc0c35b2d 100644 --- a/src/gallium/drivers/d3d12/d3d12_screen.cpp +++ b/src/gallium/drivers/d3d12/d3d12_screen.cpp @@ -329,6 +329,7 @@ d3d12_get_param(struct pipe_screen *pscreen, enum pipe_cap param) case PIPE_CAP_MEMOBJ: case PIPE_CAP_FENCE_SIGNAL: case PIPE_CAP_TIMELINE_SEMAPHORE_IMPORT: + case PIPE_CAP_CLIP_HALFZ: return 1; case PIPE_CAP_MAX_VERTEX_STREAMS: