summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2015-10-05 22:33:47 -0400
committerGravatar bunnei2015-10-21 21:53:14 -0400
commitc86b9d42423b5a83ccba40f828b7ad9dafe3e317 (patch)
tree04bdd0a99fa7fa36946422d0119b3d537dd99526 /src
parentgl_rasterizer: Move logic for creating ShaderCacheKey to a static function. (diff)
downloadyuzu-c86b9d42423b5a83ccba40f828b7ad9dafe3e317.tar.gz
yuzu-c86b9d42423b5a83ccba40f828b7ad9dafe3e317.tar.xz
yuzu-c86b9d42423b5a83ccba40f828b7ad9dafe3e317.zip
renderer_opengl: Refactor shader generation/caching to be more organized + various cleanups.
Diffstat (limited to 'src')
-rw-r--r--src/common/common_funcs.h18
-rw-r--r--src/video_core/CMakeLists.txt3
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp131
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h41
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp371
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h17
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.cpp348
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.h6
-rw-r--r--src/video_core/renderer_opengl/gl_shaders.h339
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp39
11 files changed, 527 insertions, 788 deletions
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index ed20c3629..7a8dd39a0 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -4,6 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
8#include <functional>
9
7#include "common_types.h" 10#include "common_types.h"
8 11
9#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 12#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
@@ -95,3 +98,18 @@ inline u64 _rotr64(u64 x, unsigned int shift){
95// This function might change the error code. 98// This function might change the error code.
96// Defined in Misc.cpp. 99// Defined in Misc.cpp.
97const char* GetLastErrorMsg(); 100const char* GetLastErrorMsg();
101
102template <typename T>
103inline std::size_t hash(const T& o) {
104 return std::hash<T>()(o);
105}
106
107template <typename T>
108inline std::size_t combine_hash(const T& o) {
109 return hash(o);
110}
111
112template <typename T, typename... Args>
113inline std::size_t combine_hash(const T& o, const Args&... args) {
114 return hash(o) * 3 + combine_hash(args...);
115}
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/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 01b9c91c6..4f9865230 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -9,6 +9,7 @@
9 9
10#include "common/color.h" 10#include "common/color.h"
11#include "common/file_util.h" 11#include "common/file_util.h"
12#include "common/make_unique.h"
12#include "common/math_util.h" 13#include "common/math_util.h"
13#include "common/microprofile.h" 14#include "common/microprofile.h"
14#include "common/profiler.h" 15#include "common/profiler.h"
@@ -20,7 +21,7 @@
20#include "video_core/pica.h" 21#include "video_core/pica.h"
21#include "video_core/utils.h" 22#include "video_core/utils.h"
22#include "video_core/renderer_opengl/gl_rasterizer.h" 23#include "video_core/renderer_opengl/gl_rasterizer.h"
23#include "video_core/renderer_opengl/gl_shaders.h" 24#include "video_core/renderer_opengl/gl_shader_gen.h"
24#include "video_core/renderer_opengl/gl_shader_util.h" 25#include "video_core/renderer_opengl/gl_shader_util.h"
25#include "video_core/renderer_opengl/pica_to_gl.h" 26#include "video_core/renderer_opengl/pica_to_gl.h"
26 27
@@ -54,20 +55,20 @@ void RasterizerOpenGL::InitObjects() {
54 state.Apply(); 55 state.Apply();
55 56
56 // Set vertex attributes 57 // Set vertex attributes
57 glVertexAttribPointer(ShaderUtil::ATTRIBUTE_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));
58 glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_POSITION); 59 glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION);
59 60
60 glVertexAttribPointer(ShaderUtil::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); 61 glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color));
61 glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_COLOR); 62 glEnableVertexAttribArray(GLShader::ATTRIBUTE_COLOR);
62 63
63 glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); 64 glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORDS + 0, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0));
64 glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); 65 glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORDS + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1));
65 glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); 66 glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORDS + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2));
66 glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS); 67 glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORDS + 0);
67 glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS + 1); 68 glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORDS + 1);
68 glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS + 2); 69 glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORDS + 2);
69 70
70 RegenerateShaders(); 71 SetShader();
71 72
72 // 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
73 fb_color_texture.texture.Create(); 74 fb_color_texture.texture.Create();
@@ -117,8 +118,6 @@ void RasterizerOpenGL::InitObjects() {
117} 118}
118 119
119void RasterizerOpenGL::Reset() { 120void RasterizerOpenGL::Reset() {
120 const auto& regs = Pica::g_state.regs;
121
122 SyncCullMode(); 121 SyncCullMode();
123 SyncBlendEnabled(); 122 SyncBlendEnabled();
124 SyncBlendFuncs(); 123 SyncBlendFuncs();
@@ -127,7 +126,7 @@ void RasterizerOpenGL::Reset() {
127 SyncStencilTest(); 126 SyncStencilTest();
128 SyncDepthTest(); 127 SyncDepthTest();
129 128
130 RegenerateShaders(); 129 SetShader();
131 130
132 res_cache.FullFlush(); 131 res_cache.FullFlush();
133} 132}
@@ -140,70 +139,12 @@ void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0,
140 vertex_batch.emplace_back(v2); 139 vertex_batch.emplace_back(v2);
141} 140}
142 141
143namespace ShaderCache {
144extern std::string GenerateFragmentShader(const ShaderCacheKey& config);
145}
146
147void RasterizerOpenGL::RegenerateShaders() {
148 ShaderCacheKey config = ShaderCacheKey::CurrentShaderConfig();
149
150 auto cached_shader = shader_cache.find(config);
151 if (cached_shader != shader_cache.end()) {
152 current_shader = &cached_shader->second;
153 state.draw.shader_program = current_shader->shader.handle;
154 state.Apply();
155 } else {
156 LOG_CRITICAL(Render_OpenGL, "Creating new shader: %08X", hash(config));
157
158 TEVShader shader;
159
160 std::string fragShader = ShaderCache::GenerateFragmentShader(config);
161 shader.shader.Create(GLShaders::g_vertex_shader_hw, fragShader.c_str());
162
163 shader.uniform_alphatest_ref = glGetUniformLocation(shader.shader.handle, "alphatest_ref");
164 shader.uniform_tex = glGetUniformLocation(shader.shader.handle, "tex");
165 shader.uniform_tev_combiner_buffer_color = glGetUniformLocation(shader.shader.handle, "tev_combiner_buffer_color");
166 shader.uniform_tev_const_colors = glGetUniformLocation(shader.shader.handle, "const_color");
167
168 current_shader = &shader_cache.emplace(config, std::move(shader)).first->second;
169
170 state.draw.shader_program = current_shader->shader.handle;
171 state.Apply();
172
173 // Set the texture samplers to correspond to different texture units
174 if (shader.uniform_tex != -1) {
175 glUniform1i(shader.uniform_tex, 0);
176 glUniform1i(shader.uniform_tex + 1, 1);
177 glUniform1i(shader.uniform_tex + 2, 2);
178 }
179 }
180
181 // Sync alpha reference
182 if (current_shader->uniform_alphatest_ref != -1)
183 glUniform1i(current_shader->uniform_alphatest_ref, Pica::g_state.regs.output_merger.alpha_test.ref);
184
185 // Sync combiner buffer color
186 if (current_shader->uniform_tev_combiner_buffer_color != -1) {
187 auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw);
188 glUniform4fv(current_shader->uniform_tev_combiner_buffer_color, 1, combiner_color.data());
189 }
190
191 // Sync TEV const colors
192 if (current_shader->uniform_tev_const_colors != -1) {
193 auto& tev_stages = Pica::g_state.regs.GetTevStages();
194 for (int tev_index = 0; tev_index < tev_stages.size(); ++tev_index) {
195 auto const_color = PicaToGL::ColorRGBA8(tev_stages[tev_index].const_color);
196 glUniform4fv(current_shader->uniform_tev_const_colors + tev_index, 1, const_color.data());
197 }
198 }
199}
200
201void RasterizerOpenGL::DrawTriangles() { 142void RasterizerOpenGL::DrawTriangles() {
202 SyncFramebuffer(); 143 SyncFramebuffer();
203 SyncDrawState(); 144 SyncDrawState();
204 145
205 if (state.draw.shader_dirty) { 146 if (state.draw.shader_dirty) {
206 RegenerateShaders(); 147 SetShader();
207 state.draw.shader_dirty = false; 148 state.draw.shader_dirty = false;
208 } 149 }
209 150
@@ -519,6 +460,48 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::
519 state.Apply(); 460 state.Apply();
520} 461}
521 462
463void RasterizerOpenGL::SetShader() {
464 ShaderCacheKey config = ShaderCacheKey::CurrentConfig();
465
466 // Find (or generate) the GLSL shader for the current TEV state
467 auto cached_shader = shader_cache.find(config);
468 if (cached_shader != shader_cache.end()) {
469 current_shader = cached_shader->second.get();
470
471 state.draw.shader_program = current_shader->shader.handle;
472 state.Apply();
473 } else {
474 LOG_DEBUG(Render_OpenGL, "Creating new shader: %08X", hash(config));
475
476 std::unique_ptr<TEVShader> shader = Common::make_unique<TEVShader>();
477
478 shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str());
479 shader->uniform_alphatest_ref = glGetUniformLocation(shader->shader.handle, "alphatest_ref");
480 shader->uniform_tex = glGetUniformLocation(shader->shader.handle, "tex");
481 shader->uniform_tev_combiner_buffer_color = glGetUniformLocation(shader->shader.handle, "tev_combiner_buffer_color");
482 shader->uniform_tev_const_colors = glGetUniformLocation(shader->shader.handle, "const_color");
483
484 state.draw.shader_program = shader->shader.handle;
485 state.Apply();
486
487 // Set the texture samplers to correspond to different texture units
488 if (shader->uniform_tex != -1) {
489 glUniform1i(shader->uniform_tex, 0);
490 glUniform1i(shader->uniform_tex + 1, 1);
491 glUniform1i(shader->uniform_tex + 2, 2);
492 }
493
494 current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get();
495 }
496
497 // Update uniforms
498 SyncAlphaTest();
499 SyncCombinerColor();
500 auto& tev_stages = Pica::g_state.regs.GetTevStages();
501 for (int index = 0; index < tev_stages.size(); ++index)
502 SyncTevConstColor(index, tev_stages[index]);
503}
504
522void RasterizerOpenGL::SyncFramebuffer() { 505void RasterizerOpenGL::SyncFramebuffer() {
523 const auto& regs = Pica::g_state.regs; 506 const auto& regs = Pica::g_state.regs;
524 507
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 5bc4a319f..de9e4d22e 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
8#include <memory>
7#include <vector> 9#include <vector>
8#include <unordered_map> 10#include <unordered_map>
9 11
@@ -15,21 +17,6 @@
15#include "video_core/renderer_opengl/gl_state.h" 17#include "video_core/renderer_opengl/gl_state.h"
16#include "video_core/shader/shader_interpreter.h" 18#include "video_core/shader/shader_interpreter.h"
17 19
18template <typename T>
19inline size_t hash(const T& o) {
20 return std::hash<T>()(o);
21}
22
23template <typename T>
24inline size_t combine_hash(const T& o) {
25 return hash(o);
26}
27
28template <typename T, typename... Args>
29inline size_t combine_hash(const T& o, const Args&... args) {
30 return hash(o) * 3 + combine_hash(args...);
31}
32
33struct ShaderCacheKey { 20struct ShaderCacheKey {
34 using Regs = Pica::Regs; 21 using Regs = Pica::Regs;
35 22
@@ -49,7 +36,7 @@ struct ShaderCacheKey {
49 return (stage_index < 4) && ((combiner_buffer_input >> 4) & (1 << stage_index)); 36 return (stage_index < 4) && ((combiner_buffer_input >> 4) & (1 << stage_index));
50 } 37 }
51 38
52 static ShaderCacheKey CurrentShaderConfig() { 39 static ShaderCacheKey CurrentConfig() {
53 const auto& regs = Pica::g_state.regs; 40 const auto& regs = Pica::g_state.regs;
54 ShaderCacheKey config; 41 ShaderCacheKey config;
55 42
@@ -94,8 +81,14 @@ struct ShaderCacheKey {
94 81
95namespace std { 82namespace std {
96 83
84template<> struct hash<::Pica::Regs::CompareFunc> {
85 std::size_t operator()(const ::Pica::Regs::CompareFunc& o) {
86 return ::hash((unsigned)o);
87 }
88};
89
97template<> struct hash<::Pica::Regs::TevStageConfig> { 90template<> struct hash<::Pica::Regs::TevStageConfig> {
98 size_t operator()(const ::Pica::Regs::TevStageConfig& o) { 91 std::size_t operator()(const ::Pica::Regs::TevStageConfig& o) {
99 return ::combine_hash( 92 return ::combine_hash(
100 ::hash(o.source_raw), ::hash(o.modifier_raw), 93 ::hash(o.source_raw), ::hash(o.modifier_raw),
101 ::hash(o.op_raw), ::hash(o.scale_raw)); 94 ::hash(o.op_raw), ::hash(o.scale_raw));
@@ -103,13 +96,14 @@ template<> struct hash<::Pica::Regs::TevStageConfig> {
103}; 96};
104 97
105template<> struct hash<::ShaderCacheKey> { 98template<> struct hash<::ShaderCacheKey> {
106 size_t operator()(const ::ShaderCacheKey& o) const { 99 std::size_t operator()(const ::ShaderCacheKey& o) const {
107 return ::combine_hash(o.alpha_test_func, o.combiner_buffer_input, 100 return ::combine_hash(o.alpha_test_func, o.combiner_buffer_input,
108 o.tev_stages[0], o.tev_stages[1], o.tev_stages[2], 101 o.tev_stages[0], o.tev_stages[1], o.tev_stages[2],
109 o.tev_stages[3], o.tev_stages[4], o.tev_stages[5]); 102 o.tev_stages[3], o.tev_stages[4], o.tev_stages[5]);
110 } 103 }
111}; 104};
112} 105
106} // namespace std
113 107
114class RasterizerOpenGL : public HWRasterizer { 108class RasterizerOpenGL : public HWRasterizer {
115public: 109public:
@@ -131,8 +125,6 @@ public:
131 /// Draw the current batch of triangles 125 /// Draw the current batch of triangles
132 void DrawTriangles() override; 126 void DrawTriangles() override;
133 127
134 void RegenerateShaders();
135
136 /// Commit the rasterizer's framebuffer contents immediately to the current 3DS memory framebuffer 128 /// Commit the rasterizer's framebuffer contents immediately to the current 3DS memory framebuffer
137 void CommitFramebuffer() override; 129 void CommitFramebuffer() override;
138 130
@@ -245,6 +237,9 @@ private:
245 /// Reconfigure the OpenGL depth texture to use the given format and dimensions 237 /// Reconfigure the OpenGL depth texture to use the given format and dimensions
246 void ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height); 238 void ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height);
247 239
240 /// Sets the OpenGL shader in accordance with the current PICA register state
241 void SetShader();
242
248 /// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer 243 /// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer
249 void SyncFramebuffer(); 244 void SyncFramebuffer();
250 245
@@ -315,8 +310,8 @@ private:
315 TextureInfo fb_color_texture; 310 TextureInfo fb_color_texture;
316 DepthTextureInfo fb_depth_texture; 311 DepthTextureInfo fb_depth_texture;
317 312
318 std::unordered_map<ShaderCacheKey, TEVShader> shader_cache; 313 std::unordered_map<ShaderCacheKey, std::unique_ptr<TEVShader>> shader_cache;
319 TEVShader* current_shader = nullptr; 314 const TEVShader* current_shader = nullptr;
320 315
321 OGLVertexArray vertex_array; 316 OGLVertexArray vertex_array;
322 OGLBuffer vertex_buffer; 317 OGLBuffer vertex_buffer;
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..059f127af
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -0,0 +1,371 @@
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
9namespace GLShader {
10
11static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
12 return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace &&
13 stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace &&
14 stage.color_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
15 stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
16 stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor &&
17 stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha &&
18 stage.GetColorMultiplier() == 1 &&
19 stage.GetAlphaMultiplier() == 1);
20}
21
22static void AppendSource(std::string& shader, Pica::Regs::TevStageConfig::Source source, const std::string& index_name) {
23 using Source = Pica::Regs::TevStageConfig::Source;
24 switch (source) {
25 case Source::PrimaryColor:
26 shader += "o[2]";
27 break;
28 case Source::PrimaryFragmentColor:
29 // HACK: Until we implement fragment lighting, use primary_color
30 shader += "o[2]";
31 break;
32 case Source::SecondaryFragmentColor:
33 // HACK: Until we implement fragment lighting, use zero
34 shader += "vec4(0.0, 0.0, 0.0, 0.0)";
35 break;
36 case Source::Texture0:
37 shader += "texture(tex[0], o[3].xy)";
38 break;
39 case Source::Texture1:
40 shader += "texture(tex[1], o[3].zw)";
41 break;
42 case Source::Texture2: // TODO: Unverified
43 shader += "texture(tex[2], o[5].zw)";
44 break;
45 case Source::PreviousBuffer:
46 shader += "g_combiner_buffer";
47 break;
48 case Source::Constant:
49 shader += "const_color[" + index_name + "]";
50 break;
51 case Source::Previous:
52 shader += "g_last_tex_env_out";
53 break;
54 default:
55 shader += "vec4(0.0)";
56 LOG_CRITICAL(Render_OpenGL, "Unknown source op %u", source);
57 break;
58 }
59}
60
61static void AppendColorModifier(std::string& shader, Pica::Regs::TevStageConfig::ColorModifier modifier,
62 Pica::Regs::TevStageConfig::Source source, const std::string& index_name) {
63 using ColorModifier = Pica::Regs::TevStageConfig::ColorModifier;
64 switch (modifier) {
65 case ColorModifier::SourceColor:
66 AppendSource(shader, source, index_name);
67 shader += ".rgb";
68 break;
69 case ColorModifier::OneMinusSourceColor:
70 shader += "vec3(1.0) - ";
71 AppendSource(shader, source, index_name);
72 shader += ".rgb";
73 break;
74 case ColorModifier::SourceAlpha:
75 AppendSource(shader, source, index_name);
76 shader += ".aaa";
77 break;
78 case ColorModifier::OneMinusSourceAlpha:
79 shader += "vec3(1.0) - ";
80 AppendSource(shader, source, index_name);
81 shader += ".aaa";
82 break;
83 case ColorModifier::SourceRed:
84 AppendSource(shader, source, index_name);
85 shader += ".rrr";
86 break;
87 case ColorModifier::OneMinusSourceRed:
88 shader += "vec3(1.0) - ";
89 AppendSource(shader, source, index_name);
90 shader += ".rrr";
91 break;
92 case ColorModifier::SourceGreen:
93 AppendSource(shader, source, index_name);
94 shader += ".ggg";
95 break;
96 case ColorModifier::OneMinusSourceGreen:
97 shader += "vec3(1.0) - ";
98 AppendSource(shader, source, index_name);
99 shader += ".ggg";
100 break;
101 case ColorModifier::SourceBlue:
102 AppendSource(shader, source, index_name);
103 shader += ".bbb";
104 break;
105 case ColorModifier::OneMinusSourceBlue:
106 shader += "vec3(1.0) - ";
107 AppendSource(shader, source, index_name);
108 shader += ".bbb";
109 break;
110 default:
111 shader += "vec3(0.0)";
112 LOG_CRITICAL(Render_OpenGL, "Unknown color modifier op %u", modifier);
113 break;
114 }
115}
116
117static void AppendAlphaModifier(std::string& shader, Pica::Regs::TevStageConfig::AlphaModifier modifier,
118 Pica::Regs::TevStageConfig::Source source, const std::string& index_name) {
119 using AlphaModifier = Pica::Regs::TevStageConfig::AlphaModifier;
120 switch (modifier) {
121 case AlphaModifier::SourceAlpha:
122 AppendSource(shader, source, index_name);
123 shader += ".a";
124 break;
125 case AlphaModifier::OneMinusSourceAlpha:
126 shader += "1.0 - ";
127 AppendSource(shader, source, index_name);
128 shader += ".a";
129 break;
130 case AlphaModifier::SourceRed:
131 AppendSource(shader, source, index_name);
132 shader += ".r";
133 break;
134 case AlphaModifier::OneMinusSourceRed:
135 shader += "1.0 - ";
136 AppendSource(shader, source, index_name);
137 shader += ".r";
138 break;
139 case AlphaModifier::SourceGreen:
140 AppendSource(shader, source, index_name);
141 shader += ".g";
142 break;
143 case AlphaModifier::OneMinusSourceGreen:
144 shader += "1.0 - ";
145 AppendSource(shader, source, index_name);
146 shader += ".g";
147 break;
148 case AlphaModifier::SourceBlue:
149 AppendSource(shader, source, index_name);
150 shader += ".b";
151 break;
152 case AlphaModifier::OneMinusSourceBlue:
153 shader += "1.0 - ";
154 AppendSource(shader, source, index_name);
155 shader += ".b";
156 break;
157 default:
158 shader += "vec3(0.0)";
159 LOG_CRITICAL(Render_OpenGL, "Unknown alpha modifier op %u", modifier);
160 break;
161 }
162}
163
164static void AppendColorCombiner(std::string& shader, Pica::Regs::TevStageConfig::Operation operation,
165 const std::string& variable_name) {
166 using Operation = Pica::Regs::TevStageConfig::Operation;
167
168 switch (operation) {
169 case Operation::Replace:
170 shader += variable_name + "[0]";
171 break;
172 case Operation::Modulate:
173 shader += variable_name + "[0] * " + variable_name + "[1]";
174 break;
175 case Operation::Add:
176 shader += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0))";
177 break;
178 case Operation::AddSigned:
179 shader += "clamp(" + variable_name + "[0] + " + variable_name + "[1] - vec3(0.5), vec3(0.0), vec3(1.0))";
180 break;
181 case Operation::Lerp:
182 shader += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (vec3(1.0) - " + variable_name + "[2])";
183 break;
184 case Operation::Subtract:
185 shader += "max(" + variable_name + "[0] - " + variable_name + "[1], vec3(0.0))";
186 break;
187 case Operation::MultiplyThenAdd:
188 shader += "min(" + variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2], vec3(1.0))";
189 break;
190 case Operation::AddThenMultiply:
191 shader += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + variable_name + "[2]";
192 break;
193 default:
194 shader += "vec3(0.0)";
195 LOG_CRITICAL(Render_OpenGL, "Unknown color comb op %u", operation);
196 break;
197 }
198}
199
200static void AppendAlphaCombiner(std::string& shader, Pica::Regs::TevStageConfig::Operation operation,
201 const std::string& variable_name) {
202 using Operation = Pica::Regs::TevStageConfig::Operation;
203 switch (operation) {
204 case Operation::Replace:
205 shader += variable_name + "[0]";
206 break;
207 case Operation::Modulate:
208 shader += variable_name + "[0] * " + variable_name + "[1]";
209 break;
210 case Operation::Add:
211 shader += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0)";
212 break;
213 case Operation::AddSigned:
214 shader += "clamp(" + variable_name + "[0] + " + variable_name + "[1] - 0.5, 0.0, 1.0)";
215 break;
216 case Operation::Lerp:
217 shader += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (1.0 - " + variable_name + "[2])";
218 break;
219 case Operation::Subtract:
220 shader += "max(" + variable_name + "[0] - " + variable_name + "[1], 0.0)";
221 break;
222 case Operation::MultiplyThenAdd:
223 shader += "min(" + variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2], 1.0)";
224 break;
225 case Operation::AddThenMultiply:
226 shader += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + "[2]";
227 break;
228 default:
229 shader += "0.0";
230 LOG_CRITICAL(Render_OpenGL, "Unknown alpha combiner op %u", operation);
231 break;
232 }
233}
234
235static void AppendAlphaTestCondition(std::string& shader, Pica::Regs::CompareFunc func) {
236 using CompareFunc = Pica::Regs::CompareFunc;
237 switch (func) {
238 case CompareFunc::Never:
239 shader += "true";
240 break;
241 case CompareFunc::Always:
242 shader += "false";
243 break;
244 case CompareFunc::Equal:
245 shader += "int(g_last_tex_env_out.a * 255.0f) != alphatest_ref";
246 break;
247 case CompareFunc::NotEqual:
248 shader += "int(g_last_tex_env_out.a * 255.0f) == alphatest_ref";
249 break;
250 case CompareFunc::LessThan:
251 shader += "int(g_last_tex_env_out.a * 255.0f) >= alphatest_ref";
252 break;
253 case CompareFunc::LessThanOrEqual:
254 shader += "int(g_last_tex_env_out.a * 255.0f) > alphatest_ref";
255 break;
256 case CompareFunc::GreaterThan:
257 shader += "int(g_last_tex_env_out.a * 255.0f) <= alphatest_ref";
258 break;
259 case CompareFunc::GreaterThanOrEqual:
260 shader += "int(g_last_tex_env_out.a * 255.0f) < alphatest_ref";
261 break;
262 default:
263 shader += "false";
264 LOG_CRITICAL(Render_OpenGL, "Unknown alpha test condition %u", func);
265 break;
266 }
267}
268
269std::string GenerateFragmentShader(const ShaderCacheKey& config) {
270 std::string shader = R"(
271#version 150 core
272
273#define NUM_VTX_ATTR 7
274#define NUM_TEV_STAGES 6
275
276in vec4 o[NUM_VTX_ATTR];
277out vec4 color;
278
279uniform int alphatest_ref;
280uniform vec4 const_color[NUM_TEV_STAGES];
281uniform sampler2D tex[3];
282
283uniform vec4 tev_combiner_buffer_color;
284
285void main(void) {
286vec4 g_combiner_buffer = tev_combiner_buffer_color;
287vec4 g_last_tex_env_out = vec4(0.0, 0.0, 0.0, 0.0);
288)";
289
290 // Do not do any sort of processing if it's obvious we're not going to pass the alpha test
291 if (config.alpha_test_func == Pica::Regs::CompareFunc::Never) {
292 shader += "discard;";
293 return shader;
294 }
295
296 auto& tev_stages = config.tev_stages;
297 for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) {
298 auto& tev_stage = tev_stages[tev_stage_index];
299 if (!IsPassThroughTevStage(tev_stage)) {
300 std::string index_name = std::to_string(tev_stage_index);
301
302 shader += "vec3 color_results_" + index_name + "[3] = vec3[3](";
303 AppendColorModifier(shader, tev_stage.color_modifier1, tev_stage.color_source1, index_name);
304 shader += ", ";
305 AppendColorModifier(shader, tev_stage.color_modifier2, tev_stage.color_source2, index_name);
306 shader += ", ";
307 AppendColorModifier(shader, tev_stage.color_modifier3, tev_stage.color_source3, index_name);
308 shader += ");\n";
309
310 shader += "vec3 color_output_" + index_name + " = ";
311 AppendColorCombiner(shader, tev_stage.color_op, "color_results_" + index_name);
312 shader += ";\n";
313
314 shader += "float alpha_results_" + index_name + "[3] = float[3](";
315 AppendAlphaModifier(shader, tev_stage.alpha_modifier1, tev_stage.alpha_source1, index_name);
316 shader += ", ";
317 AppendAlphaModifier(shader, tev_stage.alpha_modifier2, tev_stage.alpha_source2, index_name);
318 shader += ", ";
319 AppendAlphaModifier(shader, tev_stage.alpha_modifier3, tev_stage.alpha_source3, index_name);
320 shader += ");\n";
321
322 shader += "float alpha_output_" + index_name + " = ";
323 AppendAlphaCombiner(shader, tev_stage.alpha_op, "alpha_results_" + index_name);
324 shader += ";\n";
325
326 shader += "g_last_tex_env_out = vec4(min(color_output_" + index_name + " * " + std::to_string(tev_stage.GetColorMultiplier()) + ".0, 1.0), min(alpha_output_" + index_name + " * " + std::to_string(tev_stage.GetAlphaMultiplier()) + ".0, 1.0));\n";
327 }
328
329 if (config.TevStageUpdatesCombinerBufferColor(tev_stage_index))
330 shader += "g_combiner_buffer.rgb = g_last_tex_env_out.rgb;\n";
331
332 if (config.TevStageUpdatesCombinerBufferAlpha(tev_stage_index))
333 shader += "g_combiner_buffer.a = g_last_tex_env_out.a;\n";
334 }
335
336 if (config.alpha_test_func != Pica::Regs::CompareFunc::Always) {
337 shader += "if (";
338 AppendAlphaTestCondition(shader, config.alpha_test_func);
339 shader += ") {\n discard;\n }\n";
340 }
341
342 shader += "color = g_last_tex_env_out;\n}";
343 return shader;
344}
345
346std::string GenerateVertexShader() {
347 static const std::string shader_str = R"(
348#version 150 core
349
350#define NUM_VTX_ATTR 7
351
352in vec4 vert_position;
353in vec4 vert_color;
354in vec2 vert_texcoords0;
355in vec2 vert_texcoords1;
356in vec2 vert_texcoords2;
357
358out vec4 o[NUM_VTX_ATTR];
359
360void main() {
361 o[2] = vert_color;
362 o[3] = vec4(vert_texcoords0.xy, vert_texcoords1.xy);
363 o[5] = vec4(0.0, 0.0, vert_texcoords2.xy);
364
365 gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w);
366}
367)";
368 return shader_str;
369}
370
371} // namespace GLShaderGen
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..7fd18de6d
--- /dev/null
+++ b/src/video_core/renderer_opengl/gl_shader_gen.h
@@ -0,0 +1,17 @@
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
13std::string GenerateVertexShader();
14
15std::string GenerateFragmentShader(const ShaderCacheKey& config);
16
17} // 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 8a6a51ad4..ce218b857 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_util.cpp
@@ -2,22 +2,15 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5
6#include "gl_shader_util.h"
7#include "gl_rasterizer.h"
8#include "common/logging/log.h"
9
10#include "video_core/pica.h"
11
12#include <algorithm> 5#include <algorithm>
13#include <vector> 6#include <vector>
14 7
15#include "common/logging/log.h" 8#include "common/logging/log.h"
16#include "video_core/renderer_opengl/gl_shader_util.h" 9#include "video_core/renderer_opengl/gl_shader_util.h"
17 10
18namespace ShaderUtil { 11namespace GLShader {
19 12
20GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { 13GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) {
21 14
22 // Create the shaders 15 // Create the shaders
23 GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER); 16 GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER);
@@ -101,339 +94,4 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
101 return program_id; 94 return program_id;
102} 95}
103 96
104} 97} // namespace GLShader
105
106namespace ShaderCache
107{
108
109static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
110 return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace &&
111 stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace &&
112 stage.color_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
113 stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
114 stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor &&
115 stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha &&
116 stage.GetColorMultiplier() == 1 &&
117 stage.GetAlphaMultiplier() == 1);
118}
119
120void AppendSource(std::string& shader, Pica::Regs::TevStageConfig::Source source, const std::string& index_name) {
121 using Source = Pica::Regs::TevStageConfig::Source;
122 switch (source) {
123 case Source::PrimaryColor:
124 shader += "o[2]";
125 break;
126 case Source::PrimaryFragmentColor:
127 // HACK: Until we implement fragment lighting, use primary_color
128 shader += "o[2]";
129 break;
130 case Source::SecondaryFragmentColor:
131 // HACK: Until we implement fragment lighting, use zero
132 shader += "vec4(0.0, 0.0, 0.0, 0.0)";
133 break;
134 case Source::Texture0:
135 shader += "texture(tex[0], o[3].xy)";
136 break;
137 case Source::Texture1:
138 shader += "texture(tex[1], o[3].zw)";
139 break;
140 case Source::Texture2: // TODO: Unverified
141 shader += "texture(tex[2], o[5].zw)";
142 break;
143 case Source::PreviousBuffer:
144 shader += "g_combiner_buffer";
145 break;
146 case Source::Constant:
147 shader += "const_color[" + index_name + "]";
148 break;
149 case Source::Previous:
150 shader += "g_last_tex_env_out";
151 break;
152 default:
153 shader += "vec4(0.0)";
154 LOG_CRITICAL(Render_OpenGL, "Unknown source op %u", source);
155 break;
156 }
157}
158
159void AppendColorModifier(std::string& shader, Pica::Regs::TevStageConfig::ColorModifier modifier, Pica::Regs::TevStageConfig::Source source, const std::string& index_name) {
160 using ColorModifier = Pica::Regs::TevStageConfig::ColorModifier;
161 switch (modifier) {
162 case ColorModifier::SourceColor:
163 AppendSource(shader, source, index_name);
164 shader += ".rgb";
165 break;
166 case ColorModifier::OneMinusSourceColor:
167 shader += "vec3(1.0) - ";
168 AppendSource(shader, source, index_name);
169 shader += ".rgb";
170 break;
171 case ColorModifier::SourceAlpha:
172 AppendSource(shader, source, index_name);
173 shader += ".aaa";
174 break;
175 case ColorModifier::OneMinusSourceAlpha:
176 shader += "vec3(1.0) - ";
177 AppendSource(shader, source, index_name);
178 shader += ".aaa";
179 break;
180 case ColorModifier::SourceRed:
181 AppendSource(shader, source, index_name);
182 shader += ".rrr";
183 break;
184 case ColorModifier::OneMinusSourceRed:
185 shader += "vec3(1.0) - ";
186 AppendSource(shader, source, index_name);
187 shader += ".rrr";
188 break;
189 case ColorModifier::SourceGreen:
190 AppendSource(shader, source, index_name);
191 shader += ".ggg";
192 break;
193 case ColorModifier::OneMinusSourceGreen:
194 shader += "vec3(1.0) - ";
195 AppendSource(shader, source, index_name);
196 shader += ".ggg";
197 break;
198 case ColorModifier::SourceBlue:
199 AppendSource(shader, source, index_name);
200 shader += ".bbb";
201 break;
202 case ColorModifier::OneMinusSourceBlue:
203 shader += "vec3(1.0) - ";
204 AppendSource(shader, source, index_name);
205 shader += ".bbb";
206 break;
207 default:
208 shader += "vec3(0.0)";
209 LOG_CRITICAL(Render_OpenGL, "Unknown color modifier op %u", modifier);
210 break;
211 }
212}
213
214void AppendAlphaModifier(std::string& shader, Pica::Regs::TevStageConfig::AlphaModifier modifier, Pica::Regs::TevStageConfig::Source source, const std::string& index_name) {
215 using AlphaModifier = Pica::Regs::TevStageConfig::AlphaModifier;
216 switch (modifier) {
217 case AlphaModifier::SourceAlpha:
218 AppendSource(shader, source, index_name);
219 shader += ".a";
220 break;
221 case AlphaModifier::OneMinusSourceAlpha:
222 shader += "1.0 - ";
223 AppendSource(shader, source, index_name);
224 shader += ".a";
225 break;
226 case AlphaModifier::SourceRed:
227 AppendSource(shader, source, index_name);
228 shader += ".r";
229 break;
230 case AlphaModifier::OneMinusSourceRed:
231 shader += "1.0 - ";
232 AppendSource(shader, source, index_name);
233 shader += ".r";
234 break;
235 case AlphaModifier::SourceGreen:
236 AppendSource(shader, source, index_name);
237 shader += ".g";
238 break;
239 case AlphaModifier::OneMinusSourceGreen:
240 shader += "1.0 - ";
241 AppendSource(shader, source, index_name);
242 shader += ".g";
243 break;
244 case AlphaModifier::SourceBlue:
245 AppendSource(shader, source, index_name);
246 shader += ".b";
247 break;
248 case AlphaModifier::OneMinusSourceBlue:
249 shader += "1.0 - ";
250 AppendSource(shader, source, index_name);
251 shader += ".b";
252 break;
253 default:
254 shader += "vec3(0.0)";
255 LOG_CRITICAL(Render_OpenGL, "Unknown alpha modifier op %u", modifier);
256 break;
257 }
258}
259
260void AppendColorCombiner(std::string& shader, Pica::Regs::TevStageConfig::Operation operation, const std::string& variable_name) {
261 using Operation = Pica::Regs::TevStageConfig::Operation;
262
263 switch (operation) {
264 case Operation::Replace:
265 shader += variable_name + "[0]";
266 break;
267 case Operation::Modulate:
268 shader += variable_name + "[0] * " + variable_name + "[1]";
269 break;
270 case Operation::Add:
271 shader += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0))";
272 break;
273 case Operation::AddSigned:
274 shader += "clamp(" + variable_name + "[0] + " + variable_name + "[1] - vec3(0.5), vec3(0.0), vec3(1.0))";
275 break;
276 case Operation::Lerp:
277 shader += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (vec3(1.0) - " + variable_name + "[2])";
278 break;
279 case Operation::Subtract:
280 shader += "max(" + variable_name + "[0] - " + variable_name + "[1], vec3(0.0))";
281 break;
282 case Operation::MultiplyThenAdd:
283 shader += "min(" + variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2], vec3(1.0))";
284 break;
285 case Operation::AddThenMultiply:
286 shader += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + variable_name + "[2]";
287 break;
288 default:
289 shader += "vec3(0.0)";
290 LOG_CRITICAL(Render_OpenGL, "Unknown color comb op %u", operation);
291 break;
292 }
293}
294
295void AppendAlphaCombiner(std::string& shader, Pica::Regs::TevStageConfig::Operation operation, const std::string& variable_name) {
296 using Operation = Pica::Regs::TevStageConfig::Operation;
297 switch (operation) {
298 case Operation::Replace:
299 shader += variable_name + "[0]";
300 break;
301 case Operation::Modulate:
302 shader += variable_name + "[0] * " + variable_name + "[1]";
303 break;
304 case Operation::Add:
305 shader += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0)";
306 break;
307 case Operation::AddSigned:
308 shader += "clamp(" + variable_name + "[0] + " + variable_name + "[1] - 0.5, 0.0, 1.0)";
309 break;
310 case Operation::Lerp:
311 shader += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (1.0 - " + variable_name + "[2])";
312 break;
313 case Operation::Subtract:
314 shader += "max(" + variable_name + "[0] - " + variable_name + "[1], 0.0)";
315 break;
316 case Operation::MultiplyThenAdd:
317 shader += "min(" + variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2], 1.0)";
318 break;
319 case Operation::AddThenMultiply:
320 shader += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + "[2]";
321 break;
322 default:
323 shader += "0.0";
324 LOG_CRITICAL(Render_OpenGL, "Unknown alpha combiner op %u", operation);
325 break;
326 }
327}
328
329void AppendAlphaTestCondition(std::string& shader, Pica::Regs::CompareFunc func) {
330 using CompareFunc = Pica::Regs::CompareFunc;
331 switch (func) {
332 case CompareFunc::Never:
333 shader += "true";
334 break;
335 case CompareFunc::Always:
336 shader += "false";
337 break;
338 case CompareFunc::Equal:
339 shader += "int(g_last_tex_env_out.a * 255.0f) != alphatest_ref";
340 break;
341 case CompareFunc::NotEqual:
342 shader += "int(g_last_tex_env_out.a * 255.0f) == alphatest_ref";
343 break;
344 case CompareFunc::LessThan:
345 shader += "int(g_last_tex_env_out.a * 255.0f) >= alphatest_ref";
346 break;
347 case CompareFunc::LessThanOrEqual:
348 shader += "int(g_last_tex_env_out.a * 255.0f) > alphatest_ref";
349 break;
350 case CompareFunc::GreaterThan:
351 shader += "int(g_last_tex_env_out.a * 255.0f) <= alphatest_ref";
352 break;
353 case CompareFunc::GreaterThanOrEqual:
354 shader += "int(g_last_tex_env_out.a * 255.0f) < alphatest_ref";
355 break;
356 default:
357 shader += "false";
358 LOG_CRITICAL(Render_OpenGL, "Unknown alpha test condition %u", func);
359 break;
360 }
361}
362
363std::string GenerateFragmentShader(const ShaderCacheKey& config) {
364 std::string shader = R"(
365#version 150 core
366
367#define NUM_VTX_ATTR 7
368#define NUM_TEV_STAGES 6
369
370in vec4 o[NUM_VTX_ATTR];
371out vec4 color;
372
373uniform int alphatest_ref;
374uniform vec4 const_color[NUM_TEV_STAGES];
375uniform sampler2D tex[3];
376
377uniform vec4 tev_combiner_buffer_color;
378
379void main(void) {
380 vec4 g_combiner_buffer = tev_combiner_buffer_color;
381 vec4 g_last_tex_env_out = vec4(0.0, 0.0, 0.0, 0.0);
382)";
383
384 // Do not do any sort of processing if it's obvious we're not going to pass the alpha test
385 if (config.alpha_test_func == Pica::Regs::CompareFunc::Never) {
386 shader += "discard;";
387 return shader;
388 }
389
390 auto& tev_stages = config.tev_stages;
391 for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) {
392 auto& tev_stage = tev_stages[tev_stage_index];
393 if (!IsPassThroughTevStage(tev_stage)) {
394 std::string index_name = std::to_string(tev_stage_index);
395
396 shader += "vec3 color_results_" + index_name + "[3] = vec3[3](";
397 AppendColorModifier(shader, tev_stage.color_modifier1, tev_stage.color_source1, index_name);
398 shader += ", ";
399 AppendColorModifier(shader, tev_stage.color_modifier2, tev_stage.color_source2, index_name);
400 shader += ", ";
401 AppendColorModifier(shader, tev_stage.color_modifier3, tev_stage.color_source3, index_name);
402 shader += ");\n";
403
404 shader += "vec3 color_output_" + index_name + " = ";
405 AppendColorCombiner(shader, tev_stage.color_op, "color_results_" + index_name);
406 shader += ";\n";
407
408 shader += "float alpha_results_" + index_name + "[3] = float[3](";
409 AppendAlphaModifier(shader, tev_stage.alpha_modifier1, tev_stage.alpha_source1, index_name);
410 shader += ", ";
411 AppendAlphaModifier(shader, tev_stage.alpha_modifier2, tev_stage.alpha_source2, index_name);
412 shader += ", ";
413 AppendAlphaModifier(shader, tev_stage.alpha_modifier3, tev_stage.alpha_source3, index_name);
414 shader += ");\n";
415
416 shader += "float alpha_output_" + index_name + " = ";
417 AppendAlphaCombiner(shader, tev_stage.alpha_op, "alpha_results_" + index_name);
418 shader += ";\n";
419
420 shader += "g_last_tex_env_out = vec4(min(color_output_" + index_name + " * " + std::to_string(tev_stage.GetColorMultiplier()) + ".0, 1.0), min(alpha_output_" + index_name + " * " + std::to_string(tev_stage.GetAlphaMultiplier()) + ".0, 1.0));\n";
421 }
422
423 if (config.TevStageUpdatesCombinerBufferColor(tev_stage_index))
424 shader += "g_combiner_buffer.rgb = g_last_tex_env_out.rgb;\n";
425
426 if (config.TevStageUpdatesCombinerBufferAlpha(tev_stage_index))
427 shader += "g_combiner_buffer.a = g_last_tex_env_out.a;\n";
428 }
429
430 if (config.alpha_test_func != Pica::Regs::CompareFunc::Always) {
431 shader += "if (";
432 AppendAlphaTestCondition(shader, config.alpha_test_func);
433 shader += ") {\n discard;\n }\n";
434 }
435
436 shader += "color = g_last_tex_env_out;\n}";
437 return shader;
438}
439}
diff --git a/src/video_core/renderer_opengl/gl_shader_util.h b/src/video_core/renderer_opengl/gl_shader_util.h
index ca62c83ba..6e2d007f8 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.h
+++ b/src/video_core/renderer_opengl/gl_shader_util.h
@@ -6,7 +6,7 @@
6 6
7#include <glad/glad.h> 7#include <glad/glad.h>
8 8
9namespace ShaderUtil { 9namespace GLShader {
10 10
11enum Attributes { 11enum Attributes {
12 ATTRIBUTE_POSITION = 0, 12 ATTRIBUTE_POSITION = 0,
@@ -14,6 +14,6 @@ enum Attributes {
14 ATTRIBUTE_TEXCOORDS = 2, 14 ATTRIBUTE_TEXCOORDS = 2,
15}; 15};
16 16
17GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path); 17GLuint LoadProgram(const char* vertex_file_path, const char* fragment_file_path);
18 18
19} 19} // 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 2ba2c6b0f..000000000
--- a/src/video_core/renderer_opengl/gl_shaders.h
+++ /dev/null
@@ -1,339 +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_texcoords0;
53in vec2 vert_texcoords1;
54in vec2 vert_texcoords2;
55
56out vec4 o[NUM_VTX_ATTR];
57
58void main() {
59 o[2] = vert_color;
60 o[3] = vec4(vert_texcoords0.xy, vert_texcoords1.xy);
61 o[5] = vec4(0.0, 0.0, vert_texcoords2.xy);
62
63 gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w);
64}
65)";
66
67// TODO: Create a shader constructor and cache that builds this program with minimal conditionals instead of using tev_cfg uniforms
68const char g_fragment_shader_hw[] = R"(
69#version 150 core
70
71#define NUM_VTX_ATTR 7
72#define NUM_TEV_STAGES 6
73
74#define SOURCE_PRIMARYCOLOR 0x0
75#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1
76#define SOURCE_SECONDARYFRAGMENTCOLOR 0x2
77#define SOURCE_TEXTURE0 0x3
78#define SOURCE_TEXTURE1 0x4
79#define SOURCE_TEXTURE2 0x5
80#define SOURCE_TEXTURE3 0x6
81#define SOURCE_PREVIOUSBUFFER 0xd
82#define SOURCE_CONSTANT 0xe
83#define SOURCE_PREVIOUS 0xf
84
85#define COLORMODIFIER_SOURCECOLOR 0x0
86#define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1
87#define COLORMODIFIER_SOURCEALPHA 0x2
88#define COLORMODIFIER_ONEMINUSSOURCEALPHA 0x3
89#define COLORMODIFIER_SOURCERED 0x4
90#define COLORMODIFIER_ONEMINUSSOURCERED 0x5
91#define COLORMODIFIER_SOURCEGREEN 0x8
92#define COLORMODIFIER_ONEMINUSSOURCEGREEN 0x9
93#define COLORMODIFIER_SOURCEBLUE 0xc
94#define COLORMODIFIER_ONEMINUSSOURCEBLUE 0xd
95
96#define ALPHAMODIFIER_SOURCEALPHA 0x0
97#define ALPHAMODIFIER_ONEMINUSSOURCEALPHA 0x1
98#define ALPHAMODIFIER_SOURCERED 0x2
99#define ALPHAMODIFIER_ONEMINUSSOURCERED 0x3
100#define ALPHAMODIFIER_SOURCEGREEN 0x4
101#define ALPHAMODIFIER_ONEMINUSSOURCEGREEN 0x5
102#define ALPHAMODIFIER_SOURCEBLUE 0x6
103#define ALPHAMODIFIER_ONEMINUSSOURCEBLUE 0x7
104
105#define OPERATION_REPLACE 0
106#define OPERATION_MODULATE 1
107#define OPERATION_ADD 2
108#define OPERATION_ADDSIGNED 3
109#define OPERATION_LERP 4
110#define OPERATION_SUBTRACT 5
111#define OPERATION_MULTIPLYTHENADD 8
112#define OPERATION_ADDTHENMULTIPLY 9
113
114#define COMPAREFUNC_NEVER 0
115#define COMPAREFUNC_ALWAYS 1
116#define COMPAREFUNC_EQUAL 2
117#define COMPAREFUNC_NOTEQUAL 3
118#define COMPAREFUNC_LESSTHAN 4
119#define COMPAREFUNC_LESSTHANOREQUAL 5
120#define COMPAREFUNC_GREATERTHAN 6
121#define COMPAREFUNC_GREATERTHANOREQUAL 7
122
123in vec4 o[NUM_VTX_ATTR];
124out vec4 color;
125
126uniform bool alphatest_enabled;
127uniform int alphatest_func;
128uniform float alphatest_ref;
129
130uniform sampler2D tex[3];
131
132uniform vec4 tev_combiner_buffer_color;
133
134struct TEVConfig
135{
136 bool enabled;
137 ivec3 color_sources;
138 ivec3 alpha_sources;
139 ivec3 color_modifiers;
140 ivec3 alpha_modifiers;
141 ivec2 color_alpha_op;
142 ivec2 color_alpha_multiplier;
143 vec4 const_color;
144 bvec2 updates_combiner_buffer_color_alpha;
145};
146
147uniform TEVConfig tev_cfgs[NUM_TEV_STAGES];
148
149vec4 g_combiner_buffer;
150vec4 g_last_tex_env_out;
151vec4 g_const_color;
152
153vec4 GetSource(int source) {
154 if (source == SOURCE_PRIMARYCOLOR) {
155 return o[2];
156 } else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) {
157 // HACK: Until we implement fragment lighting, use primary_color
158 return o[2];
159 } else if (source == SOURCE_SECONDARYFRAGMENTCOLOR) {
160 // HACK: Until we implement fragment lighting, use zero
161 return vec4(0.0, 0.0, 0.0, 0.0);
162 } else if (source == SOURCE_TEXTURE0) {
163 return texture(tex[0], o[3].xy);
164 } else if (source == SOURCE_TEXTURE1) {
165 return texture(tex[1], o[3].zw);
166 } else if (source == SOURCE_TEXTURE2) {
167 // TODO: Unverified
168 return texture(tex[2], o[5].zw);
169 } else if (source == SOURCE_TEXTURE3) {
170 // TODO: no 4th texture?
171 } else if (source == SOURCE_PREVIOUSBUFFER) {
172 return g_combiner_buffer;
173 } else if (source == SOURCE_CONSTANT) {
174 return g_const_color;
175 } else if (source == SOURCE_PREVIOUS) {
176 return g_last_tex_env_out;
177 }
178
179 return vec4(0.0);
180}
181
182vec3 GetColorModifier(int factor, vec4 color) {
183 if (factor == COLORMODIFIER_SOURCECOLOR) {
184 return color.rgb;
185 } else if (factor == COLORMODIFIER_ONEMINUSSOURCECOLOR) {
186 return vec3(1.0) - color.rgb;
187 } else if (factor == COLORMODIFIER_SOURCEALPHA) {
188 return color.aaa;
189 } else if (factor == COLORMODIFIER_ONEMINUSSOURCEALPHA) {
190 return vec3(1.0) - color.aaa;
191 } else if (factor == COLORMODIFIER_SOURCERED) {
192 return color.rrr;
193 } else if (factor == COLORMODIFIER_ONEMINUSSOURCERED) {
194 return vec3(1.0) - color.rrr;
195 } else if (factor == COLORMODIFIER_SOURCEGREEN) {
196 return color.ggg;
197 } else if (factor == COLORMODIFIER_ONEMINUSSOURCEGREEN) {
198 return vec3(1.0) - color.ggg;
199 } else if (factor == COLORMODIFIER_SOURCEBLUE) {
200 return color.bbb;
201 } else if (factor == COLORMODIFIER_ONEMINUSSOURCEBLUE) {
202 return vec3(1.0) - color.bbb;
203 }
204
205 return vec3(0.0);
206}
207
208float GetAlphaModifier(int factor, vec4 color) {
209 if (factor == ALPHAMODIFIER_SOURCEALPHA) {
210 return color.a;
211 } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEALPHA) {
212 return 1.0 - color.a;
213 } else if (factor == ALPHAMODIFIER_SOURCERED) {
214 return color.r;
215 } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCERED) {
216 return 1.0 - color.r;
217 } else if (factor == ALPHAMODIFIER_SOURCEGREEN) {
218 return color.g;
219 } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEGREEN) {
220 return 1.0 - color.g;
221 } else if (factor == ALPHAMODIFIER_SOURCEBLUE) {
222 return color.b;
223 } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEBLUE) {
224 return 1.0 - color.b;
225 }
226
227 return 0.0;
228}
229
230vec3 ColorCombine(int op, vec3 color[3]) {
231 if (op == OPERATION_REPLACE) {
232 return color[0];
233 } else if (op == OPERATION_MODULATE) {
234 return color[0] * color[1];
235 } else if (op == OPERATION_ADD) {
236 return min(color[0] + color[1], 1.0);
237 } else if (op == OPERATION_ADDSIGNED) {
238 return clamp(color[0] + color[1] - vec3(0.5), 0.0, 1.0);
239 } else if (op == OPERATION_LERP) {
240 return color[0] * color[2] + color[1] * (vec3(1.0) - color[2]);
241 } else if (op == OPERATION_SUBTRACT) {
242 return max(color[0] - color[1], 0.0);
243 } else if (op == OPERATION_MULTIPLYTHENADD) {
244 return min(color[0] * color[1] + color[2], 1.0);
245 } else if (op == OPERATION_ADDTHENMULTIPLY) {
246 return min(color[0] + color[1], 1.0) * color[2];
247 }
248
249 return vec3(0.0);
250}
251
252float AlphaCombine(int op, float alpha[3]) {
253 if (op == OPERATION_REPLACE) {
254 return alpha[0];
255 } else if (op == OPERATION_MODULATE) {
256 return alpha[0] * alpha[1];
257 } else if (op == OPERATION_ADD) {
258 return min(alpha[0] + alpha[1], 1.0);
259 } else if (op == OPERATION_ADDSIGNED) {
260 return clamp(alpha[0] + alpha[1] - 0.5, 0.0, 1.0);
261 } else if (op == OPERATION_LERP) {
262 return alpha[0] * alpha[2] + alpha[1] * (1.0 - alpha[2]);
263 } else if (op == OPERATION_SUBTRACT) {
264 return max(alpha[0] - alpha[1], 0.0);
265 } else if (op == OPERATION_MULTIPLYTHENADD) {
266 return min(alpha[0] * alpha[1] + alpha[2], 1.0);
267 } else if (op == OPERATION_ADDTHENMULTIPLY) {
268 return min(alpha[0] + alpha[1], 1.0) * alpha[2];
269 }
270
271 return 0.0;
272}
273
274void main(void) {
275 g_combiner_buffer = tev_combiner_buffer_color;
276
277 for (int tex_env_idx = 0; tex_env_idx < NUM_TEV_STAGES; ++tex_env_idx) {
278 if (tev_cfgs[tex_env_idx].enabled) {
279 g_const_color = tev_cfgs[tex_env_idx].const_color;
280
281 vec3 color_results[3] = vec3[3](GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.x, GetSource(tev_cfgs[tex_env_idx].color_sources.x)),
282 GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.y, GetSource(tev_cfgs[tex_env_idx].color_sources.y)),
283 GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.z, GetSource(tev_cfgs[tex_env_idx].color_sources.z)));
284 vec3 color_output = ColorCombine(tev_cfgs[tex_env_idx].color_alpha_op.x, color_results);
285
286 float alpha_results[3] = float[3](GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.x, GetSource(tev_cfgs[tex_env_idx].alpha_sources.x)),
287 GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.y, GetSource(tev_cfgs[tex_env_idx].alpha_sources.y)),
288 GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.z, GetSource(tev_cfgs[tex_env_idx].alpha_sources.z)));
289 float alpha_output = AlphaCombine(tev_cfgs[tex_env_idx].color_alpha_op.y, alpha_results);
290
291 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));
292 }
293
294 if (tev_cfgs[tex_env_idx].updates_combiner_buffer_color_alpha.x) {
295 g_combiner_buffer.rgb = g_last_tex_env_out.rgb;
296 }
297
298 if (tev_cfgs[tex_env_idx].updates_combiner_buffer_color_alpha.y) {
299 g_combiner_buffer.a = g_last_tex_env_out.a;
300 }
301 }
302
303 if (alphatest_enabled) {
304 if (alphatest_func == COMPAREFUNC_NEVER) {
305 discard;
306 } else if (alphatest_func == COMPAREFUNC_ALWAYS) {
307
308 } else if (alphatest_func == COMPAREFUNC_EQUAL) {
309 if (g_last_tex_env_out.a != alphatest_ref) {
310 discard;
311 }
312 } else if (alphatest_func == COMPAREFUNC_NOTEQUAL) {
313 if (g_last_tex_env_out.a == alphatest_ref) {
314 discard;
315 }
316 } else if (alphatest_func == COMPAREFUNC_LESSTHAN) {
317 if (g_last_tex_env_out.a >= alphatest_ref) {
318 discard;
319 }
320 } else if (alphatest_func == COMPAREFUNC_LESSTHANOREQUAL) {
321 if (g_last_tex_env_out.a > alphatest_ref) {
322 discard;
323 }
324 } else if (alphatest_func == COMPAREFUNC_GREATERTHAN) {
325 if (g_last_tex_env_out.a <= alphatest_ref) {
326 discard;
327 }
328 } else if (alphatest_func == COMPAREFUNC_GREATERTHANOREQUAL) {
329 if (g_last_tex_env_out.a < alphatest_ref) {
330 discard;
331 }
332 }
333 }
334
335 color = g_last_tex_env_out;
336}
337)";
338
339}
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");