diff options
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 416 |
1 files changed, 262 insertions, 154 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 3716bb782..8b235e252 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -41,7 +41,7 @@ enum class ExitMethod { | |||
| 41 | struct Subroutine { | 41 | struct Subroutine { |
| 42 | /// Generates a name suitable for GLSL source code. | 42 | /// Generates a name suitable for GLSL source code. |
| 43 | std::string GetName() const { | 43 | std::string GetName() const { |
| 44 | return "sub_" + std::to_string(begin) + "_" + std::to_string(end); | 44 | return "sub_" + std::to_string(begin) + '_' + std::to_string(end); |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | u32 begin; ///< Entry point of the subroutine. | 47 | u32 begin; ///< Entry point of the subroutine. |
| @@ -216,6 +216,16 @@ public: | |||
| 216 | return declr_type.find(Type::Integer) != declr_type.end(); | 216 | return declr_type.find(Type::Integer) != declr_type.end(); |
| 217 | } | 217 | } |
| 218 | 218 | ||
| 219 | /// Returns true if the active type is float | ||
| 220 | bool IsFloat() const { | ||
| 221 | return active_type == Type::Float; | ||
| 222 | } | ||
| 223 | |||
| 224 | /// Returns true if the active type is integer | ||
| 225 | bool IsInteger() const { | ||
| 226 | return active_type == Type::Integer; | ||
| 227 | } | ||
| 228 | |||
| 219 | private: | 229 | private: |
| 220 | enum class Type { | 230 | enum class Type { |
| 221 | Float, | 231 | Float, |
| @@ -230,41 +240,168 @@ private: | |||
| 230 | std::set<Type> declr_type; | 240 | std::set<Type> declr_type; |
| 231 | }; | 241 | }; |
| 232 | 242 | ||
| 233 | class GLSLGenerator { | 243 | /** |
| 244 | * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state | ||
| 245 | * of all registers (e.g. whether they are currently being used as Floats or Integers), and | ||
| 246 | * generates the necessary GLSL code to perform conversions as needed. This class is used for | ||
| 247 | * bookkeeping within the GLSL program. | ||
| 248 | */ | ||
| 249 | class GLSLRegisterManager { | ||
| 234 | public: | 250 | public: |
| 235 | GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code, | 251 | GLSLRegisterManager(ShaderWriter& shader, ShaderWriter& declarations, |
| 236 | u32 main_offset, Maxwell3D::Regs::ShaderStage stage) | 252 | const Maxwell3D::Regs::ShaderStage& stage) |
| 237 | : subroutines(subroutines), program_code(program_code), main_offset(main_offset), | 253 | : shader{shader}, declarations{declarations}, stage{stage} { |
| 238 | stage(stage) { | ||
| 239 | |||
| 240 | BuildRegisterList(); | 254 | BuildRegisterList(); |
| 241 | Generate(); | ||
| 242 | } | 255 | } |
| 243 | 256 | ||
| 244 | std::string GetShaderCode() { | 257 | /// Generates code representing a temporary (GPR) register. |
| 245 | return declarations.GetResult() + shader.GetResult(); | 258 | std::string GetRegister(const Register& reg, unsigned elem = 0) { |
| 259 | if (reg == Register::ZeroIndex) { | ||
| 260 | return "0"; | ||
| 261 | } | ||
| 262 | |||
| 263 | return regs[reg.GetSwizzledIndex(elem)].GetActiveString(); | ||
| 246 | } | 264 | } |
| 247 | 265 | ||
| 248 | /// Returns entries in the shader that are useful for external functions | 266 | /** |
| 249 | ShaderEntries GetEntries() const { | 267 | * Writes code that does a register assignment to float value operation. Should only be used |
| 250 | return {GetConstBuffersDeclarations()}; | 268 | * with shader instructions that deal with floats. |
| 269 | * @param reg The destination register to use. | ||
| 270 | * @param elem The element to use for the operation. | ||
| 271 | * @param value The code representing the value to assign. | ||
| 272 | * @param dest_num_components Number of components in the destination. | ||
| 273 | * @param value_num_components Number of components in the value. | ||
| 274 | * @param is_abs Optional, when True, applies absolute value to output. | ||
| 275 | * @param dest_elem Optional, the destination element to use for the operation. | ||
| 276 | */ | ||
| 277 | void SetRegisterToFloat(const Register& reg, u64 elem, const std::string& value, | ||
| 278 | u64 dest_num_components, u64 value_num_components, bool is_abs = false, | ||
| 279 | u64 dest_elem = 0) { | ||
| 280 | ASSERT(regs[reg].IsFloat()); | ||
| 281 | |||
| 282 | std::string dest = GetRegister(reg, dest_elem); | ||
| 283 | if (dest_num_components > 1) { | ||
| 284 | dest += GetSwizzle(elem); | ||
| 285 | } | ||
| 286 | |||
| 287 | std::string src = '(' + value + ')'; | ||
| 288 | if (value_num_components > 1) { | ||
| 289 | src += GetSwizzle(elem); | ||
| 290 | } | ||
| 291 | |||
| 292 | src = is_abs ? "abs(" + src + ')' : src; | ||
| 293 | |||
| 294 | shader.AddLine(dest + " = " + src + ';'); | ||
| 295 | } | ||
| 296 | |||
| 297 | /** | ||
| 298 | * Writes code that does a register assignment to input attribute operation. Input attributes | ||
| 299 | * are stored as floats, so this may require conversion. | ||
| 300 | * @param reg The destination register to use. | ||
| 301 | * @param elem The element to use for the operation. | ||
| 302 | * @param attribute The input attibute to use as the source value. | ||
| 303 | */ | ||
| 304 | void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute) { | ||
| 305 | std::string dest = GetRegister(reg); | ||
| 306 | std::string src = GetInputAttribute(attribute) + GetSwizzle(elem); | ||
| 307 | |||
| 308 | if (regs[reg].IsFloat()) { | ||
| 309 | shader.AddLine(dest + " = " + src + ';'); | ||
| 310 | } else if (regs[reg].IsInteger()) { | ||
| 311 | shader.AddLine(dest + " = floatBitsToInt(" + src + ");"); | ||
| 312 | } else { | ||
| 313 | UNREACHABLE(); | ||
| 314 | } | ||
| 315 | } | ||
| 316 | |||
| 317 | /** | ||
| 318 | * Writes code that does a output attribute assignment to register operation. Output attributes | ||
| 319 | * are stored as floats, so this may require conversion. | ||
| 320 | * @param attribute The destination output attribute. | ||
| 321 | * @param elem The element to use for the operation. | ||
| 322 | * @param reg The register to use as the source value. | ||
| 323 | */ | ||
| 324 | void SetOutputAttributeToRegister(Attribute::Index attribute, u64 elem, const Register& reg) { | ||
| 325 | std::string dest = GetOutputAttribute(attribute) + GetSwizzle(elem); | ||
| 326 | std::string src = GetRegister(reg); | ||
| 327 | ASSERT_MSG(regs[reg].IsFloat(), "Output attributes must be set to a float"); | ||
| 328 | shader.AddLine(dest + " = " + src + ';'); | ||
| 329 | } | ||
| 330 | |||
| 331 | /// Generates code representing a uniform (C buffer) register. | ||
| 332 | std::string GetUniform(const Uniform& uniform, const Register& dest_reg) { | ||
| 333 | declr_const_buffers[uniform.index].MarkAsUsed(static_cast<unsigned>(uniform.index), | ||
| 334 | static_cast<unsigned>(uniform.offset), stage); | ||
| 335 | std::string value = | ||
| 336 | 'c' + std::to_string(uniform.index) + '[' + std::to_string(uniform.offset) + ']'; | ||
| 337 | |||
| 338 | if (regs[dest_reg].IsFloat()) { | ||
| 339 | return value; | ||
| 340 | } else if (regs[dest_reg].IsInteger()) { | ||
| 341 | return "floatBitsToInt(" + value + ')'; | ||
| 342 | } else { | ||
| 343 | UNREACHABLE(); | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | /// Add declarations for registers | ||
| 348 | void GenerateDeclarations() { | ||
| 349 | for (const auto& reg : regs) { | ||
| 350 | if (reg.IsFloatUsed()) { | ||
| 351 | declarations.AddLine("float " + reg.GetFloatString() + " = 0.0;"); | ||
| 352 | } | ||
| 353 | if (reg.IsIntegerUsed()) { | ||
| 354 | declarations.AddLine("int " + reg.GetIntegerString() + " = 0;"); | ||
| 355 | } | ||
| 356 | } | ||
| 357 | declarations.AddNewLine(); | ||
| 358 | |||
| 359 | for (const auto& index : declr_input_attribute) { | ||
| 360 | // TODO(bunnei): Use proper number of elements for these | ||
| 361 | declarations.AddLine("layout(location = " + | ||
| 362 | std::to_string(static_cast<u32>(index) - | ||
| 363 | static_cast<u32>(Attribute::Index::Attribute_0)) + | ||
| 364 | ") in vec4 " + GetInputAttribute(index) + ';'); | ||
| 365 | } | ||
| 366 | declarations.AddNewLine(); | ||
| 367 | |||
| 368 | for (const auto& index : declr_output_attribute) { | ||
| 369 | // TODO(bunnei): Use proper number of elements for these | ||
| 370 | declarations.AddLine("layout(location = " + | ||
| 371 | std::to_string(static_cast<u32>(index) - | ||
| 372 | static_cast<u32>(Attribute::Index::Attribute_0)) + | ||
| 373 | ") out vec4 " + GetOutputAttribute(index) + ';'); | ||
| 374 | } | ||
| 375 | declarations.AddNewLine(); | ||
| 376 | |||
| 377 | unsigned const_buffer_layout = 0; | ||
| 378 | for (const auto& entry : GetConstBuffersDeclarations()) { | ||
| 379 | declarations.AddLine("layout(std430) buffer " + entry.GetName()); | ||
| 380 | declarations.AddLine('{'); | ||
| 381 | declarations.AddLine(" float c" + std::to_string(entry.GetIndex()) + "[];"); | ||
| 382 | declarations.AddLine("};"); | ||
| 383 | declarations.AddNewLine(); | ||
| 384 | ++const_buffer_layout; | ||
| 385 | } | ||
| 386 | declarations.AddNewLine(); | ||
| 387 | } | ||
| 388 | |||
| 389 | /// Returns a list of constant buffer declarations | ||
| 390 | std::vector<ConstBufferEntry> GetConstBuffersDeclarations() const { | ||
| 391 | std::vector<ConstBufferEntry> result; | ||
| 392 | std::copy_if(declr_const_buffers.begin(), declr_const_buffers.end(), | ||
| 393 | std::back_inserter(result), [](const auto& entry) { return entry.IsUsed(); }); | ||
| 394 | return result; | ||
| 251 | } | 395 | } |
| 252 | 396 | ||
| 253 | private: | 397 | private: |
| 254 | /// Build the GLSL register list | 398 | /// Build the GLSL register list. |
| 255 | void BuildRegisterList() { | 399 | void BuildRegisterList() { |
| 256 | for (size_t index = 0; index < Register::NumRegisters; ++index) { | 400 | for (size_t index = 0; index < Register::NumRegisters; ++index) { |
| 257 | regs.emplace_back(index, shader); | 401 | regs.emplace_back(index, shader); |
| 258 | } | 402 | } |
| 259 | } | 403 | } |
| 260 | 404 | ||
| 261 | /// Gets the Subroutine object corresponding to the specified address. | ||
| 262 | const Subroutine& GetSubroutine(u32 begin, u32 end) const { | ||
| 263 | auto iter = subroutines.find(Subroutine{begin, end}); | ||
| 264 | ASSERT(iter != subroutines.end()); | ||
| 265 | return *iter; | ||
| 266 | } | ||
| 267 | |||
| 268 | /// Generates code representing an input attribute register. | 405 | /// Generates code representing an input attribute register. |
| 269 | std::string GetInputAttribute(Attribute::Index attribute) { | 406 | std::string GetInputAttribute(Attribute::Index attribute) { |
| 270 | switch (attribute) { | 407 | switch (attribute) { |
| @@ -301,6 +438,50 @@ private: | |||
| 301 | } | 438 | } |
| 302 | } | 439 | } |
| 303 | 440 | ||
| 441 | /// Generates code to use for a swizzle operation. | ||
| 442 | static std::string GetSwizzle(u64 elem) { | ||
| 443 | ASSERT(elem <= 3); | ||
| 444 | std::string swizzle = "."; | ||
| 445 | swizzle += "xyzw"[elem]; | ||
| 446 | return swizzle; | ||
| 447 | } | ||
| 448 | |||
| 449 | ShaderWriter& shader; | ||
| 450 | ShaderWriter& declarations; | ||
| 451 | std::vector<GLSLRegister> regs; | ||
| 452 | std::set<Attribute::Index> declr_input_attribute; | ||
| 453 | std::set<Attribute::Index> declr_output_attribute; | ||
| 454 | std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers; | ||
| 455 | const Maxwell3D::Regs::ShaderStage& stage; | ||
| 456 | }; | ||
| 457 | |||
| 458 | class GLSLGenerator { | ||
| 459 | public: | ||
| 460 | GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code, | ||
| 461 | u32 main_offset, Maxwell3D::Regs::ShaderStage stage) | ||
| 462 | : subroutines(subroutines), program_code(program_code), main_offset(main_offset), | ||
| 463 | stage(stage) { | ||
| 464 | |||
| 465 | Generate(); | ||
| 466 | } | ||
| 467 | |||
| 468 | std::string GetShaderCode() { | ||
| 469 | return declarations.GetResult() + shader.GetResult(); | ||
| 470 | } | ||
| 471 | |||
| 472 | /// Returns entries in the shader that are useful for external functions | ||
| 473 | ShaderEntries GetEntries() const { | ||
| 474 | return {regs.GetConstBuffersDeclarations()}; | ||
| 475 | } | ||
| 476 | |||
| 477 | private: | ||
| 478 | /// Gets the Subroutine object corresponding to the specified address. | ||
| 479 | const Subroutine& GetSubroutine(u32 begin, u32 end) const { | ||
| 480 | auto iter = subroutines.find(Subroutine{begin, end}); | ||
| 481 | ASSERT(iter != subroutines.end()); | ||
| 482 | return *iter; | ||
| 483 | } | ||
| 484 | |||
| 304 | /// Generates code representing a 19-bit immediate value | 485 | /// Generates code representing a 19-bit immediate value |
| 305 | static std::string GetImmediate19(const Instruction& instr) { | 486 | static std::string GetImmediate19(const Instruction& instr) { |
| 306 | return std::to_string(instr.alu.GetImm20_19()); | 487 | return std::to_string(instr.alu.GetImm20_19()); |
| @@ -311,29 +492,13 @@ private: | |||
| 311 | return std::to_string(instr.alu.GetImm20_32()); | 492 | return std::to_string(instr.alu.GetImm20_32()); |
| 312 | } | 493 | } |
| 313 | 494 | ||
| 314 | /// Generates code representing a temporary (GPR) register. | ||
| 315 | std::string GetRegister(const Register& reg, unsigned elem = 0) { | ||
| 316 | if (reg == Register::ZeroIndex) { | ||
| 317 | return "0"; | ||
| 318 | } | ||
| 319 | |||
| 320 | return regs[reg.GetSwizzledIndex(elem)].GetActiveString(); | ||
| 321 | } | ||
| 322 | |||
| 323 | /// Generates code representing a uniform (C buffer) register. | ||
| 324 | std::string GetUniform(const Uniform& reg) { | ||
| 325 | declr_const_buffers[reg.index].MarkAsUsed(static_cast<unsigned>(reg.index), | ||
| 326 | static_cast<unsigned>(reg.offset), stage); | ||
| 327 | return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']'; | ||
| 328 | } | ||
| 329 | |||
| 330 | /// Generates code representing a texture sampler. | 495 | /// Generates code representing a texture sampler. |
| 331 | std::string GetSampler(const Sampler& sampler) const { | 496 | std::string GetSampler(const Sampler& sampler) const { |
| 332 | // TODO(Subv): Support more than just texture sampler 0 | 497 | // TODO(Subv): Support more than just texture sampler 0 |
| 333 | ASSERT_MSG(sampler.index == Sampler::Index::Sampler_0, "unsupported"); | 498 | ASSERT_MSG(sampler.index == Sampler::Index::Sampler_0, "unsupported"); |
| 334 | const unsigned index{static_cast<unsigned>(sampler.index.Value()) - | 499 | const unsigned index{static_cast<unsigned>(sampler.index.Value()) - |
| 335 | static_cast<unsigned>(Sampler::Index::Sampler_0)}; | 500 | static_cast<unsigned>(Sampler::Index::Sampler_0)}; |
| 336 | return "tex[" + std::to_string(index) + "]"; | 501 | return "tex[" + std::to_string(index) + ']'; |
| 337 | } | 502 | } |
| 338 | 503 | ||
| 339 | /** | 504 | /** |
| @@ -351,23 +516,6 @@ private: | |||
| 351 | } | 516 | } |
| 352 | } | 517 | } |
| 353 | 518 | ||
| 354 | /** | ||
| 355 | * Writes code that does an assignment operation. | ||
| 356 | * @param reg the destination register code. | ||
| 357 | * @param value the code representing the value to assign. | ||
| 358 | */ | ||
| 359 | void SetDest(u64 elem, const std::string& reg, const std::string& value, | ||
| 360 | u64 dest_num_components, u64 value_num_components, bool is_abs = false) { | ||
| 361 | std::string swizzle = "."; | ||
| 362 | swizzle += "xyzw"[elem]; | ||
| 363 | |||
| 364 | std::string dest = reg + (dest_num_components != 1 ? swizzle : ""); | ||
| 365 | std::string src = "(" + value + ")" + (value_num_components != 1 ? swizzle : ""); | ||
| 366 | src = is_abs ? "abs(" + src + ")" : src; | ||
| 367 | |||
| 368 | shader.AddLine(dest + " = " + src + ";"); | ||
| 369 | } | ||
| 370 | |||
| 371 | /* | 519 | /* |
| 372 | * Writes code that assigns a predicate boolean variable. | 520 | * Writes code that assigns a predicate boolean variable. |
| 373 | * @param pred The id of the predicate to write to. | 521 | * @param pred The id of the predicate to write to. |
| @@ -449,11 +597,10 @@ private: | |||
| 449 | 597 | ||
| 450 | switch (opcode->GetType()) { | 598 | switch (opcode->GetType()) { |
| 451 | case OpCode::Type::Arithmetic: { | 599 | case OpCode::Type::Arithmetic: { |
| 452 | std::string dest = GetRegister(instr.gpr0); | ||
| 453 | std::string op_a = instr.alu.negate_a ? "-" : ""; | 600 | std::string op_a = instr.alu.negate_a ? "-" : ""; |
| 454 | op_a += GetRegister(instr.gpr8); | 601 | op_a += regs.GetRegister(instr.gpr8); |
| 455 | if (instr.alu.abs_a) { | 602 | if (instr.alu.abs_a) { |
| 456 | op_a = "abs(" + op_a + ")"; | 603 | op_a = "abs(" + op_a + ')'; |
| 457 | } | 604 | } |
| 458 | 605 | ||
| 459 | std::string op_b = instr.alu.negate_b ? "-" : ""; | 606 | std::string op_b = instr.alu.negate_b ? "-" : ""; |
| @@ -462,56 +609,64 @@ private: | |||
| 462 | op_b += GetImmediate19(instr); | 609 | op_b += GetImmediate19(instr); |
| 463 | } else { | 610 | } else { |
| 464 | if (instr.is_b_gpr) { | 611 | if (instr.is_b_gpr) { |
| 465 | op_b += GetRegister(instr.gpr20); | 612 | op_b += regs.GetRegister(instr.gpr20); |
| 466 | } else { | 613 | } else { |
| 467 | op_b += GetUniform(instr.uniform); | 614 | op_b += regs.GetUniform(instr.uniform, instr.gpr0); |
| 468 | } | 615 | } |
| 469 | } | 616 | } |
| 470 | 617 | ||
| 471 | if (instr.alu.abs_b) { | 618 | if (instr.alu.abs_b) { |
| 472 | op_b = "abs(" + op_b + ")"; | 619 | op_b = "abs(" + op_b + ')'; |
| 473 | } | 620 | } |
| 474 | 621 | ||
| 475 | switch (opcode->GetId()) { | 622 | switch (opcode->GetId()) { |
| 476 | case OpCode::Id::FMUL_C: | 623 | case OpCode::Id::FMUL_C: |
| 477 | case OpCode::Id::FMUL_R: | 624 | case OpCode::Id::FMUL_R: |
| 478 | case OpCode::Id::FMUL_IMM: { | 625 | case OpCode::Id::FMUL_IMM: { |
| 479 | SetDest(0, dest, op_a + " * " + op_b, 1, 1, instr.alu.abs_d); | 626 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, instr.alu.abs_d); |
| 480 | break; | 627 | break; |
| 481 | } | 628 | } |
| 482 | case OpCode::Id::FMUL32_IMM: { | 629 | case OpCode::Id::FMUL32_IMM: { |
| 483 | // fmul32i doesn't have abs or neg bits. | 630 | // fmul32i doesn't have abs or neg bits. |
| 484 | SetDest(0, dest, GetRegister(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1); | 631 | regs.SetRegisterToFloat( |
| 632 | instr.gpr0, 0, regs.GetRegister(instr.gpr8) + " * " + GetImmediate32(instr), 1, | ||
| 633 | 1); | ||
| 485 | break; | 634 | break; |
| 486 | } | 635 | } |
| 487 | case OpCode::Id::FADD_C: | 636 | case OpCode::Id::FADD_C: |
| 488 | case OpCode::Id::FADD_R: | 637 | case OpCode::Id::FADD_R: |
| 489 | case OpCode::Id::FADD_IMM: { | 638 | case OpCode::Id::FADD_IMM: { |
| 490 | SetDest(0, dest, op_a + " + " + op_b, 1, 1, instr.alu.abs_d); | 639 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, instr.alu.abs_d); |
| 491 | break; | 640 | break; |
| 492 | } | 641 | } |
| 493 | case OpCode::Id::MUFU: { | 642 | case OpCode::Id::MUFU: { |
| 494 | switch (instr.sub_op) { | 643 | switch (instr.sub_op) { |
| 495 | case SubOp::Cos: | 644 | case SubOp::Cos: |
| 496 | SetDest(0, dest, "cos(" + op_a + ")", 1, 1, instr.alu.abs_d); | 645 | regs.SetRegisterToFloat(instr.gpr0, 0, "cos(" + op_a + ')', 1, 1, |
| 646 | instr.alu.abs_d); | ||
| 497 | break; | 647 | break; |
| 498 | case SubOp::Sin: | 648 | case SubOp::Sin: |
| 499 | SetDest(0, dest, "sin(" + op_a + ")", 1, 1, instr.alu.abs_d); | 649 | regs.SetRegisterToFloat(instr.gpr0, 0, "sin(" + op_a + ')', 1, 1, |
| 650 | instr.alu.abs_d); | ||
| 500 | break; | 651 | break; |
| 501 | case SubOp::Ex2: | 652 | case SubOp::Ex2: |
| 502 | SetDest(0, dest, "exp2(" + op_a + ")", 1, 1, instr.alu.abs_d); | 653 | regs.SetRegisterToFloat(instr.gpr0, 0, "exp2(" + op_a + ')', 1, 1, |
| 654 | instr.alu.abs_d); | ||
| 503 | break; | 655 | break; |
| 504 | case SubOp::Lg2: | 656 | case SubOp::Lg2: |
| 505 | SetDest(0, dest, "log2(" + op_a + ")", 1, 1, instr.alu.abs_d); | 657 | regs.SetRegisterToFloat(instr.gpr0, 0, "log2(" + op_a + ')', 1, 1, |
| 658 | instr.alu.abs_d); | ||
| 506 | break; | 659 | break; |
| 507 | case SubOp::Rcp: | 660 | case SubOp::Rcp: |
| 508 | SetDest(0, dest, "1.0 / " + op_a, 1, 1, instr.alu.abs_d); | 661 | regs.SetRegisterToFloat(instr.gpr0, 0, "1.0 / " + op_a, 1, 1, instr.alu.abs_d); |
| 509 | break; | 662 | break; |
| 510 | case SubOp::Rsq: | 663 | case SubOp::Rsq: |
| 511 | SetDest(0, dest, "inversesqrt(" + op_a + ")", 1, 1, instr.alu.abs_d); | 664 | regs.SetRegisterToFloat(instr.gpr0, 0, "inversesqrt(" + op_a + ')', 1, 1, |
| 665 | instr.alu.abs_d); | ||
| 512 | break; | 666 | break; |
| 513 | case SubOp::Min: | 667 | case SubOp::Min: |
| 514 | SetDest(0, dest, "min(" + op_a + "," + op_b + ")", 1, 1, instr.alu.abs_d); | 668 | regs.SetRegisterToFloat(instr.gpr0, 0, "min(" + op_a + "," + op_b + ')', 1, 1, |
| 669 | instr.alu.abs_d); | ||
| 515 | break; | 670 | break; |
| 516 | default: | 671 | default: |
| 517 | NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {0:x}", | 672 | NGLOG_CRITICAL(HW_GPU, "Unhandled MUFU sub op: {0:x}", |
| @@ -532,30 +687,29 @@ private: | |||
| 532 | break; | 687 | break; |
| 533 | } | 688 | } |
| 534 | case OpCode::Type::Ffma: { | 689 | case OpCode::Type::Ffma: { |
| 535 | std::string dest = GetRegister(instr.gpr0); | 690 | std::string op_a = regs.GetRegister(instr.gpr8); |
| 536 | std::string op_a = GetRegister(instr.gpr8); | ||
| 537 | std::string op_b = instr.ffma.negate_b ? "-" : ""; | 691 | std::string op_b = instr.ffma.negate_b ? "-" : ""; |
| 538 | std::string op_c = instr.ffma.negate_c ? "-" : ""; | 692 | std::string op_c = instr.ffma.negate_c ? "-" : ""; |
| 539 | 693 | ||
| 540 | switch (opcode->GetId()) { | 694 | switch (opcode->GetId()) { |
| 541 | case OpCode::Id::FFMA_CR: { | 695 | case OpCode::Id::FFMA_CR: { |
| 542 | op_b += GetUniform(instr.uniform); | 696 | op_b += regs.GetUniform(instr.uniform, instr.gpr0); |
| 543 | op_c += GetRegister(instr.gpr39); | 697 | op_c += regs.GetRegister(instr.gpr39); |
| 544 | break; | 698 | break; |
| 545 | } | 699 | } |
| 546 | case OpCode::Id::FFMA_RR: { | 700 | case OpCode::Id::FFMA_RR: { |
| 547 | op_b += GetRegister(instr.gpr20); | 701 | op_b += regs.GetRegister(instr.gpr20); |
| 548 | op_c += GetRegister(instr.gpr39); | 702 | op_c += regs.GetRegister(instr.gpr39); |
| 549 | break; | 703 | break; |
| 550 | } | 704 | } |
| 551 | case OpCode::Id::FFMA_RC: { | 705 | case OpCode::Id::FFMA_RC: { |
| 552 | op_b += GetRegister(instr.gpr39); | 706 | op_b += regs.GetRegister(instr.gpr39); |
| 553 | op_c += GetUniform(instr.uniform); | 707 | op_c += regs.GetUniform(instr.uniform, instr.gpr0); |
| 554 | break; | 708 | break; |
| 555 | } | 709 | } |
| 556 | case OpCode::Id::FFMA_IMM: { | 710 | case OpCode::Id::FFMA_IMM: { |
| 557 | op_b += GetImmediate19(instr); | 711 | op_b += GetImmediate19(instr); |
| 558 | op_c += GetRegister(instr.gpr39); | 712 | op_c += regs.GetRegister(instr.gpr39); |
| 559 | break; | 713 | break; |
| 560 | } | 714 | } |
| 561 | default: { | 715 | default: { |
| @@ -564,28 +718,29 @@ private: | |||
| 564 | } | 718 | } |
| 565 | } | 719 | } |
| 566 | 720 | ||
| 567 | SetDest(0, dest, op_a + " * " + op_b + " + " + op_c, 1, 1); | 721 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b + " + " + op_c, 1, 1); |
| 568 | break; | 722 | break; |
| 569 | } | 723 | } |
| 570 | case OpCode::Type::Memory: { | 724 | case OpCode::Type::Memory: { |
| 571 | std::string gpr0 = GetRegister(instr.gpr0); | ||
| 572 | const Attribute::Index attribute = instr.attribute.fmt20.index; | 725 | const Attribute::Index attribute = instr.attribute.fmt20.index; |
| 573 | 726 | ||
| 574 | switch (opcode->GetId()) { | 727 | switch (opcode->GetId()) { |
| 575 | case OpCode::Id::LD_A: { | 728 | case OpCode::Id::LD_A: { |
| 576 | ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); | 729 | ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); |
| 577 | SetDest(instr.attribute.fmt20.element, gpr0, GetInputAttribute(attribute), 1, 4); | 730 | regs.SetRegisterToInputAttibute(instr.gpr0, instr.attribute.fmt20.element, |
| 731 | attribute); | ||
| 578 | break; | 732 | break; |
| 579 | } | 733 | } |
| 580 | case OpCode::Id::ST_A: { | 734 | case OpCode::Id::ST_A: { |
| 581 | ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); | 735 | ASSERT_MSG(instr.attribute.fmt20.size == 0, "untested"); |
| 582 | SetDest(instr.attribute.fmt20.element, GetOutputAttribute(attribute), gpr0, 4, 1); | 736 | regs.SetOutputAttributeToRegister(attribute, instr.attribute.fmt20.element, |
| 737 | instr.gpr0); | ||
| 583 | break; | 738 | break; |
| 584 | } | 739 | } |
| 585 | case OpCode::Id::TEXS: { | 740 | case OpCode::Id::TEXS: { |
| 586 | ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested"); | 741 | ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested"); |
| 587 | const std::string op_a = GetRegister(instr.gpr8); | 742 | const std::string op_a = regs.GetRegister(instr.gpr8); |
| 588 | const std::string op_b = GetRegister(instr.gpr20); | 743 | const std::string op_b = regs.GetRegister(instr.gpr20); |
| 589 | const std::string sampler = GetSampler(instr.sampler); | 744 | const std::string sampler = GetSampler(instr.sampler); |
| 590 | const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; | 745 | const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; |
| 591 | // Add an extra scope and declare the texture coords inside to prevent overwriting | 746 | // Add an extra scope and declare the texture coords inside to prevent overwriting |
| @@ -595,7 +750,7 @@ private: | |||
| 595 | shader.AddLine(coord); | 750 | shader.AddLine(coord); |
| 596 | const std::string texture = "texture(" + sampler + ", coords)"; | 751 | const std::string texture = "texture(" + sampler + ", coords)"; |
| 597 | for (unsigned elem = 0; elem < instr.attribute.fmt20.size; ++elem) { | 752 | for (unsigned elem = 0; elem < instr.attribute.fmt20.size; ++elem) { |
| 598 | SetDest(elem, GetRegister(instr.gpr0, elem), texture, 1, 4); | 753 | regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, elem); |
| 599 | } | 754 | } |
| 600 | --shader.scope; | 755 | --shader.scope; |
| 601 | shader.AddLine("}"); | 756 | shader.AddLine("}"); |
| @@ -610,7 +765,7 @@ private: | |||
| 610 | } | 765 | } |
| 611 | case OpCode::Type::FloatSetPredicate: { | 766 | case OpCode::Type::FloatSetPredicate: { |
| 612 | std::string op_a = instr.fsetp.neg_a ? "-" : ""; | 767 | std::string op_a = instr.fsetp.neg_a ? "-" : ""; |
| 613 | op_a += GetRegister(instr.gpr8); | 768 | op_a += regs.GetRegister(instr.gpr8); |
| 614 | 769 | ||
| 615 | if (instr.fsetp.abs_a) { | 770 | if (instr.fsetp.abs_a) { |
| 616 | op_a = "abs(" + op_a + ')'; | 771 | op_a = "abs(" + op_a + ')'; |
| @@ -626,9 +781,9 @@ private: | |||
| 626 | op_b += '(' + GetImmediate19(instr) + ')'; | 781 | op_b += '(' + GetImmediate19(instr) + ')'; |
| 627 | } else { | 782 | } else { |
| 628 | if (instr.is_b_gpr) { | 783 | if (instr.is_b_gpr) { |
| 629 | op_b += GetRegister(instr.gpr20); | 784 | op_b += regs.GetRegister(instr.gpr20); |
| 630 | } else { | 785 | } else { |
| 631 | op_b += GetUniform(instr.uniform); | 786 | op_b += regs.GetUniform(instr.uniform, instr.gpr0); |
| 632 | } | 787 | } |
| 633 | } | 788 | } |
| 634 | 789 | ||
| @@ -660,9 +815,8 @@ private: | |||
| 660 | break; | 815 | break; |
| 661 | } | 816 | } |
| 662 | case OpCode::Type::FloatSet: { | 817 | case OpCode::Type::FloatSet: { |
| 663 | std::string dest = GetRegister(instr.gpr0); | ||
| 664 | std::string op_a = instr.fset.neg_a ? "-" : ""; | 818 | std::string op_a = instr.fset.neg_a ? "-" : ""; |
| 665 | op_a += GetRegister(instr.gpr8); | 819 | op_a += regs.GetRegister(instr.gpr8); |
| 666 | 820 | ||
| 667 | if (instr.fset.abs_a) { | 821 | if (instr.fset.abs_a) { |
| 668 | op_a = "abs(" + op_a + ')'; | 822 | op_a = "abs(" + op_a + ')'; |
| @@ -678,14 +832,14 @@ private: | |||
| 678 | op_b += imm; | 832 | op_b += imm; |
| 679 | } else { | 833 | } else { |
| 680 | if (instr.is_b_gpr) { | 834 | if (instr.is_b_gpr) { |
| 681 | op_b += GetRegister(instr.gpr20); | 835 | op_b += regs.GetRegister(instr.gpr20); |
| 682 | } else { | 836 | } else { |
| 683 | op_b += GetUniform(instr.uniform); | 837 | op_b += regs.GetUniform(instr.uniform, instr.gpr0); |
| 684 | } | 838 | } |
| 685 | } | 839 | } |
| 686 | 840 | ||
| 687 | if (instr.fset.abs_b) { | 841 | if (instr.fset.abs_b) { |
| 688 | op_b = "abs(" + op_b + ")"; | 842 | op_b = "abs(" + op_b + ')'; |
| 689 | } | 843 | } |
| 690 | 844 | ||
| 691 | using Tegra::Shader::Pred; | 845 | using Tegra::Shader::Pred; |
| @@ -697,13 +851,16 @@ private: | |||
| 697 | using Tegra::Shader::PredCondition; | 851 | using Tegra::Shader::PredCondition; |
| 698 | switch (instr.fset.cond) { | 852 | switch (instr.fset.cond) { |
| 699 | case PredCondition::LessThan: | 853 | case PredCondition::LessThan: |
| 700 | SetDest(0, dest, "((" + op_a + ") < (" + op_b + ")) ? 1.0 : 0", 1, 1); | 854 | regs.SetRegisterToFloat(instr.gpr0, 0, |
| 855 | "((" + op_a + ") < (" + op_b + ")) ? 1.0 : 0", 1, 1); | ||
| 701 | break; | 856 | break; |
| 702 | case PredCondition::Equal: | 857 | case PredCondition::Equal: |
| 703 | SetDest(0, dest, "((" + op_a + ") == (" + op_b + ")) ? 1.0 : 0", 1, 1); | 858 | regs.SetRegisterToFloat(instr.gpr0, 0, |
| 859 | "((" + op_a + ") == (" + op_b + ")) ? 1.0 : 0", 1, 1); | ||
| 704 | break; | 860 | break; |
| 705 | case PredCondition::GreaterThan: | 861 | case PredCondition::GreaterThan: |
| 706 | SetDest(0, dest, "((" + op_a + ") > (" + op_b + ")) ? 1.0 : 0", 1, 1); | 862 | regs.SetRegisterToFloat(instr.gpr0, 0, |
| 863 | "((" + op_a + ") > (" + op_b + ")) ? 1.0 : 0", 1, 1); | ||
| 707 | break; | 864 | break; |
| 708 | default: | 865 | default: |
| 709 | NGLOG_CRITICAL(HW_GPU, "Unhandled predicate condition: {} (a: {}, b: {})", | 866 | NGLOG_CRITICAL(HW_GPU, "Unhandled predicate condition: {} (a: {}, b: {})", |
| @@ -720,10 +877,10 @@ private: | |||
| 720 | 877 | ||
| 721 | // Final color output is currently hardcoded to GPR0-3 for fragment shaders | 878 | // Final color output is currently hardcoded to GPR0-3 for fragment shaders |
| 722 | if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { | 879 | if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { |
| 723 | shader.AddLine("color.r = " + GetRegister(0) + ";"); | 880 | shader.AddLine("color.r = " + regs.GetRegister(0) + ';'); |
| 724 | shader.AddLine("color.g = " + GetRegister(1) + ";"); | 881 | shader.AddLine("color.g = " + regs.GetRegister(1) + ';'); |
| 725 | shader.AddLine("color.b = " + GetRegister(2) + ";"); | 882 | shader.AddLine("color.b = " + regs.GetRegister(2) + ';'); |
| 726 | shader.AddLine("color.a = " + GetRegister(3) + ";"); | 883 | shader.AddLine("color.a = " + regs.GetRegister(3) + ';'); |
| 727 | } | 884 | } |
| 728 | 885 | ||
| 729 | shader.AddLine("return true;"); | 886 | shader.AddLine("return true;"); |
| @@ -736,8 +893,7 @@ private: | |||
| 736 | } | 893 | } |
| 737 | case OpCode::Id::IPA: { | 894 | case OpCode::Id::IPA: { |
| 738 | const auto& attribute = instr.attribute.fmt28; | 895 | const auto& attribute = instr.attribute.fmt28; |
| 739 | std::string dest = GetRegister(instr.gpr0); | 896 | regs.SetRegisterToInputAttibute(instr.gpr0, attribute.element, attribute.index); |
| 740 | SetDest(attribute.element, dest, GetInputAttribute(attribute.index), 1, 4); | ||
| 741 | break; | 897 | break; |
| 742 | } | 898 | } |
| 743 | default: { | 899 | default: { |
| @@ -843,55 +999,10 @@ private: | |||
| 843 | GenerateDeclarations(); | 999 | GenerateDeclarations(); |
| 844 | } | 1000 | } |
| 845 | 1001 | ||
| 846 | /// Returns a list of constant buffer declarations | ||
| 847 | std::vector<ConstBufferEntry> GetConstBuffersDeclarations() const { | ||
| 848 | std::vector<ConstBufferEntry> result; | ||
| 849 | std::copy_if(declr_const_buffers.begin(), declr_const_buffers.end(), | ||
| 850 | std::back_inserter(result), [](const auto& entry) { return entry.IsUsed(); }); | ||
| 851 | return result; | ||
| 852 | } | ||
| 853 | |||
| 854 | /// Add declarations for registers | 1002 | /// Add declarations for registers |
| 855 | void GenerateDeclarations() { | 1003 | void GenerateDeclarations() { |
| 856 | for (const auto& reg : regs) { | 1004 | regs.GenerateDeclarations(); |
| 857 | if (reg.IsFloatUsed()) { | ||
| 858 | declarations.AddLine("float " + reg.GetFloatString() + " = 0.0;"); | ||
| 859 | } | ||
| 860 | if (reg.IsIntegerUsed()) { | ||
| 861 | declarations.AddLine("int " + reg.GetIntegerString() + " = 0;"); | ||
| 862 | } | ||
| 863 | } | ||
| 864 | declarations.AddNewLine(); | ||
| 865 | 1005 | ||
| 866 | for (const auto& index : declr_input_attribute) { | ||
| 867 | // TODO(bunnei): Use proper number of elements for these | ||
| 868 | declarations.AddLine("layout(location = " + | ||
| 869 | std::to_string(static_cast<u32>(index) - | ||
| 870 | static_cast<u32>(Attribute::Index::Attribute_0)) + | ||
| 871 | ") in vec4 " + GetInputAttribute(index) + ";"); | ||
| 872 | } | ||
| 873 | declarations.AddNewLine(); | ||
| 874 | |||
| 875 | for (const auto& index : declr_output_attribute) { | ||
| 876 | // TODO(bunnei): Use proper number of elements for these | ||
| 877 | declarations.AddLine("layout(location = " + | ||
| 878 | std::to_string(static_cast<u32>(index) - | ||
| 879 | static_cast<u32>(Attribute::Index::Attribute_0)) + | ||
| 880 | ") out vec4 " + GetOutputAttribute(index) + ";"); | ||
| 881 | } | ||
| 882 | declarations.AddNewLine(); | ||
| 883 | |||
| 884 | unsigned const_buffer_layout = 0; | ||
| 885 | for (const auto& entry : GetConstBuffersDeclarations()) { | ||
| 886 | declarations.AddLine("layout(std430) buffer " + entry.GetName()); | ||
| 887 | declarations.AddLine('{'); | ||
| 888 | declarations.AddLine(" float c" + std::to_string(entry.GetIndex()) + "[];"); | ||
| 889 | declarations.AddLine("};"); | ||
| 890 | declarations.AddNewLine(); | ||
| 891 | ++const_buffer_layout; | ||
| 892 | } | ||
| 893 | |||
| 894 | declarations.AddNewLine(); | ||
| 895 | for (const auto& pred : declr_predicates) { | 1006 | for (const auto& pred : declr_predicates) { |
| 896 | declarations.AddLine("bool " + pred + " = false;"); | 1007 | declarations.AddLine("bool " + pred + " = false;"); |
| 897 | } | 1008 | } |
| @@ -906,13 +1017,10 @@ private: | |||
| 906 | 1017 | ||
| 907 | ShaderWriter shader; | 1018 | ShaderWriter shader; |
| 908 | ShaderWriter declarations; | 1019 | ShaderWriter declarations; |
| 909 | std::vector<GLSLRegister> regs; | 1020 | GLSLRegisterManager regs{shader, declarations, stage}; |
| 910 | 1021 | ||
| 911 | // Declarations | 1022 | // Declarations |
| 912 | std::set<std::string> declr_predicates; | 1023 | std::set<std::string> declr_predicates; |
| 913 | std::set<Attribute::Index> declr_input_attribute; | ||
| 914 | std::set<Attribute::Index> declr_output_attribute; | ||
| 915 | std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers; | ||
| 916 | }; // namespace Decompiler | 1024 | }; // namespace Decompiler |
| 917 | 1025 | ||
| 918 | std::string GetCommonDeclarations() { | 1026 | std::string GetCommonDeclarations() { |