diff options
| author | 2018-04-17 22:10:53 -0400 | |
|---|---|---|
| committer | 2018-04-17 22:10:53 -0400 | |
| commit | 71b4a3b9f6894536d1a64265d5eb52a15be2094d (patch) | |
| tree | 53297c2c2659146a7cef8d91ab6b4bf169ec8654 /src | |
| parent | Merge pull request #345 from bunnei/blending (diff) | |
| parent | shader_bytecode: Make ctor's constexpr and explicit. (diff) | |
| download | yuzu-71b4a3b9f6894536d1a64265d5eb52a15be2094d.tar.gz yuzu-71b4a3b9f6894536d1a64265d5eb52a15be2094d.tar.xz yuzu-71b4a3b9f6894536d1a64265d5eb52a15be2094d.zip | |
Merge pull request #344 from bunnei/shader-decompiler-p2
Shader decompiler changes part 2
Diffstat (limited to '')
| -rw-r--r-- | src/common/bit_field.h | 7 | ||||
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 43 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 197 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 6 |
4 files changed, 180 insertions, 73 deletions
diff --git a/src/common/bit_field.h b/src/common/bit_field.h index 5638bdbba..65e357dec 100644 --- a/src/common/bit_field.h +++ b/src/common/bit_field.h | |||
| @@ -192,11 +192,6 @@ private: | |||
| 192 | static_assert(position < 8 * sizeof(T), "Invalid position"); | 192 | static_assert(position < 8 * sizeof(T), "Invalid position"); |
| 193 | static_assert(bits <= 8 * sizeof(T), "Invalid number of bits"); | 193 | static_assert(bits <= 8 * sizeof(T), "Invalid number of bits"); |
| 194 | static_assert(bits > 0, "Invalid number of bits"); | 194 | static_assert(bits > 0, "Invalid number of bits"); |
| 195 | static_assert(std::is_pod<T>::value, "Invalid base type"); | 195 | static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable in a BitField"); |
| 196 | }; | 196 | }; |
| 197 | #pragma pack() | 197 | #pragma pack() |
| 198 | |||
| 199 | #if (__GNUC__ >= 5) || defined(__clang__) || defined(_MSC_VER) | ||
| 200 | static_assert(std::is_trivially_copyable<BitField<0, 1, unsigned>>::value, | ||
| 201 | "BitField must be trivially copyable"); | ||
| 202 | #endif | ||
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index eff0c35a1..ed66d893a 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstring> | ||
| 7 | #include <map> | 8 | #include <map> |
| 8 | #include <string> | 9 | #include <string> |
| 9 | #include "common/bit_field.h" | 10 | #include "common/bit_field.h" |
| @@ -12,14 +13,10 @@ namespace Tegra { | |||
| 12 | namespace Shader { | 13 | namespace Shader { |
| 13 | 14 | ||
| 14 | struct Register { | 15 | struct Register { |
| 15 | Register() = default; | 16 | constexpr Register() = default; |
| 16 | 17 | ||
| 17 | constexpr Register(u64 value) : value(value) {} | 18 | constexpr Register(u64 value) : value(value) {} |
| 18 | 19 | ||
| 19 | constexpr u64 GetIndex() const { | ||
| 20 | return value; | ||
| 21 | } | ||
| 22 | |||
| 23 | constexpr operator u64() const { | 20 | constexpr operator u64() const { |
| 24 | return value; | 21 | return value; |
| 25 | } | 22 | } |
| @@ -43,13 +40,13 @@ struct Register { | |||
| 43 | } | 40 | } |
| 44 | 41 | ||
| 45 | private: | 42 | private: |
| 46 | u64 value; | 43 | u64 value{}; |
| 47 | }; | 44 | }; |
| 48 | 45 | ||
| 49 | union Attribute { | 46 | union Attribute { |
| 50 | Attribute() = default; | 47 | Attribute() = default; |
| 51 | 48 | ||
| 52 | constexpr Attribute(u64 value) : value(value) {} | 49 | constexpr explicit Attribute(u64 value) : value(value) {} |
| 53 | 50 | ||
| 54 | enum class Index : u64 { | 51 | enum class Index : u64 { |
| 55 | Position = 7, | 52 | Position = 7, |
| @@ -68,7 +65,20 @@ union Attribute { | |||
| 68 | } fmt28; | 65 | } fmt28; |
| 69 | 66 | ||
| 70 | BitField<39, 8, u64> reg; | 67 | BitField<39, 8, u64> reg; |
| 71 | u64 value; | 68 | u64 value{}; |
| 69 | }; | ||
| 70 | |||
| 71 | union Sampler { | ||
| 72 | Sampler() = default; | ||
| 73 | |||
| 74 | constexpr explicit Sampler(u64 value) : value(value) {} | ||
| 75 | |||
| 76 | enum class Index : u64 { | ||
| 77 | Sampler_0 = 8, | ||
| 78 | }; | ||
| 79 | |||
| 80 | BitField<36, 13, Index> index; | ||
| 81 | u64 value{}; | ||
| 72 | }; | 82 | }; |
| 73 | 83 | ||
| 74 | union Uniform { | 84 | union Uniform { |
| @@ -238,7 +248,7 @@ union OpCode { | |||
| 238 | BitField<55, 9, Id> op3; | 248 | BitField<55, 9, Id> op3; |
| 239 | BitField<52, 12, Id> op4; | 249 | BitField<52, 12, Id> op4; |
| 240 | BitField<51, 13, Id> op5; | 250 | BitField<51, 13, Id> op5; |
| 241 | u64 value; | 251 | u64 value{}; |
| 242 | }; | 252 | }; |
| 243 | static_assert(sizeof(OpCode) == 0x8, "Incorrect structure size"); | 253 | static_assert(sizeof(OpCode) == 0x8, "Incorrect structure size"); |
| 244 | 254 | ||
| @@ -280,6 +290,7 @@ enum class SubOp : u64 { | |||
| 280 | Lg2 = 0x3, | 290 | Lg2 = 0x3, |
| 281 | Rcp = 0x4, | 291 | Rcp = 0x4, |
| 282 | Rsq = 0x5, | 292 | Rsq = 0x5, |
| 293 | Min = 0x8, | ||
| 283 | }; | 294 | }; |
| 284 | 295 | ||
| 285 | union Instruction { | 296 | union Instruction { |
| @@ -295,15 +306,25 @@ union Instruction { | |||
| 295 | BitField<20, 8, Register> gpr20; | 306 | BitField<20, 8, Register> gpr20; |
| 296 | BitField<20, 7, SubOp> sub_op; | 307 | BitField<20, 7, SubOp> sub_op; |
| 297 | BitField<28, 8, Register> gpr28; | 308 | BitField<28, 8, Register> gpr28; |
| 298 | BitField<36, 13, u64> imm36; | ||
| 299 | BitField<39, 8, Register> gpr39; | 309 | BitField<39, 8, Register> gpr39; |
| 300 | 310 | ||
| 301 | union { | 311 | union { |
| 312 | BitField<20, 19, u64> imm20; | ||
| 302 | BitField<45, 1, u64> negate_b; | 313 | BitField<45, 1, u64> negate_b; |
| 303 | BitField<46, 1, u64> abs_a; | 314 | BitField<46, 1, u64> abs_a; |
| 304 | BitField<48, 1, u64> negate_a; | 315 | BitField<48, 1, u64> negate_a; |
| 305 | BitField<49, 1, u64> abs_b; | 316 | BitField<49, 1, u64> abs_b; |
| 306 | BitField<50, 1, u64> abs_d; | 317 | BitField<50, 1, u64> abs_d; |
| 318 | BitField<56, 1, u64> negate_imm; | ||
| 319 | |||
| 320 | float GetImm20() const { | ||
| 321 | float result{}; | ||
| 322 | u32 imm{static_cast<u32>(imm20)}; | ||
| 323 | imm <<= 12; | ||
| 324 | imm |= negate_imm ? 0x80000000 : 0; | ||
| 325 | std::memcpy(&result, &imm, sizeof(imm)); | ||
| 326 | return result; | ||
| 327 | } | ||
| 307 | } alu; | 328 | } alu; |
| 308 | 329 | ||
| 309 | union { | 330 | union { |
| @@ -311,11 +332,13 @@ union Instruction { | |||
| 311 | BitField<49, 1, u64> negate_c; | 332 | BitField<49, 1, u64> negate_c; |
| 312 | } ffma; | 333 | } ffma; |
| 313 | 334 | ||
| 335 | BitField<61, 1, u64> is_b_imm; | ||
| 314 | BitField<60, 1, u64> is_b_gpr; | 336 | BitField<60, 1, u64> is_b_gpr; |
| 315 | BitField<59, 1, u64> is_c_gpr; | 337 | BitField<59, 1, u64> is_c_gpr; |
| 316 | 338 | ||
| 317 | Attribute attribute; | 339 | Attribute attribute; |
| 318 | Uniform uniform; | 340 | Uniform uniform; |
| 341 | Sampler sampler; | ||
| 319 | 342 | ||
| 320 | u64 hex; | 343 | u64 hex; |
| 321 | }; | 344 | }; |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index e11711533..6233ee358 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -17,6 +17,7 @@ using Tegra::Shader::Attribute; | |||
| 17 | using Tegra::Shader::Instruction; | 17 | using Tegra::Shader::Instruction; |
| 18 | using Tegra::Shader::OpCode; | 18 | using Tegra::Shader::OpCode; |
| 19 | using Tegra::Shader::Register; | 19 | using Tegra::Shader::Register; |
| 20 | using Tegra::Shader::Sampler; | ||
| 20 | using Tegra::Shader::SubOp; | 21 | using Tegra::Shader::SubOp; |
| 21 | using Tegra::Shader::Uniform; | 22 | using Tegra::Shader::Uniform; |
| 22 | 23 | ||
| @@ -155,23 +156,27 @@ private: | |||
| 155 | 156 | ||
| 156 | /// Generates code representing an input attribute register. | 157 | /// Generates code representing an input attribute register. |
| 157 | std::string GetInputAttribute(Attribute::Index attribute) { | 158 | std::string GetInputAttribute(Attribute::Index attribute) { |
| 158 | declr_input_attribute.insert(attribute); | 159 | switch (attribute) { |
| 160 | case Attribute::Index::Position: | ||
| 161 | return "position"; | ||
| 162 | default: | ||
| 163 | const u32 index{static_cast<u32>(attribute) - | ||
| 164 | static_cast<u32>(Attribute::Index::Attribute_0)}; | ||
| 165 | if (attribute >= Attribute::Index::Attribute_0) { | ||
| 166 | declr_input_attribute.insert(attribute); | ||
| 167 | return "input_attribute_" + std::to_string(index); | ||
| 168 | } | ||
| 159 | 169 | ||
| 160 | const u32 index{static_cast<u32>(attribute) - | 170 | NGLOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", index); |
| 161 | static_cast<u32>(Attribute::Index::Attribute_0)}; | 171 | UNREACHABLE(); |
| 162 | if (attribute >= Attribute::Index::Attribute_0) { | ||
| 163 | return "input_attribute_" + std::to_string(index); | ||
| 164 | } | 172 | } |
| 165 | |||
| 166 | LOG_CRITICAL(HW_GPU, "Unhandled input attribute: 0x%02x", index); | ||
| 167 | UNREACHABLE(); | ||
| 168 | } | 173 | } |
| 169 | 174 | ||
| 170 | /// Generates code representing an output attribute register. | 175 | /// Generates code representing an output attribute register. |
| 171 | std::string GetOutputAttribute(Attribute::Index attribute) { | 176 | std::string GetOutputAttribute(Attribute::Index attribute) { |
| 172 | switch (attribute) { | 177 | switch (attribute) { |
| 173 | case Attribute::Index::Position: | 178 | case Attribute::Index::Position: |
| 174 | return "gl_Position"; | 179 | return "position"; |
| 175 | default: | 180 | default: |
| 176 | const u32 index{static_cast<u32>(attribute) - | 181 | const u32 index{static_cast<u32>(attribute) - |
| 177 | static_cast<u32>(Attribute::Index::Attribute_0)}; | 182 | static_cast<u32>(Attribute::Index::Attribute_0)}; |
| @@ -180,22 +185,42 @@ private: | |||
| 180 | return "output_attribute_" + std::to_string(index); | 185 | return "output_attribute_" + std::to_string(index); |
| 181 | } | 186 | } |
| 182 | 187 | ||
| 183 | LOG_CRITICAL(HW_GPU, "Unhandled output attribute: 0x%02x", index); | 188 | NGLOG_CRITICAL(HW_GPU, "Unhandled output attribute: {}", index); |
| 184 | UNREACHABLE(); | 189 | UNREACHABLE(); |
| 185 | } | 190 | } |
| 186 | } | 191 | } |
| 187 | 192 | ||
| 193 | /// Generates code representing an immediate value | ||
| 194 | static std::string GetImmediate(const Instruction& instr) { | ||
| 195 | return std::to_string(instr.alu.GetImm20()); | ||
| 196 | } | ||
| 197 | |||
| 188 | /// Generates code representing a temporary (GPR) register. | 198 | /// Generates code representing a temporary (GPR) register. |
| 189 | std::string GetRegister(const Register& reg) { | 199 | std::string GetRegister(const Register& reg, unsigned elem = 0) { |
| 190 | return *declr_register.insert("register_" + std::to_string(reg)).first; | 200 | if (stage == Maxwell3D::Regs::ShaderStage::Fragment && reg < 4) { |
| 201 | // GPRs 0-3 are output color for the fragment shader | ||
| 202 | return std::string{"color."} + "rgba"[(reg + elem) & 3]; | ||
| 203 | } | ||
| 204 | |||
| 205 | return *declr_register.insert("register_" + std::to_string(reg + elem)).first; | ||
| 191 | } | 206 | } |
| 192 | 207 | ||
| 193 | /// Generates code representing a uniform (C buffer) register. | 208 | /// Generates code representing a uniform (C buffer) register. |
| 194 | std::string GetUniform(const Uniform& reg) { | 209 | std::string GetUniform(const Uniform& reg) { |
| 195 | declr_const_buffers[reg.index].MarkAsUsed(reg.index, reg.offset, stage); | 210 | declr_const_buffers[reg.index].MarkAsUsed(static_cast<unsigned>(reg.index), |
| 211 | static_cast<unsigned>(reg.offset), stage); | ||
| 196 | return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']'; | 212 | return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']'; |
| 197 | } | 213 | } |
| 198 | 214 | ||
| 215 | /// Generates code representing a texture sampler. | ||
| 216 | std::string GetSampler(const Sampler& sampler) const { | ||
| 217 | // TODO(Subv): Support more than just texture sampler 0 | ||
| 218 | ASSERT_MSG(sampler.index == Sampler::Index::Sampler_0, "unsupported"); | ||
| 219 | const unsigned index{static_cast<unsigned>(sampler.index.Value()) - | ||
| 220 | static_cast<unsigned>(Sampler::Index::Sampler_0)}; | ||
| 221 | return "tex[" + std::to_string(index) + "]"; | ||
| 222 | } | ||
| 223 | |||
| 199 | /** | 224 | /** |
| 200 | * Adds code that calls a subroutine. | 225 | * Adds code that calls a subroutine. |
| 201 | * @param subroutine the subroutine to call. | 226 | * @param subroutine the subroutine to call. |
| @@ -217,12 +242,13 @@ private: | |||
| 217 | * @param value the code representing the value to assign. | 242 | * @param value the code representing the value to assign. |
| 218 | */ | 243 | */ |
| 219 | void SetDest(u64 elem, const std::string& reg, const std::string& value, | 244 | void SetDest(u64 elem, const std::string& reg, const std::string& value, |
| 220 | u64 dest_num_components, u64 value_num_components) { | 245 | u64 dest_num_components, u64 value_num_components, bool is_abs = false) { |
| 221 | std::string swizzle = "."; | 246 | std::string swizzle = "."; |
| 222 | swizzle += "xyzw"[elem]; | 247 | swizzle += "xyzw"[elem]; |
| 223 | 248 | ||
| 224 | std::string dest = reg + (dest_num_components != 1 ? swizzle : ""); | 249 | std::string dest = reg + (dest_num_components != 1 ? swizzle : ""); |
| 225 | std::string src = "(" + value + ")" + (value_num_components != 1 ? swizzle : ""); | 250 | std::string src = "(" + value + ")" + (value_num_components != 1 ? swizzle : ""); |
| 251 | src = is_abs ? "abs(" + src + ")" : src; | ||
| 226 | 252 | ||
| 227 | shader.AddLine(dest + " = " + src + ";"); | 253 | shader.AddLine(dest + " = " + src + ";"); |
| 228 | } | 254 | } |
| @@ -240,8 +266,6 @@ private: | |||
| 240 | 266 | ||
| 241 | switch (OpCode::GetInfo(instr.opcode).type) { | 267 | switch (OpCode::GetInfo(instr.opcode).type) { |
| 242 | case OpCode::Type::Arithmetic: { | 268 | case OpCode::Type::Arithmetic: { |
| 243 | ASSERT(!instr.alu.abs_d); | ||
| 244 | |||
| 245 | std::string dest = GetRegister(instr.gpr0); | 269 | std::string dest = GetRegister(instr.gpr0); |
| 246 | std::string op_a = instr.alu.negate_a ? "-" : ""; | 270 | std::string op_a = instr.alu.negate_a ? "-" : ""; |
| 247 | op_a += GetRegister(instr.gpr8); | 271 | op_a += GetRegister(instr.gpr8); |
| @@ -250,63 +274,109 @@ private: | |||
| 250 | } | 274 | } |
| 251 | 275 | ||
| 252 | std::string op_b = instr.alu.negate_b ? "-" : ""; | 276 | std::string op_b = instr.alu.negate_b ? "-" : ""; |
| 253 | if (instr.is_b_gpr) { | 277 | |
| 254 | op_b += GetRegister(instr.gpr20); | 278 | if (instr.is_b_imm) { |
| 279 | op_b += GetImmediate(instr); | ||
| 255 | } else { | 280 | } else { |
| 256 | op_b += GetUniform(instr.uniform); | 281 | if (instr.is_b_gpr) { |
| 282 | op_b += GetRegister(instr.gpr20); | ||
| 283 | } else { | ||
| 284 | op_b += GetUniform(instr.uniform); | ||
| 285 | } | ||
| 257 | } | 286 | } |
| 287 | |||
| 258 | if (instr.alu.abs_b) { | 288 | if (instr.alu.abs_b) { |
| 259 | op_b = "abs(" + op_b + ")"; | 289 | op_b = "abs(" + op_b + ")"; |
| 260 | } | 290 | } |
| 261 | 291 | ||
| 262 | switch (instr.opcode.EffectiveOpCode()) { | 292 | switch (instr.opcode.EffectiveOpCode()) { |
| 263 | case OpCode::Id::FMUL_C: | 293 | case OpCode::Id::FMUL_C: |
| 264 | case OpCode::Id::FMUL_R: { | 294 | case OpCode::Id::FMUL_R: |
| 265 | SetDest(0, dest, op_a + " * " + op_b, 1, 1); | 295 | case OpCode::Id::FMUL_IMM: { |
| 296 | SetDest(0, dest, op_a + " * " + op_b, 1, 1, instr.alu.abs_d); | ||
| 266 | break; | 297 | break; |
| 267 | } | 298 | } |
| 268 | case OpCode::Id::FADD_C: | 299 | case OpCode::Id::FADD_C: |
| 269 | case OpCode::Id::FADD_R: { | 300 | case OpCode::Id::FADD_R: |
| 270 | SetDest(0, dest, op_a + " + " + op_b, 1, 1); | 301 | case OpCode::Id::FADD_IMM: { |
| 302 | SetDest(0, dest, op_a + " + " + op_b, 1, 1, instr.alu.abs_d); | ||
| 271 | break; | 303 | break; |
| 272 | } | 304 | } |
| 273 | default: { | 305 | case OpCode::Id::MUFU: { |
| 274 | LOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: 0x%02x (%s): 0x%08x", | 306 | switch (instr.sub_op) { |
| 275 | static_cast<unsigned>(instr.opcode.EffectiveOpCode()), | 307 | case SubOp::Cos: |
| 276 | OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex); | 308 | SetDest(0, dest, "cos(" + op_a + ")", 1, 1, instr.alu.abs_d); |
| 277 | throw DecompileFail("Unhandled instruction"); | 309 | break; |
| 310 | case SubOp::Sin: | ||
| 311 | SetDest(0, dest, "sin(" + op_a + ")", 1, 1, instr.alu.abs_d); | ||
| 312 | break; | ||
| 313 | case SubOp::Ex2: | ||
| 314 | SetDest(0, dest, "exp2(" + op_a + ")", 1, 1, instr.alu.abs_d); | ||
| 315 | break; | ||
| 316 | case SubOp::Lg2: | ||
| 317 | SetDest(0, dest, "log2(" + op_a + ")", 1, 1, instr.alu.abs_d); | ||
| 318 | break; | ||
| 319 | case SubOp::Rcp: | ||
| 320 | SetDest(0, dest, "1.0 / " + op_a, 1, 1, instr.alu.abs_d); | ||
| 321 | break; | ||
| 322 | case SubOp::Rsq: | ||
| 323 | SetDest(0, dest, "inversesqrt(" + op_a + ")", 1, 1, instr.alu.abs_d); | ||
| 324 | break; | ||
| 325 | case SubOp::Min: | ||
| 326 | SetDest(0, dest, "min(" + op_a + "," + op_b + ")", 1, 1, instr.alu.abs_d); | ||
| 327 | break; | ||
| 328 | default: | ||
| 329 | NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {}", | ||
| 330 | static_cast<unsigned>(instr.sub_op.Value())); | ||
| 331 | UNREACHABLE(); | ||
| 332 | } | ||
| 278 | break; | 333 | break; |
| 279 | } | 334 | } |
| 335 | default: { | ||
| 336 | NGLOG_CRITICAL(HW_GPU, "Unhandled arithmetic instruction: {} ({}): {}", | ||
| 337 | static_cast<unsigned>(instr.opcode.EffectiveOpCode()), | ||
| 338 | OpCode::GetInfo(instr.opcode).name, instr.hex); | ||
| 339 | UNREACHABLE(); | ||
| 340 | } | ||
| 280 | } | 341 | } |
| 281 | break; | 342 | break; |
| 282 | } | 343 | } |
| 283 | case OpCode::Type::Ffma: { | 344 | case OpCode::Type::Ffma: { |
| 284 | ASSERT_MSG(!instr.ffma.negate_b, "untested"); | ||
| 285 | ASSERT_MSG(!instr.ffma.negate_c, "untested"); | ||
| 286 | |||
| 287 | std::string dest = GetRegister(instr.gpr0); | 345 | std::string dest = GetRegister(instr.gpr0); |
| 288 | std::string op_a = GetRegister(instr.gpr8); | 346 | std::string op_a = GetRegister(instr.gpr8); |
| 289 | |||
| 290 | std::string op_b = instr.ffma.negate_b ? "-" : ""; | 347 | std::string op_b = instr.ffma.negate_b ? "-" : ""; |
| 291 | op_b += GetUniform(instr.uniform); | ||
| 292 | |||
| 293 | std::string op_c = instr.ffma.negate_c ? "-" : ""; | 348 | std::string op_c = instr.ffma.negate_c ? "-" : ""; |
| 294 | op_c += GetRegister(instr.gpr39); | ||
| 295 | 349 | ||
| 296 | switch (instr.opcode.EffectiveOpCode()) { | 350 | switch (instr.opcode.EffectiveOpCode()) { |
| 297 | case OpCode::Id::FFMA_CR: { | 351 | case OpCode::Id::FFMA_CR: { |
| 298 | SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1); | 352 | op_b += GetUniform(instr.uniform); |
| 353 | op_c += GetRegister(instr.gpr39); | ||
| 299 | break; | 354 | break; |
| 300 | } | 355 | } |
| 301 | 356 | case OpCode::Id::FFMA_RR: { | |
| 302 | default: { | 357 | op_b += GetRegister(instr.gpr20); |
| 303 | LOG_CRITICAL(HW_GPU, "Unhandled arithmetic FFMA instruction: 0x%02x (%s): 0x%08x", | 358 | op_c += GetRegister(instr.gpr39); |
| 304 | static_cast<unsigned>(instr.opcode.EffectiveOpCode()), | 359 | break; |
| 305 | OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex); | 360 | } |
| 306 | throw DecompileFail("Unhandled instruction"); | 361 | case OpCode::Id::FFMA_RC: { |
| 362 | op_b += GetRegister(instr.gpr39); | ||
| 363 | op_c += GetUniform(instr.uniform); | ||
| 307 | break; | 364 | break; |
| 308 | } | 365 | } |
| 366 | case OpCode::Id::FFMA_IMM: { | ||
| 367 | op_b += GetImmediate(instr); | ||
| 368 | op_c += GetRegister(instr.gpr39); | ||
| 369 | break; | ||
| 309 | } | 370 | } |
| 371 | default: { | ||
| 372 | NGLOG_CRITICAL(HW_GPU, "Unhandled FFMA instruction: {} ({}): {}", | ||
| 373 | static_cast<unsigned>(instr.opcode.EffectiveOpCode()), | ||
| 374 | OpCode::GetInfo(instr.opcode).name, instr.hex); | ||
| 375 | UNREACHABLE(); | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1); | ||
| 310 | break; | 380 | break; |
| 311 | } | 381 | } |
| 312 | case OpCode::Type::Memory: { | 382 | case OpCode::Type::Memory: { |
| @@ -315,22 +385,33 @@ private: | |||
| 315 | 385 | ||
| 316 | switch (instr.opcode.EffectiveOpCode()) { | 386 | switch (instr.opcode.EffectiveOpCode()) { |
| 317 | case OpCode::Id::LD_A: { | 387 | case OpCode::Id::LD_A: { |
| 318 | ASSERT(instr.attribute.fmt20.size == 0); | 388 | ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); |
| 319 | SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4); | 389 | SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4); |
| 320 | break; | 390 | break; |
| 321 | } | 391 | } |
| 322 | case OpCode::Id::ST_A: { | 392 | case OpCode::Id::ST_A: { |
| 323 | ASSERT(instr.attribute.fmt20.size == 0); | 393 | ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); |
| 324 | SetDest(instr.attribute.fmt20.element, GetOutputAttribute(attribute), gpr0, 4, 1); | 394 | SetDest(instr.attribute.fmt20.element, GetOutputAttribute(attribute), gpr0, 4, 1); |
| 325 | break; | 395 | break; |
| 326 | } | 396 | } |
| 327 | default: { | 397 | case OpCode::Id::TEXS: { |
| 328 | LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: 0x%02x (%s): 0x%08x", | 398 | ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested"); |
| 329 | static_cast<unsigned>(instr.opcode.EffectiveOpCode()), | 399 | const std::string op_a = GetRegister(instr.gpr8); |
| 330 | OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex); | 400 | const std::string op_b = GetRegister(instr.gpr20); |
| 331 | throw DecompileFail("Unhandled instruction"); | 401 | const std::string sampler = GetSampler(instr.sampler); |
| 402 | const std::string coord = "vec2(" + op_a + ", " + op_b + ")"; | ||
| 403 | const std::string texture = "texture(" + sampler + ", " + coord + ")"; | ||
| 404 | for (unsigned elem = 0; elem < instr.attribute.fmt20.size; ++elem) { | ||
| 405 | SetDest(elem, GetRegister(instr.gpr0, elem), texture, 1, 4); | ||
| 406 | } | ||
| 332 | break; | 407 | break; |
| 333 | } | 408 | } |
| 409 | default: { | ||
| 410 | NGLOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {} ({}): {}", | ||
| 411 | static_cast<unsigned>(instr.opcode.EffectiveOpCode()), | ||
| 412 | OpCode::GetInfo(instr.opcode).name, instr.hex); | ||
| 413 | UNREACHABLE(); | ||
| 414 | } | ||
| 334 | } | 415 | } |
| 335 | break; | 416 | break; |
| 336 | } | 417 | } |
| @@ -342,14 +423,18 @@ private: | |||
| 342 | offset = PROGRAM_END - 1; | 423 | offset = PROGRAM_END - 1; |
| 343 | break; | 424 | break; |
| 344 | } | 425 | } |
| 345 | 426 | case OpCode::Id::IPA: { | |
| 346 | default: { | 427 | const auto& attribute = instr.attribute.fmt28; |
| 347 | LOG_CRITICAL(HW_GPU, "Unhandled instruction: 0x%02x (%s): 0x%08x", | 428 | std::string dest = GetRegister(instr.gpr0); |
| 348 | static_cast<unsigned>(instr.opcode.EffectiveOpCode()), | 429 | SetDest(attribute.element, dest, GetInputAttribute(attribute.index), 1, 4); |
| 349 | OpCode::GetInfo(instr.opcode).name.c_str(), instr.hex); | ||
| 350 | throw DecompileFail("Unhandled instruction"); | ||
| 351 | break; | 430 | break; |
| 352 | } | 431 | } |
| 432 | default: { | ||
| 433 | NGLOG_CRITICAL(HW_GPU, "Unhandled instruction: {} ({}): {}", | ||
| 434 | static_cast<unsigned>(instr.opcode.EffectiveOpCode()), | ||
| 435 | OpCode::GetInfo(instr.opcode).name, instr.hex); | ||
| 436 | UNREACHABLE(); | ||
| 437 | } | ||
| 353 | } | 438 | } |
| 354 | 439 | ||
| 355 | break; | 440 | break; |
| @@ -514,7 +599,7 @@ boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, | |||
| 514 | GLSLGenerator generator(subroutines, program_code, main_offset, stage); | 599 | GLSLGenerator generator(subroutines, program_code, main_offset, stage); |
| 515 | return ProgramResult{generator.GetShaderCode(), generator.GetEntries()}; | 600 | return ProgramResult{generator.GetShaderCode(), generator.GetEntries()}; |
| 516 | } catch (const DecompileFail& exception) { | 601 | } catch (const DecompileFail& exception) { |
| 517 | LOG_ERROR(HW_GPU, "Shader decompilation failed: %s", exception.what()); | 602 | NGLOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what()); |
| 518 | } | 603 | } |
| 519 | return boost::none; | 604 | return boost::none; |
| 520 | } | 605 | } |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index aeea1c805..8b7f17601 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -27,10 +27,13 @@ out gl_PerVertex { | |||
| 27 | vec4 gl_Position; | 27 | vec4 gl_Position; |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | out vec4 position; | ||
| 31 | |||
| 30 | void main() { | 32 | void main() { |
| 31 | exec_shader(); | 33 | exec_shader(); |
| 32 | } | ||
| 33 | 34 | ||
| 35 | gl_Position = position; | ||
| 36 | } | ||
| 34 | )"; | 37 | )"; |
| 35 | out += program.first; | 38 | out += program.first; |
| 36 | return {out, program.second}; | 39 | return {out, program.second}; |
| @@ -46,6 +49,7 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSCo | |||
| 46 | .get_value_or({}); | 49 | .get_value_or({}); |
| 47 | out += R"( | 50 | out += R"( |
| 48 | 51 | ||
| 52 | in vec4 position; | ||
| 49 | out vec4 color; | 53 | out vec4 color; |
| 50 | 54 | ||
| 51 | uniform sampler2D tex[32]; | 55 | uniform sampler2D tex[32]; |