Merge pull request #1237 from Subv/ubos
Shaders: Use UBOs instead of individual uniforms in the generated frag shaders
This commit is contained in:
commit
ac829f87e0
|
@ -46,14 +46,21 @@ void RasterizerOpenGL::InitObjects() {
|
||||||
state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
|
state.texture_units[i].sampler = texture_samplers[i].sampler.handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate VBO and VAO
|
// Generate VBO, VAO and UBO
|
||||||
vertex_buffer.Create();
|
vertex_buffer.Create();
|
||||||
vertex_array.Create();
|
vertex_array.Create();
|
||||||
|
uniform_buffer.Create();
|
||||||
|
|
||||||
state.draw.vertex_array = vertex_array.handle;
|
state.draw.vertex_array = vertex_array.handle;
|
||||||
state.draw.vertex_buffer = vertex_buffer.handle;
|
state.draw.vertex_buffer = vertex_buffer.handle;
|
||||||
|
state.draw.uniform_buffer = uniform_buffer.handle;
|
||||||
state.Apply();
|
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
|
// Set vertex attributes
|
||||||
glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position));
|
glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position));
|
||||||
glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION);
|
glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION);
|
||||||
|
@ -148,6 +155,11 @@ void RasterizerOpenGL::DrawTriangles() {
|
||||||
state.draw.shader_dirty = false;
|
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);
|
glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW);
|
||||||
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size());
|
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size());
|
||||||
|
|
||||||
|
@ -485,6 +497,9 @@ void RasterizerOpenGL::SetShader() {
|
||||||
glUniform1i(PicaShader::Uniform::Texture2, 2);
|
glUniform1i(PicaShader::Uniform::Texture2, 2);
|
||||||
|
|
||||||
current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get();
|
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
|
// Update uniforms
|
||||||
|
@ -615,7 +630,10 @@ void RasterizerOpenGL::SyncBlendColor() {
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncAlphaTest() {
|
void RasterizerOpenGL::SyncAlphaTest() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
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() {
|
void RasterizerOpenGL::SyncLogicOp() {
|
||||||
|
@ -647,12 +665,18 @@ void RasterizerOpenGL::SyncDepthTest() {
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncCombinerColor() {
|
void RasterizerOpenGL::SyncCombinerColor() {
|
||||||
auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw);
|
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) {
|
void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevStageConfig& tev_stage) {
|
||||||
auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color);
|
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() {
|
void RasterizerOpenGL::SyncDrawState() {
|
||||||
|
@ -683,6 +707,7 @@ void RasterizerOpenGL::SyncDrawState() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
state.draw.uniform_buffer = uniform_buffer.handle;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,12 +141,9 @@ public:
|
||||||
|
|
||||||
/// Fragment shader uniforms
|
/// Fragment shader uniforms
|
||||||
enum Uniform : GLuint {
|
enum Uniform : GLuint {
|
||||||
AlphaTestRef = 0,
|
Texture0 = 0,
|
||||||
TevConstColors = 1,
|
Texture1 = 1,
|
||||||
Texture0 = 7,
|
Texture2 = 2,
|
||||||
Texture1 = 8,
|
|
||||||
Texture2 = 9,
|
|
||||||
TevCombinerBufferColor = 10,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -216,6 +213,18 @@ private:
|
||||||
GLfloat tex_coord2[2];
|
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
|
/// Reconfigure the OpenGL color texture to use the given format and dimensions
|
||||||
void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height);
|
void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height);
|
||||||
|
|
||||||
|
@ -298,7 +307,13 @@ private:
|
||||||
std::unordered_map<PicaShaderConfig, std::unique_ptr<PicaShader>> shader_cache;
|
std::unordered_map<PicaShaderConfig, std::unique_ptr<PicaShader>> shader_cache;
|
||||||
const PicaShader* current_shader = nullptr;
|
const PicaShader* current_shader = nullptr;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
UniformData data;
|
||||||
|
bool dirty;
|
||||||
|
} uniform_block_data;
|
||||||
|
|
||||||
OGLVertexArray vertex_array;
|
OGLVertexArray vertex_array;
|
||||||
OGLBuffer vertex_buffer;
|
OGLBuffer vertex_buffer;
|
||||||
|
OGLBuffer uniform_buffer;
|
||||||
OGLFramebuffer framebuffer;
|
OGLFramebuffer framebuffer;
|
||||||
};
|
};
|
||||||
|
|
|
@ -329,13 +329,17 @@ in vec4 primary_color;
|
||||||
in vec2 texcoord[3];
|
in vec2 texcoord[3];
|
||||||
|
|
||||||
out vec4 color;
|
out vec4 color;
|
||||||
|
|
||||||
|
layout (std140) uniform shader_data {
|
||||||
|
vec4 const_color[NUM_TEV_STAGES];
|
||||||
|
vec4 tev_combiner_buffer_color;
|
||||||
|
int alphatest_ref;
|
||||||
|
};
|
||||||
|
|
||||||
)";
|
)";
|
||||||
|
|
||||||
using Uniform = RasterizerOpenGL::PicaShader::Uniform;
|
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::Texture0) + ") uniform sampler2D tex[3];\n";
|
||||||
out += "layout(location = " + std::to_string((int)Uniform::TevCombinerBufferColor) + ") uniform vec4 tev_combiner_buffer_color;\n";
|
|
||||||
|
|
||||||
out += "void main() {\n";
|
out += "void main() {\n";
|
||||||
out += "vec4 combiner_buffer = tev_combiner_buffer_color;\n";
|
out += "vec4 combiner_buffer = tev_combiner_buffer_color;\n";
|
||||||
|
|
|
@ -180,6 +180,11 @@ void OpenGLState::Apply() {
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, draw.vertex_buffer);
|
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
|
// Shader program
|
||||||
if (draw.shader_program != cur_state.draw.shader_program) {
|
if (draw.shader_program != cur_state.draw.shader_program) {
|
||||||
glUseProgram(draw.shader_program);
|
glUseProgram(draw.shader_program);
|
||||||
|
@ -214,6 +219,9 @@ void OpenGLState::ResetBuffer(GLuint id) {
|
||||||
if (cur_state.draw.vertex_buffer == id) {
|
if (cur_state.draw.vertex_buffer == id) {
|
||||||
cur_state.draw.vertex_buffer = 0;
|
cur_state.draw.vertex_buffer = 0;
|
||||||
}
|
}
|
||||||
|
if (cur_state.draw.uniform_buffer == id) {
|
||||||
|
cur_state.draw.uniform_buffer = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLState::ResetVertexArray(GLuint id) {
|
void OpenGLState::ResetVertexArray(GLuint id) {
|
||||||
|
|
|
@ -64,6 +64,7 @@ public:
|
||||||
GLuint framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING
|
GLuint framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING
|
||||||
GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING
|
GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING
|
||||||
GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING
|
GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING
|
||||||
|
GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING
|
||||||
GLuint shader_program; // GL_CURRENT_PROGRAM
|
GLuint shader_program; // GL_CURRENT_PROGRAM
|
||||||
bool shader_dirty;
|
bool shader_dirty;
|
||||||
} draw;
|
} draw;
|
||||||
|
|
|
@ -256,6 +256,7 @@ void RendererOpenGL::InitOpenGLObjects() {
|
||||||
|
|
||||||
state.draw.vertex_array = vertex_array_handle;
|
state.draw.vertex_array = vertex_array_handle;
|
||||||
state.draw.vertex_buffer = vertex_buffer_handle;
|
state.draw.vertex_buffer = vertex_buffer_handle;
|
||||||
|
state.draw.uniform_buffer = 0;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
// Attach vertex data to VAO
|
// Attach vertex data to VAO
|
||||||
|
|
Reference in New Issue