diff options
| author | 2018-04-15 03:32:12 -0400 | |
|---|---|---|
| committer | 2018-04-15 11:50:10 -0400 | |
| commit | 73d9c494ea6ae0a8076f679506ff07e2fe014826 (patch) | |
| tree | f283b7d9b9014488dabd45e97f5687c2d67e842d /src | |
| parent | Merge pull request #328 from Subv/constbuffers (diff) | |
| download | yuzu-73d9c494ea6ae0a8076f679506ff07e2fe014826.tar.gz yuzu-73d9c494ea6ae0a8076f679506ff07e2fe014826.tar.xz yuzu-73d9c494ea6ae0a8076f679506ff07e2fe014826.zip | |
shaders: Expose hints about used const buffers.
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 40 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 54 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.h | 38 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_manager.h | 41 |
5 files changed, 146 insertions, 31 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 1290fa4cd..9cf2c6a0c 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -140,6 +140,11 @@ public: | |||
| 140 | return declarations.GetResult() + shader.GetResult(); | 140 | return declarations.GetResult() + shader.GetResult(); |
| 141 | } | 141 | } |
| 142 | 142 | ||
| 143 | /// Returns entries in the shader that are useful for external functions | ||
| 144 | ShaderEntries GetEntries() const { | ||
| 145 | return {GetConstBuffersDeclarations()}; | ||
| 146 | } | ||
| 147 | |||
| 143 | private: | 148 | private: |
| 144 | /// Gets the Subroutine object corresponding to the specified address. | 149 | /// Gets the Subroutine object corresponding to the specified address. |
| 145 | const Subroutine& GetSubroutine(u32 begin, u32 end) const { | 150 | const Subroutine& GetSubroutine(u32 begin, u32 end) const { |
| @@ -186,10 +191,9 @@ private: | |||
| 186 | } | 191 | } |
| 187 | 192 | ||
| 188 | /// Generates code representing a uniform (C buffer) register. | 193 | /// Generates code representing a uniform (C buffer) register. |
| 189 | std::string GetUniform(const Uniform& reg) const { | 194 | std::string GetUniform(const Uniform& reg) { |
| 190 | std::string index = std::to_string(reg.index); | 195 | declr_const_buffers[reg.index].MarkAsUsed(reg.index, reg.offset); |
| 191 | return "uniform_" + index + "[" + std::to_string(reg.offset >> 2) + "][" + | 196 | return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']'; |
| 192 | std::to_string(reg.offset & 3) + "]"; | ||
| 193 | } | 197 | } |
| 194 | 198 | ||
| 195 | /** | 199 | /** |
| @@ -439,6 +443,14 @@ private: | |||
| 439 | GenerateDeclarations(); | 443 | GenerateDeclarations(); |
| 440 | } | 444 | } |
| 441 | 445 | ||
| 446 | /// Returns a list of constant buffer declarations | ||
| 447 | std::vector<ConstBufferEntry> GetConstBuffersDeclarations() const { | ||
| 448 | std::vector<ConstBufferEntry> result; | ||
| 449 | std::copy_if(declr_const_buffers.begin(), declr_const_buffers.end(), | ||
| 450 | std::back_inserter(result), [](const auto& entry) { return entry.IsUsed(); }); | ||
| 451 | return result; | ||
| 452 | } | ||
| 453 | |||
| 442 | /// Add declarations for registers | 454 | /// Add declarations for registers |
| 443 | void GenerateDeclarations() { | 455 | void GenerateDeclarations() { |
| 444 | for (const auto& reg : declr_register) { | 456 | for (const auto& reg : declr_register) { |
| @@ -463,6 +475,17 @@ private: | |||
| 463 | ") out vec4 " + GetOutputAttribute(index) + ";"); | 475 | ") out vec4 " + GetOutputAttribute(index) + ";"); |
| 464 | } | 476 | } |
| 465 | declarations.AddLine(""); | 477 | declarations.AddLine(""); |
| 478 | |||
| 479 | unsigned const_buffer_layout = 0; | ||
| 480 | for (const auto& entry : GetConstBuffersDeclarations()) { | ||
| 481 | declarations.AddLine("layout(std430, binding = " + std::to_string(const_buffer_layout) + | ||
| 482 | ") buffer c" + std::to_string(entry.GetIndex()) + "_buffer"); | ||
| 483 | declarations.AddLine("{"); | ||
| 484 | declarations.AddLine(" float c" + std::to_string(entry.GetIndex()) + "[];"); | ||
| 485 | declarations.AddLine("};"); | ||
| 486 | declarations.AddLine(""); | ||
| 487 | ++const_buffer_layout; | ||
| 488 | } | ||
| 466 | } | 489 | } |
| 467 | 490 | ||
| 468 | private: | 491 | private: |
| @@ -478,18 +501,19 @@ private: | |||
| 478 | std::set<std::string> declr_register; | 501 | std::set<std::string> declr_register; |
| 479 | std::set<Attribute::Index> declr_input_attribute; | 502 | std::set<Attribute::Index> declr_input_attribute; |
| 480 | std::set<Attribute::Index> declr_output_attribute; | 503 | std::set<Attribute::Index> declr_output_attribute; |
| 481 | }; // namespace Decompiler | 504 | std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers; |
| 505 | }; | ||
| 482 | 506 | ||
| 483 | std::string GetCommonDeclarations() { | 507 | std::string GetCommonDeclarations() { |
| 484 | return "bool exec_shader();"; | 508 | return "bool exec_shader();"; |
| 485 | } | 509 | } |
| 486 | 510 | ||
| 487 | boost::optional<std::string> DecompileProgram(const ProgramCode& program_code, u32 main_offset, | 511 | boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, |
| 488 | Maxwell3D::Regs::ShaderStage stage) { | 512 | Maxwell3D::Regs::ShaderStage stage) { |
| 489 | try { | 513 | try { |
| 490 | auto subroutines = ControlFlowAnalyzer(program_code, main_offset).GetSubroutines(); | 514 | auto subroutines = ControlFlowAnalyzer(program_code, main_offset).GetSubroutines(); |
| 491 | GLSLGenerator generator(subroutines, program_code, main_offset, stage); | 515 | GLSLGenerator generator(subroutines, program_code, main_offset, stage); |
| 492 | return generator.GetShaderCode(); | 516 | return ProgramResult{generator.GetShaderCode(), generator.GetEntries()}; |
| 493 | } catch (const DecompileFail& exception) { | 517 | } catch (const DecompileFail& exception) { |
| 494 | LOG_ERROR(HW_GPU, "Shader decompilation failed: %s", exception.what()); | 518 | LOG_ERROR(HW_GPU, "Shader decompilation failed: %s", exception.what()); |
| 495 | } | 519 | } |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.h b/src/video_core/renderer_opengl/gl_shader_decompiler.h index 2f4047d87..9f6e0ef58 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.h +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.h | |||
| @@ -17,8 +17,8 @@ using Tegra::Engines::Maxwell3D; | |||
| 17 | 17 | ||
| 18 | std::string GetCommonDeclarations(); | 18 | std::string GetCommonDeclarations(); |
| 19 | 19 | ||
| 20 | boost::optional<std::string> DecompileProgram(const ProgramCode& program_code, u32 main_offset, | 20 | boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset, |
| 21 | Maxwell3D::Regs::ShaderStage stage); | 21 | Maxwell3D::Regs::ShaderStage stage); |
| 22 | 22 | ||
| 23 | } // namespace Decompiler | 23 | } // namespace Decompiler |
| 24 | } // namespace GLShader | 24 | } // 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 524c2cfb5..aeea1c805 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -3,18 +3,60 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/assert.h" | 5 | #include "common/assert.h" |
| 6 | #include "video_core/engines/maxwell_3d.h" | ||
| 7 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" | ||
| 6 | #include "video_core/renderer_opengl/gl_shader_gen.h" | 8 | #include "video_core/renderer_opengl/gl_shader_gen.h" |
| 7 | 9 | ||
| 8 | namespace GLShader { | 10 | namespace GLShader { |
| 9 | 11 | ||
| 10 | std::string GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config) { | 12 | using Tegra::Engines::Maxwell3D; |
| 11 | UNREACHABLE(); | 13 | |
| 12 | return {}; | 14 | static constexpr u32 PROGRAM_OFFSET{10}; |
| 15 | |||
| 16 | ProgramResult GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config) { | ||
| 17 | std::string out = "#version 430 core\n"; | ||
| 18 | out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; | ||
| 19 | out += Decompiler::GetCommonDeclarations(); | ||
| 20 | |||
| 21 | ProgramResult program = Decompiler::DecompileProgram(setup.program_code, PROGRAM_OFFSET, | ||
| 22 | Maxwell3D::Regs::ShaderStage::Vertex) | ||
| 23 | .get_value_or({}); | ||
| 24 | out += R"( | ||
| 25 | |||
| 26 | out gl_PerVertex { | ||
| 27 | vec4 gl_Position; | ||
| 28 | }; | ||
| 29 | |||
| 30 | void main() { | ||
| 31 | exec_shader(); | ||
| 32 | } | ||
| 33 | |||
| 34 | )"; | ||
| 35 | out += program.first; | ||
| 36 | return {out, program.second}; | ||
| 37 | } | ||
| 38 | |||
| 39 | ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSConfig& config) { | ||
| 40 | std::string out = "#version 430 core\n"; | ||
| 41 | out += "#extension GL_ARB_separate_shader_objects : enable\n\n"; | ||
| 42 | out += Decompiler::GetCommonDeclarations(); | ||
| 43 | |||
| 44 | ProgramResult program = Decompiler::DecompileProgram(setup.program_code, PROGRAM_OFFSET, | ||
| 45 | Maxwell3D::Regs::ShaderStage::Fragment) | ||
| 46 | .get_value_or({}); | ||
| 47 | out += R"( | ||
| 48 | |||
| 49 | out vec4 color; | ||
| 50 | |||
| 51 | uniform sampler2D tex[32]; | ||
| 52 | |||
| 53 | void main() { | ||
| 54 | exec_shader(); | ||
| 13 | } | 55 | } |
| 14 | 56 | ||
| 15 | std::string GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSConfig& config) { | 57 | )"; |
| 16 | UNREACHABLE(); | 58 | out += program.first; |
| 17 | return {}; | 59 | return {out, program.second}; |
| 18 | } | 60 | } |
| 19 | 61 | ||
| 20 | } // namespace GLShader | 62 | } // namespace GLShader |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index 925e66ee4..3d9aead74 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | #include <type_traits> | 9 | #include <type_traits> |
| 10 | #include <utility> | ||
| 11 | #include <vector> | ||
| 10 | #include "common/common_types.h" | 12 | #include "common/common_types.h" |
| 11 | #include "common/hash.h" | 13 | #include "common/hash.h" |
| 12 | 14 | ||
| @@ -16,6 +18,38 @@ constexpr size_t MAX_PROGRAM_CODE_LENGTH{0x1000}; | |||
| 16 | 18 | ||
| 17 | using ProgramCode = std::array<u64, MAX_PROGRAM_CODE_LENGTH>; | 19 | using ProgramCode = std::array<u64, MAX_PROGRAM_CODE_LENGTH>; |
| 18 | 20 | ||
| 21 | class ConstBufferEntry { | ||
| 22 | public: | ||
| 23 | void MarkAsUsed(unsigned index, unsigned offset) { | ||
| 24 | is_used = true; | ||
| 25 | this->index = index; | ||
| 26 | max_offset = std::max(max_offset, offset); | ||
| 27 | } | ||
| 28 | |||
| 29 | bool IsUsed() const { | ||
| 30 | return is_used; | ||
| 31 | } | ||
| 32 | |||
| 33 | unsigned GetIndex() const { | ||
| 34 | return index; | ||
| 35 | } | ||
| 36 | |||
| 37 | unsigned GetSize() const { | ||
| 38 | return max_offset + 1; | ||
| 39 | } | ||
| 40 | |||
| 41 | private: | ||
| 42 | bool is_used{}; | ||
| 43 | unsigned index{}; | ||
| 44 | unsigned max_offset{}; | ||
| 45 | }; | ||
| 46 | |||
| 47 | struct ShaderEntries { | ||
| 48 | std::vector<ConstBufferEntry> const_buffer_entries; | ||
| 49 | }; | ||
| 50 | |||
| 51 | using ProgramResult = std::pair<std::string, ShaderEntries>; | ||
| 52 | |||
| 19 | struct ShaderSetup { | 53 | struct ShaderSetup { |
| 20 | ShaderSetup(ProgramCode&& program_code) : program_code(std::move(program_code)) {} | 54 | ShaderSetup(ProgramCode&& program_code) : program_code(std::move(program_code)) {} |
| 21 | 55 | ||
| @@ -58,13 +92,13 @@ struct MaxwellFSConfig : Common::HashableStruct<MaxwellShaderConfigCommon> { | |||
| 58 | * Generates the GLSL vertex shader program source code for the given VS program | 92 | * Generates the GLSL vertex shader program source code for the given VS program |
| 59 | * @returns String of the shader source code | 93 | * @returns String of the shader source code |
| 60 | */ | 94 | */ |
| 61 | std::string GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config); | 95 | ProgramResult GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config); |
| 62 | 96 | ||
| 63 | /** | 97 | /** |
| 64 | * Generates the GLSL fragment shader program source code for the given FS program | 98 | * Generates the GLSL fragment shader program source code for the given FS program |
| 65 | * @returns String of the shader source code | 99 | * @returns String of the shader source code |
| 66 | */ | 100 | */ |
| 67 | std::string GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSConfig& config); | 101 | ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSConfig& config); |
| 68 | 102 | ||
| 69 | } // namespace GLShader | 103 | } // namespace GLShader |
| 70 | 104 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index f003ce532..ecc92d986 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h | |||
| @@ -41,19 +41,25 @@ class OGLShaderStage { | |||
| 41 | public: | 41 | public: |
| 42 | OGLShaderStage() = default; | 42 | OGLShaderStage() = default; |
| 43 | 43 | ||
| 44 | void Create(const char* source, GLenum type) { | 44 | void Create(const ProgramResult& program_result, GLenum type) { |
| 45 | OGLShader shader; | 45 | OGLShader shader; |
| 46 | shader.Create(source, type); | 46 | shader.Create(program_result.first.c_str(), type); |
| 47 | program.Create(true, shader.handle); | 47 | program.Create(true, shader.handle); |
| 48 | Impl::SetShaderUniformBlockBindings(program.handle); | 48 | Impl::SetShaderUniformBlockBindings(program.handle); |
| 49 | Impl::SetShaderSamplerBindings(program.handle); | 49 | Impl::SetShaderSamplerBindings(program.handle); |
| 50 | entries = program_result.second; | ||
| 50 | } | 51 | } |
| 51 | GLuint GetHandle() const { | 52 | GLuint GetHandle() const { |
| 52 | return program.handle; | 53 | return program.handle; |
| 53 | } | 54 | } |
| 54 | 55 | ||
| 56 | ShaderEntries GetEntries() const { | ||
| 57 | return entries; | ||
| 58 | } | ||
| 59 | |||
| 55 | private: | 60 | private: |
| 56 | OGLProgram program; | 61 | OGLProgram program; |
| 62 | ShaderEntries entries; | ||
| 57 | }; | 63 | }; |
| 58 | 64 | ||
| 59 | // TODO(wwylele): beautify this doc | 65 | // TODO(wwylele): beautify this doc |
| @@ -61,25 +67,28 @@ private: | |||
| 61 | // The double cache is needed because diffent KeyConfigType, which includes a hash of the code | 67 | // The double cache is needed because diffent KeyConfigType, which includes a hash of the code |
| 62 | // region (including its leftover unused code) can generate the same GLSL code. | 68 | // region (including its leftover unused code) can generate the same GLSL code. |
| 63 | template <typename KeyConfigType, | 69 | template <typename KeyConfigType, |
| 64 | std::string (*CodeGenerator)(const ShaderSetup&, const KeyConfigType&), GLenum ShaderType> | 70 | ProgramResult (*CodeGenerator)(const ShaderSetup&, const KeyConfigType&), |
| 71 | GLenum ShaderType> | ||
| 65 | class ShaderCache { | 72 | class ShaderCache { |
| 66 | public: | 73 | public: |
| 67 | ShaderCache() = default; | 74 | ShaderCache() = default; |
| 68 | 75 | ||
| 69 | GLuint Get(const KeyConfigType& key, const ShaderSetup& setup) { | 76 | using Result = std::pair<GLuint, ShaderEntries>; |
| 77 | |||
| 78 | Result Get(const KeyConfigType& key, const ShaderSetup& setup) { | ||
| 70 | auto map_it = shader_map.find(key); | 79 | auto map_it = shader_map.find(key); |
| 71 | if (map_it == shader_map.end()) { | 80 | if (map_it == shader_map.end()) { |
| 72 | std::string program = CodeGenerator(setup, key); | 81 | ProgramResult program = CodeGenerator(setup, key); |
| 73 | 82 | ||
| 74 | auto [iter, new_shader] = shader_cache.emplace(program, OGLShaderStage{}); | 83 | auto [iter, new_shader] = shader_cache.emplace(program.first, OGLShaderStage{}); |
| 75 | OGLShaderStage& cached_shader = iter->second; | 84 | OGLShaderStage& cached_shader = iter->second; |
| 76 | if (new_shader) { | 85 | if (new_shader) { |
| 77 | cached_shader.Create(program.c_str(), ShaderType); | 86 | cached_shader.Create(program, ShaderType); |
| 78 | } | 87 | } |
| 79 | shader_map[key] = &cached_shader; | 88 | shader_map[key] = &cached_shader; |
| 80 | return cached_shader.GetHandle(); | 89 | return {cached_shader.GetHandle(), program.second}; |
| 81 | } else { | 90 | } else { |
| 82 | return map_it->second->GetHandle(); | 91 | return {map_it->second->GetHandle(), map_it->second->GetEntries()}; |
| 83 | } | 92 | } |
| 84 | } | 93 | } |
| 85 | 94 | ||
| @@ -98,12 +107,18 @@ public: | |||
| 98 | pipeline.Create(); | 107 | pipeline.Create(); |
| 99 | } | 108 | } |
| 100 | 109 | ||
| 101 | void UseProgrammableVertexShader(const MaxwellVSConfig& config, const ShaderSetup setup) { | 110 | ShaderEntries UseProgrammableVertexShader(const MaxwellVSConfig& config, |
| 102 | current.vs = vertex_shaders.Get(config, setup); | 111 | const ShaderSetup setup) { |
| 112 | ShaderEntries result; | ||
| 113 | std::tie(current.vs, result) = vertex_shaders.Get(config, setup); | ||
| 114 | return result; | ||
| 103 | } | 115 | } |
| 104 | 116 | ||
| 105 | void UseProgrammableFragmentShader(const MaxwellFSConfig& config, const ShaderSetup setup) { | 117 | ShaderEntries UseProgrammableFragmentShader(const MaxwellFSConfig& config, |
| 106 | current.fs = fragment_shaders.Get(config, setup); | 118 | const ShaderSetup setup) { |
| 119 | ShaderEntries result; | ||
| 120 | std::tie(current.fs, result) = fragment_shaders.Get(config, setup); | ||
| 121 | return result; | ||
| 107 | } | 122 | } |
| 108 | 123 | ||
| 109 | void UseTrivialGeometryShader() { | 124 | void UseTrivialGeometryShader() { |