diff options
| author | 2023-04-05 01:29:46 +0200 | |
|---|---|---|
| committer | 2023-04-08 16:12:30 +0200 | |
| commit | 780240e6979b198e7bd10feaad5399b8b4b63762 (patch) | |
| tree | c145f48c66cf003e618cefc63496e3f5b7637f56 /src/shader_recompiler/backend/glsl | |
| parent | Merge pull request #10024 from german77/crysis (diff) | |
| download | yuzu-780240e6979b198e7bd10feaad5399b8b4b63762.tar.gz yuzu-780240e6979b198e7bd10feaad5399b8b4b63762.tar.xz yuzu-780240e6979b198e7bd10feaad5399b8b4b63762.zip | |
shader_recompiler: Add subpixel offset for correct rounding at `ImageGather`
On AMD a subpixel offset of 1/512 of the texel size is applied to the texture coordinates at a ImageGather call to ensure the rounding at the texel centers is done the same way as in Maxwell or other Nvidia architectures.
See https://www.reedbeta.com/blog/texture-gathers-and-coordinate-precision/ for more details why this might be necessary.
This should fix shadow artifacts at object edges in Zelda: Breath of the Wild (#9957, #6956).
Diffstat (limited to 'src/shader_recompiler/backend/glsl')
| -rw-r--r-- | src/shader_recompiler/backend/glsl/emit_glsl_image.cpp | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp index f335c8af0..418505475 100644 --- a/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp +++ b/src/shader_recompiler/backend/glsl/emit_glsl_image.cpp | |||
| @@ -143,6 +143,21 @@ IR::Inst* PrepareSparse(IR::Inst& inst) { | |||
| 143 | } | 143 | } |
| 144 | return sparse_inst; | 144 | return sparse_inst; |
| 145 | } | 145 | } |
| 146 | |||
| 147 | std::string ImageGatherSubpixelOffset(const IR::TextureInstInfo& info, std::string_view texture, | ||
| 148 | std::string_view coords) { | ||
| 149 | switch (info.type) { | ||
| 150 | case TextureType::Color2D: | ||
| 151 | case TextureType::Color2DRect: | ||
| 152 | return fmt::format("{}+vec2(0.001953125)/vec2(textureSize({}, 0))", coords, texture); | ||
| 153 | case TextureType::ColorArray2D: | ||
| 154 | case TextureType::ColorCube: | ||
| 155 | return fmt::format("vec3({0}.xy+vec2(0.001953125)/vec2(textureSize({1}, 0)),{0}.z)", coords, | ||
| 156 | texture); | ||
| 157 | default: | ||
| 158 | return std::string{coords}; | ||
| 159 | } | ||
| 160 | } | ||
| 146 | } // Anonymous namespace | 161 | } // Anonymous namespace |
| 147 | 162 | ||
| 148 | void EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | 163 | void EmitImageSampleImplicitLod(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, |
| @@ -340,6 +355,13 @@ void EmitImageGather(EmitContext& ctx, IR::Inst& inst, const IR::Value& index, | |||
| 340 | LOG_WARNING(Shader_GLSL, "Device does not support sparse texture queries. STUBBING"); | 355 | LOG_WARNING(Shader_GLSL, "Device does not support sparse texture queries. STUBBING"); |
| 341 | ctx.AddU1("{}=true;", *sparse_inst); | 356 | ctx.AddU1("{}=true;", *sparse_inst); |
| 342 | } | 357 | } |
| 358 | std::string coords_with_subpixel_offset; | ||
| 359 | if (ctx.profile.need_gather_subpixel_offset) { | ||
| 360 | // Apply a subpixel offset of 1/512 the texel size of the texture to ensure same rounding on | ||
| 361 | // AMD hardware as on Maxwell or other Nvidia architectures. | ||
| 362 | coords_with_subpixel_offset = ImageGatherSubpixelOffset(info, texture, coords); | ||
| 363 | coords = coords_with_subpixel_offset; | ||
| 364 | } | ||
| 343 | if (!sparse_inst || !supports_sparse) { | 365 | if (!sparse_inst || !supports_sparse) { |
| 344 | if (offset.IsEmpty()) { | 366 | if (offset.IsEmpty()) { |
| 345 | ctx.Add("{}=textureGather({},{},int({}));", texel, texture, coords, | 367 | ctx.Add("{}=textureGather({},{},int({}));", texel, texture, coords, |
| @@ -387,6 +409,13 @@ void EmitImageGatherDref(EmitContext& ctx, IR::Inst& inst, const IR::Value& inde | |||
| 387 | LOG_WARNING(Shader_GLSL, "Device does not support sparse texture queries. STUBBING"); | 409 | LOG_WARNING(Shader_GLSL, "Device does not support sparse texture queries. STUBBING"); |
| 388 | ctx.AddU1("{}=true;", *sparse_inst); | 410 | ctx.AddU1("{}=true;", *sparse_inst); |
| 389 | } | 411 | } |
| 412 | std::string coords_with_subpixel_offset; | ||
| 413 | if (ctx.profile.need_gather_subpixel_offset) { | ||
| 414 | // Apply a subpixel offset of 1/512 the texel size of the texture to ensure same rounding on | ||
| 415 | // AMD hardware as on Maxwell or other Nvidia architectures. | ||
| 416 | coords_with_subpixel_offset = ImageGatherSubpixelOffset(info, texture, coords); | ||
| 417 | coords = coords_with_subpixel_offset; | ||
| 418 | } | ||
| 390 | if (!sparse_inst || !supports_sparse) { | 419 | if (!sparse_inst || !supports_sparse) { |
| 391 | if (offset.IsEmpty()) { | 420 | if (offset.IsEmpty()) { |
| 392 | ctx.Add("{}=textureGather({},{},{});", texel, texture, coords, dref); | 421 | ctx.Add("{}=textureGather({},{},{});", texel, texture, coords, dref); |