summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2015-10-21 22:36:27 -0400
committerGravatar bunnei2015-10-21 22:36:27 -0400
commit4195d9b3f83441c60f23f939a19733e93ee04ff8 (patch)
treef3005c0737a6ade25afc5a912e0a7f14e48adfa5 /src
parentMerge pull request #1207 from kemenaran/persist-citra-settings-in-qt (diff)
parentgl_shader_gen: Use explicit locations for vertex shader attributes. (diff)
downloadyuzu-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.txt3
-rw-r--r--src/video_core/pica.h4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp313
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h157
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp388
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h27
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.h20
-rw-r--r--src/video_core/renderer_opengl/gl_shaders.h337
-rw-r--r--src/video_core/renderer_opengl/gl_state.h1
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp39
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 @@
1set(SRCS 1set(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
38RasterizerOpenGL::~RasterizerOpenGL() { } 40RasterizerOpenGL::~RasterizerOpenGL() { }
39 41
40void RasterizerOpenGL::InitObjects() { 42void 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
152void RasterizerOpenGL::Reset() { 120void 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
463void 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
595void RasterizerOpenGL::SyncFramebuffer() { 498void 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
713void RasterizerOpenGL::SyncAlphaTest() { 616void 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
720void RasterizerOpenGL::SyncLogicOp() { 621void 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
747void 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
759void 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
771void 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
775void 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
780void 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
784void RasterizerOpenGL::SyncCombinerColor() { 648void 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
789void RasterizerOpenGL::SyncCombinerWriteFlags() { 653void 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
799void RasterizerOpenGL::SyncDrawState() { 658void 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 */
30struct 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
94namespace std {
95
96template <>
97struct hash<PicaShaderConfig> {
98 size_t operator()(const PicaShaderConfig& k) const {
99 return Common::ComputeHash64(&k, sizeof(PicaShaderConfig));
100 }
101};
102
103} // namespace std
104
16class RasterizerOpenGL : public HWRasterizer { 105class RasterizerOpenGL : public HWRasterizer {
17public: 106public:
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
48private: 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
153private:
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
9using Pica::Regs;
10using TevStageConfig = Regs::TevStageConfig;
11
12namespace GLShader {
13
14/// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code)
15static 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)
27static 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
68static 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
125static 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
173static 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
212static 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
250static 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
280static 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
321std::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
328in vec4 primary_color;
329in vec2 texcoord[3];
330
331out 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
364std::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"(
373out vec4 primary_color;
374out vec2 texcoord[3];
375
376void 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
11namespace 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 */
17std::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 */
25std::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
11namespace ShaderUtil { 11namespace GLShader {
12 12
13GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { 13GLuint 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
9namespace ShaderUtil { 9namespace GLShader {
10 10
11GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path); 11enum 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 */
25GLuint 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
7namespace GLShaders {
8
9const char g_vertex_shader[] = R"(
10#version 150 core
11
12in vec2 vert_position;
13in vec2 vert_tex_coord;
14out 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]
21uniform mat3x2 modelview_matrix;
22
23void 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
32const char g_fragment_shader[] = R"(
33#version 150 core
34
35in vec2 frag_tex_coord;
36out vec4 color;
37
38uniform sampler2D color_texture;
39
40void main() {
41 color = texture(color_texture, frag_tex_coord);
42}
43)";
44
45const char g_vertex_shader_hw[] = R"(
46#version 150 core
47
48#define NUM_VTX_ATTR 7
49
50in vec4 vert_position;
51in vec4 vert_color;
52in vec2 vert_texcoords[3];
53
54out vec4 o[NUM_VTX_ATTR];
55
56void 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
66const 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
121in vec4 o[NUM_VTX_ATTR];
122out vec4 color;
123
124uniform bool alphatest_enabled;
125uniform int alphatest_func;
126uniform float alphatest_ref;
127
128uniform sampler2D tex[3];
129
130uniform vec4 tev_combiner_buffer_color;
131
132struct 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
145uniform TEVConfig tev_cfgs[NUM_TEV_STAGES];
146
147vec4 g_combiner_buffer;
148vec4 g_last_tex_env_out;
149vec4 g_const_color;
150
151vec4 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
180vec3 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
206float 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
228vec3 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
250float 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
272void 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
26static const char vertex_shader[] = R"(
27#version 150 core
28
29in vec2 vert_position;
30in vec2 vert_tex_coord;
31out 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]
38uniform mat3x2 modelview_matrix;
39
40void 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
49static const char fragment_shader[] = R"(
50#version 150 core
51
52in vec2 frag_tex_coord;
53out vec4 color;
54
55uniform sampler2D color_texture;
56
57void 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");