summaryrefslogtreecommitdiff
path: root/src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2021-08-01 18:57:45 -0300
committerGravatar Fernando Sahmkow2021-11-16 22:11:29 +0100
commite66d5b88a6f1c2d85c5cd8e351c6ed52c96a0ecf (patch)
tree0107548906df0b9d42e89451489be6a54ed71bf3 /src/shader_recompiler/backend/spirv/emit_spirv_image.cpp
parentshader: Properly blacklist and scale image loads (diff)
downloadyuzu-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.cpp74
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
228Id 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
256Id 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
229Id EmitBindlessImageSampleImplicitLod(EmitContext&) { 263Id EmitBindlessImageSampleImplicitLod(EmitContext&) {
@@ -471,29 +505,27 @@ void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id
471} 505}
472 506
473Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index) { 507Id 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
519Id 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