summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbunnei <bunneidev@gmail.com>2015-10-06 04:33:47 +0200
committerbunnei <bunneidev@gmail.com>2015-10-22 03:53:14 +0200
commitc86b9d42423b5a83ccba40f828b7ad9dafe3e317 (patch)
tree04bdd0a99fa7fa36946422d0119b3d537dd99526
parentgl_rasterizer: Move logic for creating ShaderCacheKey to a static function. (diff)
downloadyuzu-c86b9d42423b5a83ccba40f828b7ad9dafe3e317.tar
yuzu-c86b9d42423b5a83ccba40f828b7ad9dafe3e317.tar.gz
yuzu-c86b9d42423b5a83ccba40f828b7ad9dafe3e317.tar.bz2
yuzu-c86b9d42423b5a83ccba40f828b7ad9dafe3e317.tar.lz
yuzu-c86b9d42423b5a83ccba40f828b7ad9dafe3e317.tar.xz
yuzu-c86b9d42423b5a83ccba40f828b7ad9dafe3e317.tar.zst
yuzu-c86b9d42423b5a83ccba40f828b7ad9dafe3e317.zip
-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 @@
#pragma once
+#include <cstddef>
+#include <functional>
+
#include "common_types.h"
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
@@ -95,3 +98,18 @@ inline u64 _rotr64(u64 x, unsigned int shift){
// This function might change the error code.
// Defined in Misc.cpp.
const char* GetLastErrorMsg();
+
+template <typename T>
+inline std::size_t hash(const T& o) {
+ return std::hash<T>()(o);
+}
+
+template <typename T>
+inline std::size_t combine_hash(const T& o) {
+ return hash(o);
+}
+
+template <typename T, typename... Args>
+inline std::size_t combine_hash(const T& o, const Args&... args) {
+ return hash(o) * 3 + combine_hash(args...);
+}
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 @@
set(SRCS
renderer_opengl/gl_rasterizer.cpp
renderer_opengl/gl_rasterizer_cache.cpp
+ renderer_opengl/gl_shader_gen.cpp
renderer_opengl/gl_shader_util.cpp
renderer_opengl/gl_state.cpp
renderer_opengl/renderer_opengl.cpp
@@ -21,8 +22,8 @@ set(HEADERS
renderer_opengl/gl_rasterizer.h
renderer_opengl/gl_rasterizer_cache.h
renderer_opengl/gl_resource_manager.h
+ renderer_opengl/gl_shader_gen.h
renderer_opengl/gl_shader_util.h
- renderer_opengl/gl_shaders.h
renderer_opengl/gl_state.h
renderer_opengl/pica_to_gl.h
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 @@
#include "common/color.h"
#include "common/file_util.h"
+#include "common/make_unique.h"
#include "common/math_util.h"
#include "common/microprofile.h"
#include "common/profiler.h"
@@ -20,7 +21,7 @@
#include "video_core/pica.h"
#include "video_core/utils.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
-#include "video_core/renderer_opengl/gl_shaders.h"
+#include "video_core/renderer_opengl/gl_shader_gen.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
#include "video_core/renderer_opengl/pica_to_gl.h"
@@ -54,20 +55,20 @@ void RasterizerOpenGL::InitObjects() {
state.Apply();
// Set vertex attributes
- glVertexAttribPointer(ShaderUtil::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position));
- glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_POSITION);
+ glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position));
+ glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION);
- glVertexAttribPointer(ShaderUtil::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color));
- glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_COLOR);
+ glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color));
+ glEnableVertexAttribArray(GLShader::ATTRIBUTE_COLOR);
- glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0));
- glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1));
- glVertexAttribPointer(ShaderUtil::ATTRIBUTE_TEXCOORDS + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2));
- glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS);
- glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS + 1);
- glEnableVertexAttribArray(ShaderUtil::ATTRIBUTE_TEXCOORDS + 2);
+ glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORDS + 0, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0));
+ glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORDS + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1));
+ glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORDS + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2));
+ glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORDS + 0);
+ glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORDS + 1);
+ glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORDS + 2);
- RegenerateShaders();
+ SetShader();
// Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation
fb_color_texture.texture.Create();
@@ -117,8 +118,6 @@ void RasterizerOpenGL::InitObjects() {
}
void RasterizerOpenGL::Reset() {
- const auto& regs = Pica::g_state.regs;
-
SyncCullMode();
SyncBlendEnabled();
SyncBlendFuncs();
@@ -127,7 +126,7 @@ void RasterizerOpenGL::Reset() {
SyncStencilTest();
SyncDepthTest();
- RegenerateShaders();
+ SetShader();
res_cache.FullFlush();
}
@@ -140,70 +139,12 @@ void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0,
vertex_batch.emplace_back(v2);
}
-namespace ShaderCache {
-extern std::string GenerateFragmentShader(const ShaderCacheKey& config);
-}
-
-void RasterizerOpenGL::RegenerateShaders() {
- ShaderCacheKey config = ShaderCacheKey::CurrentShaderConfig();
-
- auto cached_shader = shader_cache.find(config);
- if (cached_shader != shader_cache.end()) {
- current_shader = &cached_shader->second;
- state.draw.shader_program = current_shader->shader.handle;
- state.Apply();
- } else {
- LOG_CRITICAL(Render_OpenGL, "Creating new shader: %08X", hash(config));
-
- TEVShader shader;
-
- std::string fragShader = ShaderCache::GenerateFragmentShader(config);
- shader.shader.Create(GLShaders::g_vertex_shader_hw, fragShader.c_str());
-
- shader.uniform_alphatest_ref = glGetUniformLocation(shader.shader.handle, "alphatest_ref");
- shader.uniform_tex = glGetUniformLocation(shader.shader.handle, "tex");
- shader.uniform_tev_combiner_buffer_color = glGetUniformLocation(shader.shader.handle, "tev_combiner_buffer_color");
- shader.uniform_tev_const_colors = glGetUniformLocation(shader.shader.handle, "const_color");
-
- current_shader = &shader_cache.emplace(config, std::move(shader)).first->second;
-
- state.draw.shader_program = current_shader->shader.handle;
- state.Apply();
-
- // Set the texture samplers to correspond to different texture units
- if (shader.uniform_tex != -1) {
- glUniform1i(shader.uniform_tex, 0);
- glUniform1i(shader.uniform_tex + 1, 1);
- glUniform1i(shader.uniform_tex + 2, 2);
- }
- }
-
- // Sync alpha reference
- if (current_shader->uniform_alphatest_ref != -1)
- glUniform1i(current_shader->uniform_alphatest_ref, Pica::g_state.regs.output_merger.alpha_test.ref);
-
- // Sync combiner buffer color
- if (current_shader->uniform_tev_combiner_buffer_color != -1) {
- auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw);
- glUniform4fv(current_shader->uniform_tev_combiner_buffer_color, 1, combiner_color.data());
- }
-
- // Sync TEV const colors
- if (current_shader->uniform_tev_const_colors != -1) {
- auto& tev_stages = Pica::g_state.regs.GetTevStages();
- for (int tev_index = 0; tev_index < tev_stages.size(); ++tev_index) {
- auto const_color = PicaToGL::ColorRGBA8(tev_stages[tev_index].const_color);
- glUniform4fv(current_shader->uniform_tev_const_colors + tev_index, 1, const_color.data());
- }
- }
-}
-
void RasterizerOpenGL::DrawTriangles() {
SyncFramebuffer();
SyncDrawState();
if (state.draw.shader_dirty) {
- RegenerateShaders();
+ SetShader();
state.draw.shader_dirty = false;
}
@@ -519,6 +460,48 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::
state.Apply();
}
+void RasterizerOpenGL::SetShader() {
+ ShaderCacheKey config = ShaderCacheKey::CurrentConfig();
+
+ // Find (or generate) the GLSL shader for the current TEV state
+ auto cached_shader = shader_cache.find(config);
+ if (cached_shader != shader_cache.end()) {
+ current_shader = cached_shader->second.get();
+
+ state.draw.shader_program = current_shader->shader.handle;
+ state.Apply();
+ } else {
+ LOG_DEBUG(Render_OpenGL, "Creating new shader: %08X", hash(config));
+
+ std::unique_ptr<TEVShader> shader = Common::make_unique<TEVShader>();
+
+ shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str());
+ shader->uniform_alphatest_ref = glGetUniformLocation(shader->shader.handle, "alphatest_ref");
+ shader->uniform_tex = glGetUniformLocation(shader->shader.handle, "tex");
+ shader->uniform_tev_combiner_buffer_color = glGetUniformLocation(shader->shader.handle, "tev_combiner_buffer_color");
+ shader->uniform_tev_const_colors = glGetUniformLocation(shader->shader.handle, "const_color");
+
+ state.draw.shader_program = shader->shader.handle;
+ state.Apply();
+
+ // Set the texture samplers to correspond to different texture units
+ if (shader->uniform_tex != -1) {
+ glUniform1i(shader->uniform_tex, 0);
+ glUniform1i(shader->uniform_tex + 1, 1);
+ glUniform1i(shader->uniform_tex + 2, 2);
+ }
+
+ current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get();
+ }
+
+ // Update uniforms
+ SyncAlphaTest();
+ SyncCombinerColor();
+ auto& tev_stages = Pica::g_state.regs.GetTevStages();
+ for (int index = 0; index < tev_stages.size(); ++index)
+ SyncTevConstColor(index, tev_stages[index]);
+}
+
void RasterizerOpenGL::SyncFramebuffer() {
const auto& regs = Pica::g_state.regs;
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 @@
#pragma once
+#include <cstddef>
+#include <memory>
#include <vector>
#include <unordered_map>
@@ -15,21 +17,6 @@
#include "video_core/renderer_opengl/gl_state.h"
#include "video_core/shader/shader_interpreter.h"
-template <typename T>
-inline size_t hash(const T& o) {
- return std::hash<T>()(o);
-}
-
-template <typename T>
-inline size_t combine_hash(const T& o) {
- return hash(o);
-}
-
-template <typename T, typename... Args>
-inline size_t combine_hash(const T& o, const Args&... args) {
- return hash(o) * 3 + combine_hash(args...);
-}
-
struct ShaderCacheKey {
using Regs = Pica::Regs;
@@ -49,7 +36,7 @@ struct ShaderCacheKey {
return (stage_index < 4) && ((combiner_buffer_input >> 4) & (1 << stage_index));
}
- static ShaderCacheKey CurrentShaderConfig() {
+ static ShaderCacheKey CurrentConfig() {
const auto& regs = Pica::g_state.regs;
ShaderCacheKey config;
@@ -94,8 +81,14 @@ struct ShaderCacheKey {
namespace std {
+template<> struct hash<::Pica::Regs::CompareFunc> {
+ std::size_t operator()(const ::Pica::Regs::CompareFunc& o) {
+ return ::hash((unsigned)o);
+ }
+};
+
template<> struct hash<::Pica::Regs::TevStageConfig> {
- size_t operator()(const ::Pica::Regs::TevStageConfig& o) {
+ std::size_t operator()(const ::Pica::Regs::TevStageConfig& o) {
return ::combine_hash(
::hash(o.source_raw), ::hash(o.modifier_raw),
::hash(o.op_raw), ::hash(o.scale_raw));
@@ -103,13 +96,14 @@ template<> struct hash<::Pica::Regs::TevStageConfig> {
};
template<> struct hash<::ShaderCacheKey> {
- size_t operator()(const ::ShaderCacheKey& o) const {
+ std::size_t operator()(const ::ShaderCacheKey& o) const {
return ::combine_hash(o.alpha_test_func, o.combiner_buffer_input,
o.tev_stages[0], o.tev_stages[1], o.tev_stages[2],
o.tev_stages[3], o.tev_stages[4], o.tev_stages[5]);
}
};
-}
+
+} // namespace std
class RasterizerOpenGL : public HWRasterizer {
public:
@@ -131,8 +125,6 @@ public:
/// Draw the current batch of triangles
void DrawTriangles() override;
- void RegenerateShaders();
-
/// Commit the rasterizer's framebuffer contents immediately to the current 3DS memory framebuffer
void CommitFramebuffer() override;
@@ -245,6 +237,9 @@ private:
/// Reconfigure the OpenGL depth texture to use the given format and dimensions
void ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height);
+ /// Sets the OpenGL shader in accordance with the current PICA register state
+ void SetShader();
+
/// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer
void SyncFramebuffer();
@@ -315,8 +310,8 @@ private:
TextureInfo fb_color_texture;
DepthTextureInfo fb_depth_texture;
- std::unordered_map<ShaderCacheKey, TEVShader> shader_cache;
- TEVShader* current_shader = nullptr;
+ std::unordered_map<ShaderCacheKey, std::unique_ptr<TEVShader>> shader_cache;
+ const TEVShader* current_shader = nullptr;
OGLVertexArray vertex_array;
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:
/// Creates a new internal OpenGL resource and stores the handle
void Create(const char* vert_shader, const char* frag_shader) {
if (handle != 0) return;
- handle = ShaderUtil::LoadShaders(vert_shader, frag_shader);
+ handle = GLShader::LoadProgram(vert_shader, frag_shader);
}
/// 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 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "video_core/pica.h"
+#include "video_core/renderer_opengl/gl_rasterizer.h"
+#include "video_core/renderer_opengl/gl_shader_gen.h"
+
+namespace GLShader {
+
+static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
+ return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace &&
+ stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace &&
+ stage.color_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
+ stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
+ stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor &&
+ stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha &&
+ stage.GetColorMultiplier() == 1 &&
+ stage.GetAlphaMultiplier() == 1);
+}
+
+static void AppendSource(std::string& shader, Pica::Regs::TevStageConfig::Source source, const std::string& index_name) {
+ using Source = Pica::Regs::TevStageConfig::Source;
+ switch (source) {
+ case Source::PrimaryColor:
+ shader += "o[2]";
+ break;
+ case Source::PrimaryFragmentColor:
+ // HACK: Until we implement fragment lighting, use primary_color
+ shader += "o[2]";
+ break;
+ case Source::SecondaryFragmentColor:
+ // HACK: Until we implement fragment lighting, use zero
+ shader += "vec4(0.0, 0.0, 0.0, 0.0)";
+ break;
+ case Source::Texture0:
+ shader += "texture(tex[0], o[3].xy)";
+ break;
+ case Source::Texture1:
+ shader += "texture(tex[1], o[3].zw)";
+ break;
+ case Source::Texture2: // TODO: Unverified
+ shader += "texture(tex[2], o[5].zw)";
+ break;
+ case Source::PreviousBuffer:
+ shader += "g_combiner_buffer";
+ break;
+ case Source::Constant:
+ shader += "const_color[" + index_name + "]";
+ break;
+ case Source::Previous:
+ shader += "g_last_tex_env_out";
+ break;
+ default:
+ shader += "vec4(0.0)";
+ LOG_CRITICAL(Render_OpenGL, "Unknown source op %u", source);
+ break;
+ }
+}
+
+static void AppendColorModifier(std::string& shader, Pica::Regs::TevStageConfig::ColorModifier modifier,
+ Pica::Regs::TevStageConfig::Source source, const std::string& index_name) {
+ using ColorModifier = Pica::Regs::TevStageConfig::ColorModifier;
+ switch (modifier) {
+ case ColorModifier::SourceColor:
+ AppendSource(shader, source, index_name);
+ shader += ".rgb";
+ break;
+ case ColorModifier::OneMinusSourceColor:
+ shader += "vec3(1.0) - ";
+ AppendSource(shader, source, index_name);
+ shader += ".rgb";
+ break;
+ case ColorModifier::SourceAlpha:
+ AppendSource(shader, source, index_name);
+ shader += ".aaa";
+ break;
+ case ColorModifier::OneMinusSourceAlpha:
+ shader += "vec3(1.0) - ";
+ AppendSource(shader, source, index_name);
+ shader += ".aaa";
+ break;
+ case ColorModifier::SourceRed:
+ AppendSource(shader, source, index_name);
+ shader += ".rrr";
+ break;
+ case ColorModifier::OneMinusSourceRed:
+ shader += "vec3(1.0) - ";
+ AppendSource(shader, source, index_name);
+ shader += ".rrr";
+ break;
+ case ColorModifier::SourceGreen:
+ AppendSource(shader, source, index_name);
+ shader += ".ggg";
+ break;
+ case ColorModifier::OneMinusSourceGreen:
+ shader += "vec3(1.0) - ";
+ AppendSource(shader, source, index_name);
+ shader += ".ggg";
+ break;
+ case ColorModifier::SourceBlue:
+ AppendSource(shader, source, index_name);
+ shader += ".bbb";
+ break;
+ case ColorModifier::OneMinusSourceBlue:
+ shader += "vec3(1.0) - ";
+ AppendSource(shader, source, index_name);
+ shader += ".bbb";
+ break;
+ default:
+ shader += "vec3(0.0)";
+ LOG_CRITICAL(Render_OpenGL, "Unknown color modifier op %u", modifier);
+ break;
+ }
+}
+
+static void AppendAlphaModifier(std::string& shader, Pica::Regs::TevStageConfig::AlphaModifier modifier,
+ Pica::Regs::TevStageConfig::Source source, const std::string& index_name) {
+ using AlphaModifier = Pica::Regs::TevStageConfig::AlphaModifier;
+ switch (modifier) {
+ case AlphaModifier::SourceAlpha:
+ AppendSource(shader, source, index_name);
+ shader += ".a";
+ break;
+ case AlphaModifier::OneMinusSourceAlpha:
+ shader += "1.0 - ";
+ AppendSource(shader, source, index_name);
+ shader += ".a";
+ break;
+ case AlphaModifier::SourceRed:
+ AppendSource(shader, source, index_name);
+ shader += ".r";
+ break;
+ case AlphaModifier::OneMinusSourceRed:
+ shader += "1.0 - ";
+ AppendSource(shader, source, index_name);
+ shader += ".r";
+ break;
+ case AlphaModifier::SourceGreen:
+ AppendSource(shader, source, index_name);
+ shader += ".g";
+ break;
+ case AlphaModifier::OneMinusSourceGreen:
+ shader += "1.0 - ";
+ AppendSource(shader, source, index_name);
+ shader += ".g";
+ break;
+ case AlphaModifier::SourceBlue:
+ AppendSource(shader, source, index_name);
+ shader += ".b";
+ break;
+ case AlphaModifier::OneMinusSourceBlue:
+ shader += "1.0 - ";
+ AppendSource(shader, source, index_name);
+ shader += ".b";
+ break;
+ default:
+ shader += "vec3(0.0)";
+ LOG_CRITICAL(Render_OpenGL, "Unknown alpha modifier op %u", modifier);
+ break;
+ }
+}
+
+static void AppendColorCombiner(std::string& shader, Pica::Regs::TevStageConfig::Operation operation,
+ const std::string& variable_name) {
+ using Operation = Pica::Regs::TevStageConfig::Operation;
+
+ switch (operation) {
+ case Operation::Replace:
+ shader += variable_name + "[0]";
+ break;
+ case Operation::Modulate:
+ shader += variable_name + "[0] * " + variable_name + "[1]";
+ break;
+ case Operation::Add:
+ shader += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0))";
+ break;
+ case Operation::AddSigned:
+ shader += "clamp(" + variable_name + "[0] + " + variable_name + "[1] - vec3(0.5), vec3(0.0), vec3(1.0))";
+ break;
+ case Operation::Lerp:
+ shader += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (vec3(1.0) - " + variable_name + "[2])";
+ break;
+ case Operation::Subtract:
+ shader += "max(" + variable_name + "[0] - " + variable_name + "[1], vec3(0.0))";
+ break;
+ case Operation::MultiplyThenAdd:
+ shader += "min(" + variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2], vec3(1.0))";
+ break;
+ case Operation::AddThenMultiply:
+ shader += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + variable_name + "[2]";
+ break;
+ default:
+ shader += "vec3(0.0)";
+ LOG_CRITICAL(Render_OpenGL, "Unknown color comb op %u", operation);
+ break;
+ }
+}
+
+static void AppendAlphaCombiner(std::string& shader, Pica::Regs::TevStageConfig::Operation operation,
+ const std::string& variable_name) {
+ using Operation = Pica::Regs::TevStageConfig::Operation;
+ switch (operation) {
+ case Operation::Replace:
+ shader += variable_name + "[0]";
+ break;
+ case Operation::Modulate:
+ shader += variable_name + "[0] * " + variable_name + "[1]";
+ break;
+ case Operation::Add:
+ shader += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0)";
+ break;
+ case Operation::AddSigned:
+ shader += "clamp(" + variable_name + "[0] + " + variable_name + "[1] - 0.5, 0.0, 1.0)";
+ break;
+ case Operation::Lerp:
+ shader += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (1.0 - " + variable_name + "[2])";
+ break;
+ case Operation::Subtract:
+ shader += "max(" + variable_name + "[0] - " + variable_name + "[1], 0.0)";
+ break;
+ case Operation::MultiplyThenAdd:
+ shader += "min(" + variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2], 1.0)";
+ break;
+ case Operation::AddThenMultiply:
+ shader += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + "[2]";
+ break;
+ default:
+ shader += "0.0";
+ LOG_CRITICAL(Render_OpenGL, "Unknown alpha combiner op %u", operation);
+ break;
+ }
+}
+
+static void AppendAlphaTestCondition(std::string& shader, Pica::Regs::CompareFunc func) {
+ using CompareFunc = Pica::Regs::CompareFunc;
+ switch (func) {
+ case CompareFunc::Never:
+ shader += "true";
+ break;
+ case CompareFunc::Always:
+ shader += "false";
+ break;
+ case CompareFunc::Equal:
+ shader += "int(g_last_tex_env_out.a * 255.0f) != alphatest_ref";
+ break;
+ case CompareFunc::NotEqual:
+ shader += "int(g_last_tex_env_out.a * 255.0f) == alphatest_ref";
+ break;
+ case CompareFunc::LessThan:
+ shader += "int(g_last_tex_env_out.a * 255.0f) >= alphatest_ref";
+ break;
+ case CompareFunc::LessThanOrEqual:
+ shader += "int(g_last_tex_env_out.a * 255.0f) > alphatest_ref";
+ break;
+ case CompareFunc::GreaterThan:
+ shader += "int(g_last_tex_env_out.a * 255.0f) <= alphatest_ref";
+ break;
+ case CompareFunc::GreaterThanOrEqual:
+ shader += "int(g_last_tex_env_out.a * 255.0f) < alphatest_ref";
+ break;
+ default:
+ shader += "false";
+ LOG_CRITICAL(Render_OpenGL, "Unknown alpha test condition %u", func);
+ break;
+ }
+}
+
+std::string GenerateFragmentShader(const ShaderCacheKey& config) {
+ std::string shader = R"(
+#version 150 core
+
+#define NUM_VTX_ATTR 7
+#define NUM_TEV_STAGES 6
+
+in vec4 o[NUM_VTX_ATTR];
+out vec4 color;
+
+uniform int alphatest_ref;
+uniform vec4 const_color[NUM_TEV_STAGES];
+uniform sampler2D tex[3];
+
+uniform vec4 tev_combiner_buffer_color;
+
+void main(void) {
+vec4 g_combiner_buffer = tev_combiner_buffer_color;
+vec4 g_last_tex_env_out = vec4(0.0, 0.0, 0.0, 0.0);
+)";
+
+ // Do not do any sort of processing if it's obvious we're not going to pass the alpha test
+ if (config.alpha_test_func == Pica::Regs::CompareFunc::Never) {
+ shader += "discard;";
+ return shader;
+ }
+
+ auto& tev_stages = config.tev_stages;
+ for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) {
+ auto& tev_stage = tev_stages[tev_stage_index];
+ if (!IsPassThroughTevStage(tev_stage)) {
+ std::string index_name = std::to_string(tev_stage_index);
+
+ shader += "vec3 color_results_" + index_name + "[3] = vec3[3](";
+ AppendColorModifier(shader, tev_stage.color_modifier1, tev_stage.color_source1, index_name);
+ shader += ", ";
+ AppendColorModifier(shader, tev_stage.color_modifier2, tev_stage.color_source2, index_name);
+ shader += ", ";
+ AppendColorModifier(shader, tev_stage.color_modifier3, tev_stage.color_source3, index_name);
+ shader += ");\n";
+
+ shader += "vec3 color_output_" + index_name + " = ";
+ AppendColorCombiner(shader, tev_stage.color_op, "color_results_" + index_name);
+ shader += ";\n";
+
+ shader += "float alpha_results_" + index_name + "[3] = float[3](";
+ AppendAlphaModifier(shader, tev_stage.alpha_modifier1, tev_stage.alpha_source1, index_name);
+ shader += ", ";
+ AppendAlphaModifier(shader, tev_stage.alpha_modifier2, tev_stage.alpha_source2, index_name);
+ shader += ", ";
+ AppendAlphaModifier(shader, tev_stage.alpha_modifier3, tev_stage.alpha_source3, index_name);
+ shader += ");\n";
+
+ shader += "float alpha_output_" + index_name + " = ";
+ AppendAlphaCombiner(shader, tev_stage.alpha_op, "alpha_results_" + index_name);
+ shader += ";\n";
+
+ 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";
+ }
+
+ if (config.TevStageUpdatesCombinerBufferColor(tev_stage_index))
+ shader += "g_combiner_buffer.rgb = g_last_tex_env_out.rgb;\n";
+
+ if (config.TevStageUpdatesCombinerBufferAlpha(tev_stage_index))
+ shader += "g_combiner_buffer.a = g_last_tex_env_out.a;\n";
+ }
+
+ if (config.alpha_test_func != Pica::Regs::CompareFunc::Always) {
+ shader += "if (";
+ AppendAlphaTestCondition(shader, config.alpha_test_func);
+ shader += ") {\n discard;\n }\n";
+ }
+
+ shader += "color = g_last_tex_env_out;\n}";
+ return shader;
+}
+
+std::string GenerateVertexShader() {
+ static const std::string shader_str = R"(
+#version 150 core
+
+#define NUM_VTX_ATTR 7
+
+in vec4 vert_position;
+in vec4 vert_color;
+in vec2 vert_texcoords0;
+in vec2 vert_texcoords1;
+in vec2 vert_texcoords2;
+
+out vec4 o[NUM_VTX_ATTR];
+
+void main() {
+ o[2] = vert_color;
+ o[3] = vec4(vert_texcoords0.xy, vert_texcoords1.xy);
+ o[5] = vec4(0.0, 0.0, vert_texcoords2.xy);
+
+ gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w);
+}
+)";
+ return shader_str;
+}
+
+} // 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 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+
+#include "video_core/renderer_opengl/gl_rasterizer.h"
+
+namespace GLShader {
+
+std::string GenerateVertexShader();
+
+std::string GenerateFragmentShader(const ShaderCacheKey& config);
+
+} // 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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-
-#include "gl_shader_util.h"
-#include "gl_rasterizer.h"
-#include "common/logging/log.h"
-
-#include "video_core/pica.h"
-
#include <algorithm>
#include <vector>
#include "common/logging/log.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
-namespace ShaderUtil {
+namespace GLShader {
-GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
+GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) {
// Create the shaders
GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER);
@@ -101,339 +94,4 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
return program_id;
}
-}
-
-namespace ShaderCache
-{
-
-static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
- return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace &&
- stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace &&
- stage.color_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
- stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous &&
- stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor &&
- stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha &&
- stage.GetColorMultiplier() == 1 &&
- stage.GetAlphaMultiplier() == 1);
-}
-
-void AppendSource(std::string& shader, Pica::Regs::TevStageConfig::Source source, const std::string& index_name) {
- using Source = Pica::Regs::TevStageConfig::Source;
- switch (source) {
- case Source::PrimaryColor:
- shader += "o[2]";
- break;
- case Source::PrimaryFragmentColor:
- // HACK: Until we implement fragment lighting, use primary_color
- shader += "o[2]";
- break;
- case Source::SecondaryFragmentColor:
- // HACK: Until we implement fragment lighting, use zero
- shader += "vec4(0.0, 0.0, 0.0, 0.0)";
- break;
- case Source::Texture0:
- shader += "texture(tex[0], o[3].xy)";
- break;
- case Source::Texture1:
- shader += "texture(tex[1], o[3].zw)";
- break;
- case Source::Texture2: // TODO: Unverified
- shader += "texture(tex[2], o[5].zw)";
- break;
- case Source::PreviousBuffer:
- shader += "g_combiner_buffer";
- break;
- case Source::Constant:
- shader += "const_color[" + index_name + "]";
- break;
- case Source::Previous:
- shader += "g_last_tex_env_out";
- break;
- default:
- shader += "vec4(0.0)";
- LOG_CRITICAL(Render_OpenGL, "Unknown source op %u", source);
- break;
- }
-}
-
-void AppendColorModifier(std::string& shader, Pica::Regs::TevStageConfig::ColorModifier modifier, Pica::Regs::TevStageConfig::Source source, const std::string& index_name) {
- using ColorModifier = Pica::Regs::TevStageConfig::ColorModifier;
- switch (modifier) {
- case ColorModifier::SourceColor:
- AppendSource(shader, source, index_name);
- shader += ".rgb";
- break;
- case ColorModifier::OneMinusSourceColor:
- shader += "vec3(1.0) - ";
- AppendSource(shader, source, index_name);
- shader += ".rgb";
- break;
- case ColorModifier::SourceAlpha:
- AppendSource(shader, source, index_name);
- shader += ".aaa";
- break;
- case ColorModifier::OneMinusSourceAlpha:
- shader += "vec3(1.0) - ";
- AppendSource(shader, source, index_name);
- shader += ".aaa";
- break;
- case ColorModifier::SourceRed:
- AppendSource(shader, source, index_name);
- shader += ".rrr";
- break;
- case ColorModifier::OneMinusSourceRed:
- shader += "vec3(1.0) - ";
- AppendSource(shader, source, index_name);
- shader += ".rrr";
- break;
- case ColorModifier::SourceGreen:
- AppendSource(shader, source, index_name);
- shader += ".ggg";
- break;
- case ColorModifier::OneMinusSourceGreen:
- shader += "vec3(1.0) - ";
- AppendSource(shader, source, index_name);
- shader += ".ggg";
- break;
- case ColorModifier::SourceBlue:
- AppendSource(shader, source, index_name);
- shader += ".bbb";
- break;
- case ColorModifier::OneMinusSourceBlue:
- shader += "vec3(1.0) - ";
- AppendSource(shader, source, index_name);
- shader += ".bbb";
- break;
- default:
- shader += "vec3(0.0)";
- LOG_CRITICAL(Render_OpenGL, "Unknown color modifier op %u", modifier);
- break;
- }
-}
-
-void AppendAlphaModifier(std::string& shader, Pica::Regs::TevStageConfig::AlphaModifier modifier, Pica::Regs::TevStageConfig::Source source, const std::string& index_name) {
- using AlphaModifier = Pica::Regs::TevStageConfig::AlphaModifier;
- switch (modifier) {
- case AlphaModifier::SourceAlpha:
- AppendSource(shader, source, index_name);
- shader += ".a";
- break;
- case AlphaModifier::OneMinusSourceAlpha:
- shader += "1.0 - ";
- AppendSource(shader, source, index_name);
- shader += ".a";
- break;
- case AlphaModifier::SourceRed:
- AppendSource(shader, source, index_name);
- shader += ".r";
- break;
- case AlphaModifier::OneMinusSourceRed:
- shader += "1.0 - ";
- AppendSource(shader, source, index_name);
- shader += ".r";
- break;
- case AlphaModifier::SourceGreen:
- AppendSource(shader, source, index_name);
- shader += ".g";
- break;
- case AlphaModifier::OneMinusSourceGreen:
- shader += "1.0 - ";
- AppendSource(shader, source, index_name);
- shader += ".g";
- break;
- case AlphaModifier::SourceBlue:
- AppendSource(shader, source, index_name);
- shader += ".b";
- break;
- case AlphaModifier::OneMinusSourceBlue:
- shader += "1.0 - ";
- AppendSource(shader, source, index_name);
- shader += ".b";
- break;
- default:
- shader += "vec3(0.0)";
- LOG_CRITICAL(Render_OpenGL, "Unknown alpha modifier op %u", modifier);
- break;
- }
-}
-
-void AppendColorCombiner(std::string& shader, Pica::Regs::TevStageConfig::Operation operation, const std::string& variable_name) {
- using Operation = Pica::Regs::TevStageConfig::Operation;
-
- switch (operation) {
- case Operation::Replace:
- shader += variable_name + "[0]";
- break;
- case Operation::Modulate:
- shader += variable_name + "[0] * " + variable_name + "[1]";
- break;
- case Operation::Add:
- shader += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0))";
- break;
- case Operation::AddSigned:
- shader += "clamp(" + variable_name + "[0] + " + variable_name + "[1] - vec3(0.5), vec3(0.0), vec3(1.0))";
- break;
- case Operation::Lerp:
- shader += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (vec3(1.0) - " + variable_name + "[2])";
- break;
- case Operation::Subtract:
- shader += "max(" + variable_name + "[0] - " + variable_name + "[1], vec3(0.0))";
- break;
- case Operation::MultiplyThenAdd:
- shader += "min(" + variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2], vec3(1.0))";
- break;
- case Operation::AddThenMultiply:
- shader += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + variable_name + "[2]";
- break;
- default:
- shader += "vec3(0.0)";
- LOG_CRITICAL(Render_OpenGL, "Unknown color comb op %u", operation);
- break;
- }
-}
-
-void AppendAlphaCombiner(std::string& shader, Pica::Regs::TevStageConfig::Operation operation, const std::string& variable_name) {
- using Operation = Pica::Regs::TevStageConfig::Operation;
- switch (operation) {
- case Operation::Replace:
- shader += variable_name + "[0]";
- break;
- case Operation::Modulate:
- shader += variable_name + "[0] * " + variable_name + "[1]";
- break;
- case Operation::Add:
- shader += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0)";
- break;
- case Operation::AddSigned:
- shader += "clamp(" + variable_name + "[0] + " + variable_name + "[1] - 0.5, 0.0, 1.0)";
- break;
- case Operation::Lerp:
- shader += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (1.0 - " + variable_name + "[2])";
- break;
- case Operation::Subtract:
- shader += "max(" + variable_name + "[0] - " + variable_name + "[1], 0.0)";
- break;
- case Operation::MultiplyThenAdd:
- shader += "min(" + variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2], 1.0)";
- break;
- case Operation::AddThenMultiply:
- shader += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + "[2]";
- break;
- default:
- shader += "0.0";
- LOG_CRITICAL(Render_OpenGL, "Unknown alpha combiner op %u", operation);
- break;
- }
-}
-
-void AppendAlphaTestCondition(std::string& shader, Pica::Regs::CompareFunc func) {
- using CompareFunc = Pica::Regs::CompareFunc;
- switch (func) {
- case CompareFunc::Never:
- shader += "true";
- break;
- case CompareFunc::Always:
- shader += "false";
- break;
- case CompareFunc::Equal:
- shader += "int(g_last_tex_env_out.a * 255.0f) != alphatest_ref";
- break;
- case CompareFunc::NotEqual:
- shader += "int(g_last_tex_env_out.a * 255.0f) == alphatest_ref";
- break;
- case CompareFunc::LessThan:
- shader += "int(g_last_tex_env_out.a * 255.0f) >= alphatest_ref";
- break;
- case CompareFunc::LessThanOrEqual:
- shader += "int(g_last_tex_env_out.a * 255.0f) > alphatest_ref";
- break;
- case CompareFunc::GreaterThan:
- shader += "int(g_last_tex_env_out.a * 255.0f) <= alphatest_ref";
- break;
- case CompareFunc::GreaterThanOrEqual:
- shader += "int(g_last_tex_env_out.a * 255.0f) < alphatest_ref";
- break;
- default:
- shader += "false";
- LOG_CRITICAL(Render_OpenGL, "Unknown alpha test condition %u", func);
- break;
- }
-}
-
-std::string GenerateFragmentShader(const ShaderCacheKey& config) {
- std::string shader = R"(
-#version 150 core
-
-#define NUM_VTX_ATTR 7
-#define NUM_TEV_STAGES 6
-
-in vec4 o[NUM_VTX_ATTR];
-out vec4 color;
-
-uniform int alphatest_ref;
-uniform vec4 const_color[NUM_TEV_STAGES];
-uniform sampler2D tex[3];
-
-uniform vec4 tev_combiner_buffer_color;
-
-void main(void) {
- vec4 g_combiner_buffer = tev_combiner_buffer_color;
- vec4 g_last_tex_env_out = vec4(0.0, 0.0, 0.0, 0.0);
-)";
-
- // Do not do any sort of processing if it's obvious we're not going to pass the alpha test
- if (config.alpha_test_func == Pica::Regs::CompareFunc::Never) {
- shader += "discard;";
- return shader;
- }
-
- auto& tev_stages = config.tev_stages;
- for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) {
- auto& tev_stage = tev_stages[tev_stage_index];
- if (!IsPassThroughTevStage(tev_stage)) {
- std::string index_name = std::to_string(tev_stage_index);
-
- shader += "vec3 color_results_" + index_name + "[3] = vec3[3](";
- AppendColorModifier(shader, tev_stage.color_modifier1, tev_stage.color_source1, index_name);
- shader += ", ";
- AppendColorModifier(shader, tev_stage.color_modifier2, tev_stage.color_source2, index_name);
- shader += ", ";
- AppendColorModifier(shader, tev_stage.color_modifier3, tev_stage.color_source3, index_name);
- shader += ");\n";
-
- shader += "vec3 color_output_" + index_name + " = ";
- AppendColorCombiner(shader, tev_stage.color_op, "color_results_" + index_name);
- shader += ";\n";
-
- shader += "float alpha_results_" + index_name + "[3] = float[3](";
- AppendAlphaModifier(shader, tev_stage.alpha_modifier1, tev_stage.alpha_source1, index_name);
- shader += ", ";
- AppendAlphaModifier(shader, tev_stage.alpha_modifier2, tev_stage.alpha_source2, index_name);
- shader += ", ";
- AppendAlphaModifier(shader, tev_stage.alpha_modifier3, tev_stage.alpha_source3, index_name);
- shader += ");\n";
-
- shader += "float alpha_output_" + index_name + " = ";
- AppendAlphaCombiner(shader, tev_stage.alpha_op, "alpha_results_" + index_name);
- shader += ";\n";
-
- 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";
- }
-
- if (config.TevStageUpdatesCombinerBufferColor(tev_stage_index))
- shader += "g_combiner_buffer.rgb = g_last_tex_env_out.rgb;\n";
-
- if (config.TevStageUpdatesCombinerBufferAlpha(tev_stage_index))
- shader += "g_combiner_buffer.a = g_last_tex_env_out.a;\n";
- }
-
- if (config.alpha_test_func != Pica::Regs::CompareFunc::Always) {
- shader += "if (";
- AppendAlphaTestCondition(shader, config.alpha_test_func);
- shader += ") {\n discard;\n }\n";
- }
-
- shader += "color = g_last_tex_env_out;\n}";
- return shader;
-}
-}
+} // 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 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 @@
#include <glad/glad.h>
-namespace ShaderUtil {
+namespace GLShader {
enum Attributes {
ATTRIBUTE_POSITION = 0,
@@ -14,6 +14,6 @@ enum Attributes {
ATTRIBUTE_TEXCOORDS = 2,
};
-GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path);
+GLuint LoadProgram(const char* vertex_file_path, const char* fragment_file_path);
-}
+} // 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 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-namespace GLShaders {
-
-const char g_vertex_shader[] = R"(
-#version 150 core
-
-in vec2 vert_position;
-in vec2 vert_tex_coord;
-out vec2 frag_tex_coord;
-
-// This is a truncated 3x3 matrix for 2D transformations:
-// The upper-left 2x2 submatrix performs scaling/rotation/mirroring.
-// The third column performs translation.
-// The third row could be used for projection, which we don't need in 2D. It hence is assumed to
-// implicitly be [0, 0, 1]
-uniform mat3x2 modelview_matrix;
-
-void main() {
- // Multiply input position by the rotscale part of the matrix and then manually translate by
- // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
- // to `vec3(vert_position.xy, 1.0)`
- gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
- frag_tex_coord = vert_tex_coord;
-}
-)";
-
-const char g_fragment_shader[] = R"(
-#version 150 core
-
-in vec2 frag_tex_coord;
-out vec4 color;
-
-uniform sampler2D color_texture;
-
-void main() {
- color = texture(color_texture, frag_tex_coord);
-}
-)";
-
-const char g_vertex_shader_hw[] = R"(
-#version 150 core
-
-#define NUM_VTX_ATTR 7
-
-in vec4 vert_position;
-in vec4 vert_color;
-in vec2 vert_texcoords0;
-in vec2 vert_texcoords1;
-in vec2 vert_texcoords2;
-
-out vec4 o[NUM_VTX_ATTR];
-
-void main() {
- o[2] = vert_color;
- o[3] = vec4(vert_texcoords0.xy, vert_texcoords1.xy);
- o[5] = vec4(0.0, 0.0, vert_texcoords2.xy);
-
- gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w);
-}
-)";
-
-// TODO: Create a shader constructor and cache that builds this program with minimal conditionals instead of using tev_cfg uniforms
-const char g_fragment_shader_hw[] = R"(
-#version 150 core
-
-#define NUM_VTX_ATTR 7
-#define NUM_TEV_STAGES 6
-
-#define SOURCE_PRIMARYCOLOR 0x0
-#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1
-#define SOURCE_SECONDARYFRAGMENTCOLOR 0x2
-#define SOURCE_TEXTURE0 0x3
-#define SOURCE_TEXTURE1 0x4
-#define SOURCE_TEXTURE2 0x5
-#define SOURCE_TEXTURE3 0x6
-#define SOURCE_PREVIOUSBUFFER 0xd
-#define SOURCE_CONSTANT 0xe
-#define SOURCE_PREVIOUS 0xf
-
-#define COLORMODIFIER_SOURCECOLOR 0x0
-#define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1
-#define COLORMODIFIER_SOURCEALPHA 0x2
-#define COLORMODIFIER_ONEMINUSSOURCEALPHA 0x3
-#define COLORMODIFIER_SOURCERED 0x4
-#define COLORMODIFIER_ONEMINUSSOURCERED 0x5
-#define COLORMODIFIER_SOURCEGREEN 0x8
-#define COLORMODIFIER_ONEMINUSSOURCEGREEN 0x9
-#define COLORMODIFIER_SOURCEBLUE 0xc
-#define COLORMODIFIER_ONEMINUSSOURCEBLUE 0xd
-
-#define ALPHAMODIFIER_SOURCEALPHA 0x0
-#define ALPHAMODIFIER_ONEMINUSSOURCEALPHA 0x1
-#define ALPHAMODIFIER_SOURCERED 0x2
-#define ALPHAMODIFIER_ONEMINUSSOURCERED 0x3
-#define ALPHAMODIFIER_SOURCEGREEN 0x4
-#define ALPHAMODIFIER_ONEMINUSSOURCEGREEN 0x5
-#define ALPHAMODIFIER_SOURCEBLUE 0x6
-#define ALPHAMODIFIER_ONEMINUSSOURCEBLUE 0x7
-
-#define OPERATION_REPLACE 0
-#define OPERATION_MODULATE 1
-#define OPERATION_ADD 2
-#define OPERATION_ADDSIGNED 3
-#define OPERATION_LERP 4
-#define OPERATION_SUBTRACT 5
-#define OPERATION_MULTIPLYTHENADD 8
-#define OPERATION_ADDTHENMULTIPLY 9
-
-#define COMPAREFUNC_NEVER 0
-#define COMPAREFUNC_ALWAYS 1
-#define COMPAREFUNC_EQUAL 2
-#define COMPAREFUNC_NOTEQUAL 3
-#define COMPAREFUNC_LESSTHAN 4
-#define COMPAREFUNC_LESSTHANOREQUAL 5
-#define COMPAREFUNC_GREATERTHAN 6
-#define COMPAREFUNC_GREATERTHANOREQUAL 7
-
-in vec4 o[NUM_VTX_ATTR];
-out vec4 color;
-
-uniform bool alphatest_enabled;
-uniform int alphatest_func;
-uniform float alphatest_ref;
-
-uniform sampler2D tex[3];
-
-uniform vec4 tev_combiner_buffer_color;
-
-struct TEVConfig
-{
- bool enabled;
- ivec3 color_sources;
- ivec3 alpha_sources;
- ivec3 color_modifiers;
- ivec3 alpha_modifiers;
- ivec2 color_alpha_op;
- ivec2 color_alpha_multiplier;
- vec4 const_color;
- bvec2 updates_combiner_buffer_color_alpha;
-};
-
-uniform TEVConfig tev_cfgs[NUM_TEV_STAGES];
-
-vec4 g_combiner_buffer;
-vec4 g_last_tex_env_out;
-vec4 g_const_color;
-
-vec4 GetSource(int source) {
- if (source == SOURCE_PRIMARYCOLOR) {
- return o[2];
- } else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) {
- // HACK: Until we implement fragment lighting, use primary_color
- return o[2];
- } else if (source == SOURCE_SECONDARYFRAGMENTCOLOR) {
- // HACK: Until we implement fragment lighting, use zero
- return vec4(0.0, 0.0, 0.0, 0.0);
- } else if (source == SOURCE_TEXTURE0) {
- return texture(tex[0], o[3].xy);
- } else if (source == SOURCE_TEXTURE1) {
- return texture(tex[1], o[3].zw);
- } else if (source == SOURCE_TEXTURE2) {
- // TODO: Unverified
- return texture(tex[2], o[5].zw);
- } else if (source == SOURCE_TEXTURE3) {
- // TODO: no 4th texture?
- } else if (source == SOURCE_PREVIOUSBUFFER) {
- return g_combiner_buffer;
- } else if (source == SOURCE_CONSTANT) {
- return g_const_color;
- } else if (source == SOURCE_PREVIOUS) {
- return g_last_tex_env_out;
- }
-
- return vec4(0.0);
-}
-
-vec3 GetColorModifier(int factor, vec4 color) {
- if (factor == COLORMODIFIER_SOURCECOLOR) {
- return color.rgb;
- } else if (factor == COLORMODIFIER_ONEMINUSSOURCECOLOR) {
- return vec3(1.0) - color.rgb;
- } else if (factor == COLORMODIFIER_SOURCEALPHA) {
- return color.aaa;
- } else if (factor == COLORMODIFIER_ONEMINUSSOURCEALPHA) {
- return vec3(1.0) - color.aaa;
- } else if (factor == COLORMODIFIER_SOURCERED) {
- return color.rrr;
- } else if (factor == COLORMODIFIER_ONEMINUSSOURCERED) {
- return vec3(1.0) - color.rrr;
- } else if (factor == COLORMODIFIER_SOURCEGREEN) {
- return color.ggg;
- } else if (factor == COLORMODIFIER_ONEMINUSSOURCEGREEN) {
- return vec3(1.0) - color.ggg;
- } else if (factor == COLORMODIFIER_SOURCEBLUE) {
- return color.bbb;
- } else if (factor == COLORMODIFIER_ONEMINUSSOURCEBLUE) {
- return vec3(1.0) - color.bbb;
- }
-
- return vec3(0.0);
-}
-
-float GetAlphaModifier(int factor, vec4 color) {
- if (factor == ALPHAMODIFIER_SOURCEALPHA) {
- return color.a;
- } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEALPHA) {
- return 1.0 - color.a;
- } else if (factor == ALPHAMODIFIER_SOURCERED) {
- return color.r;
- } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCERED) {
- return 1.0 - color.r;
- } else if (factor == ALPHAMODIFIER_SOURCEGREEN) {
- return color.g;
- } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEGREEN) {
- return 1.0 - color.g;
- } else if (factor == ALPHAMODIFIER_SOURCEBLUE) {
- return color.b;
- } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEBLUE) {
- return 1.0 - color.b;
- }
-
- return 0.0;
-}
-
-vec3 ColorCombine(int op, vec3 color[3]) {
- if (op == OPERATION_REPLACE) {
- return color[0];
- } else if (op == OPERATION_MODULATE) {
- return color[0] * color[1];
- } else if (op == OPERATION_ADD) {
- return min(color[0] + color[1], 1.0);
- } else if (op == OPERATION_ADDSIGNED) {
- return clamp(color[0] + color[1] - vec3(0.5), 0.0, 1.0);
- } else if (op == OPERATION_LERP) {
- return color[0] * color[2] + color[1] * (vec3(1.0) - color[2]);
- } else if (op == OPERATION_SUBTRACT) {
- return max(color[0] - color[1], 0.0);
- } else if (op == OPERATION_MULTIPLYTHENADD) {
- return min(color[0] * color[1] + color[2], 1.0);
- } else if (op == OPERATION_ADDTHENMULTIPLY) {
- return min(color[0] + color[1], 1.0) * color[2];
- }
-
- return vec3(0.0);
-}
-
-float AlphaCombine(int op, float alpha[3]) {
- if (op == OPERATION_REPLACE) {
- return alpha[0];
- } else if (op == OPERATION_MODULATE) {
- return alpha[0] * alpha[1];
- } else if (op == OPERATION_ADD) {
- return min(alpha[0] + alpha[1], 1.0);
- } else if (op == OPERATION_ADDSIGNED) {
- return clamp(alpha[0] + alpha[1] - 0.5, 0.0, 1.0);
- } else if (op == OPERATION_LERP) {
- return alpha[0] * alpha[2] + alpha[1] * (1.0 - alpha[2]);
- } else if (op == OPERATION_SUBTRACT) {
- return max(alpha[0] - alpha[1], 0.0);
- } else if (op == OPERATION_MULTIPLYTHENADD) {
- return min(alpha[0] * alpha[1] + alpha[2], 1.0);
- } else if (op == OPERATION_ADDTHENMULTIPLY) {
- return min(alpha[0] + alpha[1], 1.0) * alpha[2];
- }
-
- return 0.0;
-}
-
-void main(void) {
- g_combiner_buffer = tev_combiner_buffer_color;
-
- for (int tex_env_idx = 0; tex_env_idx < NUM_TEV_STAGES; ++tex_env_idx) {
- if (tev_cfgs[tex_env_idx].enabled) {
- g_const_color = tev_cfgs[tex_env_idx].const_color;
-
- vec3 color_results[3] = vec3[3](GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.x, GetSource(tev_cfgs[tex_env_idx].color_sources.x)),
- GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.y, GetSource(tev_cfgs[tex_env_idx].color_sources.y)),
- GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.z, GetSource(tev_cfgs[tex_env_idx].color_sources.z)));
- vec3 color_output = ColorCombine(tev_cfgs[tex_env_idx].color_alpha_op.x, color_results);
-
- float alpha_results[3] = float[3](GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.x, GetSource(tev_cfgs[tex_env_idx].alpha_sources.x)),
- GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.y, GetSource(tev_cfgs[tex_env_idx].alpha_sources.y)),
- GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.z, GetSource(tev_cfgs[tex_env_idx].alpha_sources.z)));
- float alpha_output = AlphaCombine(tev_cfgs[tex_env_idx].color_alpha_op.y, alpha_results);
-
- g_last_tex_env_out = vec4(min(color_output * tev_cfgs[tex_env_idx].color_alpha_multiplier.x, 1.0), min(alpha_output * tev_cfgs[tex_env_idx].color_alpha_multiplier.y, 1.0));
- }
-
- if (tev_cfgs[tex_env_idx].updates_combiner_buffer_color_alpha.x) {
- g_combiner_buffer.rgb = g_last_tex_env_out.rgb;
- }
-
- if (tev_cfgs[tex_env_idx].updates_combiner_buffer_color_alpha.y) {
- g_combiner_buffer.a = g_last_tex_env_out.a;
- }
- }
-
- if (alphatest_enabled) {
- if (alphatest_func == COMPAREFUNC_NEVER) {
- discard;
- } else if (alphatest_func == COMPAREFUNC_ALWAYS) {
-
- } else if (alphatest_func == COMPAREFUNC_EQUAL) {
- if (g_last_tex_env_out.a != alphatest_ref) {
- discard;
- }
- } else if (alphatest_func == COMPAREFUNC_NOTEQUAL) {
- if (g_last_tex_env_out.a == alphatest_ref) {
- discard;
- }
- } else if (alphatest_func == COMPAREFUNC_LESSTHAN) {
- if (g_last_tex_env_out.a >= alphatest_ref) {
- discard;
- }
- } else if (alphatest_func == COMPAREFUNC_LESSTHANOREQUAL) {
- if (g_last_tex_env_out.a > alphatest_ref) {
- discard;
- }
- } else if (alphatest_func == COMPAREFUNC_GREATERTHAN) {
- if (g_last_tex_env_out.a <= alphatest_ref) {
- discard;
- }
- } else if (alphatest_func == COMPAREFUNC_GREATERTHANOREQUAL) {
- if (g_last_tex_env_out.a < alphatest_ref) {
- discard;
- }
- }
- }
-
- color = g_last_tex_env_out;
-}
-)";
-
-}
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 @@
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
-#include "video_core/renderer_opengl/gl_shaders.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
+static const char vertex_shader[] = R"(
+#version 150 core
+
+in vec2 vert_position;
+in vec2 vert_tex_coord;
+out vec2 frag_tex_coord;
+
+// This is a truncated 3x3 matrix for 2D transformations:
+// The upper-left 2x2 submatrix performs scaling/rotation/mirroring.
+// The third column performs translation.
+// The third row could be used for projection, which we don't need in 2D. It hence is assumed to
+// implicitly be [0, 0, 1]
+uniform mat3x2 modelview_matrix;
+
+void main() {
+ // Multiply input position by the rotscale part of the matrix and then manually translate by
+ // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
+ // to `vec3(vert_position.xy, 1.0)`
+ gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
+ frag_tex_coord = vert_tex_coord;
+}
+)";
+
+static const char fragment_shader[] = R"(
+#version 150 core
+
+in vec2 frag_tex_coord;
+out vec4 color;
+
+uniform sampler2D color_texture;
+
+void main() {
+ color = texture(color_texture, frag_tex_coord);
+}
+)";
+
/**
* Vertex structure that the drawn screen rectangles are composed of.
*/
@@ -207,7 +242,7 @@ void RendererOpenGL::InitOpenGLObjects() {
glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f);
// Link shaders and get variable locations
- program_id = ShaderUtil::LoadShaders(GLShaders::g_vertex_shader, GLShaders::g_fragment_shader);
+ program_id = GLShader::LoadProgram(vertex_shader, fragment_shader);
uniform_modelview_matrix = glGetUniformLocation(program_id, "modelview_matrix");
uniform_color_texture = glGetUniformLocation(program_id, "color_texture");
attrib_position = glGetAttribLocation(program_id, "vert_position");