mirror of
https://git.h3cjp.net/H3cJP/citra.git
synced 2024-12-27 13:46:54 +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
|
@ -4,8 +4,8 @@
|
|||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <string_view>
|
||||
#include <fmt/format.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/bit_field.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) {
|
||||
std::string out;
|
||||
|
||||
auto append_variable = [&](const char* var, int location) {
|
||||
const auto append_variable = [&](std::string_view var, int location) {
|
||||
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);
|
||||
|
@ -267,11 +267,12 @@ void PicaGSConfigCommonRaw::Init(const Pica::Regs& regs) {
|
|||
|
||||
semantic_maps.fill({16, 0});
|
||||
for (u32 attrib = 0; attrib < regs.rasterizer.vs_output_total; ++attrib) {
|
||||
std::array<VSOutputAttributes::Semantic, 4> semantics = {
|
||||
regs.rasterizer.vs_output_attributes[attrib].map_x,
|
||||
regs.rasterizer.vs_output_attributes[attrib].map_y,
|
||||
regs.rasterizer.vs_output_attributes[attrib].map_z,
|
||||
regs.rasterizer.vs_output_attributes[attrib].map_w};
|
||||
const std::array semantics{
|
||||
regs.rasterizer.vs_output_attributes[attrib].map_x.Value(),
|
||||
regs.rasterizer.vs_output_attributes[attrib].map_y.Value(),
|
||||
regs.rasterizer.vs_output_attributes[attrib].map_z.Value(),
|
||||
regs.rasterizer.vs_output_attributes[attrib].map_w.Value(),
|
||||
};
|
||||
for (u32 comp = 0; comp < 4; ++comp) {
|
||||
const auto semantic = semantics[comp];
|
||||
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)
|
||||
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;
|
||||
switch (source) {
|
||||
case Source::PrimaryColor:
|
||||
|
@ -370,7 +371,9 @@ static void AppendSource(std::string& out, const PicaFSConfig& config,
|
|||
out += "combiner_buffer";
|
||||
break;
|
||||
case Source::Constant:
|
||||
((out += "const_color[") += index_name) += ']';
|
||||
out += "const_color[";
|
||||
out += index_name;
|
||||
out += ']';
|
||||
break;
|
||||
case Source::Previous:
|
||||
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
|
||||
static void AppendColorModifier(std::string& out, const PicaFSConfig& config,
|
||||
TevStageConfig::ColorModifier modifier,
|
||||
TevStageConfig::Source source, const std::string& index_name) {
|
||||
TevStageConfig::Source source, std::string_view index_name) {
|
||||
using ColorModifier = TevStageConfig::ColorModifier;
|
||||
switch (modifier) {
|
||||
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
|
||||
static void AppendColorCombiner(std::string& out, TevStageConfig::Operation operation,
|
||||
const std::string& variable_name) {
|
||||
std::string_view variable_name) {
|
||||
out += "clamp(";
|
||||
using Operation = TevStageConfig::Operation;
|
||||
switch (operation) {
|
||||
case Operation::Replace:
|
||||
out += variable_name + "[0]";
|
||||
out += fmt::format("{}[0]", variable_name);
|
||||
break;
|
||||
case Operation::Modulate:
|
||||
out += variable_name + "[0] * " + variable_name + "[1]";
|
||||
out += fmt::format("{0}[0] * {0}[1]", variable_name);
|
||||
break;
|
||||
case Operation::Add:
|
||||
out += variable_name + "[0] + " + variable_name + "[1]";
|
||||
out += fmt::format("{0}[0] + {0}[1]", variable_name);
|
||||
break;
|
||||
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;
|
||||
case Operation::Lerp:
|
||||
out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name +
|
||||
"[1] * (vec3(1.0) - " + variable_name + "[2])";
|
||||
out += fmt::format("{0}[0] * {0}[2] + {0}[1] * (vec3(1.0) - {0}[2])", variable_name);
|
||||
break;
|
||||
case Operation::Subtract:
|
||||
out += variable_name + "[0] - " + variable_name + "[1]";
|
||||
out += fmt::format("{0}[0] - {0}[1]", variable_name);
|
||||
break;
|
||||
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;
|
||||
case Operation::AddThenMultiply:
|
||||
out += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " +
|
||||
variable_name + "[2]";
|
||||
out += fmt::format("min({0}[0] + {0}[1], vec3(1.0)) * {0}[2]", variable_name);
|
||||
break;
|
||||
case Operation::Dot3_RGB:
|
||||
case Operation::Dot3_RGBA:
|
||||
out += "vec3(dot(" + variable_name + "[0] - vec3(0.5), " + variable_name +
|
||||
"[1] - vec3(0.5)) * 4.0)";
|
||||
out +=
|
||||
fmt::format("vec3(dot({0}[0] - vec3(0.5), {0}[1] - vec3(0.5)) * 4.0)", variable_name);
|
||||
break;
|
||||
default:
|
||||
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
|
||||
static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation operation,
|
||||
const std::string& variable_name) {
|
||||
std::string_view variable_name) {
|
||||
out += "clamp(";
|
||||
using Operation = TevStageConfig::Operation;
|
||||
switch (operation) {
|
||||
case Operation::Replace:
|
||||
out += variable_name + "[0]";
|
||||
out += fmt::format("{}[0]", variable_name);
|
||||
break;
|
||||
case Operation::Modulate:
|
||||
out += variable_name + "[0] * " + variable_name + "[1]";
|
||||
out += fmt::format("{0}[0] * {0}[1]", variable_name);
|
||||
break;
|
||||
case Operation::Add:
|
||||
out += variable_name + "[0] + " + variable_name + "[1]";
|
||||
out += fmt::format("{0}[0] + {0}[1]", variable_name);
|
||||
break;
|
||||
case Operation::AddSigned:
|
||||
out += variable_name + "[0] + " + variable_name + "[1] - 0.5";
|
||||
out += fmt::format("{0}[0] + {0}[1] - 0.5", variable_name);
|
||||
break;
|
||||
case Operation::Lerp:
|
||||
out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name +
|
||||
"[1] * (1.0 - " + variable_name + "[2])";
|
||||
out += fmt::format("{0}[0] * {0}[2] + {0}[1] * (1.0 - {0}[2])", variable_name);
|
||||
break;
|
||||
case Operation::Subtract:
|
||||
out += variable_name + "[0] - " + variable_name + "[1]";
|
||||
out += fmt::format("{0}[0] - {0}[1]", variable_name);
|
||||
break;
|
||||
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;
|
||||
case Operation::AddThenMultiply:
|
||||
out += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name +
|
||||
"[2]";
|
||||
out += fmt::format("min({0}[0] + {0}[1], 1.0) * {0}[2]", variable_name);
|
||||
break;
|
||||
default:
|
||||
out += "0.0";
|
||||
|
@ -592,9 +591,9 @@ static void AppendAlphaTestCondition(std::string& out, FramebufferRegs::CompareF
|
|||
case CompareFunc::LessThanOrEqual:
|
||||
case CompareFunc::GreaterThan:
|
||||
case CompareFunc::GreaterThanOrEqual: {
|
||||
static const char* op[] = {"!=", "==", ">=", ">", "<=", "<"};
|
||||
unsigned index = (unsigned)func - (unsigned)CompareFunc::Equal;
|
||||
out += "int(last_tex_env_out.a * 255.0) " + std::string(op[index]) + " alphatest_ref";
|
||||
static constexpr std::array op{"!=", "==", ">=", ">", "<=", "<"};
|
||||
const auto index = static_cast<u32>(func) - static_cast<u32>(CompareFunc::Equal);
|
||||
out += fmt::format("int(last_tex_env_out.a * 255.0) {} alphatest_ref", op[index]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -610,9 +609,9 @@ static void WriteTevStage(std::string& out, const PicaFSConfig& config, unsigned
|
|||
const auto stage =
|
||||
static_cast<const TexturingRegs::TevStageConfig>(config.state.tev_stages[index]);
|
||||
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);
|
||||
out += ", ";
|
||||
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";
|
||||
|
||||
// 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);
|
||||
out += ");\n";
|
||||
|
||||
if (stage.color_op == TevStageConfig::Operation::Dot3_RGBA) {
|
||||
// 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 {
|
||||
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,
|
||||
index_name);
|
||||
out += ", ";
|
||||
|
@ -640,18 +639,16 @@ static void WriteTevStage(std::string& out, const PicaFSConfig& config, unsigned
|
|||
index_name);
|
||||
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);
|
||||
out += ");\n";
|
||||
}
|
||||
|
||||
out += "last_tex_env_out = vec4("
|
||||
"clamp(color_output_" +
|
||||
index_name + " * " + std::to_string(stage.GetColorMultiplier()) +
|
||||
".0, vec3(0.0), vec3(1.0)),"
|
||||
"clamp(alpha_output_" +
|
||||
index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) +
|
||||
".0, 0.0, 1.0));\n";
|
||||
out += fmt::format("last_tex_env_out = vec4("
|
||||
"clamp(color_output_{} * {}.0, vec3(0.0), vec3(1.0)), "
|
||||
"clamp(alpha_output_{} * {}.0, 0.0, 1.0));\n",
|
||||
index_name, stage.GetColorMultiplier(), index_name,
|
||||
stage.GetAlphaMultiplier());
|
||||
}
|
||||
|
||||
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";
|
||||
|
||||
// Compute fragment normals and tangents
|
||||
auto Perturbation = [&]() {
|
||||
return "2.0 * (" + SampleTexture(config, lighting.bump_selector) + ").rgb - 1.0";
|
||||
const auto Perturbation = [&] {
|
||||
return fmt::format("2.0 * ({}).rgb - 1.0", SampleTexture(config, lighting.bump_selector));
|
||||
};
|
||||
if (lighting.bump_mode == LightingRegs::LightingBumpMode::NormalMap) {
|
||||
// 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
|
||||
// precision result
|
||||
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))";
|
||||
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.
|
||||
out += "vec3 surface_tangent = vec3(1.0, 0.0, 0.0);\n";
|
||||
} else if (lighting.bump_mode == LightingRegs::LightingBumpMode::TangentMap) {
|
||||
// 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
|
||||
// computation below, which is also confirmed on 3DS. So we don't bother recomputing here
|
||||
// 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";
|
||||
} else {
|
||||
// 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_tangent = vec3(1.0, 0.0, 0.0);\n";
|
||||
out += "vec3 surface_normal = vec3(0.0, 0.0, 1.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
|
||||
// eyespace.
|
||||
out += "vec4 normalized_normquat = normalize(normquat);\n";
|
||||
out += "vec3 normal = quaternion_rotate(normalized_normquat, surface_normal);\n";
|
||||
out += "vec3 tangent = quaternion_rotate(normalized_normquat, surface_tangent);\n";
|
||||
out += "vec4 normalized_normquat = normalize(normquat);\n"
|
||||
"vec3 normal = quaternion_rotate(normalized_normquat, surface_normal);\n"
|
||||
"vec3 tangent = quaternion_rotate(normalized_normquat, surface_tangent);\n";
|
||||
|
||||
if (lighting.enable_shadow) {
|
||||
std::string shadow_texture = SampleTexture(config, lighting.shadow_selector);
|
||||
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 {
|
||||
out += "vec4 shadow = " + shadow_texture + ";\n";
|
||||
out += fmt::format("vec4 shadow = {};\n", shadow_texture);
|
||||
}
|
||||
} else {
|
||||
out += "vec4 shadow = vec4(1.0);\n";
|
||||
|
@ -738,19 +735,19 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
|||
break;
|
||||
|
||||
case LightingRegs::LightingLutInput::VH:
|
||||
index = std::string("dot(normalize(view), normalize(half_vector))");
|
||||
index = "dot(normalize(view), normalize(half_vector))";
|
||||
break;
|
||||
|
||||
case LightingRegs::LightingLutInput::NV:
|
||||
index = std::string("dot(normal, normalize(view))");
|
||||
index = "dot(normal, normalize(view))";
|
||||
break;
|
||||
|
||||
case LightingRegs::LightingLutInput::LN:
|
||||
index = std::string("dot(light_vector, normal)");
|
||||
index = "dot(light_vector, normal)";
|
||||
break;
|
||||
|
||||
case LightingRegs::LightingLutInput::SP:
|
||||
index = std::string("dot(light_vector, spot_dir)");
|
||||
index = "dot(light_vector, spot_dir)";
|
||||
break;
|
||||
|
||||
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
|
||||
// normal of the tangent plane anymore, the half angle vector is still projected
|
||||
// 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))";
|
||||
// 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.
|
||||
index = "dot(" + half_angle_proj + ", tangent)";
|
||||
index = fmt::format("dot({}, tangent)", half_angle_proj);
|
||||
} else {
|
||||
index = "0.0";
|
||||
}
|
||||
|
@ -776,31 +773,33 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
|||
break;
|
||||
}
|
||||
|
||||
std::string sampler_string = std::to_string(static_cast<unsigned>(sampler));
|
||||
const auto sampler_index = static_cast<u32>(sampler);
|
||||
|
||||
if (abs) {
|
||||
// LUT index is in the range of (0.0, 1.0)
|
||||
index = lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")"
|
||||
: "max(" + index + ", 0.0)";
|
||||
return "LookupLightingLUTUnsigned(" + sampler_string + ", " + index + ")";
|
||||
index = lighting.light[light_num].two_sided_diffuse
|
||||
? fmt::format("abs({})", index)
|
||||
: fmt::format("max({}, 0.0)", index);
|
||||
return fmt::format("LookupLightingLUTUnsigned({}, {})", sampler_index, index);
|
||||
} else {
|
||||
// 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
|
||||
for (unsigned light_index = 0; light_index < lighting.src_num; ++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)
|
||||
if (light_config.directional)
|
||||
out += "light_vector = normalize(" + light_src + ".position);\n";
|
||||
else
|
||||
out += "light_vector = normalize(" + light_src + ".position + view);\n";
|
||||
if (light_config.directional) {
|
||||
out += fmt::format("light_vector = normalize({}.position);\n", light_src);
|
||||
} else {
|
||||
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";
|
||||
|
||||
// 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 &&
|
||||
LightingRegs::IsLightingSamplerSupported(
|
||||
lighting.config, LightingRegs::LightingSampler::SpotlightAttenuation)) {
|
||||
std::string value =
|
||||
const std::string value =
|
||||
GetLutValue(LightingRegs::SpotlightAttenuationSampler(light_config.num),
|
||||
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
|
||||
std::string dist_atten = "1.0";
|
||||
if (light_config.dist_atten_enable) {
|
||||
std::string index = "clamp(" + light_src + ".dist_atten_scale * length(-view - " +
|
||||
light_src + ".position) + " + light_src +
|
||||
".dist_atten_bias, 0.0, 1.0)";
|
||||
auto sampler = LightingRegs::DistanceAttenuationSampler(light_config.num);
|
||||
dist_atten = "LookupLightingLUTUnsigned(" +
|
||||
std::to_string(static_cast<unsigned>(sampler)) + "," + index + ")";
|
||||
const std::string index = fmt::format("clamp({}.dist_atten_scale * length(-view - "
|
||||
"{}.position) + {}.dist_atten_bias, 0.0, 1.0)",
|
||||
light_src, light_src, light_src);
|
||||
const auto sampler = LightingRegs::DistanceAttenuationSampler(light_config.num);
|
||||
dist_atten =
|
||||
fmt::format("LookupLightingLUTUnsigned({}, {})", static_cast<u32>(sampler), index);
|
||||
}
|
||||
|
||||
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(
|
||||
lighting.config, LightingRegs::LightingSampler::Distribution0)) {
|
||||
// Lookup specular "distribution 0" LUT value
|
||||
std::string value =
|
||||
const std::string value =
|
||||
GetLutValue(LightingRegs::LightingSampler::Distribution0, light_config.num,
|
||||
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) {
|
||||
specular_0 = "(" + specular_0 + " * geo_factor)";
|
||||
specular_0 = fmt::format("({} * geo_factor)", specular_0);
|
||||
}
|
||||
|
||||
// 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 =
|
||||
GetLutValue(LightingRegs::LightingSampler::ReflectRed, light_config.num,
|
||||
lighting.lut_rr.type, lighting.lut_rr.abs_input);
|
||||
value = "(" + std::to_string(lighting.lut_rr.scale) + " * " + value + ")";
|
||||
out += "refl_value.r = " + value + ";\n";
|
||||
value = fmt::format("({} * {})", lighting.lut_rr.scale, value);
|
||||
out += fmt::format("refl_value.r = {};\n", value);
|
||||
} else {
|
||||
out += "refl_value.r = 1.0;\n";
|
||||
}
|
||||
|
@ -878,8 +877,8 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
|||
std::string value =
|
||||
GetLutValue(LightingRegs::LightingSampler::ReflectGreen, light_config.num,
|
||||
lighting.lut_rg.type, lighting.lut_rg.abs_input);
|
||||
value = "(" + std::to_string(lighting.lut_rg.scale) + " * " + value + ")";
|
||||
out += "refl_value.g = " + value + ";\n";
|
||||
value = fmt::format("({} * {})", lighting.lut_rg.scale, value);
|
||||
out += fmt::format("refl_value.g = {};\n", value);
|
||||
} else {
|
||||
out += "refl_value.g = refl_value.r;\n";
|
||||
}
|
||||
|
@ -891,8 +890,8 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
|||
std::string value =
|
||||
GetLutValue(LightingRegs::LightingSampler::ReflectBlue, light_config.num,
|
||||
lighting.lut_rb.type, lighting.lut_rb.abs_input);
|
||||
value = "(" + std::to_string(lighting.lut_rb.scale) + " * " + value + ")";
|
||||
out += "refl_value.b = " + value + ";\n";
|
||||
value = fmt::format("({} * {})", lighting.lut_rb.scale, value);
|
||||
out += fmt::format("refl_value.b = {};\n", value);
|
||||
} else {
|
||||
out += "refl_value.b = refl_value.r;\n";
|
||||
}
|
||||
|
@ -903,15 +902,15 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
|||
LightingRegs::IsLightingSamplerSupported(
|
||||
lighting.config, LightingRegs::LightingSampler::Distribution1)) {
|
||||
// Lookup specular "distribution 1" LUT value
|
||||
std::string value =
|
||||
const std::string value =
|
||||
GetLutValue(LightingRegs::LightingSampler::Distribution1, light_config.num,
|
||||
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 =
|
||||
"(" + 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) {
|
||||
specular_1 = "(" + specular_1 + " * geo_factor)";
|
||||
specular_1 = fmt::format("({} * geo_factor)", specular_1);
|
||||
}
|
||||
|
||||
// Fresnel
|
||||
|
@ -923,16 +922,16 @@ static void WriteLighting(std::string& out, const PicaFSConfig& config) {
|
|||
std::string value =
|
||||
GetLutValue(LightingRegs::LightingSampler::Fresnel, light_config.num,
|
||||
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
|
||||
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
|
||||
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" : "";
|
||||
|
||||
// Compute primary fragment color (diffuse lighting) function
|
||||
out += "diffuse_sum.rgb += ((" + light_src + ".diffuse * dot_product) + " + light_src +
|
||||
".ambient) * " + dist_atten + " * " + spot_atten + shadow_primary + ";\n";
|
||||
out += fmt::format(
|
||||
"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
|
||||
out += "specular_sum.rgb += (" + specular_0 + " + " + specular_1 +
|
||||
") * clamp_highlights * " + dist_atten + " * " + spot_atten + shadow_secondary +
|
||||
";\n";
|
||||
out += fmt::format("specular_sum.rgb += ({} + {}) * clamp_highlights * {} * {}{};\n",
|
||||
specular_0, specular_1, dist_atten, spot_atten, shadow_secondary);
|
||||
}
|
||||
|
||||
// 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
|
||||
out += "diffuse_sum.rgb += lighting_global_ambient;\n";
|
||||
out += "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";
|
||||
out += "diffuse_sum.rgb += lighting_global_ambient;\n"
|
||||
"primary_fragment_color = clamp(diffuse_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;
|
||||
|
@ -972,18 +971,18 @@ using ProcTexShift = TexturingRegs::ProcTexShift;
|
|||
using ProcTexCombiner = TexturingRegs::ProcTexCombiner;
|
||||
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) {
|
||||
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) {
|
||||
case ProcTexShift::None:
|
||||
out += "0.0";
|
||||
break;
|
||||
case ProcTexShift::Odd:
|
||||
out += offset + " * float((int(" + v + ") / 2) % 2)";
|
||||
out += fmt::format("{} * float((int({}) / 2) % 2)", offset, v);
|
||||
break;
|
||||
case ProcTexShift::Even:
|
||||
out += offset + " * float(((int(" + v + ") + 1) / 2) % 2)";
|
||||
out += fmt::format("{} * float(((int({}) + 1) / 2) % 2)", offset, v);
|
||||
break;
|
||||
default:
|
||||
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) {
|
||||
case ProcTexClamp::ToZero:
|
||||
out += var + " = " + var + " > 1.0 ? 0 : " + var + ";\n";
|
||||
out += fmt::format("{0} = {0} > 1.0 ? 0 : {0};\n", var);
|
||||
break;
|
||||
case ProcTexClamp::ToEdge:
|
||||
out += var + " = " + "min(" + var + ", 1.0);\n";
|
||||
out += fmt::format("{0} = min({0}, 1.0);\n", var);
|
||||
break;
|
||||
case ProcTexClamp::SymmetricalRepeat:
|
||||
out += var + " = " + "fract(" + var + ");\n";
|
||||
out += fmt::format("{0} = fract({0});\n", var);
|
||||
break;
|
||||
case ProcTexClamp::MirroredRepeat: {
|
||||
out +=
|
||||
var + " = int(" + var + ") % 2 == 0 ? fract(" + var + ") : 1.0 - fract(" + var + ");\n";
|
||||
out += fmt::format("{0} = int({0}) % 2 == 0 ? fract({0}) : 1.0 - fract({0});\n", var);
|
||||
break;
|
||||
}
|
||||
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;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void AppendProcTexCombineAndMap(std::string& out, ProcTexCombiner combiner,
|
||||
const std::string& offset) {
|
||||
std::string_view offset) {
|
||||
std::string combined;
|
||||
switch (combiner) {
|
||||
case ProcTexCombiner::U:
|
||||
|
@ -1057,7 +1055,7 @@ void AppendProcTexCombineAndMap(std::string& out, ProcTexCombiner combiner,
|
|||
combined = "0.0";
|
||||
break;
|
||||
}
|
||||
out += "ProcTexLookupLUT(" + offset + ", " + combined + ")";
|
||||
out += fmt::format("ProcTexLookupLUT({}, {})", offset, combined);
|
||||
}
|
||||
|
||||
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 += "int lut_width = " + std::to_string(config.state.proctex.lut_width) + " >> level;\n";
|
||||
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);
|
||||
out += fmt::format("int lut_width = {} >> level;\n", config.state.proctex.lut_width);
|
||||
// Offsets for level 4-7 seem to be hardcoded
|
||||
out += "int lut_offsets[8] = int[](" + offset0 + ", " + offset1 + ", " + offset2 + ", " +
|
||||
offset3 + ", 0xF0, 0xF8, 0xFC, 0xFE);\n";
|
||||
out += fmt::format("int lut_offsets[8] = int[]({}, {}, {}, {}, 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";
|
||||
// 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";
|
||||
|
@ -1153,7 +1148,7 @@ float ProcTexNoiseCoef(vec2 x) {
|
|||
|
||||
out += "vec4 ProcTex() {\n";
|
||||
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 {
|
||||
LOG_CRITICAL(Render_OpenGL, "Unexpected proctex.coord >= 3");
|
||||
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.
|
||||
out += "vec2 duv = max(abs(dFdx(uv)), abs(dFdy(uv)));\n";
|
||||
// unlike normal texture, the bias is inside the log2
|
||||
out += "float lod = log2(abs(float(" + std::to_string(config.state.proctex.lut_width) +
|
||||
") * proctex_bias) * (duv.x + duv.y));\n";
|
||||
out += fmt::format("float lod = log2(abs(float({}) * proctex_bias) * (duv.x + duv.y));\n",
|
||||
config.state.proctex.lut_width);
|
||||
out += "if (proctex_bias == 0.0) lod = 0.0;\n";
|
||||
out += "lod = clamp(lod, " +
|
||||
std::to_string(std::max<float>(0.0f, config.state.proctex.lod_min)) + ", " +
|
||||
std::to_string(std::min<float>(7.0f, config.state.proctex.lod_max)) + ");\n";
|
||||
out += fmt::format("lod = clamp(lod, {}, {});\n",
|
||||
std::max(0.0f, static_cast<float>(config.state.proctex.lod_min)),
|
||||
std::min(7.0f, static_cast<float>(config.state.proctex.lod_max)));
|
||||
// Get shift offset before noise generation
|
||||
out += "float u_shift = ";
|
||||
AppendProcTexShiftOffset(out, "uv.y", config.state.proctex.u_shift,
|
||||
|
@ -1183,13 +1178,13 @@ float ProcTexNoiseCoef(vec2 x) {
|
|||
|
||||
// Generate noise
|
||||
if (config.state.proctex.noise_enable) {
|
||||
out += "uv += proctex_noise_a * ProcTexNoiseCoef(uv);\n";
|
||||
out += "uv = abs(uv);\n";
|
||||
out += "uv += proctex_noise_a * ProcTexNoiseCoef(uv);\n"
|
||||
"uv = abs(uv);\n";
|
||||
}
|
||||
|
||||
// Shift
|
||||
out += "float u = uv.x + u_shift;\n";
|
||||
out += "float v = uv.y + v_shift;\n";
|
||||
out += "float u = uv.x + u_shift;\n"
|
||||
"float v = uv.y + v_shift;\n";
|
||||
|
||||
// Clamp
|
||||
AppendProcTexClamp(out, "u", config.state.proctex.u_clamp);
|
||||
|
@ -1212,9 +1207,9 @@ float ProcTexNoiseCoef(vec2 x) {
|
|||
break;
|
||||
case ProcTexFilter::NearestMipmapLinear:
|
||||
case ProcTexFilter::LinearMipmapLinear:
|
||||
out += "int lod_i = int(lod);\n";
|
||||
out += "float lod_f = fract(lod);\n";
|
||||
out += "vec4 final_color = mix(SampleProcTexColor(lut_coord, lod_i), "
|
||||
out += "int lod_i = int(lod);\n"
|
||||
"float lod_f = fract(lod);\n"
|
||||
"vec4 final_color = mix(SampleProcTexColor(lut_coord, lod_i), "
|
||||
"SampleProcTexColor(lut_coord, lod_i + 1), lod_f);\n";
|
||||
break;
|
||||
}
|
||||
|
@ -1491,8 +1486,9 @@ vec4 secondary_fragment_color = vec4(0.0);
|
|||
if (state.scissor_test_mode != RasterizerRegs::ScissorMode::Disabled) {
|
||||
out += "if (";
|
||||
// Negate the condition if we have to keep only the pixels outside the scissor box
|
||||
if (state.scissor_test_mode == RasterizerRegs::ScissorMode::Include)
|
||||
out += "!";
|
||||
if (state.scissor_test_mode == RasterizerRegs::ScissorMode::Include) {
|
||||
out += '!';
|
||||
}
|
||||
out += "(gl_FragCoord.x >= float(scissor_x1) && "
|
||||
"gl_FragCoord.y >= float(scissor_y1) && "
|
||||
"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
|
||||
// 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.
|
||||
out += "float z_over_w = 2.0 * gl_FragCoord.z - 1.0;\n";
|
||||
out += "float depth = z_over_w * depth_scale + depth_offset;\n";
|
||||
out += "float z_over_w = 2.0 * gl_FragCoord.z - 1.0;\n"
|
||||
"float depth = z_over_w * depth_scale + depth_offset;\n";
|
||||
if (state.depthmap_enable == RasterizerRegs::DepthBuffering::WBuffering) {
|
||||
out += "depth /= gl_FragCoord.w;\n";
|
||||
}
|
||||
|
@ -1511,12 +1507,13 @@ vec4 secondary_fragment_color = vec4(0.0);
|
|||
if (state.lighting.enable)
|
||||
WriteLighting(out, config);
|
||||
|
||||
out += "vec4 combiner_buffer = vec4(0.0);\n";
|
||||
out += "vec4 next_combiner_buffer = tev_combiner_buffer_color;\n";
|
||||
out += "vec4 last_tex_env_out = vec4(0.0);\n";
|
||||
out += "vec4 combiner_buffer = vec4(0.0);\n"
|
||||
"vec4 next_combiner_buffer = tev_combiner_buffer_color;\n"
|
||||
"vec4 last_tex_env_out = vec4(0.0);\n";
|
||||
|
||||
for (std::size_t index = 0; index < state.tev_stages.size(); ++index)
|
||||
WriteTevStage(out, config, (unsigned)index);
|
||||
for (std::size_t index = 0; index < state.tev_stages.size(); ++index) {
|
||||
WriteTevStage(out, config, static_cast<u32>(index));
|
||||
}
|
||||
|
||||
if (state.alpha_test_func != FramebufferRegs::CompareFunc::Always) {
|
||||
out += "if (";
|
||||
|
@ -1534,12 +1531,12 @@ vec4 secondary_fragment_color = vec4(0.0);
|
|||
}
|
||||
|
||||
// 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_f = fog_index - fog_i;\n";
|
||||
out += "vec2 fog_lut_entry = texelFetch(texture_buffer_lut_rg, int(fog_i) + "
|
||||
"fog_lut_offset).rg;\n";
|
||||
out += "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";
|
||||
out += "float fog_i = clamp(floor(fog_index), 0.0, 127.0);\n"
|
||||
"float fog_f = fog_index - fog_i;\n"
|
||||
"vec2 fog_lut_entry = texelFetch(texture_buffer_lut_rg, int(fog_i) + "
|
||||
"fog_lut_offset).rg;\n"
|
||||
"float fog_factor = fog_lut_entry.r + fog_lut_entry.g * fog_f;\n"
|
||||
"fog_factor = clamp(fog_factor, 0.0, 1.0);\n";
|
||||
|
||||
// Blend the fog
|
||||
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 += "}";
|
||||
out += '}';
|
||||
|
||||
return {out};
|
||||
}
|
||||
|
||||
ShaderDecompiler::ProgramResult GenerateTrivialVertexShader(bool separable_shader) {
|
||||
std::string out = "";
|
||||
std::string out;
|
||||
if (separable_shader) {
|
||||
out += "#extension GL_ARB_separate_shader_objects : enable\n";
|
||||
}
|
||||
|
||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) +
|
||||
") in vec4 vert_position;\n";
|
||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n";
|
||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) +
|
||||
") in vec2 vert_texcoord0;\n";
|
||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) +
|
||||
") in vec2 vert_texcoord1;\n";
|
||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) +
|
||||
") in vec2 vert_texcoord2;\n";
|
||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0_W) +
|
||||
") in float vert_texcoord0_w;\n";
|
||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_NORMQUAT) +
|
||||
") in vec4 vert_normquat;\n";
|
||||
out += "layout(location = " + std::to_string((int)ATTRIBUTE_VIEW) + ") in vec3 vert_view;\n";
|
||||
out += fmt::format("layout(location = {}) in vec4 vert_position;\n",
|
||||
static_cast<int>(ATTRIBUTE_POSITION));
|
||||
out += fmt::format("layout(location = {}) in vec4 vert_color;\n",
|
||||
static_cast<int>(ATTRIBUTE_COLOR));
|
||||
out += fmt::format("layout(location = {}) in vec2 vert_texcoord0;\n",
|
||||
static_cast<int>(ATTRIBUTE_TEXCOORD0));
|
||||
out += fmt::format("layout(location = {}) in vec2 vert_texcoord1;\n",
|
||||
static_cast<int>(ATTRIBUTE_TEXCOORD1));
|
||||
out += fmt::format("layout(location = {}) in vec2 vert_texcoord2;\n",
|
||||
static_cast<int>(ATTRIBUTE_TEXCOORD2));
|
||||
out += fmt::format("layout(location = {}) in float vert_texcoord0_w;\n",
|
||||
static_cast<int>(ATTRIBUTE_TEXCOORD0_W));
|
||||
out += fmt::format("layout(location = {}) in vec4 vert_normquat;\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);
|
||||
|
||||
|
@ -1645,16 +1644,16 @@ std::optional<ShaderDecompiler::ProgramResult> GenerateVertexShader(
|
|||
out += ShaderDecompiler::GetCommonDeclarations();
|
||||
|
||||
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);
|
||||
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);
|
||||
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 "";
|
||||
};
|
||||
|
@ -1678,11 +1677,10 @@ layout (std140) uniform vs_config {
|
|||
// input attributes declaration
|
||||
for (std::size_t i = 0; i < used_regs.size(); ++i) {
|
||||
if (used_regs[i]) {
|
||||
out += "layout(location = " + std::to_string(i) + ") in vec4 vs_in_reg" +
|
||||
std::to_string(i) + ";\n";
|
||||
out += fmt::format("layout(location = {0}) in vec4 vs_in_reg{0};\n", i);
|
||||
}
|
||||
}
|
||||
out += "\n";
|
||||
out += '\n';
|
||||
|
||||
// output attributes declaration
|
||||
for (u32 i = 0; i < config.state.num_outputs; ++i) {
|
||||
|
@ -1692,7 +1690,7 @@ layout (std140) uniform vs_config {
|
|||
|
||||
out += "\nvoid main() {\n";
|
||||
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";
|
||||
|
||||
|
@ -1715,15 +1713,15 @@ static std::string GetGSCommonSource(const PicaGSConfigCommonRaw& config, bool s
|
|||
out += R"(
|
||||
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";
|
||||
|
||||
auto semantic = [&config](VSOutputAttributes::Semantic slot_semantic) -> std::string {
|
||||
u32 slot = static_cast<u32>(slot_semantic);
|
||||
u32 attrib = config.semantic_maps[slot].attribute_index;
|
||||
u32 comp = config.semantic_maps[slot].component_index;
|
||||
const auto semantic = [&config](VSOutputAttributes::Semantic slot_semantic) -> std::string {
|
||||
const u32 slot = static_cast<u32>(slot_semantic);
|
||||
const u32 attrib = config.semantic_maps[slot].attribute_index;
|
||||
const u32 comp = config.semantic_maps[slot].component_index;
|
||||
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";
|
||||
};
|
||||
|
@ -1806,11 +1804,10 @@ void main() {
|
|||
Vertex prim_buffer[3];
|
||||
)";
|
||||
for (u32 vtx = 0; vtx < 3; ++vtx) {
|
||||
out += " prim_buffer[" + std::to_string(vtx) + "].attributes = vec4[" +
|
||||
std::to_string(config.state.gs_output_attributes) + "](";
|
||||
out += fmt::format(" prim_buffer[{}].attributes = vec4[{}](", vtx,
|
||||
config.state.gs_output_attributes);
|
||||
for (u32 i = 0; i < config.state.vs_output_attributes; ++i) {
|
||||
out += std::string(i == 0 ? "" : ", ") + "vs_out_attr" + std::to_string(i) + "[" +
|
||||
std::to_string(vtx) + "]";
|
||||
out += fmt::format("{}vs_out_attr{}[{}]", i == 0 ? "" : ", ", i, vtx);
|
||||
}
|
||||
out += ");\n";
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue