Merge pull request #1187 from bunnei/shader-gen
GLSL Fragment Shader Generation
This commit is contained in:
commit
4195d9b3f8
|
@ -1,6 +1,7 @@
|
||||||
set(SRCS
|
set(SRCS
|
||||||
renderer_opengl/gl_rasterizer.cpp
|
renderer_opengl/gl_rasterizer.cpp
|
||||||
renderer_opengl/gl_rasterizer_cache.cpp
|
renderer_opengl/gl_rasterizer_cache.cpp
|
||||||
|
renderer_opengl/gl_shader_gen.cpp
|
||||||
renderer_opengl/gl_shader_util.cpp
|
renderer_opengl/gl_shader_util.cpp
|
||||||
renderer_opengl/gl_state.cpp
|
renderer_opengl/gl_state.cpp
|
||||||
renderer_opengl/renderer_opengl.cpp
|
renderer_opengl/renderer_opengl.cpp
|
||||||
|
@ -21,8 +22,8 @@ set(HEADERS
|
||||||
renderer_opengl/gl_rasterizer.h
|
renderer_opengl/gl_rasterizer.h
|
||||||
renderer_opengl/gl_rasterizer_cache.h
|
renderer_opengl/gl_rasterizer_cache.h
|
||||||
renderer_opengl/gl_resource_manager.h
|
renderer_opengl/gl_resource_manager.h
|
||||||
|
renderer_opengl/gl_shader_gen.h
|
||||||
renderer_opengl/gl_shader_util.h
|
renderer_opengl/gl_shader_util.h
|
||||||
renderer_opengl/gl_shaders.h
|
|
||||||
renderer_opengl/gl_state.h
|
renderer_opengl/gl_state.h
|
||||||
renderer_opengl/pica_to_gl.h
|
renderer_opengl/pica_to_gl.h
|
||||||
renderer_opengl/renderer_opengl.h
|
renderer_opengl/renderer_opengl.h
|
||||||
|
|
|
@ -317,6 +317,7 @@ struct Regs {
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
u32 sources_raw;
|
||||||
BitField< 0, 4, Source> color_source1;
|
BitField< 0, 4, Source> color_source1;
|
||||||
BitField< 4, 4, Source> color_source2;
|
BitField< 4, 4, Source> color_source2;
|
||||||
BitField< 8, 4, Source> color_source3;
|
BitField< 8, 4, Source> color_source3;
|
||||||
|
@ -326,6 +327,7 @@ struct Regs {
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
u32 modifiers_raw;
|
||||||
BitField< 0, 4, ColorModifier> color_modifier1;
|
BitField< 0, 4, ColorModifier> color_modifier1;
|
||||||
BitField< 4, 4, ColorModifier> color_modifier2;
|
BitField< 4, 4, ColorModifier> color_modifier2;
|
||||||
BitField< 8, 4, ColorModifier> color_modifier3;
|
BitField< 8, 4, ColorModifier> color_modifier3;
|
||||||
|
@ -335,6 +337,7 @@ struct Regs {
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
u32 ops_raw;
|
||||||
BitField< 0, 4, Operation> color_op;
|
BitField< 0, 4, Operation> color_op;
|
||||||
BitField<16, 4, Operation> alpha_op;
|
BitField<16, 4, Operation> alpha_op;
|
||||||
};
|
};
|
||||||
|
@ -348,6 +351,7 @@ struct Regs {
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
u32 scales_raw;
|
||||||
BitField< 0, 2, u32> color_scale;
|
BitField< 0, 2, u32> color_scale;
|
||||||
BitField<16, 2, u32> alpha_scale;
|
BitField<16, 2, u32> alpha_scale;
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
|
|
||||||
#include "common/color.h"
|
#include "common/color.h"
|
||||||
|
#include "common/file_util.h"
|
||||||
|
#include "common/make_unique.h"
|
||||||
#include "common/math_util.h"
|
#include "common/math_util.h"
|
||||||
#include "common/microprofile.h"
|
#include "common/microprofile.h"
|
||||||
#include "common/profiler.h"
|
#include "common/profiler.h"
|
||||||
|
@ -19,7 +21,7 @@
|
||||||
#include "video_core/pica.h"
|
#include "video_core/pica.h"
|
||||||
#include "video_core/utils.h"
|
#include "video_core/utils.h"
|
||||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||||
#include "video_core/renderer_opengl/gl_shaders.h"
|
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
||||||
#include "video_core/renderer_opengl/gl_shader_util.h"
|
#include "video_core/renderer_opengl/gl_shader_util.h"
|
||||||
#include "video_core/renderer_opengl/pica_to_gl.h"
|
#include "video_core/renderer_opengl/pica_to_gl.h"
|
||||||
|
|
||||||
|
@ -38,36 +40,6 @@ RasterizerOpenGL::RasterizerOpenGL() : last_fb_color_addr(0), last_fb_depth_addr
|
||||||
RasterizerOpenGL::~RasterizerOpenGL() { }
|
RasterizerOpenGL::~RasterizerOpenGL() { }
|
||||||
|
|
||||||
void RasterizerOpenGL::InitObjects() {
|
void RasterizerOpenGL::InitObjects() {
|
||||||
// Create the hardware shader program and get attrib/uniform locations
|
|
||||||
shader.Create(GLShaders::g_vertex_shader_hw, GLShaders::g_fragment_shader_hw);
|
|
||||||
attrib_position = glGetAttribLocation(shader.handle, "vert_position");
|
|
||||||
attrib_color = glGetAttribLocation(shader.handle, "vert_color");
|
|
||||||
attrib_texcoords = glGetAttribLocation(shader.handle, "vert_texcoords");
|
|
||||||
|
|
||||||
uniform_alphatest_enabled = glGetUniformLocation(shader.handle, "alphatest_enabled");
|
|
||||||
uniform_alphatest_func = glGetUniformLocation(shader.handle, "alphatest_func");
|
|
||||||
uniform_alphatest_ref = glGetUniformLocation(shader.handle, "alphatest_ref");
|
|
||||||
|
|
||||||
uniform_tex = glGetUniformLocation(shader.handle, "tex");
|
|
||||||
|
|
||||||
uniform_tev_combiner_buffer_color = glGetUniformLocation(shader.handle, "tev_combiner_buffer_color");
|
|
||||||
|
|
||||||
const auto tev_stages = Pica::g_state.regs.GetTevStages();
|
|
||||||
for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) {
|
|
||||||
auto& uniform_tev_cfg = uniform_tev_cfgs[tev_stage_index];
|
|
||||||
|
|
||||||
std::string tev_ref_str = "tev_cfgs[" + std::to_string(tev_stage_index) + "]";
|
|
||||||
uniform_tev_cfg.enabled = glGetUniformLocation(shader.handle, (tev_ref_str + ".enabled").c_str());
|
|
||||||
uniform_tev_cfg.color_sources = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_sources").c_str());
|
|
||||||
uniform_tev_cfg.alpha_sources = glGetUniformLocation(shader.handle, (tev_ref_str + ".alpha_sources").c_str());
|
|
||||||
uniform_tev_cfg.color_modifiers = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_modifiers").c_str());
|
|
||||||
uniform_tev_cfg.alpha_modifiers = glGetUniformLocation(shader.handle, (tev_ref_str + ".alpha_modifiers").c_str());
|
|
||||||
uniform_tev_cfg.color_alpha_op = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_alpha_op").c_str());
|
|
||||||
uniform_tev_cfg.color_alpha_multiplier = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_alpha_multiplier").c_str());
|
|
||||||
uniform_tev_cfg.const_color = glGetUniformLocation(shader.handle, (tev_ref_str + ".const_color").c_str());
|
|
||||||
uniform_tev_cfg.updates_combiner_buffer_color_alpha = glGetUniformLocation(shader.handle, (tev_ref_str + ".updates_combiner_buffer_color_alpha").c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create sampler objects
|
// Create sampler objects
|
||||||
for (size_t i = 0; i < texture_samplers.size(); ++i) {
|
for (size_t i = 0; i < texture_samplers.size(); ++i) {
|
||||||
texture_samplers[i].Create();
|
texture_samplers[i].Create();
|
||||||
|
@ -78,29 +50,25 @@ void RasterizerOpenGL::InitObjects() {
|
||||||
vertex_buffer.Create();
|
vertex_buffer.Create();
|
||||||
vertex_array.Create();
|
vertex_array.Create();
|
||||||
|
|
||||||
// Update OpenGL state
|
|
||||||
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.shader_program = shader.handle;
|
|
||||||
|
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
||||||
// Set the texture samplers to correspond to different texture units
|
|
||||||
glUniform1i(uniform_tex, 0);
|
|
||||||
glUniform1i(uniform_tex + 1, 1);
|
|
||||||
glUniform1i(uniform_tex + 2, 2);
|
|
||||||
|
|
||||||
// Set vertex attributes
|
// Set vertex attributes
|
||||||
glVertexAttribPointer(attrib_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));
|
||||||
glVertexAttribPointer(attrib_color, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color));
|
glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION);
|
||||||
glVertexAttribPointer(attrib_texcoords, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0));
|
|
||||||
glVertexAttribPointer(attrib_texcoords + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1));
|
glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color));
|
||||||
glVertexAttribPointer(attrib_texcoords + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2));
|
glEnableVertexAttribArray(GLShader::ATTRIBUTE_COLOR);
|
||||||
glEnableVertexAttribArray(attrib_position);
|
|
||||||
glEnableVertexAttribArray(attrib_color);
|
glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0));
|
||||||
glEnableVertexAttribArray(attrib_texcoords);
|
glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1));
|
||||||
glEnableVertexAttribArray(attrib_texcoords + 1);
|
glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2));
|
||||||
glEnableVertexAttribArray(attrib_texcoords + 2);
|
glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0);
|
||||||
|
glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD1);
|
||||||
|
glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD2);
|
||||||
|
|
||||||
|
SetShader();
|
||||||
|
|
||||||
// Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation
|
// Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation
|
||||||
fb_color_texture.texture.Create();
|
fb_color_texture.texture.Create();
|
||||||
|
@ -150,61 +118,15 @@ void RasterizerOpenGL::InitObjects() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::Reset() {
|
void RasterizerOpenGL::Reset() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
|
||||||
|
|
||||||
SyncCullMode();
|
SyncCullMode();
|
||||||
SyncBlendEnabled();
|
SyncBlendEnabled();
|
||||||
SyncBlendFuncs();
|
SyncBlendFuncs();
|
||||||
SyncBlendColor();
|
SyncBlendColor();
|
||||||
SyncAlphaTest();
|
|
||||||
SyncLogicOp();
|
SyncLogicOp();
|
||||||
SyncStencilTest();
|
SyncStencilTest();
|
||||||
SyncDepthTest();
|
SyncDepthTest();
|
||||||
|
|
||||||
// TEV stage 0
|
SetShader();
|
||||||
SyncTevSources(0, regs.tev_stage0);
|
|
||||||
SyncTevModifiers(0, regs.tev_stage0);
|
|
||||||
SyncTevOps(0, regs.tev_stage0);
|
|
||||||
SyncTevColor(0, regs.tev_stage0);
|
|
||||||
SyncTevMultipliers(0, regs.tev_stage0);
|
|
||||||
|
|
||||||
// TEV stage 1
|
|
||||||
SyncTevSources(1, regs.tev_stage1);
|
|
||||||
SyncTevModifiers(1, regs.tev_stage1);
|
|
||||||
SyncTevOps(1, regs.tev_stage1);
|
|
||||||
SyncTevColor(1, regs.tev_stage1);
|
|
||||||
SyncTevMultipliers(1, regs.tev_stage1);
|
|
||||||
|
|
||||||
// TEV stage 2
|
|
||||||
SyncTevSources(2, regs.tev_stage2);
|
|
||||||
SyncTevModifiers(2, regs.tev_stage2);
|
|
||||||
SyncTevOps(2, regs.tev_stage2);
|
|
||||||
SyncTevColor(2, regs.tev_stage2);
|
|
||||||
SyncTevMultipliers(2, regs.tev_stage2);
|
|
||||||
|
|
||||||
// TEV stage 3
|
|
||||||
SyncTevSources(3, regs.tev_stage3);
|
|
||||||
SyncTevModifiers(3, regs.tev_stage3);
|
|
||||||
SyncTevOps(3, regs.tev_stage3);
|
|
||||||
SyncTevColor(3, regs.tev_stage3);
|
|
||||||
SyncTevMultipliers(3, regs.tev_stage3);
|
|
||||||
|
|
||||||
// TEV stage 4
|
|
||||||
SyncTevSources(4, regs.tev_stage4);
|
|
||||||
SyncTevModifiers(4, regs.tev_stage4);
|
|
||||||
SyncTevOps(4, regs.tev_stage4);
|
|
||||||
SyncTevColor(4, regs.tev_stage4);
|
|
||||||
SyncTevMultipliers(4, regs.tev_stage4);
|
|
||||||
|
|
||||||
// TEV stage 5
|
|
||||||
SyncTevSources(5, regs.tev_stage5);
|
|
||||||
SyncTevModifiers(5, regs.tev_stage5);
|
|
||||||
SyncTevOps(5, regs.tev_stage5);
|
|
||||||
SyncTevColor(5, regs.tev_stage5);
|
|
||||||
SyncTevMultipliers(5, regs.tev_stage5);
|
|
||||||
|
|
||||||
SyncCombinerColor();
|
|
||||||
SyncCombinerWriteFlags();
|
|
||||||
|
|
||||||
res_cache.FullFlush();
|
res_cache.FullFlush();
|
||||||
}
|
}
|
||||||
|
@ -221,6 +143,11 @@ void RasterizerOpenGL::DrawTriangles() {
|
||||||
SyncFramebuffer();
|
SyncFramebuffer();
|
||||||
SyncDrawState();
|
SyncDrawState();
|
||||||
|
|
||||||
|
if (state.draw.shader_dirty) {
|
||||||
|
SetShader();
|
||||||
|
state.draw.shader_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());
|
||||||
|
|
||||||
|
@ -272,6 +199,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
|
||||||
// Alpha test
|
// Alpha test
|
||||||
case PICA_REG_INDEX(output_merger.alpha_test):
|
case PICA_REG_INDEX(output_merger.alpha_test):
|
||||||
SyncAlphaTest();
|
SyncAlphaTest();
|
||||||
|
state.draw.shader_dirty = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Stencil test
|
// Stencil test
|
||||||
|
@ -290,117 +218,57 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
|
||||||
SyncLogicOp();
|
SyncLogicOp();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TEV stage 0
|
// TEV stages
|
||||||
case PICA_REG_INDEX(tev_stage0.color_source1):
|
case PICA_REG_INDEX(tev_stage0.color_source1):
|
||||||
SyncTevSources(0, regs.tev_stage0);
|
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage0.color_modifier1):
|
case PICA_REG_INDEX(tev_stage0.color_modifier1):
|
||||||
SyncTevModifiers(0, regs.tev_stage0);
|
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage0.color_op):
|
case PICA_REG_INDEX(tev_stage0.color_op):
|
||||||
SyncTevOps(0, regs.tev_stage0);
|
case PICA_REG_INDEX(tev_stage0.color_scale):
|
||||||
|
case PICA_REG_INDEX(tev_stage1.color_source1):
|
||||||
|
case PICA_REG_INDEX(tev_stage1.color_modifier1):
|
||||||
|
case PICA_REG_INDEX(tev_stage1.color_op):
|
||||||
|
case PICA_REG_INDEX(tev_stage1.color_scale):
|
||||||
|
case PICA_REG_INDEX(tev_stage2.color_source1):
|
||||||
|
case PICA_REG_INDEX(tev_stage2.color_modifier1):
|
||||||
|
case PICA_REG_INDEX(tev_stage2.color_op):
|
||||||
|
case PICA_REG_INDEX(tev_stage2.color_scale):
|
||||||
|
case PICA_REG_INDEX(tev_stage3.color_source1):
|
||||||
|
case PICA_REG_INDEX(tev_stage3.color_modifier1):
|
||||||
|
case PICA_REG_INDEX(tev_stage3.color_op):
|
||||||
|
case PICA_REG_INDEX(tev_stage3.color_scale):
|
||||||
|
case PICA_REG_INDEX(tev_stage4.color_source1):
|
||||||
|
case PICA_REG_INDEX(tev_stage4.color_modifier1):
|
||||||
|
case PICA_REG_INDEX(tev_stage4.color_op):
|
||||||
|
case PICA_REG_INDEX(tev_stage4.color_scale):
|
||||||
|
case PICA_REG_INDEX(tev_stage5.color_source1):
|
||||||
|
case PICA_REG_INDEX(tev_stage5.color_modifier1):
|
||||||
|
case PICA_REG_INDEX(tev_stage5.color_op):
|
||||||
|
case PICA_REG_INDEX(tev_stage5.color_scale):
|
||||||
|
case PICA_REG_INDEX(tev_combiner_buffer_input):
|
||||||
|
state.draw.shader_dirty = true;
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage0.const_r):
|
case PICA_REG_INDEX(tev_stage0.const_r):
|
||||||
SyncTevColor(0, regs.tev_stage0);
|
SyncTevConstColor(0, regs.tev_stage0);
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage0.color_scale):
|
|
||||||
SyncTevMultipliers(0, regs.tev_stage0);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// TEV stage 1
|
|
||||||
case PICA_REG_INDEX(tev_stage1.color_source1):
|
|
||||||
SyncTevSources(1, regs.tev_stage1);
|
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage1.color_modifier1):
|
|
||||||
SyncTevModifiers(1, regs.tev_stage1);
|
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage1.color_op):
|
|
||||||
SyncTevOps(1, regs.tev_stage1);
|
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage1.const_r):
|
case PICA_REG_INDEX(tev_stage1.const_r):
|
||||||
SyncTevColor(1, regs.tev_stage1);
|
SyncTevConstColor(1, regs.tev_stage1);
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage1.color_scale):
|
|
||||||
SyncTevMultipliers(1, regs.tev_stage1);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// TEV stage 2
|
|
||||||
case PICA_REG_INDEX(tev_stage2.color_source1):
|
|
||||||
SyncTevSources(2, regs.tev_stage2);
|
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage2.color_modifier1):
|
|
||||||
SyncTevModifiers(2, regs.tev_stage2);
|
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage2.color_op):
|
|
||||||
SyncTevOps(2, regs.tev_stage2);
|
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage2.const_r):
|
case PICA_REG_INDEX(tev_stage2.const_r):
|
||||||
SyncTevColor(2, regs.tev_stage2);
|
SyncTevConstColor(2, regs.tev_stage2);
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage2.color_scale):
|
|
||||||
SyncTevMultipliers(2, regs.tev_stage2);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// TEV stage 3
|
|
||||||
case PICA_REG_INDEX(tev_stage3.color_source1):
|
|
||||||
SyncTevSources(3, regs.tev_stage3);
|
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage3.color_modifier1):
|
|
||||||
SyncTevModifiers(3, regs.tev_stage3);
|
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage3.color_op):
|
|
||||||
SyncTevOps(3, regs.tev_stage3);
|
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage3.const_r):
|
case PICA_REG_INDEX(tev_stage3.const_r):
|
||||||
SyncTevColor(3, regs.tev_stage3);
|
SyncTevConstColor(3, regs.tev_stage3);
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage3.color_scale):
|
|
||||||
SyncTevMultipliers(3, regs.tev_stage3);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// TEV stage 4
|
|
||||||
case PICA_REG_INDEX(tev_stage4.color_source1):
|
|
||||||
SyncTevSources(4, regs.tev_stage4);
|
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage4.color_modifier1):
|
|
||||||
SyncTevModifiers(4, regs.tev_stage4);
|
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage4.color_op):
|
|
||||||
SyncTevOps(4, regs.tev_stage4);
|
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage4.const_r):
|
case PICA_REG_INDEX(tev_stage4.const_r):
|
||||||
SyncTevColor(4, regs.tev_stage4);
|
SyncTevConstColor(4, regs.tev_stage4);
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage4.color_scale):
|
|
||||||
SyncTevMultipliers(4, regs.tev_stage4);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// TEV stage 5
|
|
||||||
case PICA_REG_INDEX(tev_stage5.color_source1):
|
|
||||||
SyncTevSources(5, regs.tev_stage5);
|
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage5.color_modifier1):
|
|
||||||
SyncTevModifiers(5, regs.tev_stage5);
|
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage5.color_op):
|
|
||||||
SyncTevOps(5, regs.tev_stage5);
|
|
||||||
break;
|
break;
|
||||||
case PICA_REG_INDEX(tev_stage5.const_r):
|
case PICA_REG_INDEX(tev_stage5.const_r):
|
||||||
SyncTevColor(5, regs.tev_stage5);
|
SyncTevConstColor(5, regs.tev_stage5);
|
||||||
break;
|
|
||||||
case PICA_REG_INDEX(tev_stage5.color_scale):
|
|
||||||
SyncTevMultipliers(5, regs.tev_stage5);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TEV combiner buffer color
|
// TEV combiner buffer color
|
||||||
case PICA_REG_INDEX(tev_combiner_buffer_color):
|
case PICA_REG_INDEX(tev_combiner_buffer_color):
|
||||||
SyncCombinerColor();
|
SyncCombinerColor();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// TEV combiner buffer write flags
|
|
||||||
case PICA_REG_INDEX(tev_combiner_buffer_input):
|
|
||||||
SyncCombinerWriteFlags();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -592,6 +460,41 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::
|
||||||
state.Apply();
|
state.Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RasterizerOpenGL::SetShader() {
|
||||||
|
PicaShaderConfig config = PicaShaderConfig::CurrentConfig();
|
||||||
|
std::unique_ptr<PicaShader> shader = Common::make_unique<PicaShader>();
|
||||||
|
|
||||||
|
// Find (or generate) the GLSL shader for the current TEV state
|
||||||
|
auto cached_shader = shader_cache.find(config);
|
||||||
|
if (cached_shader != shader_cache.end()) {
|
||||||
|
current_shader = cached_shader->second.get();
|
||||||
|
|
||||||
|
state.draw.shader_program = current_shader->shader.handle;
|
||||||
|
state.Apply();
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG(Render_OpenGL, "Creating new shader");
|
||||||
|
|
||||||
|
shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str());
|
||||||
|
|
||||||
|
state.draw.shader_program = shader->shader.handle;
|
||||||
|
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);
|
||||||
|
|
||||||
|
current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update uniforms
|
||||||
|
SyncAlphaTest();
|
||||||
|
SyncCombinerColor();
|
||||||
|
auto& tev_stages = Pica::g_state.regs.GetTevStages();
|
||||||
|
for (int index = 0; index < tev_stages.size(); ++index)
|
||||||
|
SyncTevConstColor(index, tev_stages[index]);
|
||||||
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncFramebuffer() {
|
void RasterizerOpenGL::SyncFramebuffer() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
|
|
||||||
|
@ -712,9 +615,7 @@ void RasterizerOpenGL::SyncBlendColor() {
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncAlphaTest() {
|
void RasterizerOpenGL::SyncAlphaTest() {
|
||||||
const auto& regs = Pica::g_state.regs;
|
const auto& regs = Pica::g_state.regs;
|
||||||
glUniform1i(uniform_alphatest_enabled, regs.output_merger.alpha_test.enable);
|
glUniform1i(PicaShader::Uniform::AlphaTestRef, regs.output_merger.alpha_test.ref);
|
||||||
glUniform1i(uniform_alphatest_func, (GLint)regs.output_merger.alpha_test.func.Value());
|
|
||||||
glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncLogicOp() {
|
void RasterizerOpenGL::SyncLogicOp() {
|
||||||
|
@ -744,56 +645,14 @@ void RasterizerOpenGL::SyncDepthTest() {
|
||||||
state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE;
|
state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncTevSources(unsigned stage_index, const Pica::Regs::TevStageConfig& config) {
|
|
||||||
GLint color_srcs[3] = { (GLint)config.color_source1.Value(),
|
|
||||||
(GLint)config.color_source2.Value(),
|
|
||||||
(GLint)config.color_source3.Value() };
|
|
||||||
GLint alpha_srcs[3] = { (GLint)config.alpha_source1.Value(),
|
|
||||||
(GLint)config.alpha_source2.Value(),
|
|
||||||
(GLint)config.alpha_source3.Value() };
|
|
||||||
|
|
||||||
glUniform3iv(uniform_tev_cfgs[stage_index].color_sources, 1, color_srcs);
|
|
||||||
glUniform3iv(uniform_tev_cfgs[stage_index].alpha_sources, 1, alpha_srcs);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncTevModifiers(unsigned stage_index, const Pica::Regs::TevStageConfig& config) {
|
|
||||||
GLint color_mods[3] = { (GLint)config.color_modifier1.Value(),
|
|
||||||
(GLint)config.color_modifier2.Value(),
|
|
||||||
(GLint)config.color_modifier3.Value() };
|
|
||||||
GLint alpha_mods[3] = { (GLint)config.alpha_modifier1.Value(),
|
|
||||||
(GLint)config.alpha_modifier2.Value(),
|
|
||||||
(GLint)config.alpha_modifier3.Value() };
|
|
||||||
|
|
||||||
glUniform3iv(uniform_tev_cfgs[stage_index].color_modifiers, 1, color_mods);
|
|
||||||
glUniform3iv(uniform_tev_cfgs[stage_index].alpha_modifiers, 1, alpha_mods);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncTevOps(unsigned stage_index, const Pica::Regs::TevStageConfig& config) {
|
|
||||||
glUniform2i(uniform_tev_cfgs[stage_index].color_alpha_op, (GLint)config.color_op.Value(), (GLint)config.alpha_op.Value());
|
|
||||||
}
|
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncTevColor(unsigned stage_index, const Pica::Regs::TevStageConfig& config) {
|
|
||||||
auto const_color = PicaToGL::ColorRGBA8(config.const_color);
|
|
||||||
glUniform4fv(uniform_tev_cfgs[stage_index].const_color, 1, const_color.data());
|
|
||||||
}
|
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncTevMultipliers(unsigned stage_index, const Pica::Regs::TevStageConfig& config) {
|
|
||||||
glUniform2i(uniform_tev_cfgs[stage_index].color_alpha_multiplier, config.GetColorMultiplier(), config.GetAlphaMultiplier());
|
|
||||||
}
|
|
||||||
|
|
||||||
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(uniform_tev_combiner_buffer_color, 1, combiner_color.data());
|
glUniform4fv(PicaShader::Uniform::TevCombinerBufferColor, 1, combiner_color.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncCombinerWriteFlags() {
|
void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevStageConfig& tev_stage) {
|
||||||
const auto& regs = Pica::g_state.regs;
|
auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color);
|
||||||
const auto tev_stages = regs.GetTevStages();
|
glUniform4fv(PicaShader::Uniform::TevConstColors + stage_index, 1, const_color.data());
|
||||||
for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) {
|
|
||||||
glUniform2i(uniform_tev_cfgs[tev_stage_index].updates_combiner_buffer_color_alpha,
|
|
||||||
regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index),
|
|
||||||
regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerOpenGL::SyncDrawState() {
|
void RasterizerOpenGL::SyncDrawState() {
|
||||||
|
@ -824,12 +683,6 @@ void RasterizerOpenGL::SyncDrawState() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip processing TEV stages that simply pass the previous stage results through
|
|
||||||
const auto tev_stages = regs.GetTevStages();
|
|
||||||
for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) {
|
|
||||||
glUniform1i(uniform_tev_cfgs[tev_stage_index].enabled, !IsPassThroughTevStage(tev_stages[tev_stage_index]));
|
|
||||||
}
|
|
||||||
|
|
||||||
state.Apply();
|
state.Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,104 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/hash.h"
|
||||||
|
|
||||||
|
#include "video_core/pica.h"
|
||||||
#include "video_core/hwrasterizer_base.h"
|
#include "video_core/hwrasterizer_base.h"
|
||||||
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
|
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_state.h"
|
#include "video_core/renderer_opengl/gl_state.h"
|
||||||
#include "video_core/shader/shader_interpreter.h"
|
#include "video_core/shader/shader_interpreter.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This struct contains all state used to generate the GLSL shader program that emulates the current
|
||||||
|
* Pica register configuration. This struct is used as a cache key for generated GLSL shader
|
||||||
|
* programs. The functions in gl_shader_gen.cpp should retrieve state from this struct only, not by
|
||||||
|
* directly accessing Pica registers. This should reduce the risk of bugs in shader generation where
|
||||||
|
* Pica state is not being captured in the shader cache key, thereby resulting in (what should be)
|
||||||
|
* two separate shaders sharing the same key.
|
||||||
|
*/
|
||||||
|
struct PicaShaderConfig {
|
||||||
|
/// Construct a PicaShaderConfig with the current Pica register configuration.
|
||||||
|
static PicaShaderConfig CurrentConfig() {
|
||||||
|
PicaShaderConfig res;
|
||||||
|
const auto& regs = Pica::g_state.regs;
|
||||||
|
|
||||||
|
res.alpha_test_func = regs.output_merger.alpha_test.enable ?
|
||||||
|
regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always;
|
||||||
|
|
||||||
|
// Copy relevant TevStageConfig fields only. We're doing this manually (instead of calling
|
||||||
|
// the GetTevStages() function) because BitField explicitly disables copies.
|
||||||
|
|
||||||
|
res.tev_stages[0].sources_raw = regs.tev_stage0.sources_raw;
|
||||||
|
res.tev_stages[1].sources_raw = regs.tev_stage1.sources_raw;
|
||||||
|
res.tev_stages[2].sources_raw = regs.tev_stage2.sources_raw;
|
||||||
|
res.tev_stages[3].sources_raw = regs.tev_stage3.sources_raw;
|
||||||
|
res.tev_stages[4].sources_raw = regs.tev_stage4.sources_raw;
|
||||||
|
res.tev_stages[5].sources_raw = regs.tev_stage5.sources_raw;
|
||||||
|
|
||||||
|
res.tev_stages[0].modifiers_raw = regs.tev_stage0.modifiers_raw;
|
||||||
|
res.tev_stages[1].modifiers_raw = regs.tev_stage1.modifiers_raw;
|
||||||
|
res.tev_stages[2].modifiers_raw = regs.tev_stage2.modifiers_raw;
|
||||||
|
res.tev_stages[3].modifiers_raw = regs.tev_stage3.modifiers_raw;
|
||||||
|
res.tev_stages[4].modifiers_raw = regs.tev_stage4.modifiers_raw;
|
||||||
|
res.tev_stages[5].modifiers_raw = regs.tev_stage5.modifiers_raw;
|
||||||
|
|
||||||
|
res.tev_stages[0].ops_raw = regs.tev_stage0.ops_raw;
|
||||||
|
res.tev_stages[1].ops_raw = regs.tev_stage1.ops_raw;
|
||||||
|
res.tev_stages[2].ops_raw = regs.tev_stage2.ops_raw;
|
||||||
|
res.tev_stages[3].ops_raw = regs.tev_stage3.ops_raw;
|
||||||
|
res.tev_stages[4].ops_raw = regs.tev_stage4.ops_raw;
|
||||||
|
res.tev_stages[5].ops_raw = regs.tev_stage5.ops_raw;
|
||||||
|
|
||||||
|
res.tev_stages[0].scales_raw = regs.tev_stage0.scales_raw;
|
||||||
|
res.tev_stages[1].scales_raw = regs.tev_stage1.scales_raw;
|
||||||
|
res.tev_stages[2].scales_raw = regs.tev_stage2.scales_raw;
|
||||||
|
res.tev_stages[3].scales_raw = regs.tev_stage3.scales_raw;
|
||||||
|
res.tev_stages[4].scales_raw = regs.tev_stage4.scales_raw;
|
||||||
|
res.tev_stages[5].scales_raw = regs.tev_stage5.scales_raw;
|
||||||
|
|
||||||
|
res.combiner_buffer_input =
|
||||||
|
regs.tev_combiner_buffer_input.update_mask_rgb.Value() |
|
||||||
|
regs.tev_combiner_buffer_input.update_mask_a.Value() << 4;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const {
|
||||||
|
return (stage_index < 4) && (combiner_buffer_input & (1 << stage_index));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const {
|
||||||
|
return (stage_index < 4) && ((combiner_buffer_input >> 4) & (1 << stage_index));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator ==(const PicaShaderConfig& o) const {
|
||||||
|
return std::memcmp(this, &o, sizeof(PicaShaderConfig)) == 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
Pica::Regs::CompareFunc alpha_test_func;
|
||||||
|
std::array<Pica::Regs::TevStageConfig, 6> tev_stages = {};
|
||||||
|
u8 combiner_buffer_input;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct hash<PicaShaderConfig> {
|
||||||
|
size_t operator()(const PicaShaderConfig& k) const {
|
||||||
|
return Common::ComputeHash64(&k, sizeof(PicaShaderConfig));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
class RasterizerOpenGL : public HWRasterizer {
|
class RasterizerOpenGL : public HWRasterizer {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -45,19 +134,23 @@ public:
|
||||||
/// Notify rasterizer that a 3DS memory region has been changed
|
/// Notify rasterizer that a 3DS memory region has been changed
|
||||||
void NotifyFlush(PAddr addr, u32 size) override;
|
void NotifyFlush(PAddr addr, u32 size) override;
|
||||||
|
|
||||||
private:
|
/// OpenGL shader generated for a given Pica register state
|
||||||
/// Structure used for managing texture environment states
|
struct PicaShader {
|
||||||
struct TEVConfigUniforms {
|
/// OpenGL shader resource
|
||||||
GLuint enabled;
|
OGLShader shader;
|
||||||
GLuint color_sources;
|
|
||||||
GLuint alpha_sources;
|
/// Fragment shader uniforms
|
||||||
GLuint color_modifiers;
|
enum Uniform : GLuint {
|
||||||
GLuint alpha_modifiers;
|
AlphaTestRef = 0,
|
||||||
GLuint color_alpha_op;
|
TevConstColors = 1,
|
||||||
GLuint color_alpha_multiplier;
|
Texture0 = 7,
|
||||||
GLuint const_color;
|
Texture1 = 8,
|
||||||
GLuint updates_combiner_buffer_color_alpha;
|
Texture2 = 9,
|
||||||
|
TevCombinerBufferColor = 10,
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
/// Structure used for storing information about color textures
|
/// Structure used for storing information about color textures
|
||||||
struct TextureInfo {
|
struct TextureInfo {
|
||||||
|
@ -129,6 +222,9 @@ private:
|
||||||
/// Reconfigure the OpenGL depth texture to use the given format and dimensions
|
/// Reconfigure the OpenGL depth texture to use the given format and dimensions
|
||||||
void ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height);
|
void ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height);
|
||||||
|
|
||||||
|
/// Sets the OpenGL shader in accordance with the current PICA register state
|
||||||
|
void SetShader();
|
||||||
|
|
||||||
/// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer
|
/// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer
|
||||||
void SyncFramebuffer();
|
void SyncFramebuffer();
|
||||||
|
|
||||||
|
@ -156,27 +252,12 @@ private:
|
||||||
/// Syncs the depth test states to match the PICA register
|
/// Syncs the depth test states to match the PICA register
|
||||||
void SyncDepthTest();
|
void SyncDepthTest();
|
||||||
|
|
||||||
/// Syncs the specified TEV stage's color and alpha sources to match the PICA register
|
/// Syncs the TEV constant color to match the PICA register
|
||||||
void SyncTevSources(unsigned stage_index, const Pica::Regs::TevStageConfig& config);
|
void SyncTevConstColor(int tev_index, const Pica::Regs::TevStageConfig& tev_stage);
|
||||||
|
|
||||||
/// Syncs the specified TEV stage's color and alpha modifiers to match the PICA register
|
|
||||||
void SyncTevModifiers(unsigned stage_index, const Pica::Regs::TevStageConfig& config);
|
|
||||||
|
|
||||||
/// Syncs the specified TEV stage's color and alpha combiner operations to match the PICA register
|
|
||||||
void SyncTevOps(unsigned stage_index, const Pica::Regs::TevStageConfig& config);
|
|
||||||
|
|
||||||
/// Syncs the specified TEV stage's constant color to match the PICA register
|
|
||||||
void SyncTevColor(unsigned stage_index, const Pica::Regs::TevStageConfig& config);
|
|
||||||
|
|
||||||
/// Syncs the specified TEV stage's color and alpha multipliers to match the PICA register
|
|
||||||
void SyncTevMultipliers(unsigned stage_index, const Pica::Regs::TevStageConfig& config);
|
|
||||||
|
|
||||||
/// Syncs the TEV combiner color buffer to match the PICA register
|
/// Syncs the TEV combiner color buffer to match the PICA register
|
||||||
void SyncCombinerColor();
|
void SyncCombinerColor();
|
||||||
|
|
||||||
/// Syncs the TEV combiner write flags to match the PICA register
|
|
||||||
void SyncCombinerWriteFlags();
|
|
||||||
|
|
||||||
/// Syncs the remaining OpenGL drawing state to match the current PICA state
|
/// Syncs the remaining OpenGL drawing state to match the current PICA state
|
||||||
void SyncDrawState();
|
void SyncDrawState();
|
||||||
|
|
||||||
|
@ -213,21 +294,11 @@ private:
|
||||||
std::array<SamplerInfo, 3> texture_samplers;
|
std::array<SamplerInfo, 3> texture_samplers;
|
||||||
TextureInfo fb_color_texture;
|
TextureInfo fb_color_texture;
|
||||||
DepthTextureInfo fb_depth_texture;
|
DepthTextureInfo fb_depth_texture;
|
||||||
OGLShader shader;
|
|
||||||
|
std::unordered_map<PicaShaderConfig, std::unique_ptr<PicaShader>> shader_cache;
|
||||||
|
const PicaShader* current_shader = nullptr;
|
||||||
|
|
||||||
OGLVertexArray vertex_array;
|
OGLVertexArray vertex_array;
|
||||||
OGLBuffer vertex_buffer;
|
OGLBuffer vertex_buffer;
|
||||||
OGLFramebuffer framebuffer;
|
OGLFramebuffer framebuffer;
|
||||||
|
|
||||||
// Hardware vertex shader
|
|
||||||
GLuint attrib_position;
|
|
||||||
GLuint attrib_color;
|
|
||||||
GLuint attrib_texcoords;
|
|
||||||
|
|
||||||
// Hardware fragment shader
|
|
||||||
GLuint uniform_alphatest_enabled;
|
|
||||||
GLuint uniform_alphatest_func;
|
|
||||||
GLuint uniform_alphatest_ref;
|
|
||||||
GLuint uniform_tex;
|
|
||||||
GLuint uniform_tev_combiner_buffer_color;
|
|
||||||
TEVConfigUniforms uniform_tev_cfgs[6];
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -71,7 +71,7 @@ public:
|
||||||
/// Creates a new internal OpenGL resource and stores the handle
|
/// Creates a new internal OpenGL resource and stores the handle
|
||||||
void Create(const char* vert_shader, const char* frag_shader) {
|
void Create(const char* vert_shader, const char* frag_shader) {
|
||||||
if (handle != 0) return;
|
if (handle != 0) return;
|
||||||
handle = ShaderUtil::LoadShaders(vert_shader, frag_shader);
|
handle = GLShader::LoadProgram(vert_shader, frag_shader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deletes the internal OpenGL resource
|
/// Deletes the internal OpenGL resource
|
||||||
|
|
|
@ -0,0 +1,388 @@
|
||||||
|
// Copyright 2015 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "video_core/pica.h"
|
||||||
|
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||||
|
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
||||||
|
|
||||||
|
using Pica::Regs;
|
||||||
|
using TevStageConfig = Regs::TevStageConfig;
|
||||||
|
|
||||||
|
namespace GLShader {
|
||||||
|
|
||||||
|
/// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code)
|
||||||
|
static bool IsPassThroughTevStage(const TevStageConfig& stage) {
|
||||||
|
return (stage.color_op == TevStageConfig::Operation::Replace &&
|
||||||
|
stage.alpha_op == TevStageConfig::Operation::Replace &&
|
||||||
|
stage.color_source1 == TevStageConfig::Source::Previous &&
|
||||||
|
stage.alpha_source1 == TevStageConfig::Source::Previous &&
|
||||||
|
stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor &&
|
||||||
|
stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha &&
|
||||||
|
stage.GetColorMultiplier() == 1 &&
|
||||||
|
stage.GetAlphaMultiplier() == 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes the specified TEV stage source component(s)
|
||||||
|
static void AppendSource(std::string& out, TevStageConfig::Source source,
|
||||||
|
const std::string& index_name) {
|
||||||
|
using Source = TevStageConfig::Source;
|
||||||
|
switch (source) {
|
||||||
|
case Source::PrimaryColor:
|
||||||
|
out += "primary_color";
|
||||||
|
break;
|
||||||
|
case Source::PrimaryFragmentColor:
|
||||||
|
// HACK: Until we implement fragment lighting, use primary_color
|
||||||
|
out += "primary_color";
|
||||||
|
break;
|
||||||
|
case Source::SecondaryFragmentColor:
|
||||||
|
// HACK: Until we implement fragment lighting, use zero
|
||||||
|
out += "vec4(0.0)";
|
||||||
|
break;
|
||||||
|
case Source::Texture0:
|
||||||
|
out += "texture(tex[0], texcoord[0])";
|
||||||
|
break;
|
||||||
|
case Source::Texture1:
|
||||||
|
out += "texture(tex[1], texcoord[1])";
|
||||||
|
break;
|
||||||
|
case Source::Texture2:
|
||||||
|
out += "texture(tex[2], texcoord[2])";
|
||||||
|
break;
|
||||||
|
case Source::PreviousBuffer:
|
||||||
|
out += "combiner_buffer";
|
||||||
|
break;
|
||||||
|
case Source::Constant:
|
||||||
|
((out += "const_color[") += index_name) += ']';
|
||||||
|
break;
|
||||||
|
case Source::Previous:
|
||||||
|
out += "last_tex_env_out";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out += "vec4(0.0)";
|
||||||
|
LOG_CRITICAL(Render_OpenGL, "Unknown source op %u", source);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes the color components to use for the specified TEV stage color modifier
|
||||||
|
static void AppendColorModifier(std::string& out, TevStageConfig::ColorModifier modifier,
|
||||||
|
TevStageConfig::Source source, const std::string& index_name) {
|
||||||
|
using ColorModifier = TevStageConfig::ColorModifier;
|
||||||
|
switch (modifier) {
|
||||||
|
case ColorModifier::SourceColor:
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".rgb";
|
||||||
|
break;
|
||||||
|
case ColorModifier::OneMinusSourceColor:
|
||||||
|
out += "vec3(1.0) - ";
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".rgb";
|
||||||
|
break;
|
||||||
|
case ColorModifier::SourceAlpha:
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".aaa";
|
||||||
|
break;
|
||||||
|
case ColorModifier::OneMinusSourceAlpha:
|
||||||
|
out += "vec3(1.0) - ";
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".aaa";
|
||||||
|
break;
|
||||||
|
case ColorModifier::SourceRed:
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".rrr";
|
||||||
|
break;
|
||||||
|
case ColorModifier::OneMinusSourceRed:
|
||||||
|
out += "vec3(1.0) - ";
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".rrr";
|
||||||
|
break;
|
||||||
|
case ColorModifier::SourceGreen:
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".ggg";
|
||||||
|
break;
|
||||||
|
case ColorModifier::OneMinusSourceGreen:
|
||||||
|
out += "vec3(1.0) - ";
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".ggg";
|
||||||
|
break;
|
||||||
|
case ColorModifier::SourceBlue:
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".bbb";
|
||||||
|
break;
|
||||||
|
case ColorModifier::OneMinusSourceBlue:
|
||||||
|
out += "vec3(1.0) - ";
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".bbb";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out += "vec3(0.0)";
|
||||||
|
LOG_CRITICAL(Render_OpenGL, "Unknown color modifier op %u", modifier);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes the alpha component to use for the specified TEV stage alpha modifier
|
||||||
|
static void AppendAlphaModifier(std::string& out, TevStageConfig::AlphaModifier modifier,
|
||||||
|
TevStageConfig::Source source, const std::string& index_name) {
|
||||||
|
using AlphaModifier = TevStageConfig::AlphaModifier;
|
||||||
|
switch (modifier) {
|
||||||
|
case AlphaModifier::SourceAlpha:
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".a";
|
||||||
|
break;
|
||||||
|
case AlphaModifier::OneMinusSourceAlpha:
|
||||||
|
out += "1.0 - ";
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".a";
|
||||||
|
break;
|
||||||
|
case AlphaModifier::SourceRed:
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".r";
|
||||||
|
break;
|
||||||
|
case AlphaModifier::OneMinusSourceRed:
|
||||||
|
out += "1.0 - ";
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".r";
|
||||||
|
break;
|
||||||
|
case AlphaModifier::SourceGreen:
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".g";
|
||||||
|
break;
|
||||||
|
case AlphaModifier::OneMinusSourceGreen:
|
||||||
|
out += "1.0 - ";
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".g";
|
||||||
|
break;
|
||||||
|
case AlphaModifier::SourceBlue:
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".b";
|
||||||
|
break;
|
||||||
|
case AlphaModifier::OneMinusSourceBlue:
|
||||||
|
out += "1.0 - ";
|
||||||
|
AppendSource(out, source, index_name);
|
||||||
|
out += ".b";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out += "0.0";
|
||||||
|
LOG_CRITICAL(Render_OpenGL, "Unknown alpha modifier op %u", modifier);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes the combiner function for the color components for the specified TEV stage operation
|
||||||
|
static void AppendColorCombiner(std::string& out, TevStageConfig::Operation operation,
|
||||||
|
const std::string& variable_name) {
|
||||||
|
out += "clamp(";
|
||||||
|
using Operation = TevStageConfig::Operation;
|
||||||
|
switch (operation) {
|
||||||
|
case Operation::Replace:
|
||||||
|
out += variable_name + "[0]";
|
||||||
|
break;
|
||||||
|
case Operation::Modulate:
|
||||||
|
out += variable_name + "[0] * " + variable_name + "[1]";
|
||||||
|
break;
|
||||||
|
case Operation::Add:
|
||||||
|
out += variable_name + "[0] + " + variable_name + "[1]";
|
||||||
|
break;
|
||||||
|
case Operation::AddSigned:
|
||||||
|
out += variable_name + "[0] + " + variable_name + "[1] - vec3(0.5)";
|
||||||
|
break;
|
||||||
|
case Operation::Lerp:
|
||||||
|
// TODO(bunnei): Verify if HW actually does this per-component, otherwise we can just use builtin lerp
|
||||||
|
out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (vec3(1.0) - " + variable_name + "[2])";
|
||||||
|
break;
|
||||||
|
case Operation::Subtract:
|
||||||
|
out += variable_name + "[0] - " + variable_name + "[1]";
|
||||||
|
break;
|
||||||
|
case Operation::MultiplyThenAdd:
|
||||||
|
out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]";
|
||||||
|
break;
|
||||||
|
case Operation::AddThenMultiply:
|
||||||
|
out += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + variable_name + "[2]";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out += "vec3(0.0)";
|
||||||
|
LOG_CRITICAL(Render_OpenGL, "Unknown color combiner operation: %u", operation);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out += ", vec3(0.0), vec3(1.0))"; // Clamp result to 0.0, 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes the combiner function for the alpha component for the specified TEV stage operation
|
||||||
|
static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation operation,
|
||||||
|
const std::string& variable_name) {
|
||||||
|
out += "clamp(";
|
||||||
|
using Operation = TevStageConfig::Operation;
|
||||||
|
switch (operation) {
|
||||||
|
case Operation::Replace:
|
||||||
|
out += variable_name + "[0]";
|
||||||
|
break;
|
||||||
|
case Operation::Modulate:
|
||||||
|
out += variable_name + "[0] * " + variable_name + "[1]";
|
||||||
|
break;
|
||||||
|
case Operation::Add:
|
||||||
|
out += variable_name + "[0] + " + variable_name + "[1]";
|
||||||
|
break;
|
||||||
|
case Operation::AddSigned:
|
||||||
|
out += variable_name + "[0] + " + variable_name + "[1] - 0.5";
|
||||||
|
break;
|
||||||
|
case Operation::Lerp:
|
||||||
|
out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (1.0 - " + variable_name + "[2])";
|
||||||
|
break;
|
||||||
|
case Operation::Subtract:
|
||||||
|
out += variable_name + "[0] - " + variable_name + "[1]";
|
||||||
|
break;
|
||||||
|
case Operation::MultiplyThenAdd:
|
||||||
|
out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]";
|
||||||
|
break;
|
||||||
|
case Operation::AddThenMultiply:
|
||||||
|
out += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + "[2]";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
out += "0.0";
|
||||||
|
LOG_CRITICAL(Render_OpenGL, "Unknown alpha combiner operation: %u", operation);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out += ", 0.0, 1.0)";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes the if-statement condition used to evaluate alpha testing
|
||||||
|
static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) {
|
||||||
|
using CompareFunc = Regs::CompareFunc;
|
||||||
|
switch (func) {
|
||||||
|
case CompareFunc::Never:
|
||||||
|
out += "true";
|
||||||
|
break;
|
||||||
|
case CompareFunc::Always:
|
||||||
|
out += "false";
|
||||||
|
break;
|
||||||
|
case CompareFunc::Equal:
|
||||||
|
case CompareFunc::NotEqual:
|
||||||
|
case CompareFunc::LessThan:
|
||||||
|
case CompareFunc::LessThanOrEqual:
|
||||||
|
case CompareFunc::GreaterThan:
|
||||||
|
case CompareFunc::GreaterThanOrEqual:
|
||||||
|
{
|
||||||
|
static const char* op[] = { "!=", "==", ">=", ">", "<=", "<", };
|
||||||
|
unsigned index = (unsigned)func - (unsigned)CompareFunc::Equal;
|
||||||
|
out += "int(last_tex_env_out.a * 255.0f) " + std::string(op[index]) + " alphatest_ref";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
out += "false";
|
||||||
|
LOG_CRITICAL(Render_OpenGL, "Unknown alpha test condition %u", func);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes the code to emulate the specified TEV stage
|
||||||
|
static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) {
|
||||||
|
auto& stage = config.tev_stages[index];
|
||||||
|
if (!IsPassThroughTevStage(stage)) {
|
||||||
|
std::string index_name = std::to_string(index);
|
||||||
|
|
||||||
|
out += "vec3 color_results_" + index_name + "[3] = vec3[3](";
|
||||||
|
AppendColorModifier(out, stage.color_modifier1, stage.color_source1, index_name);
|
||||||
|
out += ", ";
|
||||||
|
AppendColorModifier(out, stage.color_modifier2, stage.color_source2, index_name);
|
||||||
|
out += ", ";
|
||||||
|
AppendColorModifier(out, stage.color_modifier3, stage.color_source3, index_name);
|
||||||
|
out += ");\n";
|
||||||
|
|
||||||
|
out += "vec3 color_output_" + index_name + " = ";
|
||||||
|
AppendColorCombiner(out, stage.color_op, "color_results_" + index_name);
|
||||||
|
out += ";\n";
|
||||||
|
|
||||||
|
out += "float alpha_results_" + index_name + "[3] = float[3](";
|
||||||
|
AppendAlphaModifier(out, stage.alpha_modifier1, stage.alpha_source1, index_name);
|
||||||
|
out += ", ";
|
||||||
|
AppendAlphaModifier(out, stage.alpha_modifier2, stage.alpha_source2, index_name);
|
||||||
|
out += ", ";
|
||||||
|
AppendAlphaModifier(out, stage.alpha_modifier3, stage.alpha_source3, index_name);
|
||||||
|
out += ");\n";
|
||||||
|
|
||||||
|
out += "float alpha_output_" + index_name + " = ";
|
||||||
|
AppendAlphaCombiner(out, stage.alpha_op, "alpha_results_" + index_name);
|
||||||
|
out += ";\n";
|
||||||
|
|
||||||
|
out += "last_tex_env_out = vec4("
|
||||||
|
"clamp(color_output_" + index_name + " * " + std::to_string(stage.GetColorMultiplier()) + ".0, vec3(0.0), vec3(1.0)),"
|
||||||
|
"clamp(alpha_output_" + index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) + ".0, 0.0, 1.0));\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.TevStageUpdatesCombinerBufferColor(index))
|
||||||
|
out += "combiner_buffer.rgb = last_tex_env_out.rgb;\n";
|
||||||
|
|
||||||
|
if (config.TevStageUpdatesCombinerBufferAlpha(index))
|
||||||
|
out += "combiner_buffer.a = last_tex_env_out.a;\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GenerateFragmentShader(const PicaShaderConfig& config) {
|
||||||
|
std::string out = R"(
|
||||||
|
#version 330
|
||||||
|
#extension GL_ARB_explicit_uniform_location : require
|
||||||
|
|
||||||
|
#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";
|
||||||
|
|
||||||
|
out += "void main() {\n";
|
||||||
|
out += "vec4 combiner_buffer = tev_combiner_buffer_color;\n";
|
||||||
|
out += "vec4 last_tex_env_out = vec4(0.0);\n";
|
||||||
|
|
||||||
|
// Do not do any sort of processing if it's obvious we're not going to pass the alpha test
|
||||||
|
if (config.alpha_test_func == Regs::CompareFunc::Never) {
|
||||||
|
out += "discard; }";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t index = 0; index < config.tev_stages.size(); ++index)
|
||||||
|
WriteTevStage(out, config, (unsigned)index);
|
||||||
|
|
||||||
|
if (config.alpha_test_func != Regs::CompareFunc::Always) {
|
||||||
|
out += "if (";
|
||||||
|
AppendAlphaTestCondition(out, config.alpha_test_func);
|
||||||
|
out += ") discard;\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
out += "color = last_tex_env_out;\n}";
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GenerateVertexShader() {
|
||||||
|
std::string out = "#version 330\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";
|
||||||
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) + ") in vec2 vert_texcoord1;\n";
|
||||||
|
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) + ") in vec2 vert_texcoord2;\n";
|
||||||
|
|
||||||
|
out += R"(
|
||||||
|
out vec4 primary_color;
|
||||||
|
out vec2 texcoord[3];
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
primary_color = vert_color;
|
||||||
|
texcoord[0] = vert_texcoord0;
|
||||||
|
texcoord[1] = vert_texcoord1;
|
||||||
|
texcoord[2] = vert_texcoord2;
|
||||||
|
gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace GLShader
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright 2015 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||||
|
|
||||||
|
namespace GLShader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the GLSL vertex shader program source code for the current Pica state
|
||||||
|
* @returns String of the shader source code
|
||||||
|
*/
|
||||||
|
std::string GenerateVertexShader();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the GLSL fragment shader program source code for the current Pica state
|
||||||
|
* @param config ShaderCacheKey object generated for the current Pica state, used for the shader
|
||||||
|
* configuration (NOTE: Use state in this struct only, not the Pica registers!)
|
||||||
|
* @returns String of the shader source code
|
||||||
|
*/
|
||||||
|
std::string GenerateFragmentShader(const PicaShaderConfig& config);
|
||||||
|
|
||||||
|
} // namespace GLShader
|
|
@ -8,9 +8,9 @@
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "video_core/renderer_opengl/gl_shader_util.h"
|
#include "video_core/renderer_opengl/gl_shader_util.h"
|
||||||
|
|
||||||
namespace ShaderUtil {
|
namespace GLShader {
|
||||||
|
|
||||||
GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
|
GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) {
|
||||||
|
|
||||||
// Create the shaders
|
// Create the shaders
|
||||||
GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER);
|
GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER);
|
||||||
|
@ -65,6 +65,7 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
|
||||||
GLuint program_id = glCreateProgram();
|
GLuint program_id = glCreateProgram();
|
||||||
glAttachShader(program_id, vertex_shader_id);
|
glAttachShader(program_id, vertex_shader_id);
|
||||||
glAttachShader(program_id, fragment_shader_id);
|
glAttachShader(program_id, fragment_shader_id);
|
||||||
|
|
||||||
glLinkProgram(program_id);
|
glLinkProgram(program_id);
|
||||||
|
|
||||||
// Check the program
|
// Check the program
|
||||||
|
@ -87,4 +88,4 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
|
||||||
return program_id;
|
return program_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
} // namespace GLShader
|
||||||
|
|
|
@ -6,8 +6,22 @@
|
||||||
|
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
|
|
||||||
namespace ShaderUtil {
|
namespace GLShader {
|
||||||
|
|
||||||
GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path);
|
enum Attributes {
|
||||||
|
ATTRIBUTE_POSITION,
|
||||||
|
ATTRIBUTE_COLOR,
|
||||||
|
ATTRIBUTE_TEXCOORD0,
|
||||||
|
ATTRIBUTE_TEXCOORD1,
|
||||||
|
ATTRIBUTE_TEXCOORD2,
|
||||||
|
};
|
||||||
|
|
||||||
}
|
/**
|
||||||
|
* Utility function to create and compile an OpenGL GLSL shader program (vertex + fragment shader)
|
||||||
|
* @param vertex_shader String of the GLSL vertex shader program
|
||||||
|
* @param fragment_shader String of the GLSL fragment shader program
|
||||||
|
* @returns Handle of the newly created OpenGL shader object
|
||||||
|
*/
|
||||||
|
GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader);
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
|
@ -1,337 +0,0 @@
|
||||||
// Copyright 2014 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace GLShaders {
|
|
||||||
|
|
||||||
const char g_vertex_shader[] = R"(
|
|
||||||
#version 150 core
|
|
||||||
|
|
||||||
in vec2 vert_position;
|
|
||||||
in vec2 vert_tex_coord;
|
|
||||||
out vec2 frag_tex_coord;
|
|
||||||
|
|
||||||
// This is a truncated 3x3 matrix for 2D transformations:
|
|
||||||
// The upper-left 2x2 submatrix performs scaling/rotation/mirroring.
|
|
||||||
// The third column performs translation.
|
|
||||||
// The third row could be used for projection, which we don't need in 2D. It hence is assumed to
|
|
||||||
// implicitly be [0, 0, 1]
|
|
||||||
uniform mat3x2 modelview_matrix;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
// Multiply input position by the rotscale part of the matrix and then manually translate by
|
|
||||||
// the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
|
|
||||||
// to `vec3(vert_position.xy, 1.0)`
|
|
||||||
gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
|
|
||||||
frag_tex_coord = vert_tex_coord;
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
|
|
||||||
const char g_fragment_shader[] = R"(
|
|
||||||
#version 150 core
|
|
||||||
|
|
||||||
in vec2 frag_tex_coord;
|
|
||||||
out vec4 color;
|
|
||||||
|
|
||||||
uniform sampler2D color_texture;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
color = texture(color_texture, frag_tex_coord);
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
|
|
||||||
const char g_vertex_shader_hw[] = R"(
|
|
||||||
#version 150 core
|
|
||||||
|
|
||||||
#define NUM_VTX_ATTR 7
|
|
||||||
|
|
||||||
in vec4 vert_position;
|
|
||||||
in vec4 vert_color;
|
|
||||||
in vec2 vert_texcoords[3];
|
|
||||||
|
|
||||||
out vec4 o[NUM_VTX_ATTR];
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
o[2] = vert_color;
|
|
||||||
o[3] = vec4(vert_texcoords[0].xy, vert_texcoords[1].xy);
|
|
||||||
o[5] = vec4(0.0, 0.0, vert_texcoords[2].xy);
|
|
||||||
|
|
||||||
gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w);
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
|
|
||||||
// TODO: Create a shader constructor and cache that builds this program with minimal conditionals instead of using tev_cfg uniforms
|
|
||||||
const char g_fragment_shader_hw[] = R"(
|
|
||||||
#version 150 core
|
|
||||||
|
|
||||||
#define NUM_VTX_ATTR 7
|
|
||||||
#define NUM_TEV_STAGES 6
|
|
||||||
|
|
||||||
#define SOURCE_PRIMARYCOLOR 0x0
|
|
||||||
#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1
|
|
||||||
#define SOURCE_SECONDARYFRAGMENTCOLOR 0x2
|
|
||||||
#define SOURCE_TEXTURE0 0x3
|
|
||||||
#define SOURCE_TEXTURE1 0x4
|
|
||||||
#define SOURCE_TEXTURE2 0x5
|
|
||||||
#define SOURCE_TEXTURE3 0x6
|
|
||||||
#define SOURCE_PREVIOUSBUFFER 0xd
|
|
||||||
#define SOURCE_CONSTANT 0xe
|
|
||||||
#define SOURCE_PREVIOUS 0xf
|
|
||||||
|
|
||||||
#define COLORMODIFIER_SOURCECOLOR 0x0
|
|
||||||
#define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1
|
|
||||||
#define COLORMODIFIER_SOURCEALPHA 0x2
|
|
||||||
#define COLORMODIFIER_ONEMINUSSOURCEALPHA 0x3
|
|
||||||
#define COLORMODIFIER_SOURCERED 0x4
|
|
||||||
#define COLORMODIFIER_ONEMINUSSOURCERED 0x5
|
|
||||||
#define COLORMODIFIER_SOURCEGREEN 0x8
|
|
||||||
#define COLORMODIFIER_ONEMINUSSOURCEGREEN 0x9
|
|
||||||
#define COLORMODIFIER_SOURCEBLUE 0xc
|
|
||||||
#define COLORMODIFIER_ONEMINUSSOURCEBLUE 0xd
|
|
||||||
|
|
||||||
#define ALPHAMODIFIER_SOURCEALPHA 0x0
|
|
||||||
#define ALPHAMODIFIER_ONEMINUSSOURCEALPHA 0x1
|
|
||||||
#define ALPHAMODIFIER_SOURCERED 0x2
|
|
||||||
#define ALPHAMODIFIER_ONEMINUSSOURCERED 0x3
|
|
||||||
#define ALPHAMODIFIER_SOURCEGREEN 0x4
|
|
||||||
#define ALPHAMODIFIER_ONEMINUSSOURCEGREEN 0x5
|
|
||||||
#define ALPHAMODIFIER_SOURCEBLUE 0x6
|
|
||||||
#define ALPHAMODIFIER_ONEMINUSSOURCEBLUE 0x7
|
|
||||||
|
|
||||||
#define OPERATION_REPLACE 0
|
|
||||||
#define OPERATION_MODULATE 1
|
|
||||||
#define OPERATION_ADD 2
|
|
||||||
#define OPERATION_ADDSIGNED 3
|
|
||||||
#define OPERATION_LERP 4
|
|
||||||
#define OPERATION_SUBTRACT 5
|
|
||||||
#define OPERATION_MULTIPLYTHENADD 8
|
|
||||||
#define OPERATION_ADDTHENMULTIPLY 9
|
|
||||||
|
|
||||||
#define COMPAREFUNC_NEVER 0
|
|
||||||
#define COMPAREFUNC_ALWAYS 1
|
|
||||||
#define COMPAREFUNC_EQUAL 2
|
|
||||||
#define COMPAREFUNC_NOTEQUAL 3
|
|
||||||
#define COMPAREFUNC_LESSTHAN 4
|
|
||||||
#define COMPAREFUNC_LESSTHANOREQUAL 5
|
|
||||||
#define COMPAREFUNC_GREATERTHAN 6
|
|
||||||
#define COMPAREFUNC_GREATERTHANOREQUAL 7
|
|
||||||
|
|
||||||
in vec4 o[NUM_VTX_ATTR];
|
|
||||||
out vec4 color;
|
|
||||||
|
|
||||||
uniform bool alphatest_enabled;
|
|
||||||
uniform int alphatest_func;
|
|
||||||
uniform float alphatest_ref;
|
|
||||||
|
|
||||||
uniform sampler2D tex[3];
|
|
||||||
|
|
||||||
uniform vec4 tev_combiner_buffer_color;
|
|
||||||
|
|
||||||
struct TEVConfig
|
|
||||||
{
|
|
||||||
bool enabled;
|
|
||||||
ivec3 color_sources;
|
|
||||||
ivec3 alpha_sources;
|
|
||||||
ivec3 color_modifiers;
|
|
||||||
ivec3 alpha_modifiers;
|
|
||||||
ivec2 color_alpha_op;
|
|
||||||
ivec2 color_alpha_multiplier;
|
|
||||||
vec4 const_color;
|
|
||||||
bvec2 updates_combiner_buffer_color_alpha;
|
|
||||||
};
|
|
||||||
|
|
||||||
uniform TEVConfig tev_cfgs[NUM_TEV_STAGES];
|
|
||||||
|
|
||||||
vec4 g_combiner_buffer;
|
|
||||||
vec4 g_last_tex_env_out;
|
|
||||||
vec4 g_const_color;
|
|
||||||
|
|
||||||
vec4 GetSource(int source) {
|
|
||||||
if (source == SOURCE_PRIMARYCOLOR) {
|
|
||||||
return o[2];
|
|
||||||
} else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) {
|
|
||||||
// HACK: Until we implement fragment lighting, use primary_color
|
|
||||||
return o[2];
|
|
||||||
} else if (source == SOURCE_SECONDARYFRAGMENTCOLOR) {
|
|
||||||
// HACK: Until we implement fragment lighting, use zero
|
|
||||||
return vec4(0.0, 0.0, 0.0, 0.0);
|
|
||||||
} else if (source == SOURCE_TEXTURE0) {
|
|
||||||
return texture(tex[0], o[3].xy);
|
|
||||||
} else if (source == SOURCE_TEXTURE1) {
|
|
||||||
return texture(tex[1], o[3].zw);
|
|
||||||
} else if (source == SOURCE_TEXTURE2) {
|
|
||||||
// TODO: Unverified
|
|
||||||
return texture(tex[2], o[5].zw);
|
|
||||||
} else if (source == SOURCE_TEXTURE3) {
|
|
||||||
// TODO: no 4th texture?
|
|
||||||
} else if (source == SOURCE_PREVIOUSBUFFER) {
|
|
||||||
return g_combiner_buffer;
|
|
||||||
} else if (source == SOURCE_CONSTANT) {
|
|
||||||
return g_const_color;
|
|
||||||
} else if (source == SOURCE_PREVIOUS) {
|
|
||||||
return g_last_tex_env_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
return vec4(0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 GetColorModifier(int factor, vec4 color) {
|
|
||||||
if (factor == COLORMODIFIER_SOURCECOLOR) {
|
|
||||||
return color.rgb;
|
|
||||||
} else if (factor == COLORMODIFIER_ONEMINUSSOURCECOLOR) {
|
|
||||||
return vec3(1.0) - color.rgb;
|
|
||||||
} else if (factor == COLORMODIFIER_SOURCEALPHA) {
|
|
||||||
return color.aaa;
|
|
||||||
} else if (factor == COLORMODIFIER_ONEMINUSSOURCEALPHA) {
|
|
||||||
return vec3(1.0) - color.aaa;
|
|
||||||
} else if (factor == COLORMODIFIER_SOURCERED) {
|
|
||||||
return color.rrr;
|
|
||||||
} else if (factor == COLORMODIFIER_ONEMINUSSOURCERED) {
|
|
||||||
return vec3(1.0) - color.rrr;
|
|
||||||
} else if (factor == COLORMODIFIER_SOURCEGREEN) {
|
|
||||||
return color.ggg;
|
|
||||||
} else if (factor == COLORMODIFIER_ONEMINUSSOURCEGREEN) {
|
|
||||||
return vec3(1.0) - color.ggg;
|
|
||||||
} else if (factor == COLORMODIFIER_SOURCEBLUE) {
|
|
||||||
return color.bbb;
|
|
||||||
} else if (factor == COLORMODIFIER_ONEMINUSSOURCEBLUE) {
|
|
||||||
return vec3(1.0) - color.bbb;
|
|
||||||
}
|
|
||||||
|
|
||||||
return vec3(0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float GetAlphaModifier(int factor, vec4 color) {
|
|
||||||
if (factor == ALPHAMODIFIER_SOURCEALPHA) {
|
|
||||||
return color.a;
|
|
||||||
} else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEALPHA) {
|
|
||||||
return 1.0 - color.a;
|
|
||||||
} else if (factor == ALPHAMODIFIER_SOURCERED) {
|
|
||||||
return color.r;
|
|
||||||
} else if (factor == ALPHAMODIFIER_ONEMINUSSOURCERED) {
|
|
||||||
return 1.0 - color.r;
|
|
||||||
} else if (factor == ALPHAMODIFIER_SOURCEGREEN) {
|
|
||||||
return color.g;
|
|
||||||
} else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEGREEN) {
|
|
||||||
return 1.0 - color.g;
|
|
||||||
} else if (factor == ALPHAMODIFIER_SOURCEBLUE) {
|
|
||||||
return color.b;
|
|
||||||
} else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEBLUE) {
|
|
||||||
return 1.0 - color.b;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec3 ColorCombine(int op, vec3 color[3]) {
|
|
||||||
if (op == OPERATION_REPLACE) {
|
|
||||||
return color[0];
|
|
||||||
} else if (op == OPERATION_MODULATE) {
|
|
||||||
return color[0] * color[1];
|
|
||||||
} else if (op == OPERATION_ADD) {
|
|
||||||
return min(color[0] + color[1], 1.0);
|
|
||||||
} else if (op == OPERATION_ADDSIGNED) {
|
|
||||||
return clamp(color[0] + color[1] - vec3(0.5), 0.0, 1.0);
|
|
||||||
} else if (op == OPERATION_LERP) {
|
|
||||||
return color[0] * color[2] + color[1] * (vec3(1.0) - color[2]);
|
|
||||||
} else if (op == OPERATION_SUBTRACT) {
|
|
||||||
return max(color[0] - color[1], 0.0);
|
|
||||||
} else if (op == OPERATION_MULTIPLYTHENADD) {
|
|
||||||
return min(color[0] * color[1] + color[2], 1.0);
|
|
||||||
} else if (op == OPERATION_ADDTHENMULTIPLY) {
|
|
||||||
return min(color[0] + color[1], 1.0) * color[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
return vec3(0.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float AlphaCombine(int op, float alpha[3]) {
|
|
||||||
if (op == OPERATION_REPLACE) {
|
|
||||||
return alpha[0];
|
|
||||||
} else if (op == OPERATION_MODULATE) {
|
|
||||||
return alpha[0] * alpha[1];
|
|
||||||
} else if (op == OPERATION_ADD) {
|
|
||||||
return min(alpha[0] + alpha[1], 1.0);
|
|
||||||
} else if (op == OPERATION_ADDSIGNED) {
|
|
||||||
return clamp(alpha[0] + alpha[1] - 0.5, 0.0, 1.0);
|
|
||||||
} else if (op == OPERATION_LERP) {
|
|
||||||
return alpha[0] * alpha[2] + alpha[1] * (1.0 - alpha[2]);
|
|
||||||
} else if (op == OPERATION_SUBTRACT) {
|
|
||||||
return max(alpha[0] - alpha[1], 0.0);
|
|
||||||
} else if (op == OPERATION_MULTIPLYTHENADD) {
|
|
||||||
return min(alpha[0] * alpha[1] + alpha[2], 1.0);
|
|
||||||
} else if (op == OPERATION_ADDTHENMULTIPLY) {
|
|
||||||
return min(alpha[0] + alpha[1], 1.0) * alpha[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void main(void) {
|
|
||||||
g_combiner_buffer = tev_combiner_buffer_color;
|
|
||||||
|
|
||||||
for (int tex_env_idx = 0; tex_env_idx < NUM_TEV_STAGES; ++tex_env_idx) {
|
|
||||||
if (tev_cfgs[tex_env_idx].enabled) {
|
|
||||||
g_const_color = tev_cfgs[tex_env_idx].const_color;
|
|
||||||
|
|
||||||
vec3 color_results[3] = vec3[3](GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.x, GetSource(tev_cfgs[tex_env_idx].color_sources.x)),
|
|
||||||
GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.y, GetSource(tev_cfgs[tex_env_idx].color_sources.y)),
|
|
||||||
GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.z, GetSource(tev_cfgs[tex_env_idx].color_sources.z)));
|
|
||||||
vec3 color_output = ColorCombine(tev_cfgs[tex_env_idx].color_alpha_op.x, color_results);
|
|
||||||
|
|
||||||
float alpha_results[3] = float[3](GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.x, GetSource(tev_cfgs[tex_env_idx].alpha_sources.x)),
|
|
||||||
GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.y, GetSource(tev_cfgs[tex_env_idx].alpha_sources.y)),
|
|
||||||
GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.z, GetSource(tev_cfgs[tex_env_idx].alpha_sources.z)));
|
|
||||||
float alpha_output = AlphaCombine(tev_cfgs[tex_env_idx].color_alpha_op.y, alpha_results);
|
|
||||||
|
|
||||||
g_last_tex_env_out = vec4(min(color_output * tev_cfgs[tex_env_idx].color_alpha_multiplier.x, 1.0), min(alpha_output * tev_cfgs[tex_env_idx].color_alpha_multiplier.y, 1.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tev_cfgs[tex_env_idx].updates_combiner_buffer_color_alpha.x) {
|
|
||||||
g_combiner_buffer.rgb = g_last_tex_env_out.rgb;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tev_cfgs[tex_env_idx].updates_combiner_buffer_color_alpha.y) {
|
|
||||||
g_combiner_buffer.a = g_last_tex_env_out.a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alphatest_enabled) {
|
|
||||||
if (alphatest_func == COMPAREFUNC_NEVER) {
|
|
||||||
discard;
|
|
||||||
} else if (alphatest_func == COMPAREFUNC_ALWAYS) {
|
|
||||||
|
|
||||||
} else if (alphatest_func == COMPAREFUNC_EQUAL) {
|
|
||||||
if (g_last_tex_env_out.a != alphatest_ref) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
} else if (alphatest_func == COMPAREFUNC_NOTEQUAL) {
|
|
||||||
if (g_last_tex_env_out.a == alphatest_ref) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
} else if (alphatest_func == COMPAREFUNC_LESSTHAN) {
|
|
||||||
if (g_last_tex_env_out.a >= alphatest_ref) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
} else if (alphatest_func == COMPAREFUNC_LESSTHANOREQUAL) {
|
|
||||||
if (g_last_tex_env_out.a > alphatest_ref) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
} else if (alphatest_func == COMPAREFUNC_GREATERTHAN) {
|
|
||||||
if (g_last_tex_env_out.a <= alphatest_ref) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
} else if (alphatest_func == COMPAREFUNC_GREATERTHANOREQUAL) {
|
|
||||||
if (g_last_tex_env_out.a < alphatest_ref) {
|
|
||||||
discard;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
color = g_last_tex_env_out;
|
|
||||||
}
|
|
||||||
)";
|
|
||||||
|
|
||||||
}
|
|
|
@ -65,6 +65,7 @@ public:
|
||||||
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 shader_program; // GL_CURRENT_PROGRAM
|
GLuint shader_program; // GL_CURRENT_PROGRAM
|
||||||
|
bool shader_dirty;
|
||||||
} draw;
|
} draw;
|
||||||
|
|
||||||
OpenGLState();
|
OpenGLState();
|
||||||
|
|
|
@ -21,9 +21,44 @@
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
#include "video_core/debug_utils/debug_utils.h"
|
||||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||||
#include "video_core/renderer_opengl/gl_shader_util.h"
|
#include "video_core/renderer_opengl/gl_shader_util.h"
|
||||||
#include "video_core/renderer_opengl/gl_shaders.h"
|
|
||||||
#include "video_core/renderer_opengl/renderer_opengl.h"
|
#include "video_core/renderer_opengl/renderer_opengl.h"
|
||||||
|
|
||||||
|
static const char vertex_shader[] = R"(
|
||||||
|
#version 150 core
|
||||||
|
|
||||||
|
in vec2 vert_position;
|
||||||
|
in vec2 vert_tex_coord;
|
||||||
|
out vec2 frag_tex_coord;
|
||||||
|
|
||||||
|
// This is a truncated 3x3 matrix for 2D transformations:
|
||||||
|
// The upper-left 2x2 submatrix performs scaling/rotation/mirroring.
|
||||||
|
// The third column performs translation.
|
||||||
|
// The third row could be used for projection, which we don't need in 2D. It hence is assumed to
|
||||||
|
// implicitly be [0, 0, 1]
|
||||||
|
uniform mat3x2 modelview_matrix;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
// Multiply input position by the rotscale part of the matrix and then manually translate by
|
||||||
|
// the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
|
||||||
|
// to `vec3(vert_position.xy, 1.0)`
|
||||||
|
gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
|
||||||
|
frag_tex_coord = vert_tex_coord;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
static const char fragment_shader[] = R"(
|
||||||
|
#version 150 core
|
||||||
|
|
||||||
|
in vec2 frag_tex_coord;
|
||||||
|
out vec4 color;
|
||||||
|
|
||||||
|
uniform sampler2D color_texture;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
color = texture(color_texture, frag_tex_coord);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vertex structure that the drawn screen rectangles are composed of.
|
* Vertex structure that the drawn screen rectangles are composed of.
|
||||||
*/
|
*/
|
||||||
|
@ -207,7 +242,7 @@ void RendererOpenGL::InitOpenGLObjects() {
|
||||||
glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f);
|
glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f);
|
||||||
|
|
||||||
// Link shaders and get variable locations
|
// Link shaders and get variable locations
|
||||||
program_id = ShaderUtil::LoadShaders(GLShaders::g_vertex_shader, GLShaders::g_fragment_shader);
|
program_id = GLShader::LoadProgram(vertex_shader, fragment_shader);
|
||||||
uniform_modelview_matrix = glGetUniformLocation(program_id, "modelview_matrix");
|
uniform_modelview_matrix = glGetUniformLocation(program_id, "modelview_matrix");
|
||||||
uniform_color_texture = glGetUniformLocation(program_id, "color_texture");
|
uniform_color_texture = glGetUniformLocation(program_id, "color_texture");
|
||||||
attrib_position = glGetAttribLocation(program_id, "vert_position");
|
attrib_position = glGetAttribLocation(program_id, "vert_position");
|
||||||
|
|
Reference in New Issue