diff options
| -rw-r--r-- | src/video_core/engines/maxwell_3d.cpp | 21 | ||||
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 11 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 55 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 71 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.h | 3 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 44 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.h | 33 |
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 | ||
| 401 | bool 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 | |||
| 422 | void Maxwell3D::ProcessClearBuffers() { | 401 | void 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 | |||
| 786 | private: | 791 | private: |
| 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 | ||
| 184 | static 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 | |||
| 184 | void RasterizerOpenGL::SetupShaders(u8* buffer_ptr, GLintptr buffer_offset) { | 197 | void 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 { | |||
| 42 | struct Subroutine { | 42 | struct 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. |
| 59 | class ControlFlowAnalyzer { | 60 | class ControlFlowAnalyzer { |
| 60 | public: | 61 | public: |
| 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: | |||
| 262 | class GLSLRegisterManager { | 265 | class GLSLRegisterManager { |
| 263 | public: | 266 | public: |
| 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 | ||
| 625 | class GLSLGenerator { | 629 | class GLSLGenerator { |
| 626 | public: | 630 | public: |
| 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: | |||
| 644 | private: | 648 | private: |
| 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 | ||
| 1824 | std::string GetCommonDeclarations() { | 1829 | std::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 | ||
| 1831 | boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, | 1837 | boost::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; | |||
| 20 | std::string GetCommonDeclarations(); | 20 | std::string GetCommonDeclarations(); |
| 21 | 21 | ||
| 22 | boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, | 22 | boost::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 | ||
| 26 | out gl_PerVertex { | 33 | out gl_PerVertex { |
| @@ -34,7 +41,14 @@ layout (std140) uniform vs_config { | |||
| 34 | }; | 41 | }; |
| 35 | 42 | ||
| 36 | void main() { | 43 | void 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 | |||
| 62 | in vec4 position; | 88 | in vec4 position; |
| 63 | out vec4 color; | 89 | out vec4 color; |
| 64 | 90 | ||
| @@ -67,7 +93,7 @@ layout (std140) uniform fs_config { | |||
| 67 | }; | 93 | }; |
| 68 | 94 | ||
| 69 | void main() { | 95 | void 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 { | |||
| 115 | using ProgramResult = std::pair<std::string, ShaderEntries>; | 115 | using ProgramResult = std::pair<std::string, ShaderEntries>; |
| 116 | 116 | ||
| 117 | struct ShaderSetup { | 117 | struct 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 | |||
| 131 | private: | 147 | private: |
| 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 | ||
| 135 | struct MaxwellShaderConfigCommon { | 162 | struct MaxwellShaderConfigCommon { |