diff options
| author | 2021-08-01 18:57:45 -0300 | |
|---|---|---|
| committer | 2021-11-16 22:11:29 +0100 | |
| commit | e66d5b88a6f1c2d85c5cd8e351c6ed52c96a0ecf (patch) | |
| tree | 0107548906df0b9d42e89451489be6a54ed71bf3 /src/shader_recompiler/backend/spirv/emit_spirv_image.cpp | |
| parent | shader: Properly blacklist and scale image loads (diff) | |
| download | yuzu-e66d5b88a6f1c2d85c5cd8e351c6ed52c96a0ecf.tar.gz yuzu-e66d5b88a6f1c2d85c5cd8e351c6ed52c96a0ecf.tar.xz yuzu-e66d5b88a6f1c2d85c5cd8e351c6ed52c96a0ecf.zip | |
shader: Properly scale image reads and add GL SPIR-V support
Thanks for everything!
Diffstat (limited to 'src/shader_recompiler/backend/spirv/emit_spirv_image.cpp')
| -rw-r--r-- | src/shader_recompiler/backend/spirv/emit_spirv_image.cpp | 74 |
1 files changed, 53 insertions, 21 deletions
diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp index 7d7c0627e..519ce8b9b 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp | |||
| @@ -224,6 +224,40 @@ Id Emit(MethodPtrType sparse_ptr, MethodPtrType non_sparse_ptr, EmitContext& ctx | |||
| 224 | Decorate(ctx, inst, sample); | 224 | Decorate(ctx, inst, sample); |
| 225 | return ctx.OpCompositeExtract(result_type, sample, 1U); | 225 | return ctx.OpCompositeExtract(result_type, sample, 1U); |
| 226 | } | 226 | } |
| 227 | |||
| 228 | Id IsScaled(EmitContext& ctx, const IR::Value& index, Id member_index, u32 base_index) { | ||
| 229 | const Id push_constant_u32{ctx.TypePointer(spv::StorageClass::PushConstant, ctx.U32[1])}; | ||
| 230 | Id bit{}; | ||
| 231 | if (index.IsImmediate()) { | ||
| 232 | // Use BitwiseAnd instead of BitfieldExtract for better codegen on Nvidia OpenGL. | ||
| 233 | // LOP32I.NZ is used to set the predicate rather than BFE+ISETP. | ||
| 234 | const u32 index_value{index.U32() + base_index}; | ||
| 235 | const Id word_index{ctx.Const(index_value / 32)}; | ||
| 236 | const Id bit_index_mask{ctx.Const(1u << (index_value % 32))}; | ||
| 237 | const Id pointer{ctx.OpAccessChain(push_constant_u32, ctx.rescaling_push_constants, | ||
| 238 | member_index, word_index)}; | ||
| 239 | const Id word{ctx.OpLoad(ctx.U32[1], pointer)}; | ||
| 240 | bit = ctx.OpBitwiseAnd(ctx.U32[1], word, bit_index_mask); | ||
| 241 | } else { | ||
| 242 | Id index_value{ctx.Def(index)}; | ||
| 243 | if (base_index != 0) { | ||
| 244 | index_value = ctx.OpIAdd(ctx.U32[1], index_value, ctx.Const(base_index)); | ||
| 245 | } | ||
| 246 | const Id word_index{ctx.OpShiftRightArithmetic(ctx.U32[1], index_value, ctx.Const(5u))}; | ||
| 247 | const Id pointer{ctx.OpAccessChain(push_constant_u32, ctx.rescaling_push_constants, | ||
| 248 | member_index, word_index)}; | ||
| 249 | const Id word{ctx.OpLoad(ctx.U32[1], pointer)}; | ||
| 250 | const Id bit_index{ctx.OpBitwiseAnd(ctx.U32[1], index_value, ctx.Const(31u))}; | ||
| 251 | bit = ctx.OpBitFieldUExtract(ctx.U32[1], index_value, bit_index, ctx.Const(1u)); | ||
| 252 | } | ||
| 253 | return ctx.OpINotEqual(ctx.U1, bit, ctx.u32_zero_value); | ||
| 254 | } | ||
| 255 | |||
| 256 | Id BitTest(EmitContext& ctx, Id mask, Id bit) { | ||
| 257 | const Id shifted{ctx.OpShiftRightLogical(ctx.U32[1], mask, bit)}; | ||
| 258 | const Id bit_value{ctx.OpBitwiseAnd(ctx.U32[1], shifted, ctx.Const(1u))}; | ||
| 259 | return ctx.OpINotEqual(ctx.U1, bit_value, ctx.u32_zero_value); | ||
| 260 | } | ||
| 227 | } // Anonymous namespace | 261 | } // Anonymous namespace |
| 228 | 262 | ||
| 229 | Id EmitBindlessImageSampleImplicitLod(EmitContext&) { | 263 | Id EmitBindlessImageSampleImplicitLod(EmitContext&) { |
| @@ -471,29 +505,27 @@ void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id | |||
| 471 | } | 505 | } |
| 472 | 506 | ||
| 473 | Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index) { | 507 | Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index) { |
| 474 | const Id push_constant_u32{ctx.TypePointer(spv::StorageClass::PushConstant, ctx.U32[1])}; | 508 | if (ctx.profile.unified_descriptor_binding) { |
| 475 | const Id member_index{ctx.Const(ctx.rescaling_textures_member_index)}; | 509 | const Id member_index{ctx.Const(ctx.rescaling_textures_member_index)}; |
| 476 | Id bit{}; | 510 | return IsScaled(ctx, index, member_index, ctx.texture_rescaling_index); |
| 477 | if (index.IsImmediate()) { | ||
| 478 | // Use BitwiseAnd instead of BitfieldExtract for better codegen on Nvidia OpenGL. | ||
| 479 | // LOP32I.NZ is used to set the predicate rather than BFE+ISETP. | ||
| 480 | const u32 index_value{index.U32()}; | ||
| 481 | const Id word_index{ctx.Const(index_value / 32)}; | ||
| 482 | const Id bit_index_mask{ctx.Const(1u << (index_value % 32))}; | ||
| 483 | const Id pointer{ctx.OpAccessChain(push_constant_u32, ctx.rescaling_push_constants, | ||
| 484 | member_index, word_index)}; | ||
| 485 | const Id word{ctx.OpLoad(ctx.U32[1], pointer)}; | ||
| 486 | bit = ctx.OpBitwiseAnd(ctx.U32[1], word, bit_index_mask); | ||
| 487 | } else { | 511 | } else { |
| 488 | const Id index_value{ctx.Def(index)}; | 512 | const Id composite{ctx.OpLoad(ctx.F32[4], ctx.rescaling_uniform_constant)}; |
| 489 | const Id word_index{ctx.OpShiftRightArithmetic(ctx.U32[1], index_value, ctx.Const(5u))}; | 513 | const Id mask_f32{ctx.OpCompositeExtract(ctx.F32[1], composite, 0u)}; |
| 490 | const Id pointer{ctx.OpAccessChain(push_constant_u32, ctx.rescaling_push_constants, | 514 | const Id mask{ctx.OpBitcast(ctx.U32[1], mask_f32)}; |
| 491 | member_index, word_index)}; | 515 | return BitTest(ctx, mask, ctx.Def(index)); |
| 492 | const Id word{ctx.OpLoad(ctx.U32[1], pointer)}; | 516 | } |
| 493 | const Id bit_index{ctx.OpBitwiseAnd(ctx.U32[1], index_value, ctx.Const(31u))}; | 517 | } |
| 494 | bit = ctx.OpBitFieldUExtract(ctx.U32[1], index_value, bit_index, ctx.Const(1u)); | 518 | |
| 519 | Id EmitIsImageScaled(EmitContext& ctx, const IR::Value& index) { | ||
| 520 | if (ctx.profile.unified_descriptor_binding) { | ||
| 521 | const Id member_index{ctx.Const(ctx.rescaling_images_member_index)}; | ||
| 522 | return IsScaled(ctx, index, member_index, ctx.image_rescaling_index); | ||
| 523 | } else { | ||
| 524 | const Id composite{ctx.OpLoad(ctx.F32[4], ctx.rescaling_uniform_constant)}; | ||
| 525 | const Id mask_f32{ctx.OpCompositeExtract(ctx.F32[1], composite, 1u)}; | ||
| 526 | const Id mask{ctx.OpBitcast(ctx.U32[1], mask_f32)}; | ||
| 527 | return BitTest(ctx, mask, ctx.Def(index)); | ||
| 495 | } | 528 | } |
| 496 | return ctx.OpINotEqual(ctx.U1, bit, ctx.u32_zero_value); | ||
| 497 | } | 529 | } |
| 498 | 530 | ||
| 499 | } // namespace Shader::Backend::SPIRV | 531 | } // namespace Shader::Backend::SPIRV |