summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/video_core/engines/shader_bytecode.h76
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp157
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h50
3 files changed, 250 insertions, 33 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index 9413a81fb..3ba6fe614 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -223,6 +223,13 @@ enum class PredicateResultMode : u64 {
223 NotZero = 0x3, 223 NotZero = 0x3,
224}; 224};
225 225
226enum class TextureType : u64 {
227 Texture1D = 0,
228 Texture2D = 1,
229 Texture3D = 2,
230 TextureCube = 3,
231};
232
226union Instruction { 233union Instruction {
227 Instruction& operator=(const Instruction& instr) { 234 Instruction& operator=(const Instruction& instr) {
228 value = instr.value; 235 value = instr.value;
@@ -434,6 +441,8 @@ union Instruction {
434 } conversion; 441 } conversion;
435 442
436 union { 443 union {
444 BitField<28, 1, u64> array;
445 BitField<29, 2, TextureType> texture_type;
437 BitField<31, 4, u64> component_mask; 446 BitField<31, 4, u64> component_mask;
438 447
439 bool IsComponentEnabled(size_t component) const { 448 bool IsComponentEnabled(size_t component) const {
@@ -442,9 +451,39 @@ union Instruction {
442 } tex; 451 } tex;
443 452
444 union { 453 union {
445 BitField<50, 3, u64> component_mask_selector; 454 BitField<28, 1, u64> array;
455 BitField<29, 2, TextureType> texture_type;
456 BitField<56, 2, u64> component;
457 } tld4;
458
459 union {
460 BitField<52, 2, u64> component;
461 } tld4s;
462
463 union {
446 BitField<0, 8, Register> gpr0; 464 BitField<0, 8, Register> gpr0;
447 BitField<28, 8, Register> gpr28; 465 BitField<28, 8, Register> gpr28;
466 BitField<50, 3, u64> component_mask_selector;
467 BitField<53, 4, u64> texture_info;
468
469 TextureType GetTextureType() const {
470 // The TEXS instruction has a weird encoding for the texture type.
471 if (texture_info == 0)
472 return TextureType::Texture1D;
473 if (texture_info >= 1 && texture_info <= 9)
474 return TextureType::Texture2D;
475 if (texture_info >= 10 && texture_info <= 11)
476 return TextureType::Texture3D;
477 if (texture_info >= 12 && texture_info <= 13)
478 return TextureType::TextureCube;
479
480 UNIMPLEMENTED();
481 }
482
483 bool IsArrayTexture() const {
484 // TEXS only supports Texture2D arrays.
485 return texture_info >= 7 && texture_info <= 9;
486 }
448 487
449 bool HasTwoDestinations() const { 488 bool HasTwoDestinations() const {
450 return gpr28.Value() != Register::ZeroIndex; 489 return gpr28.Value() != Register::ZeroIndex;
@@ -469,6 +508,31 @@ union Instruction {
469 } texs; 508 } texs;
470 509
471 union { 510 union {
511 BitField<53, 4, u64> texture_info;
512
513 TextureType GetTextureType() const {
514 // The TLDS instruction has a weird encoding for the texture type.
515 if (texture_info >= 0 && texture_info <= 1) {
516 return TextureType::Texture1D;
517 }
518 if (texture_info == 2 || texture_info == 8 || texture_info == 12 ||
519 texture_info >= 4 && texture_info <= 6) {
520 return TextureType::Texture2D;
521 }
522 if (texture_info == 7) {
523 return TextureType::Texture3D;
524 }
525
526 UNIMPLEMENTED();
527 }
528
529 bool IsArrayTexture() const {
530 // TEXS only supports Texture2D arrays.
531 return texture_info == 8;
532 }
533 } tlds;
534
535 union {
472 BitField<20, 24, u64> target; 536 BitField<20, 24, u64> target;
473 BitField<5, 1, u64> constant_buffer; 537 BitField<5, 1, u64> constant_buffer;
474 538
@@ -533,9 +597,11 @@ public:
533 LDG, // Load from global memory 597 LDG, // Load from global memory
534 STG, // Store in global memory 598 STG, // Store in global memory
535 TEX, 599 TEX,
536 TEXQ, // Texture Query 600 TEXQ, // Texture Query
537 TEXS, // Texture Fetch with scalar/non-vec4 source/destinations 601 TEXS, // Texture Fetch with scalar/non-vec4 source/destinations
538 TLDS, // Texture Load with scalar/non-vec4 source/destinations 602 TLDS, // Texture Load with scalar/non-vec4 source/destinations
603 TLD4, // Texture Load 4
604 TLD4S, // Texture Load 4 with scalar / non - vec4 source / destinations
539 EXIT, 605 EXIT,
540 IPA, 606 IPA,
541 FFMA_IMM, // Fused Multiply and Add 607 FFMA_IMM, // Fused Multiply and Add
@@ -749,6 +815,8 @@ private:
749 INST("1101111101001---", Id::TEXQ, Type::Memory, "TEXQ"), 815 INST("1101111101001---", Id::TEXQ, Type::Memory, "TEXQ"),
750 INST("1101100---------", Id::TEXS, Type::Memory, "TEXS"), 816 INST("1101100---------", Id::TEXS, Type::Memory, "TEXS"),
751 INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"), 817 INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"),
818 INST("110010----111---", Id::TLD4, Type::Memory, "TLD4"),
819 INST("1101111100------", Id::TLD4S, Type::Memory, "TLD4S"),
752 INST("111000110000----", Id::EXIT, Type::Trivial, "EXIT"), 820 INST("111000110000----", Id::EXIT, Type::Trivial, "EXIT"),
753 INST("11100000--------", Id::IPA, Type::Trivial, "IPA"), 821 INST("11100000--------", Id::IPA, Type::Trivial, "IPA"),
754 INST("0011001-1-------", Id::FFMA_IMM, Type::Ffma, "FFMA_IMM"), 822 INST("0011001-1-------", Id::FFMA_IMM, Type::Ffma, "FFMA_IMM"),
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 57cf9f213..f3b2d1328 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -439,13 +439,12 @@ public:
439 } 439 }
440 declarations.AddNewLine(); 440 declarations.AddNewLine();
441 441
442 // Append the sampler2D array for the used textures. 442 const auto& samplers = GetSamplers();
443 size_t num_samplers = GetSamplers().size(); 443 for (const auto& sampler : samplers) {
444 if (num_samplers > 0) { 444 declarations.AddLine("uniform " + sampler.GetTypeString() + ' ' + sampler.GetName() +
445 declarations.AddLine("uniform sampler2D " + SamplerEntry::GetArrayName(stage) + '[' + 445 ';');
446 std::to_string(num_samplers) + "];");
447 declarations.AddNewLine();
448 } 446 }
447 declarations.AddNewLine();
449 } 448 }
450 449
451 /// Returns a list of constant buffer declarations 450 /// Returns a list of constant buffer declarations
@@ -457,13 +456,14 @@ public:
457 } 456 }
458 457
459 /// Returns a list of samplers used in the shader 458 /// Returns a list of samplers used in the shader
460 std::vector<SamplerEntry> GetSamplers() const { 459 const std::vector<SamplerEntry>& GetSamplers() const {
461 return used_samplers; 460 return used_samplers;
462 } 461 }
463 462
464 /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if 463 /// Returns the GLSL sampler used for the input shader sampler, and creates a new one if
465 /// necessary. 464 /// necessary.
466 std::string AccessSampler(const Sampler& sampler) { 465 std::string AccessSampler(const Sampler& sampler, Tegra::Shader::TextureType type,
466 bool is_array) {
467 size_t offset = static_cast<size_t>(sampler.index.Value()); 467 size_t offset = static_cast<size_t>(sampler.index.Value());
468 468
469 // If this sampler has already been used, return the existing mapping. 469 // If this sampler has already been used, return the existing mapping.
@@ -472,12 +472,13 @@ public:
472 [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; }); 472 [&](const SamplerEntry& entry) { return entry.GetOffset() == offset; });
473 473
474 if (itr != used_samplers.end()) { 474 if (itr != used_samplers.end()) {
475 ASSERT(itr->GetType() == type && itr->IsArray() == is_array);
475 return itr->GetName(); 476 return itr->GetName();
476 } 477 }
477 478
478 // Otherwise create a new mapping for this sampler 479 // Otherwise create a new mapping for this sampler
479 size_t next_index = used_samplers.size(); 480 size_t next_index = used_samplers.size();
480 SamplerEntry entry{stage, offset, next_index}; 481 SamplerEntry entry{stage, offset, next_index, type, is_array};
481 used_samplers.emplace_back(entry); 482 used_samplers.emplace_back(entry);
482 return entry.GetName(); 483 return entry.GetName();
483 } 484 }
@@ -638,8 +639,8 @@ private:
638 } 639 }
639 640
640 /// Generates code representing a texture sampler. 641 /// Generates code representing a texture sampler.
641 std::string GetSampler(const Sampler& sampler) { 642 std::string GetSampler(const Sampler& sampler, Tegra::Shader::TextureType type, bool is_array) {
642 return regs.AccessSampler(sampler); 643 return regs.AccessSampler(sampler, type, is_array);
643 } 644 }
644 645
645 /** 646 /**
@@ -1507,10 +1508,29 @@ private:
1507 break; 1508 break;
1508 } 1509 }
1509 case OpCode::Id::TEX: { 1510 case OpCode::Id::TEX: {
1510 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); 1511 ASSERT_MSG(instr.tex.array == 0, "TEX arrays unimplemented");
1511 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); 1512 std::string coord{};
1512 const std::string sampler = GetSampler(instr.sampler); 1513
1513 const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; 1514 switch (instr.tex.texture_type) {
1515 case Tegra::Shader::TextureType::Texture2D: {
1516 std::string x = regs.GetRegisterAsFloat(instr.gpr8);
1517 std::string y = regs.GetRegisterAsFloat(instr.gpr20);
1518 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
1519 break;
1520 }
1521 case Tegra::Shader::TextureType::Texture3D: {
1522 std::string x = regs.GetRegisterAsFloat(instr.gpr8);
1523 std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
1524 std::string z = regs.GetRegisterAsFloat(instr.gpr20);
1525 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
1526 break;
1527 }
1528 default:
1529 UNIMPLEMENTED();
1530 }
1531
1532 const std::string sampler =
1533 GetSampler(instr.sampler, instr.tex.texture_type, instr.tex.array);
1514 // Add an extra scope and declare the texture coords inside to prevent 1534 // Add an extra scope and declare the texture coords inside to prevent
1515 // overwriting them in case they are used as outputs of the texs instruction. 1535 // overwriting them in case they are used as outputs of the texs instruction.
1516 shader.AddLine("{"); 1536 shader.AddLine("{");
@@ -1532,24 +1552,115 @@ private:
1532 break; 1552 break;
1533 } 1553 }
1534 case OpCode::Id::TEXS: { 1554 case OpCode::Id::TEXS: {
1535 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); 1555 std::string coord{};
1536 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20); 1556
1537 const std::string sampler = GetSampler(instr.sampler); 1557 switch (instr.texs.GetTextureType()) {
1538 const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; 1558 case Tegra::Shader::TextureType::Texture2D: {
1559 if (instr.texs.IsArrayTexture()) {
1560 std::string index = regs.GetRegisterAsInteger(instr.gpr8);
1561 std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
1562 std::string y = regs.GetRegisterAsFloat(instr.gpr20);
1563 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");";
1564 } else {
1565 std::string x = regs.GetRegisterAsFloat(instr.gpr8);
1566 std::string y = regs.GetRegisterAsFloat(instr.gpr20);
1567 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
1568 }
1569 break;
1570 }
1571 case Tegra::Shader::TextureType::TextureCube: {
1572 std::string x = regs.GetRegisterAsFloat(instr.gpr8);
1573 std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
1574 std::string z = regs.GetRegisterAsFloat(instr.gpr20);
1575 coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");";
1576 break;
1577 }
1578 default:
1579 UNIMPLEMENTED();
1580 }
1581 const std::string sampler = GetSampler(instr.sampler, instr.texs.GetTextureType(),
1582 instr.texs.IsArrayTexture());
1539 1583
1540 const std::string texture = "texture(" + sampler + ", coords)"; 1584 const std::string texture = "texture(" + sampler + ", coords)";
1541 WriteTexsInstruction(instr, coord, texture); 1585 WriteTexsInstruction(instr, coord, texture);
1542 break; 1586 break;
1543 } 1587 }
1544 case OpCode::Id::TLDS: { 1588 case OpCode::Id::TLDS: {
1545 const std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); 1589 ASSERT(instr.tlds.GetTextureType() == Tegra::Shader::TextureType::Texture2D);
1546 const std::string op_b = regs.GetRegisterAsInteger(instr.gpr20); 1590 ASSERT(instr.tlds.IsArrayTexture() == false);
1547 const std::string sampler = GetSampler(instr.sampler); 1591 std::string coord{};
1548 const std::string coord = "ivec2 coords = ivec2(" + op_a + ", " + op_b + ");"; 1592
1593 switch (instr.tlds.GetTextureType()) {
1594 case Tegra::Shader::TextureType::Texture2D: {
1595 if (instr.tlds.IsArrayTexture()) {
1596 UNIMPLEMENTED();
1597 } else {
1598 std::string x = regs.GetRegisterAsInteger(instr.gpr8);
1599 std::string y = regs.GetRegisterAsInteger(instr.gpr20);
1600 coord = "ivec2 coords = ivec2(" + x + ", " + y + ");";
1601 }
1602 break;
1603 }
1604 default:
1605 UNIMPLEMENTED();
1606 }
1607 const std::string sampler = GetSampler(instr.sampler, instr.tlds.GetTextureType(),
1608 instr.tlds.IsArrayTexture());
1549 const std::string texture = "texelFetch(" + sampler + ", coords, 0)"; 1609 const std::string texture = "texelFetch(" + sampler + ", coords, 0)";
1550 WriteTexsInstruction(instr, coord, texture); 1610 WriteTexsInstruction(instr, coord, texture);
1551 break; 1611 break;
1552 } 1612 }
1613 case OpCode::Id::TLD4: {
1614 ASSERT(instr.tld4.texture_type == Tegra::Shader::TextureType::Texture2D);
1615 ASSERT(instr.tld4.array == 0);
1616 std::string coord{};
1617
1618 switch (instr.tld4.texture_type) {
1619 case Tegra::Shader::TextureType::Texture2D: {
1620 std::string x = regs.GetRegisterAsFloat(instr.gpr8);
1621 std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
1622 coord = "vec2 coords = vec2(" + x + ", " + y + ");";
1623 break;
1624 }
1625 default:
1626 UNIMPLEMENTED();
1627 }
1628
1629 const std::string sampler =
1630 GetSampler(instr.sampler, instr.tld4.texture_type, instr.tld4.array);
1631 // Add an extra scope and declare the texture coords inside to prevent
1632 // overwriting them in case they are used as outputs of the texs instruction.
1633 shader.AddLine("{");
1634 ++shader.scope;
1635 shader.AddLine(coord);
1636 const std::string texture = "textureGather(" + sampler + ", coords, " +
1637 std::to_string(instr.tld4.component) + ')';
1638
1639 size_t dest_elem{};
1640 for (size_t elem = 0; elem < 4; ++elem) {
1641 if (!instr.tex.IsComponentEnabled(elem)) {
1642 // Skip disabled components
1643 continue;
1644 }
1645 regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem);
1646 ++dest_elem;
1647 }
1648 --shader.scope;
1649 shader.AddLine("}");
1650 break;
1651 }
1652 case OpCode::Id::TLD4S: {
1653 const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
1654 const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
1655 // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction.
1656 const std::string sampler =
1657 GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false);
1658 const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
1659 const std::string texture = "textureGather(" + sampler + ", coords, " +
1660 std::to_string(instr.tld4s.component) + ')';
1661 WriteTexsInstruction(instr, coord, texture);
1662 break;
1663 }
1553 default: { 1664 default: {
1554 LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->GetName()); 1665 LOG_CRITICAL(HW_GPU, "Unhandled memory instruction: {}", opcode->GetName());
1555 UNREACHABLE(); 1666 UNREACHABLE();
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index 4729ce0fc..db48da645 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -11,6 +11,7 @@
11#include <vector> 11#include <vector>
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/hash.h" 13#include "common/hash.h"
14#include "video_core/engines/shader_bytecode.h"
14 15
15namespace GLShader { 16namespace GLShader {
16 17
@@ -72,8 +73,9 @@ class SamplerEntry {
72 using Maxwell = Tegra::Engines::Maxwell3D::Regs; 73 using Maxwell = Tegra::Engines::Maxwell3D::Regs;
73 74
74public: 75public:
75 SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index) 76 SamplerEntry(Maxwell::ShaderStage stage, size_t offset, size_t index,
76 : offset(offset), stage(stage), sampler_index(index) {} 77 Tegra::Shader::TextureType type, bool is_array)
78 : offset(offset), stage(stage), sampler_index(index), type(type), is_array(is_array) {}
77 79
78 size_t GetOffset() const { 80 size_t GetOffset() const {
79 return offset; 81 return offset;
@@ -88,8 +90,41 @@ public:
88 } 90 }
89 91
90 std::string GetName() const { 92 std::string GetName() const {
91 return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '[' + 93 return std::string(TextureSamplerNames[static_cast<size_t>(stage)]) + '_' +
92 std::to_string(sampler_index) + ']'; 94 std::to_string(sampler_index);
95 }
96
97 std::string GetTypeString() const {
98 using Tegra::Shader::TextureType;
99 std::string glsl_type;
100
101 switch (type) {
102 case TextureType::Texture1D:
103 glsl_type = "sampler1D";
104 break;
105 case TextureType::Texture2D:
106 glsl_type = "sampler2D";
107 break;
108 case TextureType::Texture3D:
109 glsl_type = "sampler3D";
110 break;
111 case TextureType::TextureCube:
112 glsl_type = "samplerCube";
113 break;
114 default:
115 UNIMPLEMENTED();
116 }
117 if (is_array)
118 glsl_type += "Array";
119 return glsl_type;
120 }
121
122 Tegra::Shader::TextureType GetType() const {
123 return type;
124 }
125
126 bool IsArray() const {
127 return is_array;
93 } 128 }
94 129
95 static std::string GetArrayName(Maxwell::ShaderStage stage) { 130 static std::string GetArrayName(Maxwell::ShaderStage stage) {
@@ -100,11 +135,14 @@ private:
100 static constexpr std::array<const char*, Maxwell::MaxShaderStage> TextureSamplerNames = { 135 static constexpr std::array<const char*, Maxwell::MaxShaderStage> TextureSamplerNames = {
101 "tex_vs", "tex_tessc", "tex_tesse", "tex_gs", "tex_fs", 136 "tex_vs", "tex_tessc", "tex_tesse", "tex_gs", "tex_fs",
102 }; 137 };
138
103 /// Offset in TSC memory from which to read the sampler object, as specified by the sampling 139 /// Offset in TSC memory from which to read the sampler object, as specified by the sampling
104 /// instruction. 140 /// instruction.
105 size_t offset; 141 size_t offset;
106 Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used. 142 Maxwell::ShaderStage stage; ///< Shader stage where this sampler was used.
107 size_t sampler_index; ///< Value used to index into the generated GLSL sampler array. 143 size_t sampler_index; ///< Value used to index into the generated GLSL sampler array.
144 Tegra::Shader::TextureType type; ///< The type used to sample this texture (Texture2D, etc)
145 bool is_array; ///< Whether the texture is being sampled as an array texture or not.
108}; 146};
109 147
110struct ShaderEntries { 148struct ShaderEntries {