mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-04-20 22:05:12 +00:00
split rpcs3 and hle libraries
merge rpcs3 utilities
This commit is contained in:
parent
b33e2662b6
commit
62ad27d1e2
1233 changed files with 7004 additions and 3819 deletions
867
rpcs3/Emu/RSX/Program/GLSLInterpreter/FragmentInterpreter.glsl
Normal file
867
rpcs3/Emu/RSX/Program/GLSLInterpreter/FragmentInterpreter.glsl
Normal file
|
|
@ -0,0 +1,867 @@
|
|||
R"(
|
||||
layout(location=0) out vec4 ocol0;
|
||||
layout(location=1) out vec4 ocol1;
|
||||
layout(location=2) out vec4 ocol2;
|
||||
layout(location=3) out vec4 ocol3;
|
||||
|
||||
layout(location=0) in vec4 in_regs[16];
|
||||
|
||||
#define RSX_FP_OPCODE_NOP 0x00 // No-Operation
|
||||
#define RSX_FP_OPCODE_MOV 0x01 // Move
|
||||
#define RSX_FP_OPCODE_MUL 0x02 // Multiply
|
||||
#define RSX_FP_OPCODE_ADD 0x03 // Add
|
||||
#define RSX_FP_OPCODE_MAD 0x04 // Multiply-Add
|
||||
#define RSX_FP_OPCODE_DP3 0x05 // 3-component Dot Product
|
||||
#define RSX_FP_OPCODE_DP4 0x06 // 4-component Dot Product
|
||||
#define RSX_FP_OPCODE_DST 0x07 // Distance
|
||||
#define RSX_FP_OPCODE_MIN 0x08 // Minimum
|
||||
#define RSX_FP_OPCODE_MAX 0x09 // Maximum
|
||||
#define RSX_FP_OPCODE_SLT 0x0A // Set-If-LessThan
|
||||
#define RSX_FP_OPCODE_SGE 0x0B // Set-If-GreaterEqual
|
||||
#define RSX_FP_OPCODE_SLE 0x0C // Set-If-LessEqual
|
||||
#define RSX_FP_OPCODE_SGT 0x0D // Set-If-GreaterThan
|
||||
#define RSX_FP_OPCODE_SNE 0x0E // Set-If-NotEqual
|
||||
#define RSX_FP_OPCODE_SEQ 0x0F // Set-If-Equal
|
||||
#define RSX_FP_OPCODE_FRC 0x10 // Fraction (fract)
|
||||
#define RSX_FP_OPCODE_FLR 0x11 // Floor
|
||||
#define RSX_FP_OPCODE_KIL 0x12 // Kill fragment
|
||||
#define RSX_FP_OPCODE_PK4 0x13 // Pack four signed 8-bit values
|
||||
#define RSX_FP_OPCODE_UP4 0x14 // Unpack four signed 8-bit values
|
||||
#define RSX_FP_OPCODE_DDX 0x15 // Partial-derivative in x (Screen space derivative w.r.t. x)
|
||||
#define RSX_FP_OPCODE_DDY 0x16 // Partial-derivative in y (Screen space derivative w.r.t. y)
|
||||
#define RSX_FP_OPCODE_TEX 0x17 // Texture lookup
|
||||
#define RSX_FP_OPCODE_TXP 0x18 // Texture sample with projection (Projective texture lookup)
|
||||
#define RSX_FP_OPCODE_TXD 0x19 // Texture sample with partial differentiation (Texture lookup with derivatives)
|
||||
#define RSX_FP_OPCODE_RCP 0x1A // Reciprocal
|
||||
#define RSX_FP_OPCODE_RSQ 0x1B // Reciprocal Square Root
|
||||
#define RSX_FP_OPCODE_EX2 0x1C // Exponentiation base 2
|
||||
#define RSX_FP_OPCODE_LG2 0x1D // Log base 2
|
||||
#define RSX_FP_OPCODE_LIT 0x1E // Lighting coefficients
|
||||
#define RSX_FP_OPCODE_LRP 0x1F // Linear Interpolation
|
||||
#define RSX_FP_OPCODE_STR 0x20 // Set-If-True
|
||||
#define RSX_FP_OPCODE_SFL 0x21 // Set-If-False
|
||||
#define RSX_FP_OPCODE_COS 0x22 // Cosine
|
||||
#define RSX_FP_OPCODE_SIN 0x23 // Sine
|
||||
#define RSX_FP_OPCODE_PK2 0x24 // Pack two 16-bit floats
|
||||
#define RSX_FP_OPCODE_UP2 0x25 // Unpack two 16-bit floats
|
||||
#define RSX_FP_OPCODE_POW 0x26 // Power
|
||||
#define RSX_FP_OPCODE_PKB 0x27 // Pack bytes
|
||||
#define RSX_FP_OPCODE_UPB 0x28 // Unpack bytes
|
||||
#define RSX_FP_OPCODE_PK16 0x29 // Pack 16 bits
|
||||
#define RSX_FP_OPCODE_UP16 0x2A // Unpack 16
|
||||
#define RSX_FP_OPCODE_BEM 0x2B // Bump-environment map (a.k.a. 2D coordinate transform)
|
||||
#define RSX_FP_OPCODE_PKG 0x2C // Pack with sRGB transformation
|
||||
#define RSX_FP_OPCODE_UPG 0x2D // Unpack gamma
|
||||
#define RSX_FP_OPCODE_DP2A 0x2E // 2-component dot product with scalar addition
|
||||
#define RSX_FP_OPCODE_TXL 0x2F // Texture sample with explicit LOD
|
||||
#define RSX_FP_OPCODE_TXB 0x31 // Texture sample with bias
|
||||
#define RSX_FP_OPCODE_TEXBEM 0x33
|
||||
#define RSX_FP_OPCODE_TXPBEM 0x34
|
||||
#define RSX_FP_OPCODE_BEMLUM 0x35
|
||||
#define RSX_FP_OPCODE_REFL 0x36 // Reflection vector
|
||||
#define RSX_FP_OPCODE_TIMESWTEX 0x37
|
||||
#define RSX_FP_OPCODE_DP2 0x38 // 2-component dot product
|
||||
#define RSX_FP_OPCODE_NRM 0x39 // Normalize
|
||||
#define RSX_FP_OPCODE_DIV 0x3A // Division
|
||||
#define RSX_FP_OPCODE_DIVSQ 0x3B // Divide by Square Root
|
||||
#define RSX_FP_OPCODE_LIF 0x3C // Final part of LIT
|
||||
#define RSX_FP_OPCODE_FENCT 0x3D // Fence T?
|
||||
#define RSX_FP_OPCODE_FENCB 0x3E // Fence B?
|
||||
#define RSX_FP_OPCODE_BRK 0x40 // Break
|
||||
#define RSX_FP_OPCODE_CAL 0x41 // Subroutine call
|
||||
#define RSX_FP_OPCODE_IFE 0x42 // If
|
||||
#define RSX_FP_OPCODE_LOOP 0x43 // Loop
|
||||
#define RSX_FP_OPCODE_REP 0x44 // Repeat
|
||||
#define RSX_FP_OPCODE_RET 0x45 // Return
|
||||
|
||||
#define EXEC_LT 1
|
||||
#define EXEC_EQ 2
|
||||
#define EXEC_GT 4
|
||||
|
||||
#define RSX_FP_REGISTER_TYPE_TEMP 0
|
||||
#define RSX_FP_REGISTER_TYPE_INPUT 1
|
||||
#define RSX_FP_REGISTER_TYPE_CONSTANT 2
|
||||
#define RSX_FP_REGISTER_TYPE_UNKNOWN 3
|
||||
|
||||
#define CELL_GCM_SHADER_CONTROL_DEPTH_EXPORT 0xe
|
||||
#define CELL_GCM_SHADER_CONTROL_32_BITS_EXPORTS 0x40
|
||||
|
||||
#define GET_BITS(bitfield, offset, count) bitfieldExtract(bitfield, offset, count)
|
||||
#define TEST_BIT(bitfield, offset) (GET_BITS(bitfield, offset, 1) > 0)
|
||||
|
||||
#define GET_INST_BITS(word, offset, count) GET_BITS(inst.words[word], offset, count)
|
||||
#define TEST_INST_BIT(word, offset) (GET_INST_BITS(word, offset, 1) > 0)
|
||||
|
||||
#define select mix
|
||||
#define reg_mov(d, s, m) d = select(d, s, m)
|
||||
|
||||
// GPR set
|
||||
vec4 vr0, vr1; // GP vector register
|
||||
uint ur0, ur1; // GP unsigned register (scalar)
|
||||
uvec4 uvr0; // GP unsigned register (vector)
|
||||
bvec4 bvr0, bvr1; // GP boolean register (vector)
|
||||
float sr0; // GP scalar register
|
||||
|
||||
vec4 vrr; // value return (dst register)
|
||||
vec4 s0, s1, s2; // instruction src (src0, src1, src2)
|
||||
|
||||
vec4 wpos; // window position register WPOS
|
||||
vec4 fogc; // Fog coordinate register FOGC
|
||||
|
||||
const vec4 vr_zero = vec4(0.);
|
||||
const vec4 vr_one = vec4(1.);
|
||||
|
||||
bool shader_attribute(const in uint mask)
|
||||
{
|
||||
return (shader_control & mask) != 0;
|
||||
}
|
||||
|
||||
vec4 _distance(const in vec4 a, const in vec4 b)
|
||||
{
|
||||
// Old-school distance vector
|
||||
return vec4(1., a.y * b.y, a.z, b.w);
|
||||
}
|
||||
|
||||
vec4 shuffle(const in vec4 value, const in uint code)
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case 0xE4:
|
||||
return value;
|
||||
case 0x24:
|
||||
return value.xyzx;
|
||||
case 0xA4:
|
||||
return value.xyzz;
|
||||
case 0x00:
|
||||
return value.xxxx;
|
||||
case 0x55:
|
||||
return value.yyyy;
|
||||
case 0xAA:
|
||||
return value.zzzz;
|
||||
case 0xFF:
|
||||
return value.wwww;
|
||||
case 0x04:
|
||||
return value.xyxx;
|
||||
default:
|
||||
uint x = bitfieldExtract(code, 0, 2);
|
||||
uint y = bitfieldExtract(code, 2, 2);
|
||||
uint z = bitfieldExtract(code, 4, 2);
|
||||
uint w = bitfieldExtract(code, 6, 2);
|
||||
return vec4(value[x], value[y], value[z], value[w]);
|
||||
}
|
||||
}
|
||||
|
||||
struct instruction_t
|
||||
{
|
||||
uvec4 words;
|
||||
uint opcode;
|
||||
bool end;
|
||||
};
|
||||
|
||||
const float modifier_scale[] = {1.f, 2.f, 4.f, 8.f, 1.f, 0.5f, 0.25f, 0.125f};
|
||||
|
||||
vec4 regs16[48];
|
||||
vec4 regs32[48];
|
||||
vec4 cc[2];
|
||||
int inst_length = 1;
|
||||
int ip = -1;
|
||||
instruction_t inst;
|
||||
|
||||
#ifdef WITH_FLOW_CTRL
|
||||
int test_addr = -1;
|
||||
int jump_addr = -1;
|
||||
int loop_start_addr = -1;
|
||||
int loop_end_addr = -1;
|
||||
int counter = 0;
|
||||
#endif
|
||||
|
||||
vec4 read_src(const in int index)
|
||||
{
|
||||
ur0 = GET_INST_BITS(index + 1, 0, 2);
|
||||
|
||||
switch (ur0)
|
||||
{
|
||||
case RSX_FP_REGISTER_TYPE_TEMP:
|
||||
{
|
||||
switch(index)
|
||||
{
|
||||
case 0:
|
||||
ur1 = GET_INST_BITS(1, 2, 6); break;
|
||||
case 1:
|
||||
ur1 = GET_INST_BITS(2, 2, 6); break;
|
||||
case 2:
|
||||
ur1 = GET_INST_BITS(3, 2, 6); break;
|
||||
}
|
||||
|
||||
if (TEST_INST_BIT(index + 1, 8))
|
||||
{
|
||||
vr0 = regs16[ur1];
|
||||
}
|
||||
else
|
||||
{
|
||||
vr0 = regs32[ur1];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RSX_FP_REGISTER_TYPE_INPUT:
|
||||
{
|
||||
ur1 = GET_INST_BITS(0, 13, 4);
|
||||
switch (ur1)
|
||||
{
|
||||
case 0:
|
||||
vr0 = wpos; break;
|
||||
case 1:
|
||||
vr0 = gl_FrontFacing? in_regs[3] : in_regs[1]; break;
|
||||
case 2:
|
||||
vr0 = gl_FrontFacing? in_regs[4] : in_regs[2]; break;
|
||||
case 3:
|
||||
vr0 = fogc; break;
|
||||
case 13:
|
||||
vr0 = in_regs[6]; break;
|
||||
case 14:
|
||||
vr0 = gl_FrontFacing? vr_one : -vr_one; break;
|
||||
default:
|
||||
ur1 += 3;
|
||||
vr0 = in_regs[ur1]; break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case RSX_FP_REGISTER_TYPE_CONSTANT:
|
||||
{
|
||||
inst_length = 2;
|
||||
uvr0 =
|
||||
((fp_instructions[ip + 1] << 8) & uvec4(0xFF00FF00)) |
|
||||
((fp_instructions[ip + 1] >> 8) & uvec4(0x00FF00FF));
|
||||
vr0 = uintBitsToFloat(uvr0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ur1 = GET_INST_BITS(index + 1, 9, 8);
|
||||
vr0 = shuffle(vr0, ur1);
|
||||
|
||||
// abs
|
||||
if (index == 0)
|
||||
{
|
||||
if (TEST_INST_BIT(1, 29)) vr0 = abs(vr0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ur1 = index + 1;
|
||||
if (TEST_INST_BIT(ur1, 18)) vr0 = abs(vr0);
|
||||
}
|
||||
|
||||
// neg
|
||||
return (TEST_INST_BIT(index + 1, 17))? -vr0 : vr0;
|
||||
}
|
||||
|
||||
vec4 read_cond()
|
||||
{
|
||||
return shuffle(cc[GET_INST_BITS(1, 31, 1)], GET_INST_BITS(1, 21, 8));
|
||||
}
|
||||
|
||||
bvec4 decode_cond(const in uint mode, const in vec4 cond)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case EXEC_GT | EXEC_EQ:
|
||||
return greaterThanEqual(cond, vr_zero);
|
||||
case EXEC_LT | EXEC_EQ:
|
||||
return lessThanEqual(cond, vr_zero);
|
||||
case EXEC_LT | EXEC_GT:
|
||||
return notEqual(cond, vr_zero);
|
||||
case EXEC_GT:
|
||||
return greaterThan(cond, vr_zero);
|
||||
case EXEC_LT:
|
||||
return lessThan(cond, vr_zero);
|
||||
case EXEC_EQ:
|
||||
return equal(cond, vr_zero);
|
||||
default:
|
||||
return bvec4(vr_zero);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WITH_FLOW_CTRL) || defined(WITH_KIL)
|
||||
|
||||
bool check_cond()
|
||||
{
|
||||
ur0 = GET_INST_BITS(1, 18, 3);
|
||||
if (ur0 == 0x7)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
vr0 = read_cond();
|
||||
bvr0 = decode_cond(ur0, vr0);
|
||||
return any(bvr0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WITH_TEXTURES
|
||||
|
||||
#define RSX_SAMPLE_TEXTURE_1D 0
|
||||
#define RSX_SAMPLE_TEXTURE_2D 1
|
||||
#define RSX_SAMPLE_TEXTURE_CUBE 2
|
||||
#define RSX_SAMPLE_TEXTURE_3D 3
|
||||
|
||||
// FIXME: Remove when codegen is unified
|
||||
#define CLAMP_COORDS_BIT 17
|
||||
|
||||
float _texcoord_xform(const in float coord, const in sampler_info params)
|
||||
{
|
||||
float result = fma(coord, params.scale_x, params.bias_x);
|
||||
if (TEST_BIT(params.flags, CLAMP_COORDS_BIT))
|
||||
{
|
||||
result = clamp(result, params.clamp_min_x, params.clamp_max_x);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
vec2 _texcoord_xform(const in vec2 coord, const in sampler_info params)
|
||||
{
|
||||
vec2 result = fma(
|
||||
coord,
|
||||
vec2(params.scale_x, params.scale_y),
|
||||
vec2(params.bias_x, params.bias_y)
|
||||
);
|
||||
|
||||
if (TEST_BIT(params.flags, CLAMP_COORDS_BIT))
|
||||
{
|
||||
result = clamp(
|
||||
result,
|
||||
vec2(params.clamp_min_x, params.clamp_min_y),
|
||||
vec2(params.clamp_max_x, params.clamp_max_y)
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
vec3 _texcoord_xform(const in vec3 coord, const in sampler_info params)
|
||||
{
|
||||
vec3 result = fma(
|
||||
coord,
|
||||
vec3(params.scale_x, params.scale_y, params.scale_z),
|
||||
vec3(params.bias_x, params.bias_y, params.bias_z)
|
||||
);
|
||||
|
||||
// NOTE: Coordinate clamping not supported for CUBE and 3D textures
|
||||
return result;
|
||||
}
|
||||
|
||||
vec4 _texture(in vec4 coord, float bias)
|
||||
{
|
||||
ur0 = GET_INST_BITS(0, 17, 4);
|
||||
if (!IS_TEXTURE_RESIDENT(ur0))
|
||||
{
|
||||
return vr_zero;
|
||||
}
|
||||
|
||||
ur1 = ur0 + ur0;
|
||||
const uint type = GET_BITS(texture_control, int(ur1), 2);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case RSX_SAMPLE_TEXTURE_1D:
|
||||
coord.x = _texcoord_xform(coord.x, texture_parameters[ur0]);
|
||||
vr0 = texture(SAMPLER1D(ur0), coord.x, bias);
|
||||
break;
|
||||
case RSX_SAMPLE_TEXTURE_2D:
|
||||
coord.xy = _texcoord_xform(coord.xy, texture_parameters[ur0]);
|
||||
vr0 = texture(SAMPLER2D(ur0), coord.xy, bias);
|
||||
break;
|
||||
case RSX_SAMPLE_TEXTURE_CUBE:
|
||||
coord.xyz = _texcoord_xform(coord.xyz, texture_parameters[ur0]);
|
||||
vr0 = texture(SAMPLERCUBE(ur0), coord.xyz, bias);
|
||||
break;
|
||||
case RSX_SAMPLE_TEXTURE_3D:
|
||||
coord.xyz = _texcoord_xform(coord.xyz, texture_parameters[ur0]);
|
||||
vr0 = texture(SAMPLER3D(ur0), coord.xyz, bias);
|
||||
break;
|
||||
}
|
||||
|
||||
if (TEST_INST_BIT(0, 21))
|
||||
{
|
||||
vr0 = vr0 * 2. - 1.;
|
||||
}
|
||||
|
||||
return vr0;
|
||||
}
|
||||
|
||||
vec4 _textureLod(in vec4 coord, float lod)
|
||||
{
|
||||
ur0 = GET_INST_BITS(0, 17, 4);
|
||||
if (!IS_TEXTURE_RESIDENT(ur0))
|
||||
{
|
||||
return vr_zero;
|
||||
}
|
||||
|
||||
ur1 = ur0 + ur0;
|
||||
const uint type = GET_BITS(texture_control, int(ur1), 2);
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case RSX_SAMPLE_TEXTURE_1D:
|
||||
coord.x = _texcoord_xform(coord.x, texture_parameters[ur0]);
|
||||
vr0 = textureLod(SAMPLER1D(ur0), coord.x, lod);
|
||||
break;
|
||||
case RSX_SAMPLE_TEXTURE_2D:
|
||||
coord.xy = _texcoord_xform(coord.xy, texture_parameters[ur0]);
|
||||
vr0 = textureLod(SAMPLER2D(ur0), coord.xy, lod);
|
||||
break;
|
||||
case RSX_SAMPLE_TEXTURE_CUBE:
|
||||
coord.xyz = _texcoord_xform(coord.xyz, texture_parameters[ur0]);
|
||||
vr0 = textureLod(SAMPLERCUBE(ur0), coord.xyz, lod);
|
||||
break;
|
||||
case RSX_SAMPLE_TEXTURE_3D:
|
||||
coord.xyz = _texcoord_xform(coord.xyz, texture_parameters[ur0]);
|
||||
vr0 = textureLod(SAMPLER3D(ur0), coord.xyz, lod);
|
||||
break;
|
||||
}
|
||||
|
||||
if (TEST_INST_BIT(0, 21))
|
||||
{
|
||||
// Normal-expand, v = 2v - 1
|
||||
vr0 += vr0;
|
||||
vr0 -= 1.;
|
||||
}
|
||||
|
||||
return vr0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void write_dst(const in vec4 value)
|
||||
{
|
||||
uvr0 = uvec4(uint(1 << 9), uint(1 << 10), uint(1 << 11), uint(1 << 12));
|
||||
bvr0 = bvec4(uvr0 & inst.words.xxxx);
|
||||
|
||||
if (TEST_INST_BIT(0, 8)) // SET COND
|
||||
{
|
||||
ur0 = GET_INST_BITS(1, 30, 1);
|
||||
reg_mov(cc[ur0], value, bvr0);
|
||||
}
|
||||
|
||||
if (TEST_INST_BIT(0, 30)) // NO DEST
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ur1 = GET_INST_BITS(2, 28, 3);
|
||||
sr0 = modifier_scale[ur1];
|
||||
vr0 = value * sr0;
|
||||
|
||||
if (TEST_INST_BIT(0, 31)) // SAT
|
||||
{
|
||||
vr0 = clamp(vr0, 0, 1);
|
||||
}
|
||||
|
||||
ur0 = GET_INST_BITS(1, 18, 3);
|
||||
if (ur0 != 0x7)
|
||||
{
|
||||
vr1 = read_cond();
|
||||
bvr1 = decode_cond(ur0, vr1);
|
||||
bvr0 = bvec4(uvec4(bvr0) & uvec4(bvr1));
|
||||
}
|
||||
|
||||
ur1 = GET_INST_BITS(0, 1, 6);
|
||||
if (TEST_INST_BIT(0, 7))
|
||||
{
|
||||
reg_mov(regs16[ur1], vr0, bvr0);
|
||||
}
|
||||
else
|
||||
{
|
||||
reg_mov(regs32[ur1], vr0, bvr0);
|
||||
}
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
// Initialize registers
|
||||
// NOTE: Register count is the number of 'full' registers that will be consumed. Hardware seems to do some renaming.
|
||||
// NOTE: Attempting to zero-initialize all the registers will slow things to a crawl!
|
||||
|
||||
uint register_count = GET_BITS(shader_control, 24, 6);
|
||||
ur0 = 0, ur1 = 0;
|
||||
while (register_count > 0)
|
||||
{
|
||||
regs32[ur0++] = vr_zero;
|
||||
regs16[ur1++] = vr_zero;
|
||||
regs16[ur1++] = vr_zero;
|
||||
register_count--;
|
||||
}
|
||||
|
||||
// Fog coord
|
||||
fogc = in_regs[5];
|
||||
switch(fog_mode)
|
||||
{
|
||||
case 0:
|
||||
//linear
|
||||
fogc.y = fog_param1 * fogc.x + (fog_param0 - 1.);
|
||||
break;
|
||||
case 1:
|
||||
//exponential
|
||||
fogc.y = exp(11.084 * (fog_param1 * fogc.x + fog_param0 - 1.5));
|
||||
break;
|
||||
case 2:
|
||||
//exponential2
|
||||
fogc.y = exp(-pow(4.709 * (fog_param1 * fogc.x + fog_param0 - 1.5), 2.));
|
||||
break;
|
||||
case 3:
|
||||
//exponential_abs
|
||||
fogc.y = exp(11.084 * (fog_param1 * abs(fogc.x) + fog_param0 - 1.5));
|
||||
break;
|
||||
case 4:
|
||||
//exponential2_abs
|
||||
fogc.y = exp(-pow(4.709 * (fog_param1 * abs(fogc.x) + fog_param0 - 1.5), 2.));
|
||||
break;
|
||||
case 5:
|
||||
//linear_abs
|
||||
fogc.y = fog_param1 * abs(fogc.x) + (fog_param0 - 1.);
|
||||
break;
|
||||
default:
|
||||
fogc = in_regs[5];
|
||||
}
|
||||
fogc.y = clamp(fogc.y, 0., 1.);
|
||||
|
||||
// WPOS
|
||||
vr0 = vec4(abs(wpos_scale), wpos_scale, 1., 1.);
|
||||
vr1 = vec4(0., wpos_bias, 0., 0.);
|
||||
wpos = gl_FragCoord * vr0 + vr1;
|
||||
|
||||
// Other
|
||||
cc[0] = vr_zero;
|
||||
cc[1] = vr_zero;
|
||||
})"
|
||||
|
||||
R"(
|
||||
|
||||
void main()
|
||||
{
|
||||
initialize();
|
||||
|
||||
inst.end = false;
|
||||
bool handled;
|
||||
|
||||
#ifdef WITH_STIPPLING
|
||||
uvr0.xy = uvec2(gl_FragCoord.xy) % uvec2(32u); // x,y location
|
||||
ur0 = uvr0.y * 32u + uvr0.x; // linear address
|
||||
ur1 = ur0 & 31u; // address % 32 -> fetch bit offset
|
||||
ur1 = (1u << ur1); // address mask
|
||||
uvr0.x = (ur0 >> 7u); // address to uvec4 row (each row has 32x4 bits)
|
||||
ur0 = (ur0 >> 5u) & 3u; // address to uvec4 word (address / 32) % 4
|
||||
|
||||
if ((stipple_pattern[uvr0.x][ur0] & ur1) == 0u)
|
||||
{
|
||||
discard;
|
||||
inst.end = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
while (!inst.end)
|
||||
{
|
||||
ip += inst_length;
|
||||
inst_length = 1;
|
||||
|
||||
#ifdef WITH_FLOW_CTRL
|
||||
if (ip == test_addr)
|
||||
{
|
||||
ip = jump_addr;
|
||||
test_addr = -1;
|
||||
jump_addr = -1;
|
||||
}
|
||||
else if (ip == loop_end_addr)
|
||||
{
|
||||
if (counter > 0)
|
||||
{
|
||||
counter--;
|
||||
ip = loop_start_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
loop_end_addr = -1;
|
||||
loop_start_addr = -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Decode instruction
|
||||
// endian swap + word swap
|
||||
inst.words =
|
||||
((fp_instructions[ip] << 8) & uvec4(0xFF00FF00)) |
|
||||
((fp_instructions[ip] >> 8) & uvec4(0x00FF00FF));
|
||||
|
||||
inst.opcode = GET_INST_BITS(0, 24, 6);
|
||||
inst.end = TEST_INST_BIT(0, 0);
|
||||
|
||||
#ifdef WITH_FLOW_CTRL
|
||||
if (TEST_INST_BIT(2, 31))
|
||||
{
|
||||
// Flow control
|
||||
switch (inst.opcode | (1 << 6))
|
||||
{
|
||||
//case RSX_FP_OPCODE_CAL:
|
||||
// Function call not yet found in the wild for this hw class
|
||||
case RSX_FP_OPCODE_RET:
|
||||
inst.end = true;
|
||||
continue;
|
||||
case RSX_FP_OPCODE_IFE:
|
||||
if (check_cond())
|
||||
{
|
||||
// Go down IF path
|
||||
if (inst.words.z < inst.words.w)
|
||||
{
|
||||
test_addr = int(inst.words.z >> 2);
|
||||
jump_addr = int(inst.words.w >> 2);
|
||||
}
|
||||
// If simple IF..ENDIF, do nothing
|
||||
}
|
||||
else
|
||||
{
|
||||
// Go to ELSE path
|
||||
ip = int(inst.words.z >> 2);
|
||||
inst_length = 0;
|
||||
}
|
||||
continue;
|
||||
case RSX_FP_OPCODE_LOOP:
|
||||
case RSX_FP_OPCODE_REP:
|
||||
if (check_cond())
|
||||
{
|
||||
counter = int(GET_INST_BITS(2, 2, 8) - GET_INST_BITS(2, 10, 8));
|
||||
counter /= int(GET_INST_BITS(2, 19, 8));
|
||||
loop_start_addr = ip + 1;
|
||||
loop_end_addr = int(inst.words.w >> 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
ip = int(inst.words.w >> 2);
|
||||
inst_length = 0;
|
||||
}
|
||||
continue;
|
||||
case RSX_FP_OPCODE_BRK:
|
||||
if (loop_end_addr > 0)
|
||||
{
|
||||
ip = loop_end_addr;
|
||||
inst_length = 0;
|
||||
counter = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Class 1, no input/output
|
||||
switch (inst.opcode)
|
||||
{
|
||||
case RSX_FP_OPCODE_NOP:
|
||||
case RSX_FP_OPCODE_FENCT:
|
||||
case RSX_FP_OPCODE_FENCB:
|
||||
continue;
|
||||
#ifdef WITH_KIL
|
||||
case RSX_FP_OPCODE_KIL:
|
||||
if (check_cond())
|
||||
{
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Class 2, 1 input
|
||||
s0 = read_src(0);
|
||||
handled = true;
|
||||
switch (inst.opcode)
|
||||
{
|
||||
case RSX_FP_OPCODE_MOV:
|
||||
vrr = s0; break;
|
||||
case RSX_FP_OPCODE_FRC:
|
||||
vrr = fract(s0); break;
|
||||
case RSX_FP_OPCODE_FLR:
|
||||
vrr = floor(s0); break;
|
||||
case RSX_FP_OPCODE_DDX:
|
||||
vrr = dFdx(s0); break;
|
||||
case RSX_FP_OPCODE_DDY:
|
||||
vrr = dFdy(s0); break;
|
||||
case RSX_FP_OPCODE_RCP:
|
||||
vrr = (1.f / s0.xxxx); break;
|
||||
case RSX_FP_OPCODE_RSQ:
|
||||
vrr = inversesqrt(s0.xxxx); break;
|
||||
case RSX_FP_OPCODE_EX2:
|
||||
vrr = exp2(s0.xxxx); break;
|
||||
case RSX_FP_OPCODE_LG2:
|
||||
vrr = log2(s0.xxxx); break;
|
||||
case RSX_FP_OPCODE_STR:
|
||||
vrr = vr_one; break;
|
||||
case RSX_FP_OPCODE_SFL:
|
||||
vrr = vr_zero; break;
|
||||
case RSX_FP_OPCODE_COS:
|
||||
vrr = cos(s0.xxxx); break;
|
||||
case RSX_FP_OPCODE_SIN:
|
||||
vrr = sin(s0.xxxx); break;
|
||||
case RSX_FP_OPCODE_NRM:
|
||||
vrr.xyz = normalize(s0.xyz); break;
|
||||
|
||||
#ifdef WITH_TEXTURES
|
||||
case RSX_FP_OPCODE_TEX:
|
||||
vrr = _texture(s0, 0.f); break;
|
||||
case RSX_FP_OPCODE_TXP:
|
||||
vrr = _texture(vec4(s0.xyz / s0.w, s0.w), 0.f); break;
|
||||
#endif
|
||||
|
||||
#ifdef WITH_PACKING
|
||||
case RSX_FP_OPCODE_PK2:
|
||||
vrr = vec4(uintBitsToFloat(packHalf2x16(s0.xy))); break;
|
||||
case RSX_FP_OPCODE_PK4:
|
||||
vrr = vec4(uintBitsToFloat(packSnorm4x8(s0))); break;
|
||||
case RSX_FP_OPCODE_PK16:
|
||||
vrr = vec4(uintBitsToFloat(packSnorm2x16(s0.xy))); break;
|
||||
case RSX_FP_OPCODE_PKG:
|
||||
// Should be similar to PKB but with gamma correction, see description of PK4UBG in khronos page
|
||||
case RSX_FP_OPCODE_PKB:
|
||||
vrr = vec4(uintBitsToFloat(packUnorm4x8(s0))); break;
|
||||
case RSX_FP_OPCODE_UP2:
|
||||
vrr = unpackHalf2x16(floatBitsToUint(s0.x)).xyxy; break;
|
||||
case RSX_FP_OPCODE_UP4:
|
||||
vrr = unpackSnorm4x8(floatBitsToUint(s0.x)); break;
|
||||
case RSX_FP_OPCODE_UP16:
|
||||
vrr = unpackSnorm2x16(floatBitsToUint(s0.x)).xyxy; break;
|
||||
case RSX_FP_OPCODE_UPG:
|
||||
// Same as UPB with gamma correction
|
||||
case RSX_FP_OPCODE_UPB:
|
||||
vrr = unpackUnorm4x8(floatBitsToUint(s0.x)); break;
|
||||
#endif
|
||||
default:
|
||||
handled = false;
|
||||
}
|
||||
|
||||
if (!handled)
|
||||
{
|
||||
// Class 3, 2 inputs
|
||||
s1 = read_src(1);
|
||||
handled = true;
|
||||
switch (inst.opcode)
|
||||
{
|
||||
case RSX_FP_OPCODE_MUL:
|
||||
vrr = s0 * s1; break;
|
||||
case RSX_FP_OPCODE_ADD:
|
||||
vrr = s0 + s1; break;
|
||||
case RSX_FP_OPCODE_DP2:
|
||||
vrr = dot(s0.xy, s1.xy).xxxx; break;
|
||||
case RSX_FP_OPCODE_DP3:
|
||||
vrr = dot(s0.xyz, s1.xyz).xxxx; break;
|
||||
case RSX_FP_OPCODE_DP4:
|
||||
vrr = dot(s0, s1).xxxx; break;
|
||||
case RSX_FP_OPCODE_DST:
|
||||
vrr = _distance(s0, s1); break;
|
||||
case RSX_FP_OPCODE_MIN:
|
||||
vrr = min(s0, s1); break;
|
||||
case RSX_FP_OPCODE_MAX:
|
||||
vrr = max(s0, s1); break;
|
||||
case RSX_FP_OPCODE_SLT:
|
||||
vrr = vec4(lessThan(s0, s1)); break;
|
||||
case RSX_FP_OPCODE_SGE:
|
||||
vrr = vec4(greaterThanEqual(s0, s1)); break;
|
||||
case RSX_FP_OPCODE_SLE:
|
||||
vrr = vec4(lessThanEqual(s0, s1)); break;
|
||||
case RSX_FP_OPCODE_SGT:
|
||||
vrr = vec4(greaterThan(s0, s1)); break;
|
||||
case RSX_FP_OPCODE_SNE:
|
||||
vrr = vec4(notEqual(s0, s1)); break;
|
||||
case RSX_FP_OPCODE_SEQ:
|
||||
vrr = vec4(equal(s0, s1)); break;
|
||||
case RSX_FP_OPCODE_POW:
|
||||
vrr = pow(s0, s1).xxxx; break;
|
||||
case RSX_FP_OPCODE_DIV:
|
||||
vrr = s0 / s1.xxxx; break;
|
||||
case RSX_FP_OPCODE_DIVSQ:
|
||||
bvr0 = bvec4(s0);
|
||||
sr0 = inversesqrt(s1.x);
|
||||
vr0 = s0 * sr0;
|
||||
vrr = select(s0, vr0, bvr0);
|
||||
break;
|
||||
case RSX_FP_OPCODE_REFL:
|
||||
vrr = reflect(s0, s1); break;
|
||||
|
||||
#ifdef WITH_TEXTURES
|
||||
//case RSX_FP_OPCODE_TXD:
|
||||
case RSX_FP_OPCODE_TXL:
|
||||
vrr = _textureLod(s0, s1.x); break;
|
||||
case RSX_FP_OPCODE_TXB:
|
||||
vrr = _texture(s0, s1.x); break;
|
||||
//case RSX_FP_OPCODE_TEXBEM:
|
||||
//case RSX_FP_OPCODE_TXPBEM:
|
||||
#endif
|
||||
default:
|
||||
handled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled)
|
||||
{
|
||||
// Class 4, 3 inputs
|
||||
s2 = read_src(2);
|
||||
switch (inst.opcode)
|
||||
{
|
||||
case RSX_FP_OPCODE_MAD:
|
||||
vrr = fma(s0, s1, s2); break;
|
||||
case RSX_FP_OPCODE_LRP:
|
||||
vrr = mix(s1, s2, s0); break;
|
||||
case RSX_FP_OPCODE_DP2A:
|
||||
vrr = dot(s0.xy, s1.xy).xxxx + s2.xxxx; break;
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
// Other
|
||||
case RSX_FP_OPCODE_BEM:
|
||||
case RSX_FP_OPCODE_BEMLUM:
|
||||
case RSX_FP_OPCODE_LIT:
|
||||
case RSX_FP_OPCODE_LIF:
|
||||
case RSX_FP_OPCODE_TIMESWTEX:
|
||||
#endif
|
||||
write_dst(vrr);
|
||||
}
|
||||
|
||||
#ifdef WITH_HALF_OUTPUT_REGISTER
|
||||
ocol0 = regs16[0];
|
||||
ocol1 = regs16[4];
|
||||
ocol2 = regs16[6];
|
||||
ocol3 = regs16[8];
|
||||
#else
|
||||
ocol0 = regs32[0];
|
||||
ocol1 = regs32[2];
|
||||
ocol2 = regs32[3];
|
||||
ocol3 = regs32[4];
|
||||
#endif
|
||||
|
||||
#ifdef WITH_DEPTH_EXPORT
|
||||
gl_FragDepth = regs32[1].z;
|
||||
#endif
|
||||
|
||||
// Typically an application will pick one strategy and stick with it
|
||||
#ifdef ALPHA_TEST_GEQUAL
|
||||
if (ocol0.a < alpha_ref) discard; // gequal
|
||||
#endif
|
||||
#ifdef ALPHA_TEST_GREATER
|
||||
if (ocol0.a <= alpha_ref) discard; // greater
|
||||
#endif
|
||||
#ifdef ALPHA_TEST_LESS
|
||||
if (ocol0.a >= alpha_ref) discard; // less
|
||||
#endif
|
||||
#ifdef ALPHA_TEST_LEQUAL
|
||||
if (ocol0.a > alpha_ref) discard; // lequal
|
||||
#endif
|
||||
#ifdef ALPHA_TEST_EQUAL
|
||||
if (ocol0.a != alpha_ref) discard; // equal
|
||||
#endif
|
||||
#ifdef ALPHA_TEST_NEQUAL
|
||||
if (ocol0.a == alpha_ref) discard; // nequal
|
||||
#endif
|
||||
}
|
||||
|
||||
)"
|
||||
606
rpcs3/Emu/RSX/Program/GLSLInterpreter/VertexInterpreter.glsl
Normal file
606
rpcs3/Emu/RSX/Program/GLSLInterpreter/VertexInterpreter.glsl
Normal file
|
|
@ -0,0 +1,606 @@
|
|||
R"(
|
||||
|
||||
// Program outputs
|
||||
layout(location=0) out vec4 dest[16];
|
||||
|
||||
#define RSX_SCA_OPCODE_NOP 0x00 // No-Operation
|
||||
#define RSX_SCA_OPCODE_MOV 0x01 // Move (copy)
|
||||
#define RSX_SCA_OPCODE_RCP 0x02 // Reciprocal
|
||||
#define RSX_SCA_OPCODE_RCC 0x03 // Reciprocal clamped
|
||||
#define RSX_SCA_OPCODE_RSQ 0x04 // Reciprocal square root
|
||||
#define RSX_SCA_OPCODE_EXP 0x05 // Exponential base 2 (low-precision)
|
||||
#define RSX_SCA_OPCODE_LOG 0x06 // Logarithm base 2 (low-precision)
|
||||
#define RSX_SCA_OPCODE_LIT 0x07 // Lighting calculation
|
||||
#define RSX_SCA_OPCODE_BRA 0x08 // Branch
|
||||
#define RSX_SCA_OPCODE_BRI 0x09 // Branch by CC register
|
||||
#define RSX_SCA_OPCODE_CAL 0x0a // Subroutine call
|
||||
#define RSX_SCA_OPCODE_CLI 0x0b // Subroutine call by CC register
|
||||
#define RSX_SCA_OPCODE_RET 0x0c // Return from subroutine
|
||||
#define RSX_SCA_OPCODE_LG2 0x0d // Logarithm base 2
|
||||
#define RSX_SCA_OPCODE_EX2 0x0e // Exponential base 2
|
||||
#define RSX_SCA_OPCODE_SIN 0x0f // Sine function
|
||||
#define RSX_SCA_OPCODE_COS 0x10 // Cosine function
|
||||
#define RSX_SCA_OPCODE_BRB 0x11 // Branch by Boolean constant
|
||||
#define RSX_SCA_OPCODE_CLB 0x12 // Subroutine call by Boolean constant
|
||||
#define RSX_SCA_OPCODE_PSH 0x13 // Push onto stack
|
||||
#define RSX_SCA_OPCODE_POP 0x14 // Pop from stack
|
||||
#define RSX_VEC_OPCODE_NOP 0x00 // No-Operation
|
||||
#define RSX_VEC_OPCODE_MOV 0x01 // Move
|
||||
#define RSX_VEC_OPCODE_MUL 0x02 // Multiply
|
||||
#define RSX_VEC_OPCODE_ADD 0x03 // Addition
|
||||
#define RSX_VEC_OPCODE_MAD 0x04 // Multiply-Add
|
||||
#define RSX_VEC_OPCODE_DP3 0x05 // 3-component Dot Product
|
||||
#define RSX_VEC_OPCODE_DPH 0x06 // Homogeneous Dot Product
|
||||
#define RSX_VEC_OPCODE_DP4 0x07 // 4-component Dot Product
|
||||
#define RSX_VEC_OPCODE_DST 0x08 // Calculate distance vector
|
||||
#define RSX_VEC_OPCODE_MIN 0x09 // Minimum
|
||||
#define RSX_VEC_OPCODE_MAX 0x0a // Maximum
|
||||
#define RSX_VEC_OPCODE_SLT 0x0b // Set-If-LessThan
|
||||
#define RSX_VEC_OPCODE_SGE 0x0c // Set-If-GreaterEqual
|
||||
#define RSX_VEC_OPCODE_ARL 0x0d // Load to address register (round down)
|
||||
#define RSX_VEC_OPCODE_FRC 0x0e // Extract fractional part (fraction)
|
||||
#define RSX_VEC_OPCODE_FLR 0x0f // Round down (floor)
|
||||
#define RSX_VEC_OPCODE_SEQ 0x10 // Set-If-Equal
|
||||
#define RSX_VEC_OPCODE_SFL 0x11 // Set-If-False
|
||||
#define RSX_VEC_OPCODE_SGT 0x12 // Set-If-GreaterThan
|
||||
#define RSX_VEC_OPCODE_SLE 0x13 // Set-If-LessEqual
|
||||
#define RSX_VEC_OPCODE_SNE 0x14 // Set-If-NotEqual
|
||||
#define RSX_VEC_OPCODE_STR 0x15 // Set-If-True
|
||||
#define RSX_VEC_OPCODE_SSG 0x16 // Convert positive values to 1 and negative values to -1
|
||||
#define RSX_VEC_OPCODE_TXL 0x19 // Texture fetch
|
||||
|
||||
#define RSX_VP_REGISTER_TYPE_TEMP 1
|
||||
#define RSX_VP_REGISTER_TYPE_INPUT 2
|
||||
#define RSX_VP_REGISTER_TYPE_CONSTANT 3
|
||||
|
||||
#define EXEC_LT 1
|
||||
#define EXEC_EQ 2
|
||||
#define EXEC_GT 4
|
||||
|
||||
#define GET_BITS bitfieldExtract
|
||||
#define TEST_BIT(word, bit) (GET_BITS(word, bit, 1) != 0)
|
||||
|
||||
#define reg_mov(d, s, m) d = mix(d, s, m)
|
||||
|
||||
struct D0
|
||||
{
|
||||
uint addr_swz;
|
||||
uvec4 swizzle;
|
||||
uint cond;
|
||||
bool cond_test_enable;
|
||||
bool cond_update_enable_0;
|
||||
uint dst_tmp;
|
||||
uint addr_reg_sel_1;
|
||||
uint cond_reg_sel_1;
|
||||
bool saturate;
|
||||
bool index_input;
|
||||
bool cond_update_enable_1;
|
||||
bool vec_result;
|
||||
};
|
||||
|
||||
struct D1
|
||||
{
|
||||
uint input_src;
|
||||
uint const_src;
|
||||
uint vec_opcode;
|
||||
uint sca_opcode;
|
||||
};
|
||||
|
||||
struct D2
|
||||
{
|
||||
uint tex_num;
|
||||
};
|
||||
|
||||
struct D3
|
||||
{
|
||||
bool end;
|
||||
bool index_const;
|
||||
uint dst;
|
||||
uint sca_dst_tmp;
|
||||
bvec4 vec_mask;
|
||||
bvec4 sca_mask;
|
||||
};
|
||||
|
||||
struct SRC
|
||||
{
|
||||
uint reg_type;
|
||||
uint tmp_src;
|
||||
uvec4 swizzle;
|
||||
bool neg;
|
||||
bool abs;
|
||||
};
|
||||
|
||||
D0 unpack_D0(const in uint packed_value)
|
||||
{
|
||||
D0 result;
|
||||
|
||||
result.addr_swz = GET_BITS(packed_value, 0, 2);
|
||||
result.swizzle.w = GET_BITS(packed_value, 2, 2);
|
||||
result.swizzle.z = GET_BITS(packed_value, 4, 2);
|
||||
result.swizzle.y = GET_BITS(packed_value, 6, 2);
|
||||
result.swizzle.x = GET_BITS(packed_value, 8, 2);
|
||||
result.cond = GET_BITS(packed_value, 10, 3);
|
||||
result.cond_test_enable = TEST_BIT(packed_value, 13);
|
||||
result.cond_update_enable_0 = TEST_BIT(packed_value, 14);
|
||||
result.dst_tmp = GET_BITS(packed_value, 15, 6);
|
||||
result.addr_reg_sel_1 = GET_BITS(packed_value, 24, 1);
|
||||
result.cond_reg_sel_1 = GET_BITS(packed_value, 25, 1);
|
||||
result.saturate = TEST_BIT(packed_value, 26);
|
||||
result.index_input = TEST_BIT(packed_value, 27);
|
||||
result.cond_update_enable_1 = TEST_BIT(packed_value, 29);
|
||||
result.vec_result = TEST_BIT(packed_value, 30);
|
||||
return result;
|
||||
}
|
||||
|
||||
D1 unpack_D1(const in uint packed_value)
|
||||
{
|
||||
D1 result;
|
||||
|
||||
result.input_src = GET_BITS(packed_value, 8, 4);
|
||||
result.const_src = GET_BITS(packed_value, 12, 10);
|
||||
result.vec_opcode = GET_BITS(packed_value, 22, 5);
|
||||
result.sca_opcode = GET_BITS(packed_value, 27, 5);
|
||||
return result;
|
||||
}
|
||||
|
||||
D2 unpack_D2(const in uint packed_value)
|
||||
{
|
||||
D2 result;
|
||||
|
||||
result.tex_num = GET_BITS(packed_value, 8, 2);
|
||||
return result;
|
||||
}
|
||||
|
||||
D3 unpack_D3(const in uint packed_value)
|
||||
{
|
||||
D3 result;
|
||||
|
||||
result.end = TEST_BIT(packed_value, 0);
|
||||
result.index_const = TEST_BIT(packed_value, 1);
|
||||
result.dst = GET_BITS(packed_value, 2, 5);
|
||||
result.sca_dst_tmp = GET_BITS(packed_value, 7, 6);
|
||||
result.vec_mask.w = TEST_BIT(packed_value, 13);
|
||||
result.vec_mask.z = TEST_BIT(packed_value, 14);
|
||||
result.vec_mask.y = TEST_BIT(packed_value, 15);
|
||||
result.vec_mask.x = TEST_BIT(packed_value, 16);
|
||||
result.sca_mask.w = TEST_BIT(packed_value, 17);
|
||||
result.sca_mask.z = TEST_BIT(packed_value, 18);
|
||||
result.sca_mask.y = TEST_BIT(packed_value, 19);
|
||||
result.sca_mask.x = TEST_BIT(packed_value, 20);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool attribute_enabled(const in uint mask)
|
||||
{
|
||||
return (output_mask & mask) != 0;
|
||||
}
|
||||
|
||||
vec4 shuffle(const in vec4 value, const in uvec4 swz)
|
||||
{
|
||||
vec4 result;
|
||||
result.x = ref(value, swz.x);
|
||||
result.y = ref(value, swz.y);
|
||||
result.z = ref(value, swz.z);
|
||||
result.w = ref(value, swz.w);
|
||||
return result;
|
||||
}
|
||||
|
||||
vec4 _distance(const in vec4 a, const in vec4 b)
|
||||
{
|
||||
// Old-school distance vector
|
||||
return vec4(1., a.y * b.y, a.z, b.w);
|
||||
}
|
||||
|
||||
bvec4 test_cond(const in vec4 cond, const in uint mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case EXEC_GT | EXEC_EQ | EXEC_LT:
|
||||
return bvec4(true);
|
||||
case EXEC_GT | EXEC_EQ:
|
||||
return greaterThanEqual(cond, vec4(0.));
|
||||
case EXEC_LT | EXEC_EQ:
|
||||
return lessThanEqual(cond, vec4(0.));
|
||||
case EXEC_LT | EXEC_GT:
|
||||
return notEqual(cond, vec4(0.));
|
||||
case EXEC_GT:
|
||||
return greaterThan(cond, vec4(0.));
|
||||
case EXEC_LT:
|
||||
return lessThan(cond, vec4(0.));
|
||||
case EXEC_EQ:
|
||||
return equal(cond, vec4(0.));
|
||||
default:
|
||||
return bvec4(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Local registers
|
||||
uvec4 instr;
|
||||
vec4 temp[32];
|
||||
ivec4 a[2] = { ivec4(0), ivec4(0) };
|
||||
vec4 cc[2] = { vec4(0), vec4(0) };
|
||||
|
||||
D0 d0;
|
||||
D1 d1;
|
||||
D2 d2;
|
||||
D3 d3;
|
||||
|
||||
vec4 get_cond()
|
||||
{
|
||||
return shuffle(cc[d0.cond_reg_sel_1], d0.swizzle);
|
||||
}
|
||||
|
||||
void write_sca(in float value)
|
||||
{
|
||||
if (d0.saturate)
|
||||
{
|
||||
value = clamp(value, 0, 1);
|
||||
}
|
||||
|
||||
if (d3.sca_dst_tmp == 0x3f)
|
||||
{
|
||||
if (!d0.vec_result)
|
||||
{
|
||||
reg_mov(dest[d3.dst], vec4(value), d3.sca_mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
reg_mov(cc[d0.cond_reg_sel_1], vec4(value), d3.sca_mask);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
reg_mov(temp[d3.sca_dst_tmp], vec4(value), d3.sca_mask);
|
||||
}
|
||||
}
|
||||
|
||||
void write_vec(in vec4 value)
|
||||
{
|
||||
if (d0.saturate)
|
||||
{
|
||||
value = clamp(value, 0, 1);
|
||||
}
|
||||
|
||||
bvec4 write_mask = d3.vec_mask;
|
||||
if (d0.cond_test_enable)
|
||||
{
|
||||
const bvec4 mask = test_cond(get_cond(), d0.cond);
|
||||
write_mask = bvec4(uvec4(write_mask) & uvec4(mask));
|
||||
}
|
||||
|
||||
if (d0.dst_tmp == 0x3f && !d0.vec_result)
|
||||
{
|
||||
reg_mov(cc[d0.cond_reg_sel_1], value, write_mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (d0.vec_result && d3.dst < 16)
|
||||
{
|
||||
reg_mov(dest[d3.dst], value, write_mask);
|
||||
}
|
||||
|
||||
if (d0.dst_tmp != 0x3f)
|
||||
{
|
||||
reg_mov(temp[d0.dst_tmp], value, write_mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void write_output(const in int oid, const in int mask_bit)
|
||||
{
|
||||
if (!attribute_enabled(1 << mask_bit))
|
||||
{
|
||||
dest[oid] = vec4(0., 0., 0., 1.);
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot dynamically index into the gl_ClipDistance array without causing problems due to it's unknown size
|
||||
#define write_clip_distance(plane, mask_bit, test, value)\
|
||||
if (test && attribute_enabled(1 << mask_bit))\
|
||||
gl_ClipDistance[plane] = value;\
|
||||
else\
|
||||
gl_ClipDistance[plane] = 0.5f;\
|
||||
|
||||
ivec4 read_addr_reg()
|
||||
{
|
||||
return a[d0.addr_reg_sel_1];
|
||||
}
|
||||
|
||||
int branch_addr()
|
||||
{
|
||||
uint addr_h = GET_BITS(instr.z, 0, 6);
|
||||
uint addr_l = GET_BITS(instr.w, 29, 3);
|
||||
return int((addr_h << 3) + addr_l);
|
||||
}
|
||||
|
||||
bool static_branch()
|
||||
{
|
||||
uint mask = (1 << GET_BITS(instr.w, 23, 5));
|
||||
bool cond = TEST_BIT(instr.w, 28);
|
||||
bool actual = (transform_branch_bits & mask) != 0;
|
||||
|
||||
return (cond == actual);
|
||||
}
|
||||
|
||||
bool dynamic_branch()
|
||||
{
|
||||
if (d0.cond == (EXEC_LT | EXEC_GT | EXEC_EQ)) return true;
|
||||
if (d0.cond == 0) return false;
|
||||
|
||||
return any(test_cond(get_cond(), d0.cond));
|
||||
}
|
||||
|
||||
vec4 read_src(const in int index)
|
||||
{
|
||||
uint src;
|
||||
vec4 value;
|
||||
bool do_abs = false;
|
||||
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
src = (GET_BITS(instr.y, 0, 8) << 9) | GET_BITS(instr.z, 23, 9);
|
||||
do_abs = TEST_BIT(instr.x, 21);
|
||||
break;
|
||||
case 1:
|
||||
src = GET_BITS(instr.z, 6, 17);
|
||||
do_abs = TEST_BIT(instr.x, 22);
|
||||
break;
|
||||
case 2:
|
||||
src = (GET_BITS(instr.z, 0, 6) << 11) | GET_BITS(instr.w, 21, 11);
|
||||
do_abs = TEST_BIT(instr.x, 23);
|
||||
break;
|
||||
}
|
||||
|
||||
uint reg_type = GET_BITS(src, 0, 2);
|
||||
uint tmp_src = GET_BITS(src, 2, 6);
|
||||
|
||||
switch (reg_type)
|
||||
{
|
||||
case RSX_VP_REGISTER_TYPE_TEMP:
|
||||
value = temp[tmp_src];
|
||||
break;
|
||||
|
||||
case RSX_VP_REGISTER_TYPE_INPUT:
|
||||
value = read_location(int(d1.input_src));
|
||||
break;
|
||||
|
||||
case RSX_VP_REGISTER_TYPE_CONSTANT:
|
||||
if (d3.index_const)
|
||||
{
|
||||
value = _fetch_constant(d1.const_src + ref(a[d0.addr_reg_sel_1], d0.addr_swz));
|
||||
}
|
||||
else
|
||||
{
|
||||
value = _fetch_constant(d1.const_src);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (GET_BITS(src, 8, 8) != 0x1B)
|
||||
{
|
||||
uvec4 swz = uvec4(
|
||||
GET_BITS(src, 14, 2),
|
||||
GET_BITS(src, 12, 2),
|
||||
GET_BITS(src, 10, 2),
|
||||
GET_BITS(src, 8, 2)
|
||||
);
|
||||
|
||||
value = shuffle(value, swz);
|
||||
}
|
||||
|
||||
if (do_abs)
|
||||
{
|
||||
value = abs(value);
|
||||
}
|
||||
|
||||
if (TEST_BIT(src, 16))
|
||||
{
|
||||
value = -value;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// Initialize output registers
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
dest[i] = vec4(0., 0., 0., 1.);
|
||||
}
|
||||
|
||||
int callstack[8];
|
||||
int stack_ptr = 0;
|
||||
int current_instruction = 0;
|
||||
|
||||
d3.end = false;
|
||||
|
||||
while (current_instruction < 512)
|
||||
{
|
||||
if (d3.end)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
instr = vp_instructions[current_instruction];
|
||||
current_instruction++;
|
||||
|
||||
d0 = unpack_D0(instr.x);
|
||||
d1 = unpack_D1(instr.y);
|
||||
d2 = unpack_D2(instr.z);
|
||||
d3 = unpack_D3(instr.w);
|
||||
|
||||
uint vec_opcode = d1.vec_opcode;
|
||||
uint sca_opcode = d1.sca_opcode;
|
||||
|
||||
if (d0.cond_test_enable && d0.cond == 0)
|
||||
{
|
||||
vec_opcode = RSX_VEC_OPCODE_NOP;
|
||||
sca_opcode = RSX_SCA_OPCODE_NOP;
|
||||
}
|
||||
|
||||
if (vec_opcode == RSX_VEC_OPCODE_ARL)
|
||||
{
|
||||
a[d0.dst_tmp] = ivec4(read_src(0));
|
||||
}
|
||||
else if (vec_opcode != RSX_VEC_OPCODE_NOP)
|
||||
{
|
||||
vec4 value = read_src(0);
|
||||
switch (vec_opcode)
|
||||
{
|
||||
case RSX_VEC_OPCODE_MOV: break;
|
||||
case RSX_VEC_OPCODE_MUL: value *= read_src(1); break;
|
||||
case RSX_VEC_OPCODE_ADD: value += read_src(2); break;
|
||||
case RSX_VEC_OPCODE_MAD: value = fma(value, read_src(1), read_src(2)); break;
|
||||
case RSX_VEC_OPCODE_DP3: value = vec4(dot(value.xyz, read_src(1).xyz)); break;
|
||||
case RSX_VEC_OPCODE_DPH: value = vec4(dot(vec4(value.xyz, 1.0), read_src(1))); break;
|
||||
case RSX_VEC_OPCODE_DP4: value = vec4(dot(value, read_src(1))); break;
|
||||
case RSX_VEC_OPCODE_DST: value = _distance(value, read_src(1)); break;
|
||||
case RSX_VEC_OPCODE_MIN: value = min(value, read_src(1)); break;
|
||||
case RSX_VEC_OPCODE_MAX: value = max(value, read_src(1)); break;
|
||||
case RSX_VEC_OPCODE_SLT: value = vec4(lessThan(value, read_src(1))); break;
|
||||
case RSX_VEC_OPCODE_SGE: value = vec4(greaterThanEqual(value, read_src(1))); break;
|
||||
case RSX_VEC_OPCODE_FRC: value = fract(value); break;
|
||||
case RSX_VEC_OPCODE_FLR: value = floor(value); break;
|
||||
case RSX_VEC_OPCODE_SEQ: value = vec4(equal(value, read_src(1))); break;
|
||||
case RSX_VEC_OPCODE_SFL: value = vec4(0); break;
|
||||
case RSX_VEC_OPCODE_SGT: value = vec4(greaterThan(value, read_src(1))); break;
|
||||
case RSX_VEC_OPCODE_SLE: value = vec4(lessThanEqual(value, read_src(1))); break;
|
||||
case RSX_VEC_OPCODE_SNE: value = vec4(notEqual(value, read_src(1))); break;
|
||||
case RSX_VEC_OPCODE_STR: value = vec4(1); break;
|
||||
case RSX_VEC_OPCODE_SSG: value = sign(value); break;
|
||||
}
|
||||
|
||||
write_vec(value);
|
||||
}
|
||||
|
||||
if (sca_opcode != RSX_SCA_OPCODE_NOP)
|
||||
{
|
||||
float value = read_src(2).x;
|
||||
switch (sca_opcode)
|
||||
{
|
||||
case RSX_SCA_OPCODE_MOV: break;
|
||||
case RSX_SCA_OPCODE_RCP: value = 1.0 / value; break;
|
||||
case RSX_SCA_OPCODE_RCC: value = clamp(1.0 / value, 5.42101e-20, 1.884467e19); break;
|
||||
case RSX_SCA_OPCODE_RSQ: value = 1.0 / sqrt(value); break;
|
||||
case RSX_SCA_OPCODE_EXP: value = exp(value); break;
|
||||
case RSX_SCA_OPCODE_LOG: value = log(value); break;
|
||||
//case RSX_SCA_OPCODE_LIT: value = lit_legacy(value); break;
|
||||
case RSX_SCA_OPCODE_LG2: value = log2(value); break;
|
||||
case RSX_SCA_OPCODE_EX2: value = exp2(value); break;
|
||||
case RSX_SCA_OPCODE_SIN: value = sin(value); break;
|
||||
case RSX_SCA_OPCODE_COS: value = cos(value); break;
|
||||
|
||||
case RSX_SCA_OPCODE_BRA:
|
||||
// Jump by address register
|
||||
if (dynamic_branch()) current_instruction = int(read_addr_reg().x);
|
||||
continue;
|
||||
case RSX_SCA_OPCODE_BRI:
|
||||
// Jump immediate
|
||||
if (dynamic_branch()) current_instruction = branch_addr();
|
||||
continue;
|
||||
case RSX_SCA_OPCODE_CAL:
|
||||
// Call immediate
|
||||
if (dynamic_branch())
|
||||
{
|
||||
callstack[stack_ptr] = current_instruction;
|
||||
stack_ptr++;
|
||||
current_instruction = branch_addr();
|
||||
}
|
||||
continue;
|
||||
case RSX_SCA_OPCODE_CLI:
|
||||
// Unknown
|
||||
continue;
|
||||
case RSX_SCA_OPCODE_RET:
|
||||
// Return
|
||||
if (dynamic_branch())
|
||||
{
|
||||
if (stack_ptr == 0) return;
|
||||
current_instruction = callstack[stack_ptr];
|
||||
stack_ptr--;
|
||||
}
|
||||
continue;
|
||||
case RSX_SCA_OPCODE_BRB:
|
||||
// Branch by boolean mask
|
||||
if (static_branch())
|
||||
{
|
||||
current_instruction = branch_addr();
|
||||
}
|
||||
continue;
|
||||
case RSX_SCA_OPCODE_CLB:
|
||||
// Call by boolean mask
|
||||
if (static_branch())
|
||||
{
|
||||
callstack[stack_ptr] = current_instruction;
|
||||
stack_ptr++;
|
||||
current_instruction = branch_addr();
|
||||
}
|
||||
continue;
|
||||
//case RSX_SCA_OPCODE_PSH:
|
||||
//case RSX_SCA_OPCODE_POP:
|
||||
}
|
||||
|
||||
write_sca(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Unconditionally update COLOR0 and SPECULAR0
|
||||
write_output(1, 0);
|
||||
write_output(2, 1);
|
||||
|
||||
// Conditionally update COLOR1 and SPECULAR1 depending on 2-sided mask
|
||||
if (control == 0)
|
||||
{
|
||||
dest[3] = dest[1];
|
||||
dest[4] = dest[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
// 2-sided lighting
|
||||
write_output(3, 2);
|
||||
write_output(4, 3);
|
||||
}
|
||||
|
||||
if (!attribute_enabled(1 << 4))
|
||||
{
|
||||
dest[5].x = 0;
|
||||
}
|
||||
|
||||
if (attribute_enabled(1 << 5))
|
||||
{
|
||||
gl_PointSize = dest[6].x;
|
||||
}
|
||||
else
|
||||
{
|
||||
gl_PointSize = point_size;
|
||||
}
|
||||
|
||||
write_clip_distance(0, 6, user_clip_enabled[0].x > 0, dest[5].y * user_clip_factor[0].x);
|
||||
write_clip_distance(1, 7, user_clip_enabled[0].y > 0, dest[5].z * user_clip_factor[0].y);
|
||||
write_clip_distance(2, 8, user_clip_enabled[0].z > 0, dest[5].w * user_clip_factor[0].z);
|
||||
write_clip_distance(3, 9, user_clip_enabled[0].w > 0, dest[6].y * user_clip_factor[0].w);
|
||||
write_clip_distance(4, 10, user_clip_enabled[1].x > 0, dest[6].z * user_clip_factor[1].x);
|
||||
write_clip_distance(5, 11, user_clip_enabled[1].y > 0, dest[6].w * user_clip_factor[1].y);
|
||||
|
||||
write_output(15, 12);
|
||||
write_output(6, 13);
|
||||
write_output(7, 14);
|
||||
write_output(8, 15);
|
||||
write_output(9, 16);
|
||||
write_output(10, 17);
|
||||
write_output(11, 18);
|
||||
write_output(12, 19);
|
||||
write_output(13, 20);
|
||||
write_output(14, 21);
|
||||
|
||||
vec4 pos = dest[0] * scale_offset_mat;
|
||||
|
||||
#ifdef Z_NEGATIVE_ONE_TO_ONE
|
||||
pos.z = (pos.z + pos.z) - pos.w;
|
||||
#endif
|
||||
|
||||
gl_Position = pos;
|
||||
}
|
||||
|
||||
)"
|
||||
Loading…
Add table
Add a link
Reference in a new issue