diff options
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 18 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 17 |
2 files changed, 26 insertions, 9 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index fd4e0746e..da64430e9 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -270,8 +270,22 @@ union Instruction { | |||
| 270 | } tex; | 270 | } tex; |
| 271 | 271 | ||
| 272 | union { | 272 | union { |
| 273 | // TODO(bunnei): This is just a guess, needs to be verified | 273 | BitField<50, 3, u64> component_mask_selector; |
| 274 | BitField<52, 1, u64> enable_g_component; | 274 | BitField<28, 8, Register> gpr28; |
| 275 | |||
| 276 | bool HasTwoDestinations() const { | ||
| 277 | return gpr28.Value() != Register::ZeroIndex; | ||
| 278 | } | ||
| 279 | |||
| 280 | bool IsComponentEnabled(size_t component) const { | ||
| 281 | static constexpr std::array<size_t, 5> one_dest_mask{0x1, 0x2, 0x4, 0x8, 0x3}; | ||
| 282 | static constexpr std::array<size_t, 5> two_dest_mask{0x7, 0xb, 0xd, 0xe, 0xf}; | ||
| 283 | const auto& mask{HasTwoDestinations() ? two_dest_mask : one_dest_mask}; | ||
| 284 | |||
| 285 | ASSERT(component_mask_selector < mask.size()); | ||
| 286 | |||
| 287 | return ((1 << component) & mask[component_mask_selector]) != 0; | ||
| 288 | } | ||
| 275 | } texs; | 289 | } texs; |
| 276 | 290 | ||
| 277 | BitField<61, 1, u64> is_b_imm; | 291 | BitField<61, 1, u64> is_b_imm; |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 86d880dfc..bb5209a7e 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -938,18 +938,21 @@ private: | |||
| 938 | // TEXS has two destination registers. RG goes into gpr0+0 and gpr0+1, and BA goes | 938 | // TEXS has two destination registers. RG goes into gpr0+0 and gpr0+1, and BA goes |
| 939 | // into gpr28+0 and gpr28+1 | 939 | // into gpr28+0 and gpr28+1 |
| 940 | size_t offset{}; | 940 | size_t offset{}; |
| 941 | |||
| 941 | for (const auto& dest : {instr.gpr0.Value(), instr.gpr28.Value()}) { | 942 | for (const auto& dest : {instr.gpr0.Value(), instr.gpr28.Value()}) { |
| 942 | for (unsigned elem = 0; elem < 2; ++elem) { | 943 | for (unsigned elem = 0; elem < 2; ++elem) { |
| 943 | if (dest + elem >= Register::ZeroIndex) { | 944 | if (!instr.texs.IsComponentEnabled(elem)) { |
| 944 | // Skip invalid register values | 945 | // Skip disabled components |
| 945 | break; | 946 | continue; |
| 946 | } | 947 | } |
| 947 | regs.SetRegisterToFloat(dest, elem + offset, texture, 1, 4, false, elem); | 948 | regs.SetRegisterToFloat(dest, elem + offset, texture, 1, 4, false, elem); |
| 948 | if (!instr.texs.enable_g_component) { | ||
| 949 | // Skip the second component | ||
| 950 | break; | ||
| 951 | } | ||
| 952 | } | 949 | } |
| 950 | |||
| 951 | if (!instr.texs.HasTwoDestinations()) { | ||
| 952 | // Skip the second destination | ||
| 953 | break; | ||
| 954 | } | ||
| 955 | |||
| 953 | offset += 2; | 956 | offset += 2; |
| 954 | } | 957 | } |
| 955 | --shader.scope; | 958 | --shader.scope; |