Include the hlsl code as a raw string

Make all Xbox VSh opcodes consistent (using an x_ function or macro)
Replace switch statements with table lookups, making the code much more compact
This commit is contained in:
PatrickvL 2019-12-03 11:36:10 +01:00 committed by patrickvl
parent e372a80a8d
commit c1ba533455
2 changed files with 88 additions and 150 deletions

View File

@ -1,3 +1,6 @@
// This starts the raw string (comment to get syntax highlighting, UNCOMMENT to compile) :
R"DELIMITER(
#define r12 oPos // oPos and r12 are two ways of accessing the same register on Xbox
struct VS_INPUT
@ -33,6 +36,21 @@ float4 c(int index) {
return hostConstants[index + 96];
}
// Generic macro's
//#define x_mov(src0) src0
// Macro's for MAC ('Multiply And Accumulate') opcodes
//#define x_mul(src0, src1) src0 * src1
//#define x_add(src0, src1) src0 + src1
//#define x_min(src0, src1) min(src0, src1)
//#define x_max(src0, src1) max(src0, src1)
//#define x_mad(src0, src1, src2) src0 * src1 + src2
// Macro's for ILU ('Inverse Logic Unit') opcodes
#define x_rcp(src0) rcp(src0)
#define x_rsq(src0) rsqrt(src0)
// Xbox functions
int x_arl(float src0) {
// The address register should be floored
// Due to rounding differences with the Xbox (and increased precision on PC?)
@ -197,7 +215,7 @@ VS_OUTPUT main(const VS_INPUT xIn)
// Insert Xbox shader here
// <Xbox Shader>
// <Xbox Shader> // !!MUST CORRESPOND WITH THE REGEX IN EmuRecompileVshFunction!!
// Copy variables to output struct
VS_OUTPUT xOut;
@ -216,3 +234,5 @@ VS_OUTPUT main(const VS_INPUT xIn)
return xOut;
}
// )DELIMITER" /* This terminates the raw string" // */

View File

@ -912,7 +912,7 @@ static void VshWriteShader(VSH_XBOX_SHADER *pShader,
std::stringstream moveConstantsToTemporaries;
pDisassembly << "; Input usage declarations --\n";
for(int i = 0; i < RegVIsUsedByShader.size(); i++){
for(size_t i = 0; i < RegVIsUsedByShader.size(); i++){
if (RegVIsUsedByShader[i]) {
if (!RegVIsPresentInDeclaration[i]) {
// Log test case and skip
@ -2752,13 +2752,9 @@ extern HRESULT EmuRecompileVshFunction
std::stringstream& pXboxShaderDisassembly = std::stringstream();
std::stringstream& pHostShaderDisassembly = std::stringstream();
//static std::ifstream t("Xb.hlsl");
static std::ifstream t("..\\..\\..\\..\\src\\core\\hle\\D3D8\\Direct3D9\\Xb.hlsl");
const static std::string hlslTemplate((std::istreambuf_iterator<char>(t)),
std::istreambuf_iterator<char>());
if (t.is_open()) {
t.close();
}
static std::string hlslTemplate =
#include "core\hle\D3D8\Direct3D9\Xb.hlsl" // Note : This included .hlsl defines a raw string
;
DbgVshPrintf("-- Before conversion --\n");
VshWriteShader(pShader, pXboxShaderDisassembly, pRecompiledDeclaration, FALSE);
@ -2980,30 +2976,25 @@ std::string ToHlsl(VSH_IMD_OUTPUT& dest) {
std::string ToHlsl(VSH_IMD_PARAMETER& paramMeta)
{
auto hlsl = std::stringstream();
auto param = paramMeta.Parameter;
hlsl << (param.Neg ? "-" : "");
if (param.ParameterType == PARAM_C){
hlsl << "c";
if (param.Neg) {
hlsl << "-";
}
if (param.ParameterType == PARAM_C) {
// We'll use the c() function instead of direct indexing
// Only display the offset if it's not 0.
if (paramMeta.IndexesWithA0_X) {
param.Address
? hlsl << "(a+" << param.Address << ")"
: hlsl << "(a)";
// Only display the offset if it's not 0.
if (param.Address != 0) {
hlsl << "c(a+" << param.Address << ")";
} else {
hlsl << "c(a)";
}
} else {
hlsl << "c(" << param.Address << ")";
}
else {
hlsl << "(" << param.Address << ")";
}
}
else if (param.ParameterType == PARAM_R && param.Address == 12) {
// Replace r12 with oPos
hlsl << "oPos";
}
else {
} else {
hlsl << VshGetRegisterName(param.ParameterType) << param.Address;
}
@ -3014,43 +3005,22 @@ std::string ToHlsl(VSH_IMD_PARAMETER& paramMeta)
param.Swizzle[2] == SWIZZLE_Z &&
param.Swizzle[3] == SWIZZLE_W ))
{
hlsl << ".";
// We'll try to simplify swizzles if we can
int swizzles;
// If all swizzles are the same, we only need to write one out
if (param.Swizzle[0] == param.Swizzle[1] &&
param.Swizzle[0] == param.Swizzle[2] &&
param.Swizzle[0] == param.Swizzle[3]) {
swizzles = 1;
}
else {
// We need to use the full swizzle
// Note we can't always remove trailing repeats, like in VS asm
// As it may change the type from float4, to float3 or float2
unsigned swizzles = 1;
// Otherwise, we need to use the full swizzle
if (param.Swizzle[0] != param.Swizzle[1] ||
param.Swizzle[0] != param.Swizzle[2] ||
param.Swizzle[0] != param.Swizzle[3]) {
// Note, we can't remove trailing repeats, like in VS asm,
// as it may change the type from float4 to float3, float2 or float1!
swizzles = 4;
}
for (int i = 0; i < swizzles; i++)
{
char Swizzle = '?';
switch (param.Swizzle[i])
{
case SWIZZLE_X:
Swizzle = 'x';
break;
case SWIZZLE_Y:
Swizzle = 'y';
break;
case SWIZZLE_Z:
Swizzle = 'z';
break;
case SWIZZLE_W:
Swizzle = 'w';
break;
}
hlsl << Swizzle;
hlsl << ".";
for (unsigned i = 0; i < swizzles; i++) {
hlsl << "xyzw"[param.Swizzle[i]];
}
}
@ -3079,103 +3049,51 @@ std::string ToHlsl(std::string pattern, VSH_INTERMEDIATE_FORMAT& instruction) {
std::string BuildShader(VSH_XBOX_SHADER* pShader) {
// HLSL strings for all MAC opcodes, indexed with VSH_MAC
static std::string VSH_MAC_HLSL[] = {
/*MAC_NOP:*/"// MAC_NOP\n",
/*MAC_MOV:*/"dest = x_mov(src0);\n",
/*MAC_MUL:*/"dest = x_mul(src0, src1);\n",
/*MAC_ADD:*/"dest = x_add(src0, src1);\n",
/*MAC_MAD:*/"dest = x_mad(src0, src1, src2);\n",
/*MAC_DP3:*/"dest = x_dp3(src0, src1);\n",
/*MAC_DPH:*/"dest = x_dph(src0, src1);\n",
/*MAC_DP4:*/"dest = x_dp4(src0, src1);\n",
/*MAC_DST:*/"dest = x_dst(src0, src1);\n",
/*MAC_MIN:*/"dest = x_min(src0, src1);\n",
/*MAC_MAX:*/"dest = x_max(src0, src1);\n",
/*MAC_SLT:*/"dest = x_slt(src0, src1);\n",
/*MAC_SGE:*/"dest = x_sge(src0, src1);\n",
/*MAC_ARL:*/"a = x_arl(src0);\n", // Note : For this MAC_ARL case, ToHlsl would always replace 'dest' with 'a', so we optimized this upfront
"// ??? VSH_MAC 14 ???;\n",
"// ??? VSH_MAC 15 ???;\n" // VSH_MAC 2 final values of the 4 bits are undefined/unknown TODO : Investigate their effect (if any) and emulate that as well
};
// HLSL strings for all ILU opcodes, indexed with VSH_ILU
static std::string VSH_ILU_HLSL[] = {
/*ILU_NOP:*/"// ILU_NOP\n",
/*ILU_MOV:*/"dest = x_mov(src0);\n",
/*ILU_RCP:*/"dest = x_rcp(src0);\n",
/*ILU_RCC:*/"dest = x_rcc(src0);\n",
/*ILU_RSQ:*/"dest = x_rsq(src0);\n",
/*ILU_EXP:*/"dest = x_exp(src0);\n",
/*ILU_LOG:*/"dest = x_log(src0);\n",
/*ILU_LIT:*/"dest = x_lit(src0);\n" // = 7 - all values of the 3 bits are used
};
auto hlsl = std::stringstream();
for (int i = 0; i < pShader->IntermediateCount; i++) {
VSH_INTERMEDIATE_FORMAT& xboxInstruction = pShader->Intermediate[i];
VSH_INTERMEDIATE_FORMAT xboxInstruction = pShader->Intermediate[i];
if (xboxInstruction.InstructionType == IMD_MAC)
{
switch (xboxInstruction.MAC)
{
case MAC_NOP:
hlsl << "// NOP";
break;
case MAC_MOV:
hlsl << ToHlsl("dest = x_mov(src0)", xboxInstruction);
break;
case MAC_MUL:
hlsl << ToHlsl("dest = x_mul(src0, src1)", xboxInstruction);
break;
case MAC_ADD:
hlsl << ToHlsl("dest = x_add(src0, src1)", xboxInstruction);
break;
case MAC_MAD:
hlsl << ToHlsl("dest = x_mad(src0, src1, src2)", xboxInstruction);
break;
case MAC_DP3:
hlsl << ToHlsl("dest = x_dp3(src0, src1)", xboxInstruction);
break;
case MAC_DPH:
hlsl << ToHlsl("dest = x_dph(src0, src1)", xboxInstruction);
break;
case MAC_DP4:
hlsl << ToHlsl("dest = x_dp4(src0, src1)", xboxInstruction);
break;
case MAC_DST:
hlsl << ToHlsl("dest = x_dst(src0, src1)", xboxInstruction);
break;
case MAC_MIN:
hlsl << ToHlsl("dest = x_min(src0, src1)", xboxInstruction);
break;
case MAC_MAX:
hlsl << ToHlsl("dest = x_max(src0, src1)", xboxInstruction);
break;
case MAC_SLT:
hlsl << ToHlsl("dest = x_slt(src0, src1)", xboxInstruction);
break;
case MAC_SGE:
hlsl << ToHlsl("dest = x_sge(src0, src1)", xboxInstruction);
break;
case MAC_ARL:
hlsl << ToHlsl("a = x_arl(src0)", xboxInstruction);
break;
default:
EmuLog(LOG_LEVEL::WARNING, "TODO message");
}
}
else if (xboxInstruction.InstructionType == IMD_ILU)
{
switch (xboxInstruction.ILU)
{
case ILU_NOP:
hlsl << "// NOP";
break;
case ILU_MOV:
hlsl << ToHlsl("dest = src0", xboxInstruction);
break;
case ILU_RCP:
hlsl << ToHlsl("dest = rcp(src0)", xboxInstruction);
break;
case ILU_RCC:
hlsl << ToHlsl("dest = x_rcc(src0)", xboxInstruction);
break;
case ILU_RSQ:
hlsl << ToHlsl("dest = rsqrt(src0)", xboxInstruction);
break;
case ILU_EXP:
hlsl << ToHlsl("dest = x_exp(src0)", xboxInstruction);
break;
case ILU_LOG:
hlsl << ToHlsl("dest = x_log(src0)", xboxInstruction);
break;
case ILU_LIT:
hlsl << ToHlsl("dest = x_lit(src0)", xboxInstruction);
break;
default:
EmuLog(LOG_LEVEL::WARNING, "TODO message");
}
}
else
{
if (xboxInstruction.InstructionType == IMD_MAC) {
hlsl << ToHlsl(VSH_MAC_HLSL[xboxInstruction.MAC], xboxInstruction);
} else if (xboxInstruction.InstructionType == IMD_ILU) {
hlsl << ToHlsl(VSH_ILU_HLSL[xboxInstruction.ILU], xboxInstruction);
} else {
EmuLog(LOG_LEVEL::WARNING, "TODO message");
}
// Finish the line
hlsl << ";\n";
}
return hlsl.str();
}