Compare commits

..

2 commits

Author SHA1 Message Date
Isaac Marovitz
7be2b82bb3
Merge a0e2d16fb0 into b15b5e4728 2025-03-22 02:07:31 +00:00
Isaac Marovitz
a0e2d16fb0
MSL Shader Generation
Signed-off-by: Isaac Marovitz <isaacryu@icloud.com>
2025-03-21 22:07:17 -04:00
4 changed files with 247 additions and 117 deletions

View file

@ -34,6 +34,11 @@ IDxcBlob* DxcCompiler::compile(const std::string& shaderSource, bool compilePixe
target = L"-T vs_6_0";
}
if (!compileLibrary)
{
args[argCount++] = L"-E shaderMain";
}
args[argCount++] = target;
args[argCount++] = L"-HV 2021";
args[argCount++] = L"-all-resources-bound";

View file

@ -44,7 +44,8 @@ using namespace metal;
constant uint G_SPEC_CONSTANT [[function_constant(0)]];
uint g_SpecConstants() {
uint g_SpecConstants()
{
return G_SPEC_CONSTANT;
}
@ -172,7 +173,7 @@ float rcp(T a)
template<typename T>
float4x4 mul(T a, T b)
{
a * b;
return a * b;
}
#endif

View file

@ -130,14 +130,21 @@ static FetchDestinationSwizzle getDestSwizzle(uint32_t dstSwizzle, uint32_t inde
return FetchDestinationSwizzle((dstSwizzle >> (index * 3)) & 0x7);
}
void ShaderRecompiler::printDstSwizzle(uint32_t dstSwizzle, bool operand)
uint32_t ShaderRecompiler::printDstSwizzle(uint32_t dstSwizzle, bool operand)
{
uint32_t size = 0;
for (size_t i = 0; i < 4; i++)
{
const auto swizzle = getDestSwizzle(dstSwizzle, i);
if (swizzle >= FetchDestinationSwizzle::X && swizzle <= FetchDestinationSwizzle::W)
{
out += SWIZZLES[operand ? uint32_t(swizzle) : i];
size++;
}
}
return size;
}
void ShaderRecompiler::printDstSwizzle01(uint32_t dstRegister, uint32_t dstSwizzle)
@ -172,10 +179,15 @@ void ShaderRecompiler::recompile(const VertexFetchInstruction& instr, uint32_t a
indent();
print("r{}.", instr.dstRegister);
printDstSwizzle(instr.dstSwizzle, false);
uint32_t size = printDstSwizzle(instr.dstSwizzle, false);
out += " = ";
if (size <= 1)
out += "(float)(";
else
print("(float{})(", size);
auto findResult = vertexElements.find(address);
assert(findResult != vertexElements.end());
@ -185,15 +197,15 @@ void ShaderRecompiler::recompile(const VertexFetchInstruction& instr, uint32_t a
case DeclUsage::Tangent:
case DeclUsage::Binormal:
specConstantsMask |= SPEC_CONSTANT_R11G11B10_NORMAL;
print("tfetchR11G11B10(");
print("tfetchR11G11B10((uint4)");
break;
case DeclUsage::TexCoord:
print("tfetchTexcoord(g_SwappedTexcoords, ");
print("tfetchTexcoord(g_SwappedTexcoords, (float4)");
break;
}
print("i{}{}", USAGE_VARIABLES[uint32_t(findResult->second.usage)], uint32_t(findResult->second.usageIndex));
print("(input.i{}{})", USAGE_VARIABLES[uint32_t(findResult->second.usage)], uint32_t(findResult->second.usageIndex));
switch (findResult->second.usage)
{
@ -208,7 +220,7 @@ void ShaderRecompiler::recompile(const VertexFetchInstruction& instr, uint32_t a
break;
}
out += '.';
out += ").";
printDstSwizzle(instr.dstSwizzle, true);
out += ";\n";
@ -356,7 +368,13 @@ void ShaderRecompiler::recompile(const TextureFetchInstruction& instr, bool bicu
print(", float2({}, {})", instr.offsetX * 0.5f, instr.offsetY * 0.5f);
break;
case TextureDimension::TextureCube:
out += ", cubeMapData";
println("\n#ifdef __air__");
indent();
println(", &cubeMapData");
println("#else");
indent();
println(", cubeMapData");
println("#endif");
break;
}
@ -594,6 +612,8 @@ void ShaderRecompiler::recompile(const AluInstruction& instr)
bool closeIfBracket = false;
std::string_view exportRegister;
bool vectorRegister = true;
if (instr.exportData)
{
if (isPixelShader)
@ -601,19 +621,20 @@ void ShaderRecompiler::recompile(const AluInstruction& instr)
switch (ExportRegister(instr.vectorDest))
{
case ExportRegister::PSColor0:
exportRegister = "oC0";
exportRegister = "output.oC0";
break;
case ExportRegister::PSColor1:
exportRegister = "oC1";
exportRegister = "output.oC1";
break;
case ExportRegister::PSColor2:
exportRegister = "oC2";
exportRegister = "output.oC2";
break;
case ExportRegister::PSColor3:
exportRegister = "oC3";
exportRegister = "output.oC3";
break;
case ExportRegister::PSDepth:
exportRegister = "oDepth";
exportRegister = "output.oDepth";
vectorRegister = false;
break;
}
}
@ -622,7 +643,7 @@ void ShaderRecompiler::recompile(const AluInstruction& instr)
switch (ExportRegister(instr.vectorDest))
{
case ExportRegister::VSPosition:
exportRegister = "oPos";
exportRegister = "output.oPos";
#ifdef UNLEASHED_RECOMP
if (hasMtxProjection)
@ -689,7 +710,8 @@ void ShaderRecompiler::recompile(const AluInstruction& instr)
if (!exportRegister.empty())
{
out += exportRegister;
out += '.';
if (vectorRegister)
out += '.';
}
else
{
@ -700,19 +722,20 @@ void ShaderRecompiler::recompile(const AluInstruction& instr)
for (size_t i = 0; i < 4; i++)
{
if ((vectorWriteMask >> i) & 0x1) {
out += SWIZZLES[i];
if ((vectorWriteMask >> i) & 0x1)
{
if (vectorRegister)
out += SWIZZLES[i];
vectorWriteSize++;
}
}
out += " = ";
if (vectorWriteSize > 1) {
if (vectorWriteSize > 1)
print("(float{})(", vectorWriteSize);
} else {
else
out += "(float)(";
}
if (instr.vectorSaturate)
out += "saturate(";
@ -790,7 +813,13 @@ void ShaderRecompiler::recompile(const AluInstruction& instr)
break;
case AluVectorOpcode::Cube:
println("\n#ifdef __air__");
indent();
print("cube(r{}, &cubeMapData)", instr.src1Register);
println("\n#else");
indent();
print("cube(r{}, cubeMapData)", instr.src1Register);
println("\n#endif");
break;
case AluVectorOpcode::Max4:
@ -1066,7 +1095,8 @@ void ShaderRecompiler::recompile(const AluInstruction& instr)
if (!exportRegister.empty())
{
out += exportRegister;
out += '.';
if (vectorRegister)
out += '.';
}
else
{
@ -1075,7 +1105,7 @@ void ShaderRecompiler::recompile(const AluInstruction& instr)
for (size_t i = 0; i < 4; i++)
{
if ((scalarWriteMask >> i) & 0x1)
if (((scalarWriteMask >> i) & 0x1) && vectorRegister)
out += SWIZZLES[i];
}
@ -1349,7 +1379,7 @@ void ShaderRecompiler::recompile(const uint8_t* shaderData, const std::string_vi
if (constantInfo->registerSet == RegisterSet::Bool)
{
const char* constantName = reinterpret_cast<const char*>(constantTableData + constantInfo->name);
println("\t#define {} (1 << {})", constantName, constantInfo->registerIndex + (isPixelShader ? 16 : 0));
println("#define {} (1 << {})", constantName, constantInfo->registerIndex + (isPixelShader ? 16 : 0));
boolConstants.emplace(constantInfo->registerIndex, constantName);
}
}
@ -1358,17 +1388,164 @@ void ShaderRecompiler::recompile(const uint8_t* shaderData, const std::string_vi
const auto shader = reinterpret_cast<const Shader*>(shaderData + shaderContainer->shaderOffset);
out += "#if __air__\n";
println("struct {}", isPixelShader ? "Interpolators" : "VertexShaderInput");
out += "{\n";
if (isPixelShader) {
out += "struct StageIn\n";
out += "{\n";
if (isPixelShader)
{
out += "#if __air__\n";
for (auto& [usage, usageIndex] : INTERPOLATORS)
println("\tfloat4 i{}{};", USAGE_VARIABLES[uint32_t(usage)], usageIndex);
out += "};\n";
out += "#else\n";
for (auto& [usage, usageIndex] : INTERPOLATORS)
println("\tfloat4 i{0}{1} : {2}{1};", USAGE_VARIABLES[uint32_t(usage)], usageIndex, USAGE_SEMANTICS[uint32_t(usage)]);
out += "#endif\n";
}
else
{
auto vertexShader = reinterpret_cast<const VertexShader*>(shader);
out += "#if __air__\n";
for (uint32_t i = 0; i < vertexShader->vertexElementCount; i++)
{
union
{
VertexElement vertexElement;
uint32_t value;
};
value = vertexShader->vertexElementsAndInterpolators[vertexShader->field18 + i];
const char* usageType = USAGE_TYPES[uint32_t(vertexElement.usage)];
#ifdef UNLEASHED_RECOMP
if ((vertexElement.usage == DeclUsage::TexCoord && vertexElement.usageIndex == 2 && isMetaInstancer) ||
(vertexElement.usage == DeclUsage::Position && vertexElement.usageIndex == 1))
{
usageType = "uint4";
}
#endif
out += '\t';
print("{0} i{1}{2}", usageType, USAGE_VARIABLES[uint32_t(vertexElement.usage)],
uint32_t(vertexElement.usageIndex));
for (auto& usageLocation : USAGE_LOCATIONS)
{
if (usageLocation.usage == vertexElement.usage && usageLocation.usageIndex == vertexElement.usageIndex)
{
println(" [[attribute({})]];", usageLocation.location);
break;
}
}
vertexElements.emplace(uint32_t(vertexElement.address), vertexElement);
}
out += "#else\n";
for (uint32_t i = 0; i < vertexShader->vertexElementCount; i++)
{
union
{
VertexElement vertexElement;
uint32_t value;
};
value = vertexShader->vertexElementsAndInterpolators[vertexShader->field18 + i];
const char* usageType = USAGE_TYPES[uint32_t(vertexElement.usage)];
#ifdef UNLEASHED_RECOMP
if ((vertexElement.usage == DeclUsage::TexCoord && vertexElement.usageIndex == 2 && isMetaInstancer) ||
(vertexElement.usage == DeclUsage::Position && vertexElement.usageIndex == 1))
{
usageType = "uint4";
}
#endif
out += '\t';
for (auto& usageLocation : USAGE_LOCATIONS)
{
if (usageLocation.usage == vertexElement.usage && usageLocation.usageIndex == vertexElement.usageIndex)
{
print("[[vk::location({})]] ", usageLocation.location);
break;
}
}
println("{0} i{1}{2} : {3}{2};", usageType, USAGE_VARIABLES[uint32_t(vertexElement.usage)],
uint32_t(vertexElement.usageIndex), USAGE_SEMANTICS[uint32_t(vertexElement.usage)]);
}
out += "#endif\n";
}
out += "};\n";
println("struct {}", isPixelShader ? "PixelShaderOutput" : "Interpolators");
out += "{\n";
if (isPixelShader)
{
out += "#if __air__\n";
auto pixelShader = reinterpret_cast<const PixelShader*>(shader);
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR0)
out += "\tfloat4 oC0 [[color(0)]];\n";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR1)
out += "\tfloat4 oC1 [[color(1)]];\n";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR2)
out += "\tfloat4 oC2 [[color(2)]];\n";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR3)
out += "\tfloat4 oC3 [[color(3)]];\n";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_DEPTH)
out += "\tfloat oDepth [[depth(any)]];\n";
out += "#else\n";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR0)
out += "\tfloat4 oC0 : SV_Target0;\n";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR1)
out += "\tfloat4 oC1 : SV_Target1;\n";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR2)
out += "\tfloat4 oC2 : SV_Target2;\n";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR3)
out += "\tfloat4 oC3 : SV_Target3;\n";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_DEPTH)
out += "\tfloat oDepth : SV_Depth;\n";
out += "#endif\n";
}
else
{
out += "#if __air__\n";
out += "\tfloat4 oPos [[position]];\n";
for (auto& [usage, usageIndex] : INTERPOLATORS)
print("\tfloat4 o{0}{1};\n", USAGE_VARIABLES[uint32_t(usage)], usageIndex);
out += "#else\n";
out += "\tfloat4 oPos : SV_Position;\n";
for (auto& [usage, usageIndex] : INTERPOLATORS)
print("\tfloat4 o{0}{1} : {2}{1};\n", USAGE_VARIABLES[uint32_t(usage)], usageIndex, USAGE_SEMANTICS[uint32_t(usage)]);
out += "#endif\n";
}
out += "};\n";
out += "#ifdef __air__\n";
if (isPixelShader)
out += "[[fragment]]\n";
@ -1384,128 +1561,77 @@ void ShaderRecompiler::recompile(const uint8_t* shaderData, const std::string_vi
out += "#endif\n";
out += "void shaderMain(\n";
println("{} shaderMain(", isPixelShader ? "PixelShaderOutput" : "Interpolators");
if (isPixelShader)
{
out += "#ifdef __air__\n";
out += "\tStageIn iStageIn [[stage_in]],\n";
out += "\tInterpolators input [[stage_in]],\n";
out += "\tfloat4 iPos [[position]],\n";
out += "\tbool iFace [[front_facing]],\n";
auto pixelShader = reinterpret_cast<const PixelShader*>(shader);
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR0)
out += "\tfloat4 oC0 [[color(0)]],\n";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR1)
out += "\tfloat4 oC1 [[color(1)]],\n";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR2)
out += "\tfloat4 oC2 [[color(2)]],\n";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR3)
out += "\tfloat4 oC3 [[color(3)]],\n";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_DEPTH)
out += "\tfloat oDepth [[depth(any)]],\n";
out += "\tconstant Texture2DDescriptorHeap& g_Texture2DDescriptorHeap [[buffer(0)]],\n";
out += "\tconstant Texture3DDescriptorHeap& g_Texture3DDescriptorHeap [[buffer(1)]],\n";
out += "\tconstant TextureCubeDescriptorHeap& g_TextureCubeDescriptorHeap [[buffer(2)]],\n";
out += "\tconstant SamplerDescriptorHeap& g_SamplerDescriptorHeap [[buffer(3)]],\n";
out += "\tconstant PushConstants& g_PushConstants [[buffer(4)]]\n";
out += "\tconstant PushConstants& g_PushConstants [[buffer(8)]]\n";
out += "#else\n";
out += "\tInterpolators input,\n";
out += "\tin float4 iPos : SV_Position,\n";
for (auto& [usage, usageIndex] : INTERPOLATORS)
println("\tin float4 i{0}{1} : {2}{1},", USAGE_VARIABLES[uint32_t(usage)], usageIndex, USAGE_SEMANTICS[uint32_t(usage)]);
out += "#ifdef __spirv__\n";
out += "\tin bool iFace : SV_IsFrontFace\n";
out += "#else\n";
out += "\tin uint iFace : SV_IsFrontFace\n";
out += "#endif\n";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR0)
out += ",\n\tout float4 oC0 : SV_Target0";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR1)
out += ",\n\tout float4 oC1 : SV_Target1";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR2)
out += ",\n\tout float4 oC2 : SV_Target2";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_COLOR3)
out += ",\n\tout float4 oC3 : SV_Target3";
if (pixelShader->outputs & PIXEL_SHADER_OUTPUT_DEPTH)
out += ",\n\tout float oDepth : SV_Depth";
out += "\n#endif\n";
}
else
{
auto vertexShader = reinterpret_cast<const VertexShader*>(shader);
for (uint32_t i = 0; i < vertexShader->vertexElementCount; i++)
{
union
{
VertexElement vertexElement;
uint32_t value;
};
value = vertexShader->vertexElementsAndInterpolators[vertexShader->field18 + i];
const char* usageType = USAGE_TYPES[uint32_t(vertexElement.usage)];
#ifdef UNLEASHED_RECOMP
if ((vertexElement.usage == DeclUsage::TexCoord && vertexElement.usageIndex == 2 && isMetaInstancer) ||
(vertexElement.usage == DeclUsage::Position && vertexElement.usageIndex == 1))
{
usageType = "uint4";
}
#endif
out += '\t';
for (auto& usageLocation : USAGE_LOCATIONS)
{
if (usageLocation.usage == vertexElement.usage && usageLocation.usageIndex == vertexElement.usageIndex)
{
print("[[vk::location({})]] ", usageLocation.location);
break;
}
}
println("in {0} i{1}{2} : {3}{2},", usageType, USAGE_VARIABLES[uint32_t(vertexElement.usage)],
uint32_t(vertexElement.usageIndex), USAGE_SEMANTICS[uint32_t(vertexElement.usage)]);
vertexElements.emplace(uint32_t(vertexElement.address), vertexElement);
}
out += "#ifdef __air__\n";
out += "\tconstant PushConstants& g_PushConstants [[buffer(8)]],\n";
out += "\tVertexShaderInput input [[stage_in]]\n";
out += "#else\n";
out += "\tVertexShaderInput input\n";
out += "#endif\n";
#ifdef UNLEASHED_RECOMP
if (hasIndexCount)
{
out += "\t,\n";
out += "#ifdef __air__\n";
out += "\tuint iVertexId [[vertex_id]],\n";
out += "\tuint iInstanceId [[instance_id]],\n";
out += "\tuint iInstanceId [[instance_id]]\n";
out += "#else\n";
out += "\tin uint iVertexId : SV_VertexID,\n";
out += "\tin uint iInstanceId : SV_InstanceID,\n";
out += "\tin uint iInstanceId : SV_InstanceID\n";
out += "#endif\n";
}
#endif
out += "\tout float4 oPos : SV_Position";
for (auto& [usage, usageIndex] : INTERPOLATORS)
print(",\n\tout float4 o{0}{1} : {2}{1}", USAGE_VARIABLES[uint32_t(usage)], usageIndex, USAGE_SEMANTICS[uint32_t(usage)]);
}
out += ")\n";
out += "{\n";
#ifdef UNLEASHED_RECOMP
std::string outputName = isPixelShader ? "PixelShaderOutput" : "Interpolators";
out += "#ifdef __air__\n";
println("\t{0} output = {0}{{}};", outputName);
out += "#else\n";
println("\t{0} output = ({0})0;", outputName);
out += "#endif\n";
if (hasMtxProjection)
{
specConstantsMask |= SPEC_CONSTANT_REVERSE_Z;
out += "\toPos = 0.0;\n";
out += "\toutput.oPos = 0.0;\n";
out += "\tfloat4x4 mtxProjection = float4x4(g_MtxProjection(0), g_MtxProjection(1), g_MtxProjection(2), g_MtxProjection(3));\n";
out += "\tfloat4x4 mtxProjectionReverseZ = mul(mtxProjection, float4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 1, 1));\n";
@ -1582,18 +1708,14 @@ void ShaderRecompiler::recompile(const uint8_t* shaderData, const std::string_vi
if (isPixelShader)
{
value = reinterpret_cast<const PixelShader*>(shader)->interpolators[i];
println("#ifdef __air__");
println("\tfloat4 r{} = iStageIn.i{}{};", uint32_t(interpolator.reg), USAGE_VARIABLES[uint32_t(interpolator.usage)], uint32_t(interpolator.usageIndex));
println("#else");
println("\tfloat4 r{} = i{}{};", uint32_t(interpolator.reg), USAGE_VARIABLES[uint32_t(interpolator.usage)], uint32_t(interpolator.usageIndex));
println("#endif");
println("\tfloat4 r{} = input.i{}{};", uint32_t(interpolator.reg), USAGE_VARIABLES[uint32_t(interpolator.usage)], uint32_t(interpolator.usageIndex));
printedRegisters[interpolator.reg] = true;
}
else
{
auto vertexShader = reinterpret_cast<const VertexShader*>(shader);
value = vertexShader->vertexElementsAndInterpolators[vertexShader->field18 + vertexShader->vertexElementCount + i];
interpolators.emplace(i, fmt::format("o{}{}", USAGE_VARIABLES[uint32_t(interpolator.usage)], uint32_t(interpolator.usageIndex)));
interpolators.emplace(i, fmt::format("output.o{}{}", USAGE_VARIABLES[uint32_t(interpolator.usage)], uint32_t(interpolator.usageIndex)));
}
}
@ -1601,11 +1723,11 @@ void ShaderRecompiler::recompile(const uint8_t* shaderData, const std::string_vi
{
#ifdef UNLEASHED_RECOMP
if (!hasMtxProjection)
out += "\toPos = 0.0;\n";
out += "\toutput.oPos = 0.0;\n";
#endif
for (auto& [usage, usageIndex] : INTERPOLATORS)
println("\to{}{} = 0.0;", USAGE_VARIABLES[uint32_t(usage)], usageIndex);
println("\toutput.o{}{} = 0.0;", USAGE_VARIABLES[uint32_t(usage)], usageIndex);
out += "\n";
}
@ -1642,7 +1764,7 @@ void ShaderRecompiler::recompile(const uint8_t* shaderData, const std::string_vi
out += "\tfloat2 pixelCoord = 0.0;\n";
#endif
out += "#ifdef __air__\n";
out += "\tCubeMapData cubeMapdata = CubeMapData{};\n";
out += "\tCubeMapData cubeMapData = CubeMapData{};\n";
out += "#else\n";
out += "\tCubeMapData cubeMapData = (CubeMapData)0;\n";
out += "#endif\n";
@ -1961,7 +2083,7 @@ void ShaderRecompiler::recompile(const uint8_t* shaderData, const std::string_vi
out += "{\n";
indent();
out += "\tclip(oC0.w - g_AlphaThreshold);\n";
out += "\tclip(output.oC0.w - g_AlphaThreshold);\n";
indent();
out += "}\n";
@ -1975,9 +2097,9 @@ void ShaderRecompiler::recompile(const uint8_t* shaderData, const std::string_vi
out += "{\n";
indent();
out += "\toC0.w *= 1.0 + computeMipLevel(pixelCoord) * 0.25;\n";
out += "\toutput.oC0.w *= 1.0 + computeMipLevel(pixelCoord) * 0.25;\n";
indent();
out += "\toC0.w = 0.5 + (oC0.w - g_AlphaThreshold) / max(fwidth(oC0.w), 1e-6);\n";
out += "\toutput.oC0.w = 0.5 + (output.oC0.w - g_AlphaThreshold) / max(fwidth(output.oC0.w), 1e-6);\n";
indent();
out += "}\n";
@ -1995,7 +2117,7 @@ void ShaderRecompiler::recompile(const uint8_t* shaderData, const std::string_vi
else
#endif
{
out += "return;\n";
out += "return output;\n";
}
}
else
@ -2029,5 +2151,7 @@ void ShaderRecompiler::recompile(const uint8_t* shaderData, const std::string_vi
out += "\t}\n";
#endif
out += "\treturn output;\n";
out += "}";
}

View file

@ -45,7 +45,7 @@ struct ShaderRecompiler : StringBuffer
out += '\t';
}
void printDstSwizzle(uint32_t dstSwizzle, bool operand);
uint32_t printDstSwizzle(uint32_t dstSwizzle, bool operand);
void printDstSwizzle01(uint32_t dstRegister, uint32_t dstSwizzle);
void recompile(const VertexFetchInstruction& instr, uint32_t address);