summaryrefslogtreecommitdiffstats
path: root/src/video_core/renderer_opengl
diff options
context:
space:
mode:
Diffstat (limited to 'src/video_core/renderer_opengl')
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp42
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h28
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp20
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp8
-rw-r--r--src/video_core/renderer_opengl/gl_state.h1
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp1
6 files changed, 73 insertions, 27 deletions
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index d1def2f3b..822739088 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -46,14 +46,21 @@ void RasterizerOpenGL::InitObjects() {
state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
}
- // Generate VBO and VAO
+ // Generate VBO, VAO and UBO
vertex_buffer.Create();
vertex_array.Create();
+ uniform_buffer.Create();
state.draw.vertex_array = vertex_array.handle;
state.draw.vertex_buffer = vertex_buffer.handle;
+ state.draw.uniform_buffer = uniform_buffer.handle;
state.Apply();
+ // Bind the UBO to binding point 0
+ glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniform_buffer.handle);
+
+ uniform_block_data.dirty = true;
+
// Set vertex attributes
glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position));
glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION);
@@ -148,6 +155,11 @@ void RasterizerOpenGL::DrawTriangles() {
state.draw.shader_dirty = false;
}
+ if (uniform_block_data.dirty) {
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), &uniform_block_data.data, GL_STATIC_DRAW);
+ uniform_block_data.dirty = false;
+ }
+
glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW);
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size());
@@ -480,11 +492,17 @@ void RasterizerOpenGL::SetShader() {
state.Apply();
// Set the texture samplers to correspond to different texture units
- glUniform1i(PicaShader::Uniform::Texture0, 0);
- glUniform1i(PicaShader::Uniform::Texture1, 1);
- glUniform1i(PicaShader::Uniform::Texture2, 2);
+ GLuint uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[0]");
+ if (uniform_tex != -1) { glUniform1i(uniform_tex, 0); }
+ uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[1]");
+ if (uniform_tex != -1) { glUniform1i(uniform_tex, 1); }
+ uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]");
+ if (uniform_tex != -1) { glUniform1i(uniform_tex, 2); }
current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get();
+
+ unsigned int block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data");
+ glUniformBlockBinding(current_shader->shader.handle, block_index, 0);
}
// Update uniforms
@@ -615,7 +633,10 @@ void RasterizerOpenGL::SyncBlendColor() {
void RasterizerOpenGL::SyncAlphaTest() {
const auto& regs = Pica::g_state.regs;
- glUniform1i(PicaShader::Uniform::AlphaTestRef, regs.output_merger.alpha_test.ref);
+ if (regs.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) {
+ uniform_block_data.data.alphatest_ref = regs.output_merger.alpha_test.ref;
+ uniform_block_data.dirty = true;
+ }
}
void RasterizerOpenGL::SyncLogicOp() {
@@ -647,12 +668,18 @@ void RasterizerOpenGL::SyncDepthTest() {
void RasterizerOpenGL::SyncCombinerColor() {
auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw);
- glUniform4fv(PicaShader::Uniform::TevCombinerBufferColor, 1, combiner_color.data());
+ if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) {
+ uniform_block_data.data.tev_combiner_buffer_color = combiner_color;
+ uniform_block_data.dirty = true;
+ }
}
void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevStageConfig& tev_stage) {
auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color);
- glUniform4fv(PicaShader::Uniform::TevConstColors + stage_index, 1, const_color.data());
+ if (const_color != uniform_block_data.data.const_color[stage_index]) {
+ uniform_block_data.data.const_color[stage_index] = const_color;
+ uniform_block_data.dirty = true;
+ }
}
void RasterizerOpenGL::SyncDrawState() {
@@ -683,6 +710,7 @@ void RasterizerOpenGL::SyncDrawState() {
}
}
+ state.draw.uniform_buffer = uniform_buffer.handle;
state.Apply();
}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 872cae7da..5ba898189 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -138,16 +138,6 @@ public:
struct PicaShader {
/// OpenGL shader resource
OGLShader shader;
-
- /// Fragment shader uniforms
- enum Uniform : GLuint {
- AlphaTestRef = 0,
- TevConstColors = 1,
- Texture0 = 7,
- Texture1 = 8,
- Texture2 = 9,
- TevCombinerBufferColor = 10,
- };
};
private:
@@ -216,6 +206,18 @@ private:
GLfloat tex_coord2[2];
};
+ /// Uniform structure for the Uniform Buffer Object, all members must be 16-byte aligned
+ struct UniformData {
+ // A vec4 color for each of the six tev stages
+ std::array<GLfloat, 4> const_color[6];
+ std::array<GLfloat, 4> tev_combiner_buffer_color;
+ GLint alphatest_ref;
+ INSERT_PADDING_BYTES(12);
+ };
+
+ static_assert(sizeof(UniformData) == 0x80, "The size of the UniformData structure has changed, update the structure in the shader");
+ static_assert(sizeof(UniformData) < 16000, "UniformData structure must be less than 16kb as per the OpenGL spec");
+
/// Reconfigure the OpenGL color texture to use the given format and dimensions
void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height);
@@ -298,7 +300,13 @@ private:
std::unordered_map<PicaShaderConfig, std::unique_ptr<PicaShader>> shader_cache;
const PicaShader* current_shader = nullptr;
+ struct {
+ UniformData data;
+ bool dirty;
+ } uniform_block_data;
+
OGLVertexArray vertex_array;
OGLBuffer vertex_buffer;
+ OGLBuffer uniform_buffer;
OGLFramebuffer framebuffer;
};
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index d19d15e75..5268340cf 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -320,23 +320,23 @@ static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsi
std::string GenerateFragmentShader(const PicaShaderConfig& config) {
std::string out = R"(
-#version 330
-#extension GL_ARB_explicit_uniform_location : require
-
+#version 330 core
#define NUM_TEV_STAGES 6
in vec4 primary_color;
in vec2 texcoord[3];
out vec4 color;
-)";
- using Uniform = RasterizerOpenGL::PicaShader::Uniform;
- out += "layout(location = " + std::to_string((int)Uniform::AlphaTestRef) + ") uniform int alphatest_ref;\n";
- out += "layout(location = " + std::to_string((int)Uniform::TevConstColors) + ") uniform vec4 const_color[NUM_TEV_STAGES];\n";
- out += "layout(location = " + std::to_string((int)Uniform::Texture0) + ") uniform sampler2D tex[3];\n";
- out += "layout(location = " + std::to_string((int)Uniform::TevCombinerBufferColor) + ") uniform vec4 tev_combiner_buffer_color;\n";
+layout (std140) uniform shader_data {
+ vec4 const_color[NUM_TEV_STAGES];
+ vec4 tev_combiner_buffer_color;
+ int alphatest_ref;
+};
+
+)";
+ out += "uniform sampler2D tex[3];\n";
out += "void main() {\n";
out += "vec4 combiner_buffer = tev_combiner_buffer_color;\n";
out += "vec4 last_tex_env_out = vec4(0.0);\n";
@@ -362,7 +362,7 @@ out vec4 color;
}
std::string GenerateVertexShader() {
- std::string out = "#version 330\n";
+ std::string out = "#version 330 core\n";
out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + ") in vec4 vert_position;\n";
out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n";
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + ") in vec2 vert_texcoord0;\n";
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 77b2816cb..c44497fc3 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -180,6 +180,11 @@ void OpenGLState::Apply() {
glBindBuffer(GL_ARRAY_BUFFER, draw.vertex_buffer);
}
+ // Uniform buffer
+ if (draw.uniform_buffer != cur_state.draw.uniform_buffer) {
+ glBindBuffer(GL_UNIFORM_BUFFER, draw.uniform_buffer);
+ }
+
// Shader program
if (draw.shader_program != cur_state.draw.shader_program) {
glUseProgram(draw.shader_program);
@@ -214,6 +219,9 @@ void OpenGLState::ResetBuffer(GLuint id) {
if (cur_state.draw.vertex_buffer == id) {
cur_state.draw.vertex_buffer = 0;
}
+ if (cur_state.draw.uniform_buffer == id) {
+ cur_state.draw.uniform_buffer = 0;
+ }
}
void OpenGLState::ResetVertexArray(GLuint id) {
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 668b04259..84b3d49bc 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -64,6 +64,7 @@ public:
GLuint framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING
GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING
GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING
+ GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING
GLuint shader_program; // GL_CURRENT_PROGRAM
bool shader_dirty;
} draw;
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index ac0a058db..1420229cc 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -256,6 +256,7 @@ void RendererOpenGL::InitOpenGLObjects() {
state.draw.vertex_array = vertex_array_handle;
state.draw.vertex_buffer = vertex_buffer_handle;
+ state.draw.uniform_buffer = 0;
state.Apply();
// Attach vertex data to VAO