1278 lines
49 KiB
C++
1278 lines
49 KiB
C++
#include <stdio.h>
|
|
#include "internal_includes/HLSLccToolkit.h"
|
|
#include "internal_includes/HLSLCrossCompilerContext.h"
|
|
#include "hlslcc.h"
|
|
#include "internal_includes/debug.h"
|
|
#include "internal_includes/Shader.h"
|
|
#include "internal_includes/toMetal.h"
|
|
#include <cmath>
|
|
#include <sstream>
|
|
|
|
#include <float.h>
|
|
#include <stdlib.h>
|
|
|
|
using namespace HLSLcc;
|
|
|
|
#ifdef _MSC_VER
|
|
#if _MSC_VER < 1900
|
|
#define snprintf _snprintf
|
|
#endif
|
|
#endif
|
|
|
|
#ifndef fpcheck
|
|
#ifdef _MSC_VER
|
|
#define fpcheck(x) (_isnan(x) || !_finite(x))
|
|
#else
|
|
#define fpcheck(x) (std::isnan(x) || std::isinf(x))
|
|
#endif
|
|
#endif // #ifndef fpcheck
|
|
|
|
|
|
// Returns nonzero if types are just different precisions of the same underlying type
|
|
static bool AreTypesCompatibleMetal(SHADER_VARIABLE_TYPE a, uint32_t ui32TOFlag)
|
|
{
|
|
SHADER_VARIABLE_TYPE b = TypeFlagsToSVTType(ui32TOFlag);
|
|
|
|
if (a == b)
|
|
return true;
|
|
|
|
// Special case for array indices: both uint and int are fine
|
|
if ((ui32TOFlag & TO_FLAG_INTEGER) && (ui32TOFlag & TO_FLAG_UNSIGNED_INTEGER) &&
|
|
(a == SVT_INT || a == SVT_INT16 || a == SVT_UINT || a == SVT_UINT16))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
std::string ToMetal::TranslateOperandSwizzle(const Operand* psOperand, uint32_t ui32ComponentMask, int iRebase, bool includeDot /*= true*/)
|
|
{
|
|
std::ostringstream oss;
|
|
uint32_t accessMask = ui32ComponentMask & psOperand->GetAccessMask();
|
|
if (psOperand->eType == OPERAND_TYPE_INPUT)
|
|
{
|
|
int regSpace = psOperand->GetRegisterSpace(psContext);
|
|
// Skip swizzle for scalar inputs, but only if we haven't redirected them
|
|
if (regSpace == 0)
|
|
{
|
|
if ((psContext->psShader->asPhases[psContext->currentPhase].acInputNeedsRedirect[psOperand->ui32RegisterNumber] == 0) &&
|
|
(psContext->psShader->abScalarInput[regSpace][psOperand->ui32RegisterNumber] & accessMask))
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((psContext->psShader->asPhases[psContext->currentPhase].acPatchConstantsNeedsRedirect[psOperand->ui32RegisterNumber] == 0) &&
|
|
(psContext->psShader->abScalarInput[regSpace][psOperand->ui32RegisterNumber] & accessMask))
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
if (psOperand->eType == OPERAND_TYPE_OUTPUT)
|
|
{
|
|
int regSpace = psOperand->GetRegisterSpace(psContext);
|
|
// Skip swizzle for scalar outputs, but only if we haven't redirected them
|
|
if (regSpace == 0)
|
|
{
|
|
if ((psContext->psShader->asPhases[psContext->currentPhase].acOutputNeedsRedirect[psOperand->ui32RegisterNumber] == 0) &&
|
|
(psContext->psShader->abScalarOutput[regSpace][psOperand->ui32RegisterNumber] & accessMask))
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((psContext->psShader->asPhases[psContext->currentPhase].acPatchConstantsNeedsRedirect[psOperand->ui32RegisterNumber] == 0) &&
|
|
(psContext->psShader->abScalarOutput[regSpace][psOperand->ui32RegisterNumber] & accessMask))
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (psOperand->iWriteMaskEnabled &&
|
|
psOperand->iNumComponents != 1)
|
|
{
|
|
//Component Mask
|
|
if (psOperand->eSelMode == OPERAND_4_COMPONENT_MASK_MODE)
|
|
{
|
|
uint32_t mask;
|
|
if (psOperand->ui32CompMask != 0)
|
|
mask = psOperand->ui32CompMask & ui32ComponentMask;
|
|
else
|
|
mask = ui32ComponentMask;
|
|
|
|
if (mask != 0 && mask != OPERAND_4_COMPONENT_MASK_ALL)
|
|
{
|
|
if (includeDot)
|
|
oss << ".";
|
|
if (mask & OPERAND_4_COMPONENT_MASK_X)
|
|
{
|
|
ASSERT(iRebase == 0);
|
|
oss << "x";
|
|
}
|
|
if (mask & OPERAND_4_COMPONENT_MASK_Y)
|
|
{
|
|
ASSERT(iRebase <= 1);
|
|
oss << "xy"[1 - iRebase];
|
|
}
|
|
if (mask & OPERAND_4_COMPONENT_MASK_Z)
|
|
{
|
|
ASSERT(iRebase <= 2);
|
|
oss << "xyz"[2 - iRebase];
|
|
}
|
|
if (mask & OPERAND_4_COMPONENT_MASK_W)
|
|
{
|
|
ASSERT(iRebase <= 3);
|
|
oss << "xyzw"[3 - iRebase];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
//Component Swizzle
|
|
if (psOperand->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE)
|
|
{
|
|
if (ui32ComponentMask != OPERAND_4_COMPONENT_MASK_ALL ||
|
|
!(psOperand->aui32Swizzle[0] == OPERAND_4_COMPONENT_X &&
|
|
psOperand->aui32Swizzle[1] == OPERAND_4_COMPONENT_Y &&
|
|
psOperand->aui32Swizzle[2] == OPERAND_4_COMPONENT_Z &&
|
|
psOperand->aui32Swizzle[3] == OPERAND_4_COMPONENT_W
|
|
)
|
|
)
|
|
{
|
|
uint32_t i;
|
|
|
|
if (includeDot)
|
|
oss << ".";
|
|
|
|
for (i = 0; i < 4; ++i)
|
|
{
|
|
if (!(ui32ComponentMask & (OPERAND_4_COMPONENT_MASK_X << i)))
|
|
continue;
|
|
|
|
if (psOperand->aui32Swizzle[i] == OPERAND_4_COMPONENT_X)
|
|
{
|
|
ASSERT(iRebase == 0);
|
|
oss << "x";
|
|
}
|
|
else if (psOperand->aui32Swizzle[i] == OPERAND_4_COMPONENT_Y)
|
|
{
|
|
ASSERT(iRebase <= 1);
|
|
oss << "xy"[1 - iRebase];
|
|
}
|
|
else if (psOperand->aui32Swizzle[i] == OPERAND_4_COMPONENT_Z)
|
|
{
|
|
ASSERT(iRebase <= 2);
|
|
oss << "xyz"[2 - iRebase];
|
|
}
|
|
else if (psOperand->aui32Swizzle[i] == OPERAND_4_COMPONENT_W)
|
|
{
|
|
ASSERT(iRebase <= 3);
|
|
oss << "xyzw"[3 - iRebase];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (psOperand->eSelMode == OPERAND_4_COMPONENT_SELECT_1_MODE) // ui32ComponentMask is ignored in this case
|
|
{
|
|
if (includeDot)
|
|
oss << ".";
|
|
|
|
if (psOperand->aui32Swizzle[0] == OPERAND_4_COMPONENT_X)
|
|
{
|
|
ASSERT(iRebase == 0);
|
|
oss << "x";
|
|
}
|
|
else if (psOperand->aui32Swizzle[0] == OPERAND_4_COMPONENT_Y)
|
|
{
|
|
ASSERT(iRebase <= 1);
|
|
oss << "xy"[1 - iRebase];
|
|
}
|
|
else if (psOperand->aui32Swizzle[0] == OPERAND_4_COMPONENT_Z)
|
|
{
|
|
ASSERT(iRebase <= 2);
|
|
oss << "xyz"[2 - iRebase];
|
|
}
|
|
else if (psOperand->aui32Swizzle[0] == OPERAND_4_COMPONENT_W)
|
|
{
|
|
ASSERT(iRebase <= 3);
|
|
oss << "xyzw"[3 - iRebase];
|
|
}
|
|
}
|
|
}
|
|
return oss.str();
|
|
}
|
|
|
|
std::string ToMetal::TranslateOperandIndex(const Operand* psOperand, int index)
|
|
{
|
|
int i = index;
|
|
std::ostringstream oss;
|
|
ASSERT(index < psOperand->iIndexDims);
|
|
|
|
switch (psOperand->eIndexRep[i])
|
|
{
|
|
case OPERAND_INDEX_IMMEDIATE32:
|
|
{
|
|
oss << "[" << psOperand->aui32ArraySizes[i] << "]";
|
|
return oss.str();
|
|
}
|
|
case OPERAND_INDEX_RELATIVE:
|
|
{
|
|
oss << "[" << TranslateOperand(psOperand->m_SubOperands[i].get(), TO_FLAG_INTEGER) << "]";
|
|
return oss.str();
|
|
}
|
|
case OPERAND_INDEX_IMMEDIATE32_PLUS_RELATIVE:
|
|
{
|
|
oss << "[" << TranslateOperand(psOperand->m_SubOperands[i].get(), TO_FLAG_INTEGER) << " + " << psOperand->aui32ArraySizes[i] << "]";
|
|
return oss.str();
|
|
}
|
|
default:
|
|
{
|
|
ASSERT(0);
|
|
return "";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*static std::string GetBitcastOp(HLSLCrossCompilerContext *psContext, SHADER_VARIABLE_TYPE from, SHADER_VARIABLE_TYPE to, uint32_t numComponents)
|
|
{
|
|
if (psContext->psShader->eTargetLanguage == LANG_METAL)
|
|
{
|
|
std::ostringstream oss;
|
|
oss << "as_type<";
|
|
oss << GetConstructorForTypeMetal(to, numComponents);
|
|
oss << ">";
|
|
return oss.str();
|
|
}
|
|
else
|
|
{
|
|
if ((to == SVT_FLOAT || to == SVT_FLOAT16 || to == SVT_FLOAT10) && from == SVT_INT)
|
|
return "intBitsToFloat";
|
|
else if ((to == SVT_FLOAT || to == SVT_FLOAT16 || to == SVT_FLOAT10) && from == SVT_UINT)
|
|
return "uintBitsToFloat";
|
|
else if (to == SVT_INT && from == SVT_FLOAT)
|
|
return "floatBitsToInt";
|
|
else if (to == SVT_UINT && from == SVT_FLOAT)
|
|
return "floatBitsToUint";
|
|
}
|
|
|
|
ASSERT(0);
|
|
return "ERROR missing components in GetBitcastOp()";
|
|
}*/
|
|
|
|
|
|
// Helper function to print floats with full precision
|
|
static std::string printFloat(float f)
|
|
{
|
|
char temp[30];
|
|
|
|
snprintf(temp, 30, "%.9g", f);
|
|
char * ePos = strchr(temp, 'e');
|
|
char * pointPos = strchr(temp, '.');
|
|
|
|
if (ePos == NULL && pointPos == NULL && !fpcheck(f))
|
|
return std::string(temp) + ".0";
|
|
else
|
|
return std::string(temp);
|
|
}
|
|
|
|
// Helper function to print out a single 32-bit immediate value in desired format
|
|
static std::string printImmediate32(uint32_t value, SHADER_VARIABLE_TYPE eType)
|
|
{
|
|
std::ostringstream oss;
|
|
int needsParenthesis = 0;
|
|
|
|
// Print floats as bit patterns.
|
|
if ((eType == SVT_FLOAT || eType == SVT_FLOAT16 || eType == SVT_FLOAT10) && fpcheck(*((float *)(&value))))
|
|
{
|
|
oss << "as_type<float>(";
|
|
eType = SVT_INT;
|
|
needsParenthesis = 1;
|
|
}
|
|
|
|
switch (eType)
|
|
{
|
|
default:
|
|
ASSERT(0);
|
|
case SVT_INT:
|
|
case SVT_INT16:
|
|
case SVT_INT12:
|
|
// Need special handling for anything >= uint 0x3fffffff
|
|
if (value > 0x3ffffffe)
|
|
oss << "int(0x" << std::hex << value << "u)";
|
|
else
|
|
oss << "0x" << std::hex << value << "";
|
|
break;
|
|
case SVT_UINT:
|
|
case SVT_UINT16:
|
|
oss << "0x" << std::hex << value << "u";
|
|
break;
|
|
case SVT_FLOAT:
|
|
case SVT_FLOAT10:
|
|
case SVT_FLOAT16:
|
|
oss << printFloat(*((float *)(&value)));
|
|
break;
|
|
case SVT_BOOL:
|
|
if (value == 0)
|
|
oss << "false";
|
|
else
|
|
oss << "true";
|
|
}
|
|
if (needsParenthesis)
|
|
oss << ")";
|
|
|
|
return oss.str();
|
|
}
|
|
|
|
static std::string MakeCBVarName(const std::string &cbName, const std::string &fullName, bool isUnityInstancingBuffer)
|
|
{
|
|
// For Unity instancing buffer: "CBufferName.StructTypeName[] -> CBufferName[]". See ToMetal::DeclareConstantBuffer.
|
|
if (isUnityInstancingBuffer && !cbName.empty() && cbName[cbName.size() - 1] == '.' && fullName.find_first_of('[') != std::string::npos)
|
|
{
|
|
return cbName.substr(0, cbName.size() - 1) + fullName.substr(fullName.find_first_of('['));
|
|
}
|
|
return cbName + fullName;
|
|
}
|
|
|
|
std::string ToMetal::TranslateVariableName(const Operand* psOperand, uint32_t ui32TOFlag, uint32_t* pui32IgnoreSwizzle, uint32_t ui32CompMask, int *piRebase)
|
|
{
|
|
std::ostringstream oss;
|
|
int numParenthesis = 0;
|
|
int hasCtor = 0;
|
|
int needsBoolUpscale = 0; // If nonzero, bools need * 0xffffffff in them
|
|
SHADER_VARIABLE_TYPE requestedType = TypeFlagsToSVTType(ui32TOFlag);
|
|
SHADER_VARIABLE_TYPE eType = psOperand->GetDataType(psContext, requestedType);
|
|
int numComponents = psOperand->GetNumSwizzleElements(ui32CompMask);
|
|
int requestedComponents = 0;
|
|
int scalarWithSwizzle = 0;
|
|
|
|
*pui32IgnoreSwizzle = 0;
|
|
|
|
if (psOperand->eType == OPERAND_TYPE_TEMP)
|
|
{
|
|
// Check for scalar
|
|
if (psContext->psShader->GetTempComponentCount(eType, psOperand->ui32RegisterNumber) == 1 && psOperand->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE)
|
|
{
|
|
scalarWithSwizzle = 1; // Going to need a constructor
|
|
}
|
|
}
|
|
|
|
if (psOperand->eType == OPERAND_TYPE_INPUT)
|
|
{
|
|
// Check for scalar
|
|
// You would think checking would be easy but there is a caveat:
|
|
// checking abScalarInput might report as scalar, while in reality that was redirected and now is vector so swizzle must be preserved
|
|
// as an example consider we have input:
|
|
// float2 x; float y;
|
|
// and later on we do
|
|
// tex2D(xxx, fixed2(x.x, y));
|
|
// in that case we will generate redirect but which ui32RegisterNumber will be used for it is not strictly "specified"
|
|
// so we may end up with treating it as scalar (even though it is vector now)
|
|
const int redirectInput = psContext->psShader->asPhases[psContext->currentPhase].acInputNeedsRedirect[psOperand->ui32RegisterNumber];
|
|
const bool wasRedirected = redirectInput == 0xFF || redirectInput == 0xFE;
|
|
|
|
const int scalarInput = psContext->psShader->abScalarInput[psOperand->GetRegisterSpace(psContext)][psOperand->ui32RegisterNumber];
|
|
if (!wasRedirected && (scalarInput & psOperand->GetAccessMask()) && (psOperand->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE))
|
|
{
|
|
scalarWithSwizzle = 1;
|
|
*pui32IgnoreSwizzle = 1;
|
|
}
|
|
}
|
|
|
|
if (piRebase)
|
|
*piRebase = 0;
|
|
|
|
if (ui32TOFlag & TO_AUTO_EXPAND_TO_VEC2)
|
|
requestedComponents = 2;
|
|
else if (ui32TOFlag & TO_AUTO_EXPAND_TO_VEC3)
|
|
requestedComponents = 3;
|
|
else if (ui32TOFlag & TO_AUTO_EXPAND_TO_VEC4)
|
|
requestedComponents = 4;
|
|
|
|
requestedComponents = std::max(requestedComponents, numComponents);
|
|
|
|
if (!(ui32TOFlag & (TO_FLAG_DESTINATION | TO_FLAG_NAME_ONLY | TO_FLAG_DECLARATION_NAME)))
|
|
{
|
|
if (psOperand->eType == OPERAND_TYPE_IMMEDIATE32 || psOperand->eType == OPERAND_TYPE_IMMEDIATE64)
|
|
{
|
|
// Mark the operand type to match whatever we're asking for in the flags.
|
|
((Operand *)psOperand)->aeDataType[0] = requestedType;
|
|
((Operand *)psOperand)->aeDataType[1] = requestedType;
|
|
((Operand *)psOperand)->aeDataType[2] = requestedType;
|
|
((Operand *)psOperand)->aeDataType[3] = requestedType;
|
|
}
|
|
|
|
bool bitcast = false;
|
|
if (AreTypesCompatibleMetal(eType, ui32TOFlag) == 0)
|
|
{
|
|
if (CanDoDirectCast(psContext, eType, requestedType))
|
|
{
|
|
hasCtor = 1;
|
|
if (eType == SVT_BOOL)
|
|
{
|
|
needsBoolUpscale = 1;
|
|
// make sure to wrap the whole thing in parens so the upscale
|
|
// multiply only applies to the bool
|
|
oss << "(";
|
|
numParenthesis++;
|
|
}
|
|
oss << GetConstructorForType(psContext, requestedType, requestedComponents, false) << "(";
|
|
numParenthesis++;
|
|
}
|
|
else
|
|
{
|
|
// Direct cast not possible, need to do bitcast.
|
|
oss << "as_type<" << GetConstructorForTypeMetal(requestedType, requestedComponents) << ">(";
|
|
hasCtor = 1;
|
|
bitcast = true;
|
|
numParenthesis++;
|
|
}
|
|
}
|
|
|
|
// Add ctor if needed (upscaling). Type conversion is already handled above, so here we must
|
|
// use the original type to not make type conflicts in bitcasts
|
|
bool needsUpscaling = ((numComponents < requestedComponents) || (scalarWithSwizzle != 0)) && (hasCtor == 0 || bitcast);
|
|
|
|
// Add constuctor if half precision is forced to avoid template ambiguity error from compiler
|
|
bool needsForcedCtor = (ui32TOFlag & TO_FLAG_FORCE_HALF) && (psOperand->eType == OPERAND_TYPE_IMMEDIATE32 || psOperand->eType == OPERAND_TYPE_IMMEDIATE64);
|
|
|
|
if (needsForcedCtor)
|
|
requestedComponents = std::max(requestedComponents, 1);
|
|
|
|
if (needsUpscaling || needsForcedCtor)
|
|
{
|
|
oss << GetConstructorForType(psContext, eType, requestedComponents, false) << "(";
|
|
|
|
numParenthesis++;
|
|
hasCtor = 1;
|
|
}
|
|
}
|
|
|
|
|
|
switch (psOperand->eType)
|
|
{
|
|
case OPERAND_TYPE_IMMEDIATE32:
|
|
{
|
|
if (psOperand->iNumComponents == 1)
|
|
{
|
|
oss << printImmediate32(*((unsigned int*)(&psOperand->afImmediates[0])), requestedType);
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
int firstItemAdded = 0;
|
|
if (hasCtor == 0)
|
|
{
|
|
oss << GetConstructorForTypeMetal(requestedType, requestedComponents) << "(";
|
|
numParenthesis++;
|
|
hasCtor = 1;
|
|
}
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
uint32_t uval;
|
|
if (!(ui32CompMask & (1 << i)))
|
|
continue;
|
|
|
|
if (firstItemAdded)
|
|
oss << ", ";
|
|
uval = *((uint32_t*)(&psOperand->afImmediates[i >= psOperand->iNumComponents ? psOperand->iNumComponents - 1 : i]));
|
|
oss << printImmediate32(uval, requestedType);
|
|
firstItemAdded = 1;
|
|
}
|
|
oss << ")";
|
|
*pui32IgnoreSwizzle = 1;
|
|
numParenthesis--;
|
|
}
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_IMMEDIATE64:
|
|
{
|
|
ASSERT(0); // doubles not supported on Metal
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_INPUT:
|
|
{
|
|
int regSpace = psOperand->GetRegisterSpace(psContext);
|
|
switch (psOperand->iIndexDims)
|
|
{
|
|
case INDEX_2D:
|
|
{
|
|
const ShaderInfo::InOutSignature *psSig = NULL;
|
|
psContext->psShader->sInfo.GetInputSignatureFromRegister(psOperand->ui32RegisterNumber, psOperand->ui32CompMask, &psSig);
|
|
if (psContext->psShader->eShaderType == HULL_SHADER || psContext->psShader->eShaderType == DOMAIN_SHADER)
|
|
{
|
|
oss << "input.cp";
|
|
oss << TranslateOperandIndex(psOperand, 0);//Vertex index
|
|
oss << "." << psContext->GetDeclaredInputName(psOperand, piRebase, 1, pui32IgnoreSwizzle);
|
|
}
|
|
else
|
|
{
|
|
// Not sure if this codepath is active outside hull/domain
|
|
oss << psContext->GetDeclaredInputName(psOperand, piRebase, 0, pui32IgnoreSwizzle);
|
|
|
|
oss << TranslateOperandIndex(psOperand, 0);//Vertex index
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
if (psOperand->eIndexRep[0] == OPERAND_INDEX_IMMEDIATE32_PLUS_RELATIVE)
|
|
{
|
|
ASSERT(psContext->psShader->aIndexedInput[regSpace][psOperand->ui32RegisterNumber] != 0);
|
|
oss << "phase" << psContext->currentPhase << "_Input" << regSpace << "_" << psOperand->ui32RegisterNumber << "[";
|
|
oss << TranslateOperand(psOperand->m_SubOperands[0].get(), TO_FLAG_INTEGER);
|
|
oss << "]";
|
|
}
|
|
else
|
|
{
|
|
if (psContext->psShader->aIndexedInput[regSpace][psOperand->ui32RegisterNumber] != 0)
|
|
{
|
|
const uint32_t parentIndex = psContext->psShader->aIndexedInputParents[regSpace][psOperand->ui32RegisterNumber];
|
|
oss << "phase" << psContext->currentPhase << "_Input" << regSpace << "_" << parentIndex << "[" << (psOperand->ui32RegisterNumber - parentIndex) << "]";
|
|
}
|
|
else
|
|
{
|
|
oss << psContext->GetDeclaredInputName(psOperand, piRebase, 0, pui32IgnoreSwizzle);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_OUTPUT:
|
|
case OPERAND_TYPE_OUTPUT_DEPTH:
|
|
case OPERAND_TYPE_OUTPUT_DEPTH_GREATER_EQUAL:
|
|
case OPERAND_TYPE_OUTPUT_DEPTH_LESS_EQUAL:
|
|
{
|
|
int stream = 0;
|
|
oss << psContext->GetDeclaredOutputName(psOperand, &stream, pui32IgnoreSwizzle, piRebase, 0);
|
|
if (psOperand->m_SubOperands[0].get())
|
|
{
|
|
oss << "[";
|
|
oss << TranslateOperand(psOperand->m_SubOperands[0].get(), TO_AUTO_BITCAST_TO_INT);
|
|
oss << "]";
|
|
}
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_TEMP:
|
|
{
|
|
SHADER_VARIABLE_TYPE eTempType = psOperand->GetDataType(psContext);
|
|
|
|
if (psOperand->eSpecialName == NAME_UNDEFINED && psOperand->specialName.length())
|
|
{
|
|
oss << psOperand->specialName;
|
|
break;
|
|
}
|
|
|
|
oss << HLSLCC_TEMP_PREFIX;
|
|
ASSERT(psOperand->ui32RegisterNumber < 0x10000); // Sanity check after temp splitting.
|
|
switch (eTempType)
|
|
{
|
|
case SVT_FLOAT:
|
|
ASSERT(psContext->psShader->psFloatTempSizes[psOperand->ui32RegisterNumber] != 0);
|
|
if (psContext->psShader->psFloatTempSizes[psOperand->ui32RegisterNumber] == 1)
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case SVT_FLOAT16:
|
|
ASSERT(psContext->psShader->psFloat16TempSizes[psOperand->ui32RegisterNumber] != 0);
|
|
oss << ("16_");
|
|
if (psContext->psShader->psFloat16TempSizes[psOperand->ui32RegisterNumber] == 1)
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case SVT_FLOAT10:
|
|
ASSERT(psContext->psShader->psFloat10TempSizes[psOperand->ui32RegisterNumber] != 0);
|
|
oss << ("10_");
|
|
if (psContext->psShader->psFloat10TempSizes[psOperand->ui32RegisterNumber] == 1)
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case SVT_INT:
|
|
ASSERT(psContext->psShader->psIntTempSizes[psOperand->ui32RegisterNumber] != 0);
|
|
oss << ("i");
|
|
if (psContext->psShader->psIntTempSizes[psOperand->ui32RegisterNumber] == 1)
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case SVT_INT16:
|
|
ASSERT(psContext->psShader->psInt16TempSizes[psOperand->ui32RegisterNumber] != 0);
|
|
oss << ("i16_");
|
|
if (psContext->psShader->psInt16TempSizes[psOperand->ui32RegisterNumber] == 1)
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case SVT_INT12:
|
|
ASSERT(psContext->psShader->psInt12TempSizes[psOperand->ui32RegisterNumber] != 0);
|
|
oss << ("i12_");
|
|
if (psContext->psShader->psInt12TempSizes[psOperand->ui32RegisterNumber] == 1)
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case SVT_UINT:
|
|
ASSERT(psContext->psShader->psUIntTempSizes[psOperand->ui32RegisterNumber] != 0);
|
|
oss << ("u");
|
|
if (psContext->psShader->psUIntTempSizes[psOperand->ui32RegisterNumber] == 1)
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case SVT_UINT16:
|
|
ASSERT(psContext->psShader->psUInt16TempSizes[psOperand->ui32RegisterNumber] != 0);
|
|
oss << ("u16_");
|
|
if (psContext->psShader->psUInt16TempSizes[psOperand->ui32RegisterNumber] == 1)
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case SVT_DOUBLE:
|
|
ASSERT(psContext->psShader->psDoubleTempSizes[psOperand->ui32RegisterNumber] != 0);
|
|
oss << ("d");
|
|
if (psContext->psShader->psDoubleTempSizes[psOperand->ui32RegisterNumber] == 1)
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case SVT_BOOL:
|
|
ASSERT(psContext->psShader->psBoolTempSizes[psOperand->ui32RegisterNumber] != 0);
|
|
oss << ("b");
|
|
if (psContext->psShader->psBoolTempSizes[psOperand->ui32RegisterNumber] == 1)
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
default:
|
|
ASSERT(0 && "Should never get here!");
|
|
}
|
|
oss << psOperand->ui32RegisterNumber;
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_SPECIAL_IMMCONSTINT:
|
|
case OPERAND_TYPE_SPECIAL_IMMCONST:
|
|
case OPERAND_TYPE_SPECIAL_OUTBASECOLOUR:
|
|
case OPERAND_TYPE_SPECIAL_OUTOFFSETCOLOUR:
|
|
case OPERAND_TYPE_SPECIAL_FOG:
|
|
case OPERAND_TYPE_SPECIAL_ADDRESS:
|
|
case OPERAND_TYPE_SPECIAL_LOOPCOUNTER:
|
|
case OPERAND_TYPE_SPECIAL_TEXCOORD:
|
|
{
|
|
ASSERT(0 && "DX9 shaders no longer supported!");
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_SPECIAL_POSITION:
|
|
{
|
|
ASSERT(0 && "TODO normal shader support");
|
|
// bcatcstr(glsl, "gl_Position");
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_SPECIAL_POINTSIZE:
|
|
{
|
|
ASSERT(0 && "TODO normal shader support");
|
|
// bcatcstr(glsl, "gl_PointSize");
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_CONSTANT_BUFFER:
|
|
{
|
|
const ConstantBuffer* psCBuf = NULL;
|
|
const ShaderVarType* psVarType = NULL;
|
|
int32_t index = -1;
|
|
std::vector<uint32_t> arrayIndices;
|
|
bool isArray = false;
|
|
bool isFBInput = false;
|
|
psContext->psShader->sInfo.GetConstantBufferFromBindingPoint(RGROUP_CBUFFER, psOperand->aui32ArraySizes[0], &psCBuf);
|
|
ASSERT(psCBuf != NULL);
|
|
|
|
if (ui32TOFlag & TO_FLAG_DECLARATION_NAME)
|
|
{
|
|
pui32IgnoreSwizzle[0] = 1;
|
|
}
|
|
std::string cbName = "";
|
|
if (psCBuf)
|
|
{
|
|
//$Globals.
|
|
cbName = GetCBName(psCBuf->name);
|
|
cbName += ".";
|
|
// Drop the constant buffer name from subpass inputs
|
|
if (cbName.substr(0, 19) == "hlslcc_SubpassInput")
|
|
cbName = "";
|
|
}
|
|
|
|
if ((ui32TOFlag & TO_FLAG_DECLARATION_NAME) != TO_FLAG_DECLARATION_NAME)
|
|
{
|
|
//Work out the variable name. Don't apply swizzle to that variable yet.
|
|
int32_t rebase = 0;
|
|
|
|
ASSERT(psCBuf != NULL);
|
|
|
|
uint32_t componentsNeeded = 1;
|
|
if (psOperand->eSelMode != OPERAND_4_COMPONENT_SELECT_1_MODE)
|
|
{
|
|
uint32_t minSwiz = 3;
|
|
uint32_t maxSwiz = 0;
|
|
int i;
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
if ((ui32CompMask & (1 << i)) == 0)
|
|
continue;
|
|
minSwiz = std::min(minSwiz, psOperand->aui32Swizzle[i]);
|
|
maxSwiz = std::max(maxSwiz, psOperand->aui32Swizzle[i]);
|
|
}
|
|
componentsNeeded = maxSwiz - minSwiz + 1;
|
|
}
|
|
|
|
// When we have a component mask that doesn't have .x set (this basically only happens when we manually open operands into components)
|
|
// We have to pull down the swizzle array to match the first bit that's actually set
|
|
uint32_t tmpSwizzle[4] = { 0 };
|
|
int firstBitSet = 0;
|
|
if (ui32CompMask == 0)
|
|
ui32CompMask = 0xf;
|
|
while ((ui32CompMask & (1 << firstBitSet)) == 0)
|
|
firstBitSet++;
|
|
std::copy(&psOperand->aui32Swizzle[firstBitSet], &psOperand->aui32Swizzle[4], &tmpSwizzle[0]);
|
|
|
|
ShaderInfo::GetShaderVarFromOffset(psOperand->aui32ArraySizes[1], tmpSwizzle, psCBuf, &psVarType, &isArray, &arrayIndices, &rebase, psContext->flags);
|
|
|
|
// Get a possible dynamic array index
|
|
std::string dynamicIndexStr;
|
|
bool needsIndexCalcRevert = false;
|
|
bool isAoS = ((!isArray && arrayIndices.size() > 0) || (isArray && arrayIndices.size() > 1));
|
|
bool isUnityInstancingBuffer = isAoS && IsUnityFlexibleInstancingBuffer(psCBuf);
|
|
Operand *psDynIndexOp = psOperand->GetDynamicIndexOperand(psContext, psVarType, isAoS, &needsIndexCalcRevert);
|
|
|
|
if (psDynIndexOp != NULL)
|
|
{
|
|
SHADER_VARIABLE_TYPE eType = psDynIndexOp->GetDataType(psContext);
|
|
uint32_t opFlags = TO_FLAG_INTEGER;
|
|
|
|
if (eType != SVT_INT && eType != SVT_UINT)
|
|
opFlags = TO_AUTO_BITCAST_TO_INT;
|
|
|
|
dynamicIndexStr = TranslateOperand(psDynIndexOp, opFlags, 0x1); // Just take the first component for the index
|
|
}
|
|
|
|
if (psOperand->eSelMode == OPERAND_4_COMPONENT_SELECT_1_MODE || (componentsNeeded <= psVarType->Columns))
|
|
{
|
|
// Simple case: just access one component
|
|
std::string fullName = ShaderInfo::GetShaderVarIndexedFullName(psVarType, arrayIndices, dynamicIndexStr, needsIndexCalcRevert, psContext->flags & HLSLCC_FLAG_TRANSLATE_MATRICES);
|
|
|
|
// Special hack for MSAA subpass inputs: in Metal we can only read the "current" sample, so ignore the index
|
|
if (strncmp(fullName.c_str(), "hlslcc_fbinput", 14) == 0)
|
|
isFBInput = true;
|
|
|
|
if (((psContext->flags & HLSLCC_FLAG_TRANSLATE_MATRICES) != 0) && ((psVarType->Class == SVC_MATRIX_ROWS) || (psVarType->Class == SVC_MATRIX_COLUMNS)))
|
|
{
|
|
// We'll need to add the prefix only to the last section of the name
|
|
size_t commaPos = fullName.find_last_of('.');
|
|
char prefix[256];
|
|
sprintf(prefix, HLSLCC_TRANSLATE_MATRIX_FORMAT_STRING, psVarType->Rows, psVarType->Columns);
|
|
if (commaPos == std::string::npos)
|
|
fullName.insert(0, prefix);
|
|
else
|
|
fullName.insert(commaPos + 1, prefix);
|
|
}
|
|
|
|
oss << MakeCBVarName(cbName, fullName, isUnityInstancingBuffer);
|
|
}
|
|
else
|
|
{
|
|
// Non-simple case: build vec4 and apply mask
|
|
uint32_t i;
|
|
int32_t tmpRebase;
|
|
std::vector<uint32_t> tmpArrayIndices;
|
|
bool tmpIsArray;
|
|
int firstItemAdded = 0;
|
|
|
|
oss << GetConstructorForTypeMetal(psVarType->Type, GetNumberBitsSet(ui32CompMask)) << "(";
|
|
for (i = 0; i < 4; i++)
|
|
{
|
|
const ShaderVarType *tmpVarType = NULL;
|
|
if ((ui32CompMask & (1 << i)) == 0)
|
|
continue;
|
|
tmpRebase = 0;
|
|
if (firstItemAdded != 0)
|
|
oss << ", ";
|
|
else
|
|
firstItemAdded = 1;
|
|
|
|
uint32_t tmpSwizzle[4] = { 0 };
|
|
std::copy(&psOperand->aui32Swizzle[i], &psOperand->aui32Swizzle[4], &tmpSwizzle[0]);
|
|
|
|
ShaderInfo::GetShaderVarFromOffset(psOperand->aui32ArraySizes[1], tmpSwizzle, psCBuf, &tmpVarType, &tmpIsArray, &tmpArrayIndices, &tmpRebase, psContext->flags);
|
|
std::string fullName = ShaderInfo::GetShaderVarIndexedFullName(tmpVarType, tmpArrayIndices, dynamicIndexStr, needsIndexCalcRevert, psContext->flags & HLSLCC_FLAG_TRANSLATE_MATRICES);
|
|
oss << MakeCBVarName(cbName, fullName, isUnityInstancingBuffer);
|
|
|
|
if (tmpVarType->Class != SVC_SCALAR)
|
|
{
|
|
uint32_t swizzle;
|
|
tmpRebase /= 4; // 0 => 0, 4 => 1, 8 => 2, 12 /= 3
|
|
swizzle = psOperand->aui32Swizzle[i] - tmpRebase;
|
|
|
|
oss << "." << ("xyzw"[swizzle]);
|
|
}
|
|
}
|
|
oss << ")";
|
|
// Clear rebase, we've already done it.
|
|
rebase = 0;
|
|
// Also swizzle.
|
|
*pui32IgnoreSwizzle = 1;
|
|
}
|
|
|
|
|
|
if (isArray)
|
|
{
|
|
index = arrayIndices.back();
|
|
|
|
// Dynamic index is atm supported only at the root array level. Add here only if there is no such parent.
|
|
bool hasDynamicIndex = !dynamicIndexStr.empty() && (arrayIndices.size() <= 1);
|
|
bool hasImmediateIndex = (index != -1) && !(hasDynamicIndex && index == 0);
|
|
|
|
// Ignore index altogether on fb inputs
|
|
if (isFBInput)
|
|
{
|
|
// Nothing to do here
|
|
}
|
|
else if (hasDynamicIndex || hasImmediateIndex)
|
|
{
|
|
std::ostringstream fullIndexOss;
|
|
if (hasDynamicIndex && hasImmediateIndex)
|
|
fullIndexOss << "(" << dynamicIndexStr << " + " << index << ")";
|
|
else if (hasDynamicIndex)
|
|
fullIndexOss << dynamicIndexStr;
|
|
else // hasImmediateStr
|
|
fullIndexOss << index;
|
|
|
|
if (((psVarType->Class == SVC_MATRIX_COLUMNS) || (psVarType->Class == SVC_MATRIX_ROWS)) && (psVarType->Elements > 1) && ((psContext->flags & HLSLCC_FLAG_TRANSLATE_MATRICES) == 0))
|
|
{
|
|
// Special handling for old matrix arrays
|
|
oss << "[" << fullIndexOss.str() << " / 4]";
|
|
oss << "[" << fullIndexOss.str() << " %% 4]";
|
|
}
|
|
else // This path is atm the default
|
|
{
|
|
oss << "[" << fullIndexOss.str() << "]";
|
|
}
|
|
}
|
|
}
|
|
|
|
if (psVarType->Class == SVC_VECTOR && !*pui32IgnoreSwizzle)
|
|
{
|
|
switch (rebase)
|
|
{
|
|
case 4:
|
|
{
|
|
if (psVarType->Columns == 2)
|
|
{
|
|
//.x(GLSL) is .y(HLSL). .y(GLSL) is .z(HLSL)
|
|
oss << ".xxyx";
|
|
}
|
|
else if (psVarType->Columns == 3)
|
|
{
|
|
//.x(GLSL) is .y(HLSL). .y(GLSL) is .z(HLSL) .z(GLSL) is .w(HLSL)
|
|
oss << ".xxyz";
|
|
}
|
|
break;
|
|
}
|
|
case 8:
|
|
{
|
|
if (psVarType->Columns == 2)
|
|
{
|
|
//.x(GLSL) is .z(HLSL). .y(GLSL) is .w(HLSL)
|
|
oss << ".xxxy";
|
|
}
|
|
break;
|
|
}
|
|
case 0:
|
|
default:
|
|
{
|
|
//No rebase, but extend to vec4.
|
|
if (psVarType->Columns == 2)
|
|
{
|
|
oss << ".xyxx";
|
|
}
|
|
else if (psVarType->Columns == 3)
|
|
{
|
|
oss << ".xyzx";
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (psVarType->Class == SVC_SCALAR)
|
|
{
|
|
*pui32IgnoreSwizzle = 1;
|
|
|
|
// CB arrays are all declared as 4-component vectors to match DX11 data layout.
|
|
// Therefore add swizzle here to access the element corresponding to the scalar var.
|
|
if ((psVarType->Elements > 0) && (psContext->psShader->eShaderType == COMPUTE_SHADER))
|
|
{
|
|
oss << ".x";
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_RESOURCE:
|
|
{
|
|
oss << ResourceName(RGROUP_TEXTURE, psOperand->ui32RegisterNumber);
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_SAMPLER:
|
|
{
|
|
oss << ResourceName(RGROUP_SAMPLER, psOperand->ui32RegisterNumber);
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_FUNCTION_BODY:
|
|
{
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_INPUT_FORK_INSTANCE_ID:
|
|
case OPERAND_TYPE_INPUT_JOIN_INSTANCE_ID:
|
|
{
|
|
oss << "phaseInstanceID"; // Not a real builtin, but passed as a function parameter.
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_IMMEDIATE_CONSTANT_BUFFER:
|
|
{
|
|
oss << "ImmCB_" << psContext->currentPhase;
|
|
oss << TranslateOperandIndex(psOperand, 0);
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_INPUT_DOMAIN_POINT:
|
|
{
|
|
oss << "mtl_TessCoord";
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_INPUT_CONTROL_POINT:
|
|
{
|
|
int ignoreRedirect = 1;
|
|
int regSpace = psOperand->GetRegisterSpace(psContext);
|
|
|
|
if ((regSpace == 0 && psContext->psShader->asPhases[psContext->currentPhase].acInputNeedsRedirect[psOperand->ui32RegisterNumber] == 0xfe) ||
|
|
(regSpace == 1 && psContext->psShader->asPhases[psContext->currentPhase].acPatchConstantsNeedsRedirect[psOperand->ui32RegisterNumber] == 0xfe))
|
|
{
|
|
ignoreRedirect = 0;
|
|
}
|
|
|
|
if (ignoreRedirect)
|
|
{
|
|
oss << "input.cp";
|
|
oss << TranslateOperandIndex(psOperand, 0);//Vertex index
|
|
oss << "." << psContext->GetDeclaredInputName(psOperand, piRebase, ignoreRedirect, pui32IgnoreSwizzle);
|
|
}
|
|
else
|
|
{
|
|
oss << psContext->GetDeclaredInputName(psOperand, piRebase, ignoreRedirect, pui32IgnoreSwizzle);
|
|
oss << TranslateOperandIndex(psOperand, 0);//Vertex index
|
|
}
|
|
|
|
// Check for scalar
|
|
if ((psContext->psShader->abScalarInput[psOperand->GetRegisterSpace(psContext)][psOperand->ui32RegisterNumber] & psOperand->GetAccessMask()) != 0)
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_NULL:
|
|
{
|
|
// Null register, used to discard results of operations
|
|
oss << "//null";
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_OUTPUT_CONTROL_POINT_ID:
|
|
{
|
|
oss << "controlPointID";
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_OUTPUT_COVERAGE_MASK:
|
|
{
|
|
oss << "mtl_CoverageMask";
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_INPUT_COVERAGE_MASK:
|
|
{
|
|
oss << "mtl_CoverageMask";
|
|
//Skip swizzle on scalar types.
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_INPUT_THREAD_ID://SV_DispatchThreadID
|
|
{
|
|
oss << "mtl_ThreadID";
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_INPUT_THREAD_ID_IN_GROUP://SV_GroupThreadID
|
|
{
|
|
oss << "mtl_ThreadIDInGroup";
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_INPUT_THREAD_GROUP_ID://SV_GroupID
|
|
{
|
|
oss << "mtl_ThreadGroupID";
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_INPUT_THREAD_ID_IN_GROUP_FLATTENED://SV_GroupIndex
|
|
{
|
|
if (requestedComponents > 1 && !hasCtor)
|
|
{
|
|
oss << GetConstructorForType(psContext, eType, requestedComponents, false) << "(";
|
|
numParenthesis++;
|
|
hasCtor = 1;
|
|
}
|
|
for (uint32_t i = 0; i < requestedComponents; i++)
|
|
{
|
|
oss << "mtl_ThreadIndexInThreadGroup";
|
|
if (i < requestedComponents - 1)
|
|
oss << ", ";
|
|
}
|
|
*pui32IgnoreSwizzle = 1; // No swizzle meaningful for scalar.
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_UNORDERED_ACCESS_VIEW:
|
|
{
|
|
oss << ResourceName(RGROUP_UAV, psOperand->ui32RegisterNumber);
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY:
|
|
{
|
|
oss << "TGSM" << psOperand->ui32RegisterNumber;
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_INPUT_PRIMITIVEID:
|
|
{
|
|
// Not supported on Metal
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_INDEXABLE_TEMP:
|
|
{
|
|
oss << "TempArray" << psOperand->aui32ArraySizes[0] << "[";
|
|
if (psOperand->aui32ArraySizes[1] != 0 || !psOperand->m_SubOperands[1].get())
|
|
oss << psOperand->aui32ArraySizes[1];
|
|
|
|
if (psOperand->m_SubOperands[1].get())
|
|
{
|
|
if (psOperand->aui32ArraySizes[1] != 0)
|
|
oss << "+";
|
|
oss << TranslateOperand(psOperand->m_SubOperands[1].get(), TO_FLAG_INTEGER);
|
|
}
|
|
oss << "]";
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_STREAM:
|
|
{
|
|
// Not supported on Metal
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_INPUT_GS_INSTANCE_ID:
|
|
{
|
|
// Not supported on Metal
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_THIS_POINTER:
|
|
{
|
|
ASSERT(0); // Nope.
|
|
break;
|
|
}
|
|
case OPERAND_TYPE_INPUT_PATCH_CONSTANT:
|
|
{
|
|
const ShaderInfo::InOutSignature* psIn;
|
|
psContext->psShader->sInfo.GetPatchConstantSignatureFromRegister(psOperand->ui32RegisterNumber, psOperand->GetAccessMask(), &psIn);
|
|
*piRebase = psIn->iRebase;
|
|
switch (psIn->eSystemValueType)
|
|
{
|
|
case NAME_POSITION:
|
|
oss << "mtl_Position";
|
|
break;
|
|
case NAME_RENDER_TARGET_ARRAY_INDEX:
|
|
oss << "mtl_Layer";
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case NAME_CLIP_DISTANCE:
|
|
// this is temp variable, declaration and redirecting to actual output is handled in DeclareClipPlanes
|
|
char tmpName[128]; sprintf(tmpName, "phase%d_ClipDistance%d", psContext->currentPhase, psIn->ui32SemanticIndex);
|
|
oss << tmpName;
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case NAME_VIEWPORT_ARRAY_INDEX:
|
|
oss << "mtl_ViewPortIndex";
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case NAME_VERTEX_ID:
|
|
oss << "mtl_VertexID";
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case NAME_INSTANCE_ID:
|
|
oss << "mtl_InstanceID";
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case NAME_IS_FRONT_FACE:
|
|
oss << "(mtl_FrontFace ? 0xffffffffu : uint(0))";
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case NAME_PRIMITIVE_ID:
|
|
// Not on Metal
|
|
ASSERT(0);
|
|
break;
|
|
|
|
// as far as i understand tesselation factors are always coming from tessFactor variable (it is always declared in ToMetal::Translate)
|
|
case NAME_FINAL_QUAD_U_EQ_0_EDGE_TESSFACTOR:
|
|
case NAME_FINAL_TRI_U_EQ_0_EDGE_TESSFACTOR:
|
|
case NAME_FINAL_LINE_DENSITY_TESSFACTOR:
|
|
if (psContext->psShader->aIndexedOutput[1][psOperand->ui32RegisterNumber])
|
|
oss << "tessFactor.edgeTessellationFactor";
|
|
else
|
|
oss << "tessFactor.edgeTessellationFactor[0]";
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case NAME_FINAL_QUAD_V_EQ_0_EDGE_TESSFACTOR:
|
|
case NAME_FINAL_TRI_V_EQ_0_EDGE_TESSFACTOR:
|
|
case NAME_FINAL_LINE_DETAIL_TESSFACTOR:
|
|
oss << "tessFactor.edgeTessellationFactor[1]";
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case NAME_FINAL_QUAD_U_EQ_1_EDGE_TESSFACTOR:
|
|
case NAME_FINAL_TRI_W_EQ_0_EDGE_TESSFACTOR:
|
|
oss << "tessFactor.edgeTessellationFactor[2]";
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case NAME_FINAL_QUAD_V_EQ_1_EDGE_TESSFACTOR:
|
|
oss << "tessFactor.edgeTessellationFactor[3]";
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case NAME_FINAL_TRI_INSIDE_TESSFACTOR:
|
|
case NAME_FINAL_QUAD_U_INSIDE_TESSFACTOR:
|
|
if (psContext->psShader->aIndexedOutput[1][psOperand->ui32RegisterNumber])
|
|
oss << "tessFactor.insideTessellationFactor";
|
|
else
|
|
oss << "tessFactor.insideTessellationFactor[0]";
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
case NAME_FINAL_QUAD_V_INSIDE_TESSFACTOR:
|
|
oss << "tessFactor.insideTessellationFactor[1]";
|
|
*pui32IgnoreSwizzle = 1;
|
|
break;
|
|
|
|
default:
|
|
const std::string patchPrefix = "patch.";
|
|
|
|
if (psContext->psShader->eShaderType == DOMAIN_SHADER)
|
|
oss << psContext->inputPrefix << patchPrefix << psIn->semanticName << psIn->ui32SemanticIndex;
|
|
else
|
|
oss << patchPrefix << psIn->semanticName << psIn->ui32SemanticIndex;
|
|
|
|
// Disable swizzles if this is a scalar
|
|
if (psContext->psShader->eShaderType == HULL_SHADER)
|
|
{
|
|
if ((psContext->psShader->abScalarOutput[1][psOperand->ui32RegisterNumber] & psOperand->GetAccessMask()) != 0)
|
|
*pui32IgnoreSwizzle = 1;
|
|
}
|
|
else
|
|
{
|
|
if ((psContext->psShader->abScalarInput[1][psOperand->ui32RegisterNumber] & psOperand->GetAccessMask()) != 0)
|
|
*pui32IgnoreSwizzle = 1;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (hasCtor && (*pui32IgnoreSwizzle == 0))
|
|
{
|
|
oss << TranslateOperandSwizzle(psOperand, ui32CompMask, piRebase ? *piRebase : 0);
|
|
*pui32IgnoreSwizzle = 1;
|
|
}
|
|
|
|
if (needsBoolUpscale)
|
|
{
|
|
if (requestedType == SVT_UINT || requestedType == SVT_UINT16 || requestedType == SVT_UINT8)
|
|
oss << ") * 0xffffffffu";
|
|
else
|
|
oss << ") * int(0xffffffffu)";
|
|
numParenthesis--;
|
|
|
|
oss << ")";
|
|
numParenthesis--;
|
|
}
|
|
|
|
while (numParenthesis != 0)
|
|
{
|
|
oss << ")";
|
|
numParenthesis--;
|
|
}
|
|
return oss.str();
|
|
}
|
|
|
|
std::string ToMetal::TranslateOperand(const Operand* psOperand, uint32_t ui32TOFlag, uint32_t ui32ComponentMask)
|
|
{
|
|
std::ostringstream oss;
|
|
uint32_t ui32IgnoreSwizzle = 0;
|
|
int iRebase = 0;
|
|
|
|
// in single-component mode there is no need to use mask
|
|
if (psOperand->eSelMode == OPERAND_4_COMPONENT_SELECT_1_MODE)
|
|
ui32ComponentMask = OPERAND_4_COMPONENT_MASK_ALL;
|
|
|
|
if (ui32TOFlag & TO_FLAG_NAME_ONLY)
|
|
{
|
|
return TranslateVariableName(psOperand, ui32TOFlag, &ui32IgnoreSwizzle, OPERAND_4_COMPONENT_MASK_ALL, &iRebase);
|
|
}
|
|
|
|
switch (psOperand->eModifier)
|
|
{
|
|
case OPERAND_MODIFIER_NONE:
|
|
{
|
|
break;
|
|
}
|
|
case OPERAND_MODIFIER_NEG:
|
|
{
|
|
oss << ("(-");
|
|
break;
|
|
}
|
|
case OPERAND_MODIFIER_ABS:
|
|
{
|
|
oss << ("abs(");
|
|
break;
|
|
}
|
|
case OPERAND_MODIFIER_ABSNEG:
|
|
{
|
|
oss << ("-abs(");
|
|
break;
|
|
}
|
|
}
|
|
|
|
oss << TranslateVariableName(psOperand, ui32TOFlag, &ui32IgnoreSwizzle, ui32ComponentMask, &iRebase);
|
|
|
|
if (!ui32IgnoreSwizzle)
|
|
{
|
|
oss << TranslateOperandSwizzle(psOperand, ui32ComponentMask, iRebase);
|
|
}
|
|
|
|
switch (psOperand->eModifier)
|
|
{
|
|
case OPERAND_MODIFIER_NONE:
|
|
{
|
|
break;
|
|
}
|
|
case OPERAND_MODIFIER_NEG:
|
|
{
|
|
oss << (")");
|
|
break;
|
|
}
|
|
case OPERAND_MODIFIER_ABS:
|
|
{
|
|
oss << (")");
|
|
break;
|
|
}
|
|
case OPERAND_MODIFIER_ABSNEG:
|
|
{
|
|
oss << (")");
|
|
break;
|
|
}
|
|
}
|
|
return oss.str();
|
|
}
|