diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 33 | ||||
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 18 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 17 |
3 files changed, 50 insertions, 18 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 23e70cd8a..ef12d9300 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -156,16 +156,15 @@ void Maxwell3D::ProcessQueryGet() { | |||
| 156 | // TODO(Subv): Support the other query units. | 156 | // TODO(Subv): Support the other query units. |
| 157 | ASSERT_MSG(regs.query.query_get.unit == Regs::QueryUnit::Crop, | 157 | ASSERT_MSG(regs.query.query_get.unit == Regs::QueryUnit::Crop, |
| 158 | "Units other than CROP are unimplemented"); | 158 | "Units other than CROP are unimplemented"); |
| 159 | ASSERT_MSG(regs.query.query_get.short_query, | ||
| 160 | "Writing the entire query result structure is unimplemented"); | ||
| 161 | 159 | ||
| 162 | u32 value = Memory::Read32(*address); | 160 | u32 value = Memory::Read32(*address); |
| 163 | u32 result = 0; | 161 | u64 result = 0; |
| 164 | 162 | ||
| 165 | // TODO(Subv): Support the other query variables | 163 | // TODO(Subv): Support the other query variables |
| 166 | switch (regs.query.query_get.select) { | 164 | switch (regs.query.query_get.select) { |
| 167 | case Regs::QuerySelect::Zero: | 165 | case Regs::QuerySelect::Zero: |
| 168 | result = 0; | 166 | // This seems to actually write the query sequence to the query address. |
| 167 | result = regs.query.query_sequence; | ||
| 169 | break; | 168 | break; |
| 170 | default: | 169 | default: |
| 171 | UNIMPLEMENTED_MSG("Unimplemented query select type {}", | 170 | UNIMPLEMENTED_MSG("Unimplemented query select type {}", |
| @@ -174,15 +173,31 @@ void Maxwell3D::ProcessQueryGet() { | |||
| 174 | 173 | ||
| 175 | // TODO(Subv): Research and implement how query sync conditions work. | 174 | // TODO(Subv): Research and implement how query sync conditions work. |
| 176 | 175 | ||
| 176 | struct LongQueryResult { | ||
| 177 | u64_le value; | ||
| 178 | u64_le timestamp; | ||
| 179 | }; | ||
| 180 | static_assert(sizeof(LongQueryResult) == 16, "LongQueryResult has wrong size"); | ||
| 181 | |||
| 177 | switch (regs.query.query_get.mode) { | 182 | switch (regs.query.query_get.mode) { |
| 178 | case Regs::QueryMode::Write: | 183 | case Regs::QueryMode::Write: |
| 179 | case Regs::QueryMode::Write2: { | 184 | case Regs::QueryMode::Write2: { |
| 180 | // Write the current query sequence to the sequence address. | ||
| 181 | u32 sequence = regs.query.query_sequence; | 185 | u32 sequence = regs.query.query_sequence; |
| 182 | Memory::Write32(*address, sequence); | 186 | if (regs.query.query_get.short_query) { |
| 183 | 187 | // Write the current query sequence to the sequence address. | |
| 184 | // TODO(Subv): Write the proper query response structure to the address when not using short | 188 | // TODO(Subv): Find out what happens if you use a long query type but mark it as a short |
| 185 | // mode. | 189 | // query. |
| 190 | Memory::Write32(*address, sequence); | ||
| 191 | } else { | ||
| 192 | // Write the 128-bit result structure in long mode. Note: We emulate an infinitely fast | ||
| 193 | // GPU, this command may actually take a while to complete in real hardware due to GPU | ||
| 194 | // wait queues. | ||
| 195 | LongQueryResult query_result{}; | ||
| 196 | query_result.value = result; | ||
| 197 | // TODO(Subv): Generate a real GPU timestamp and write it here instead of 0 | ||
| 198 | query_result.timestamp = 0; | ||
| 199 | Memory::WriteBlock(*address, &query_result, sizeof(query_result)); | ||
| 200 | } | ||
| 186 | break; | 201 | break; |
| 187 | } | 202 | } |
| 188 | default: | 203 | default: |
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; |