Browse Source
renderer_opengl: Refactor shader generation/caching to be more organized + various cleanups.
nce_cpp
renderer_opengl: Refactor shader generation/caching to be more organized + various cleanups.
nce_cpp
11 changed files with 527 additions and 788 deletions
-
18src/common/common_funcs.h
-
3src/video_core/CMakeLists.txt
-
131src/video_core/renderer_opengl/gl_rasterizer.cpp
-
41src/video_core/renderer_opengl/gl_rasterizer.h
-
2src/video_core/renderer_opengl/gl_resource_manager.h
-
371src/video_core/renderer_opengl/gl_shader_gen.cpp
-
17src/video_core/renderer_opengl/gl_shader_gen.h
-
348src/video_core/renderer_opengl/gl_shader_util.cpp
-
6src/video_core/renderer_opengl/gl_shader_util.h
-
339src/video_core/renderer_opengl/gl_shaders.h
-
39src/video_core/renderer_opengl/renderer_opengl.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
|
||||
@ -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 |
||||
@ -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; |
|
||||
} |
|
||||
)"; |
|
||||
|
|
||||
} |
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue