Académique Documents
Professionnel Documents
Culture Documents
#define ATTRIBUTE_LOCATION(x)
#define FRAGMENT_OUTPUT_LOCATION(x)
#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y)
#define UBO_BINDING(packing, x) layout(packing, binding = x)
#define SAMPLER_BINDING(x) layout(binding = x)
#define SSBO_BINDING(x) layout(binding = x)
#define VARYING_LOCATION(x)
struct Light {
int4 color;
float4 cosatt;
float4 distatt;
float4 pos;
float4 dir;
};
UBO_BINDING(std140, 2) uniform VSBlock {
uint components;
uint xfmem_dualTexInfo;
uint xfmem_numColorChans;
float4 cpnmtx[6];
float4 cproj[4];
int4 cmtrl[4];
Light clights[8];
float4 ctexmtx[24];
float4 ctrmtx[64];
float4 cnmtx[32];
float4 cpostmtx[64];
float4 cpixelcenter;
float2 cviewport;
uint4 xfmem_pack1[8];
#define xfmem_texMtxInfo(i) (xfmem_pack1[(i)].x)
#define xfmem_postMtxInfo(i) (xfmem_pack1[(i)].y)
#define xfmem_color(i) (xfmem_pack1[(i)].z)
#define xfmem_alpha(i) (xfmem_pack1[(i)].w)
};
struct VS_OUTPUT {
float4 pos;
float4 colors_0;
float4 colors_1;
float3 tex0;
float4 clipPos;
float3 Normal;
float3 WorldPos;
float clipDist0;
float clipDist1;
};
switch (attnfunc) {
case 0u: // LIGNTATTN_NONE
case 2u: // LIGHTATTN_DIR
ldir = normalize(clights[index].pos.xyz - pos.xyz);
attn = 1.0;
if (length(ldir) == 0.0)
ldir = normal;
break;
default:
attn = 1.0;
ldir = normal;
break;
}
switch (diffusefunc) {
case 0u: // LIGHTDIF_NONE
return int4(round(attn * float4(clights[index].color)));
default:
return int4(0, 0, 0, 0);
}
}
// Position matrix
float4 P0;
float4 P1;
float4 P2;
// Normal matrix
float3 N0;
float3 N1;
float3 N2;
// Lighting
for (uint chan = 0u; chan < 2u; chan++) {
uint colorreg = xfmem_color(chan);
uint alphareg = xfmem_alpha(chan);
int4 mat = cmtrl[chan + 2u];
int4 lacc = int4(255, 255, 255, 255);
if (bitfieldExtract(colorreg, 0, 1) != 0u) {
if ((components & (8192u << chan)) != 0u) // VB_HAS_COL0
mat.xyz = int3(round(((chan == 0u) ? rawcolor0.xyz : rawcolor1.xyz) *
255.0));
else if ((components & 8192u) != 0u) // VB_HAS_COLO0
mat.xyz = int3(round(rawcolor0.xyz * 255.0));
else
mat.xyz = int3(255, 255, 255);
}
if (bitfieldExtract(alphareg, 0, 1) != 0u) {
if ((components & (8192u << chan)) != 0u) // VB_HAS_COL0
mat.w = int(round(((chan == 0u) ? rawcolor0.w : rawcolor1.w) * 255.0));
else if ((components & 8192u) != 0u) // VB_HAS_COLO0
mat.w = int(round(rawcolor0.w * 255.0));
else
mat.w = 255;
} else {
mat.w = cmtrl [chan + 2u].w;
}
if (bitfieldExtract(colorreg, 1, 1) != 0u) {
if (bitfieldExtract(colorreg, 6, 1) != 0u) {
if ((components & (8192u << chan)) != 0u) // VB_HAS_COL0
lacc.xyz = int3(round(((chan == 0u) ? rawcolor0.xyz : rawcolor1.xyz) *
255.0));
else if ((components & 8192u) != 0u) // VB_HAS_COLO0
lacc.xyz = int3(round(rawcolor0.xyz * 255.0));
else
lacc.xyz = int3(255, 255, 255);
} else {
lacc.xyz = cmtrl [chan].xyz;
}
if (bitfieldExtract(alphareg, 1, 1) != 0u) {
if (bitfieldExtract(alphareg, 6, 1) != 0u) {
if ((components & (8192u << chan)) != 0u) // VB_HAS_COL0
lacc.w = int(round(((chan == 0u) ? rawcolor0.w : rawcolor1.w) * 255.0));
else if ((components & 8192u) != 0u) // VB_HAS_COLO0
lacc.w = int(round(rawcolor0.w * 255.0));
else
lacc.w = 255;
} else {
lacc.w = cmtrl [chan].w;
}
// Hopefully GPUs that can support dynamic indexing will optimize this.
float4 lit_color = float4((mat * (lacc + (lacc >> 7))) >> 8) / 255.0;
switch (chan) {
case 0u: o.colors_0 = lit_color; break;
case 1u: o.colors_1 = lit_color; break;
}
}
// first transformation
uint texgentype = bitfieldExtract(texMtxInfo, 4, 3);
float3 output_tex;
switch (texgentype)
{
case 1u: // XF_TEXGEN_EMBOSS_MAP
{
uint light = bitfieldExtract(texMtxInfo, 15, 3);
uint source = bitfieldExtract(texMtxInfo, 12, 3);
switch (source) {
case 0u: output_tex.xyz = o.tex0; break;
default: output_tex.xyz = float3(0.0, 0.0, 0.0); break;
}
if ((components & 6144u) != 0u) { // VB_HAS_NRM1 | VB_HAS_NRM2
float3 ldir = normalize(clights[light].pos.xyz - pos.xyz);
output_tex.xyz += float3(dot(ldir, _norm1), dot(ldir, _norm2), 0.0);
}
}
break;
if (bitfieldExtract(texMtxInfo, 1, 1) == 1u) {
output_tex.xyz = float3(dot(coord, ctrmtx[tmp]),
dot(coord, ctrmtx[tmp + 1]),
dot(coord, ctrmtx[tmp + 2]));
} else {
output_tex.xyz = float3(dot(coord, ctrmtx[tmp]),
dot(coord, ctrmtx[tmp + 1]),
1.0);
}
} else {
if (bitfieldExtract(texMtxInfo, 1, 1) == 1u) {
output_tex.xyz = float3(dot(coord, ctexmtx[3u * texgen]),
dot(coord, ctexmtx[3u * texgen + 1u]),
dot(coord, ctexmtx[3u * texgen + 2u]));
} else {
output_tex.xyz = float3(dot(coord, ctexmtx[3u * texgen]),
dot(coord, ctexmtx[3u * texgen + 1u]),
1.0);
}
}
}
break;
if (xfmem_dualTexInfo != 0u) {
uint postMtxInfo = xfmem_postMtxInfo(texgen); uint base_index =
bitfieldExtract(postMtxInfo, 0, 6);
float4 P0 = cpostmtx[base_index & 0x3fu];
float4 P1 = cpostmtx[(base_index + 1u) & 0x3fu];
float4 P2 = cpostmtx[(base_index + 2u) & 0x3fu];
if (bitfieldExtract(postMtxInfo, 8, 1) != 0u)
output_tex.xyz = normalize(output_tex.xyz);
// multiply by postmatrix
output_tex.xyz = float3(dot(P0.xyz, output_tex.xyz) + P0.w,
dot(P1.xyz, output_tex.xyz) + P1.w,
dot(P2.xyz, output_tex.xyz) + P2.w);
}
// Hopefully GPUs that can support dynamic indexing will optimize this.
switch (texgen) {
case 0u: o.tex0 = output_tex; break;
}
}
if (xfmem_numColorChans == 0u) {
if ((components & 8192u) != 0u)
o.colors_0 = rawcolor0;
else
o.colors_1 = float4(1.0, 1.0, 1.0, 1.0);
}
if (xfmem_numColorChans < 2u) {
if ((components & 16384u) != 0u)
o.colors_0 = rawcolor1;
else
o.colors_1 = float4(1.0, 1.0, 1.0, 1.0);
}
o.clipPos = o.pos;
o.Normal = _norm0;
o.WorldPos = pos.xyz;
if ((components & 8192u) != 0u) // VB_HAS_COL0
o.colors_0 = rawcolor0;
if ((components & 16384u) != 0u) // VB_HAS_COL1
o.colors_1 = rawcolor1;
float clipDepth = o.pos.z * (1.0 - 1e-7);
o.clipDist0 = clipDepth + o.pos.w;
o.clipDist1 = -clipDepth;
o.pos.z = o.pos.w * cpixelcenter.w - o.pos.z * cpixelcenter.z;
o.pos.xy *= sign(cpixelcenter.xy * float2(1.0, -1.0));
o.pos.xy = o.pos.xy - o.pos.w * cpixelcenter.xy;
vs.pos = o.pos;
vs.colors_0 = o.colors_0;
vs.colors_1 = o.colors_1;
vs.tex0 = o.tex0;
vs.clipPos = o.clipPos;
vs.Normal = o.Normal;
vs.WorldPos = o.WorldPos;
vs.clipDist0 = o.clipDist0;
vs.clipDist1 = o.clipDist1;
gl_ClipDistance[0] = o.clipDist0;
gl_ClipDistance[1] = o.clipDist1;
gl_Position = o.pos;
}
#version 430
#define ATTRIBUTE_LOCATION(x)
#define FRAGMENT_OUTPUT_LOCATION(x)
#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y)
#define UBO_BINDING(packing, x) layout(packing, binding = x)
#define SAMPLER_BINDING(x) layout(binding = x)
#define SSBO_BINDING(x) layout(binding = x)
#define VARYING_LOCATION(x)
struct Light {
int4 color;
float4 cosatt;
float4 distatt;
float4 pos;
float4 dir;
};
UBO_BINDING(std140, 2) uniform VSBlock {
uint components;
uint xfmem_dualTexInfo;
uint xfmem_numColorChans;
float4 cpnmtx[6];
float4 cproj[4];
int4 cmtrl[4];
Light clights[8];
float4 ctexmtx[24];
float4 ctrmtx[64];
float4 cnmtx[32];
float4 cpostmtx[64];
float4 cpixelcenter;
float2 cviewport;
uint4 xfmem_pack1[8];
#define xfmem_texMtxInfo(i) (xfmem_pack1[(i)].x)
#define xfmem_postMtxInfo(i) (xfmem_pack1[(i)].y)
#define xfmem_color(i) (xfmem_pack1[(i)].z)
#define xfmem_alpha(i) (xfmem_pack1[(i)].w)
};
struct VS_OUTPUT {
float4 pos;
float4 colors_0;
float4 colors_1;
float3 tex0;
float4 clipPos;
float3 Normal;
float3 WorldPos;
float clipDist0;
float clipDist1;
};
int4 CalculateLighting(uint index, uint attnfunc, uint diffusefunc, float3 pos,
float3 normal) {
float3 ldir, h, cosAttn, distAttn;
float dist, dist2, attn;
switch (attnfunc) {
case 0u: // LIGNTATTN_NONE
case 2u: // LIGHTATTN_DIR
ldir = normalize(clights[index].pos.xyz - pos.xyz);
attn = 1.0;
if (length(ldir) == 0.0)
ldir = normal;
break;
default:
attn = 1.0;
ldir = normal;
break;
}
switch (diffusefunc) {
case 0u: // LIGHTDIF_NONE
return int4(round(attn * float4(clights[index].color)));
default:
return int4(0, 0, 0, 0);
}
}
int4 ret;
ret.r = color[bitfieldExtract(bpmem_tevksel(s * 2u), 0, 2)];
ret.g = color[bitfieldExtract(bpmem_tevksel(s * 2u), 2, 2)];
ret.b = color[bitfieldExtract(bpmem_tevksel(s * 2u + 1u), 0, 2)];
ret.a = color[bitfieldExtract(bpmem_tevksel(s * 2u + 1u), 2, 2)];
return ret;
}
// Add bias to D
if (bias == 1u) D += 128;
else if (bias == 2u) D -= 128;
// Add/Subtract D
if(op) // Subtract
result = D - result;
else // Add
result = D + result;
// Most of the Shift was moved inside the lerp for improved percision
// But we still do the divide by 2 here
if (shift == 3u)
result = result >> 1;
return result;
}
// Add bias to D
if (bias == 1u) D += 128;
else if (bias == 2u) D -= 128;
// Add/Subtract D
if(op) // Subtract
result = D - result;
else // Add
result = D + result;
// Most of the Shift was moved inside the lerp for improved percision
// But we still do the divide by 2 here
if (shift == 3u)
result = result >> 1;
return result;
}
struct State {
int4 Reg[4];
int4 TexColor;
int AlphaBump;
};
struct StageState {
uint stage;
uint order;
uint cc;
uint ac;
};
FORCE_EARLY_Z;
void main()
{
float4 rawpos = gl_FragCoord;
int3 tevcoord = int3(0, 0, 0);
State s;
s.TexColor = int4(0, 0, 0, 0);
s.AlphaBump = 0;
s.Reg[0] = color[0];
s.Reg[1] = color[1];
s.Reg[2] = color[2];
s.Reg[3] = color[3];
float4 lit_colors_0 = colors_0;
float4 lit_colors_1 = colors_1;
float3 lit_normal = normalize(Normal.xyz);
float3 lit_pos = WorldPos.xyz;
// Lighting
for (uint chan = 0u; chan < 2u; chan++) {
uint colorreg = xfmem_color(chan);
uint alphareg = xfmem_alpha(chan);
int4 mat = cmtrl[chan + 2u];
int4 lacc = int4(255, 255, 255, 255);
if (bitfieldExtract(colorreg, 0, 1) != 0u) {
if ((components & (8192u << chan)) != 0u) // VB_HAS_COL0
mat.xyz = int3(round(((chan == 0u) ? colors_0.xyz : colors_1.xyz) * 255.0));
else if ((components & 8192u) != 0u) // VB_HAS_COLO0
mat.xyz = int3(round(colors_0.xyz * 255.0));
else
mat.xyz = int3(255, 255, 255);
}
if (bitfieldExtract(alphareg, 0, 1) != 0u) {
if ((components & (8192u << chan)) != 0u) // VB_HAS_COL0
mat.w = int(round(((chan == 0u) ? colors_0.w : colors_1.w) * 255.0));
else if ((components & 8192u) != 0u) // VB_HAS_COLO0
mat.w = int(round(colors_0.w * 255.0));
else
mat.w = 255;
} else {
mat.w = cmtrl [chan + 2u].w;
}
if (bitfieldExtract(colorreg, 1, 1) != 0u) {
if (bitfieldExtract(colorreg, 6, 1) != 0u) {
if ((components & (8192u << chan)) != 0u) // VB_HAS_COL0
lacc.xyz = int3(round(((chan == 0u) ? colors_0.xyz : colors_1.xyz) *
255.0));
else if ((components & 8192u) != 0u) // VB_HAS_COLO0
lacc.xyz = int3(round(colors_0.xyz * 255.0));
else
lacc.xyz = int3(255, 255, 255);
} else {
lacc.xyz = cmtrl [chan].xyz;
}
if (bitfieldExtract(alphareg, 1, 1) != 0u) {
if (bitfieldExtract(alphareg, 6, 1) != 0u) {
if ((components & (8192u << chan)) != 0u) // VB_HAS_COL0
lacc.w = int(round(((chan == 0u) ? colors_0.w : colors_1.w) * 255.0));
else if ((components & 8192u) != 0u) // VB_HAS_COLO0
lacc.w = int(round(colors_0.w * 255.0));
else
lacc.w = 255;
} else {
lacc.w = cmtrl [chan].w;
}
// Hopefully GPUs that can support dynamic indexing will optimize this.
float4 lit_color = float4((mat * (lacc + (lacc >> 7))) >> 8) / 255.0;
switch (chan) {
case 0u: lit_colors_0 = lit_color; break;
case 1u: lit_colors_1 = lit_color; break;
}
}
// Indirect textures
uint tevind = bpmem_tevind(stage);
if (tevind != 0u)
{
uint bs = bitfieldExtract(tevind, 7, 2);
uint fmt = bitfieldExtract(tevind, 2, 2);
uint bias = bitfieldExtract(tevind, 4, 3);
uint bt = bitfieldExtract(tevind, 0, 2);
uint mid = bitfieldExtract(tevind, 9, 4);
int3 indcoord;
{
uint iref = bpmem_iref(bt);
if ( iref != 0u)
{
uint texcoord = bitfieldExtract(iref, 0, 3);
uint texmap = bitfieldExtract(iref, 8, 3);
float3 uv = getTexCoord(texcoord);
int2 fixedPoint_uv = int2((uv.z == 0.0 ? uv.xy : (uv.xy / uv.z)) *
texdim[texcoord].zw);
// Matrix multiply
int2 indtevtrans = int2(0, 0);
if ((mid & 3u) != 0u)
{
uint mtxidx = 2u * ((mid & 3u) - 1u);
int shift = cindmtx[mtxidx].w;
if (shift >= 0)
indtevtrans = indtevtrans >> shift;
else
indtevtrans = indtevtrans << ((-shift) & 31);
}
// Wrapping
uint sw = bitfieldExtract(tevind, 13, 3);
uint tw = bitfieldExtract(tevind, 16, 3);
int2 wrapped_coord = int2(Wrap(fixedPoint_uv.x, sw), Wrap(fixedPoint_uv.y,
tw));
int3 color;
if(color_bias != 3u) { // Normal mode
color = tevLerp3(color_A, color_B, color_C, color_D, color_bias, color_op,
false, color_shift);
} else { // Compare mode
// op 6 and 7 do a select per color channel
if (color_compare_op == 6u) {
// TEVCMP_RGB8_GT
color.r = (color_A.r > color_B.r) ? color_C.r : 0;
color.g = (color_A.g > color_B.g) ? color_C.g : 0;
color.b = (color_A.b > color_B.b) ? color_C.b : 0;
} else if (color_compare_op == 7u) {
// TEVCMP_RGB8_EQ
color.r = (color_A.r == color_B.r) ? color_C.r : 0;
color.g = (color_A.g == color_B.g) ? color_C.g : 0;
color.b = (color_A.b == color_B.b) ? color_C.b : 0;
} else {
// The remaining ops do one compare which selects all 3 channels
color = tevCompare(color_compare_op, color_A, color_B) ? color_C :
int3(0, 0, 0);
}
color = color_D + color;
}
// Clamp result
if (color_clamp)
color = clamp(color, 0, 255);
else
color = clamp(color, -1024, 1023);
// Alpha Combiner
uint alpha_a = bitfieldExtract(ss.ac, 13, 3);
uint alpha_b = bitfieldExtract(ss.ac, 10, 3);
uint alpha_c = bitfieldExtract(ss.ac, 7, 3);
uint alpha_d = bitfieldExtract(ss.ac, 4, 3);
uint alpha_bias = bitfieldExtract(ss.ac, 16, 2);
bool alpha_op = bool(bitfieldExtract(ss.ac, 18, 1));
bool alpha_clamp = bool(bitfieldExtract(ss.ac, 19, 1));
uint alpha_shift = bitfieldExtract(ss.ac, 20, 2);
uint alpha_dest = bitfieldExtract(ss.ac, 22, 2);
uint alpha_compare_op = alpha_shift << 1 | uint(alpha_op);
int alpha_A;
int alpha_B;
if (alpha_bias != 3u || alpha_compare_op > 5u) {
// Small optimisation here: alpha_A and alpha_B are unused by compare ops
0-5
alpha_A = selectAlphaInput(s, ss, lit_colors_0, lit_colors_1, alpha_a) &
255;
alpha_B = selectAlphaInput(s, ss, lit_colors_0, lit_colors_1, alpha_b) &
255;
};
int alpha_C = selectAlphaInput(s, ss, lit_colors_0, lit_colors_1, alpha_c) &
255;
int alpha_D = selectAlphaInput(s, ss, lit_colors_0, lit_colors_1,
alpha_d); // 10 bits + sign
int alpha;
if(alpha_bias != 3u) { // Normal mode
alpha = tevLerp(alpha_A, alpha_B, alpha_C, alpha_D, alpha_bias, alpha_op,
true, alpha_shift);
} else { // Compare mode
if (alpha_compare_op == 6u) {
// TEVCMP_A8_GT
alpha = (alpha_A > alpha_B) ? alpha_C : 0;
} else if (alpha_compare_op == 7u) {
// TEVCMP_A8_EQ
alpha = (alpha_A == alpha_B) ? alpha_C : 0;
} else {
// All remaining alpha compare ops actually compare the color channels
alpha = tevCompare(alpha_compare_op, color_A, color_B) ? alpha_C : 0;
}
alpha = alpha_D + alpha;
}
// Clamp result
if (alpha_clamp)
alpha = clamp(alpha, 0, 255);
else
alpha = clamp(alpha, -1024, 1023);
int4 TevResult;
TevResult.xyz = getTevReg(s, bitfieldExtract(bpmem_combiners(num_stages).x, 22,
2)).xyz;
TevResult.w = getTevReg(s, bitfieldExtract(bpmem_combiners(num_stages).y, 22,
2)).w;
TevResult &= 255;
// Depth Texture
int early_zCoord = zCoord;
if (bpmem_ztex_op != 0u) {
int ztex = int(czbias[1].w); // fixed bias
// Whatever texture was in our last stage, it's now our depth texture
ztex += idot(s.TexColor.xyzw, czbias[0].xyzw);
ztex += (bpmem_ztex_op == 1u) ? zCoord : 0;
zCoord = ztex & 0xFFFFFF;
}
// Alpha Test
if (bpmem_alphaTest != 0u) {
bool comp0 = alphaCompare(TevResult.a, alphaRef.r,
bitfieldExtract(bpmem_alphaTest, 16, 3));
bool comp1 = alphaCompare(TevResult.a, alphaRef.g,
bitfieldExtract(bpmem_alphaTest, 19, 3));
// These if statements are written weirdly to work around intel and qualcom
bugs with handling booleans.
switch (bitfieldExtract(bpmem_alphaTest, 22, 2)) {
case 0u: // AND
if (comp0 && comp1) break; else discard; break;
case 1u: // OR
if (comp0 || comp1) break; else discard; break;
case 2u: // XOR
if (comp0 != comp1) break; else discard; break;
case 3u: // XNOR
if (comp0 == comp1) break; else discard; break;
}
}
if (bpmem_dither) {
// Flipper uses a standard 2x2 Bayer Matrix for 6 bit dithering
// Here the matrix is encoded into the two factor constants
int2 dither = int2(rawpos.xy) & 1;
TevResult.rgb = (TevResult.rgb - (TevResult.rgb >> 6)) + abs(dither.y * 3 -
dither.x * 2);
}
// Fog
uint fog_function = bitfieldExtract(bpmem_fogParam3, 21, 3);
if (fog_function != 0u) {
// TODO: This all needs to be converted from float to fixed point
float ze;
if (bitfieldExtract(bpmem_fogParam3, 20, 1) == 0u) {
// perspective
// ze = A/(B - (Zs >> B_SHF)
ze = (cfogf.x * 16777216.0) / float(cfogi.y - (zCoord >> cfogi.w));
} else {
// orthographic
// ze = a*Zs (here, no B_SHF)
ze = cfogf.z * float(zCoord) / 16777216.0;
}
if (bpmem_rgba6_format)
ocol0.rgb = float3(TevResult.rgb >> 2) / 63.0;
else
ocol0.rgb = float3(TevResult.rgb) / 255.0;
if (bpmem_dstalpha != 0u)
ocol0.a = float(bitfieldExtract(bpmem_dstalpha, 0, 8) >> 2) / 63.0;
else
ocol0.a = float(TevResult.a >> 2) / 63.0;
#define ATTRIBUTE_LOCATION(x)
#define FRAGMENT_OUTPUT_LOCATION(x)
#define FRAGMENT_OUTPUT_LOCATION_INDEXED(x, y)
#define UBO_BINDING(packing, x) layout(packing, binding = x)
#define SAMPLER_BINDING(x) layout(binding = x)
#define SSBO_BINDING(x) layout(binding = x)
#define VARYING_LOCATION(x)
Fragment info
-------------
0(758) : warning C7050: "alpha_A" might be used before being initialized
0(759) : warning C7050: "alpha_B" might be used before being initialized
#