mirror of
https://github.com/PabloMK7/citra.git
synced 2024-11-24 16:34:24 +00:00
Merge pull request #5264 from lioncash/gen
gl_shader_gen: Make use of fmt where applicable
This commit is contained in:
commit
96ebd53466
1 changed files with 195 additions and 198 deletions
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstring>
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
#include <fmt/format.h>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
#include "common/bit_set.h"
|
#include "common/bit_set.h"
|
||||||
|
@ -82,11 +82,11 @@ layout (std140) uniform shader_data {
|
||||||
static std::string GetVertexInterfaceDeclaration(bool is_output, bool separable_shader) {
|
static std::string GetVertexInterfaceDeclaration(bool is_output, bool separable_shader) {
|
||||||
std::string out;
|
std::string out;
|
||||||
|
|
||||||
auto append_variable = [&](const char* var, int location) {
|
const auto append_variable = [&](std::string_view var, int location) {
|
||||||
if (separable_shader) {
|
if (separable_shader) {
|
||||||
out += "layout (location=" + std::to_string(location) + ") ";
|
out += fmt::format("layout (location={}) ", location);
|
||||||
}
|
}
|
||||||
out += std::string(is_output ? "out " : "in ") + var + ";\n";
|
out += fmt::format("{}{};\n", is_output ? "out " : "in ", var);
|
||||||
};
|
};
|
||||||
|
|
||||||
append_variable("vec4 primary_color", ATTRIBUTE_COLOR);
|
append_variable("vec4 primary_color", ATTRIBUTE_COLOR);
|
||||||
|
@ -267,11 +267,12 @@ void PicaGSConfigCommonRaw::Init(const Pica::Regs& regs) {
|
||||||
|
|
||||||
semantic_maps.fill({16, 0});
|
semantic_maps.fill({16, 0});
|
||||||
for (u32 attrib = 0; attrib < regs.rasterizer.vs_output_total; ++attrib) {
|
for (u32 attrib = 0; attrib < regs.rasterizer.vs_output_total; ++attrib) {
|
||||||
std::array<VSOutputAttributes::Semantic, 4> semantics = {
|
const std::array semantics{
|
||||||
regs.rasterizer.vs_output_attributes[attrib].map_x,
|
regs.rasterizer.vs_output_attributes[attrib].map_x.Value(),
|
||||||
regs.rasterizer.vs_output_attributes[attrib].map_y,
|
regs.rasterizer.vs_output_attributes[attrib].map_y.Value(),
|
||||||
regs.rasterizer.vs_output_attributes[attrib].map_z,
|
regs.rasterizer.vs_output_attributes[attrib].map_z.Value(),
|
||||||
regs.rasterizer.vs_output_attributes[attrib].map_w};
|
regs.rasterizer.vs_output_attributes[attrib].map_w.Value(),
|
||||||
|
};
|
||||||
for (u32 comp = 0; comp < 4; ++comp) {
|
for (u32 comp = 0; comp < 4; ++comp) {
|
||||||
const auto semantic = semantics[comp];
|
const auto semantic = semantics[comp];
|
||||||
if (static_cast<std::size_t>(semantic) < 24) {
|
if (static_cast<std::size_t>(semantic) < 24) {
|
||||||
|
@ -342,7 +343,7 @@ static std::string SampleTexture(const PicaFSConfig& config, unsigned texture_un
|
||||||
|
|
||||||
/// Writes the specified TEV stage source component(s)
|
/// Writes the specified TEV stage source component(s)
|
||||||
static void AppendSource(std::string& out, const PicaFSConfig& config,
|
static void AppendSource(std::string& out, const PicaFSConfig& config,
|
||||||
TevStageConfig::Source source, const std::string& index_name) {
|
TevStageConfig::Source source, std::string_view index_name) {
|
||||||
using Source = TevStageConfig::Source;
|
using Source = TevStageConfig::Source;
|
||||||
switch (source) {
|
switch (source) {
|
||||||
case Source::PrimaryColor:
|
case Source::PrimaryColor:
|
||||||
|
@ -370,7 +371,9 @@ static void AppendSource(std::string& out, const PicaFSConfig& config,
|
||||||
out += "combiner_buffer";
|
out += "combiner_buffer";
|
||||||
break;
|
break;
|
||||||
case Source::Constant:
|
case Source::Constant:
|
||||||
((out += "const_color[") += index_name) += ']';
|
out += "const_color[";
|
||||||
|
out += index_name;
|
||||||
|
out += ']';
|
||||||
break;
|
break;
|
||||||
case Source::Previous:
|
case Source::Previous:
|
||||||
out += "last_tex_env_out";
|
out += "last_tex_env_out";
|
||||||
|
@ -385,7 +388,7 @@ static void AppendSource(std::string& out, const PicaFSConfig& config,
|
||||||
/// Writes the color components to use for the specified TEV stage color modifier
|
/// Writes the color components to use for the specified TEV stage color modifier
|
||||||
static void AppendColorModifier(std::string& out, const PicaFSConfig& config,
|
static void AppendColorModifier(std::string& out, const PicaFSConfig& config,
|
||||||
TevStageConfig::ColorModifier modifier,
|
TevStageConfig::ColorModifier modifier,
|
||||||
TevStageConfig::Source source, const std::string& index_name) {
|
TevStageConfig::Source source, std::string_view index_name) {
|
||||||
using ColorModifier = TevStageConfig::ColorModifier;
|
using ColorModifier = TevStageConfig::ColorModifier;
|
||||||
switch (modifier) {
|
switch (modifier) {
|
||||||
case ColorModifier::SourceColor:
|
case ColorModifier::SourceColor:
|
||||||
|
@ -491,40 +494,38 @@ static void AppendAlphaModifier(std::string& out, const PicaFSConfig& config,
|
||||||
|
|
||||||
/// Writes the combiner function for the color components for the specified TEV stage operation
|
/// Writes the combiner function for the color components for the specified TEV stage operation
|
||||||
static void AppendColorCombiner(std::string& out, TevStageConfig::Operation operation,
|
static void AppendColorCombiner(std::string& out, TevStageConfig::Operation operation,
|
||||||
const std::string& variable_name) {
|
std::string_view variable_name) {
|
||||||
out += "clamp(";
|
out += "clamp(";
|
||||||
using Operation = TevStageConfig::Operation;
|
using Operation = TevStageConfig::Operation;
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case Operation::Replace:
|
case Operation::Replace:
|
||||||
out += variable_name + "[0]";
|
out += fmt::format("{}[0]", variable_name);
|
||||||
break;
|
break;
|
||||||
case Operation::Modulate:
|
case Operation::Modulate:
|
||||||
out += variable_name + "[0] * " + variable_name + "[1]";
|
out += fmt::format("{0}[0] * {0}[1]", variable_name);
|
||||||
break;
|
break;
|
||||||
case Operation::Add:
|
case Operation::Add:
|
||||||
out += variable_name + "[0] + " + variable_name + "[1]";
|
out += fmt::format("{0}[0] + {0}[1]", variable_name);
|
||||||
break;
|
break;
|
||||||
case Operation::AddSigned:
|
case Operation::AddSigned:
|
||||||
out += variable_name + "[0] + " + variable_name + "[1] - vec3(0.5)";
|
out += fmt::format("{0}[0] + {0}[1] - vec3(0.5)", variable_name);
|
||||||
break;
|
break;
|
||||||
case Operation::Lerp:
|
case Operation::Lerp:
|
||||||
out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name +
|
out += fmt::format("{0}[0] * {0}[2] + {0}[1] * (vec3(1.0) - {0}[2])", variable_name);
|
||||||
"[1] * (vec3(1.0) - " + variable_name + "[2])";
|
|
||||||
break;
|
break;
|
||||||
case Operation::Subtract:
|
case Operation::Subtract:
|
||||||
out += variable_name + "[0] - " + variable_name + "[1]";
|
out += fmt::format("{0}[0] - {0}[1]", variable_name);
|
||||||
break;
|
break;
|
||||||
case Operation::MultiplyThenAdd:
|
case Operation::MultiplyThenAdd:
|
||||||
out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]";
|
out += fmt::format("{0}[0] * {0}[1] + {0}[2]", variable_name);
|
||||||
break;
|
break;
|
||||||
case Operation::AddThenMultiply:
|
case Operation::AddThenMultiply:
|
||||||
out += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " +
|
out += fmt::format("min({0}[0] + {0}[1], vec3(1.0)) * {0}[2]", variable_name);
|
||||||
variable_name + "[2]";
|
|
||||||
break;
|
break;
|
||||||
case Operation::Dot3_RGB:
|
case Operation::Dot3_RGB:
|
||||||
case Operation::Dot3_RGBA:
|
case Operation::Dot3_RGBA:
|
||||||
out += "vec3(dot(" + variable_name + "[0] - vec3(0.5), " + variable_name +
|
out +=
|
||||||
"[1] - vec3(0.5)) * 4.0)";
|
fmt::format("vec3(dot({0}[0] - vec3(0.5), {0}[1] - vec3(0.5)) * 4.0)", variable_name);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
out += "vec3(0.0)";
|
out += "vec3(0.0)";
|
||||||
|
@ -537,35 +538,33 @@ static void AppendColorCombiner(std::string& out, TevStageConfig::Operation oper
|
||||||
|
|
||||||
/// Writes the combiner function for the alpha component for the specified TEV stage operation
|
/// Writes the combiner function for the alpha component for the specified TEV stage operation
|
||||||
static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation operation,
|
static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation operation,
|
||||||
const std::string& variable_name) {
|
std::string_view variable_name) {
|
||||||
out += "clamp(";
|
out += "clamp(";
|
||||||
using Operation = TevStageConfig::Operation;
|
using Operation = TevStageConfig::Operation;
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case Operation::Replace:
|
case Operation::Replace:
|
||||||
out += variable_name + "[0]";
|
out += fmt::format("{}[0]", variable_name);
|
||||||
break;
|
break;
|
||||||
case Operation::Modulate:
|
case Operation::Modulate:
|
||||||
out += variable_name + "[0] * " + variable_name + "[1]";
|
out += fmt::format("{0}[0] * {0}[1]", variable_name);
|
||||||
break;
|
break;
|
||||||
case Operation::Add:
|
case Operation::Add:
|
||||||
out += variable_name + "[0] + " + variable_name + "[1]";
|
out += fmt::format("{0}[0] + {0}[1]", variable_name);
|
||||||
break;
|
break;
|
||||||
case Operation::AddSigned:
|
case Operation::AddSigned:
|
||||||
out += variable_name + "[0] + " + variable_name + "[1] - 0.5";
|
out += fmt::format("{0}[0] + {0}[1] - 0.5", variable_name);
|
||||||
break;
|
break;
|
||||||
case Operation::Lerp:
|
case Operation::Lerp:
|
||||||
out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name +
|
out += fmt::format("{0}[0] * {0}[2] + {0}[1] * (1.0 - {0}[2])", variable_name);
|
||||||
"[1] * (1.0 - " + variable_name + "[2])";
|
|
||||||
break;
|
break;
|
||||||
case Operation::Subtract:
|
case Operation::Subtract:
|
||||||
out += variable_name + "[0] - " + variable_name + "[1]";
|
out += fmt::format("{0}[0] - {0}[1]", variable_name);
|
||||||
break;
|
break;
|
||||||
case Operation::MultiplyThenAdd:
|
case Operation::MultiplyThenAdd:
|
||||||
out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]";
|
out += fmt::format("{0}[0] * {0}[1] + {0}[2]", variable_name);
|
||||||
break;
|
break;
|
||||||
case Operation::AddThenMultiply:
|
case Operation::AddThenMultiply:
|
||||||
out += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name +
|
out += fmt::format("min({0}[0] + {0}[1], 1.0) * {0}[2]", variable_name);
|
||||||
"[2]";
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
out += "0.0";
|
out += "0.0";
|
||||||
|
@ -592,9 +591,9 @@ static void AppendAlphaTestCondition(std::string& out, FramebufferRegs::CompareF
|
||||||
case CompareFunc::LessThanOrEqual:
|
case CompareFunc::LessThanOrEqual:
|
||||||
case CompareFunc::GreaterThan:
|
case CompareFunc::GreaterThan:
|
||||||
case CompareFunc::GreaterThanOrEqual: {
|
case CompareFunc::GreaterThanOrEqual: {
|
||||||
static const char* op[] = {"!=", "==", ">=", ">", "<=", "<"};
|
static constexpr std::array op{"!=", "==", ">=", ">", "<=", "<"};
|
||||||
unsigned index = (unsigned)func - (unsigned)CompareFunc::Equal;
|
const auto index = static_cast<u32>(func) - static_cast<u32>(CompareFunc::Equal);
|
||||||
out += "int(last_tex_env_out.a * 255.0) " + std::string(op[index]) + " alphatest_ref";
|
out += fmt::format("int(last_tex_env_out.a * 255.0) {} alphatest_ref", op[index]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,9 +609,9 @@ static void WriteTevStage(std::string& out, const PicaFSConfig& config, unsigned
|
||||||
const auto stage =
|
const auto stage =
|
||||||
static_cast<const TexturingRegs::TevStageConfig>(config.state.tev_stages[index]);
|
static_cast<const TexturingRegs::TevStageConfig>(config.state.tev_stages[index]);
|
||||||
if (!IsPassThroughTevStage(stage)) {
|
if (!IsPassThroughTevStage(stage)) {
|
||||||
std::string index_name = std::to_string(index);
|
const std::string index_name = std::to_string(index);
|
||||||
|
|
||||||
out += "vec3 color_results_" + index_name + "[3] = vec3[3](";
|
out += fmt::format("vec3 color_results_{}[3] = vec3[3](", index_name);
|
||||||
AppendColorModifier(out, config, stage.color_modifier1, stage.color_source1, index_name);
|
AppendColorModifier(out, config, stage.color_modifier1, stage.color_source1, index_name);
|
||||||
out += ", ";
|
out += ", ";
|
||||||
AppendColorModifier(out, config, stage.color_modifier2, stage.color_source2, index_name);
|
AppendColorModifier(out, config, stage.color_modifier2, stage.color_source2, index_name);
|
||||||
|
@ -621,15 +620,15 @@ static void WriteTevStage(std::string& out, const PicaFSConfig& config, unsigned
|
||||||
out += ");\n";
|
out += ");\n";
|
||||||
|
|
||||||
// Round the output of each TEV stage to maintain the PICA's 8 bits of precision
|
// Round the output of each TEV stage to maintain the PICA's 8 bits of precision
|
||||||
out += "vec3 color_output_" + index_name + " = byteround(";
|
out += fmt::format("vec3 color_output_{} = byteround(", index_name);
|
||||||
AppendColorCombiner(out, stage.color_op, "color_results_" + index_name);
|
AppendColorCombiner(out, stage.color_op, "color_results_" + index_name);
|
||||||
out += ");\n";
|
out += ");\n";
|
||||||
|
|
||||||
if (stage.color_op == TevStageConfig::Operation::Dot3_RGBA) {
|
if (stage.color_op == TevStageConfig::Operation::Dot3_RGBA) {
|
||||||
// result of Dot3_RGBA operation is also placed to the alpha component
|
// result of Dot3_RGBA operation is also placed to the alpha component
|
||||||
out += "float alpha_output_" + index_name + " = color_output_" + index_name + "[0];\n";
|
out += fmt::format("float alpha_output_{0} = color_output_{0}[0];\n", index_name);
|
||||||
} else {
|
} else {
|
||||||
out += "float alpha_results_" + index_name + "[3] = float[3](";
|
out += fmt::format("float alpha_results_{}[3] = float[3](", index_name);
|
||||||
AppendAlphaModifier(out, config, stage.alpha_modifier1, stage.alpha_source1,
|
AppendAlphaModifier(out, config, stage.alpha_modifier1, stage.alpha_source1,
|
||||||
index_name);
|
index_name);
|
||||||
out += ", ";
|
out += ", ";
|
||||||
|
@ -640,18 +639,16 @@ static void WriteTevStage(std::string& out, const PicaFSConfig& config, unsigned
|
||||||
index_name);
|
index_name);
|
||||||
out += ");\n";
|
out += ");\n";
|
||||||
|
|
||||||
out += "float alpha_output_" + index_name + " = byteround(";
|
out += fmt::format("float alpha_output_{} = byteround(", index_name);
|
||||||
AppendAlphaCombiner(out, stage.alpha_op, "alpha_results_" + index_name);
|
AppendAlphaCombiner(out, stage.alpha_op, "alpha_results_" + index_name);
|
||||||
out += ");\n";
|
out += ");\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
out += "last_tex_env_out = vec4("
|
out += fmt::format("last_tex_env_out = vec4("
|
||||||
"clamp(color_output_" +
|
"clamp(color_output_{} * {}.0, vec3(0.0), vec3(1.0)), "
|
||||||
index_name + " * " + std::to_string(stage.GetColorMultiplier()) +
|
"clamp(alpha_output_{} * {}.0, 0.0, 1.0));\n",
|
||||||
".0, vec3(0.0), vec3(1.0)),"
|
index_name, stage.GetColorMultiplier(), index_name,
|
||||||
"clamp(alpha_output_" +
|
stage.GetAlphaMultiplier());
|
||||||
index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) +
|
|
||||||
".0, 0.0, 1.0));\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out += "combiner_buffer = next_combiner_buffer;\n";
|
out += "combiner_buffer = next_combiner_buffer;\n";
|
||||||
|
@ -679,26 +676,26 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
||||||
"float geo_factor = 1.0;\n";
|
"float geo_factor = 1.0;\n";
|
||||||
|
|
||||||
// Compute fragment normals and tangents
|
// Compute fragment normals and tangents
|
||||||
auto Perturbation = [&]() {
|
const auto Perturbation = [&] {
|
||||||
return "2.0 * (" + SampleTexture(config, lighting.bump_selector) + ").rgb - 1.0";
|
return fmt::format("2.0 * ({}).rgb - 1.0", SampleTexture(config, lighting.bump_selector));
|
||||||
};
|
};
|
||||||
if (lighting.bump_mode == LightingRegs::LightingBumpMode::NormalMap) {
|
if (lighting.bump_mode == LightingRegs::LightingBumpMode::NormalMap) {
|
||||||
// Bump mapping is enabled using a normal map
|
// Bump mapping is enabled using a normal map
|
||||||
out += "vec3 surface_normal = " + Perturbation() + ";\n";
|
out += fmt::format("vec3 surface_normal = {};\n", Perturbation());
|
||||||
|
|
||||||
// Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher
|
// Recompute Z-component of perturbation if 'renorm' is enabled, this provides a higher
|
||||||
// precision result
|
// precision result
|
||||||
if (lighting.bump_renorm) {
|
if (lighting.bump_renorm) {
|
||||||
std::string val =
|
constexpr std::string_view val =
|
||||||
"(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))";
|
"(1.0 - (surface_normal.x*surface_normal.x + surface_normal.y*surface_normal.y))";
|
||||||
out += "surface_normal.z = sqrt(max(" + val + ", 0.0));\n";
|
out += fmt::format("surface_normal.z = sqrt(max({}, 0.0));\n", val);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The tangent vector is not perturbed by the normal map and is just a unit vector.
|
// The tangent vector is not perturbed by the normal map and is just a unit vector.
|
||||||
out += "vec3 surface_tangent = vec3(1.0, 0.0, 0.0);\n";
|
out += "vec3 surface_tangent = vec3(1.0, 0.0, 0.0);\n";
|
||||||
} else if (lighting.bump_mode == LightingRegs::LightingBumpMode::TangentMap) {
|
} else if (lighting.bump_mode == LightingRegs::LightingBumpMode::TangentMap) {
|
||||||
// Bump mapping is enabled using a tangent map
|
// Bump mapping is enabled using a tangent map
|
||||||
out += "vec3 surface_tangent = " + Perturbation() + ";\n";
|
out += fmt::format("vec3 surface_tangent = {};\n", Perturbation());
|
||||||
// Mathematically, recomputing Z-component of the tangent vector won't affect the relevant
|
// Mathematically, recomputing Z-component of the tangent vector won't affect the relevant
|
||||||
// computation below, which is also confirmed on 3DS. So we don't bother recomputing here
|
// computation below, which is also confirmed on 3DS. So we don't bother recomputing here
|
||||||
// even if 'renorm' is enabled.
|
// even if 'renorm' is enabled.
|
||||||
|
@ -707,22 +704,22 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
||||||
out += "vec3 surface_normal = vec3(0.0, 0.0, 1.0);\n";
|
out += "vec3 surface_normal = vec3(0.0, 0.0, 1.0);\n";
|
||||||
} else {
|
} else {
|
||||||
// No bump mapping - surface local normal and tangent are just unit vectors
|
// No bump mapping - surface local normal and tangent are just unit vectors
|
||||||
out += "vec3 surface_normal = vec3(0.0, 0.0, 1.0);\n";
|
out += "vec3 surface_normal = vec3(0.0, 0.0, 1.0);\n"
|
||||||
out += "vec3 surface_tangent = vec3(1.0, 0.0, 0.0);\n";
|
"vec3 surface_tangent = vec3(1.0, 0.0, 0.0);\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rotate the surface-local normal by the interpolated normal quaternion to convert it to
|
// Rotate the surface-local normal by the interpolated normal quaternion to convert it to
|
||||||
// eyespace.
|
// eyespace.
|
||||||
out += "vec4 normalized_normquat = normalize(normquat);\n";
|
out += "vec4 normalized_normquat = normalize(normquat);\n"
|
||||||
out += "vec3 normal = quaternion_rotate(normalized_normquat, surface_normal);\n";
|
"vec3 normal = quaternion_rotate(normalized_normquat, surface_normal);\n"
|
||||||
out += "vec3 tangent = quaternion_rotate(normalized_normquat, surface_tangent);\n";
|
"vec3 tangent = quaternion_rotate(normalized_normquat, surface_tangent);\n";
|
||||||
|
|
||||||
if (lighting.enable_shadow) {
|
if (lighting.enable_shadow) {
|
||||||
std::string shadow_texture = SampleTexture(config, lighting.shadow_selector);
|
std::string shadow_texture = SampleTexture(config, lighting.shadow_selector);
|
||||||
if (lighting.shadow_invert) {
|
if (lighting.shadow_invert) {
|
||||||
out += "vec4 shadow = vec4(1.0) - " + shadow_texture + ";\n";
|
out += fmt::format("vec4 shadow = vec4(1.0) - {};\n", shadow_texture);
|
||||||
} else {
|
} else {
|
||||||
out += "vec4 shadow = " + shadow_texture + ";\n";
|
out += fmt::format("vec4 shadow = {};\n", shadow_texture);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
out += "vec4 shadow = vec4(1.0);\n";
|
out += "vec4 shadow = vec4(1.0);\n";
|
||||||
|
@ -738,19 +735,19 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LightingRegs::LightingLutInput::VH:
|
case LightingRegs::LightingLutInput::VH:
|
||||||
index = std::string("dot(normalize(view), normalize(half_vector))");
|
index = "dot(normalize(view), normalize(half_vector))";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LightingRegs::LightingLutInput::NV:
|
case LightingRegs::LightingLutInput::NV:
|
||||||
index = std::string("dot(normal, normalize(view))");
|
index = "dot(normal, normalize(view))";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LightingRegs::LightingLutInput::LN:
|
case LightingRegs::LightingLutInput::LN:
|
||||||
index = std::string("dot(light_vector, normal)");
|
index = "dot(light_vector, normal)";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LightingRegs::LightingLutInput::SP:
|
case LightingRegs::LightingLutInput::SP:
|
||||||
index = std::string("dot(light_vector, spot_dir)");
|
index = "dot(light_vector, spot_dir)";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LightingRegs::LightingLutInput::CP:
|
case LightingRegs::LightingLutInput::CP:
|
||||||
|
@ -759,11 +756,11 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
||||||
// Note: even if the normal vector is modified by normal map, which is not the
|
// Note: even if the normal vector is modified by normal map, which is not the
|
||||||
// normal of the tangent plane anymore, the half angle vector is still projected
|
// normal of the tangent plane anymore, the half angle vector is still projected
|
||||||
// using the modified normal vector.
|
// using the modified normal vector.
|
||||||
std::string half_angle_proj =
|
constexpr std::string_view half_angle_proj =
|
||||||
"normalize(half_vector) - normal * dot(normal, normalize(half_vector))";
|
"normalize(half_vector) - normal * dot(normal, normalize(half_vector))";
|
||||||
// Note: the half angle vector projection is confirmed not normalized before the dot
|
// Note: the half angle vector projection is confirmed not normalized before the dot
|
||||||
// product. The result is in fact not cos(phi) as the name suggested.
|
// product. The result is in fact not cos(phi) as the name suggested.
|
||||||
index = "dot(" + half_angle_proj + ", tangent)";
|
index = fmt::format("dot({}, tangent)", half_angle_proj);
|
||||||
} else {
|
} else {
|
||||||
index = "0.0";
|
index = "0.0";
|
||||||
}
|
}
|
||||||
|
@ -776,31 +773,33 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string sampler_string = std::to_string(static_cast<unsigned>(sampler));
|
const auto sampler_index = static_cast<u32>(sampler);
|
||||||
|
|
||||||
if (abs) {
|
if (abs) {
|
||||||
// LUT index is in the range of (0.0, 1.0)
|
// LUT index is in the range of (0.0, 1.0)
|
||||||
index = lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")"
|
index = lighting.light[light_num].two_sided_diffuse
|
||||||
: "max(" + index + ", 0.0)";
|
? fmt::format("abs({})", index)
|
||||||
return "LookupLightingLUTUnsigned(" + sampler_string + ", " + index + ")";
|
: fmt::format("max({}, 0.0)", index);
|
||||||
|
return fmt::format("LookupLightingLUTUnsigned({}, {})", sampler_index, index);
|
||||||
} else {
|
} else {
|
||||||
// LUT index is in the range of (-1.0, 1.0)
|
// LUT index is in the range of (-1.0, 1.0)
|
||||||
return "LookupLightingLUTSigned(" + sampler_string + ", " + index + ")";
|
return fmt::format("LookupLightingLUTSigned({}, {})", sampler_index, index);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Write the code to emulate each enabled light
|
// Write the code to emulate each enabled light
|
||||||
for (unsigned light_index = 0; light_index < lighting.src_num; ++light_index) {
|
for (unsigned light_index = 0; light_index < lighting.src_num; ++light_index) {
|
||||||
const auto& light_config = lighting.light[light_index];
|
const auto& light_config = lighting.light[light_index];
|
||||||
std::string light_src = "light_src[" + std::to_string(light_config.num) + "]";
|
const std::string light_src = fmt::format("light_src[{}]", light_config.num);
|
||||||
|
|
||||||
// Compute light vector (directional or positional)
|
// Compute light vector (directional or positional)
|
||||||
if (light_config.directional)
|
if (light_config.directional) {
|
||||||
out += "light_vector = normalize(" + light_src + ".position);\n";
|
out += fmt::format("light_vector = normalize({}.position);\n", light_src);
|
||||||
else
|
} else {
|
||||||
out += "light_vector = normalize(" + light_src + ".position + view);\n";
|
out += fmt::format("light_vector = normalize({}.position + view);\n", light_src);
|
||||||
|
}
|
||||||
|
|
||||||
out += "spot_dir = " + light_src + ".spot_direction;\n";
|
out += fmt::format("spot_dir = {}.spot_direction;\n", light_src);
|
||||||
out += "half_vector = normalize(view) + light_vector;\n";
|
out += "half_vector = normalize(view) + light_vector;\n";
|
||||||
|
|
||||||
// Compute dot product of light_vector and normal, adjust if lighting is one-sided or
|
// Compute dot product of light_vector and normal, adjust if lighting is one-sided or
|
||||||
|
@ -819,21 +818,21 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
||||||
if (light_config.spot_atten_enable &&
|
if (light_config.spot_atten_enable &&
|
||||||
LightingRegs::IsLightingSamplerSupported(
|
LightingRegs::IsLightingSamplerSupported(
|
||||||
lighting.config, LightingRegs::LightingSampler::SpotlightAttenuation)) {
|
lighting.config, LightingRegs::LightingSampler::SpotlightAttenuation)) {
|
||||||
std::string value =
|
const std::string value =
|
||||||
GetLutValue(LightingRegs::SpotlightAttenuationSampler(light_config.num),
|
GetLutValue(LightingRegs::SpotlightAttenuationSampler(light_config.num),
|
||||||
light_config.num, lighting.lut_sp.type, lighting.lut_sp.abs_input);
|
light_config.num, lighting.lut_sp.type, lighting.lut_sp.abs_input);
|
||||||
spot_atten = "(" + std::to_string(lighting.lut_sp.scale) + " * " + value + ")";
|
spot_atten = fmt::format("({} * {})", lighting.lut_sp.scale, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If enabled, compute distance attenuation value
|
// If enabled, compute distance attenuation value
|
||||||
std::string dist_atten = "1.0";
|
std::string dist_atten = "1.0";
|
||||||
if (light_config.dist_atten_enable) {
|
if (light_config.dist_atten_enable) {
|
||||||
std::string index = "clamp(" + light_src + ".dist_atten_scale * length(-view - " +
|
const std::string index = fmt::format("clamp({}.dist_atten_scale * length(-view - "
|
||||||
light_src + ".position) + " + light_src +
|
"{}.position) + {}.dist_atten_bias, 0.0, 1.0)",
|
||||||
".dist_atten_bias, 0.0, 1.0)";
|
light_src, light_src, light_src);
|
||||||
auto sampler = LightingRegs::DistanceAttenuationSampler(light_config.num);
|
const auto sampler = LightingRegs::DistanceAttenuationSampler(light_config.num);
|
||||||
dist_atten = "LookupLightingLUTUnsigned(" +
|
dist_atten =
|
||||||
std::to_string(static_cast<unsigned>(sampler)) + "," + index + ")";
|
fmt::format("LookupLightingLUTUnsigned({}, {})", static_cast<u32>(sampler), index);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (light_config.geometric_factor_0 || light_config.geometric_factor_1) {
|
if (light_config.geometric_factor_0 || light_config.geometric_factor_1) {
|
||||||
|
@ -848,14 +847,14 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
||||||
LightingRegs::IsLightingSamplerSupported(
|
LightingRegs::IsLightingSamplerSupported(
|
||||||
lighting.config, LightingRegs::LightingSampler::Distribution0)) {
|
lighting.config, LightingRegs::LightingSampler::Distribution0)) {
|
||||||
// Lookup specular "distribution 0" LUT value
|
// Lookup specular "distribution 0" LUT value
|
||||||
std::string value =
|
const std::string value =
|
||||||
GetLutValue(LightingRegs::LightingSampler::Distribution0, light_config.num,
|
GetLutValue(LightingRegs::LightingSampler::Distribution0, light_config.num,
|
||||||
lighting.lut_d0.type, lighting.lut_d0.abs_input);
|
lighting.lut_d0.type, lighting.lut_d0.abs_input);
|
||||||
d0_lut_value = "(" + std::to_string(lighting.lut_d0.scale) + " * " + value + ")";
|
d0_lut_value = fmt::format("({} * {})", lighting.lut_d0.scale, value);
|
||||||
}
|
}
|
||||||
std::string specular_0 = "(" + d0_lut_value + " * " + light_src + ".specular_0)";
|
std::string specular_0 = fmt::format("({} * {}.specular_0)", d0_lut_value, light_src);
|
||||||
if (light_config.geometric_factor_0) {
|
if (light_config.geometric_factor_0) {
|
||||||
specular_0 = "(" + specular_0 + " * geo_factor)";
|
specular_0 = fmt::format("({} * geo_factor)", specular_0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If enabled, lookup ReflectRed value, otherwise, 1.0 is used
|
// If enabled, lookup ReflectRed value, otherwise, 1.0 is used
|
||||||
|
@ -865,8 +864,8 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
||||||
std::string value =
|
std::string value =
|
||||||
GetLutValue(LightingRegs::LightingSampler::ReflectRed, light_config.num,
|
GetLutValue(LightingRegs::LightingSampler::ReflectRed, light_config.num,
|
||||||
lighting.lut_rr.type, lighting.lut_rr.abs_input);
|
lighting.lut_rr.type, lighting.lut_rr.abs_input);
|
||||||
value = "(" + std::to_string(lighting.lut_rr.scale) + " * " + value + ")";
|
value = fmt::format("({} * {})", lighting.lut_rr.scale, value);
|
||||||
out += "refl_value.r = " + value + ";\n";
|
out += fmt::format("refl_value.r = {};\n", value);
|
||||||
} else {
|
} else {
|
||||||
out += "refl_value.r = 1.0;\n";
|
out += "refl_value.r = 1.0;\n";
|
||||||
}
|
}
|
||||||
|
@ -878,8 +877,8 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
||||||
std::string value =
|
std::string value =
|
||||||
GetLutValue(LightingRegs::LightingSampler::ReflectGreen, light_config.num,
|
GetLutValue(LightingRegs::LightingSampler::ReflectGreen, light_config.num,
|
||||||
lighting.lut_rg.type, lighting.lut_rg.abs_input);
|
lighting.lut_rg.type, lighting.lut_rg.abs_input);
|
||||||
value = "(" + std::to_string(lighting.lut_rg.scale) + " * " + value + ")";
|
value = fmt::format("({} * {})", lighting.lut_rg.scale, value);
|
||||||
out += "refl_value.g = " + value + ";\n";
|
out += fmt::format("refl_value.g = {};\n", value);
|
||||||
} else {
|
} else {
|
||||||
out += "refl_value.g = refl_value.r;\n";
|
out += "refl_value.g = refl_value.r;\n";
|
||||||
}
|
}
|
||||||
|
@ -891,8 +890,8 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
||||||
std::string value =
|
std::string value =
|
||||||
GetLutValue(LightingRegs::LightingSampler::ReflectBlue, light_config.num,
|
GetLutValue(LightingRegs::LightingSampler::ReflectBlue, light_config.num,
|
||||||
lighting.lut_rb.type, lighting.lut_rb.abs_input);
|
lighting.lut_rb.type, lighting.lut_rb.abs_input);
|
||||||
value = "(" + std::to_string(lighting.lut_rb.scale) + " * " + value + ")";
|
value = fmt::format("({} * {})", lighting.lut_rb.scale, value);
|
||||||
out += "refl_value.b = " + value + ";\n";
|
out += fmt::format("refl_value.b = {};\n", value);
|
||||||
} else {
|
} else {
|
||||||
out += "refl_value.b = refl_value.r;\n";
|
out += "refl_value.b = refl_value.r;\n";
|
||||||
}
|
}
|
||||||
|
@ -903,15 +902,15 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
||||||
LightingRegs::IsLightingSamplerSupported(
|
LightingRegs::IsLightingSamplerSupported(
|
||||||
lighting.config, LightingRegs::LightingSampler::Distribution1)) {
|
lighting.config, LightingRegs::LightingSampler::Distribution1)) {
|
||||||
// Lookup specular "distribution 1" LUT value
|
// Lookup specular "distribution 1" LUT value
|
||||||
std::string value =
|
const std::string value =
|
||||||
GetLutValue(LightingRegs::LightingSampler::Distribution1, light_config.num,
|
GetLutValue(LightingRegs::LightingSampler::Distribution1, light_config.num,
|
||||||
lighting.lut_d1.type, lighting.lut_d1.abs_input);
|
lighting.lut_d1.type, lighting.lut_d1.abs_input);
|
||||||
d1_lut_value = "(" + std::to_string(lighting.lut_d1.scale) + " * " + value + ")";
|
d1_lut_value = fmt::format("({} * {})", lighting.lut_d1.scale, value);
|
||||||
}
|
}
|
||||||
std::string specular_1 =
|
std::string specular_1 =
|
||||||
"(" + d1_lut_value + " * refl_value * " + light_src + ".specular_1)";
|
fmt::format("({} * refl_value * {}.specular_1)", d1_lut_value, light_src);
|
||||||
if (light_config.geometric_factor_1) {
|
if (light_config.geometric_factor_1) {
|
||||||
specular_1 = "(" + specular_1 + " * geo_factor)";
|
specular_1 = fmt::format("({} * geo_factor)", specular_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fresnel
|
// Fresnel
|
||||||
|
@ -923,16 +922,16 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
||||||
std::string value =
|
std::string value =
|
||||||
GetLutValue(LightingRegs::LightingSampler::Fresnel, light_config.num,
|
GetLutValue(LightingRegs::LightingSampler::Fresnel, light_config.num,
|
||||||
lighting.lut_fr.type, lighting.lut_fr.abs_input);
|
lighting.lut_fr.type, lighting.lut_fr.abs_input);
|
||||||
value = "(" + std::to_string(lighting.lut_fr.scale) + " * " + value + ")";
|
value = fmt::format("({} * {})", lighting.lut_fr.scale, value);
|
||||||
|
|
||||||
// Enabled for diffuse lighting alpha component
|
// Enabled for diffuse lighting alpha component
|
||||||
if (lighting.enable_primary_alpha) {
|
if (lighting.enable_primary_alpha) {
|
||||||
out += "diffuse_sum.a = " + value + ";\n";
|
out += fmt::format("diffuse_sum.a = {};\n", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enabled for the specular lighting alpha component
|
// Enabled for the specular lighting alpha component
|
||||||
if (lighting.enable_secondary_alpha) {
|
if (lighting.enable_secondary_alpha) {
|
||||||
out += "specular_sum.a = " + value + ";\n";
|
out += fmt::format("specular_sum.a = {};\n", value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -942,13 +941,13 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
||||||
std::string shadow_secondary = shadow_secondary_enable ? " * shadow.rgb" : "";
|
std::string shadow_secondary = shadow_secondary_enable ? " * shadow.rgb" : "";
|
||||||
|
|
||||||
// Compute primary fragment color (diffuse lighting) function
|
// Compute primary fragment color (diffuse lighting) function
|
||||||
out += "diffuse_sum.rgb += ((" + light_src + ".diffuse * dot_product) + " + light_src +
|
out += fmt::format(
|
||||||
".ambient) * " + dist_atten + " * " + spot_atten + shadow_primary + ";\n";
|
"diffuse_sum.rgb += (({}.diffuse * dot_product) + {}.ambient) * {} * {}{};\n",
|
||||||
|
light_src, light_src, dist_atten, spot_atten, shadow_primary);
|
||||||
|
|
||||||
// Compute secondary fragment color (specular lighting) function
|
// Compute secondary fragment color (specular lighting) function
|
||||||
out += "specular_sum.rgb += (" + specular_0 + " + " + specular_1 +
|
out += fmt::format("specular_sum.rgb += ({} + {}) * clamp_highlights * {} * {}{};\n",
|
||||||
") * clamp_highlights * " + dist_atten + " * " + spot_atten + shadow_secondary +
|
specular_0, specular_1, dist_atten, spot_atten, shadow_secondary);
|
||||||
";\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply shadow attenuation to alpha components if enabled
|
// Apply shadow attenuation to alpha components if enabled
|
||||||
|
@ -962,9 +961,9 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sum final lighting result
|
// Sum final lighting result
|
||||||
out += "diffuse_sum.rgb += lighting_global_ambient;\n";
|
out += "diffuse_sum.rgb += lighting_global_ambient;\n"
|
||||||
out += "primary_fragment_color = clamp(diffuse_sum, vec4(0.0), vec4(1.0));\n";
|
"primary_fragment_color = clamp(diffuse_sum, vec4(0.0), vec4(1.0));\n"
|
||||||
out += "secondary_fragment_color = clamp(specular_sum, vec4(0.0), vec4(1.0));\n";
|
"secondary_fragment_color = clamp(specular_sum, vec4(0.0), vec4(1.0));\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
using ProcTexClamp = TexturingRegs::ProcTexClamp;
|
using ProcTexClamp = TexturingRegs::ProcTexClamp;
|
||||||
|
@ -972,18 +971,18 @@ using ProcTexShift = TexturingRegs::ProcTexShift;
|
||||||
using ProcTexCombiner = TexturingRegs::ProcTexCombiner;
|
using ProcTexCombiner = TexturingRegs::ProcTexCombiner;
|
||||||
using ProcTexFilter = TexturingRegs::ProcTexFilter;
|
using ProcTexFilter = TexturingRegs::ProcTexFilter;
|
||||||
|
|
||||||
void AppendProcTexShiftOffset(std::string& out, const std::string& v, ProcTexShift mode,
|
void AppendProcTexShiftOffset(std::string& out, std::string_view v, ProcTexShift mode,
|
||||||
ProcTexClamp clamp_mode) {
|
ProcTexClamp clamp_mode) {
|
||||||
std::string offset = (clamp_mode == ProcTexClamp::MirroredRepeat) ? "1.0" : "0.5";
|
const std::string_view offset = (clamp_mode == ProcTexClamp::MirroredRepeat) ? "1.0" : "0.5";
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case ProcTexShift::None:
|
case ProcTexShift::None:
|
||||||
out += "0.0";
|
out += "0.0";
|
||||||
break;
|
break;
|
||||||
case ProcTexShift::Odd:
|
case ProcTexShift::Odd:
|
||||||
out += offset + " * float((int(" + v + ") / 2) % 2)";
|
out += fmt::format("{} * float((int({}) / 2) % 2)", offset, v);
|
||||||
break;
|
break;
|
||||||
case ProcTexShift::Even:
|
case ProcTexShift::Even:
|
||||||
out += offset + " * float(((int(" + v + ") + 1) / 2) % 2)";
|
out += fmt::format("{} * float(((int({}) + 1) / 2) % 2)", offset, v);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_CRITICAL(HW_GPU, "Unknown shift mode {}", static_cast<u32>(mode));
|
LOG_CRITICAL(HW_GPU, "Unknown shift mode {}", static_cast<u32>(mode));
|
||||||
|
@ -992,34 +991,33 @@ void AppendProcTexShiftOffset(std::string& out, const std::string& v, ProcTexShi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppendProcTexClamp(std::string& out, const std::string& var, ProcTexClamp mode) {
|
void AppendProcTexClamp(std::string& out, std::string_view var, ProcTexClamp mode) {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case ProcTexClamp::ToZero:
|
case ProcTexClamp::ToZero:
|
||||||
out += var + " = " + var + " > 1.0 ? 0 : " + var + ";\n";
|
out += fmt::format("{0} = {0} > 1.0 ? 0 : {0};\n", var);
|
||||||
break;
|
break;
|
||||||
case ProcTexClamp::ToEdge:
|
case ProcTexClamp::ToEdge:
|
||||||
out += var + " = " + "min(" + var + ", 1.0);\n";
|
out += fmt::format("{0} = min({0}, 1.0);\n", var);
|
||||||
break;
|
break;
|
||||||
case ProcTexClamp::SymmetricalRepeat:
|
case ProcTexClamp::SymmetricalRepeat:
|
||||||
out += var + " = " + "fract(" + var + ");\n";
|
out += fmt::format("{0} = fract({0});\n", var);
|
||||||
break;
|
break;
|
||||||
case ProcTexClamp::MirroredRepeat: {
|
case ProcTexClamp::MirroredRepeat: {
|
||||||
out +=
|
out += fmt::format("{0} = int({0}) % 2 == 0 ? fract({0}) : 1.0 - fract({0});\n", var);
|
||||||
var + " = int(" + var + ") % 2 == 0 ? fract(" + var + ") : 1.0 - fract(" + var + ");\n";
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ProcTexClamp::Pulse:
|
case ProcTexClamp::Pulse:
|
||||||
out += var + " = " + var + " > 0.5 ? 1.0 : 0.0;\n";
|
out += fmt::format("{0} = {0} > 0.5 ? 1.0 : 0.0;\n", var);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_CRITICAL(HW_GPU, "Unknown clamp mode {}", static_cast<u32>(mode));
|
LOG_CRITICAL(HW_GPU, "Unknown clamp mode {}", static_cast<u32>(mode));
|
||||||
out += var + " = " + "min(" + var + ", 1.0);\n";
|
out += fmt::format("{0} = min({0}, 1.0);\n", var);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppendProcTexCombineAndMap(std::string& out, ProcTexCombiner combiner,
|
void AppendProcTexCombineAndMap(std::string& out, ProcTexCombiner combiner,
|
||||||
const std::string& offset) {
|
std::string_view offset) {
|
||||||
std::string combined;
|
std::string combined;
|
||||||
switch (combiner) {
|
switch (combiner) {
|
||||||
case ProcTexCombiner::U:
|
case ProcTexCombiner::U:
|
||||||
|
@ -1057,7 +1055,7 @@ void AppendProcTexCombineAndMap(std::string& out, ProcTexCombiner combiner,
|
||||||
combined = "0.0";
|
combined = "0.0";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
out += "ProcTexLookupLUT(" + offset + ", " + combined + ")";
|
out += fmt::format("ProcTexLookupLUT({}, {})", offset, combined);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppendProcTexSampler(std::string& out, const PicaFSConfig& config) {
|
void AppendProcTexSampler(std::string& out, const PicaFSConfig& config) {
|
||||||
|
@ -1117,14 +1115,11 @@ float ProcTexNoiseCoef(vec2 x) {
|
||||||
}
|
}
|
||||||
|
|
||||||
out += "vec4 SampleProcTexColor(float lut_coord, int level) {\n";
|
out += "vec4 SampleProcTexColor(float lut_coord, int level) {\n";
|
||||||
out += "int lut_width = " + std::to_string(config.state.proctex.lut_width) + " >> level;\n";
|
out += fmt::format("int lut_width = {} >> level;\n", config.state.proctex.lut_width);
|
||||||
std::string offset0 = std::to_string(config.state.proctex.lut_offset0);
|
|
||||||
std::string offset1 = std::to_string(config.state.proctex.lut_offset1);
|
|
||||||
std::string offset2 = std::to_string(config.state.proctex.lut_offset2);
|
|
||||||
std::string offset3 = std::to_string(config.state.proctex.lut_offset3);
|
|
||||||
// Offsets for level 4-7 seem to be hardcoded
|
// Offsets for level 4-7 seem to be hardcoded
|
||||||
out += "int lut_offsets[8] = int[](" + offset0 + ", " + offset1 + ", " + offset2 + ", " +
|
out += fmt::format("int lut_offsets[8] = int[]({}, {}, {}, {}, 0xF0, 0xF8, 0xFC, 0xFE);\n",
|
||||||
offset3 + ", 0xF0, 0xF8, 0xFC, 0xFE);\n";
|
config.state.proctex.lut_offset0, config.state.proctex.lut_offset1,
|
||||||
|
config.state.proctex.lut_offset2, config.state.proctex.lut_offset3);
|
||||||
out += "int lut_offset = lut_offsets[level];\n";
|
out += "int lut_offset = lut_offsets[level];\n";
|
||||||
// For the color lut, coord=0.0 is lut[offset] and coord=1.0 is lut[offset+width-1]
|
// For the color lut, coord=0.0 is lut[offset] and coord=1.0 is lut[offset+width-1]
|
||||||
out += "lut_coord *= float(lut_width - 1);\n";
|
out += "lut_coord *= float(lut_width - 1);\n";
|
||||||
|
@ -1153,7 +1148,7 @@ float ProcTexNoiseCoef(vec2 x) {
|
||||||
|
|
||||||
out += "vec4 ProcTex() {\n";
|
out += "vec4 ProcTex() {\n";
|
||||||
if (config.state.proctex.coord < 3) {
|
if (config.state.proctex.coord < 3) {
|
||||||
out += "vec2 uv = abs(texcoord" + std::to_string(config.state.proctex.coord) + ");\n";
|
out += fmt::format("vec2 uv = abs(texcoord{});\n", config.state.proctex.coord);
|
||||||
} else {
|
} else {
|
||||||
LOG_CRITICAL(Render_OpenGL, "Unexpected proctex.coord >= 3");
|
LOG_CRITICAL(Render_OpenGL, "Unexpected proctex.coord >= 3");
|
||||||
out += "vec2 uv = abs(texcoord0);\n";
|
out += "vec2 uv = abs(texcoord0);\n";
|
||||||
|
@ -1165,12 +1160,12 @@ float ProcTexNoiseCoef(vec2 x) {
|
||||||
// Note: this is different from the one normal 2D textures use.
|
// Note: this is different from the one normal 2D textures use.
|
||||||
out += "vec2 duv = max(abs(dFdx(uv)), abs(dFdy(uv)));\n";
|
out += "vec2 duv = max(abs(dFdx(uv)), abs(dFdy(uv)));\n";
|
||||||
// unlike normal texture, the bias is inside the log2
|
// unlike normal texture, the bias is inside the log2
|
||||||
out += "float lod = log2(abs(float(" + std::to_string(config.state.proctex.lut_width) +
|
out += fmt::format("float lod = log2(abs(float({}) * proctex_bias) * (duv.x + duv.y));\n",
|
||||||
") * proctex_bias) * (duv.x + duv.y));\n";
|
config.state.proctex.lut_width);
|
||||||
out += "if (proctex_bias == 0.0) lod = 0.0;\n";
|
out += "if (proctex_bias == 0.0) lod = 0.0;\n";
|
||||||
out += "lod = clamp(lod, " +
|
out += fmt::format("lod = clamp(lod, {}, {});\n",
|
||||||
std::to_string(std::max<float>(0.0f, config.state.proctex.lod_min)) + ", " +
|
std::max(0.0f, static_cast<float>(config.state.proctex.lod_min)),
|
||||||
std::to_string(std::min<float>(7.0f, config.state.proctex.lod_max)) + ");\n";
|
std::min(7.0f, static_cast<float>(config.state.proctex.lod_max)));
|
||||||
// Get shift offset before noise generation
|
// Get shift offset before noise generation
|
||||||
out += "float u_shift = ";
|
out += "float u_shift = ";
|
||||||
AppendProcTexShiftOffset(out, "uv.y", config.state.proctex.u_shift,
|
AppendProcTexShiftOffset(out, "uv.y", config.state.proctex.u_shift,
|
||||||
|
@ -1183,13 +1178,13 @@ float ProcTexNoiseCoef(vec2 x) {
|
||||||
|
|
||||||
// Generate noise
|
// Generate noise
|
||||||
if (config.state.proctex.noise_enable) {
|
if (config.state.proctex.noise_enable) {
|
||||||
out += "uv += proctex_noise_a * ProcTexNoiseCoef(uv);\n";
|
out += "uv += proctex_noise_a * ProcTexNoiseCoef(uv);\n"
|
||||||
out += "uv = abs(uv);\n";
|
"uv = abs(uv);\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shift
|
// Shift
|
||||||
out += "float u = uv.x + u_shift;\n";
|
out += "float u = uv.x + u_shift;\n"
|
||||||
out += "float v = uv.y + v_shift;\n";
|
"float v = uv.y + v_shift;\n";
|
||||||
|
|
||||||
// Clamp
|
// Clamp
|
||||||
AppendProcTexClamp(out, "u", config.state.proctex.u_clamp);
|
AppendProcTexClamp(out, "u", config.state.proctex.u_clamp);
|
||||||
|
@ -1212,9 +1207,9 @@ float ProcTexNoiseCoef(vec2 x) {
|
||||||
break;
|
break;
|
||||||
case ProcTexFilter::NearestMipmapLinear:
|
case ProcTexFilter::NearestMipmapLinear:
|
||||||
case ProcTexFilter::LinearMipmapLinear:
|
case ProcTexFilter::LinearMipmapLinear:
|
||||||
out += "int lod_i = int(lod);\n";
|
out += "int lod_i = int(lod);\n"
|
||||||
out += "float lod_f = fract(lod);\n";
|
"float lod_f = fract(lod);\n"
|
||||||
out += "vec4 final_color = mix(SampleProcTexColor(lut_coord, lod_i), "
|
"vec4 final_color = mix(SampleProcTexColor(lut_coord, lod_i), "
|
||||||
"SampleProcTexColor(lut_coord, lod_i + 1), lod_f);\n";
|
"SampleProcTexColor(lut_coord, lod_i + 1), lod_f);\n";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1491,8 +1486,9 @@ vec4 secondary_fragment_color = vec4(0.0);
|
||||||
if (state.scissor_test_mode != RasterizerRegs::ScissorMode::Disabled) {
|
if (state.scissor_test_mode != RasterizerRegs::ScissorMode::Disabled) {
|
||||||
out += "if (";
|
out += "if (";
|
||||||
// Negate the condition if we have to keep only the pixels outside the scissor box
|
// Negate the condition if we have to keep only the pixels outside the scissor box
|
||||||
if (state.scissor_test_mode == RasterizerRegs::ScissorMode::Include)
|
if (state.scissor_test_mode == RasterizerRegs::ScissorMode::Include) {
|
||||||
out += "!";
|
out += '!';
|
||||||
|
}
|
||||||
out += "(gl_FragCoord.x >= float(scissor_x1) && "
|
out += "(gl_FragCoord.x >= float(scissor_x1) && "
|
||||||
"gl_FragCoord.y >= float(scissor_y1) && "
|
"gl_FragCoord.y >= float(scissor_y1) && "
|
||||||
"gl_FragCoord.x < float(scissor_x2) && "
|
"gl_FragCoord.x < float(scissor_x2) && "
|
||||||
|
@ -1502,8 +1498,8 @@ vec4 secondary_fragment_color = vec4(0.0);
|
||||||
// After perspective divide, OpenGL transform z_over_w from [-1, 1] to [near, far]. Here we use
|
// After perspective divide, OpenGL transform z_over_w from [-1, 1] to [near, far]. Here we use
|
||||||
// default near = 0 and far = 1, and undo the transformation to get the original z_over_w, then
|
// default near = 0 and far = 1, and undo the transformation to get the original z_over_w, then
|
||||||
// do our own transformation according to PICA specification.
|
// do our own transformation according to PICA specification.
|
||||||
out += "float z_over_w = 2.0 * gl_FragCoord.z - 1.0;\n";
|
out += "float z_over_w = 2.0 * gl_FragCoord.z - 1.0;\n"
|
||||||
out += "float depth = z_over_w * depth_scale + depth_offset;\n";
|
"float depth = z_over_w * depth_scale + depth_offset;\n";
|
||||||
if (state.depthmap_enable == RasterizerRegs::DepthBuffering::WBuffering) {
|
if (state.depthmap_enable == RasterizerRegs::DepthBuffering::WBuffering) {
|
||||||
out += "depth /= gl_FragCoord.w;\n";
|
out += "depth /= gl_FragCoord.w;\n";
|
||||||
}
|
}
|
||||||
|
@ -1511,12 +1507,13 @@ vec4 secondary_fragment_color = vec4(0.0);
|
||||||
if (state.lighting.enable)
|
if (state.lighting.enable)
|
||||||
WriteLighting(out, config);
|
WriteLighting(out, config);
|
||||||
|
|
||||||
out += "vec4 combiner_buffer = vec4(0.0);\n";
|
out += "vec4 combiner_buffer = vec4(0.0);\n"
|
||||||
out += "vec4 next_combiner_buffer = tev_combiner_buffer_color;\n";
|
"vec4 next_combiner_buffer = tev_combiner_buffer_color;\n"
|
||||||
out += "vec4 last_tex_env_out = vec4(0.0);\n";
|
"vec4 last_tex_env_out = vec4(0.0);\n";
|
||||||
|
|
||||||
for (std::size_t index = 0; index < state.tev_stages.size(); ++index)
|
for (std::size_t index = 0; index < state.tev_stages.size(); ++index) {
|
||||||
WriteTevStage(out, config, (unsigned)index);
|
WriteTevStage(out, config, static_cast<u32>(index));
|
||||||
|
}
|
||||||
|
|
||||||
if (state.alpha_test_func != FramebufferRegs::CompareFunc::Always) {
|
if (state.alpha_test_func != FramebufferRegs::CompareFunc::Always) {
|
||||||
out += "if (";
|
out += "if (";
|
||||||
|
@ -1534,12 +1531,12 @@ vec4 secondary_fragment_color = vec4(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate clamped fog factor from LUT for given fog index
|
// Generate clamped fog factor from LUT for given fog index
|
||||||
out += "float fog_i = clamp(floor(fog_index), 0.0, 127.0);\n";
|
out += "float fog_i = clamp(floor(fog_index), 0.0, 127.0);\n"
|
||||||
out += "float fog_f = fog_index - fog_i;\n";
|
"float fog_f = fog_index - fog_i;\n"
|
||||||
out += "vec2 fog_lut_entry = texelFetch(texture_buffer_lut_rg, int(fog_i) + "
|
"vec2 fog_lut_entry = texelFetch(texture_buffer_lut_rg, int(fog_i) + "
|
||||||
"fog_lut_offset).rg;\n";
|
"fog_lut_offset).rg;\n"
|
||||||
out += "float fog_factor = fog_lut_entry.r + fog_lut_entry.g * fog_f;\n";
|
"float fog_factor = fog_lut_entry.r + fog_lut_entry.g * fog_f;\n"
|
||||||
out += "fog_factor = clamp(fog_factor, 0.0, 1.0);\n";
|
"fog_factor = clamp(fog_factor, 0.0, 1.0);\n";
|
||||||
|
|
||||||
// Blend the fog
|
// Blend the fog
|
||||||
out += "last_tex_env_out.rgb = mix(fog_color.rgb, last_tex_env_out.rgb, fog_factor);\n";
|
out += "last_tex_env_out.rgb = mix(fog_color.rgb, last_tex_env_out.rgb, fog_factor);\n";
|
||||||
|
@ -1584,31 +1581,33 @@ do {
|
||||||
out += "color = byteround(last_tex_env_out);\n";
|
out += "color = byteround(last_tex_env_out);\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
out += "}";
|
out += '}';
|
||||||
|
|
||||||
return {out};
|
return {out};
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderDecompiler::ProgramResult GenerateTrivialVertexShader(bool separable_shader) {
|
ShaderDecompiler::ProgramResult GenerateTrivialVertexShader(bool separable_shader) {
|
||||||
std::string out = "";
|
std::string out;
|
||||||
if (separable_shader) {
|
if (separable_shader) {
|
||||||
out += "#extension GL_ARB_separate_shader_objects : enable\n";
|
out += "#extension GL_ARB_separate_shader_objects : enable\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) +
|
out += fmt::format("layout(location = {}) in vec4 vert_position;\n",
|
||||||
") in vec4 vert_position;\n";
|
static_cast<int>(ATTRIBUTE_POSITION));
|
||||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n";
|
out += fmt::format("layout(location = {}) in vec4 vert_color;\n",
|
||||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) +
|
static_cast<int>(ATTRIBUTE_COLOR));
|
||||||
") in vec2 vert_texcoord0;\n";
|
out += fmt::format("layout(location = {}) in vec2 vert_texcoord0;\n",
|
||||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) +
|
static_cast<int>(ATTRIBUTE_TEXCOORD0));
|
||||||
") in vec2 vert_texcoord1;\n";
|
out += fmt::format("layout(location = {}) in vec2 vert_texcoord1;\n",
|
||||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) +
|
static_cast<int>(ATTRIBUTE_TEXCOORD1));
|
||||||
") in vec2 vert_texcoord2;\n";
|
out += fmt::format("layout(location = {}) in vec2 vert_texcoord2;\n",
|
||||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0_W) +
|
static_cast<int>(ATTRIBUTE_TEXCOORD2));
|
||||||
") in float vert_texcoord0_w;\n";
|
out += fmt::format("layout(location = {}) in float vert_texcoord0_w;\n",
|
||||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_NORMQUAT) +
|
static_cast<int>(ATTRIBUTE_TEXCOORD0_W));
|
||||||
") in vec4 vert_normquat;\n";
|
out += fmt::format("layout(location = {}) in vec4 vert_normquat;\n",
|
||||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_VIEW) + ") in vec3 vert_view;\n";
|
static_cast<int>(ATTRIBUTE_NORMQUAT));
|
||||||
|
out +=
|
||||||
|
fmt::format("layout(location = {}) in vec3 vert_view;\n", static_cast<int>(ATTRIBUTE_VIEW));
|
||||||
|
|
||||||
out += GetVertexInterfaceDeclaration(true, separable_shader);
|
out += GetVertexInterfaceDeclaration(true, separable_shader);
|
||||||
|
|
||||||
|
@ -1645,16 +1644,16 @@ std::optional<ShaderDecompiler::ProgramResult> GenerateVertexShader(
|
||||||
out += ShaderDecompiler::GetCommonDeclarations();
|
out += ShaderDecompiler::GetCommonDeclarations();
|
||||||
|
|
||||||
std::array<bool, 16> used_regs{};
|
std::array<bool, 16> used_regs{};
|
||||||
auto get_input_reg = [&](u32 reg) -> std::string {
|
const auto get_input_reg = [&used_regs](u32 reg) {
|
||||||
ASSERT(reg < 16);
|
ASSERT(reg < 16);
|
||||||
used_regs[reg] = true;
|
used_regs[reg] = true;
|
||||||
return "vs_in_reg" + std::to_string(reg);
|
return fmt::format("vs_in_reg{}", reg);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto get_output_reg = [&](u32 reg) -> std::string {
|
const auto get_output_reg = [&](u32 reg) -> std::string {
|
||||||
ASSERT(reg < 16);
|
ASSERT(reg < 16);
|
||||||
if (config.state.output_map[reg] < config.state.num_outputs) {
|
if (config.state.output_map[reg] < config.state.num_outputs) {
|
||||||
return "vs_out_attr" + std::to_string(config.state.output_map[reg]);
|
return fmt::format("vs_out_attr{}", config.state.output_map[reg]);
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
|
@ -1678,11 +1677,10 @@ layout (std140) uniform vs_config {
|
||||||
// input attributes declaration
|
// input attributes declaration
|
||||||
for (std::size_t i = 0; i < used_regs.size(); ++i) {
|
for (std::size_t i = 0; i < used_regs.size(); ++i) {
|
||||||
if (used_regs[i]) {
|
if (used_regs[i]) {
|
||||||
out += "layout(location = " + std::to_string(i) + ") in vec4 vs_in_reg" +
|
out += fmt::format("layout(location = {0}) in vec4 vs_in_reg{0};\n", i);
|
||||||
std::to_string(i) + ";\n";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out += "\n";
|
out += '\n';
|
||||||
|
|
||||||
// output attributes declaration
|
// output attributes declaration
|
||||||
for (u32 i = 0; i < config.state.num_outputs; ++i) {
|
for (u32 i = 0; i < config.state.num_outputs; ++i) {
|
||||||
|
@ -1692,7 +1690,7 @@ layout (std140) uniform vs_config {
|
||||||
|
|
||||||
out += "\nvoid main() {\n";
|
out += "\nvoid main() {\n";
|
||||||
for (u32 i = 0; i < config.state.num_outputs; ++i) {
|
for (u32 i = 0; i < config.state.num_outputs; ++i) {
|
||||||
out += " vs_out_attr" + std::to_string(i) + " = vec4(0.0, 0.0, 0.0, 1.0);\n";
|
out += fmt::format(" vs_out_attr{} = vec4(0.0, 0.0, 0.0, 1.0);\n", i);
|
||||||
}
|
}
|
||||||
out += "\n exec_shader();\n}\n\n";
|
out += "\n exec_shader();\n}\n\n";
|
||||||
|
|
||||||
|
@ -1715,15 +1713,15 @@ static std::string GetGSCommonSource(const PicaGSConfigCommonRaw& config, bool s
|
||||||
out += R"(
|
out += R"(
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
)";
|
)";
|
||||||
out += " vec4 attributes[" + std::to_string(config.gs_output_attributes) + "];\n";
|
out += fmt::format(" vec4 attributes[{}];\n", config.gs_output_attributes);
|
||||||
out += "};\n\n";
|
out += "};\n\n";
|
||||||
|
|
||||||
auto semantic = [&config](VSOutputAttributes::Semantic slot_semantic) -> std::string {
|
const auto semantic = [&config](VSOutputAttributes::Semantic slot_semantic) -> std::string {
|
||||||
u32 slot = static_cast<u32>(slot_semantic);
|
const u32 slot = static_cast<u32>(slot_semantic);
|
||||||
u32 attrib = config.semantic_maps[slot].attribute_index;
|
const u32 attrib = config.semantic_maps[slot].attribute_index;
|
||||||
u32 comp = config.semantic_maps[slot].component_index;
|
const u32 comp = config.semantic_maps[slot].component_index;
|
||||||
if (attrib < config.gs_output_attributes) {
|
if (attrib < config.gs_output_attributes) {
|
||||||
return "vtx.attributes[" + std::to_string(attrib) + "]." + "xyzw"[comp];
|
return fmt::format("vtx.attributes[{}].{}", attrib, "xyzw"[comp]);
|
||||||
}
|
}
|
||||||
return "0.0";
|
return "0.0";
|
||||||
};
|
};
|
||||||
|
@ -1806,11 +1804,10 @@ void main() {
|
||||||
Vertex prim_buffer[3];
|
Vertex prim_buffer[3];
|
||||||
)";
|
)";
|
||||||
for (u32 vtx = 0; vtx < 3; ++vtx) {
|
for (u32 vtx = 0; vtx < 3; ++vtx) {
|
||||||
out += " prim_buffer[" + std::to_string(vtx) + "].attributes = vec4[" +
|
out += fmt::format(" prim_buffer[{}].attributes = vec4[{}](", vtx,
|
||||||
std::to_string(config.state.gs_output_attributes) + "](";
|
config.state.gs_output_attributes);
|
||||||
for (u32 i = 0; i < config.state.vs_output_attributes; ++i) {
|
for (u32 i = 0; i < config.state.vs_output_attributes; ++i) {
|
||||||
out += std::string(i == 0 ? "" : ", ") + "vs_out_attr" + std::to_string(i) + "[" +
|
out += fmt::format("{}vs_out_attr{}[{}]", i == 0 ? "" : ", ", i, vtx);
|
||||||
std::to_string(vtx) + "]";
|
|
||||||
}
|
}
|
||||||
out += ");\n";
|
out += ");\n";
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue