summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/video_core/engines/maxwell_3d.cpp21
-rw-r--r--src/video_core/engines/maxwell_3d.h11
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp55
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp71
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.h3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp44
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h33
7 files changed, 149 insertions, 89 deletions
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 3bca16364..dfbf80abd 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -398,27 +398,6 @@ u32 Maxwell3D::GetRegisterValue(u32 method) const {
398 return regs.reg_array[method]; 398 return regs.reg_array[method];
399} 399}
400 400
401bool Maxwell3D::IsShaderStageEnabled(Regs::ShaderStage stage) const {
402 // The Vertex stage is always enabled.
403 if (stage == Regs::ShaderStage::Vertex)
404 return true;
405
406 switch (stage) {
407 case Regs::ShaderStage::TesselationControl:
408 return regs.shader_config[static_cast<size_t>(Regs::ShaderProgram::TesselationControl)]
409 .enable != 0;
410 case Regs::ShaderStage::TesselationEval:
411 return regs.shader_config[static_cast<size_t>(Regs::ShaderProgram::TesselationEval)]
412 .enable != 0;
413 case Regs::ShaderStage::Geometry:
414 return regs.shader_config[static_cast<size_t>(Regs::ShaderProgram::Geometry)].enable != 0;
415 case Regs::ShaderStage::Fragment:
416 return regs.shader_config[static_cast<size_t>(Regs::ShaderProgram::Fragment)].enable != 0;
417 }
418
419 UNREACHABLE();
420}
421
422void Maxwell3D::ProcessClearBuffers() { 401void Maxwell3D::ProcessClearBuffers() {
423 ASSERT(regs.clear_buffers.R == regs.clear_buffers.G && 402 ASSERT(regs.clear_buffers.R == regs.clear_buffers.G &&
424 regs.clear_buffers.R == regs.clear_buffers.B && 403 regs.clear_buffers.R == regs.clear_buffers.B &&
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 5a7cf0107..6f0170ff7 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -379,6 +379,14 @@ public:
379 } 379 }
380 }; 380 };
381 381
382 bool IsShaderConfigEnabled(size_t index) const {
383 // The VertexB is always enabled.
384 if (index == static_cast<size_t>(Regs::ShaderProgram::VertexB)) {
385 return true;
386 }
387 return shader_config[index].enable != 0;
388 }
389
382 union { 390 union {
383 struct { 391 struct {
384 INSERT_PADDING_WORDS(0x45); 392 INSERT_PADDING_WORDS(0x45);
@@ -780,9 +788,6 @@ public:
780 /// Returns the texture information for a specific texture in a specific shader stage. 788 /// Returns the texture information for a specific texture in a specific shader stage.
781 Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, size_t offset) const; 789 Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, size_t offset) const;
782 790
783 /// Returns whether the specified shader stage is enabled or not.
784 bool IsShaderStageEnabled(Regs::ShaderStage stage) const;
785
786private: 791private:
787 std::unordered_map<u32, std::vector<u32>> uploaded_macros; 792 std::unordered_map<u32, std::vector<u32>> uploaded_macros;
788 793
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index ea138d402..4072a12b4 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -181,6 +181,19 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr,
181 return {array_ptr, buffer_offset}; 181 return {array_ptr, buffer_offset};
182} 182}
183 183
184static GLShader::ProgramCode GetShaderProgramCode(Maxwell::ShaderProgram program) {
185 auto& gpu = Core::System().GetInstance().GPU().Maxwell3D();
186
187 // Fetch program code from memory
188 GLShader::ProgramCode program_code;
189 auto& shader_config = gpu.regs.shader_config[static_cast<size_t>(program)];
190 const u64 gpu_address{gpu.regs.code_address.CodeAddress() + shader_config.offset};
191 const boost::optional<VAddr> cpu_address{gpu.memory_manager.GpuToCpuAddress(gpu_address)};
192 Memory::ReadBlock(*cpu_address, program_code.data(), program_code.size() * sizeof(u64));
193
194 return program_code;
195}
196
184void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { 197void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
185 // Helper function for uploading uniform data 198 // Helper function for uploading uniform data
186 const auto copy_buffer = [&](GLuint handle, GLintptr offset, GLsizeiptr size) { 199 const auto copy_buffer = [&](GLuint handle, GLintptr offset, GLsizeiptr size) {
@@ -193,26 +206,23 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
193 }; 206 };
194 207
195 auto& gpu = Core::System().GetInstance().GPU().Maxwell3D(); 208 auto& gpu = Core::System().GetInstance().GPU().Maxwell3D();
196 ASSERT_MSG(!gpu.regs.shader_config[0].enable, "VertexA is unsupported!");
197 209
198 // Next available bindpoints to use when uploading the const buffers and textures to the GLSL 210 // Next available bindpoints to use when uploading the const buffers and textures to the GLSL
199 // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points. 211 // shaders. The constbuffer bindpoint starts after the shader stage configuration bind points.
200 u32 current_constbuffer_bindpoint = uniform_buffers.size(); 212 u32 current_constbuffer_bindpoint = uniform_buffers.size();
201 u32 current_texture_bindpoint = 0; 213 u32 current_texture_bindpoint = 0;
202 214
203 for (unsigned index = 1; index < Maxwell::MaxShaderProgram; ++index) { 215 for (size_t index = 0; index < Maxwell::MaxShaderProgram; ++index) {
204 auto& shader_config = gpu.regs.shader_config[index]; 216 auto& shader_config = gpu.regs.shader_config[index];
205 const Maxwell::ShaderProgram program{static_cast<Maxwell::ShaderProgram>(index)}; 217 const Maxwell::ShaderProgram program{static_cast<Maxwell::ShaderProgram>(index)};
206 218
207 const auto& stage = index - 1; // Stage indices are 0 - 5
208
209 const bool is_enabled = gpu.IsShaderStageEnabled(static_cast<Maxwell::ShaderStage>(stage));
210
211 // Skip stages that are not enabled 219 // Skip stages that are not enabled
212 if (!is_enabled) { 220 if (!gpu.regs.IsShaderConfigEnabled(index)) {
213 continue; 221 continue;
214 } 222 }
215 223
224 const size_t stage{index == 0 ? 0 : index - 1}; // Stage indices are 0 - 5
225
216 GLShader::MaxwellUniformData ubo{}; 226 GLShader::MaxwellUniformData ubo{};
217 ubo.SetFromRegs(gpu.state.shader_stages[stage]); 227 ubo.SetFromRegs(gpu.state.shader_stages[stage]);
218 std::memcpy(buffer_ptr, &ubo, sizeof(ubo)); 228 std::memcpy(buffer_ptr, &ubo, sizeof(ubo));
@@ -228,16 +238,21 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
228 buffer_ptr += sizeof(GLShader::MaxwellUniformData); 238 buffer_ptr += sizeof(GLShader::MaxwellUniformData);
229 buffer_offset += sizeof(GLShader::MaxwellUniformData); 239 buffer_offset += sizeof(GLShader::MaxwellUniformData);
230 240
231 // Fetch program code from memory 241 GLShader::ShaderSetup setup{GetShaderProgramCode(program)};
232 GLShader::ProgramCode program_code;
233 const u64 gpu_address{gpu.regs.code_address.CodeAddress() + shader_config.offset};
234 const boost::optional<VAddr> cpu_address{gpu.memory_manager.GpuToCpuAddress(gpu_address)};
235 Memory::ReadBlock(*cpu_address, program_code.data(), program_code.size() * sizeof(u64));
236 GLShader::ShaderSetup setup{std::move(program_code)};
237
238 GLShader::ShaderEntries shader_resources; 242 GLShader::ShaderEntries shader_resources;
239 243
240 switch (program) { 244 switch (program) {
245 case Maxwell::ShaderProgram::VertexA: {
246 // VertexB is always enabled, so when VertexA is enabled, we have two vertex shaders.
247 // Conventional HW does not support this, so we combine VertexA and VertexB into one
248 // stage here.
249 setup.SetProgramB(GetShaderProgramCode(Maxwell::ShaderProgram::VertexB));
250 GLShader::MaxwellVSConfig vs_config{setup};
251 shader_resources =
252 shader_program_manager->UseProgrammableVertexShader(vs_config, setup);
253 break;
254 }
255
241 case Maxwell::ShaderProgram::VertexB: { 256 case Maxwell::ShaderProgram::VertexB: {
242 GLShader::MaxwellVSConfig vs_config{setup}; 257 GLShader::MaxwellVSConfig vs_config{setup};
243 shader_resources = 258 shader_resources =
@@ -268,6 +283,12 @@ void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) {
268 current_texture_bindpoint = 283 current_texture_bindpoint =
269 SetupTextures(static_cast<Maxwell::ShaderStage>(stage), gl_stage_program, 284 SetupTextures(static_cast<Maxwell::ShaderStage>(stage), gl_stage_program,
270 current_texture_bindpoint, shader_resources.texture_samplers); 285 current_texture_bindpoint, shader_resources.texture_samplers);
286
287 // When VertexA is enabled, we have dual vertex shaders
288 if (program == Maxwell::ShaderProgram::VertexA) {
289 // VertexB was combined with VertexA, so we skip the VertexB iteration
290 index++;
291 }
271 } 292 }
272 293
273 shader_program_manager->UseTrivialGeometryShader(); 294 shader_program_manager->UseTrivialGeometryShader();
@@ -605,9 +626,6 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr
605 auto& gpu = Core::System::GetInstance().GPU(); 626 auto& gpu = Core::System::GetInstance().GPU();
606 auto& maxwell3d = gpu.Get3DEngine(); 627 auto& maxwell3d = gpu.Get3DEngine();
607 628
608 ASSERT_MSG(maxwell3d.IsShaderStageEnabled(stage),
609 "Attempted to upload constbuffer of disabled shader stage");
610
611 // Reset all buffer draw state for this stage. 629 // Reset all buffer draw state for this stage.
612 for (auto& buffer : state.draw.const_buffers[static_cast<size_t>(stage)]) { 630 for (auto& buffer : state.draw.const_buffers[static_cast<size_t>(stage)]) {
613 buffer.bindpoint = 0; 631 buffer.bindpoint = 0;
@@ -674,9 +692,6 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, GLuint program,
674 auto& gpu = Core::System::GetInstance().GPU(); 692 auto& gpu = Core::System::GetInstance().GPU();
675 auto& maxwell3d = gpu.Get3DEngine(); 693 auto& maxwell3d = gpu.Get3DEngine();
676 694
677 ASSERT_MSG(maxwell3d.IsShaderStageEnabled(stage),
678 "Attempted to upload textures of disabled shader stage");
679
680 ASSERT_MSG(current_unit + entries.size() <= std::size(state.texture_units), 695 ASSERT_MSG(current_unit + entries.size() <= std::size(state.texture_units),
681 "Exceeded the number of active textures."); 696 "Exceeded the number of active textures.");
682 697
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 96a4ca6fe..5fae95788 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -42,13 +42,14 @@ enum class ExitMethod {
42struct Subroutine { 42struct Subroutine {
43 /// Generates a name suitable for GLSL source code. 43 /// Generates a name suitable for GLSL source code.
44 std::string GetName() const { 44 std::string GetName() const {
45 return "sub_" + std::to_string(begin) + '_' + std::to_string(end); 45 return "sub_" + std::to_string(begin) + '_' + std::to_string(end) + '_' + suffix;
46 } 46 }
47 47
48 u32 begin; ///< Entry point of the subroutine. 48 u32 begin; ///< Entry point of the subroutine.
49 u32 end; ///< Return point of the subroutine. 49 u32 end; ///< Return point of the subroutine.
50 ExitMethod exit_method; ///< Exit method of the subroutine. 50 const std::string& suffix; ///< Suffix of the shader, used to make a unique subroutine name
51 std::set<u32> labels; ///< Addresses refereced by JMP instructions. 51 ExitMethod exit_method; ///< Exit method of the subroutine.
52 std::set<u32> labels; ///< Addresses refereced by JMP instructions.
52 53
53 bool operator<(const Subroutine& rhs) const { 54 bool operator<(const Subroutine& rhs) const {
54 return std::tie(begin, end) < std::tie(rhs.begin, rhs.end); 55 return std::tie(begin, end) < std::tie(rhs.begin, rhs.end);
@@ -58,11 +59,11 @@ struct Subroutine {
58/// Analyzes shader code and produces a set of subroutines. 59/// Analyzes shader code and produces a set of subroutines.
59class ControlFlowAnalyzer { 60class ControlFlowAnalyzer {
60public: 61public:
61 ControlFlowAnalyzer(const ProgramCode& program_code, u32 main_offset) 62 ControlFlowAnalyzer(const ProgramCode& program_code, u32 main_offset, const std::string& suffix)
62 : program_code(program_code) { 63 : program_code(program_code) {
63 64
64 // Recursively finds all subroutines. 65 // Recursively finds all subroutines.
65 const Subroutine& program_main = AddSubroutine(main_offset, PROGRAM_END); 66 const Subroutine& program_main = AddSubroutine(main_offset, PROGRAM_END, suffix);
66 if (program_main.exit_method != ExitMethod::AlwaysEnd) 67 if (program_main.exit_method != ExitMethod::AlwaysEnd)
67 throw DecompileFail("Program does not always end"); 68 throw DecompileFail("Program does not always end");
68 } 69 }
@@ -77,12 +78,12 @@ private:
77 std::map<std::pair<u32, u32>, ExitMethod> exit_method_map; 78 std::map<std::pair<u32, u32>, ExitMethod> exit_method_map;
78 79
79 /// Adds and analyzes a new subroutine if it is not added yet. 80 /// Adds and analyzes a new subroutine if it is not added yet.
80 const Subroutine& AddSubroutine(u32 begin, u32 end) { 81 const Subroutine& AddSubroutine(u32 begin, u32 end, const std::string& suffix) {
81 auto iter = subroutines.find(Subroutine{begin, end}); 82 auto iter = subroutines.find(Subroutine{begin, end, suffix});
82 if (iter != subroutines.end()) 83 if (iter != subroutines.end())
83 return *iter; 84 return *iter;
84 85
85 Subroutine subroutine{begin, end}; 86 Subroutine subroutine{begin, end, suffix};
86 subroutine.exit_method = Scan(begin, end, subroutine.labels); 87 subroutine.exit_method = Scan(begin, end, subroutine.labels);
87 if (subroutine.exit_method == ExitMethod::Undetermined) 88 if (subroutine.exit_method == ExitMethod::Undetermined)
88 throw DecompileFail("Recursive function detected"); 89 throw DecompileFail("Recursive function detected");
@@ -191,7 +192,8 @@ public:
191 UnsignedInteger, 192 UnsignedInteger,
192 }; 193 };
193 194
194 GLSLRegister(size_t index, ShaderWriter& shader) : index{index}, shader{shader} {} 195 GLSLRegister(size_t index, ShaderWriter& shader, const std::string& suffix)
196 : index{index}, shader{shader}, suffix{suffix} {}
195 197
196 /// Gets the GLSL type string for a register 198 /// Gets the GLSL type string for a register
197 static std::string GetTypeString(Type type) { 199 static std::string GetTypeString(Type type) {
@@ -216,7 +218,7 @@ public:
216 /// Returns a GLSL string representing the current state of the register 218 /// Returns a GLSL string representing the current state of the register
217 const std::string GetActiveString() { 219 const std::string GetActiveString() {
218 declr_type.insert(active_type); 220 declr_type.insert(active_type);
219 return GetPrefixString(active_type) + std::to_string(index); 221 return GetPrefixString(active_type) + std::to_string(index) + '_' + suffix;
220 } 222 }
221 223
222 /// Returns true if the active type is a float 224 /// Returns true if the active type is a float
@@ -251,6 +253,7 @@ private:
251 ShaderWriter& shader; 253 ShaderWriter& shader;
252 Type active_type{Type::Float}; 254 Type active_type{Type::Float};
253 std::set<Type> declr_type; 255 std::set<Type> declr_type;
256 const std::string& suffix;
254}; 257};
255 258
256/** 259/**
@@ -262,8 +265,8 @@ private:
262class GLSLRegisterManager { 265class GLSLRegisterManager {
263public: 266public:
264 GLSLRegisterManager(ShaderWriter& shader, ShaderWriter& declarations, 267 GLSLRegisterManager(ShaderWriter& shader, ShaderWriter& declarations,
265 const Maxwell3D::Regs::ShaderStage& stage) 268 const Maxwell3D::Regs::ShaderStage& stage, const std::string& suffix)
266 : shader{shader}, declarations{declarations}, stage{stage} { 269 : shader{shader}, declarations{declarations}, stage{stage}, suffix{suffix} {
267 BuildRegisterList(); 270 BuildRegisterList();
268 } 271 }
269 272
@@ -430,12 +433,12 @@ public:
430 } 433 }
431 434
432 /// Add declarations for registers 435 /// Add declarations for registers
433 void GenerateDeclarations() { 436 void GenerateDeclarations(const std::string& suffix) {
434 for (const auto& reg : regs) { 437 for (const auto& reg : regs) {
435 for (const auto& type : reg.DeclaredTypes()) { 438 for (const auto& type : reg.DeclaredTypes()) {
436 declarations.AddLine(GLSLRegister::GetTypeString(type) + ' ' + 439 declarations.AddLine(GLSLRegister::GetTypeString(type) + ' ' +
437 GLSLRegister::GetPrefixString(type) + 440 reg.GetPrefixString(type) + std::to_string(reg.GetIndex()) +
438 std::to_string(reg.GetIndex()) + " = 0;"); 441 '_' + suffix + " = 0;");
439 } 442 }
440 } 443 }
441 declarations.AddNewLine(); 444 declarations.AddNewLine();
@@ -558,7 +561,7 @@ private:
558 /// Build the GLSL register list. 561 /// Build the GLSL register list.
559 void BuildRegisterList() { 562 void BuildRegisterList() {
560 for (size_t index = 0; index < Register::NumRegisters; ++index) { 563 for (size_t index = 0; index < Register::NumRegisters; ++index) {
561 regs.emplace_back(index, shader); 564 regs.emplace_back(index, shader, suffix);
562 } 565 }
563 } 566 }
564 567
@@ -620,16 +623,17 @@ private:
620 std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers; 623 std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers;
621 std::vector<SamplerEntry> used_samplers; 624 std::vector<SamplerEntry> used_samplers;
622 const Maxwell3D::Regs::ShaderStage& stage; 625 const Maxwell3D::Regs::ShaderStage& stage;
626 const std::string& suffix;
623}; 627};
624 628
625class GLSLGenerator { 629class GLSLGenerator {
626public: 630public:
627 GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code, 631 GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code,
628 u32 main_offset, Maxwell3D::Regs::ShaderStage stage) 632 u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix)
629 : subroutines(subroutines), program_code(program_code), main_offset(main_offset), 633 : subroutines(subroutines), program_code(program_code), main_offset(main_offset),
630 stage(stage) { 634 stage(stage), suffix(suffix) {
631 635
632 Generate(); 636 Generate(suffix);
633 } 637 }
634 638
635 std::string GetShaderCode() { 639 std::string GetShaderCode() {
@@ -644,7 +648,7 @@ public:
644private: 648private:
645 /// Gets the Subroutine object corresponding to the specified address. 649 /// Gets the Subroutine object corresponding to the specified address.
646 const Subroutine& GetSubroutine(u32 begin, u32 end) const { 650 const Subroutine& GetSubroutine(u32 begin, u32 end) const {
647 auto iter = subroutines.find(Subroutine{begin, end}); 651 auto iter = subroutines.find(Subroutine{begin, end, suffix});
648 ASSERT(iter != subroutines.end()); 652 ASSERT(iter != subroutines.end());
649 return *iter; 653 return *iter;
650 } 654 }
@@ -689,7 +693,7 @@ private:
689 // Can't assign to the constant predicate. 693 // Can't assign to the constant predicate.
690 ASSERT(pred != static_cast<u64>(Pred::UnusedIndex)); 694 ASSERT(pred != static_cast<u64>(Pred::UnusedIndex));
691 695
692 std::string variable = 'p' + std::to_string(pred); 696 std::string variable = 'p' + std::to_string(pred) + '_' + suffix;
693 shader.AddLine(variable + " = " + value + ';'); 697 shader.AddLine(variable + " = " + value + ';');
694 declr_predicates.insert(std::move(variable)); 698 declr_predicates.insert(std::move(variable));
695 } 699 }
@@ -707,7 +711,7 @@ private:
707 if (index == static_cast<u64>(Pred::UnusedIndex)) 711 if (index == static_cast<u64>(Pred::UnusedIndex))
708 variable = "true"; 712 variable = "true";
709 else 713 else
710 variable = 'p' + std::to_string(index); 714 variable = 'p' + std::to_string(index) + '_' + suffix;
711 715
712 if (negate) { 716 if (negate) {
713 return "!(" + variable + ')'; 717 return "!(" + variable + ')';
@@ -1728,7 +1732,7 @@ private:
1728 return program_counter; 1732 return program_counter;
1729 } 1733 }
1730 1734
1731 void Generate() { 1735 void Generate(const std::string& suffix) {
1732 // Add declarations for all subroutines 1736 // Add declarations for all subroutines
1733 for (const auto& subroutine : subroutines) { 1737 for (const auto& subroutine : subroutines) {
1734 shader.AddLine("bool " + subroutine.GetName() + "();"); 1738 shader.AddLine("bool " + subroutine.GetName() + "();");
@@ -1736,7 +1740,7 @@ private:
1736 shader.AddNewLine(); 1740 shader.AddNewLine();
1737 1741
1738 // Add the main entry point 1742 // Add the main entry point
1739 shader.AddLine("bool exec_shader() {"); 1743 shader.AddLine("bool exec_" + suffix + "() {");
1740 ++shader.scope; 1744 ++shader.scope;
1741 CallSubroutine(GetSubroutine(main_offset, PROGRAM_END)); 1745 CallSubroutine(GetSubroutine(main_offset, PROGRAM_END));
1742 --shader.scope; 1746 --shader.scope;
@@ -1799,7 +1803,7 @@ private:
1799 1803
1800 /// Add declarations for registers 1804 /// Add declarations for registers
1801 void GenerateDeclarations() { 1805 void GenerateDeclarations() {
1802 regs.GenerateDeclarations(); 1806 regs.GenerateDeclarations(suffix);
1803 1807
1804 for (const auto& pred : declr_predicates) { 1808 for (const auto& pred : declr_predicates) {
1805 declarations.AddLine("bool " + pred + " = false;"); 1809 declarations.AddLine("bool " + pred + " = false;");
@@ -1812,27 +1816,30 @@ private:
1812 const ProgramCode& program_code; 1816 const ProgramCode& program_code;
1813 const u32 main_offset; 1817 const u32 main_offset;
1814 Maxwell3D::Regs::ShaderStage stage; 1818 Maxwell3D::Regs::ShaderStage stage;
1819 const std::string& suffix;
1815 1820
1816 ShaderWriter shader; 1821 ShaderWriter shader;
1817 ShaderWriter declarations; 1822 ShaderWriter declarations;
1818 GLSLRegisterManager regs{shader, declarations, stage}; 1823 GLSLRegisterManager regs{shader, declarations, stage, suffix};
1819 1824
1820 // Declarations 1825 // Declarations
1821 std::set<std::string> declr_predicates; 1826 std::set<std::string> declr_predicates;
1822}; // namespace Decompiler 1827}; // namespace Decompiler
1823 1828
1824std::string GetCommonDeclarations() { 1829std::string GetCommonDeclarations() {
1825 std::string declarations = "bool exec_shader();\n"; 1830 std::string declarations;
1826 declarations += "#define MAX_CONSTBUFFER_ELEMENTS " + 1831 declarations += "#define MAX_CONSTBUFFER_ELEMENTS " +
1827 std::to_string(RasterizerOpenGL::MaxConstbufferSize / (sizeof(GLvec4))); 1832 std::to_string(RasterizerOpenGL::MaxConstbufferSize / (sizeof(GLvec4)));
1833 declarations += '\n';
1828 return declarations; 1834 return declarations;
1829} 1835}
1830 1836
1831boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, 1837boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset,
1832 Maxwell3D::Regs::ShaderStage stage) { 1838 Maxwell3D::Regs::ShaderStage stage,
1839 const std::string& suffix) {
1833 try { 1840 try {
1834 auto subroutines = ControlFlowAnalyzer(program_code, main_offset).GetSubroutines(); 1841 auto subroutines = ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines();
1835 GLSLGenerator generator(subroutines, program_code, main_offset, stage); 1842 GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix);
1836 return ProgramResult{generator.GetShaderCode(), generator.GetEntries()}; 1843 return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
1837 } catch (const DecompileFail& exception) { 1844 } catch (const DecompileFail& exception) {
1838 LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what()); 1845 LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what());
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h
index 382c76b7a..7610dad3a 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.h
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h
@@ -20,7 +20,8 @@ using Tegra::Engines::Maxwell3D;
20std::string GetCommonDeclarations(); 20std::string GetCommonDeclarations();
21 21
22boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, 22boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset,
23 Maxwell3D::Regs::ShaderStage stage); 23 Maxwell3D::Regs::ShaderStage stage,
24 const std::string& suffix);
24 25
25} // namespace Decompiler 26} // namespace Decompiler
26} // namespace GLShader 27} // namespace GLShader
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index c1e6fac9f..129c777d1 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -17,10 +17,17 @@ ProgramResult GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConf
17 std::string out = "#version 430 core\n"; 17 std::string out = "#version 430 core\n";
18 out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; 18 out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
19 out += Decompiler::GetCommonDeclarations(); 19 out += Decompiler::GetCommonDeclarations();
20 out += "bool exec_vertex();\n";
21
22 if (setup.IsDualProgram()) {
23 out += "bool exec_vertex_b();\n";
24 }
25
26 ProgramResult program =
27 Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET,
28 Maxwell3D::Regs::ShaderStage::Vertex, "vertex")
29 .get_value_or({});
20 30
21 ProgramResult program = Decompiler::DecompileProgram(setup.program_code, PROGRAM_OFFSET,
22 Maxwell3D::Regs::ShaderStage::Vertex)
23 .get_value_or({});
24 out += R"( 31 out += R"(
25 32
26out gl_PerVertex { 33out gl_PerVertex {
@@ -34,7 +41,14 @@ layout (std140) uniform vs_config {
34}; 41};
35 42
36void main() { 43void main() {
37 exec_shader(); 44 exec_vertex();
45)";
46
47 if (setup.IsDualProgram()) {
48 out += " exec_vertex_b();";
49 }
50
51 out += R"(
38 52
39 // Viewport can be flipped, which is unsupported by glViewport 53 // Viewport can be flipped, which is unsupported by glViewport
40 position.xy *= viewport_flip.xy; 54 position.xy *= viewport_flip.xy;
@@ -44,8 +58,19 @@ void main() {
44 // For now, this is here to bring order in lieu of proper emulation 58 // For now, this is here to bring order in lieu of proper emulation
45 position.w = 1.0; 59 position.w = 1.0;
46} 60}
61
47)"; 62)";
63
48 out += program.first; 64 out += program.first;
65
66 if (setup.IsDualProgram()) {
67 ProgramResult program_b =
68 Decompiler::DecompileProgram(setup.program.code_b, PROGRAM_OFFSET,
69 Maxwell3D::Regs::ShaderStage::Vertex, "vertex_b")
70 .get_value_or({});
71 out += program_b.first;
72 }
73
49 return {out, program.second}; 74 return {out, program.second};
50} 75}
51 76
@@ -53,12 +78,13 @@ ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSCo
53 std::string out = "#version 430 core\n"; 78 std::string out = "#version 430 core\n";
54 out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; 79 out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
55 out += Decompiler::GetCommonDeclarations(); 80 out += Decompiler::GetCommonDeclarations();
81 out += "bool exec_fragment();\n";
56 82
57 ProgramResult program = Decompiler::DecompileProgram(setup.program_code, PROGRAM_OFFSET, 83 ProgramResult program =
58 Maxwell3D::Regs::ShaderStage::Fragment) 84 Decompiler::DecompileProgram(setup.program.code, PROGRAM_OFFSET,
59 .get_value_or({}); 85 Maxwell3D::Regs::ShaderStage::Fragment, "fragment")
86 .get_value_or({});
60 out += R"( 87 out += R"(
61
62in vec4 position; 88in vec4 position;
63out vec4 color; 89out vec4 color;
64 90
@@ -67,7 +93,7 @@ layout (std140) uniform fs_config {
67}; 93};
68 94
69void main() { 95void main() {
70 exec_shader(); 96 exec_fragment();
71} 97}
72 98
73)"; 99)";
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h
index ed890e0f9..4729ce0fc 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.h
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -115,21 +115,48 @@ struct ShaderEntries {
115using ProgramResult = std::pair<std::string, ShaderEntries>; 115using ProgramResult = std::pair<std::string, ShaderEntries>;
116 116
117struct ShaderSetup { 117struct ShaderSetup {
118 ShaderSetup(ProgramCode&& program_code) : program_code(std::move(program_code)) {} 118 ShaderSetup(const ProgramCode& program_code) {
119 program.code = program_code;
120 }
121
122 struct {
123 ProgramCode code;
124 ProgramCode code_b; // Used for dual vertex shaders
125 } program;
119 126
120 ProgramCode program_code;
121 bool program_code_hash_dirty = true; 127 bool program_code_hash_dirty = true;
122 128
123 u64 GetProgramCodeHash() { 129 u64 GetProgramCodeHash() {
124 if (program_code_hash_dirty) { 130 if (program_code_hash_dirty) {
125 program_code_hash = Common::ComputeHash64(&program_code, sizeof(program_code)); 131 program_code_hash = GetNewHash();
126 program_code_hash_dirty = false; 132 program_code_hash_dirty = false;
127 } 133 }
128 return program_code_hash; 134 return program_code_hash;
129 } 135 }
130 136
137 /// Used in scenarios where we have a dual vertex shaders
138 void SetProgramB(const ProgramCode& program_b) {
139 program.code_b = program_b;
140 has_program_b = true;
141 }
142
143 bool IsDualProgram() const {
144 return has_program_b;
145 }
146
131private: 147private:
148 u64 GetNewHash() const {
149 if (has_program_b) {
150 // Compute hash over dual shader programs
151 return Common::ComputeHash64(&program, sizeof(program));
152 } else {
153 // Compute hash over a single shader program
154 return Common::ComputeHash64(&program.code, program.code.size());
155 }
156 }
157
132 u64 program_code_hash{}; 158 u64 program_code_hash{};
159 bool has_program_b{};
133}; 160};
134 161
135struct MaxwellShaderConfigCommon { 162struct MaxwellShaderConfigCommon {