summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2018-04-15 03:32:12 -0400
committerGravatar bunnei2018-04-15 11:50:10 -0400
commit73d9c494ea6ae0a8076f679506ff07e2fe014826 (patch)
treef283b7d9b9014488dabd45e97f5687c2d67e842d /src
parentMerge pull request #328 from Subv/constbuffers (diff)
downloadyuzu-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.cpp40
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.h4
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp54
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h38
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h41
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
143private: 148private:
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
468private: 491private:
@@ -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
483std::string GetCommonDeclarations() { 507std::string GetCommonDeclarations() {
484 return "bool exec_shader();"; 508 return "bool exec_shader();";
485} 509}
486 510
487boost::optional<std::string> DecompileProgram(const ProgramCode& program_code, u32 main_offset, 511boost::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
18std::string GetCommonDeclarations(); 18std::string GetCommonDeclarations();
19 19
20boost::optional<std::string> DecompileProgram(const ProgramCode& program_code, u32 main_offset, 20boost::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
8namespace GLShader { 10namespace GLShader {
9 11
10std::string GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config) { 12using Tegra::Engines::Maxwell3D;
11 UNREACHABLE(); 13
12 return {}; 14static constexpr u32 PROGRAM_OFFSET{10};
15
16ProgramResult 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
26out gl_PerVertex {
27 vec4 gl_Position;
28};
29
30void main() {
31 exec_shader();
32}
33
34)";
35 out += program.first;
36 return {out, program.second};
37}
38
39ProgramResult 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
49out vec4 color;
50
51uniform sampler2D tex[32];
52
53void main() {
54 exec_shader();
13} 55}
14 56
15std::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
17using ProgramCode = std::array<u64, MAX_PROGRAM_CODE_LENGTH>; 19using ProgramCode = std::array<u64, MAX_PROGRAM_CODE_LENGTH>;
18 20
21class ConstBufferEntry {
22public:
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
41private:
42 bool is_used{};
43 unsigned index{};
44 unsigned max_offset{};
45};
46
47struct ShaderEntries {
48 std::vector<ConstBufferEntry> const_buffer_entries;
49};
50
51using ProgramResult = std::pair<std::string, ShaderEntries>;
52
19struct ShaderSetup { 53struct 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 */
61std::string GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config); 95ProgramResult 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 */
67std::string GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSConfig& config); 101ProgramResult 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 {
41public: 41public:
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
55private: 60private:
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.
63template <typename KeyConfigType, 69template <typename KeyConfigType,
64 std::string (*CodeGenerator)(const ShaderSetup&, const KeyConfigType&), GLenum ShaderType> 70 ProgramResult (*CodeGenerator)(const ShaderSetup&, const KeyConfigType&),
71 GLenum ShaderType>
65class ShaderCache { 72class ShaderCache {
66public: 73public:
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() {