ShaderGenCommon: Rename WriteFmt() to Write()

Now that we've converted all of the shader generators over to using fmt,
we can drop the old Write() member function and perform a rename
operation on the WriteFmt() to turn it into the new Write() function.

All changes within this are the removal of a <cstdarg> header, since the
previous printf-based Write() required it, and renaming. No functional
changes are made at all.
This commit is contained in:
Lioncash
2020-11-09 02:31:49 -05:00
parent a9ef7e0e43
commit a5b28f1f07
12 changed files with 2340 additions and 2381 deletions
File diff suppressed because it is too large Load Diff
+107 -109
View File
@@ -73,133 +73,131 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
// Insert layout parameters
if (host_config.backend_gs_instancing)
{
out.WriteFmt("layout({}, invocations = {}) in;\n", primitives_ogl[primitive_type_index],
stereo ? 2 : 1);
out.WriteFmt("layout({}_strip, max_vertices = {}) out;\n", wireframe ? "line" : "triangle",
vertex_out);
out.Write("layout({}, invocations = {}) in;\n", primitives_ogl[primitive_type_index],
stereo ? 2 : 1);
out.Write("layout({}_strip, max_vertices = {}) out;\n", wireframe ? "line" : "triangle",
vertex_out);
}
else
{
out.WriteFmt("layout({}) in;\n", primitives_ogl[primitive_type_index]);
out.WriteFmt("layout({}_strip, max_vertices = {}) out;\n", wireframe ? "line" : "triangle",
stereo ? vertex_out * 2 : vertex_out);
out.Write("layout({}) in;\n", primitives_ogl[primitive_type_index]);
out.Write("layout({}_strip, max_vertices = {}) out;\n", wireframe ? "line" : "triangle",
stereo ? vertex_out * 2 : vertex_out);
}
}
out.WriteFmt("{}", s_lighting_struct);
out.Write("{}", s_lighting_struct);
// uniforms
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
out.WriteFmt("UBO_BINDING(std140, 3) uniform GSBlock {{\n");
out.Write("UBO_BINDING(std140, 3) uniform GSBlock {{\n");
else
out.WriteFmt("cbuffer GSBlock {{\n");
out.Write("cbuffer GSBlock {{\n");
out.WriteFmt("\tfloat4 " I_STEREOPARAMS ";\n"
"\tfloat4 " I_LINEPTPARAMS ";\n"
"\tint4 " I_TEXOFFSET ";\n"
"}};\n");
out.Write("\tfloat4 " I_STEREOPARAMS ";\n"
"\tfloat4 " I_LINEPTPARAMS ";\n"
"\tint4 " I_TEXOFFSET ";\n"
"}};\n");
out.WriteFmt("struct VS_OUTPUT {{\n");
out.Write("struct VS_OUTPUT {{\n");
GenerateVSOutputMembers(out, ApiType, uid_data->numTexGens, host_config, "");
out.WriteFmt("}};\n");
out.Write("}};\n");
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
{
if (host_config.backend_gs_instancing)
out.WriteFmt("#define InstanceID gl_InvocationID\n");
out.Write("#define InstanceID gl_InvocationID\n");
out.WriteFmt("VARYING_LOCATION(0) in VertexData {{\n");
out.Write("VARYING_LOCATION(0) in VertexData {{\n");
GenerateVSOutputMembers(out, ApiType, uid_data->numTexGens, host_config,
GetInterpolationQualifier(msaa, ssaa, true, true));
out.WriteFmt("}} vs[{}];\n", vertex_in);
out.Write("}} vs[{}];\n", vertex_in);
out.WriteFmt("VARYING_LOCATION(0) out VertexData {{\n");
out.Write("VARYING_LOCATION(0) out VertexData {{\n");
GenerateVSOutputMembers(out, ApiType, uid_data->numTexGens, host_config,
GetInterpolationQualifier(msaa, ssaa, true, false));
if (stereo)
out.WriteFmt("\tflat int layer;\n");
out.Write("\tflat int layer;\n");
out.WriteFmt("}} ps;\n");
out.Write("}} ps;\n");
out.WriteFmt("void main()\n{{\n");
out.Write("void main()\n{{\n");
}
else // D3D
{
out.WriteFmt("struct VertexData {{\n");
out.WriteFmt("\tVS_OUTPUT o;\n");
out.Write("struct VertexData {{\n");
out.Write("\tVS_OUTPUT o;\n");
if (stereo)
out.WriteFmt("\tuint layer : SV_RenderTargetArrayIndex;\n");
out.Write("\tuint layer : SV_RenderTargetArrayIndex;\n");
out.WriteFmt("}};\n");
out.Write("}};\n");
if (host_config.backend_gs_instancing)
{
out.WriteFmt("[maxvertexcount({})]\n[instance({})]\n", vertex_out, stereo ? 2 : 1);
out.WriteFmt("void main({} VS_OUTPUT o[{}], inout {}Stream<VertexData> output, in uint "
"InstanceID : SV_GSInstanceID)\n{{\n",
primitives_d3d[primitive_type_index], vertex_in,
wireframe ? "Line" : "Triangle");
out.Write("[maxvertexcount({})]\n[instance({})]\n", vertex_out, stereo ? 2 : 1);
out.Write("void main({} VS_OUTPUT o[{}], inout {}Stream<VertexData> output, in uint "
"InstanceID : SV_GSInstanceID)\n{{\n",
primitives_d3d[primitive_type_index], vertex_in, wireframe ? "Line" : "Triangle");
}
else
{
out.WriteFmt("[maxvertexcount({})]\n", stereo ? vertex_out * 2 : vertex_out);
out.WriteFmt("void main({} VS_OUTPUT o[{}], inout {}Stream<VertexData> output)\n{{\n",
primitives_d3d[primitive_type_index], vertex_in,
wireframe ? "Line" : "Triangle");
out.Write("[maxvertexcount({})]\n", stereo ? vertex_out * 2 : vertex_out);
out.Write("void main({} VS_OUTPUT o[{}], inout {}Stream<VertexData> output)\n{{\n",
primitives_d3d[primitive_type_index], vertex_in, wireframe ? "Line" : "Triangle");
}
out.WriteFmt("\tVertexData ps;\n");
out.Write("\tVertexData ps;\n");
}
if (primitive_type == PrimitiveType::Lines)
{
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
{
out.WriteFmt("\tVS_OUTPUT start, end;\n");
out.Write("\tVS_OUTPUT start, end;\n");
AssignVSOutputMembers(out, "start", "vs[0]", uid_data->numTexGens, host_config);
AssignVSOutputMembers(out, "end", "vs[1]", uid_data->numTexGens, host_config);
}
else
{
out.WriteFmt("\tVS_OUTPUT start = o[0];\n"
"\tVS_OUTPUT end = o[1];\n");
out.Write("\tVS_OUTPUT start = o[0];\n"
"\tVS_OUTPUT end = o[1];\n");
}
// GameCube/Wii's line drawing algorithm is a little quirky. It does not
// use the correct line caps. Instead, the line caps are vertical or
// horizontal depending the slope of the line.
out.WriteFmt("\tfloat2 offset;\n"
"\tfloat2 to = abs(end.pos.xy / end.pos.w - start.pos.xy / start.pos.w);\n"
// FIXME: What does real hardware do when line is at a 45-degree angle?
// FIXME: Lines aren't drawn at the correct width. See Twilight Princess map.
"\tif (" I_LINEPTPARAMS ".y * to.y > " I_LINEPTPARAMS ".x * to.x) {{\n"
// Line is more tall. Extend geometry left and right.
// Lerp LineWidth/2 from [0..VpWidth] to [-1..1]
"\t\toffset = float2(" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".x, 0);\n"
"\t}} else {{\n"
// Line is more wide. Extend geometry up and down.
// Lerp LineWidth/2 from [0..VpHeight] to [1..-1]
"\t\toffset = float2(0, -" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\n"
"\t}}\n");
out.Write("\tfloat2 offset;\n"
"\tfloat2 to = abs(end.pos.xy / end.pos.w - start.pos.xy / start.pos.w);\n"
// FIXME: What does real hardware do when line is at a 45-degree angle?
// FIXME: Lines aren't drawn at the correct width. See Twilight Princess map.
"\tif (" I_LINEPTPARAMS ".y * to.y > " I_LINEPTPARAMS ".x * to.x) {{\n"
// Line is more tall. Extend geometry left and right.
// Lerp LineWidth/2 from [0..VpWidth] to [-1..1]
"\t\toffset = float2(" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".x, 0);\n"
"\t}} else {{\n"
// Line is more wide. Extend geometry up and down.
// Lerp LineWidth/2 from [0..VpHeight] to [1..-1]
"\t\toffset = float2(0, -" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\n"
"\t}}\n");
}
else if (primitive_type == PrimitiveType::Points)
{
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
{
out.WriteFmt("\tVS_OUTPUT center;\n");
out.Write("\tVS_OUTPUT center;\n");
AssignVSOutputMembers(out, "center", "vs[0]", uid_data->numTexGens, host_config);
}
else
{
out.WriteFmt("\tVS_OUTPUT center = o[0];\n");
out.Write("\tVS_OUTPUT center = o[0];\n");
}
// Offset from center to upper right vertex
// Lerp PointSize/2 from [0,0..VpWidth,VpHeight] to [-1,1..1,-1]
out.WriteFmt("\tfloat2 offset = float2(" I_LINEPTPARAMS ".w / " I_LINEPTPARAMS
".x, -" I_LINEPTPARAMS ".w / " I_LINEPTPARAMS ".y) * center.pos.w;\n");
out.Write("\tfloat2 offset = float2(" I_LINEPTPARAMS ".w / " I_LINEPTPARAMS
".x, -" I_LINEPTPARAMS ".w / " I_LINEPTPARAMS ".y) * center.pos.w;\n");
}
if (stereo)
@@ -207,19 +205,19 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
// If the GPU supports invocation we don't need a for loop and can simply use the
// invocation identifier to determine which layer we're rendering.
if (host_config.backend_gs_instancing)
out.WriteFmt("\tint eye = InstanceID;\n");
out.Write("\tint eye = InstanceID;\n");
else
out.WriteFmt("\tfor (int eye = 0; eye < 2; ++eye) {{\n");
out.Write("\tfor (int eye = 0; eye < 2; ++eye) {{\n");
}
if (wireframe)
out.WriteFmt("\tVS_OUTPUT first;\n");
out.Write("\tVS_OUTPUT first;\n");
out.WriteFmt("\tfor (int i = 0; i < {}; ++i) {{\n", vertex_in);
out.Write("\tfor (int i = 0; i < {}; ++i) {{\n", vertex_in);
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
{
out.WriteFmt("\tVS_OUTPUT f;\n");
out.Write("\tVS_OUTPUT f;\n");
AssignVSOutputMembers(out, "f", "vs[i]", uid_data->numTexGens, host_config);
if (host_config.backend_depth_clamp &&
@@ -227,21 +225,21 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
{
// On certain GPUs we have to consume the clip distance from the vertex shader
// or else the other vertex shader outputs will get corrupted.
out.WriteFmt("\tf.clipDist0 = gl_in[i].gl_ClipDistance[0];\n"
"\tf.clipDist1 = gl_in[i].gl_ClipDistance[1];\n");
out.Write("\tf.clipDist0 = gl_in[i].gl_ClipDistance[0];\n"
"\tf.clipDist1 = gl_in[i].gl_ClipDistance[1];\n");
}
}
else
{
out.WriteFmt("\tVS_OUTPUT f = o[i];\n");
out.Write("\tVS_OUTPUT f = o[i];\n");
}
if (stereo)
{
// Select the output layer
out.WriteFmt("\tps.layer = eye;\n");
out.Write("\tps.layer = eye;\n");
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
out.WriteFmt("\tgl_Layer = eye;\n");
out.Write("\tgl_Layer = eye;\n");
// For stereoscopy add a small horizontal offset in Normalized Device Coordinates proportional
// to the depth of the vertex. We retrieve the depth value from the w-component of the projected
@@ -250,56 +248,56 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
// the depth value. This results in objects at a distance smaller than the convergence
// distance to seemingly appear in front of the screen.
// This formula is based on page 13 of the "Nvidia 3D Vision Automatic, Best Practices Guide"
out.WriteFmt("\tfloat hoffset = (eye == 0) ? " I_STEREOPARAMS ".x : " I_STEREOPARAMS ".y;\n");
out.WriteFmt("\tf.pos.x += hoffset * (f.pos.w - " I_STEREOPARAMS ".z);\n");
out.Write("\tfloat hoffset = (eye == 0) ? " I_STEREOPARAMS ".x : " I_STEREOPARAMS ".y;\n");
out.Write("\tf.pos.x += hoffset * (f.pos.w - " I_STEREOPARAMS ".z);\n");
}
if (primitive_type == PrimitiveType::Lines)
{
out.WriteFmt("\tVS_OUTPUT l = f;\n"
"\tVS_OUTPUT r = f;\n");
out.Write("\tVS_OUTPUT l = f;\n"
"\tVS_OUTPUT r = f;\n");
out.WriteFmt("\tl.pos.xy -= offset * l.pos.w;\n"
"\tr.pos.xy += offset * r.pos.w;\n");
out.Write("\tl.pos.xy -= offset * l.pos.w;\n"
"\tr.pos.xy += offset * r.pos.w;\n");
out.WriteFmt("\tif (" I_TEXOFFSET "[2] != 0) {{\n");
out.WriteFmt("\tfloat texOffset = 1.0 / float(" I_TEXOFFSET "[2]);\n");
out.Write("\tif (" I_TEXOFFSET "[2] != 0) {{\n");
out.Write("\tfloat texOffset = 1.0 / float(" I_TEXOFFSET "[2]);\n");
for (u32 i = 0; i < uid_data->numTexGens; ++i)
{
out.WriteFmt("\tif (((" I_TEXOFFSET "[0] >> {}) & 0x1) != 0)\n", i);
out.WriteFmt("\t\tr.tex{}.x += texOffset;\n", i);
out.Write("\tif (((" I_TEXOFFSET "[0] >> {}) & 0x1) != 0)\n", i);
out.Write("\t\tr.tex{}.x += texOffset;\n", i);
}
out.WriteFmt("\t}}\n");
out.Write("\t}}\n");
EmitVertex(out, host_config, uid_data, "l", ApiType, wireframe, true);
EmitVertex(out, host_config, uid_data, "r", ApiType, wireframe);
}
else if (primitive_type == PrimitiveType::Points)
{
out.WriteFmt("\tVS_OUTPUT ll = f;\n"
"\tVS_OUTPUT lr = f;\n"
"\tVS_OUTPUT ul = f;\n"
"\tVS_OUTPUT ur = f;\n");
out.Write("\tVS_OUTPUT ll = f;\n"
"\tVS_OUTPUT lr = f;\n"
"\tVS_OUTPUT ul = f;\n"
"\tVS_OUTPUT ur = f;\n");
out.WriteFmt("\tll.pos.xy += float2(-1,-1) * offset;\n"
"\tlr.pos.xy += float2(1,-1) * offset;\n"
"\tul.pos.xy += float2(-1,1) * offset;\n"
"\tur.pos.xy += offset;\n");
out.Write("\tll.pos.xy += float2(-1,-1) * offset;\n"
"\tlr.pos.xy += float2(1,-1) * offset;\n"
"\tul.pos.xy += float2(-1,1) * offset;\n"
"\tur.pos.xy += offset;\n");
out.WriteFmt("\tif (" I_TEXOFFSET "[3] != 0) {{\n");
out.WriteFmt("\tfloat2 texOffset = float2(1.0 / float(" I_TEXOFFSET
"[3]), 1.0 / float(" I_TEXOFFSET "[3]));\n");
out.Write("\tif (" I_TEXOFFSET "[3] != 0) {{\n");
out.Write("\tfloat2 texOffset = float2(1.0 / float(" I_TEXOFFSET
"[3]), 1.0 / float(" I_TEXOFFSET "[3]));\n");
for (u32 i = 0; i < uid_data->numTexGens; ++i)
{
out.WriteFmt("\tif (((" I_TEXOFFSET "[1] >> {}) & 0x1) != 0) {{\n", i);
out.WriteFmt("\t\tul.tex{}.xy += float2(0,1) * texOffset;\n", i);
out.WriteFmt("\t\tur.tex{}.xy += texOffset;\n", i);
out.WriteFmt("\t\tlr.tex{}.xy += float2(1,0) * texOffset;\n", i);
out.WriteFmt("\t}}\n");
out.Write("\tif (((" I_TEXOFFSET "[1] >> {}) & 0x1) != 0) {{\n", i);
out.Write("\t\tul.tex{}.xy += float2(0,1) * texOffset;\n", i);
out.Write("\t\tur.tex{}.xy += texOffset;\n", i);
out.Write("\t\tlr.tex{}.xy += float2(1,0) * texOffset;\n", i);
out.Write("\t}}\n");
}
out.WriteFmt("\t}}\n");
out.Write("\t}}\n");
EmitVertex(out, host_config, uid_data, "ll", ApiType, wireframe, true);
EmitVertex(out, host_config, uid_data, "lr", ApiType, wireframe);
@@ -311,14 +309,14 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h
EmitVertex(out, host_config, uid_data, "f", ApiType, wireframe, true);
}
out.WriteFmt("\t}}\n");
out.Write("\t}}\n");
EndPrimitive(out, host_config, uid_data, ApiType, wireframe);
if (stereo && !host_config.backend_gs_instancing)
out.WriteFmt("\t}}\n");
out.Write("\t}}\n");
out.WriteFmt("}}\n");
out.Write("}}\n");
return out;
}
@@ -328,34 +326,34 @@ static void EmitVertex(ShaderCode& out, const ShaderHostConfig& host_config,
APIType ApiType, bool wireframe, bool first_vertex)
{
if (wireframe && first_vertex)
out.WriteFmt("\tif (i == 0) first = {};\n", vertex);
out.Write("\tif (i == 0) first = {};\n", vertex);
if (ApiType == APIType::OpenGL)
{
out.WriteFmt("\tgl_Position = {}.pos;\n", vertex);
out.Write("\tgl_Position = {}.pos;\n", vertex);
if (host_config.backend_depth_clamp)
{
out.WriteFmt("\tgl_ClipDistance[0] = {}.clipDist0;\n", vertex);
out.WriteFmt("\tgl_ClipDistance[1] = {}.clipDist1;\n", vertex);
out.Write("\tgl_ClipDistance[0] = {}.clipDist0;\n", vertex);
out.Write("\tgl_ClipDistance[1] = {}.clipDist1;\n", vertex);
}
AssignVSOutputMembers(out, "ps", vertex, uid_data->numTexGens, host_config);
}
else if (ApiType == APIType::Vulkan)
{
// Vulkan NDC space has Y pointing down (right-handed NDC space).
out.WriteFmt("\tgl_Position = {}.pos;\n", vertex);
out.WriteFmt("\tgl_Position.y = -gl_Position.y;\n");
out.Write("\tgl_Position = {}.pos;\n", vertex);
out.Write("\tgl_Position.y = -gl_Position.y;\n");
AssignVSOutputMembers(out, "ps", vertex, uid_data->numTexGens, host_config);
}
else
{
out.WriteFmt("\tps.o = {};\n", vertex);
out.Write("\tps.o = {};\n", vertex);
}
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
out.WriteFmt("\tEmitVertex();\n");
out.Write("\tEmitVertex();\n");
else
out.WriteFmt("\toutput.Append(ps);\n");
out.Write("\toutput.Append(ps);\n");
}
static void EndPrimitive(ShaderCode& out, const ShaderHostConfig& host_config,
@@ -365,9 +363,9 @@ static void EndPrimitive(ShaderCode& out, const ShaderHostConfig& host_config,
EmitVertex(out, host_config, uid_data, "first", ApiType, wireframe);
if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan)
out.WriteFmt("\tEndPrimitive();\n");
out.Write("\tEndPrimitive();\n");
else
out.WriteFmt("\toutput.RestartStrip();\n");
out.Write("\toutput.RestartStrip();\n");
}
void EnumerateGeometryShaderUids(const std::function<void(const GeometryShaderUid&)>& callback)
+50 -51
View File
@@ -24,54 +24,53 @@ static void GenerateLightShader(ShaderCode& object, const LightingUidData& uid_d
{
case LIGHTATTN_NONE:
case LIGHTATTN_DIR:
object.WriteFmt("ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index));
object.WriteFmt("attn = 1.0;\n");
object.WriteFmt("if (length(ldir) == 0.0)\n\t ldir = _norm0;\n");
object.Write("ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index));
object.Write("attn = 1.0;\n");
object.Write("if (length(ldir) == 0.0)\n\t ldir = _norm0;\n");
break;
case LIGHTATTN_SPEC:
object.WriteFmt("ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index));
object.WriteFmt("attn = (dot(_norm0, ldir) >= 0.0) ? max(0.0, dot(_norm0, " LIGHT_DIR
".xyz)) : 0.0;\n",
LIGHT_DIR_PARAMS(index));
object.WriteFmt("cosAttn = " LIGHT_COSATT ".xyz;\n", LIGHT_COSATT_PARAMS(index));
object.WriteFmt("distAttn = {}(" LIGHT_DISTATT ".xyz);\n",
(diffusefunc == LIGHTDIF_NONE) ? "" : "normalize", LIGHT_DISTATT_PARAMS(index));
object.WriteFmt("attn = max(0.0f, dot(cosAttn, float3(1.0, attn, attn*attn))) / dot(distAttn, "
"float3(1.0, attn, attn*attn));\n");
object.Write("ldir = normalize(" LIGHT_POS ".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(index));
object.Write("attn = (dot(_norm0, ldir) >= 0.0) ? max(0.0, dot(_norm0, " LIGHT_DIR
".xyz)) : 0.0;\n",
LIGHT_DIR_PARAMS(index));
object.Write("cosAttn = " LIGHT_COSATT ".xyz;\n", LIGHT_COSATT_PARAMS(index));
object.Write("distAttn = {}(" LIGHT_DISTATT ".xyz);\n",
(diffusefunc == LIGHTDIF_NONE) ? "" : "normalize", LIGHT_DISTATT_PARAMS(index));
object.Write("attn = max(0.0f, dot(cosAttn, float3(1.0, attn, attn*attn))) / dot(distAttn, "
"float3(1.0, attn, attn*attn));\n");
break;
case LIGHTATTN_SPOT:
object.WriteFmt("ldir = " LIGHT_POS ".xyz - pos.xyz;\n", LIGHT_POS_PARAMS(index));
object.WriteFmt("dist2 = dot(ldir, ldir);\n"
"dist = sqrt(dist2);\n"
"ldir = ldir / dist;\n"
"attn = max(0.0, dot(ldir, " LIGHT_DIR ".xyz));\n",
LIGHT_DIR_PARAMS(index));
object.Write("ldir = " LIGHT_POS ".xyz - pos.xyz;\n", LIGHT_POS_PARAMS(index));
object.Write("dist2 = dot(ldir, ldir);\n"
"dist = sqrt(dist2);\n"
"ldir = ldir / dist;\n"
"attn = max(0.0, dot(ldir, " LIGHT_DIR ".xyz));\n",
LIGHT_DIR_PARAMS(index));
// attn*attn may overflow
object.WriteFmt("attn = max(0.0, " LIGHT_COSATT ".x + " LIGHT_COSATT ".y*attn + " LIGHT_COSATT
".z*attn*attn) / dot(" LIGHT_DISTATT ".xyz, float3(1.0,dist,dist2));\n",
LIGHT_COSATT_PARAMS(index), LIGHT_COSATT_PARAMS(index),
LIGHT_COSATT_PARAMS(index), LIGHT_DISTATT_PARAMS(index));
object.Write("attn = max(0.0, " LIGHT_COSATT ".x + " LIGHT_COSATT ".y*attn + " LIGHT_COSATT
".z*attn*attn) / dot(" LIGHT_DISTATT ".xyz, float3(1.0,dist,dist2));\n",
LIGHT_COSATT_PARAMS(index), LIGHT_COSATT_PARAMS(index), LIGHT_COSATT_PARAMS(index),
LIGHT_DISTATT_PARAMS(index));
break;
}
switch (diffusefunc)
{
case LIGHTDIF_NONE:
object.WriteFmt("lacc.{} += int{}(round(attn * float{}(" LIGHT_COL ")));\n", swizzle,
swizzle_components, swizzle_components, LIGHT_COL_PARAMS(index, swizzle));
object.Write("lacc.{} += int{}(round(attn * float{}(" LIGHT_COL ")));\n", swizzle,
swizzle_components, swizzle_components, LIGHT_COL_PARAMS(index, swizzle));
break;
case LIGHTDIF_SIGN:
case LIGHTDIF_CLAMP:
object.WriteFmt("lacc.{} += int{}(round(attn * {}dot(ldir, _norm0)) * float{}(" LIGHT_COL
")));\n",
swizzle, swizzle_components, diffusefunc != LIGHTDIF_SIGN ? "max(0.0," : "(",
swizzle_components, LIGHT_COL_PARAMS(index, swizzle));
object.Write("lacc.{} += int{}(round(attn * {}dot(ldir, _norm0)) * float{}(" LIGHT_COL ")));\n",
swizzle, swizzle_components, diffusefunc != LIGHTDIF_SIGN ? "max(0.0," : "(",
swizzle_components, LIGHT_COL_PARAMS(index, swizzle));
break;
default:
ASSERT(0);
}
object.WriteFmt("\n");
object.Write("\n");
}
// vertex shader
@@ -84,21 +83,21 @@ void GenerateLightingShaderCode(ShaderCode& object, const LightingUidData& uid_d
{
for (u32 j = 0; j < NUM_XF_COLOR_CHANNELS; j++)
{
object.WriteFmt("{{\n");
object.Write("{{\n");
const bool colormatsource = !!(uid_data.matsource & (1 << j));
if (colormatsource) // from vertex
{
if ((components & (VB_HAS_COL0 << j)) != 0)
object.WriteFmt("int4 mat = int4(round({}{} * 255.0));\n", in_color_name, j);
object.Write("int4 mat = int4(round({}{} * 255.0));\n", in_color_name, j);
else if ((components & VB_HAS_COL0) != 0)
object.WriteFmt("int4 mat = int4(round({}0 * 255.0));\n", in_color_name);
object.Write("int4 mat = int4(round({}0 * 255.0));\n", in_color_name);
else
object.WriteFmt("int4 mat = int4(255, 255, 255, 255);\n");
object.Write("int4 mat = int4(255, 255, 255, 255);\n");
}
else // from color
{
object.WriteFmt("int4 mat = {}[{}];\n", I_MATERIALS, j + 2);
object.Write("int4 mat = {}[{}];\n", I_MATERIALS, j + 2);
}
if ((uid_data.enablelighting & (1 << j)) != 0)
@@ -107,28 +106,28 @@ void GenerateLightingShaderCode(ShaderCode& object, const LightingUidData& uid_d
{
if ((components & (VB_HAS_COL0 << j)) != 0)
{
object.WriteFmt("lacc = int4(round({}{} * 255.0));\n", in_color_name, j);
object.Write("lacc = int4(round({}{} * 255.0));\n", in_color_name, j);
}
else if ((components & VB_HAS_COL0) != 0)
{
object.WriteFmt("lacc = int4(round({}0 * 255.0));\n", in_color_name);
object.Write("lacc = int4(round({}0 * 255.0));\n", in_color_name);
}
else
{
// TODO: this isn't verified. Here we want to read the ambient from the vertex,
// but the vertex itself has no color. So we don't know which value to read.
// Returning 1.0 is the same as disabled lightning, so this could be fine
object.WriteFmt("lacc = int4(255, 255, 255, 255);\n");
object.Write("lacc = int4(255, 255, 255, 255);\n");
}
}
else // from color
{
object.WriteFmt("lacc = {}[{}];\n", I_MATERIALS, j);
object.Write("lacc = {}[{}];\n", I_MATERIALS, j);
}
}
else
{
object.WriteFmt("lacc = int4(255, 255, 255, 255);\n");
object.Write("lacc = int4(255, 255, 255, 255);\n");
}
// check if alpha is different
@@ -138,15 +137,15 @@ void GenerateLightingShaderCode(ShaderCode& object, const LightingUidData& uid_d
if (alphamatsource) // from vertex
{
if ((components & (VB_HAS_COL0 << j)) != 0)
object.WriteFmt("mat.w = int(round({}{}.w * 255.0));\n", in_color_name, j);
object.Write("mat.w = int(round({}{}.w * 255.0));\n", in_color_name, j);
else if ((components & VB_HAS_COL0) != 0)
object.WriteFmt("mat.w = int(round({}0.w * 255.0));\n", in_color_name);
object.Write("mat.w = int(round({}0.w * 255.0));\n", in_color_name);
else
object.WriteFmt("mat.w = 255;\n");
object.Write("mat.w = 255;\n");
}
else // from color
{
object.WriteFmt("mat.w = {}[{}].w;\n", I_MATERIALS, j + 2);
object.Write("mat.w = {}[{}].w;\n", I_MATERIALS, j + 2);
}
}
@@ -156,26 +155,26 @@ void GenerateLightingShaderCode(ShaderCode& object, const LightingUidData& uid_d
{
if ((components & (VB_HAS_COL0 << j)) != 0)
{
object.WriteFmt("lacc.w = int(round({}{}.w * 255.0));\n", in_color_name, j);
object.Write("lacc.w = int(round({}{}.w * 255.0));\n", in_color_name, j);
}
else if ((components & VB_HAS_COL0) != 0)
{
object.WriteFmt("lacc.w = int(round({}0.w * 255.0));\n", in_color_name);
object.Write("lacc.w = int(round({}0.w * 255.0));\n", in_color_name);
}
else
{
// TODO: The same for alpha: We want to read from vertex, but the vertex has no color
object.WriteFmt("lacc.w = 255;\n");
object.Write("lacc.w = 255;\n");
}
}
else // from color
{
object.WriteFmt("lacc.w = {}[{}].w;\n", I_MATERIALS, j);
object.Write("lacc.w = {}[{}].w;\n", I_MATERIALS, j);
}
}
else
{
object.WriteFmt("lacc.w = 255;\n");
object.Write("lacc.w = 255;\n");
}
if ((uid_data.enablelighting & (1 << j)) != 0) // Color lights
@@ -194,9 +193,9 @@ void GenerateLightingShaderCode(ShaderCode& object, const LightingUidData& uid_d
GenerateLightShader(object, uid_data, i, j + 2, true);
}
}
object.WriteFmt("lacc = clamp(lacc, 0, 255);\n");
object.WriteFmt("{}{} = float4((mat * (lacc + (lacc >> 7))) >> 8) / 255.0;\n", dest, j);
object.WriteFmt("}}\n");
object.Write("lacc = clamp(lacc, 0, 255);\n");
object.Write("{}{} = float4((mat * (lacc + (lacc >> 7))) >> 8) / 255.0;\n", dest, j);
object.Write("}}\n");
}
}
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -91,20 +91,20 @@ static void DefineOutputMember(ShaderCode& object, APIType api_type, std::string
std::string_view type, std::string_view name, int var_index,
std::string_view semantic = {}, int semantic_index = -1)
{
object.WriteFmt("\t{} {} {}", qualifier, type, name);
object.Write("\t{} {} {}", qualifier, type, name);
if (var_index != -1)
object.WriteFmt("{}", var_index);
object.Write("{}", var_index);
if (api_type == APIType::D3D && !semantic.empty())
{
if (semantic_index != -1)
object.WriteFmt(" : {}{}", semantic, semantic_index);
object.Write(" : {}{}", semantic, semantic_index);
else
object.WriteFmt(" : {}", semantic);
object.Write(" : {}", semantic);
}
object.WriteFmt(";\n");
object.Write(";\n");
}
void GenerateVSOutputMembers(ShaderCode& object, APIType api_type, u32 texgens,
@@ -138,26 +138,26 @@ void GenerateVSOutputMembers(ShaderCode& object, APIType api_type, u32 texgens,
void AssignVSOutputMembers(ShaderCode& object, std::string_view a, std::string_view b, u32 texgens,
const ShaderHostConfig& host_config)
{
object.WriteFmt("\t{}.pos = {}.pos;\n", a, b);
object.WriteFmt("\t{}.colors_0 = {}.colors_0;\n", a, b);
object.WriteFmt("\t{}.colors_1 = {}.colors_1;\n", a, b);
object.Write("\t{}.pos = {}.pos;\n", a, b);
object.Write("\t{}.colors_0 = {}.colors_0;\n", a, b);
object.Write("\t{}.colors_1 = {}.colors_1;\n", a, b);
for (unsigned int i = 0; i < texgens; ++i)
object.WriteFmt("\t{}.tex{} = {}.tex{};\n", a, i, b, i);
object.Write("\t{}.tex{} = {}.tex{};\n", a, i, b, i);
if (!host_config.fast_depth_calc)
object.WriteFmt("\t{}.clipPos = {}.clipPos;\n", a, b);
object.Write("\t{}.clipPos = {}.clipPos;\n", a, b);
if (host_config.per_pixel_lighting)
{
object.WriteFmt("\t{}.Normal = {}.Normal;\n", a, b);
object.WriteFmt("\t{}.WorldPos = {}.WorldPos;\n", a, b);
object.Write("\t{}.Normal = {}.Normal;\n", a, b);
object.Write("\t{}.WorldPos = {}.WorldPos;\n", a, b);
}
if (host_config.backend_geometry_shaders)
{
object.WriteFmt("\t{}.clipDist0 = {}.clipDist0;\n", a, b);
object.WriteFmt("\t{}.clipDist1 = {}.clipDist1;\n", a, b);
object.Write("\t{}.clipDist0 = {}.clipDist0;\n", a, b);
object.Write("\t{}.clipDist1 = {}.clipDist1;\n", a, b);
}
}
+1 -14
View File
@@ -4,7 +4,6 @@
#pragma once
#include <cstdarg>
#include <cstring>
#include <iterator>
#include <string>
@@ -104,21 +103,9 @@ public:
ShaderCode() { m_buffer.reserve(16384); }
const std::string& GetBuffer() const { return m_buffer; }
// Deprecated: Writes format strings using traditional printf format strings.
void Write(const char* fmt, ...)
#ifdef __GNUC__
__attribute__((format(printf, 2, 3)))
#endif
{
va_list arglist;
va_start(arglist, fmt);
m_buffer += StringFromFormatV(fmt, arglist);
va_end(arglist);
}
// Writes format strings using fmtlib format strings.
template <typename... Args>
void WriteFmt(std::string_view format, Args&&... args)
void Write(std::string_view format, Args&&... args)
{
fmt::format_to(std::back_inserter(m_buffer), format, std::forward<Args>(args)...);
}
File diff suppressed because it is too large Load Diff
@@ -32,23 +32,23 @@ static void WriteHeader(APIType api_type, ShaderCode& out)
{
if (api_type == APIType::D3D)
{
out.WriteFmt("cbuffer PSBlock : register(b0) {{\n"
" float2 src_offset, src_size;\n"
" float3 filter_coefficients;\n"
" float gamma_rcp;\n"
" float2 clamp_tb;\n"
" float pixel_height;\n"
"}};\n\n");
out.Write("cbuffer PSBlock : register(b0) {{\n"
" float2 src_offset, src_size;\n"
" float3 filter_coefficients;\n"
" float gamma_rcp;\n"
" float2 clamp_tb;\n"
" float pixel_height;\n"
"}};\n\n");
}
else if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
{
out.WriteFmt("UBO_BINDING(std140, 1) uniform PSBlock {{\n"
" float2 src_offset, src_size;\n"
" float3 filter_coefficients;\n"
" float gamma_rcp;\n"
" float2 clamp_tb;\n"
" float pixel_height;\n"
"}};\n");
out.Write("UBO_BINDING(std140, 1) uniform PSBlock {{\n"
" float2 src_offset, src_size;\n"
" float3 filter_coefficients;\n"
" float gamma_rcp;\n"
" float2 clamp_tb;\n"
" float pixel_height;\n"
"}};\n");
}
}
@@ -59,35 +59,35 @@ ShaderCode GenerateVertexShader(APIType api_type)
if (api_type == APIType::D3D)
{
out.WriteFmt("void main(in uint id : SV_VertexID, out float3 v_tex0 : TEXCOORD0,\n"
" out float4 opos : SV_Position) {{\n");
out.Write("void main(in uint id : SV_VertexID, out float3 v_tex0 : TEXCOORD0,\n"
" out float4 opos : SV_Position) {{\n");
}
else if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
{
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
{
out.WriteFmt("VARYING_LOCATION(0) out VertexData {{\n"
" float3 v_tex0;\n"
"}};\n");
out.Write("VARYING_LOCATION(0) out VertexData {{\n"
" float3 v_tex0;\n"
"}};\n");
}
else
{
out.WriteFmt("VARYING_LOCATION(0) out float3 v_tex0;\n");
out.Write("VARYING_LOCATION(0) out float3 v_tex0;\n");
}
out.WriteFmt("#define id gl_VertexID\n"
"#define opos gl_Position\n"
"void main() {{\n");
out.Write("#define id gl_VertexID\n"
"#define opos gl_Position\n"
"void main() {{\n");
}
out.WriteFmt(" v_tex0 = float3(float((id << 1) & 2), float(id & 2), 0.0f);\n");
out.WriteFmt(
out.Write(" v_tex0 = float3(float((id << 1) & 2), float(id & 2), 0.0f);\n");
out.Write(
" opos = float4(v_tex0.xy * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);\n");
out.WriteFmt(" v_tex0 = float3(src_offset + (src_size * v_tex0.xy), 0.0f);\n");
out.Write(" v_tex0 = float3(src_offset + (src_size * v_tex0.xy), 0.0f);\n");
// NDC space is flipped in Vulkan
if (api_type == APIType::Vulkan)
out.WriteFmt(" opos.y = -opos.y;\n");
out.Write(" opos.y = -opos.y;\n");
out.WriteFmt("}}\n");
out.Write("}}\n");
return out;
}
@@ -101,52 +101,52 @@ ShaderCode GeneratePixelShader(APIType api_type, const UidData* uid_data)
if (api_type == APIType::D3D)
{
out.WriteFmt("Texture2DArray tex0 : register(t0);\n"
"SamplerState samp0 : register(s0);\n"
"float4 SampleEFB(float3 uv, float y_offset) {{\n"
" return tex0.Sample(samp0, float3(uv.x, clamp(uv.y + (y_offset * pixel_height), "
"clamp_tb.x, clamp_tb.y), {}));\n"
"}}\n\n",
mono_depth ? "0.0" : "uv.z");
out.WriteFmt("void main(in float3 v_tex0 : TEXCOORD0, out float4 ocol0 : SV_Target)\n{{\n");
out.Write("Texture2DArray tex0 : register(t0);\n"
"SamplerState samp0 : register(s0);\n"
"float4 SampleEFB(float3 uv, float y_offset) {{\n"
" return tex0.Sample(samp0, float3(uv.x, clamp(uv.y + (y_offset * pixel_height), "
"clamp_tb.x, clamp_tb.y), {}));\n"
"}}\n\n",
mono_depth ? "0.0" : "uv.z");
out.Write("void main(in float3 v_tex0 : TEXCOORD0, out float4 ocol0 : SV_Target)\n{{\n");
}
else if (api_type == APIType::OpenGL || api_type == APIType::Vulkan)
{
out.WriteFmt("SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n");
out.WriteFmt("float4 SampleEFB(float3 uv, float y_offset) {{\n"
" return texture(samp0, float3(uv.x, clamp(uv.y + (y_offset * pixel_height), "
"clamp_tb.x, clamp_tb.y), {}));\n"
"}}\n",
mono_depth ? "0.0" : "uv.z");
out.Write("SAMPLER_BINDING(0) uniform sampler2DArray samp0;\n");
out.Write("float4 SampleEFB(float3 uv, float y_offset) {{\n"
" return texture(samp0, float3(uv.x, clamp(uv.y + (y_offset * pixel_height), "
"clamp_tb.x, clamp_tb.y), {}));\n"
"}}\n",
mono_depth ? "0.0" : "uv.z");
if (g_ActiveConfig.backend_info.bSupportsGeometryShaders)
{
out.WriteFmt("VARYING_LOCATION(0) in VertexData {{\n"
" float3 v_tex0;\n"
"}};\n");
out.Write("VARYING_LOCATION(0) in VertexData {{\n"
" float3 v_tex0;\n"
"}};\n");
}
else
{
out.WriteFmt("VARYING_LOCATION(0) in vec3 v_tex0;\n");
out.Write("VARYING_LOCATION(0) in vec3 v_tex0;\n");
}
out.WriteFmt("FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;"
"void main()\n{{\n");
out.Write("FRAGMENT_OUTPUT_LOCATION(0) out vec4 ocol0;"
"void main()\n{{\n");
}
// The copy filter applies to both color and depth copies. This has been verified on hardware.
// The filter is only applied to the RGB channels, the alpha channel is left intact.
if (uid_data->copy_filter)
{
out.WriteFmt(" float4 prev_row = SampleEFB(v_tex0, -1.0f);\n"
" float4 current_row = SampleEFB(v_tex0, 0.0f);\n"
" float4 next_row = SampleEFB(v_tex0, 1.0f);\n"
" float4 texcol = float4(min(prev_row.rgb * filter_coefficients[0] +\n"
" current_row.rgb * filter_coefficients[1] +\n"
" next_row.rgb * filter_coefficients[2], \n"
" float3(1, 1, 1)), current_row.a);\n");
out.Write(" float4 prev_row = SampleEFB(v_tex0, -1.0f);\n"
" float4 current_row = SampleEFB(v_tex0, 0.0f);\n"
" float4 next_row = SampleEFB(v_tex0, 1.0f);\n"
" float4 texcol = float4(min(prev_row.rgb * filter_coefficients[0] +\n"
" current_row.rgb * filter_coefficients[1] +\n"
" next_row.rgb * filter_coefficients[2], \n"
" float3(1, 1, 1)), current_row.a);\n");
}
else
{
out.WriteFmt(
out.Write(
" float4 current_row = SampleEFB(v_tex0, 0.0f);\n"
" float4 texcol = float4(min(current_row.rgb * filter_coefficients[1], float3(1, 1, 1)),\n"
" current_row.a);\n");
@@ -155,62 +155,62 @@ ShaderCode GeneratePixelShader(APIType api_type, const UidData* uid_data)
if (uid_data->is_depth_copy)
{
if (!g_ActiveConfig.backend_info.bSupportsReversedDepthRange)
out.WriteFmt("texcol.x = 1.0 - texcol.x;\n");
out.Write("texcol.x = 1.0 - texcol.x;\n");
out.WriteFmt(" int depth = int(texcol.x * 16777216.0);\n"
out.Write(" int depth = int(texcol.x * 16777216.0);\n"
// Convert to Z24 format
" int4 workspace;\n"
" workspace.r = (depth >> 16) & 255;\n"
" workspace.g = (depth >> 8) & 255;\n"
" workspace.b = depth & 255;\n"
// Convert to Z24 format
" int4 workspace;\n"
" workspace.r = (depth >> 16) & 255;\n"
" workspace.g = (depth >> 8) & 255;\n"
" workspace.b = depth & 255;\n"
// Convert to Z4 format
" workspace.a = (depth >> 16) & 0xF0;\n"
// Convert to Z4 format
" workspace.a = (depth >> 16) & 0xF0;\n"
// Normalize components to [0.0..1.0]
" texcol = float4(workspace) / 255.0;\n");
// Normalize components to [0.0..1.0]
" texcol = float4(workspace) / 255.0;\n");
switch (uid_data->dst_format)
{
case EFBCopyFormat::R4: // Z4
out.WriteFmt(" ocol0 = texcol.aaaa;\n");
out.Write(" ocol0 = texcol.aaaa;\n");
break;
case EFBCopyFormat::R8_0x1: // Z8
case EFBCopyFormat::R8: // Z8H
out.WriteFmt(" ocol0 = texcol.rrrr;\n");
out.Write(" ocol0 = texcol.rrrr;\n");
break;
case EFBCopyFormat::RA8: // Z16
out.WriteFmt(" ocol0 = texcol.gggr;\n");
out.Write(" ocol0 = texcol.gggr;\n");
break;
case EFBCopyFormat::RG8: // Z16 (reverse order)
out.WriteFmt(" ocol0 = texcol.rrrg;\n");
out.Write(" ocol0 = texcol.rrrg;\n");
break;
case EFBCopyFormat::RGBA8: // Z24X8
out.WriteFmt(" ocol0 = float4(texcol.rgb, 1.0);\n");
out.Write(" ocol0 = float4(texcol.rgb, 1.0);\n");
break;
case EFBCopyFormat::G8: // Z8M
out.WriteFmt(" ocol0 = texcol.gggg;\n");
out.Write(" ocol0 = texcol.gggg;\n");
break;
case EFBCopyFormat::B8: // Z8L
out.WriteFmt(" ocol0 = texcol.bbbb;\n");
out.Write(" ocol0 = texcol.bbbb;\n");
break;
case EFBCopyFormat::GB8: // Z16L - copy lower 16 depth bits
// expected to be used as an IA8 texture (upper 8 bits stored as intensity, lower 8 bits
// stored as alpha)
// Used e.g. in Zelda: Skyward Sword
out.WriteFmt(" ocol0 = texcol.gggb;\n");
out.Write(" ocol0 = texcol.gggb;\n");
break;
default:
ERROR_LOG(VIDEO, "Unknown copy zbuf format: 0x%X", static_cast<int>(uid_data->dst_format));
out.WriteFmt(" ocol0 = float4(texcol.bgr, 0.0);\n");
out.Write(" ocol0 = float4(texcol.bgr, 0.0);\n");
break;
}
}
@@ -229,99 +229,99 @@ ShaderCode GeneratePixelShader(APIType api_type, const UidData* uid_data)
case EFBCopyFormat::RA4: // IA4
case EFBCopyFormat::RA8: // IA8
if (has_four_bits)
out.WriteFmt(" texcol = float4(int4(texcol * 255.0) & 0xF0) * (1.0 / 240.0);\n");
out.Write(" texcol = float4(int4(texcol * 255.0) & 0xF0) * (1.0 / 240.0);\n");
// TODO - verify these coefficients
out.WriteFmt(" const float3 coefficients = float3(0.257, 0.504, 0.098);\n"
" float intensity = dot(texcol.rgb, coefficients) + 16.0 / 255.0;\n"
" ocol0 = float4(intensity, intensity, intensity, {});\n",
has_alpha ? "texcol.a" : "intensity");
out.Write(" const float3 coefficients = float3(0.257, 0.504, 0.098);\n"
" float intensity = dot(texcol.rgb, coefficients) + 16.0 / 255.0;\n"
" ocol0 = float4(intensity, intensity, intensity, {});\n",
has_alpha ? "texcol.a" : "intensity");
break;
default:
ERROR_LOG(VIDEO, "Unknown copy intensity format: 0x%X",
static_cast<int>(uid_data->dst_format));
out.WriteFmt(" ocol0 = texcol;\n");
out.Write(" ocol0 = texcol;\n");
break;
}
}
else
{
if (!uid_data->efb_has_alpha)
out.WriteFmt(" texcol.a = 1.0;\n");
out.Write(" texcol.a = 1.0;\n");
switch (uid_data->dst_format)
{
case EFBCopyFormat::R4: // R4
out.WriteFmt(" float red = float(int(texcol.r * 255.0) & 0xF0) * (1.0 / 240.0);\n"
" ocol0 = float4(red, red, red, red);\n");
out.Write(" float red = float(int(texcol.r * 255.0) & 0xF0) * (1.0 / 240.0);\n"
" ocol0 = float4(red, red, red, red);\n");
break;
case EFBCopyFormat::R8_0x1: // R8
case EFBCopyFormat::R8: // R8
out.WriteFmt(" ocol0 = texcol.rrrr;\n");
out.Write(" ocol0 = texcol.rrrr;\n");
break;
case EFBCopyFormat::RA4: // RA4
out.WriteFmt(" float2 red_alpha = float2(int2(texcol.ra * 255.0) & 0xF0) * (1.0 / 240.0);\n"
" ocol0 = red_alpha.rrrg;\n");
out.Write(" float2 red_alpha = float2(int2(texcol.ra * 255.0) & 0xF0) * (1.0 / 240.0);\n"
" ocol0 = red_alpha.rrrg;\n");
break;
case EFBCopyFormat::RA8: // RA8
out.WriteFmt(" ocol0 = texcol.rrra;\n");
out.Write(" ocol0 = texcol.rrra;\n");
break;
case EFBCopyFormat::A8: // A8
out.WriteFmt(" ocol0 = texcol.aaaa;\n");
out.Write(" ocol0 = texcol.aaaa;\n");
break;
case EFBCopyFormat::G8: // G8
out.WriteFmt(" ocol0 = texcol.gggg;\n");
out.Write(" ocol0 = texcol.gggg;\n");
break;
case EFBCopyFormat::B8: // B8
out.WriteFmt(" ocol0 = texcol.bbbb;\n");
out.Write(" ocol0 = texcol.bbbb;\n");
break;
case EFBCopyFormat::RG8: // RG8
out.WriteFmt(" ocol0 = texcol.rrrg;\n");
out.Write(" ocol0 = texcol.rrrg;\n");
break;
case EFBCopyFormat::GB8: // GB8
out.WriteFmt(" ocol0 = texcol.gggb;\n");
out.Write(" ocol0 = texcol.gggb;\n");
break;
case EFBCopyFormat::RGB565: // RGB565
out.WriteFmt(" float2 red_blue = float2(int2(texcol.rb * 255.0) & 0xF8) * (1.0 / 248.0);\n"
" float green = float(int(texcol.g * 255.0) & 0xFC) * (1.0 / 252.0);\n"
" ocol0 = float4(red_blue.r, green, red_blue.g, 1.0);\n");
out.Write(" float2 red_blue = float2(int2(texcol.rb * 255.0) & 0xF8) * (1.0 / 248.0);\n"
" float green = float(int(texcol.g * 255.0) & 0xFC) * (1.0 / 252.0);\n"
" ocol0 = float4(red_blue.r, green, red_blue.g, 1.0);\n");
break;
case EFBCopyFormat::RGB5A3: // RGB5A3
// TODO: The MSB controls whether we have RGB5 or RGB4A3, this selection
// will need to be implemented once we move away from floats.
out.WriteFmt(" float3 color = float3(int3(texcol.rgb * 255.0) & 0xF8) * (1.0 / 248.0);\n"
" float alpha = float(int(texcol.a * 255.0) & 0xE0) * (1.0 / 224.0);\n"
" ocol0 = float4(color, alpha);\n");
out.Write(" float3 color = float3(int3(texcol.rgb * 255.0) & 0xF8) * (1.0 / 248.0);\n"
" float alpha = float(int(texcol.a * 255.0) & 0xE0) * (1.0 / 224.0);\n"
" ocol0 = float4(color, alpha);\n");
break;
case EFBCopyFormat::RGBA8: // RGBA8
out.WriteFmt(" ocol0 = texcol;\n");
out.Write(" ocol0 = texcol;\n");
break;
case EFBCopyFormat::XFB:
out.WriteFmt(
out.Write(
" ocol0 = float4(pow(texcol.rgb, float3(gamma_rcp, gamma_rcp, gamma_rcp)), 1.0f);\n");
break;
default:
ERROR_LOG(VIDEO, "Unknown copy color format: 0x%X", static_cast<int>(uid_data->dst_format));
out.WriteFmt(" ocol0 = texcol;\n");
out.Write(" ocol0 = texcol;\n");
break;
}
}
out.WriteFmt("}}\n");
out.Write("}}\n");
return out;
}
+149 -154
View File
@@ -18,14 +18,13 @@ void WriteUberShaderCommonHeader(ShaderCode& out, APIType api_type,
// ==============================================
if (!host_config.backend_bitfield)
{
out.WriteFmt(
"uint bitfieldExtract(uint val, int off, int size) {{\n"
" // This built-in function is only support in OpenGL 4.0+ and ES 3.1+\n"
" // Microsoft's HLSL compiler automatically optimises this to a bitfield extract "
"instruction.\n"
" uint mask = uint((1 << size) - 1);\n"
" return uint(val >> off) & mask;\n"
"}}\n\n");
out.Write("uint bitfieldExtract(uint val, int off, int size) {{\n"
" // This built-in function is only support in OpenGL 4.0+ and ES 3.1+\n"
" // Microsoft's HLSL compiler automatically optimises this to a bitfield extract "
"instruction.\n"
" uint mask = uint((1 << size) - 1);\n"
" return uint(val >> off) & mask;\n"
"}}\n\n");
}
}
@@ -34,61 +33,60 @@ void WriteLightingFunction(ShaderCode& out)
// ==============================================
// Lighting channel calculation helper
// ==============================================
out.WriteFmt("int4 CalculateLighting(uint index, uint attnfunc, uint diffusefunc, float3 pos, "
"float3 normal) {{\n"
" float3 ldir, h, cosAttn, distAttn;\n"
" float dist, dist2, attn;\n"
"\n"
" switch (attnfunc) {{\n");
out.WriteFmt(" case {}u: // LIGNTATTN_NONE\n", LIGHTATTN_NONE);
out.WriteFmt(" case {}u: // LIGHTATTN_DIR\n", LIGHTATTN_DIR);
out.WriteFmt(" ldir = normalize(" I_LIGHTS "[index].pos.xyz - pos.xyz);\n"
" attn = 1.0;\n"
" if (length(ldir) == 0.0)\n"
" ldir = normal;\n"
" break;\n\n");
out.WriteFmt(" case {}u: // LIGHTATTN_SPEC\n", LIGHTATTN_SPEC);
out.WriteFmt(" ldir = normalize(" I_LIGHTS "[index].pos.xyz - pos.xyz);\n"
" attn = (dot(normal, ldir) >= 0.0) ? max(0.0, dot(normal, " I_LIGHTS
"[index].dir.xyz)) : 0.0;\n"
" cosAttn = " I_LIGHTS "[index].cosatt.xyz;\n");
out.WriteFmt(" if (diffusefunc == {}u) // LIGHTDIF_NONE\n", LIGHTDIF_NONE);
out.WriteFmt(" distAttn = " I_LIGHTS "[index].distatt.xyz;\n"
" else\n"
" distAttn = normalize(" I_LIGHTS "[index].distatt.xyz);\n"
" attn = max(0.0, dot(cosAttn, float3(1.0, attn, attn*attn))) / dot(distAttn, "
"float3(1.0, attn, attn*attn));\n"
" break;\n\n");
out.WriteFmt(" case {}u: // LIGHTATTN_SPOT\n", LIGHTATTN_SPOT);
out.WriteFmt(" ldir = " I_LIGHTS "[index].pos.xyz - pos.xyz;\n"
" dist2 = dot(ldir, ldir);\n"
" dist = sqrt(dist2);\n"
" ldir = ldir / dist;\n"
" attn = max(0.0, dot(ldir, " I_LIGHTS "[index].dir.xyz));\n"
" attn = max(0.0, " I_LIGHTS "[index].cosatt.x + " I_LIGHTS
"[index].cosatt.y * attn + " I_LIGHTS
"[index].cosatt.z * attn * attn) / dot(" I_LIGHTS
"[index].distatt.xyz, float3(1.0, dist, dist2));\n"
" break;\n\n");
out.WriteFmt(" default:\n"
" attn = 1.0;\n"
" ldir = normal;\n"
" break;\n"
" }}\n"
"\n"
" switch (diffusefunc) {{\n");
out.WriteFmt(" case {}u: // LIGHTDIF_NONE\n", LIGHTDIF_NONE);
out.WriteFmt(" return int4(round(attn * float4(" I_LIGHTS "[index].color)));\n\n");
out.WriteFmt(" case {}u: // LIGHTDIF_SIGN\n", LIGHTDIF_SIGN);
out.WriteFmt(" return int4(round(attn * dot(ldir, normal) * float4(" I_LIGHTS
"[index].color)));\n\n");
out.WriteFmt(" case {}u: // LIGHTDIF_CLAMP\n", LIGHTDIF_CLAMP);
out.WriteFmt(" return int4(round(attn * max(0.0, dot(ldir, normal)) * float4(" I_LIGHTS
"[index].color)));\n\n");
out.WriteFmt(" default:\n"
" return int4(0, 0, 0, 0);\n"
" }}\n"
"}}\n\n");
out.Write("int4 CalculateLighting(uint index, uint attnfunc, uint diffusefunc, float3 pos, "
"float3 normal) {{\n"
" float3 ldir, h, cosAttn, distAttn;\n"
" float dist, dist2, attn;\n"
"\n"
" switch (attnfunc) {{\n");
out.Write(" case {}u: // LIGNTATTN_NONE\n", LIGHTATTN_NONE);
out.Write(" case {}u: // LIGHTATTN_DIR\n", LIGHTATTN_DIR);
out.Write(" ldir = normalize(" I_LIGHTS "[index].pos.xyz - pos.xyz);\n"
" attn = 1.0;\n"
" if (length(ldir) == 0.0)\n"
" ldir = normal;\n"
" break;\n\n");
out.Write(" case {}u: // LIGHTATTN_SPEC\n", LIGHTATTN_SPEC);
out.Write(" ldir = normalize(" I_LIGHTS "[index].pos.xyz - pos.xyz);\n"
" attn = (dot(normal, ldir) >= 0.0) ? max(0.0, dot(normal, " I_LIGHTS
"[index].dir.xyz)) : 0.0;\n"
" cosAttn = " I_LIGHTS "[index].cosatt.xyz;\n");
out.Write(" if (diffusefunc == {}u) // LIGHTDIF_NONE\n", LIGHTDIF_NONE);
out.Write(" distAttn = " I_LIGHTS "[index].distatt.xyz;\n"
" else\n"
" distAttn = normalize(" I_LIGHTS "[index].distatt.xyz);\n"
" attn = max(0.0, dot(cosAttn, float3(1.0, attn, attn*attn))) / dot(distAttn, "
"float3(1.0, attn, attn*attn));\n"
" break;\n\n");
out.Write(" case {}u: // LIGHTATTN_SPOT\n", LIGHTATTN_SPOT);
out.Write(" ldir = " I_LIGHTS "[index].pos.xyz - pos.xyz;\n"
" dist2 = dot(ldir, ldir);\n"
" dist = sqrt(dist2);\n"
" ldir = ldir / dist;\n"
" attn = max(0.0, dot(ldir, " I_LIGHTS "[index].dir.xyz));\n"
" attn = max(0.0, " I_LIGHTS "[index].cosatt.x + " I_LIGHTS
"[index].cosatt.y * attn + " I_LIGHTS "[index].cosatt.z * attn * attn) / dot(" I_LIGHTS
"[index].distatt.xyz, float3(1.0, dist, dist2));\n"
" break;\n\n");
out.Write(" default:\n"
" attn = 1.0;\n"
" ldir = normal;\n"
" break;\n"
" }}\n"
"\n"
" switch (diffusefunc) {{\n");
out.Write(" case {}u: // LIGHTDIF_NONE\n", LIGHTDIF_NONE);
out.Write(" return int4(round(attn * float4(" I_LIGHTS "[index].color)));\n\n");
out.Write(" case {}u: // LIGHTDIF_SIGN\n", LIGHTDIF_SIGN);
out.Write(" return int4(round(attn * dot(ldir, normal) * float4(" I_LIGHTS
"[index].color)));\n\n");
out.Write(" case {}u: // LIGHTDIF_CLAMP\n", LIGHTDIF_CLAMP);
out.Write(" return int4(round(attn * max(0.0, dot(ldir, normal)) * float4(" I_LIGHTS
"[index].color)));\n\n");
out.Write(" default:\n"
" return int4(0, 0, 0, 0);\n"
" }}\n"
"}}\n\n");
}
void WriteVertexLighting(ShaderCode& out, APIType api_type, std::string_view world_pos_var,
@@ -96,105 +94,102 @@ void WriteVertexLighting(ShaderCode& out, APIType api_type, std::string_view wor
std::string_view in_color_1_var, std::string_view out_color_0_var,
std::string_view out_color_1_var)
{
out.WriteFmt("// Lighting\n");
out.WriteFmt("{}for (uint chan = 0u; chan < {}u; chan++) {{\n",
api_type == APIType::D3D ? "[loop] " : "", NUM_XF_COLOR_CHANNELS);
out.WriteFmt(" uint colorreg = xfmem_color(chan);\n"
" uint alphareg = xfmem_alpha(chan);\n"
" int4 mat = " I_MATERIALS "[chan + 2u]; \n"
" int4 lacc = int4(255, 255, 255, 255);\n"
"\n");
out.Write("// Lighting\n");
out.Write("{}for (uint chan = 0u; chan < {}u; chan++) {{\n",
api_type == APIType::D3D ? "[loop] " : "", NUM_XF_COLOR_CHANNELS);
out.Write(" uint colorreg = xfmem_color(chan);\n"
" uint alphareg = xfmem_alpha(chan);\n"
" int4 mat = " I_MATERIALS "[chan + 2u]; \n"
" int4 lacc = int4(255, 255, 255, 255);\n"
"\n");
out.WriteFmt(" if ({} != 0u) {{\n", BitfieldExtract("colorreg", LitChannel().matsource));
out.WriteFmt(" if ((components & ({}u << chan)) != 0u) // VB_HAS_COL0\n", VB_HAS_COL0);
out.WriteFmt(" mat.xyz = int3(round(((chan == 0u) ? {}.xyz : {}.xyz) * 255.0));\n",
in_color_0_var, in_color_1_var);
out.WriteFmt(" else if ((components & {}u) != 0u) // VB_HAS_COLO0\n", VB_HAS_COL0);
out.WriteFmt(" mat.xyz = int3(round({}.xyz * 255.0));\n", in_color_0_var);
out.WriteFmt(" else\n"
" mat.xyz = int3(255, 255, 255);\n"
" }}\n"
"\n");
out.Write(" if ({} != 0u) {{\n", BitfieldExtract("colorreg", LitChannel().matsource));
out.Write(" if ((components & ({}u << chan)) != 0u) // VB_HAS_COL0\n", VB_HAS_COL0);
out.Write(" mat.xyz = int3(round(((chan == 0u) ? {}.xyz : {}.xyz) * 255.0));\n",
in_color_0_var, in_color_1_var);
out.Write(" else if ((components & {}u) != 0u) // VB_HAS_COLO0\n", VB_HAS_COL0);
out.Write(" mat.xyz = int3(round({}.xyz * 255.0));\n", in_color_0_var);
out.Write(" else\n"
" mat.xyz = int3(255, 255, 255);\n"
" }}\n"
"\n");
out.WriteFmt(" if ({} != 0u) {{\n", BitfieldExtract("alphareg", LitChannel().matsource));
out.WriteFmt(" if ((components & ({}u << chan)) != 0u) // VB_HAS_COL0\n", VB_HAS_COL0);
out.WriteFmt(" mat.w = int(round(((chan == 0u) ? {}.w : {}.w) * 255.0));\n", in_color_0_var,
in_color_1_var);
out.WriteFmt(" else if ((components & {}u) != 0u) // VB_HAS_COLO0\n", VB_HAS_COL0);
out.WriteFmt(" mat.w = int(round({}.w * 255.0));\n", in_color_0_var);
out.WriteFmt(" else\n"
" mat.w = 255;\n"
" }} else {{\n"
" mat.w = " I_MATERIALS " [chan + 2u].w;\n"
" }}\n"
"\n");
out.Write(" if ({} != 0u) {{\n", BitfieldExtract("alphareg", LitChannel().matsource));
out.Write(" if ((components & ({}u << chan)) != 0u) // VB_HAS_COL0\n", VB_HAS_COL0);
out.Write(" mat.w = int(round(((chan == 0u) ? {}.w : {}.w) * 255.0));\n", in_color_0_var,
in_color_1_var);
out.Write(" else if ((components & {}u) != 0u) // VB_HAS_COLO0\n", VB_HAS_COL0);
out.Write(" mat.w = int(round({}.w * 255.0));\n", in_color_0_var);
out.Write(" else\n"
" mat.w = 255;\n"
" }} else {{\n"
" mat.w = " I_MATERIALS " [chan + 2u].w;\n"
" }}\n"
"\n");
out.WriteFmt(" if ({} != 0u) {{\n", BitfieldExtract("colorreg", LitChannel().enablelighting));
out.WriteFmt(" if ({} != 0u) {{\n", BitfieldExtract("colorreg", LitChannel().ambsource));
out.WriteFmt(" if ((components & ({}u << chan)) != 0u) // VB_HAS_COL0\n", VB_HAS_COL0);
out.WriteFmt(" lacc.xyz = int3(round(((chan == 0u) ? {}.xyz : {}.xyz) * 255.0));\n",
in_color_0_var, in_color_1_var);
out.WriteFmt(" else if ((components & {}u) != 0u) // VB_HAS_COLO0\n", VB_HAS_COL0);
out.WriteFmt(" lacc.xyz = int3(round({}.xyz * 255.0));\n", in_color_0_var);
out.WriteFmt(" else\n"
" lacc.xyz = int3(255, 255, 255);\n"
" }} else {{\n"
" lacc.xyz = " I_MATERIALS " [chan].xyz;\n"
" }}\n"
"\n");
out.WriteFmt(" uint light_mask = {} | ({} << 4u);\n",
BitfieldExtract("colorreg", LitChannel().lightMask0_3),
BitfieldExtract("colorreg", LitChannel().lightMask4_7));
out.WriteFmt(" uint attnfunc = {};\n", BitfieldExtract("colorreg", LitChannel().attnfunc));
out.WriteFmt(" uint diffusefunc = {};\n",
BitfieldExtract("colorreg", LitChannel().diffusefunc));
out.WriteFmt(
out.Write(" if ({} != 0u) {{\n", BitfieldExtract("colorreg", LitChannel().enablelighting));
out.Write(" if ({} != 0u) {{\n", BitfieldExtract("colorreg", LitChannel().ambsource));
out.Write(" if ((components & ({}u << chan)) != 0u) // VB_HAS_COL0\n", VB_HAS_COL0);
out.Write(" lacc.xyz = int3(round(((chan == 0u) ? {}.xyz : {}.xyz) * 255.0));\n",
in_color_0_var, in_color_1_var);
out.Write(" else if ((components & {}u) != 0u) // VB_HAS_COLO0\n", VB_HAS_COL0);
out.Write(" lacc.xyz = int3(round({}.xyz * 255.0));\n", in_color_0_var);
out.Write(" else\n"
" lacc.xyz = int3(255, 255, 255);\n"
" }} else {{\n"
" lacc.xyz = " I_MATERIALS " [chan].xyz;\n"
" }}\n"
"\n");
out.Write(" uint light_mask = {} | ({} << 4u);\n",
BitfieldExtract("colorreg", LitChannel().lightMask0_3),
BitfieldExtract("colorreg", LitChannel().lightMask4_7));
out.Write(" uint attnfunc = {};\n", BitfieldExtract("colorreg", LitChannel().attnfunc));
out.Write(" uint diffusefunc = {};\n", BitfieldExtract("colorreg", LitChannel().diffusefunc));
out.Write(
" for (uint light_index = 0u; light_index < 8u; light_index++) {{\n"
" if ((light_mask & (1u << light_index)) != 0u)\n"
" lacc.xyz += CalculateLighting(light_index, attnfunc, diffusefunc, {}, {}).xyz;\n",
world_pos_var, normal_var);
out.WriteFmt(" }}\n"
" }}\n"
"\n");
out.Write(" }}\n"
" }}\n"
"\n");
out.WriteFmt(" if ({} != 0u) {{\n", BitfieldExtract("alphareg", LitChannel().enablelighting));
out.WriteFmt(" if ({} != 0u) {{\n", BitfieldExtract("alphareg", LitChannel().ambsource));
out.WriteFmt(" if ((components & ({}u << chan)) != 0u) // VB_HAS_COL0\n", VB_HAS_COL0);
out.WriteFmt(" lacc.w = int(round(((chan == 0u) ? {}.w : {}.w) * 255.0));\n",
in_color_0_var, in_color_1_var);
out.WriteFmt(" else if ((components & {}u) != 0u) // VB_HAS_COLO0\n", VB_HAS_COL0);
out.WriteFmt(" lacc.w = int(round({}.w * 255.0));\n", in_color_0_var);
out.WriteFmt(" else\n"
" lacc.w = 255;\n"
" }} else {{\n"
" lacc.w = " I_MATERIALS " [chan].w;\n"
" }}\n"
"\n");
out.WriteFmt(" uint light_mask = {} | ({} << 4u);\n",
BitfieldExtract("alphareg", LitChannel().lightMask0_3),
BitfieldExtract("alphareg", LitChannel().lightMask4_7));
out.WriteFmt(" uint attnfunc = {};\n", BitfieldExtract("alphareg", LitChannel().attnfunc));
out.WriteFmt(" uint diffusefunc = {};\n",
BitfieldExtract("alphareg", LitChannel().diffusefunc));
out.WriteFmt(
" for (uint light_index = 0u; light_index < 8u; light_index++) {{\n\n"
" if ((light_mask & (1u << light_index)) != 0u)\n\n"
" lacc.w += CalculateLighting(light_index, attnfunc, diffusefunc, {}, {}).w;\n",
world_pos_var, normal_var);
out.WriteFmt(" }}\n"
" }}\n"
"\n");
out.Write(" if ({} != 0u) {{\n", BitfieldExtract("alphareg", LitChannel().enablelighting));
out.Write(" if ({} != 0u) {{\n", BitfieldExtract("alphareg", LitChannel().ambsource));
out.Write(" if ((components & ({}u << chan)) != 0u) // VB_HAS_COL0\n", VB_HAS_COL0);
out.Write(" lacc.w = int(round(((chan == 0u) ? {}.w : {}.w) * 255.0));\n", in_color_0_var,
in_color_1_var);
out.Write(" else if ((components & {}u) != 0u) // VB_HAS_COLO0\n", VB_HAS_COL0);
out.Write(" lacc.w = int(round({}.w * 255.0));\n", in_color_0_var);
out.Write(" else\n"
" lacc.w = 255;\n"
" }} else {{\n"
" lacc.w = " I_MATERIALS " [chan].w;\n"
" }}\n"
"\n");
out.Write(" uint light_mask = {} | ({} << 4u);\n",
BitfieldExtract("alphareg", LitChannel().lightMask0_3),
BitfieldExtract("alphareg", LitChannel().lightMask4_7));
out.Write(" uint attnfunc = {};\n", BitfieldExtract("alphareg", LitChannel().attnfunc));
out.Write(" uint diffusefunc = {};\n", BitfieldExtract("alphareg", LitChannel().diffusefunc));
out.Write(" for (uint light_index = 0u; light_index < 8u; light_index++) {{\n\n"
" if ((light_mask & (1u << light_index)) != 0u)\n\n"
" lacc.w += CalculateLighting(light_index, attnfunc, diffusefunc, {}, {}).w;\n",
world_pos_var, normal_var);
out.Write(" }}\n"
" }}\n"
"\n");
out.WriteFmt(" lacc = clamp(lacc, 0, 255);\n"
"\n"
" // Hopefully GPUs that can support dynamic indexing will optimize this.\n"
" float4 lit_color = float4((mat * (lacc + (lacc >> 7))) >> 8) / 255.0;\n"
" switch (chan) {{\n"
" case 0u: {} = lit_color; break;\n",
out_color_0_var);
out.WriteFmt(" case 1u: {} = lit_color; break;\n", out_color_1_var);
out.WriteFmt(" }}\n"
"}}\n"
"\n");
out.Write(" lacc = clamp(lacc, 0, 255);\n"
"\n"
" // Hopefully GPUs that can support dynamic indexing will optimize this.\n"
" float4 lit_color = float4((mat * (lacc + (lacc >> 7))) >> 8) / 255.0;\n"
" switch (chan) {{\n"
" case 0u: {} = lit_color; break;\n",
out_color_0_var);
out.Write(" case 1u: {} = lit_color; break;\n", out_color_1_var);
out.Write(" }}\n"
"}}\n"
"\n");
}
} // namespace UberShader
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff