summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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:
return declarations.GetResult() + shader.GetResult();
}
+ /// Returns entries in the shader that are useful for external functions
+ ShaderEntries GetEntries() const {
+ return {GetConstBuffersDeclarations()};
+ }
+
private:
/// Gets the Subroutine object corresponding to the specified address.
const Subroutine& GetSubroutine(u32 begin, u32 end) const {
@@ -186,10 +191,9 @@ private:
}
/// Generates code representing a uniform (C buffer) register.
- std::string GetUniform(const Uniform& reg) const {
- std::string index = std::to_string(reg.index);
- return "uniform_" + index + "[" + std::to_string(reg.offset >> 2) + "][" +
- std::to_string(reg.offset & 3) + "]";
+ std::string GetUniform(const Uniform& reg) {
+ declr_const_buffers[reg.index].MarkAsUsed(reg.index, reg.offset);
+ return 'c' + std::to_string(reg.index) + '[' + std::to_string(reg.offset) + ']';
}
/**
@@ -439,6 +443,14 @@ private:
GenerateDeclarations();
}
+ /// Returns a list of constant buffer declarations
+ std::vector<ConstBufferEntry> GetConstBuffersDeclarations() const {
+ std::vector<ConstBufferEntry> result;
+ std::copy_if(declr_const_buffers.begin(), declr_const_buffers.end(),
+ std::back_inserter(result), [](const auto& entry) { return entry.IsUsed(); });
+ return result;
+ }
+
/// Add declarations for registers
void GenerateDeclarations() {
for (const auto& reg : declr_register) {
@@ -463,6 +475,17 @@ private:
") out vec4 " + GetOutputAttribute(index) + ";");
}
declarations.AddLine("");
+
+ unsigned const_buffer_layout = 0;
+ for (const auto& entry : GetConstBuffersDeclarations()) {
+ declarations.AddLine("layout(std430, binding = " + std::to_string(const_buffer_layout) +
+ ") buffer c" + std::to_string(entry.GetIndex()) + "_buffer");
+ declarations.AddLine("{");
+ declarations.AddLine(" float c" + std::to_string(entry.GetIndex()) + "[];");
+ declarations.AddLine("};");
+ declarations.AddLine("");
+ ++const_buffer_layout;
+ }
}
private:
@@ -478,18 +501,19 @@ private:
std::set<std::string> declr_register;
std::set<Attribute::Index> declr_input_attribute;
std::set<Attribute::Index> declr_output_attribute;
-}; // namespace Decompiler
+ std::array<ConstBufferEntry, Maxwell3D::Regs::MaxConstBuffers> declr_const_buffers;
+};
std::string GetCommonDeclarations() {
return "bool exec_shader();";
}
-boost::optional<std::string> DecompileProgram(const ProgramCode& program_code, u32 main_offset,
- Maxwell3D::Regs::ShaderStage stage) {
+boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset,
+ Maxwell3D::Regs::ShaderStage stage) {
try {
auto subroutines = ControlFlowAnalyzer(program_code, main_offset).GetSubroutines();
GLSLGenerator generator(subroutines, program_code, main_offset, stage);
- return generator.GetShaderCode();
+ return ProgramResult{generator.GetShaderCode(), generator.GetEntries()};
} catch (const DecompileFail& exception) {
LOG_ERROR(HW_GPU, "Shader decompilation failed: %s", 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 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;
std::string GetCommonDeclarations();
-boost::optional<std::string> DecompileProgram(const ProgramCode& program_code, u32 main_offset,
- Maxwell3D::Regs::ShaderStage stage);
+boost::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u32 main_offset,
+ Maxwell3D::Regs::ShaderStage stage);
} // namespace Decompiler
} // 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 @@
// Refer to the license.txt file included.
#include "common/assert.h"
+#include "video_core/engines/maxwell_3d.h"
+#include "video_core/renderer_opengl/gl_shader_decompiler.h"
#include "video_core/renderer_opengl/gl_shader_gen.h"
namespace GLShader {
-std::string GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config) {
- UNREACHABLE();
- return {};
+using Tegra::Engines::Maxwell3D;
+
+static constexpr u32 PROGRAM_OFFSET{10};
+
+ProgramResult GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config) {
+ std::string out = "#version 430 core\n";
+ out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
+ out += Decompiler::GetCommonDeclarations();
+
+ ProgramResult program = Decompiler::DecompileProgram(setup.program_code, PROGRAM_OFFSET,
+ Maxwell3D::Regs::ShaderStage::Vertex)
+ .get_value_or({});
+ out += R"(
+
+out gl_PerVertex {
+ vec4 gl_Position;
+};
+
+void main() {
+ exec_shader();
+}
+
+)";
+ out += program.first;
+ return {out, program.second};
+}
+
+ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSConfig& config) {
+ std::string out = "#version 430 core\n";
+ out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
+ out += Decompiler::GetCommonDeclarations();
+
+ ProgramResult program = Decompiler::DecompileProgram(setup.program_code, PROGRAM_OFFSET,
+ Maxwell3D::Regs::ShaderStage::Fragment)
+ .get_value_or({});
+ out += R"(
+
+out vec4 color;
+
+uniform sampler2D tex[32];
+
+void main() {
+ exec_shader();
}
-std::string GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSConfig& config) {
- UNREACHABLE();
- return {};
+)";
+ out += program.first;
+ return {out, program.second};
}
} // 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 @@
#include <array>
#include <string>
#include <type_traits>
+#include <utility>
+#include <vector>
#include "common/common_types.h"
#include "common/hash.h"
@@ -16,6 +18,38 @@ constexpr size_t MAX_PROGRAM_CODE_LENGTH{0x1000};
using ProgramCode = std::array<u64, MAX_PROGRAM_CODE_LENGTH>;
+class ConstBufferEntry {
+public:
+ void MarkAsUsed(unsigned index, unsigned offset) {
+ is_used = true;
+ this->index = index;
+ max_offset = std::max(max_offset, offset);
+ }
+
+ bool IsUsed() const {
+ return is_used;
+ }
+
+ unsigned GetIndex() const {
+ return index;
+ }
+
+ unsigned GetSize() const {
+ return max_offset + 1;
+ }
+
+private:
+ bool is_used{};
+ unsigned index{};
+ unsigned max_offset{};
+};
+
+struct ShaderEntries {
+ std::vector<ConstBufferEntry> const_buffer_entries;
+};
+
+using ProgramResult = std::pair<std::string, ShaderEntries>;
+
struct ShaderSetup {
ShaderSetup(ProgramCode&& program_code) : program_code(std::move(program_code)) {}
@@ -58,13 +92,13 @@ struct MaxwellFSConfig : Common::HashableStruct<MaxwellShaderConfigCommon> {
* Generates the GLSL vertex shader program source code for the given VS program
* @returns String of the shader source code
*/
-std::string GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config);
+ProgramResult GenerateVertexShader(const ShaderSetup& setup, const MaxwellVSConfig& config);
/**
* Generates the GLSL fragment shader program source code for the given FS program
* @returns String of the shader source code
*/
-std::string GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSConfig& config);
+ProgramResult GenerateFragmentShader(const ShaderSetup& setup, const MaxwellFSConfig& config);
} // namespace GLShader
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 {
public:
OGLShaderStage() = default;
- void Create(const char* source, GLenum type) {
+ void Create(const ProgramResult& program_result, GLenum type) {
OGLShader shader;
- shader.Create(source, type);
+ shader.Create(program_result.first.c_str(), type);
program.Create(true, shader.handle);
Impl::SetShaderUniformBlockBindings(program.handle);
Impl::SetShaderSamplerBindings(program.handle);
+ entries = program_result.second;
}
GLuint GetHandle() const {
return program.handle;
}
+ ShaderEntries GetEntries() const {
+ return entries;
+ }
+
private:
OGLProgram program;
+ ShaderEntries entries;
};
// TODO(wwylele): beautify this doc
@@ -61,25 +67,28 @@ private:
// The double cache is needed because diffent KeyConfigType, which includes a hash of the code
// region (including its leftover unused code) can generate the same GLSL code.
template <typename KeyConfigType,
- std::string (*CodeGenerator)(const ShaderSetup&, const KeyConfigType&), GLenum ShaderType>
+ ProgramResult (*CodeGenerator)(const ShaderSetup&, const KeyConfigType&),
+ GLenum ShaderType>
class ShaderCache {
public:
ShaderCache() = default;
- GLuint Get(const KeyConfigType& key, const ShaderSetup& setup) {
+ using Result = std::pair<GLuint, ShaderEntries>;
+
+ Result Get(const KeyConfigType& key, const ShaderSetup& setup) {
auto map_it = shader_map.find(key);
if (map_it == shader_map.end()) {
- std::string program = CodeGenerator(setup, key);
+ ProgramResult program = CodeGenerator(setup, key);
- auto [iter, new_shader] = shader_cache.emplace(program, OGLShaderStage{});
+ auto [iter, new_shader] = shader_cache.emplace(program.first, OGLShaderStage{});
OGLShaderStage& cached_shader = iter->second;
if (new_shader) {
- cached_shader.Create(program.c_str(), ShaderType);
+ cached_shader.Create(program, ShaderType);
}
shader_map[key] = &cached_shader;
- return cached_shader.GetHandle();
+ return {cached_shader.GetHandle(), program.second};
} else {
- return map_it->second->GetHandle();
+ return {map_it->second->GetHandle(), map_it->second->GetEntries()};
}
}
@@ -98,12 +107,18 @@ public:
pipeline.Create();
}
- void UseProgrammableVertexShader(const MaxwellVSConfig& config, const ShaderSetup setup) {
- current.vs = vertex_shaders.Get(config, setup);
+ ShaderEntries UseProgrammableVertexShader(const MaxwellVSConfig& config,
+ const ShaderSetup setup) {
+ ShaderEntries result;
+ std::tie(current.vs, result) = vertex_shaders.Get(config, setup);
+ return result;
}
- void UseProgrammableFragmentShader(const MaxwellFSConfig& config, const ShaderSetup setup) {
- current.fs = fragment_shaders.Get(config, setup);
+ ShaderEntries UseProgrammableFragmentShader(const MaxwellFSConfig& config,
+ const ShaderSetup setup) {
+ ShaderEntries result;
+ std::tie(current.fs, result) = fragment_shaders.Get(config, setup);
+ return result;
}
void UseTrivialGeometryShader() {