diff options
| author | 2015-10-21 22:36:27 -0400 | |
|---|---|---|
| committer | 2015-10-21 22:36:27 -0400 | |
| commit | 4195d9b3f83441c60f23f939a19733e93ee04ff8 (patch) | |
| tree | f3005c0737a6ade25afc5a912e0a7f14e48adfa5 /src | |
| parent | Merge pull request #1207 from kemenaran/persist-citra-settings-in-qt (diff) | |
| parent | gl_shader_gen: Use explicit locations for vertex shader attributes. (diff) | |
| download | yuzu-4195d9b3f83441c60f23f939a19733e93ee04ff8.tar.gz yuzu-4195d9b3f83441c60f23f939a19733e93ee04ff8.tar.xz yuzu-4195d9b3f83441c60f23f939a19733e93ee04ff8.zip | |
Merge pull request #1187 from bunnei/shader-gen
GLSL Fragment Shader Generation
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/video_core/pica.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.cpp | 313 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer.h | 157 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_resource_manager.h | 2 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.cpp | 388 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_gen.h | 27 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_util.cpp | 7 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_util.h | 20 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shaders.h | 337 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_state.h | 1 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 39 |
12 files changed, 678 insertions, 620 deletions
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 8c9d76ab4..2a924f4ad 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | set(SRCS | 1 | set(SRCS |
| 2 | renderer_opengl/gl_rasterizer.cpp | 2 | renderer_opengl/gl_rasterizer.cpp |
| 3 | renderer_opengl/gl_rasterizer_cache.cpp | 3 | renderer_opengl/gl_rasterizer_cache.cpp |
| 4 | renderer_opengl/gl_shader_gen.cpp | ||
| 4 | renderer_opengl/gl_shader_util.cpp | 5 | renderer_opengl/gl_shader_util.cpp |
| 5 | renderer_opengl/gl_state.cpp | 6 | renderer_opengl/gl_state.cpp |
| 6 | renderer_opengl/renderer_opengl.cpp | 7 | renderer_opengl/renderer_opengl.cpp |
| @@ -21,8 +22,8 @@ set(HEADERS | |||
| 21 | renderer_opengl/gl_rasterizer.h | 22 | renderer_opengl/gl_rasterizer.h |
| 22 | renderer_opengl/gl_rasterizer_cache.h | 23 | renderer_opengl/gl_rasterizer_cache.h |
| 23 | renderer_opengl/gl_resource_manager.h | 24 | renderer_opengl/gl_resource_manager.h |
| 25 | renderer_opengl/gl_shader_gen.h | ||
| 24 | renderer_opengl/gl_shader_util.h | 26 | renderer_opengl/gl_shader_util.h |
| 25 | renderer_opengl/gl_shaders.h | ||
| 26 | renderer_opengl/gl_state.h | 27 | renderer_opengl/gl_state.h |
| 27 | renderer_opengl/pica_to_gl.h | 28 | renderer_opengl/pica_to_gl.h |
| 28 | renderer_opengl/renderer_opengl.h | 29 | renderer_opengl/renderer_opengl.h |
diff --git a/src/video_core/pica.h b/src/video_core/pica.h index ff81b409d..2f1b2dec4 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h | |||
| @@ -317,6 +317,7 @@ struct Regs { | |||
| 317 | }; | 317 | }; |
| 318 | 318 | ||
| 319 | union { | 319 | union { |
| 320 | u32 sources_raw; | ||
| 320 | BitField< 0, 4, Source> color_source1; | 321 | BitField< 0, 4, Source> color_source1; |
| 321 | BitField< 4, 4, Source> color_source2; | 322 | BitField< 4, 4, Source> color_source2; |
| 322 | BitField< 8, 4, Source> color_source3; | 323 | BitField< 8, 4, Source> color_source3; |
| @@ -326,6 +327,7 @@ struct Regs { | |||
| 326 | }; | 327 | }; |
| 327 | 328 | ||
| 328 | union { | 329 | union { |
| 330 | u32 modifiers_raw; | ||
| 329 | BitField< 0, 4, ColorModifier> color_modifier1; | 331 | BitField< 0, 4, ColorModifier> color_modifier1; |
| 330 | BitField< 4, 4, ColorModifier> color_modifier2; | 332 | BitField< 4, 4, ColorModifier> color_modifier2; |
| 331 | BitField< 8, 4, ColorModifier> color_modifier3; | 333 | BitField< 8, 4, ColorModifier> color_modifier3; |
| @@ -335,6 +337,7 @@ struct Regs { | |||
| 335 | }; | 337 | }; |
| 336 | 338 | ||
| 337 | union { | 339 | union { |
| 340 | u32 ops_raw; | ||
| 338 | BitField< 0, 4, Operation> color_op; | 341 | BitField< 0, 4, Operation> color_op; |
| 339 | BitField<16, 4, Operation> alpha_op; | 342 | BitField<16, 4, Operation> alpha_op; |
| 340 | }; | 343 | }; |
| @@ -348,6 +351,7 @@ struct Regs { | |||
| 348 | }; | 351 | }; |
| 349 | 352 | ||
| 350 | union { | 353 | union { |
| 354 | u32 scales_raw; | ||
| 351 | BitField< 0, 2, u32> color_scale; | 355 | BitField< 0, 2, u32> color_scale; |
| 352 | BitField<16, 2, u32> alpha_scale; | 356 | BitField<16, 2, u32> alpha_scale; |
| 353 | }; | 357 | }; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index a613fe136..d1def2f3b 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -8,6 +8,8 @@ | |||
| 8 | #include <glad/glad.h> | 8 | #include <glad/glad.h> |
| 9 | 9 | ||
| 10 | #include "common/color.h" | 10 | #include "common/color.h" |
| 11 | #include "common/file_util.h" | ||
| 12 | #include "common/make_unique.h" | ||
| 11 | #include "common/math_util.h" | 13 | #include "common/math_util.h" |
| 12 | #include "common/microprofile.h" | 14 | #include "common/microprofile.h" |
| 13 | #include "common/profiler.h" | 15 | #include "common/profiler.h" |
| @@ -19,7 +21,7 @@ | |||
| 19 | #include "video_core/pica.h" | 21 | #include "video_core/pica.h" |
| 20 | #include "video_core/utils.h" | 22 | #include "video_core/utils.h" |
| 21 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 23 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 22 | #include "video_core/renderer_opengl/gl_shaders.h" | 24 | #include "video_core/renderer_opengl/gl_shader_gen.h" |
| 23 | #include "video_core/renderer_opengl/gl_shader_util.h" | 25 | #include "video_core/renderer_opengl/gl_shader_util.h" |
| 24 | #include "video_core/renderer_opengl/pica_to_gl.h" | 26 | #include "video_core/renderer_opengl/pica_to_gl.h" |
| 25 | 27 | ||
| @@ -38,36 +40,6 @@ RasterizerOpenGL::RasterizerOpenGL() : last_fb_color_addr(0), last_fb_depth_addr | |||
| 38 | RasterizerOpenGL::~RasterizerOpenGL() { } | 40 | RasterizerOpenGL::~RasterizerOpenGL() { } |
| 39 | 41 | ||
| 40 | void RasterizerOpenGL::InitObjects() { | 42 | void RasterizerOpenGL::InitObjects() { |
| 41 | // Create the hardware shader program and get attrib/uniform locations | ||
| 42 | shader.Create(GLShaders::g_vertex_shader_hw, GLShaders::g_fragment_shader_hw); | ||
| 43 | attrib_position = glGetAttribLocation(shader.handle, "vert_position"); | ||
| 44 | attrib_color = glGetAttribLocation(shader.handle, "vert_color"); | ||
| 45 | attrib_texcoords = glGetAttribLocation(shader.handle, "vert_texcoords"); | ||
| 46 | |||
| 47 | uniform_alphatest_enabled = glGetUniformLocation(shader.handle, "alphatest_enabled"); | ||
| 48 | uniform_alphatest_func = glGetUniformLocation(shader.handle, "alphatest_func"); | ||
| 49 | uniform_alphatest_ref = glGetUniformLocation(shader.handle, "alphatest_ref"); | ||
| 50 | |||
| 51 | uniform_tex = glGetUniformLocation(shader.handle, "tex"); | ||
| 52 | |||
| 53 | uniform_tev_combiner_buffer_color = glGetUniformLocation(shader.handle, "tev_combiner_buffer_color"); | ||
| 54 | |||
| 55 | const auto tev_stages = Pica::g_state.regs.GetTevStages(); | ||
| 56 | for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { | ||
| 57 | auto& uniform_tev_cfg = uniform_tev_cfgs[tev_stage_index]; | ||
| 58 | |||
| 59 | std::string tev_ref_str = "tev_cfgs[" + std::to_string(tev_stage_index) + "]"; | ||
| 60 | uniform_tev_cfg.enabled = glGetUniformLocation(shader.handle, (tev_ref_str + ".enabled").c_str()); | ||
| 61 | uniform_tev_cfg.color_sources = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_sources").c_str()); | ||
| 62 | uniform_tev_cfg.alpha_sources = glGetUniformLocation(shader.handle, (tev_ref_str + ".alpha_sources").c_str()); | ||
| 63 | uniform_tev_cfg.color_modifiers = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_modifiers").c_str()); | ||
| 64 | uniform_tev_cfg.alpha_modifiers = glGetUniformLocation(shader.handle, (tev_ref_str + ".alpha_modifiers").c_str()); | ||
| 65 | uniform_tev_cfg.color_alpha_op = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_alpha_op").c_str()); | ||
| 66 | uniform_tev_cfg.color_alpha_multiplier = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_alpha_multiplier").c_str()); | ||
| 67 | uniform_tev_cfg.const_color = glGetUniformLocation(shader.handle, (tev_ref_str + ".const_color").c_str()); | ||
| 68 | uniform_tev_cfg.updates_combiner_buffer_color_alpha = glGetUniformLocation(shader.handle, (tev_ref_str + ".updates_combiner_buffer_color_alpha").c_str()); | ||
| 69 | } | ||
| 70 | |||
| 71 | // Create sampler objects | 43 | // Create sampler objects |
| 72 | for (size_t i = 0; i < texture_samplers.size(); ++i) { | 44 | for (size_t i = 0; i < texture_samplers.size(); ++i) { |
| 73 | texture_samplers[i].Create(); | 45 | texture_samplers[i].Create(); |
| @@ -78,29 +50,25 @@ void RasterizerOpenGL::InitObjects() { | |||
| 78 | vertex_buffer.Create(); | 50 | vertex_buffer.Create(); |
| 79 | vertex_array.Create(); | 51 | vertex_array.Create(); |
| 80 | 52 | ||
| 81 | // Update OpenGL state | ||
| 82 | state.draw.vertex_array = vertex_array.handle; | 53 | state.draw.vertex_array = vertex_array.handle; |
| 83 | state.draw.vertex_buffer = vertex_buffer.handle; | 54 | state.draw.vertex_buffer = vertex_buffer.handle; |
| 84 | state.draw.shader_program = shader.handle; | ||
| 85 | |||
| 86 | state.Apply(); | 55 | state.Apply(); |
| 87 | 56 | ||
| 88 | // Set the texture samplers to correspond to different texture units | ||
| 89 | glUniform1i(uniform_tex, 0); | ||
| 90 | glUniform1i(uniform_tex + 1, 1); | ||
| 91 | glUniform1i(uniform_tex + 2, 2); | ||
| 92 | |||
| 93 | // Set vertex attributes | 57 | // Set vertex attributes |
| 94 | glVertexAttribPointer(attrib_position, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); | 58 | glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); |
| 95 | glVertexAttribPointer(attrib_color, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); | 59 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION); |
| 96 | glVertexAttribPointer(attrib_texcoords, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); | 60 | |
| 97 | glVertexAttribPointer(attrib_texcoords + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); | 61 | glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); |
| 98 | glVertexAttribPointer(attrib_texcoords + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); | 62 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_COLOR); |
| 99 | glEnableVertexAttribArray(attrib_position); | 63 | |
| 100 | glEnableVertexAttribArray(attrib_color); | 64 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); |
| 101 | glEnableVertexAttribArray(attrib_texcoords); | 65 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); |
| 102 | glEnableVertexAttribArray(attrib_texcoords + 1); | 66 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); |
| 103 | glEnableVertexAttribArray(attrib_texcoords + 2); | 67 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0); |
| 68 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD1); | ||
| 69 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD2); | ||
| 70 | |||
| 71 | SetShader(); | ||
| 104 | 72 | ||
| 105 | // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation | 73 | // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation |
| 106 | fb_color_texture.texture.Create(); | 74 | fb_color_texture.texture.Create(); |
| @@ -150,61 +118,15 @@ void RasterizerOpenGL::InitObjects() { | |||
| 150 | } | 118 | } |
| 151 | 119 | ||
| 152 | void RasterizerOpenGL::Reset() { | 120 | void RasterizerOpenGL::Reset() { |
| 153 | const auto& regs = Pica::g_state.regs; | ||
| 154 | |||
| 155 | SyncCullMode(); | 121 | SyncCullMode(); |
| 156 | SyncBlendEnabled(); | 122 | SyncBlendEnabled(); |
| 157 | SyncBlendFuncs(); | 123 | SyncBlendFuncs(); |
| 158 | SyncBlendColor(); | 124 | SyncBlendColor(); |
| 159 | SyncAlphaTest(); | ||
| 160 | SyncLogicOp(); | 125 | SyncLogicOp(); |
| 161 | SyncStencilTest(); | 126 | SyncStencilTest(); |
| 162 | SyncDepthTest(); | 127 | SyncDepthTest(); |
| 163 | 128 | ||
| 164 | // TEV stage 0 | 129 | SetShader(); |
| 165 | SyncTevSources(0, regs.tev_stage0); | ||
| 166 | SyncTevModifiers(0, regs.tev_stage0); | ||
| 167 | SyncTevOps(0, regs.tev_stage0); | ||
| 168 | SyncTevColor(0, regs.tev_stage0); | ||
| 169 | SyncTevMultipliers(0, regs.tev_stage0); | ||
| 170 | |||
| 171 | // TEV stage 1 | ||
| 172 | SyncTevSources(1, regs.tev_stage1); | ||
| 173 | SyncTevModifiers(1, regs.tev_stage1); | ||
| 174 | SyncTevOps(1, regs.tev_stage1); | ||
| 175 | SyncTevColor(1, regs.tev_stage1); | ||
| 176 | SyncTevMultipliers(1, regs.tev_stage1); | ||
| 177 | |||
| 178 | // TEV stage 2 | ||
| 179 | SyncTevSources(2, regs.tev_stage2); | ||
| 180 | SyncTevModifiers(2, regs.tev_stage2); | ||
| 181 | SyncTevOps(2, regs.tev_stage2); | ||
| 182 | SyncTevColor(2, regs.tev_stage2); | ||
| 183 | SyncTevMultipliers(2, regs.tev_stage2); | ||
| 184 | |||
| 185 | // TEV stage 3 | ||
| 186 | SyncTevSources(3, regs.tev_stage3); | ||
| 187 | SyncTevModifiers(3, regs.tev_stage3); | ||
| 188 | SyncTevOps(3, regs.tev_stage3); | ||
| 189 | SyncTevColor(3, regs.tev_stage3); | ||
| 190 | SyncTevMultipliers(3, regs.tev_stage3); | ||
| 191 | |||
| 192 | // TEV stage 4 | ||
| 193 | SyncTevSources(4, regs.tev_stage4); | ||
| 194 | SyncTevModifiers(4, regs.tev_stage4); | ||
| 195 | SyncTevOps(4, regs.tev_stage4); | ||
| 196 | SyncTevColor(4, regs.tev_stage4); | ||
| 197 | SyncTevMultipliers(4, regs.tev_stage4); | ||
| 198 | |||
| 199 | // TEV stage 5 | ||
| 200 | SyncTevSources(5, regs.tev_stage5); | ||
| 201 | SyncTevModifiers(5, regs.tev_stage5); | ||
| 202 | SyncTevOps(5, regs.tev_stage5); | ||
| 203 | SyncTevColor(5, regs.tev_stage5); | ||
| 204 | SyncTevMultipliers(5, regs.tev_stage5); | ||
| 205 | |||
| 206 | SyncCombinerColor(); | ||
| 207 | SyncCombinerWriteFlags(); | ||
| 208 | 130 | ||
| 209 | res_cache.FullFlush(); | 131 | res_cache.FullFlush(); |
| 210 | } | 132 | } |
| @@ -221,6 +143,11 @@ void RasterizerOpenGL::DrawTriangles() { | |||
| 221 | SyncFramebuffer(); | 143 | SyncFramebuffer(); |
| 222 | SyncDrawState(); | 144 | SyncDrawState(); |
| 223 | 145 | ||
| 146 | if (state.draw.shader_dirty) { | ||
| 147 | SetShader(); | ||
| 148 | state.draw.shader_dirty = false; | ||
| 149 | } | ||
| 150 | |||
| 224 | glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW); | 151 | glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW); |
| 225 | glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size()); | 152 | glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size()); |
| 226 | 153 | ||
| @@ -272,6 +199,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 272 | // Alpha test | 199 | // Alpha test |
| 273 | case PICA_REG_INDEX(output_merger.alpha_test): | 200 | case PICA_REG_INDEX(output_merger.alpha_test): |
| 274 | SyncAlphaTest(); | 201 | SyncAlphaTest(); |
| 202 | state.draw.shader_dirty = true; | ||
| 275 | break; | 203 | break; |
| 276 | 204 | ||
| 277 | // Stencil test | 205 | // Stencil test |
| @@ -290,117 +218,57 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 290 | SyncLogicOp(); | 218 | SyncLogicOp(); |
| 291 | break; | 219 | break; |
| 292 | 220 | ||
| 293 | // TEV stage 0 | 221 | // TEV stages |
| 294 | case PICA_REG_INDEX(tev_stage0.color_source1): | 222 | case PICA_REG_INDEX(tev_stage0.color_source1): |
| 295 | SyncTevSources(0, regs.tev_stage0); | ||
| 296 | break; | ||
| 297 | case PICA_REG_INDEX(tev_stage0.color_modifier1): | 223 | case PICA_REG_INDEX(tev_stage0.color_modifier1): |
| 298 | SyncTevModifiers(0, regs.tev_stage0); | ||
| 299 | break; | ||
| 300 | case PICA_REG_INDEX(tev_stage0.color_op): | 224 | case PICA_REG_INDEX(tev_stage0.color_op): |
| 301 | SyncTevOps(0, regs.tev_stage0); | ||
| 302 | break; | ||
| 303 | case PICA_REG_INDEX(tev_stage0.const_r): | ||
| 304 | SyncTevColor(0, regs.tev_stage0); | ||
| 305 | break; | ||
| 306 | case PICA_REG_INDEX(tev_stage0.color_scale): | 225 | case PICA_REG_INDEX(tev_stage0.color_scale): |
| 307 | SyncTevMultipliers(0, regs.tev_stage0); | ||
| 308 | break; | ||
| 309 | |||
| 310 | // TEV stage 1 | ||
| 311 | case PICA_REG_INDEX(tev_stage1.color_source1): | 226 | case PICA_REG_INDEX(tev_stage1.color_source1): |
| 312 | SyncTevSources(1, regs.tev_stage1); | ||
| 313 | break; | ||
| 314 | case PICA_REG_INDEX(tev_stage1.color_modifier1): | 227 | case PICA_REG_INDEX(tev_stage1.color_modifier1): |
| 315 | SyncTevModifiers(1, regs.tev_stage1); | ||
| 316 | break; | ||
| 317 | case PICA_REG_INDEX(tev_stage1.color_op): | 228 | case PICA_REG_INDEX(tev_stage1.color_op): |
| 318 | SyncTevOps(1, regs.tev_stage1); | ||
| 319 | break; | ||
| 320 | case PICA_REG_INDEX(tev_stage1.const_r): | ||
| 321 | SyncTevColor(1, regs.tev_stage1); | ||
| 322 | break; | ||
| 323 | case PICA_REG_INDEX(tev_stage1.color_scale): | 229 | case PICA_REG_INDEX(tev_stage1.color_scale): |
| 324 | SyncTevMultipliers(1, regs.tev_stage1); | ||
| 325 | break; | ||
| 326 | |||
| 327 | // TEV stage 2 | ||
| 328 | case PICA_REG_INDEX(tev_stage2.color_source1): | 230 | case PICA_REG_INDEX(tev_stage2.color_source1): |
| 329 | SyncTevSources(2, regs.tev_stage2); | ||
| 330 | break; | ||
| 331 | case PICA_REG_INDEX(tev_stage2.color_modifier1): | 231 | case PICA_REG_INDEX(tev_stage2.color_modifier1): |
| 332 | SyncTevModifiers(2, regs.tev_stage2); | ||
| 333 | break; | ||
| 334 | case PICA_REG_INDEX(tev_stage2.color_op): | 232 | case PICA_REG_INDEX(tev_stage2.color_op): |
| 335 | SyncTevOps(2, regs.tev_stage2); | ||
| 336 | break; | ||
| 337 | case PICA_REG_INDEX(tev_stage2.const_r): | ||
| 338 | SyncTevColor(2, regs.tev_stage2); | ||
| 339 | break; | ||
| 340 | case PICA_REG_INDEX(tev_stage2.color_scale): | 233 | case PICA_REG_INDEX(tev_stage2.color_scale): |
| 341 | SyncTevMultipliers(2, regs.tev_stage2); | ||
| 342 | break; | ||
| 343 | |||
| 344 | // TEV stage 3 | ||
| 345 | case PICA_REG_INDEX(tev_stage3.color_source1): | 234 | case PICA_REG_INDEX(tev_stage3.color_source1): |
| 346 | SyncTevSources(3, regs.tev_stage3); | ||
| 347 | break; | ||
| 348 | case PICA_REG_INDEX(tev_stage3.color_modifier1): | 235 | case PICA_REG_INDEX(tev_stage3.color_modifier1): |
| 349 | SyncTevModifiers(3, regs.tev_stage3); | ||
| 350 | break; | ||
| 351 | case PICA_REG_INDEX(tev_stage3.color_op): | 236 | case PICA_REG_INDEX(tev_stage3.color_op): |
| 352 | SyncTevOps(3, regs.tev_stage3); | ||
| 353 | break; | ||
| 354 | case PICA_REG_INDEX(tev_stage3.const_r): | ||
| 355 | SyncTevColor(3, regs.tev_stage3); | ||
| 356 | break; | ||
| 357 | case PICA_REG_INDEX(tev_stage3.color_scale): | 237 | case PICA_REG_INDEX(tev_stage3.color_scale): |
| 358 | SyncTevMultipliers(3, regs.tev_stage3); | ||
| 359 | break; | ||
| 360 | |||
| 361 | // TEV stage 4 | ||
| 362 | case PICA_REG_INDEX(tev_stage4.color_source1): | 238 | case PICA_REG_INDEX(tev_stage4.color_source1): |
| 363 | SyncTevSources(4, regs.tev_stage4); | ||
| 364 | break; | ||
| 365 | case PICA_REG_INDEX(tev_stage4.color_modifier1): | 239 | case PICA_REG_INDEX(tev_stage4.color_modifier1): |
| 366 | SyncTevModifiers(4, regs.tev_stage4); | ||
| 367 | break; | ||
| 368 | case PICA_REG_INDEX(tev_stage4.color_op): | 240 | case PICA_REG_INDEX(tev_stage4.color_op): |
| 369 | SyncTevOps(4, regs.tev_stage4); | 241 | case PICA_REG_INDEX(tev_stage4.color_scale): |
| 242 | case PICA_REG_INDEX(tev_stage5.color_source1): | ||
| 243 | case PICA_REG_INDEX(tev_stage5.color_modifier1): | ||
| 244 | case PICA_REG_INDEX(tev_stage5.color_op): | ||
| 245 | case PICA_REG_INDEX(tev_stage5.color_scale): | ||
| 246 | case PICA_REG_INDEX(tev_combiner_buffer_input): | ||
| 247 | state.draw.shader_dirty = true; | ||
| 370 | break; | 248 | break; |
| 371 | case PICA_REG_INDEX(tev_stage4.const_r): | 249 | case PICA_REG_INDEX(tev_stage0.const_r): |
| 372 | SyncTevColor(4, regs.tev_stage4); | 250 | SyncTevConstColor(0, regs.tev_stage0); |
| 373 | break; | 251 | break; |
| 374 | case PICA_REG_INDEX(tev_stage4.color_scale): | 252 | case PICA_REG_INDEX(tev_stage1.const_r): |
| 375 | SyncTevMultipliers(4, regs.tev_stage4); | 253 | SyncTevConstColor(1, regs.tev_stage1); |
| 376 | break; | 254 | break; |
| 377 | 255 | case PICA_REG_INDEX(tev_stage2.const_r): | |
| 378 | // TEV stage 5 | 256 | SyncTevConstColor(2, regs.tev_stage2); |
| 379 | case PICA_REG_INDEX(tev_stage5.color_source1): | ||
| 380 | SyncTevSources(5, regs.tev_stage5); | ||
| 381 | break; | 257 | break; |
| 382 | case PICA_REG_INDEX(tev_stage5.color_modifier1): | 258 | case PICA_REG_INDEX(tev_stage3.const_r): |
| 383 | SyncTevModifiers(5, regs.tev_stage5); | 259 | SyncTevConstColor(3, regs.tev_stage3); |
| 384 | break; | 260 | break; |
| 385 | case PICA_REG_INDEX(tev_stage5.color_op): | 261 | case PICA_REG_INDEX(tev_stage4.const_r): |
| 386 | SyncTevOps(5, regs.tev_stage5); | 262 | SyncTevConstColor(4, regs.tev_stage4); |
| 387 | break; | 263 | break; |
| 388 | case PICA_REG_INDEX(tev_stage5.const_r): | 264 | case PICA_REG_INDEX(tev_stage5.const_r): |
| 389 | SyncTevColor(5, regs.tev_stage5); | 265 | SyncTevConstColor(5, regs.tev_stage5); |
| 390 | break; | ||
| 391 | case PICA_REG_INDEX(tev_stage5.color_scale): | ||
| 392 | SyncTevMultipliers(5, regs.tev_stage5); | ||
| 393 | break; | 266 | break; |
| 394 | 267 | ||
| 395 | // TEV combiner buffer color | 268 | // TEV combiner buffer color |
| 396 | case PICA_REG_INDEX(tev_combiner_buffer_color): | 269 | case PICA_REG_INDEX(tev_combiner_buffer_color): |
| 397 | SyncCombinerColor(); | 270 | SyncCombinerColor(); |
| 398 | break; | 271 | break; |
| 399 | |||
| 400 | // TEV combiner buffer write flags | ||
| 401 | case PICA_REG_INDEX(tev_combiner_buffer_input): | ||
| 402 | SyncCombinerWriteFlags(); | ||
| 403 | break; | ||
| 404 | } | 272 | } |
| 405 | } | 273 | } |
| 406 | 274 | ||
| @@ -592,6 +460,41 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica:: | |||
| 592 | state.Apply(); | 460 | state.Apply(); |
| 593 | } | 461 | } |
| 594 | 462 | ||
| 463 | void RasterizerOpenGL::SetShader() { | ||
| 464 | PicaShaderConfig config = PicaShaderConfig::CurrentConfig(); | ||
| 465 | std::unique_ptr<PicaShader> shader = Common::make_unique<PicaShader>(); | ||
| 466 | |||
| 467 | // Find (or generate) the GLSL shader for the current TEV state | ||
| 468 | auto cached_shader = shader_cache.find(config); | ||
| 469 | if (cached_shader != shader_cache.end()) { | ||
| 470 | current_shader = cached_shader->second.get(); | ||
| 471 | |||
| 472 | state.draw.shader_program = current_shader->shader.handle; | ||
| 473 | state.Apply(); | ||
| 474 | } else { | ||
| 475 | LOG_DEBUG(Render_OpenGL, "Creating new shader"); | ||
| 476 | |||
| 477 | shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str()); | ||
| 478 | |||
| 479 | state.draw.shader_program = shader->shader.handle; | ||
| 480 | state.Apply(); | ||
| 481 | |||
| 482 | // Set the texture samplers to correspond to different texture units | ||
| 483 | glUniform1i(PicaShader::Uniform::Texture0, 0); | ||
| 484 | glUniform1i(PicaShader::Uniform::Texture1, 1); | ||
| 485 | glUniform1i(PicaShader::Uniform::Texture2, 2); | ||
| 486 | |||
| 487 | current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get(); | ||
| 488 | } | ||
| 489 | |||
| 490 | // Update uniforms | ||
| 491 | SyncAlphaTest(); | ||
| 492 | SyncCombinerColor(); | ||
| 493 | auto& tev_stages = Pica::g_state.regs.GetTevStages(); | ||
| 494 | for (int index = 0; index < tev_stages.size(); ++index) | ||
| 495 | SyncTevConstColor(index, tev_stages[index]); | ||
| 496 | } | ||
| 497 | |||
| 595 | void RasterizerOpenGL::SyncFramebuffer() { | 498 | void RasterizerOpenGL::SyncFramebuffer() { |
| 596 | const auto& regs = Pica::g_state.regs; | 499 | const auto& regs = Pica::g_state.regs; |
| 597 | 500 | ||
| @@ -712,9 +615,7 @@ void RasterizerOpenGL::SyncBlendColor() { | |||
| 712 | 615 | ||
| 713 | void RasterizerOpenGL::SyncAlphaTest() { | 616 | void RasterizerOpenGL::SyncAlphaTest() { |
| 714 | const auto& regs = Pica::g_state.regs; | 617 | const auto& regs = Pica::g_state.regs; |
| 715 | glUniform1i(uniform_alphatest_enabled, regs.output_merger.alpha_test.enable); | 618 | glUniform1i(PicaShader::Uniform::AlphaTestRef, regs.output_merger.alpha_test.ref); |
| 716 | glUniform1i(uniform_alphatest_func, (GLint)regs.output_merger.alpha_test.func.Value()); | ||
| 717 | glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); | ||
| 718 | } | 619 | } |
| 719 | 620 | ||
| 720 | void RasterizerOpenGL::SyncLogicOp() { | 621 | void RasterizerOpenGL::SyncLogicOp() { |
| @@ -744,56 +645,14 @@ void RasterizerOpenGL::SyncDepthTest() { | |||
| 744 | state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE; | 645 | state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE; |
| 745 | } | 646 | } |
| 746 | 647 | ||
| 747 | void RasterizerOpenGL::SyncTevSources(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { | ||
| 748 | GLint color_srcs[3] = { (GLint)config.color_source1.Value(), | ||
| 749 | (GLint)config.color_source2.Value(), | ||
| 750 | (GLint)config.color_source3.Value() }; | ||
| 751 | GLint alpha_srcs[3] = { (GLint)config.alpha_source1.Value(), | ||
| 752 | (GLint)config.alpha_source2.Value(), | ||
| 753 | (GLint)config.alpha_source3.Value() }; | ||
| 754 | |||
| 755 | glUniform3iv(uniform_tev_cfgs[stage_index].color_sources, 1, color_srcs); | ||
| 756 | glUniform3iv(uniform_tev_cfgs[stage_index].alpha_sources, 1, alpha_srcs); | ||
| 757 | } | ||
| 758 | |||
| 759 | void RasterizerOpenGL::SyncTevModifiers(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { | ||
| 760 | GLint color_mods[3] = { (GLint)config.color_modifier1.Value(), | ||
| 761 | (GLint)config.color_modifier2.Value(), | ||
| 762 | (GLint)config.color_modifier3.Value() }; | ||
| 763 | GLint alpha_mods[3] = { (GLint)config.alpha_modifier1.Value(), | ||
| 764 | (GLint)config.alpha_modifier2.Value(), | ||
| 765 | (GLint)config.alpha_modifier3.Value() }; | ||
| 766 | |||
| 767 | glUniform3iv(uniform_tev_cfgs[stage_index].color_modifiers, 1, color_mods); | ||
| 768 | glUniform3iv(uniform_tev_cfgs[stage_index].alpha_modifiers, 1, alpha_mods); | ||
| 769 | } | ||
| 770 | |||
| 771 | void RasterizerOpenGL::SyncTevOps(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { | ||
| 772 | glUniform2i(uniform_tev_cfgs[stage_index].color_alpha_op, (GLint)config.color_op.Value(), (GLint)config.alpha_op.Value()); | ||
| 773 | } | ||
| 774 | |||
| 775 | void RasterizerOpenGL::SyncTevColor(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { | ||
| 776 | auto const_color = PicaToGL::ColorRGBA8(config.const_color); | ||
| 777 | glUniform4fv(uniform_tev_cfgs[stage_index].const_color, 1, const_color.data()); | ||
| 778 | } | ||
| 779 | |||
| 780 | void RasterizerOpenGL::SyncTevMultipliers(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { | ||
| 781 | glUniform2i(uniform_tev_cfgs[stage_index].color_alpha_multiplier, config.GetColorMultiplier(), config.GetAlphaMultiplier()); | ||
| 782 | } | ||
| 783 | |||
| 784 | void RasterizerOpenGL::SyncCombinerColor() { | 648 | void RasterizerOpenGL::SyncCombinerColor() { |
| 785 | auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); | 649 | auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); |
| 786 | glUniform4fv(uniform_tev_combiner_buffer_color, 1, combiner_color.data()); | 650 | glUniform4fv(PicaShader::Uniform::TevCombinerBufferColor, 1, combiner_color.data()); |
| 787 | } | 651 | } |
| 788 | 652 | ||
| 789 | void RasterizerOpenGL::SyncCombinerWriteFlags() { | 653 | void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevStageConfig& tev_stage) { |
| 790 | const auto& regs = Pica::g_state.regs; | 654 | auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color); |
| 791 | const auto tev_stages = regs.GetTevStages(); | 655 | glUniform4fv(PicaShader::Uniform::TevConstColors + stage_index, 1, const_color.data()); |
| 792 | for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { | ||
| 793 | glUniform2i(uniform_tev_cfgs[tev_stage_index].updates_combiner_buffer_color_alpha, | ||
| 794 | regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index), | ||
| 795 | regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)); | ||
| 796 | } | ||
| 797 | } | 656 | } |
| 798 | 657 | ||
| 799 | void RasterizerOpenGL::SyncDrawState() { | 658 | void RasterizerOpenGL::SyncDrawState() { |
| @@ -824,12 +683,6 @@ void RasterizerOpenGL::SyncDrawState() { | |||
| 824 | } | 683 | } |
| 825 | } | 684 | } |
| 826 | 685 | ||
| 827 | // Skip processing TEV stages that simply pass the previous stage results through | ||
| 828 | const auto tev_stages = regs.GetTevStages(); | ||
| 829 | for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { | ||
| 830 | glUniform1i(uniform_tev_cfgs[tev_stage_index].enabled, !IsPassThroughTevStage(tev_stages[tev_stage_index])); | ||
| 831 | } | ||
| 832 | |||
| 833 | state.Apply(); | 686 | state.Apply(); |
| 834 | } | 687 | } |
| 835 | 688 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 1fe307846..872cae7da 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -4,15 +4,104 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | ||
| 8 | #include <cstring> | ||
| 9 | #include <memory> | ||
| 7 | #include <vector> | 10 | #include <vector> |
| 11 | #include <unordered_map> | ||
| 8 | 12 | ||
| 9 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "common/hash.h" | ||
| 10 | 15 | ||
| 16 | #include "video_core/pica.h" | ||
| 11 | #include "video_core/hwrasterizer_base.h" | 17 | #include "video_core/hwrasterizer_base.h" |
| 12 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | 18 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" |
| 13 | #include "video_core/renderer_opengl/gl_state.h" | 19 | #include "video_core/renderer_opengl/gl_state.h" |
| 14 | #include "video_core/shader/shader_interpreter.h" | 20 | #include "video_core/shader/shader_interpreter.h" |
| 15 | 21 | ||
| 22 | /** | ||
| 23 | * This struct contains all state used to generate the GLSL shader program that emulates the current | ||
| 24 | * Pica register configuration. This struct is used as a cache key for generated GLSL shader | ||
| 25 | * programs. The functions in gl_shader_gen.cpp should retrieve state from this struct only, not by | ||
| 26 | * directly accessing Pica registers. This should reduce the risk of bugs in shader generation where | ||
| 27 | * Pica state is not being captured in the shader cache key, thereby resulting in (what should be) | ||
| 28 | * two separate shaders sharing the same key. | ||
| 29 | */ | ||
| 30 | struct PicaShaderConfig { | ||
| 31 | /// Construct a PicaShaderConfig with the current Pica register configuration. | ||
| 32 | static PicaShaderConfig CurrentConfig() { | ||
| 33 | PicaShaderConfig res; | ||
| 34 | const auto& regs = Pica::g_state.regs; | ||
| 35 | |||
| 36 | res.alpha_test_func = regs.output_merger.alpha_test.enable ? | ||
| 37 | regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always; | ||
| 38 | |||
| 39 | // Copy relevant TevStageConfig fields only. We're doing this manually (instead of calling | ||
| 40 | // the GetTevStages() function) because BitField explicitly disables copies. | ||
| 41 | |||
| 42 | res.tev_stages[0].sources_raw = regs.tev_stage0.sources_raw; | ||
| 43 | res.tev_stages[1].sources_raw = regs.tev_stage1.sources_raw; | ||
| 44 | res.tev_stages[2].sources_raw = regs.tev_stage2.sources_raw; | ||
| 45 | res.tev_stages[3].sources_raw = regs.tev_stage3.sources_raw; | ||
| 46 | res.tev_stages[4].sources_raw = regs.tev_stage4.sources_raw; | ||
| 47 | res.tev_stages[5].sources_raw = regs.tev_stage5.sources_raw; | ||
| 48 | |||
| 49 | res.tev_stages[0].modifiers_raw = regs.tev_stage0.modifiers_raw; | ||
| 50 | res.tev_stages[1].modifiers_raw = regs.tev_stage1.modifiers_raw; | ||
| 51 | res.tev_stages[2].modifiers_raw = regs.tev_stage2.modifiers_raw; | ||
| 52 | res.tev_stages[3].modifiers_raw = regs.tev_stage3.modifiers_raw; | ||
| 53 | res.tev_stages[4].modifiers_raw = regs.tev_stage4.modifiers_raw; | ||
| 54 | res.tev_stages[5].modifiers_raw = regs.tev_stage5.modifiers_raw; | ||
| 55 | |||
| 56 | res.tev_stages[0].ops_raw = regs.tev_stage0.ops_raw; | ||
| 57 | res.tev_stages[1].ops_raw = regs.tev_stage1.ops_raw; | ||
| 58 | res.tev_stages[2].ops_raw = regs.tev_stage2.ops_raw; | ||
| 59 | res.tev_stages[3].ops_raw = regs.tev_stage3.ops_raw; | ||
| 60 | res.tev_stages[4].ops_raw = regs.tev_stage4.ops_raw; | ||
| 61 | res.tev_stages[5].ops_raw = regs.tev_stage5.ops_raw; | ||
| 62 | |||
| 63 | res.tev_stages[0].scales_raw = regs.tev_stage0.scales_raw; | ||
| 64 | res.tev_stages[1].scales_raw = regs.tev_stage1.scales_raw; | ||
| 65 | res.tev_stages[2].scales_raw = regs.tev_stage2.scales_raw; | ||
| 66 | res.tev_stages[3].scales_raw = regs.tev_stage3.scales_raw; | ||
| 67 | res.tev_stages[4].scales_raw = regs.tev_stage4.scales_raw; | ||
| 68 | res.tev_stages[5].scales_raw = regs.tev_stage5.scales_raw; | ||
| 69 | |||
| 70 | res.combiner_buffer_input = | ||
| 71 | regs.tev_combiner_buffer_input.update_mask_rgb.Value() | | ||
| 72 | regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; | ||
| 73 | |||
| 74 | return res; | ||
| 75 | } | ||
| 76 | |||
| 77 | bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const { | ||
| 78 | return (stage_index < 4) && (combiner_buffer_input & (1 << stage_index)); | ||
| 79 | } | ||
| 80 | |||
| 81 | bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const { | ||
| 82 | return (stage_index < 4) && ((combiner_buffer_input >> 4) & (1 << stage_index)); | ||
| 83 | } | ||
| 84 | |||
| 85 | bool operator ==(const PicaShaderConfig& o) const { | ||
| 86 | return std::memcmp(this, &o, sizeof(PicaShaderConfig)) == 0; | ||
| 87 | }; | ||
| 88 | |||
| 89 | Pica::Regs::CompareFunc alpha_test_func; | ||
| 90 | std::array<Pica::Regs::TevStageConfig, 6> tev_stages = {}; | ||
| 91 | u8 combiner_buffer_input; | ||
| 92 | }; | ||
| 93 | |||
| 94 | namespace std { | ||
| 95 | |||
| 96 | template <> | ||
| 97 | struct hash<PicaShaderConfig> { | ||
| 98 | size_t operator()(const PicaShaderConfig& k) const { | ||
| 99 | return Common::ComputeHash64(&k, sizeof(PicaShaderConfig)); | ||
| 100 | } | ||
| 101 | }; | ||
| 102 | |||
| 103 | } // namespace std | ||
| 104 | |||
| 16 | class RasterizerOpenGL : public HWRasterizer { | 105 | class RasterizerOpenGL : public HWRasterizer { |
| 17 | public: | 106 | public: |
| 18 | 107 | ||
| @@ -45,20 +134,24 @@ public: | |||
| 45 | /// Notify rasterizer that a 3DS memory region has been changed | 134 | /// Notify rasterizer that a 3DS memory region has been changed |
| 46 | void NotifyFlush(PAddr addr, u32 size) override; | 135 | void NotifyFlush(PAddr addr, u32 size) override; |
| 47 | 136 | ||
| 48 | private: | 137 | /// OpenGL shader generated for a given Pica register state |
| 49 | /// Structure used for managing texture environment states | 138 | struct PicaShader { |
| 50 | struct TEVConfigUniforms { | 139 | /// OpenGL shader resource |
| 51 | GLuint enabled; | 140 | OGLShader shader; |
| 52 | GLuint color_sources; | 141 | |
| 53 | GLuint alpha_sources; | 142 | /// Fragment shader uniforms |
| 54 | GLuint color_modifiers; | 143 | enum Uniform : GLuint { |
| 55 | GLuint alpha_modifiers; | 144 | AlphaTestRef = 0, |
| 56 | GLuint color_alpha_op; | 145 | TevConstColors = 1, |
| 57 | GLuint color_alpha_multiplier; | 146 | Texture0 = 7, |
| 58 | GLuint const_color; | 147 | Texture1 = 8, |
| 59 | GLuint updates_combiner_buffer_color_alpha; | 148 | Texture2 = 9, |
| 149 | TevCombinerBufferColor = 10, | ||
| 150 | }; | ||
| 60 | }; | 151 | }; |
| 61 | 152 | ||
| 153 | private: | ||
| 154 | |||
| 62 | /// Structure used for storing information about color textures | 155 | /// Structure used for storing information about color textures |
| 63 | struct TextureInfo { | 156 | struct TextureInfo { |
| 64 | OGLTexture texture; | 157 | OGLTexture texture; |
| @@ -129,6 +222,9 @@ private: | |||
| 129 | /// Reconfigure the OpenGL depth texture to use the given format and dimensions | 222 | /// Reconfigure the OpenGL depth texture to use the given format and dimensions |
| 130 | void ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height); | 223 | void ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height); |
| 131 | 224 | ||
| 225 | /// Sets the OpenGL shader in accordance with the current PICA register state | ||
| 226 | void SetShader(); | ||
| 227 | |||
| 132 | /// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer | 228 | /// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer |
| 133 | void SyncFramebuffer(); | 229 | void SyncFramebuffer(); |
| 134 | 230 | ||
| @@ -156,27 +252,12 @@ private: | |||
| 156 | /// Syncs the depth test states to match the PICA register | 252 | /// Syncs the depth test states to match the PICA register |
| 157 | void SyncDepthTest(); | 253 | void SyncDepthTest(); |
| 158 | 254 | ||
| 159 | /// Syncs the specified TEV stage's color and alpha sources to match the PICA register | 255 | /// Syncs the TEV constant color to match the PICA register |
| 160 | void SyncTevSources(unsigned stage_index, const Pica::Regs::TevStageConfig& config); | 256 | void SyncTevConstColor(int tev_index, const Pica::Regs::TevStageConfig& tev_stage); |
| 161 | |||
| 162 | /// Syncs the specified TEV stage's color and alpha modifiers to match the PICA register | ||
| 163 | void SyncTevModifiers(unsigned stage_index, const Pica::Regs::TevStageConfig& config); | ||
| 164 | |||
| 165 | /// Syncs the specified TEV stage's color and alpha combiner operations to match the PICA register | ||
| 166 | void SyncTevOps(unsigned stage_index, const Pica::Regs::TevStageConfig& config); | ||
| 167 | |||
| 168 | /// Syncs the specified TEV stage's constant color to match the PICA register | ||
| 169 | void SyncTevColor(unsigned stage_index, const Pica::Regs::TevStageConfig& config); | ||
| 170 | |||
| 171 | /// Syncs the specified TEV stage's color and alpha multipliers to match the PICA register | ||
| 172 | void SyncTevMultipliers(unsigned stage_index, const Pica::Regs::TevStageConfig& config); | ||
| 173 | 257 | ||
| 174 | /// Syncs the TEV combiner color buffer to match the PICA register | 258 | /// Syncs the TEV combiner color buffer to match the PICA register |
| 175 | void SyncCombinerColor(); | 259 | void SyncCombinerColor(); |
| 176 | 260 | ||
| 177 | /// Syncs the TEV combiner write flags to match the PICA register | ||
| 178 | void SyncCombinerWriteFlags(); | ||
| 179 | |||
| 180 | /// Syncs the remaining OpenGL drawing state to match the current PICA state | 261 | /// Syncs the remaining OpenGL drawing state to match the current PICA state |
| 181 | void SyncDrawState(); | 262 | void SyncDrawState(); |
| 182 | 263 | ||
| @@ -213,21 +294,11 @@ private: | |||
| 213 | std::array<SamplerInfo, 3> texture_samplers; | 294 | std::array<SamplerInfo, 3> texture_samplers; |
| 214 | TextureInfo fb_color_texture; | 295 | TextureInfo fb_color_texture; |
| 215 | DepthTextureInfo fb_depth_texture; | 296 | DepthTextureInfo fb_depth_texture; |
| 216 | OGLShader shader; | 297 | |
| 298 | std::unordered_map<PicaShaderConfig, std::unique_ptr<PicaShader>> shader_cache; | ||
| 299 | const PicaShader* current_shader = nullptr; | ||
| 300 | |||
| 217 | OGLVertexArray vertex_array; | 301 | OGLVertexArray vertex_array; |
| 218 | OGLBuffer vertex_buffer; | 302 | OGLBuffer vertex_buffer; |
| 219 | OGLFramebuffer framebuffer; | 303 | OGLFramebuffer framebuffer; |
| 220 | |||
| 221 | // Hardware vertex shader | ||
| 222 | GLuint attrib_position; | ||
| 223 | GLuint attrib_color; | ||
| 224 | GLuint attrib_texcoords; | ||
| 225 | |||
| 226 | // Hardware fragment shader | ||
| 227 | GLuint uniform_alphatest_enabled; | ||
| 228 | GLuint uniform_alphatest_func; | ||
| 229 | GLuint uniform_alphatest_ref; | ||
| 230 | GLuint uniform_tex; | ||
| 231 | GLuint uniform_tev_combiner_buffer_color; | ||
| 232 | TEVConfigUniforms uniform_tev_cfgs[6]; | ||
| 233 | }; | 304 | }; |
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index 65034d40d..eb128966c 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h | |||
| @@ -71,7 +71,7 @@ public: | |||
| 71 | /// Creates a new internal OpenGL resource and stores the handle | 71 | /// Creates a new internal OpenGL resource and stores the handle |
| 72 | void Create(const char* vert_shader, const char* frag_shader) { | 72 | void Create(const char* vert_shader, const char* frag_shader) { |
| 73 | if (handle != 0) return; | 73 | if (handle != 0) return; |
| 74 | handle = ShaderUtil::LoadShaders(vert_shader, frag_shader); | 74 | handle = GLShader::LoadProgram(vert_shader, frag_shader); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | /// Deletes the internal OpenGL resource | 77 | /// Deletes the internal OpenGL resource |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp new file mode 100644 index 000000000..d19d15e75 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -0,0 +1,388 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "video_core/pica.h" | ||
| 6 | #include "video_core/renderer_opengl/gl_rasterizer.h" | ||
| 7 | #include "video_core/renderer_opengl/gl_shader_gen.h" | ||
| 8 | |||
| 9 | using Pica::Regs; | ||
| 10 | using TevStageConfig = Regs::TevStageConfig; | ||
| 11 | |||
| 12 | namespace GLShader { | ||
| 13 | |||
| 14 | /// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code) | ||
| 15 | static bool IsPassThroughTevStage(const TevStageConfig& stage) { | ||
| 16 | return (stage.color_op == TevStageConfig::Operation::Replace && | ||
| 17 | stage.alpha_op == TevStageConfig::Operation::Replace && | ||
| 18 | stage.color_source1 == TevStageConfig::Source::Previous && | ||
| 19 | stage.alpha_source1 == TevStageConfig::Source::Previous && | ||
| 20 | stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor && | ||
| 21 | stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha && | ||
| 22 | stage.GetColorMultiplier() == 1 && | ||
| 23 | stage.GetAlphaMultiplier() == 1); | ||
| 24 | } | ||
| 25 | |||
| 26 | /// Writes the specified TEV stage source component(s) | ||
| 27 | static void AppendSource(std::string& out, TevStageConfig::Source source, | ||
| 28 | const std::string& index_name) { | ||
| 29 | using Source = TevStageConfig::Source; | ||
| 30 | switch (source) { | ||
| 31 | case Source::PrimaryColor: | ||
| 32 | out += "primary_color"; | ||
| 33 | break; | ||
| 34 | case Source::PrimaryFragmentColor: | ||
| 35 | // HACK: Until we implement fragment lighting, use primary_color | ||
| 36 | out += "primary_color"; | ||
| 37 | break; | ||
| 38 | case Source::SecondaryFragmentColor: | ||
| 39 | // HACK: Until we implement fragment lighting, use zero | ||
| 40 | out += "vec4(0.0)"; | ||
| 41 | break; | ||
| 42 | case Source::Texture0: | ||
| 43 | out += "texture(tex[0], texcoord[0])"; | ||
| 44 | break; | ||
| 45 | case Source::Texture1: | ||
| 46 | out += "texture(tex[1], texcoord[1])"; | ||
| 47 | break; | ||
| 48 | case Source::Texture2: | ||
| 49 | out += "texture(tex[2], texcoord[2])"; | ||
| 50 | break; | ||
| 51 | case Source::PreviousBuffer: | ||
| 52 | out += "combiner_buffer"; | ||
| 53 | break; | ||
| 54 | case Source::Constant: | ||
| 55 | ((out += "const_color[") += index_name) += ']'; | ||
| 56 | break; | ||
| 57 | case Source::Previous: | ||
| 58 | out += "last_tex_env_out"; | ||
| 59 | break; | ||
| 60 | default: | ||
| 61 | out += "vec4(0.0)"; | ||
| 62 | LOG_CRITICAL(Render_OpenGL, "Unknown source op %u", source); | ||
| 63 | break; | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | /// Writes the color components to use for the specified TEV stage color modifier | ||
| 68 | static void AppendColorModifier(std::string& out, TevStageConfig::ColorModifier modifier, | ||
| 69 | TevStageConfig::Source source, const std::string& index_name) { | ||
| 70 | using ColorModifier = TevStageConfig::ColorModifier; | ||
| 71 | switch (modifier) { | ||
| 72 | case ColorModifier::SourceColor: | ||
| 73 | AppendSource(out, source, index_name); | ||
| 74 | out += ".rgb"; | ||
| 75 | break; | ||
| 76 | case ColorModifier::OneMinusSourceColor: | ||
| 77 | out += "vec3(1.0) - "; | ||
| 78 | AppendSource(out, source, index_name); | ||
| 79 | out += ".rgb"; | ||
| 80 | break; | ||
| 81 | case ColorModifier::SourceAlpha: | ||
| 82 | AppendSource(out, source, index_name); | ||
| 83 | out += ".aaa"; | ||
| 84 | break; | ||
| 85 | case ColorModifier::OneMinusSourceAlpha: | ||
| 86 | out += "vec3(1.0) - "; | ||
| 87 | AppendSource(out, source, index_name); | ||
| 88 | out += ".aaa"; | ||
| 89 | break; | ||
| 90 | case ColorModifier::SourceRed: | ||
| 91 | AppendSource(out, source, index_name); | ||
| 92 | out += ".rrr"; | ||
| 93 | break; | ||
| 94 | case ColorModifier::OneMinusSourceRed: | ||
| 95 | out += "vec3(1.0) - "; | ||
| 96 | AppendSource(out, source, index_name); | ||
| 97 | out += ".rrr"; | ||
| 98 | break; | ||
| 99 | case ColorModifier::SourceGreen: | ||
| 100 | AppendSource(out, source, index_name); | ||
| 101 | out += ".ggg"; | ||
| 102 | break; | ||
| 103 | case ColorModifier::OneMinusSourceGreen: | ||
| 104 | out += "vec3(1.0) - "; | ||
| 105 | AppendSource(out, source, index_name); | ||
| 106 | out += ".ggg"; | ||
| 107 | break; | ||
| 108 | case ColorModifier::SourceBlue: | ||
| 109 | AppendSource(out, source, index_name); | ||
| 110 | out += ".bbb"; | ||
| 111 | break; | ||
| 112 | case ColorModifier::OneMinusSourceBlue: | ||
| 113 | out += "vec3(1.0) - "; | ||
| 114 | AppendSource(out, source, index_name); | ||
| 115 | out += ".bbb"; | ||
| 116 | break; | ||
| 117 | default: | ||
| 118 | out += "vec3(0.0)"; | ||
| 119 | LOG_CRITICAL(Render_OpenGL, "Unknown color modifier op %u", modifier); | ||
| 120 | break; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | /// Writes the alpha component to use for the specified TEV stage alpha modifier | ||
| 125 | static void AppendAlphaModifier(std::string& out, TevStageConfig::AlphaModifier modifier, | ||
| 126 | TevStageConfig::Source source, const std::string& index_name) { | ||
| 127 | using AlphaModifier = TevStageConfig::AlphaModifier; | ||
| 128 | switch (modifier) { | ||
| 129 | case AlphaModifier::SourceAlpha: | ||
| 130 | AppendSource(out, source, index_name); | ||
| 131 | out += ".a"; | ||
| 132 | break; | ||
| 133 | case AlphaModifier::OneMinusSourceAlpha: | ||
| 134 | out += "1.0 - "; | ||
| 135 | AppendSource(out, source, index_name); | ||
| 136 | out += ".a"; | ||
| 137 | break; | ||
| 138 | case AlphaModifier::SourceRed: | ||
| 139 | AppendSource(out, source, index_name); | ||
| 140 | out += ".r"; | ||
| 141 | break; | ||
| 142 | case AlphaModifier::OneMinusSourceRed: | ||
| 143 | out += "1.0 - "; | ||
| 144 | AppendSource(out, source, index_name); | ||
| 145 | out += ".r"; | ||
| 146 | break; | ||
| 147 | case AlphaModifier::SourceGreen: | ||
| 148 | AppendSource(out, source, index_name); | ||
| 149 | out += ".g"; | ||
| 150 | break; | ||
| 151 | case AlphaModifier::OneMinusSourceGreen: | ||
| 152 | out += "1.0 - "; | ||
| 153 | AppendSource(out, source, index_name); | ||
| 154 | out += ".g"; | ||
| 155 | break; | ||
| 156 | case AlphaModifier::SourceBlue: | ||
| 157 | AppendSource(out, source, index_name); | ||
| 158 | out += ".b"; | ||
| 159 | break; | ||
| 160 | case AlphaModifier::OneMinusSourceBlue: | ||
| 161 | out += "1.0 - "; | ||
| 162 | AppendSource(out, source, index_name); | ||
| 163 | out += ".b"; | ||
| 164 | break; | ||
| 165 | default: | ||
| 166 | out += "0.0"; | ||
| 167 | LOG_CRITICAL(Render_OpenGL, "Unknown alpha modifier op %u", modifier); | ||
| 168 | break; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | /// Writes the combiner function for the color components for the specified TEV stage operation | ||
| 173 | static void AppendColorCombiner(std::string& out, TevStageConfig::Operation operation, | ||
| 174 | const std::string& variable_name) { | ||
| 175 | out += "clamp("; | ||
| 176 | using Operation = TevStageConfig::Operation; | ||
| 177 | switch (operation) { | ||
| 178 | case Operation::Replace: | ||
| 179 | out += variable_name + "[0]"; | ||
| 180 | break; | ||
| 181 | case Operation::Modulate: | ||
| 182 | out += variable_name + "[0] * " + variable_name + "[1]"; | ||
| 183 | break; | ||
| 184 | case Operation::Add: | ||
| 185 | out += variable_name + "[0] + " + variable_name + "[1]"; | ||
| 186 | break; | ||
| 187 | case Operation::AddSigned: | ||
| 188 | out += variable_name + "[0] + " + variable_name + "[1] - vec3(0.5)"; | ||
| 189 | break; | ||
| 190 | case Operation::Lerp: | ||
| 191 | // TODO(bunnei): Verify if HW actually does this per-component, otherwise we can just use builtin lerp | ||
| 192 | out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (vec3(1.0) - " + variable_name + "[2])"; | ||
| 193 | break; | ||
| 194 | case Operation::Subtract: | ||
| 195 | out += variable_name + "[0] - " + variable_name + "[1]"; | ||
| 196 | break; | ||
| 197 | case Operation::MultiplyThenAdd: | ||
| 198 | out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]"; | ||
| 199 | break; | ||
| 200 | case Operation::AddThenMultiply: | ||
| 201 | out += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + variable_name + "[2]"; | ||
| 202 | break; | ||
| 203 | default: | ||
| 204 | out += "vec3(0.0)"; | ||
| 205 | LOG_CRITICAL(Render_OpenGL, "Unknown color combiner operation: %u", operation); | ||
| 206 | break; | ||
| 207 | } | ||
| 208 | out += ", vec3(0.0), vec3(1.0))"; // Clamp result to 0.0, 1.0 | ||
| 209 | } | ||
| 210 | |||
| 211 | /// Writes the combiner function for the alpha component for the specified TEV stage operation | ||
| 212 | static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation operation, | ||
| 213 | const std::string& variable_name) { | ||
| 214 | out += "clamp("; | ||
| 215 | using Operation = TevStageConfig::Operation; | ||
| 216 | switch (operation) { | ||
| 217 | case Operation::Replace: | ||
| 218 | out += variable_name + "[0]"; | ||
| 219 | break; | ||
| 220 | case Operation::Modulate: | ||
| 221 | out += variable_name + "[0] * " + variable_name + "[1]"; | ||
| 222 | break; | ||
| 223 | case Operation::Add: | ||
| 224 | out += variable_name + "[0] + " + variable_name + "[1]"; | ||
| 225 | break; | ||
| 226 | case Operation::AddSigned: | ||
| 227 | out += variable_name + "[0] + " + variable_name + "[1] - 0.5"; | ||
| 228 | break; | ||
| 229 | case Operation::Lerp: | ||
| 230 | out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (1.0 - " + variable_name + "[2])"; | ||
| 231 | break; | ||
| 232 | case Operation::Subtract: | ||
| 233 | out += variable_name + "[0] - " + variable_name + "[1]"; | ||
| 234 | break; | ||
| 235 | case Operation::MultiplyThenAdd: | ||
| 236 | out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]"; | ||
| 237 | break; | ||
| 238 | case Operation::AddThenMultiply: | ||
| 239 | out += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + "[2]"; | ||
| 240 | break; | ||
| 241 | default: | ||
| 242 | out += "0.0"; | ||
| 243 | LOG_CRITICAL(Render_OpenGL, "Unknown alpha combiner operation: %u", operation); | ||
| 244 | break; | ||
| 245 | } | ||
| 246 | out += ", 0.0, 1.0)"; | ||
| 247 | } | ||
| 248 | |||
| 249 | /// Writes the if-statement condition used to evaluate alpha testing | ||
| 250 | static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) { | ||
| 251 | using CompareFunc = Regs::CompareFunc; | ||
| 252 | switch (func) { | ||
| 253 | case CompareFunc::Never: | ||
| 254 | out += "true"; | ||
| 255 | break; | ||
| 256 | case CompareFunc::Always: | ||
| 257 | out += "false"; | ||
| 258 | break; | ||
| 259 | case CompareFunc::Equal: | ||
| 260 | case CompareFunc::NotEqual: | ||
| 261 | case CompareFunc::LessThan: | ||
| 262 | case CompareFunc::LessThanOrEqual: | ||
| 263 | case CompareFunc::GreaterThan: | ||
| 264 | case CompareFunc::GreaterThanOrEqual: | ||
| 265 | { | ||
| 266 | static const char* op[] = { "!=", "==", ">=", ">", "<=", "<", }; | ||
| 267 | unsigned index = (unsigned)func - (unsigned)CompareFunc::Equal; | ||
| 268 | out += "int(last_tex_env_out.a * 255.0f) " + std::string(op[index]) + " alphatest_ref"; | ||
| 269 | break; | ||
| 270 | } | ||
| 271 | |||
| 272 | default: | ||
| 273 | out += "false"; | ||
| 274 | LOG_CRITICAL(Render_OpenGL, "Unknown alpha test condition %u", func); | ||
| 275 | break; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | /// Writes the code to emulate the specified TEV stage | ||
| 280 | static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) { | ||
| 281 | auto& stage = config.tev_stages[index]; | ||
| 282 | if (!IsPassThroughTevStage(stage)) { | ||
| 283 | std::string index_name = std::to_string(index); | ||
| 284 | |||
| 285 | out += "vec3 color_results_" + index_name + "[3] = vec3[3]("; | ||
| 286 | AppendColorModifier(out, stage.color_modifier1, stage.color_source1, index_name); | ||
| 287 | out += ", "; | ||
| 288 | AppendColorModifier(out, stage.color_modifier2, stage.color_source2, index_name); | ||
| 289 | out += ", "; | ||
| 290 | AppendColorModifier(out, stage.color_modifier3, stage.color_source3, index_name); | ||
| 291 | out += ");\n"; | ||
| 292 | |||
| 293 | out += "vec3 color_output_" + index_name + " = "; | ||
| 294 | AppendColorCombiner(out, stage.color_op, "color_results_" + index_name); | ||
| 295 | out += ";\n"; | ||
| 296 | |||
| 297 | out += "float alpha_results_" + index_name + "[3] = float[3]("; | ||
| 298 | AppendAlphaModifier(out, stage.alpha_modifier1, stage.alpha_source1, index_name); | ||
| 299 | out += ", "; | ||
| 300 | AppendAlphaModifier(out, stage.alpha_modifier2, stage.alpha_source2, index_name); | ||
| 301 | out += ", "; | ||
| 302 | AppendAlphaModifier(out, stage.alpha_modifier3, stage.alpha_source3, index_name); | ||
| 303 | out += ");\n"; | ||
| 304 | |||
| 305 | out += "float alpha_output_" + index_name + " = "; | ||
| 306 | AppendAlphaCombiner(out, stage.alpha_op, "alpha_results_" + index_name); | ||
| 307 | out += ";\n"; | ||
| 308 | |||
| 309 | out += "last_tex_env_out = vec4(" | ||
| 310 | "clamp(color_output_" + index_name + " * " + std::to_string(stage.GetColorMultiplier()) + ".0, vec3(0.0), vec3(1.0))," | ||
| 311 | "clamp(alpha_output_" + index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) + ".0, 0.0, 1.0));\n"; | ||
| 312 | } | ||
| 313 | |||
| 314 | if (config.TevStageUpdatesCombinerBufferColor(index)) | ||
| 315 | out += "combiner_buffer.rgb = last_tex_env_out.rgb;\n"; | ||
| 316 | |||
| 317 | if (config.TevStageUpdatesCombinerBufferAlpha(index)) | ||
| 318 | out += "combiner_buffer.a = last_tex_env_out.a;\n"; | ||
| 319 | } | ||
| 320 | |||
| 321 | std::string GenerateFragmentShader(const PicaShaderConfig& config) { | ||
| 322 | std::string out = R"( | ||
| 323 | #version 330 | ||
| 324 | #extension GL_ARB_explicit_uniform_location : require | ||
| 325 | |||
| 326 | #define NUM_TEV_STAGES 6 | ||
| 327 | |||
| 328 | in vec4 primary_color; | ||
| 329 | in vec2 texcoord[3]; | ||
| 330 | |||
| 331 | out vec4 color; | ||
| 332 | )"; | ||
| 333 | |||
| 334 | using Uniform = RasterizerOpenGL::PicaShader::Uniform; | ||
| 335 | out += "layout(location = " + std::to_string((int)Uniform::AlphaTestRef) + ") uniform int alphatest_ref;\n"; | ||
| 336 | out += "layout(location = " + std::to_string((int)Uniform::TevConstColors) + ") uniform vec4 const_color[NUM_TEV_STAGES];\n"; | ||
| 337 | out += "layout(location = " + std::to_string((int)Uniform::Texture0) + ") uniform sampler2D tex[3];\n"; | ||
| 338 | out += "layout(location = " + std::to_string((int)Uniform::TevCombinerBufferColor) + ") uniform vec4 tev_combiner_buffer_color;\n"; | ||
| 339 | |||
| 340 | out += "void main() {\n"; | ||
| 341 | out += "vec4 combiner_buffer = tev_combiner_buffer_color;\n"; | ||
| 342 | out += "vec4 last_tex_env_out = vec4(0.0);\n"; | ||
| 343 | |||
| 344 | // Do not do any sort of processing if it's obvious we're not going to pass the alpha test | ||
| 345 | if (config.alpha_test_func == Regs::CompareFunc::Never) { | ||
| 346 | out += "discard; }"; | ||
| 347 | return out; | ||
| 348 | } | ||
| 349 | |||
| 350 | for (size_t index = 0; index < config.tev_stages.size(); ++index) | ||
| 351 | WriteTevStage(out, config, (unsigned)index); | ||
| 352 | |||
| 353 | if (config.alpha_test_func != Regs::CompareFunc::Always) { | ||
| 354 | out += "if ("; | ||
| 355 | AppendAlphaTestCondition(out, config.alpha_test_func); | ||
| 356 | out += ") discard;\n"; | ||
| 357 | } | ||
| 358 | |||
| 359 | out += "color = last_tex_env_out;\n}"; | ||
| 360 | |||
| 361 | return out; | ||
| 362 | } | ||
| 363 | |||
| 364 | std::string GenerateVertexShader() { | ||
| 365 | std::string out = "#version 330\n"; | ||
| 366 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + ") in vec4 vert_position;\n"; | ||
| 367 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n"; | ||
| 368 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + ") in vec2 vert_texcoord0;\n"; | ||
| 369 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) + ") in vec2 vert_texcoord1;\n"; | ||
| 370 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) + ") in vec2 vert_texcoord2;\n"; | ||
| 371 | |||
| 372 | out += R"( | ||
| 373 | out vec4 primary_color; | ||
| 374 | out vec2 texcoord[3]; | ||
| 375 | |||
| 376 | void main() { | ||
| 377 | primary_color = vert_color; | ||
| 378 | texcoord[0] = vert_texcoord0; | ||
| 379 | texcoord[1] = vert_texcoord1; | ||
| 380 | texcoord[2] = vert_texcoord2; | ||
| 381 | gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w); | ||
| 382 | } | ||
| 383 | )"; | ||
| 384 | |||
| 385 | return out; | ||
| 386 | } | ||
| 387 | |||
| 388 | } // namespace GLShader | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h new file mode 100644 index 000000000..0ca9d2879 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_shader_gen.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <string> | ||
| 8 | |||
| 9 | #include "video_core/renderer_opengl/gl_rasterizer.h" | ||
| 10 | |||
| 11 | namespace GLShader { | ||
| 12 | |||
| 13 | /** | ||
| 14 | * Generates the GLSL vertex shader program source code for the current Pica state | ||
| 15 | * @returns String of the shader source code | ||
| 16 | */ | ||
| 17 | std::string GenerateVertexShader(); | ||
| 18 | |||
| 19 | /** | ||
| 20 | * Generates the GLSL fragment shader program source code for the current Pica state | ||
| 21 | * @param config ShaderCacheKey object generated for the current Pica state, used for the shader | ||
| 22 | * configuration (NOTE: Use state in this struct only, not the Pica registers!) | ||
| 23 | * @returns String of the shader source code | ||
| 24 | */ | ||
| 25 | std::string GenerateFragmentShader(const PicaShaderConfig& config); | ||
| 26 | |||
| 27 | } // namespace GLShader | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp index 4cf246c06..e3f7a5868 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.cpp +++ b/src/video_core/renderer_opengl/gl_shader_util.cpp | |||
| @@ -8,9 +8,9 @@ | |||
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "video_core/renderer_opengl/gl_shader_util.h" | 9 | #include "video_core/renderer_opengl/gl_shader_util.h" |
| 10 | 10 | ||
| 11 | namespace ShaderUtil { | 11 | namespace GLShader { |
| 12 | 12 | ||
| 13 | GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { | 13 | GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) { |
| 14 | 14 | ||
| 15 | // Create the shaders | 15 | // Create the shaders |
| 16 | GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER); | 16 | GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER); |
| @@ -65,6 +65,7 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { | |||
| 65 | GLuint program_id = glCreateProgram(); | 65 | GLuint program_id = glCreateProgram(); |
| 66 | glAttachShader(program_id, vertex_shader_id); | 66 | glAttachShader(program_id, vertex_shader_id); |
| 67 | glAttachShader(program_id, fragment_shader_id); | 67 | glAttachShader(program_id, fragment_shader_id); |
| 68 | |||
| 68 | glLinkProgram(program_id); | 69 | glLinkProgram(program_id); |
| 69 | 70 | ||
| 70 | // Check the program | 71 | // Check the program |
| @@ -87,4 +88,4 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { | |||
| 87 | return program_id; | 88 | return program_id; |
| 88 | } | 89 | } |
| 89 | 90 | ||
| 90 | } | 91 | } // namespace GLShader |
diff --git a/src/video_core/renderer_opengl/gl_shader_util.h b/src/video_core/renderer_opengl/gl_shader_util.h index c9d7cc380..046aae14f 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.h +++ b/src/video_core/renderer_opengl/gl_shader_util.h | |||
| @@ -6,8 +6,22 @@ | |||
| 6 | 6 | ||
| 7 | #include <glad/glad.h> | 7 | #include <glad/glad.h> |
| 8 | 8 | ||
| 9 | namespace ShaderUtil { | 9 | namespace GLShader { |
| 10 | 10 | ||
| 11 | GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path); | 11 | enum Attributes { |
| 12 | ATTRIBUTE_POSITION, | ||
| 13 | ATTRIBUTE_COLOR, | ||
| 14 | ATTRIBUTE_TEXCOORD0, | ||
| 15 | ATTRIBUTE_TEXCOORD1, | ||
| 16 | ATTRIBUTE_TEXCOORD2, | ||
| 17 | }; | ||
| 12 | 18 | ||
| 13 | } | 19 | /** |
| 20 | * Utility function to create and compile an OpenGL GLSL shader program (vertex + fragment shader) | ||
| 21 | * @param vertex_shader String of the GLSL vertex shader program | ||
| 22 | * @param fragment_shader String of the GLSL fragment shader program | ||
| 23 | * @returns Handle of the newly created OpenGL shader object | ||
| 24 | */ | ||
| 25 | GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader); | ||
| 26 | |||
| 27 | } // namespace | ||
diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h deleted file mode 100644 index a8cb2f595..000000000 --- a/src/video_core/renderer_opengl/gl_shaders.h +++ /dev/null | |||
| @@ -1,337 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace GLShaders { | ||
| 8 | |||
| 9 | const char g_vertex_shader[] = R"( | ||
| 10 | #version 150 core | ||
| 11 | |||
| 12 | in vec2 vert_position; | ||
| 13 | in vec2 vert_tex_coord; | ||
| 14 | out vec2 frag_tex_coord; | ||
| 15 | |||
| 16 | // This is a truncated 3x3 matrix for 2D transformations: | ||
| 17 | // The upper-left 2x2 submatrix performs scaling/rotation/mirroring. | ||
| 18 | // The third column performs translation. | ||
| 19 | // The third row could be used for projection, which we don't need in 2D. It hence is assumed to | ||
| 20 | // implicitly be [0, 0, 1] | ||
| 21 | uniform mat3x2 modelview_matrix; | ||
| 22 | |||
| 23 | void main() { | ||
| 24 | // Multiply input position by the rotscale part of the matrix and then manually translate by | ||
| 25 | // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector | ||
| 26 | // to `vec3(vert_position.xy, 1.0)` | ||
| 27 | gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0); | ||
| 28 | frag_tex_coord = vert_tex_coord; | ||
| 29 | } | ||
| 30 | )"; | ||
| 31 | |||
| 32 | const char g_fragment_shader[] = R"( | ||
| 33 | #version 150 core | ||
| 34 | |||
| 35 | in vec2 frag_tex_coord; | ||
| 36 | out vec4 color; | ||
| 37 | |||
| 38 | uniform sampler2D color_texture; | ||
| 39 | |||
| 40 | void main() { | ||
| 41 | color = texture(color_texture, frag_tex_coord); | ||
| 42 | } | ||
| 43 | )"; | ||
| 44 | |||
| 45 | const char g_vertex_shader_hw[] = R"( | ||
| 46 | #version 150 core | ||
| 47 | |||
| 48 | #define NUM_VTX_ATTR 7 | ||
| 49 | |||
| 50 | in vec4 vert_position; | ||
| 51 | in vec4 vert_color; | ||
| 52 | in vec2 vert_texcoords[3]; | ||
| 53 | |||
| 54 | out vec4 o[NUM_VTX_ATTR]; | ||
| 55 | |||
| 56 | void main() { | ||
| 57 | o[2] = vert_color; | ||
| 58 | o[3] = vec4(vert_texcoords[0].xy, vert_texcoords[1].xy); | ||
| 59 | o[5] = vec4(0.0, 0.0, vert_texcoords[2].xy); | ||
| 60 | |||
| 61 | gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w); | ||
| 62 | } | ||
| 63 | )"; | ||
| 64 | |||
| 65 | // TODO: Create a shader constructor and cache that builds this program with minimal conditionals instead of using tev_cfg uniforms | ||
| 66 | const char g_fragment_shader_hw[] = R"( | ||
| 67 | #version 150 core | ||
| 68 | |||
| 69 | #define NUM_VTX_ATTR 7 | ||
| 70 | #define NUM_TEV_STAGES 6 | ||
| 71 | |||
| 72 | #define SOURCE_PRIMARYCOLOR 0x0 | ||
| 73 | #define SOURCE_PRIMARYFRAGMENTCOLOR 0x1 | ||
| 74 | #define SOURCE_SECONDARYFRAGMENTCOLOR 0x2 | ||
| 75 | #define SOURCE_TEXTURE0 0x3 | ||
| 76 | #define SOURCE_TEXTURE1 0x4 | ||
| 77 | #define SOURCE_TEXTURE2 0x5 | ||
| 78 | #define SOURCE_TEXTURE3 0x6 | ||
| 79 | #define SOURCE_PREVIOUSBUFFER 0xd | ||
| 80 | #define SOURCE_CONSTANT 0xe | ||
| 81 | #define SOURCE_PREVIOUS 0xf | ||
| 82 | |||
| 83 | #define COLORMODIFIER_SOURCECOLOR 0x0 | ||
| 84 | #define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1 | ||
| 85 | #define COLORMODIFIER_SOURCEALPHA 0x2 | ||
| 86 | #define COLORMODIFIER_ONEMINUSSOURCEALPHA 0x3 | ||
| 87 | #define COLORMODIFIER_SOURCERED 0x4 | ||
| 88 | #define COLORMODIFIER_ONEMINUSSOURCERED 0x5 | ||
| 89 | #define COLORMODIFIER_SOURCEGREEN 0x8 | ||
| 90 | #define COLORMODIFIER_ONEMINUSSOURCEGREEN 0x9 | ||
| 91 | #define COLORMODIFIER_SOURCEBLUE 0xc | ||
| 92 | #define COLORMODIFIER_ONEMINUSSOURCEBLUE 0xd | ||
| 93 | |||
| 94 | #define ALPHAMODIFIER_SOURCEALPHA 0x0 | ||
| 95 | #define ALPHAMODIFIER_ONEMINUSSOURCEALPHA 0x1 | ||
| 96 | #define ALPHAMODIFIER_SOURCERED 0x2 | ||
| 97 | #define ALPHAMODIFIER_ONEMINUSSOURCERED 0x3 | ||
| 98 | #define ALPHAMODIFIER_SOURCEGREEN 0x4 | ||
| 99 | #define ALPHAMODIFIER_ONEMINUSSOURCEGREEN 0x5 | ||
| 100 | #define ALPHAMODIFIER_SOURCEBLUE 0x6 | ||
| 101 | #define ALPHAMODIFIER_ONEMINUSSOURCEBLUE 0x7 | ||
| 102 | |||
| 103 | #define OPERATION_REPLACE 0 | ||
| 104 | #define OPERATION_MODULATE 1 | ||
| 105 | #define OPERATION_ADD 2 | ||
| 106 | #define OPERATION_ADDSIGNED 3 | ||
| 107 | #define OPERATION_LERP 4 | ||
| 108 | #define OPERATION_SUBTRACT 5 | ||
| 109 | #define OPERATION_MULTIPLYTHENADD 8 | ||
| 110 | #define OPERATION_ADDTHENMULTIPLY 9 | ||
| 111 | |||
| 112 | #define COMPAREFUNC_NEVER 0 | ||
| 113 | #define COMPAREFUNC_ALWAYS 1 | ||
| 114 | #define COMPAREFUNC_EQUAL 2 | ||
| 115 | #define COMPAREFUNC_NOTEQUAL 3 | ||
| 116 | #define COMPAREFUNC_LESSTHAN 4 | ||
| 117 | #define COMPAREFUNC_LESSTHANOREQUAL 5 | ||
| 118 | #define COMPAREFUNC_GREATERTHAN 6 | ||
| 119 | #define COMPAREFUNC_GREATERTHANOREQUAL 7 | ||
| 120 | |||
| 121 | in vec4 o[NUM_VTX_ATTR]; | ||
| 122 | out vec4 color; | ||
| 123 | |||
| 124 | uniform bool alphatest_enabled; | ||
| 125 | uniform int alphatest_func; | ||
| 126 | uniform float alphatest_ref; | ||
| 127 | |||
| 128 | uniform sampler2D tex[3]; | ||
| 129 | |||
| 130 | uniform vec4 tev_combiner_buffer_color; | ||
| 131 | |||
| 132 | struct TEVConfig | ||
| 133 | { | ||
| 134 | bool enabled; | ||
| 135 | ivec3 color_sources; | ||
| 136 | ivec3 alpha_sources; | ||
| 137 | ivec3 color_modifiers; | ||
| 138 | ivec3 alpha_modifiers; | ||
| 139 | ivec2 color_alpha_op; | ||
| 140 | ivec2 color_alpha_multiplier; | ||
| 141 | vec4 const_color; | ||
| 142 | bvec2 updates_combiner_buffer_color_alpha; | ||
| 143 | }; | ||
| 144 | |||
| 145 | uniform TEVConfig tev_cfgs[NUM_TEV_STAGES]; | ||
| 146 | |||
| 147 | vec4 g_combiner_buffer; | ||
| 148 | vec4 g_last_tex_env_out; | ||
| 149 | vec4 g_const_color; | ||
| 150 | |||
| 151 | vec4 GetSource(int source) { | ||
| 152 | if (source == SOURCE_PRIMARYCOLOR) { | ||
| 153 | return o[2]; | ||
| 154 | } else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) { | ||
| 155 | // HACK: Until we implement fragment lighting, use primary_color | ||
| 156 | return o[2]; | ||
| 157 | } else if (source == SOURCE_SECONDARYFRAGMENTCOLOR) { | ||
| 158 | // HACK: Until we implement fragment lighting, use zero | ||
| 159 | return vec4(0.0, 0.0, 0.0, 0.0); | ||
| 160 | } else if (source == SOURCE_TEXTURE0) { | ||
| 161 | return texture(tex[0], o[3].xy); | ||
| 162 | } else if (source == SOURCE_TEXTURE1) { | ||
| 163 | return texture(tex[1], o[3].zw); | ||
| 164 | } else if (source == SOURCE_TEXTURE2) { | ||
| 165 | // TODO: Unverified | ||
| 166 | return texture(tex[2], o[5].zw); | ||
| 167 | } else if (source == SOURCE_TEXTURE3) { | ||
| 168 | // TODO: no 4th texture? | ||
| 169 | } else if (source == SOURCE_PREVIOUSBUFFER) { | ||
| 170 | return g_combiner_buffer; | ||
| 171 | } else if (source == SOURCE_CONSTANT) { | ||
| 172 | return g_const_color; | ||
| 173 | } else if (source == SOURCE_PREVIOUS) { | ||
| 174 | return g_last_tex_env_out; | ||
| 175 | } | ||
| 176 | |||
| 177 | return vec4(0.0); | ||
| 178 | } | ||
| 179 | |||
| 180 | vec3 GetColorModifier(int factor, vec4 color) { | ||
| 181 | if (factor == COLORMODIFIER_SOURCECOLOR) { | ||
| 182 | return color.rgb; | ||
| 183 | } else if (factor == COLORMODIFIER_ONEMINUSSOURCECOLOR) { | ||
| 184 | return vec3(1.0) - color.rgb; | ||
| 185 | } else if (factor == COLORMODIFIER_SOURCEALPHA) { | ||
| 186 | return color.aaa; | ||
| 187 | } else if (factor == COLORMODIFIER_ONEMINUSSOURCEALPHA) { | ||
| 188 | return vec3(1.0) - color.aaa; | ||
| 189 | } else if (factor == COLORMODIFIER_SOURCERED) { | ||
| 190 | return color.rrr; | ||
| 191 | } else if (factor == COLORMODIFIER_ONEMINUSSOURCERED) { | ||
| 192 | return vec3(1.0) - color.rrr; | ||
| 193 | } else if (factor == COLORMODIFIER_SOURCEGREEN) { | ||
| 194 | return color.ggg; | ||
| 195 | } else if (factor == COLORMODIFIER_ONEMINUSSOURCEGREEN) { | ||
| 196 | return vec3(1.0) - color.ggg; | ||
| 197 | } else if (factor == COLORMODIFIER_SOURCEBLUE) { | ||
| 198 | return color.bbb; | ||
| 199 | } else if (factor == COLORMODIFIER_ONEMINUSSOURCEBLUE) { | ||
| 200 | return vec3(1.0) - color.bbb; | ||
| 201 | } | ||
| 202 | |||
| 203 | return vec3(0.0); | ||
| 204 | } | ||
| 205 | |||
| 206 | float GetAlphaModifier(int factor, vec4 color) { | ||
| 207 | if (factor == ALPHAMODIFIER_SOURCEALPHA) { | ||
| 208 | return color.a; | ||
| 209 | } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEALPHA) { | ||
| 210 | return 1.0 - color.a; | ||
| 211 | } else if (factor == ALPHAMODIFIER_SOURCERED) { | ||
| 212 | return color.r; | ||
| 213 | } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCERED) { | ||
| 214 | return 1.0 - color.r; | ||
| 215 | } else if (factor == ALPHAMODIFIER_SOURCEGREEN) { | ||
| 216 | return color.g; | ||
| 217 | } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEGREEN) { | ||
| 218 | return 1.0 - color.g; | ||
| 219 | } else if (factor == ALPHAMODIFIER_SOURCEBLUE) { | ||
| 220 | return color.b; | ||
| 221 | } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEBLUE) { | ||
| 222 | return 1.0 - color.b; | ||
| 223 | } | ||
| 224 | |||
| 225 | return 0.0; | ||
| 226 | } | ||
| 227 | |||
| 228 | vec3 ColorCombine(int op, vec3 color[3]) { | ||
| 229 | if (op == OPERATION_REPLACE) { | ||
| 230 | return color[0]; | ||
| 231 | } else if (op == OPERATION_MODULATE) { | ||
| 232 | return color[0] * color[1]; | ||
| 233 | } else if (op == OPERATION_ADD) { | ||
| 234 | return min(color[0] + color[1], 1.0); | ||
| 235 | } else if (op == OPERATION_ADDSIGNED) { | ||
| 236 | return clamp(color[0] + color[1] - vec3(0.5), 0.0, 1.0); | ||
| 237 | } else if (op == OPERATION_LERP) { | ||
| 238 | return color[0] * color[2] + color[1] * (vec3(1.0) - color[2]); | ||
| 239 | } else if (op == OPERATION_SUBTRACT) { | ||
| 240 | return max(color[0] - color[1], 0.0); | ||
| 241 | } else if (op == OPERATION_MULTIPLYTHENADD) { | ||
| 242 | return min(color[0] * color[1] + color[2], 1.0); | ||
| 243 | } else if (op == OPERATION_ADDTHENMULTIPLY) { | ||
| 244 | return min(color[0] + color[1], 1.0) * color[2]; | ||
| 245 | } | ||
| 246 | |||
| 247 | return vec3(0.0); | ||
| 248 | } | ||
| 249 | |||
| 250 | float AlphaCombine(int op, float alpha[3]) { | ||
| 251 | if (op == OPERATION_REPLACE) { | ||
| 252 | return alpha[0]; | ||
| 253 | } else if (op == OPERATION_MODULATE) { | ||
| 254 | return alpha[0] * alpha[1]; | ||
| 255 | } else if (op == OPERATION_ADD) { | ||
| 256 | return min(alpha[0] + alpha[1], 1.0); | ||
| 257 | } else if (op == OPERATION_ADDSIGNED) { | ||
| 258 | return clamp(alpha[0] + alpha[1] - 0.5, 0.0, 1.0); | ||
| 259 | } else if (op == OPERATION_LERP) { | ||
| 260 | return alpha[0] * alpha[2] + alpha[1] * (1.0 - alpha[2]); | ||
| 261 | } else if (op == OPERATION_SUBTRACT) { | ||
| 262 | return max(alpha[0] - alpha[1], 0.0); | ||
| 263 | } else if (op == OPERATION_MULTIPLYTHENADD) { | ||
| 264 | return min(alpha[0] * alpha[1] + alpha[2], 1.0); | ||
| 265 | } else if (op == OPERATION_ADDTHENMULTIPLY) { | ||
| 266 | return min(alpha[0] + alpha[1], 1.0) * alpha[2]; | ||
| 267 | } | ||
| 268 | |||
| 269 | return 0.0; | ||
| 270 | } | ||
| 271 | |||
| 272 | void main(void) { | ||
| 273 | g_combiner_buffer = tev_combiner_buffer_color; | ||
| 274 | |||
| 275 | for (int tex_env_idx = 0; tex_env_idx < NUM_TEV_STAGES; ++tex_env_idx) { | ||
| 276 | if (tev_cfgs[tex_env_idx].enabled) { | ||
| 277 | g_const_color = tev_cfgs[tex_env_idx].const_color; | ||
| 278 | |||
| 279 | vec3 color_results[3] = vec3[3](GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.x, GetSource(tev_cfgs[tex_env_idx].color_sources.x)), | ||
| 280 | GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.y, GetSource(tev_cfgs[tex_env_idx].color_sources.y)), | ||
| 281 | GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.z, GetSource(tev_cfgs[tex_env_idx].color_sources.z))); | ||
| 282 | vec3 color_output = ColorCombine(tev_cfgs[tex_env_idx].color_alpha_op.x, color_results); | ||
| 283 | |||
| 284 | float alpha_results[3] = float[3](GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.x, GetSource(tev_cfgs[tex_env_idx].alpha_sources.x)), | ||
| 285 | GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.y, GetSource(tev_cfgs[tex_env_idx].alpha_sources.y)), | ||
| 286 | GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.z, GetSource(tev_cfgs[tex_env_idx].alpha_sources.z))); | ||
| 287 | float alpha_output = AlphaCombine(tev_cfgs[tex_env_idx].color_alpha_op.y, alpha_results); | ||
| 288 | |||
| 289 | 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)); | ||
| 290 | } | ||
| 291 | |||
| 292 | if (tev_cfgs[tex_env_idx].updates_combiner_buffer_color_alpha.x) { | ||
| 293 | g_combiner_buffer.rgb = g_last_tex_env_out.rgb; | ||
| 294 | } | ||
| 295 | |||
| 296 | if (tev_cfgs[tex_env_idx].updates_combiner_buffer_color_alpha.y) { | ||
| 297 | g_combiner_buffer.a = g_last_tex_env_out.a; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | if (alphatest_enabled) { | ||
| 302 | if (alphatest_func == COMPAREFUNC_NEVER) { | ||
| 303 | discard; | ||
| 304 | } else if (alphatest_func == COMPAREFUNC_ALWAYS) { | ||
| 305 | |||
| 306 | } else if (alphatest_func == COMPAREFUNC_EQUAL) { | ||
| 307 | if (g_last_tex_env_out.a != alphatest_ref) { | ||
| 308 | discard; | ||
| 309 | } | ||
| 310 | } else if (alphatest_func == COMPAREFUNC_NOTEQUAL) { | ||
| 311 | if (g_last_tex_env_out.a == alphatest_ref) { | ||
| 312 | discard; | ||
| 313 | } | ||
| 314 | } else if (alphatest_func == COMPAREFUNC_LESSTHAN) { | ||
| 315 | if (g_last_tex_env_out.a >= alphatest_ref) { | ||
| 316 | discard; | ||
| 317 | } | ||
| 318 | } else if (alphatest_func == COMPAREFUNC_LESSTHANOREQUAL) { | ||
| 319 | if (g_last_tex_env_out.a > alphatest_ref) { | ||
| 320 | discard; | ||
| 321 | } | ||
| 322 | } else if (alphatest_func == COMPAREFUNC_GREATERTHAN) { | ||
| 323 | if (g_last_tex_env_out.a <= alphatest_ref) { | ||
| 324 | discard; | ||
| 325 | } | ||
| 326 | } else if (alphatest_func == COMPAREFUNC_GREATERTHANOREQUAL) { | ||
| 327 | if (g_last_tex_env_out.a < alphatest_ref) { | ||
| 328 | discard; | ||
| 329 | } | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 333 | color = g_last_tex_env_out; | ||
| 334 | } | ||
| 335 | )"; | ||
| 336 | |||
| 337 | } | ||
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 6ecbedbb4..668b04259 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -65,6 +65,7 @@ public: | |||
| 65 | GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING | 65 | GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING |
| 66 | GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING | 66 | GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING |
| 67 | GLuint shader_program; // GL_CURRENT_PROGRAM | 67 | GLuint shader_program; // GL_CURRENT_PROGRAM |
| 68 | bool shader_dirty; | ||
| 68 | } draw; | 69 | } draw; |
| 69 | 70 | ||
| 70 | OpenGLState(); | 71 | OpenGLState(); |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index f1313b54f..ac0a058db 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -21,9 +21,44 @@ | |||
| 21 | #include "video_core/debug_utils/debug_utils.h" | 21 | #include "video_core/debug_utils/debug_utils.h" |
| 22 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 22 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 23 | #include "video_core/renderer_opengl/gl_shader_util.h" | 23 | #include "video_core/renderer_opengl/gl_shader_util.h" |
| 24 | #include "video_core/renderer_opengl/gl_shaders.h" | ||
| 25 | #include "video_core/renderer_opengl/renderer_opengl.h" | 24 | #include "video_core/renderer_opengl/renderer_opengl.h" |
| 26 | 25 | ||
| 26 | static const char vertex_shader[] = R"( | ||
| 27 | #version 150 core | ||
| 28 | |||
| 29 | in vec2 vert_position; | ||
| 30 | in vec2 vert_tex_coord; | ||
| 31 | out vec2 frag_tex_coord; | ||
| 32 | |||
| 33 | // This is a truncated 3x3 matrix for 2D transformations: | ||
| 34 | // The upper-left 2x2 submatrix performs scaling/rotation/mirroring. | ||
| 35 | // The third column performs translation. | ||
| 36 | // The third row could be used for projection, which we don't need in 2D. It hence is assumed to | ||
| 37 | // implicitly be [0, 0, 1] | ||
| 38 | uniform mat3x2 modelview_matrix; | ||
| 39 | |||
| 40 | void main() { | ||
| 41 | // Multiply input position by the rotscale part of the matrix and then manually translate by | ||
| 42 | // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector | ||
| 43 | // to `vec3(vert_position.xy, 1.0)` | ||
| 44 | gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0); | ||
| 45 | frag_tex_coord = vert_tex_coord; | ||
| 46 | } | ||
| 47 | )"; | ||
| 48 | |||
| 49 | static const char fragment_shader[] = R"( | ||
| 50 | #version 150 core | ||
| 51 | |||
| 52 | in vec2 frag_tex_coord; | ||
| 53 | out vec4 color; | ||
| 54 | |||
| 55 | uniform sampler2D color_texture; | ||
| 56 | |||
| 57 | void main() { | ||
| 58 | color = texture(color_texture, frag_tex_coord); | ||
| 59 | } | ||
| 60 | )"; | ||
| 61 | |||
| 27 | /** | 62 | /** |
| 28 | * Vertex structure that the drawn screen rectangles are composed of. | 63 | * Vertex structure that the drawn screen rectangles are composed of. |
| 29 | */ | 64 | */ |
| @@ -207,7 +242,7 @@ void RendererOpenGL::InitOpenGLObjects() { | |||
| 207 | glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f); | 242 | glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f); |
| 208 | 243 | ||
| 209 | // Link shaders and get variable locations | 244 | // Link shaders and get variable locations |
| 210 | program_id = ShaderUtil::LoadShaders(GLShaders::g_vertex_shader, GLShaders::g_fragment_shader); | 245 | program_id = GLShader::LoadProgram(vertex_shader, fragment_shader); |
| 211 | uniform_modelview_matrix = glGetUniformLocation(program_id, "modelview_matrix"); | 246 | uniform_modelview_matrix = glGetUniformLocation(program_id, "modelview_matrix"); |
| 212 | uniform_color_texture = glGetUniformLocation(program_id, "color_texture"); | 247 | uniform_color_texture = glGetUniformLocation(program_id, "color_texture"); |
| 213 | attrib_position = glGetAttribLocation(program_id, "vert_position"); | 248 | attrib_position = glGetAttribLocation(program_id, "vert_position"); |