You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Tools/HLSLCrossCompiler/src/toGLSLDeclaration.c

2909 lines
101 KiB
C

// Modifications copyright Amazon.com, Inc. or its affiliates
// Modifications copyright Crytek GmbH
#include "hlslcc.h"
#include "internal_includes/toGLSLDeclaration.h"
#include "internal_includes/toGLSLOperand.h"
#include "internal_includes/languages.h"
#include "internal_includes/hlslccToolkit.h"
#include "bstrlib.h"
#include "internal_includes/debug.h"
#include <math.h>
#include <float.h>
#include <stdbool.h>
#if !defined(isnan)
#ifdef _MSC_VER
#define isnan(x) _isnan(x)
#define isinf(x) (!_finite(x))
#endif
#endif
#define fpcheck(x) (isnan(x) || isinf(x))
typedef enum
{
GLVARTYPE_FLOAT,
GLVARTYPE_INT,
GLVARTYPE_FLOAT4,
} GLVARTYPE;
extern void AddIndentation(HLSLCrossCompilerContext* psContext);
extern uint32_t AddImport(HLSLCrossCompilerContext* psContext, SYMBOL_TYPE eType, uint32_t ui32ID, uint32_t ui32Default);
extern uint32_t AddExport(HLSLCrossCompilerContext* psContext, SYMBOL_TYPE eType, uint32_t ui32ID, uint32_t ui32Value);
const char* GetTypeString(GLVARTYPE eType)
{
switch (eType)
{
case GLVARTYPE_FLOAT:
{
return "float";
}
case GLVARTYPE_INT:
{
return "int";
}
case GLVARTYPE_FLOAT4:
{
return "vec4";
}
default:
{
return "";
}
}
}
const uint32_t GetTypeElementCount(GLVARTYPE eType)
{
switch (eType)
{
case GLVARTYPE_FLOAT:
case GLVARTYPE_INT:
{
return 1;
}
case GLVARTYPE_FLOAT4:
{
return 4;
}
default:
{
return 0;
}
}
}
void GetSTD140Layout(ShaderVarType* pType, uint32_t* puAlignment, uint32_t* puSize)
{
*puSize = 0;
*puAlignment = 1;
switch (pType->Type)
{
case SVT_BOOL:
case SVT_UINT:
case SVT_UINT8:
case SVT_UINT16:
case SVT_INT:
case SVT_INT12:
case SVT_INT16:
case SVT_FLOAT:
case SVT_FLOAT10:
case SVT_FLOAT16:
*puSize = 4;
*puAlignment = 4;
break;
case SVT_DOUBLE:
*puSize = 8;
*puAlignment = 4;
break;
case SVT_VOID:
break;
default:
ASSERT(0);
break;
}
switch (pType->Class)
{
case SVC_SCALAR:
break;
case SVC_MATRIX_ROWS:
case SVC_MATRIX_COLUMNS:
// Matrices are translated to arrays of vectors
*puSize *= pType->Rows;
case SVC_VECTOR:
switch (pType->Columns)
{
case 2:
*puSize *= 2;
*puAlignment *= 2;
break;
case 3:
case 4:
*puSize *= 4;
*puAlignment *= 4;
break;
}
break;
case SVC_STRUCT:
{
uint32_t uMember;
for (uMember = 0; uMember < pType->MemberCount; ++uMember)
{
uint32_t uMemberAlignment, uMemberSize;
*puSize += pType->Members[uMember].Offset;
GetSTD140Layout(pType->Members + uMember, &uMemberAlignment, &uMemberSize);
*puSize += uMemberAlignment - 1;
*puSize -= *puSize % uMemberAlignment;
*puAlignment = *puAlignment > uMemberAlignment ? *puAlignment : uMemberAlignment;
}
}
break;
default:
ASSERT(0);
break;
}
if (pType->Elements > 1)
{
*puSize *= pType->Elements;
}
if (pType->Elements > 1 || pType->Class == SVC_MATRIX_ROWS || pType->Class == SVC_MATRIX_COLUMNS)
{
*puAlignment = (*puAlignment + 0x0000000F) & 0xFFFFFFF0;
}
}
void AddToDx9ImmConstIndexableArray(HLSLCrossCompilerContext* psContext, const Operand* psOperand)
{
bstring* savedStringPtr = psContext->currentGLSLString;
psContext->currentGLSLString = &psContext->earlyMain;
psContext->indent++;
AddIndentation(psContext);
psContext->psShader->aui32Dx9ImmConstArrayRemap[psOperand->ui32RegisterNumber] = psContext->psShader->ui32NumDx9ImmConst;
bformata(psContext->earlyMain, "ImmConstArray[%d] = ", psContext->psShader->ui32NumDx9ImmConst);
TranslateOperand(psContext, psOperand, TO_FLAG_NONE);
bcatcstr(psContext->earlyMain, ";\n");
psContext->indent--;
psContext->psShader->ui32NumDx9ImmConst++;
psContext->currentGLSLString = savedStringPtr;
}
void DeclareConstBufferShaderVariable(HLSLCrossCompilerContext* psContext, const char* Name, const struct ShaderVarType_TAG* psType, int unsizedArray)
{
bstring glsl = *psContext->currentGLSLString;
if (psType->Class == SVC_STRUCT)
{
bcatcstr(glsl, "\t");
ShaderVarName(glsl, psContext->psShader, Name);
bcatcstr(glsl, "_Type ");
ShaderVarName(glsl, psContext->psShader, Name);
if (psType->Elements > 1)
{
bformata(glsl, "[%d]", psType->Elements);
}
}
else if (psType->Class == SVC_MATRIX_COLUMNS || psType->Class == SVC_MATRIX_ROWS)
{
switch (psType->Type)
{
case SVT_FLOAT:
{
bformata(glsl, "\tvec%d ", psType->Columns);
ShaderVarName(glsl, psContext->psShader, Name);
bformata(glsl, "[%d", psType->Rows);
break;
}
default:
{
ASSERT(0);
break;
}
}
if (psType->Elements > 1)
{
bformata(glsl, " * %d", psType->Elements);
}
bformata(glsl, "]");
}
else
if (psType->Class == SVC_VECTOR)
{
switch (psType->Type)
{
default:
ASSERT(0);
case SVT_FLOAT:
case SVT_FLOAT10:
case SVT_FLOAT16:
case SVT_UINT:
case SVT_UINT8:
case SVT_UINT16:
case SVT_INT:
case SVT_INT12:
case SVT_INT16:
bformata(glsl, "\t%s ", GetConstructorForTypeGLSL(psContext, psType->Type, psType->Columns, true));
break;
case SVT_DOUBLE:
bformata(glsl, "\tdvec%d ", psType->Columns);
break;
}
ShaderVarName(glsl, psContext->psShader, Name);
if (psType->Elements > 1)
{
bformata(glsl, "[%d]", psType->Elements);
}
}
else
if (psType->Class == SVC_SCALAR)
{
switch (psType->Type)
{
default:
ASSERT(0);
case SVT_FLOAT:
case SVT_FLOAT10:
case SVT_FLOAT16:
case SVT_UINT:
case SVT_UINT8:
case SVT_UINT16:
case SVT_INT:
case SVT_INT12:
case SVT_INT16:
bformata(glsl, "\t%s ", GetConstructorForTypeGLSL(psContext, psType->Type, 1, true));
break;
case SVT_DOUBLE:
bformata(glsl, "\tdouble ");
break;
case SVT_BOOL:
//Use int instead of bool.
//Allows implicit conversions to integer and
//bool consumes 4-bytes in HLSL and GLSL anyway.
bformata(glsl, "\tint ");
break;
}
ShaderVarName(glsl, psContext->psShader, Name);
if (psType->Elements > 1)
{
bformata(glsl, "[%d]", psType->Elements);
}
}
if (unsizedArray)
{
bformata(glsl, "[]");
}
bformata(glsl, ";\n");
}
//In GLSL embedded structure definitions are not supported.
void PreDeclareStructType(HLSLCrossCompilerContext* psContext, const char* Name, const struct ShaderVarType_TAG* psType)
{
uint32_t i;
bstring glsl = *psContext->currentGLSLString;
for (i = 0; i < psType->MemberCount; ++i)
{
if (psType->Members[i].Class == SVC_STRUCT)
{
PreDeclareStructType(psContext, psType->Members[i].Name, &psType->Members[i]);
}
}
if (psType->Class == SVC_STRUCT)
{
#if !defined(NDEBUG)
uint32_t unnamed_struct = strcmp(Name, "$Element") == 0 ? 1 : 0;
#endif
//Not supported at the moment
ASSERT(!unnamed_struct);
bcatcstr(glsl, "struct ");
ShaderVarName(glsl, psContext->psShader, Name);
bcatcstr(glsl, "_Type {\n");
for (i = 0; i < psType->MemberCount; ++i)
{
ASSERT(psType->Members != 0);
DeclareConstBufferShaderVariable(psContext, psType->Members[i].Name, &psType->Members[i], 0);
}
bformata(glsl, "};\n");
}
}
void DeclarePLSStructVars(HLSLCrossCompilerContext* psContext, const char* Name, const struct ShaderVarType_TAG* psType)
{
(void)Name;
uint32_t i;
bstring glsl = *psContext->currentGLSLString;
ASSERT(psType->Members != 0);
for (i = 0; i < psType->MemberCount; ++i)
{
if (psType->Members[i].Class == SVC_STRUCT)
{
ASSERT(0); // PLS can't have nested structs
}
}
if (psType->Class == SVC_STRUCT)
{
for (i = 0; i < psType->MemberCount; ++i)
{
ShaderVarType cur_member = psType->Members[i];
if (cur_member.Class == SVC_VECTOR)
{
switch (cur_member.Type)
{
case SVT_FLOAT:
{
// float2 -> rg16f
if (2 == cur_member.Columns)
{
bcatcstr(glsl, "\tlayout(rg16f) highp vec2 ");
}
// float3 -> r11f_g11f_b10f
else if (3 == cur_member.Columns)
{
bcatcstr(glsl, "\tlayout(r11f_g11f_b10f) highp vec3 ");
}
// float4 -> rgba8
else if (4 == cur_member.Columns)
{
bcatcstr(glsl, "\tlayout(rgba8) highp vec4 ");
}
else
{
ASSERT(0); // not supported
}
break;
}
case SVT_INT:
{
// int2 -> rg16i
if (2 == cur_member.Columns)
{
bcatcstr(glsl, "\tlayout(rg16i) highp ivec2 ");
}
// int4 -> rgba8i
else if (4 == cur_member.Columns)
{
bcatcstr(glsl, "\tlayout(rgba8i) highp ivec4 ");
}
else
{
ASSERT(0); // not supported
}
break;
}
case SVT_UINT:
case SVT_DOUBLE:
default:
ASSERT(0);
}
if (cur_member.Elements > 1)
{
ASSERT(0); // PLS can't have arrays
}
}
else if (cur_member.Class == SVC_SCALAR)
{
switch (cur_member.Type)
{
case SVT_UINT:
bcatcstr(glsl, "\tlayout(r32ui) highp uint ");
break;
case SVT_FLOAT:
case SVT_INT:
case SVT_DOUBLE:
case SVT_BOOL:
default:
ASSERT(0);
}
}
ShaderVarName(glsl, psContext->psShader, cur_member.Name);
bcatcstr(glsl, ";\n");
}
}
else
{
ASSERT(0);
}
}
char* GetDeclaredInputName(const HLSLCrossCompilerContext* psContext, const SHADER_TYPE eShaderType, const Operand* psOperand)
{
bstring inputName;
char* cstr;
InOutSignature* psIn;
if (eShaderType == GEOMETRY_SHADER)
{
inputName = bformat("VtxOutput%d", psOperand->ui32RegisterNumber);
}
else if (eShaderType == HULL_SHADER)
{
inputName = bformat("VtxGeoOutput%d", psOperand->ui32RegisterNumber);
}
else if (eShaderType == DOMAIN_SHADER)
{
inputName = bformat("HullOutput%d", psOperand->ui32RegisterNumber);
}
else if (eShaderType == PIXEL_SHADER)
{
if (psContext->flags & HLSLCC_FLAG_TESS_ENABLED)
{
inputName = bformat("DomOutput%d", psOperand->ui32RegisterNumber);
}
else
{
inputName = bformat("VtxGeoOutput%d", psOperand->ui32RegisterNumber);
}
}
else
{
ASSERT(eShaderType == VERTEX_SHADER);
inputName = bformat("dcl_Input%d", psOperand->ui32RegisterNumber);
}
if ((psContext->flags & HLSLCC_FLAG_INOUT_SEMANTIC_NAMES) && GetInputSignatureFromRegister(psOperand->ui32RegisterNumber, &psContext->psShader->sInfo, &psIn))
{
bformata(inputName, "_%s%d", psIn->SemanticName, psIn->ui32SemanticIndex);
}
cstr = bstr2cstr(inputName, '\0');
bdestroy(inputName);
return cstr;
}
char* GetDeclaredOutputName(const HLSLCrossCompilerContext* psContext,
const SHADER_TYPE eShaderType,
const Operand* psOperand,
int* piStream)
{
bstring outputName;
char* cstr;
InOutSignature* psOut;
int foundOutput = GetOutputSignatureFromRegister(psOperand->ui32RegisterNumber,
psOperand->ui32CompMask,
psContext->psShader->ui32CurrentVertexOutputStream,
&psContext->psShader->sInfo,
&psOut);
(void)(foundOutput);
ASSERT(foundOutput);
if (eShaderType == GEOMETRY_SHADER)
{
if (psOut->ui32Stream != 0)
{
outputName = bformat("VtxGeoOutput%d_S%d", psOperand->ui32RegisterNumber, psOut->ui32Stream);
piStream[0] = psOut->ui32Stream;
}
else
{
outputName = bformat("VtxGeoOutput%d", psOperand->ui32RegisterNumber);
}
}
else if (eShaderType == DOMAIN_SHADER)
{
outputName = bformat("DomOutput%d", psOperand->ui32RegisterNumber);
}
else if (eShaderType == VERTEX_SHADER)
{
if (psContext->flags & HLSLCC_FLAG_GS_ENABLED)
{
outputName = bformat("VtxOutput%d", psOperand->ui32RegisterNumber);
}
else
{
outputName = bformat("VtxGeoOutput%d", psOperand->ui32RegisterNumber);
}
}
else if (eShaderType == PIXEL_SHADER)
{
outputName = bformat("PixOutput%d", psOperand->ui32RegisterNumber);
}
else
{
ASSERT(eShaderType == HULL_SHADER);
outputName = bformat("HullOutput%d", psOperand->ui32RegisterNumber);
}
if (psContext->flags & HLSLCC_FLAG_INOUT_SEMANTIC_NAMES)
{
bformata(outputName, "_%s%d", psOut->SemanticName, psOut->ui32SemanticIndex);
}
cstr = bstr2cstr(outputName, '\0');
bdestroy(outputName);
return cstr;
}
static void DeclareInput(
HLSLCrossCompilerContext* psContext,
const Declaration* psDecl,
const char* Interpolation, const char* StorageQualifier, const char* Precision, int iNumComponents, OPERAND_INDEX_DIMENSION eIndexDim, const char* InputName)
{
Shader* psShader = psContext->psShader;
bstring glsl = *psContext->currentGLSLString;
// This falls within the specified index ranges. The default is 0 if no input range is specified
if (psShader->aIndexedInput[psDecl->asOperands[0].ui32RegisterNumber] == -1)
{
return;
}
if (psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] == 0)
{
const char* vecType = "vec";
const char* scalarType = "float";
InOutSignature* psSignature = NULL;
if (GetInputSignatureFromRegister(psDecl->asOperands[0].ui32RegisterNumber, &psShader->sInfo, &psSignature))
{
switch (psSignature->eComponentType)
{
case INOUT_COMPONENT_UINT32:
{
vecType = "uvec";
scalarType = "uint";
break;
}
case INOUT_COMPONENT_SINT32:
{
vecType = "ivec";
scalarType = "int";
break;
}
case INOUT_COMPONENT_FLOAT32:
{
break;
}
}
}
if (psShader->eShaderType == PIXEL_SHADER)
{
psShader->sInfo.aePixelInputInterpolation[psDecl->asOperands[0].ui32RegisterNumber] = psDecl->value.eInterpolation;
}
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions) ||
(psShader->eShaderType == VERTEX_SHADER && HaveLimitedInOutLocationQualifier(psContext->psShader->eTargetLanguage)))
{
bformata(glsl, "layout(location = %d) ", psDecl->asOperands[0].ui32RegisterNumber);
}
switch (eIndexDim)
{
case INDEX_2D:
{
if (iNumComponents == 1)
{
const uint32_t arraySize = psDecl->asOperands[0].aui32ArraySizes[0];
psContext->psShader->abScalarInput[psDecl->asOperands[0].ui32RegisterNumber] = -1;
bformata(glsl, "%s %s %s %s [%d];\n", StorageQualifier, Precision, scalarType, InputName, arraySize);
bformata(glsl, "%s1 Input%d;\n", vecType, psDecl->asOperands[0].ui32RegisterNumber);
psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] = arraySize;
}
else
{
bformata(glsl, "%s %s %s%d %s [%d];\n", StorageQualifier, Precision, vecType, iNumComponents, InputName, psDecl->asOperands[0].aui32ArraySizes[0]);
bformata(glsl, "%s %s%d Input%d[%d];\n", Precision, vecType, iNumComponents, psDecl->asOperands[0].ui32RegisterNumber, psDecl->asOperands[0].aui32ArraySizes[0]);
psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] = psDecl->asOperands[0].aui32ArraySizes[0];
}
break;
}
default:
{
if (psDecl->asOperands[0].eType == OPERAND_TYPE_SPECIAL_TEXCOORD)
{
InputName = "TexCoord";
}
if (iNumComponents == 1)
{
psContext->psShader->abScalarInput[psDecl->asOperands[0].ui32RegisterNumber] = 1;
bformata(glsl, "%s %s %s %s %s;\n", Interpolation, StorageQualifier, Precision, scalarType, InputName);
bformata(glsl, "%s1 Input%d;\n", vecType, psDecl->asOperands[0].ui32RegisterNumber);
psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] = -1;
}
else
{
if (psShader->aIndexedInput[psDecl->asOperands[0].ui32RegisterNumber] > 0)
{
bformata(glsl, "%s %s %s %s%d %s", Interpolation, StorageQualifier, Precision, vecType, iNumComponents, InputName);
bformata(glsl, "[%d];\n", psShader->aIndexedInput[psDecl->asOperands[0].ui32RegisterNumber]);
bformata(glsl, "%s %s%d Input%d[%d];\n", Precision, vecType, iNumComponents, psDecl->asOperands[0].ui32RegisterNumber, psShader->aIndexedInput[psDecl->asOperands[0].ui32RegisterNumber]);
psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] = psShader->aIndexedInput[psDecl->asOperands[0].ui32RegisterNumber];
}
else
{
bformata(glsl, "%s %s %s %s%d %s;\n", Interpolation, StorageQualifier, Precision, vecType, iNumComponents, InputName);
bformata(glsl, "%s %s%d Input%d;\n", Precision, vecType, iNumComponents, psDecl->asOperands[0].ui32RegisterNumber);
psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] = -1;
}
}
break;
}
}
}
if (psShader->abInputReferencedByInstruction[psDecl->asOperands[0].ui32RegisterNumber])
{
psContext->currentGLSLString = &psContext->earlyMain;
psContext->indent++;
if (psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] == -1) //Not an array
{
AddIndentation(psContext);
bformata(psContext->earlyMain, "Input%d = %s;\n", psDecl->asOperands[0].ui32RegisterNumber, InputName);
}
else
{
int arrayIndex = psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber];
while (arrayIndex)
{
AddIndentation(psContext);
bformata(psContext->earlyMain, "Input%d[%d] = %s[%d];\n", psDecl->asOperands[0].ui32RegisterNumber, arrayIndex - 1, InputName, arrayIndex - 1);
arrayIndex--;
}
}
psContext->indent--;
psContext->currentGLSLString = &psContext->glsl;
}
}
void AddBuiltinInput(HLSLCrossCompilerContext* psContext, const Declaration* psDecl, const char* builtinName, uint32_t uNumComponents)
{
(void)uNumComponents;
bstring glsl = *psContext->currentGLSLString;
Shader* psShader = psContext->psShader;
if (psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] == 0)
{
SHADER_VARIABLE_TYPE eType = GetOperandDataType(psContext, &psDecl->asOperands[0]);
bformata(glsl, "%s ", GetConstructorForTypeGLSL(psContext, eType, 4, false));
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NAME_ONLY);
bformata(glsl, ";\n");
psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] = 1;
}
else
{
//This register has already been declared. The HLSL bytecode likely looks
//something like this then:
// dcl_input_ps constant v3.x
// dcl_input_ps_sgv v3.y, primitive_id
//GLSL does not allow assignment to a varying!
}
psContext->currentGLSLString = &psContext->earlyMain;
psContext->indent++;
AddIndentation(psContext);
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
bformata(psContext->earlyMain, " = %s", builtinName);
switch (psDecl->asOperands[0].eSpecialName)
{
case NAME_POSITION:
TranslateOperandSwizzle(psContext, &psDecl->asOperands[0]);
// Invert w coordinate if necessary to be the same as SV_Position
if (psContext->psShader->eShaderType == PIXEL_SHADER)
{
if (psDecl->asOperands[0].eSelMode == OPERAND_4_COMPONENT_MASK_MODE &&
psDecl->asOperands[0].eType == OPERAND_TYPE_INPUT)
{
if (psDecl->asOperands[0].ui32CompMask & OPERAND_4_COMPONENT_MASK_Z)
{
uint32_t ui32IgnoreSwizzle;
bcatcstr(psContext->earlyMain, ";\n#ifdef EMULATE_DEPTH_CLAMP\n");
AddIndentation(psContext);
TranslateVariableName(psContext, &psDecl->asOperands[0], TO_FLAG_NONE, &ui32IgnoreSwizzle);
bcatcstr(psContext->earlyMain, ".z = unclampedDepth;\n");
bcatcstr(psContext->earlyMain, "#endif\n");
}
if (psDecl->asOperands[0].ui32CompMask & OPERAND_4_COMPONENT_MASK_W)
{
uint32_t ui32IgnoreSwizzle;
bcatcstr(psContext->earlyMain, ";\n");
AddIndentation(psContext);
TranslateVariableName(psContext, &psDecl->asOperands[0], TO_FLAG_NONE, &ui32IgnoreSwizzle);
bcatcstr(psContext->earlyMain, ".w = 1.0 / ");
TranslateVariableName(psContext, &psDecl->asOperands[0], TO_FLAG_NONE, &ui32IgnoreSwizzle);
bcatcstr(psContext->earlyMain, ".w;\n");
}
}
else
{
ASSERT(0);
}
}
break;
default:
//Scalar built-in. Don't apply swizzle.
break;
}
bcatcstr(psContext->earlyMain, ";\n");
psContext->indent--;
psContext->currentGLSLString = &psContext->glsl;
}
int OutputNeedsDeclaring(HLSLCrossCompilerContext* psContext, const Operand* psOperand, const int count)
{
Shader* psShader = psContext->psShader;
// Depth Output operands are a special case and won't have a ui32RegisterNumber,
// so first we have to check if the output operand is depth.
if (psShader->eShaderType == PIXEL_SHADER)
{
if (psOperand->eType == OPERAND_TYPE_OUTPUT_DEPTH_GREATER_EQUAL ||
psOperand->eType == OPERAND_TYPE_OUTPUT_DEPTH_LESS_EQUAL)
{
return 1;
}
else if (psOperand->eType == OPERAND_TYPE_OUTPUT_DEPTH)
{
return 0; // OpenGL doesn't need to declare depth output variable (gl_FragDepth)
}
}
const uint32_t declared = ((psContext->currentPhase + 1) << 3) | psShader->ui32CurrentVertexOutputStream;
ASSERT(psOperand->ui32RegisterNumber >= 0);
ASSERT(psOperand->ui32RegisterNumber < MAX_SHADER_VEC4_OUTPUT);
if (psShader->aiOutputDeclared[psOperand->ui32RegisterNumber] != declared)
{
int offset;
for (offset = 0; offset < count; offset++)
{
psShader->aiOutputDeclared[psOperand->ui32RegisterNumber + offset] = declared;
}
return 1;
}
return 0;
}
void AddBuiltinOutput(HLSLCrossCompilerContext* psContext, const Declaration* psDecl, const GLVARTYPE type, int arrayElements, const char* builtinName)
{
bstring glsl = *psContext->currentGLSLString;
Shader* psShader = psContext->psShader;
psContext->havePostShaderCode[psContext->currentPhase] = 1;
if (OutputNeedsDeclaring(psContext, &psDecl->asOperands[0], arrayElements ? arrayElements : 1))
{
InOutSignature* psSignature = NULL;
GetOutputSignatureFromRegister(psDecl->asOperands[0].ui32RegisterNumber,
psDecl->asOperands[0].ui32CompMask,
0,
&psShader->sInfo, &psSignature);
bcatcstr(glsl, "#undef ");
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NAME_ONLY);
bcatcstr(glsl, "\n");
bcatcstr(glsl, "#define ");
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NAME_ONLY);
bformata(glsl, " phase%d_", psContext->currentPhase);
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NAME_ONLY);
bcatcstr(glsl, "\n");
bcatcstr(glsl, "vec4 ");
bformata(glsl, "phase%d_", psContext->currentPhase);
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NAME_ONLY);
if (arrayElements)
{
bformata(glsl, "[%d];\n", arrayElements);
}
else
{
bcatcstr(glsl, ";\n");
}
psContext->currentGLSLString = &psContext->postShaderCode[psContext->currentPhase];
glsl = *psContext->currentGLSLString;
psContext->indent++;
if (arrayElements)
{
int elem;
for (elem = 0; elem < arrayElements; elem++)
{
AddIndentation(psContext);
bformata(glsl, "%s[%d] = %s(phase%d_", builtinName, elem, GetTypeString(type), psContext->currentPhase);
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NAME_ONLY);
bformata(glsl, "[%d]", elem);
TranslateOperandSwizzle(psContext, &psDecl->asOperands[0]);
bformata(glsl, ");\n");
}
}
else
{
if (psDecl->asOperands[0].eSpecialName == NAME_CLIP_DISTANCE)
{
int max = GetMaxComponentFromComponentMask(&psDecl->asOperands[0]);
int applySiwzzle = GetNumSwizzleElements(&psDecl->asOperands[0]) > 1 ? 1 : 0;
int index;
int i;
int multiplier = 1;
char* swizzle[] = {".x", ".y", ".z", ".w"};
ASSERT(psSignature != NULL);
index = psSignature->ui32SemanticIndex;
//Clip distance can be spread across 1 or 2 outputs (each no more than a vec4).
//Some examples:
//float4 clip[2] : SV_ClipDistance; //8 clip distances
//float3 clip[2] : SV_ClipDistance; //6 clip distances
//float4 clip : SV_ClipDistance; //4 clip distances
//float clip : SV_ClipDistance; //1 clip distance.
//In GLSL the clip distance built-in is an array of up to 8 floats.
//So vector to array conversion needs to be done here.
if (index == 1)
{
InOutSignature* psFirstClipSignature;
if (GetOutputSignatureFromSystemValue(NAME_CLIP_DISTANCE, 1, &psShader->sInfo, &psFirstClipSignature))
{
if (psFirstClipSignature->ui32Mask & (1 << 3))
{
multiplier = 4;
}
else
if (psFirstClipSignature->ui32Mask & (1 << 2))
{
multiplier = 3;
}
else
if (psFirstClipSignature->ui32Mask & (1 << 1))
{
multiplier = 2;
}
}
}
for (i = 0; i < max; ++i)
{
AddIndentation(psContext);
bformata(glsl, "%s[%d] = (phase%d_", builtinName, i + multiplier * index, psContext->currentPhase);
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
if (applySiwzzle)
{
bformata(glsl, ")%s;\n", swizzle[i]);
}
else
{
bformata(glsl, ");\n");
}
}
}
else
{
uint32_t elements = GetNumSwizzleElements(&psDecl->asOperands[0]);
if (elements != GetTypeElementCount(type))
{
//This is to handle float3 position seen in control point phases
//struct HS_OUTPUT
//{
// float3 vPosition : POSITION;
//}; -> dcl_output o0.xyz
//gl_Position is vec4.
AddIndentation(psContext);
bformata(glsl, "%s = %s(phase%d_", builtinName, GetTypeString(type), psContext->currentPhase);
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
bformata(glsl, ", 1);\n");
}
else
{
AddIndentation(psContext);
bformata(glsl, "%s = %s(phase%d_", builtinName, GetTypeString(type), psContext->currentPhase);
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
bformata(glsl, ");\n");
}
}
if (psShader->eShaderType == VERTEX_SHADER && psDecl->asOperands[0].eSpecialName == NAME_POSITION)
{
if (psContext->flags & HLSLCC_FLAG_INVERT_CLIP_SPACE_Y)
{
AddIndentation(psContext);
bformata(glsl, "gl_Position.y = -gl_Position.y;\n");
}
if (EmulateDepthClamp(psContext->psShader->eTargetLanguage))
{
bcatcstr(glsl, "#ifdef EMULATE_DEPTH_CLAMP\n");
bcatcstr(glsl, "#if EMULATE_DEPTH_CLAMP == 1\n");
AddIndentation(psContext);
bcatcstr(glsl, "unclampedDepth = gl_DepthRange.near + gl_DepthRange.diff * gl_Position.z / gl_Position.w;\n");
bcatcstr(glsl, "#elif EMULATE_DEPTH_CLAMP == 2\n");
AddIndentation(psContext);
bcatcstr(glsl, "unclampedZ = gl_DepthRange.diff * gl_Position.z;\n");
bcatcstr(glsl, "#endif\n");
AddIndentation(psContext);
bcatcstr(glsl, "gl_Position.z = 0.0;\n");
}
if (psContext->flags & HLSLCC_FLAG_CONVERT_CLIP_SPACE_Z)
{
if (EmulateDepthClamp(psContext->psShader->eTargetLanguage))
{
bcatcstr(glsl, "#else\n");
}
AddIndentation(psContext);
bcatcstr(glsl, "gl_Position.z = gl_Position.z * 2.0 - gl_Position.w;\n");
}
if (EmulateDepthClamp(psContext->psShader->eTargetLanguage))
{
bcatcstr(glsl, "#endif\n");
}
}
}
psContext->indent--;
psContext->currentGLSLString = &psContext->glsl;
}
}
void AddUserOutput(HLSLCrossCompilerContext* psContext, const Declaration* psDecl)
{
bstring glsl = *psContext->currentGLSLString;
Shader* psShader = psContext->psShader;
if (OutputNeedsDeclaring(psContext, &psDecl->asOperands[0], 1))
{
const Operand* psOperand = &psDecl->asOperands[0];
const char* Precision = "";
const char* type = "vec";
InOutSignature* psSignature = NULL;
GetOutputSignatureFromRegister(psDecl->asOperands[0].ui32RegisterNumber,
psDecl->asOperands[0].ui32CompMask,
psShader->ui32CurrentVertexOutputStream,
&psShader->sInfo,
&psSignature);
switch (psSignature->eComponentType)
{
case INOUT_COMPONENT_UINT32:
{
type = "uvec";
break;
}
case INOUT_COMPONENT_SINT32:
{
type = "ivec";
break;
}
case INOUT_COMPONENT_FLOAT32:
{
break;
}
}
if (HavePrecisionQualifers(psShader->eTargetLanguage))
{
switch (psOperand->eMinPrecision)
{
case OPERAND_MIN_PRECISION_DEFAULT:
{
Precision = "highp";
break;
}
case OPERAND_MIN_PRECISION_FLOAT_16:
{
Precision = "mediump";
break;
}
case OPERAND_MIN_PRECISION_FLOAT_2_8:
{
Precision = "lowp";
break;
}
case OPERAND_MIN_PRECISION_SINT_16:
{
Precision = "mediump";
//type = "ivec";
break;
}
case OPERAND_MIN_PRECISION_UINT_16:
{
Precision = "mediump";
//type = "uvec";
break;
}
}
}
switch (psShader->eShaderType)
{
case PIXEL_SHADER:
{
switch (psDecl->asOperands[0].eType)
{
case OPERAND_TYPE_OUTPUT_COVERAGE_MASK:
case OPERAND_TYPE_OUTPUT_DEPTH:
{
break;
}
case OPERAND_TYPE_OUTPUT_DEPTH_GREATER_EQUAL:
{
bcatcstr(glsl, "#ifdef GL_ARB_conservative_depth\n");
bcatcstr(glsl, "#extension GL_ARB_conservative_depth : enable\n");
bcatcstr(glsl, "layout (depth_greater) out float gl_FragDepth;\n");
bcatcstr(glsl, "#endif\n");
break;
}
case OPERAND_TYPE_OUTPUT_DEPTH_LESS_EQUAL:
{
bcatcstr(glsl, "#ifdef GL_ARB_conservative_depth\n");
bcatcstr(glsl, "#extension GL_ARB_conservative_depth : enable\n");
bcatcstr(glsl, "layout (depth_less) out float gl_FragDepth;\n");
bcatcstr(glsl, "#endif\n");
break;
}
default:
{
if (WriteToFragData(psContext->psShader->eTargetLanguage))
{
bformata(glsl, "#define Output%d gl_FragData[%d]\n", psDecl->asOperands[0].ui32RegisterNumber, psDecl->asOperands[0].ui32RegisterNumber);
}
else
{
int stream = 0;
char* OutputName = GetDeclaredOutputName(psContext, PIXEL_SHADER, psOperand, &stream);
uint32_t renderTarget = psDecl->asOperands[0].ui32RegisterNumber;
// Check if we already defined this as a "inout"
if ((psContext->rendertargetUse[renderTarget] & INPUT_RENDERTARGET) == 0)
{
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions) || HaveLimitedInOutLocationQualifier(psContext->psShader->eTargetLanguage))
{
uint32_t index = 0;
if ((psContext->flags & HLSLCC_FLAG_DUAL_SOURCE_BLENDING) && DualSourceBlendSupported(psContext->psShader->eTargetLanguage))
{
if (renderTarget > 0)
{
renderTarget = 0;
index = 1;
}
bformata(glsl, "layout(location = %d, index = %d) ", renderTarget, index);
}
else
{
bformata(glsl, "layout(location = %d) ", renderTarget);
}
}
bformata(glsl, "out %s %s4 %s;\n", Precision, type, OutputName);
}
if (stream)
{
bformata(glsl, "#define Output%d_S%d %s\n", psDecl->asOperands[0].ui32RegisterNumber, stream, OutputName);
}
else
{
bformata(glsl, "#define Output%d %s\n", psDecl->asOperands[0].ui32RegisterNumber, OutputName);
}
bcstrfree(OutputName);
}
break;
}
}
break;
}
case VERTEX_SHADER:
{
int iNumComponents = 4; //GetMaxComponentFromComponentMask(&psDecl->asOperands[0]);
int stream = 0;
char* OutputName = GetDeclaredOutputName(psContext, VERTEX_SHADER, psOperand, &stream);
if (psShader->eShaderType == VERTEX_SHADER)
{
uint32_t ui32InterpImp = AddImport(psContext, SYMBOL_INPUT_INTERPOLATION_MODE, psDecl->asOperands[0].ui32RegisterNumber, (uint32_t)INTERPOLATION_LINEAR);
bformata(glsl, "#if IMPORT_%d == %d\n", ui32InterpImp, INTERPOLATION_CONSTANT);
bformata(glsl, "#define Output%dInterpolation flat\n", psDecl->asOperands[0].ui32RegisterNumber);
bformata(glsl, "#elif IMPORT_%d == %d\n", ui32InterpImp, INTERPOLATION_LINEAR_CENTROID);
bformata(glsl, "#define Output%dInterpolation centroid\n", psDecl->asOperands[0].ui32RegisterNumber);
bformata(glsl, "#elif IMPORT_%d == %d\n", ui32InterpImp, INTERPOLATION_LINEAR_NOPERSPECTIVE);
bformata(glsl, "#define Output%dInterpolation noperspective\n", psDecl->asOperands[0].ui32RegisterNumber);
bformata(glsl, "#elif IMPORT_%d == %d\n", ui32InterpImp, INTERPOLATION_LINEAR_NOPERSPECTIVE_CENTROID);
bformata(glsl, "#define Output%dInterpolation noperspective centroid\n", psDecl->asOperands[0].ui32RegisterNumber);
bformata(glsl, "#elif IMPORT_%d == %d\n", ui32InterpImp, INTERPOLATION_LINEAR_SAMPLE);
bformata(glsl, "#define Output%dInterpolation sample\n", psDecl->asOperands[0].ui32RegisterNumber);
bformata(glsl, "#elif IMPORT_%d == %d\n", ui32InterpImp, INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE);
bformata(glsl, "#define Output%dInterpolation noperspective sample\n", psDecl->asOperands[0].ui32RegisterNumber);
bcatcstr(glsl, "#else\n");
bformata(glsl, "#define Output%dInterpolation \n", psDecl->asOperands[0].ui32RegisterNumber);
bcatcstr(glsl, "#endif\n");
}
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions))
{
bformata(glsl, "layout(location = %d) ", psDecl->asOperands[0].ui32RegisterNumber);
}
if (psShader->eShaderType == VERTEX_SHADER)
{
bformata(glsl, "Output%dInterpolation ", psDecl->asOperands[0].ui32RegisterNumber);
}
if (InOutSupported(psContext->psShader->eTargetLanguage))
{
bformata(glsl, "out %s %s%d %s;\n", Precision, type, iNumComponents, OutputName);
}
else
{
bformata(glsl, "varying %s %s%d %s;\n", Precision, type, iNumComponents, OutputName);
}
bformata(glsl, "#define Output%d %s\n", psDecl->asOperands[0].ui32RegisterNumber, OutputName);
bcstrfree(OutputName);
break;
}
case GEOMETRY_SHADER:
{
int stream = 0;
char* OutputName = GetDeclaredOutputName(psContext, GEOMETRY_SHADER, psOperand, &stream);
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions))
{
bformata(glsl, "layout(location = %d) ", psDecl->asOperands[0].ui32RegisterNumber);
}
bformata(glsl, "out %s4 %s;\n", type, OutputName);
if (stream)
{
bformata(glsl, "#define Output%d_S%d %s\n", psDecl->asOperands[0].ui32RegisterNumber, stream, OutputName);
}
else
{
bformata(glsl, "#define Output%d %s\n", psDecl->asOperands[0].ui32RegisterNumber, OutputName);
}
bcstrfree(OutputName);
break;
}
case HULL_SHADER:
{
int stream = 0;
char* OutputName = GetDeclaredOutputName(psContext, HULL_SHADER, psOperand, &stream);
ASSERT(psDecl->asOperands[0].ui32RegisterNumber != 0); //Reg 0 should be gl_out[gl_InvocationID].gl_Position.
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions))
{
bformata(glsl, "layout(location = %d) ", psDecl->asOperands[0].ui32RegisterNumber);
}
bformata(glsl, "out %s4 %s[];\n", type, OutputName);
bformata(glsl, "#define Output%d %s[gl_InvocationID]\n", psDecl->asOperands[0].ui32RegisterNumber, OutputName);
bcstrfree(OutputName);
break;
}
case DOMAIN_SHADER:
{
int stream = 0;
char* OutputName = GetDeclaredOutputName(psContext, DOMAIN_SHADER, psOperand, &stream);
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions))
{
bformata(glsl, "layout(location = %d) ", psDecl->asOperands[0].ui32RegisterNumber);
}
bformata(glsl, "out %s4 %s;\n", type, OutputName);
bformata(glsl, "#define Output%d %s\n", psDecl->asOperands[0].ui32RegisterNumber, OutputName);
bcstrfree(OutputName);
break;
}
}
}
else
{
/*
Multiple outputs can be packed into one register. e.g.
// Name Index Mask Register SysValue Format Used
// -------------------- ----- ------ -------- -------- ------- ------
// FACTOR 0 x 3 NONE int x
// MAX 0 y 3 NONE int y
We want unique outputs to make it easier to use transform feedback.
out ivec4 FACTOR0;
#define Output3 FACTOR0
out ivec4 MAX0;
MAIN SHADER CODE. Writes factor and max to Output3 which aliases FACTOR0.
MAX0.x = FACTOR0.y;
This unpacking of outputs is only done when using HLSLCC_FLAG_INOUT_SEMANTIC_NAMES.
When not set the application will be using HLSL reflection information to discover
what the input and outputs mean if need be.
*/
//
if ((psContext->flags & HLSLCC_FLAG_INOUT_SEMANTIC_NAMES) && (psDecl->asOperands[0].eType == OPERAND_TYPE_OUTPUT))
{
const Operand* psOperand = &psDecl->asOperands[0];
InOutSignature* psSignature = NULL;
const char* type = "vec";
int stream = 0;
char* OutputName = GetDeclaredOutputName(psContext, psShader->eShaderType, psOperand, &stream);
GetOutputSignatureFromRegister(psOperand->ui32RegisterNumber,
psOperand->ui32CompMask,
0,
&psShader->sInfo,
&psSignature);
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions))
{
bformata(glsl, "layout(location = %d) ", psDecl->asOperands[0].ui32RegisterNumber);
}
switch (psSignature->eComponentType)
{
case INOUT_COMPONENT_UINT32:
{
type = "uvec";
break;
}
case INOUT_COMPONENT_SINT32:
{
type = "ivec";
break;
}
case INOUT_COMPONENT_FLOAT32:
{
break;
}
}
bformata(glsl, "out %s4 %s;\n", type, OutputName);
psContext->havePostShaderCode[psContext->currentPhase] = 1;
psContext->currentGLSLString = &psContext->postShaderCode[psContext->currentPhase];
glsl = *psContext->currentGLSLString;
bcatcstr(glsl, OutputName);
bcstrfree(OutputName);
AddSwizzleUsingElementCount(psContext, GetNumSwizzleElements(psOperand));
bformata(glsl, " = Output%d", psOperand->ui32RegisterNumber);
TranslateOperandSwizzle(psContext, psOperand);
bcatcstr(glsl, ";\n");
psContext->currentGLSLString = &psContext->glsl;
glsl = *psContext->currentGLSLString;
}
}
}
void DeclareUBOConstants(HLSLCrossCompilerContext* psContext, const uint32_t ui32BindingPoint, ConstantBuffer* psCBuf)
{
bstring glsl = *psContext->currentGLSLString;
uint32_t i, implicitOffset;
const char* Name = psCBuf->Name;
uint32_t auiSortedVars[MAX_SHADER_VARS];
if (psCBuf->Name[0] == '$') //For $Globals
{
Name++;
}
for (i = 0; i < psCBuf->ui32NumVars; ++i)
{
PreDeclareStructType(psContext, psCBuf->asVars[i].sType.Name, &psCBuf->asVars[i].sType);
}
/* [layout (location = X)] uniform vec4 HLSLConstantBufferName[numConsts]; */
if (HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage, psContext->psShader->extensions) && (psContext->flags & HLSLCC_FLAG_AVOID_RESOURCE_BINDINGS_AND_LOCATIONS) == 0)
{
bformata(glsl, "layout(binding = %d) ", ui32BindingPoint);
}
bformata(glsl, "uniform ");
ConvertToUniformBufferName(glsl, psContext->psShader, psCBuf->Name);
bformata(glsl, " {\n ");
if (psCBuf->ui32NumVars > 0)
{
uint32_t bSorted = 1;
auiSortedVars[0] = 0;
for (i = 1; i < psCBuf->ui32NumVars; ++i)
{
auiSortedVars[i] = i;
bSorted = bSorted && psCBuf->asVars[i - 1].ui32StartOffset <= psCBuf->asVars[i].ui32StartOffset;
}
while (!bSorted)
{
bSorted = 1;
for (i = 1; i < psCBuf->ui32NumVars; ++i)
{
if (psCBuf->asVars[auiSortedVars[i - 1]].ui32StartOffset > psCBuf->asVars[auiSortedVars[i]].ui32StartOffset)
{
uint32_t uiTemp = auiSortedVars[i];
auiSortedVars[i] = auiSortedVars[i - 1];
auiSortedVars[i - 1] = uiTemp;
bSorted = 0;
}
}
}
}
implicitOffset = 0;
for (i = 0; i < psCBuf->ui32NumVars; ++i)
{
uint32_t uVarAlignment, uVarSize;
ShaderVar* psVar = psCBuf->asVars + auiSortedVars[i];
GetSTD140Layout(&psVar->sType, &uVarAlignment, &uVarSize);
if ((implicitOffset + 16 - 1) / 16 < psVar->ui32StartOffset / 16)
{
uint32_t uNumPaddingUvecs = psVar->ui32StartOffset / 16 - (implicitOffset + 16 - 1) / 16;
bcatcstr(glsl, "\tuvec4 padding_");
ConvertToUniformBufferName(glsl, psContext->psShader, psCBuf->Name);
bformata(glsl, "_%d[%d];\n", implicitOffset, uNumPaddingUvecs);
implicitOffset = psVar->ui32StartOffset - psVar->ui32StartOffset % 16;
}
if ((implicitOffset + 4 - 1) / 4 < psVar->ui32StartOffset / 4)
{
uint32_t uNumPaddingUints = psVar->ui32StartOffset / 4 - (implicitOffset + 4 - 1) / 4;
uint32_t uPaddingUint;
for (uPaddingUint = 0; uPaddingUint < uNumPaddingUints; ++uPaddingUint)
{
bcatcstr(glsl, "\tuint padding_");
ConvertToUniformBufferName(glsl, psContext->psShader, psCBuf->Name);
bformata(glsl, "_%d_%d;\n", psVar->ui32StartOffset, uPaddingUint);
}
implicitOffset = psVar->ui32StartOffset - psVar->ui32StartOffset % 4;
}
implicitOffset += uVarAlignment - 1;
implicitOffset -= implicitOffset % uVarAlignment;
ASSERT(implicitOffset == psVar->ui32StartOffset);
DeclareConstBufferShaderVariable(psContext, psVar->sType.Name, &psVar->sType, 0);
implicitOffset += uVarSize;
}
bcatcstr(glsl, "};\n");
}
void DeclareBufferVariable(HLSLCrossCompilerContext* psContext, const uint32_t ui32BindingPoint, ConstantBuffer* psCBuf, const Operand* psOperand, const uint32_t ui32GloballyCoherentAccess, const ResourceType eResourceType)
{
const char* Name = psCBuf->Name;
bstring StructName;
#if !defined(NDEBUG)
uint32_t unnamed_struct = strcmp(psCBuf->asVars[0].Name, "$Element") == 0 ? 1 : 0;
#endif
bstring glsl = *psContext->currentGLSLString;
ASSERT(psCBuf->ui32NumVars == 1);
ASSERT(unnamed_struct);
StructName = bfromcstr("");
//TranslateOperand(psContext, psOperand, TO_FLAG_NAME_ONLY);
if (psOperand->eType == OPERAND_TYPE_RESOURCE && eResourceType == RTYPE_STRUCTURED)
{
bformata(StructName, "StructuredRes%d", psOperand->ui32RegisterNumber);
}
else if (psOperand->eType == OPERAND_TYPE_RESOURCE && eResourceType == RTYPE_UAV_RWBYTEADDRESS)
{
bformata(StructName, "RawRes%d", psOperand->ui32RegisterNumber);
}
else
{
bformata(StructName, "UAV%d", psOperand->ui32RegisterNumber);
}
PreDeclareStructType(psContext, bstr2cstr(StructName, '\0'), &psCBuf->asVars[0].sType);
// Add 'std430' layout for storage buffers.
// We don't use a global setting for all buffers because Mali drivers don't like that.
bcatcstr(glsl, "layout(std430");
/* [layout (location = X)] uniform vec4 HLSLConstantBufferName[numConsts]; */
// If storage blocking binding is not supported, then we must set the binding location in the shader. If we don't do it,
// all the storage buffers of the program get assigned the same value (0).
// Unfortunately this could cause binding collisions between different render stages for a storage buffer.
if (HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage, psContext->psShader->extensions) &&
(!StorageBlockBindingSupported(psContext->psShader->eTargetLanguage) || (psContext->flags & HLSLCC_FLAG_AVOID_RESOURCE_BINDINGS_AND_LOCATIONS) == 0))
{
bformata(glsl, ", binding = %d", ui32BindingPoint);
}
// Close 'layout'
bcatcstr(glsl, ")");
if (ui32GloballyCoherentAccess & GLOBALLY_COHERENT_ACCESS)
{
bcatcstr(glsl, "coherent ");
}
if (eResourceType == RTYPE_STRUCTURED)
{
bcatcstr(glsl, "readonly ");
}
bcatcstr(glsl, "buffer ");
if (eResourceType == RTYPE_STRUCTURED)
{
ConvertToTextureName(glsl, psContext->psShader, Name, NULL, 0);
}
else
{
ConvertToUAVName(glsl, psContext->psShader, Name);
}
bcatcstr(glsl, " {\n ");
DeclareConstBufferShaderVariable(psContext, bstr2cstr(StructName, '\0'), &psCBuf->asVars[0].sType, 1);
bcatcstr(glsl, "};\n");
bdestroy(StructName);
}
void DeclarePLSVariable(HLSLCrossCompilerContext* psContext, const uint32_t ui32BindingPoint, ConstantBuffer* plsVar, const Operand* psOperand, const uint32_t ui32GloballyCoherentAccess, const ResourceType eResourceType)
{
(void)psOperand;
(void)ui32GloballyCoherentAccess;
(void)eResourceType;
const char* Name = plsVar->Name;
#if !defined(NDEBUG)
uint32_t unnamed_struct = strcmp(plsVar->asVars[0].Name, "$Element") == 0 ? 1 : 0;
#endif
bstring glsl = *psContext->currentGLSLString;
ASSERT(plsVar->ui32NumVars == 1);
ASSERT(unnamed_struct);
// Define extension
// TODO: if we need more than one PLS var... we can't redefine the extension every time
// Extensions need to be declared before any non-preprocessor symbols. So we put it all the way at the beginning.
bstring ext = bfromcstralloc(1024, "#extension GL_EXT_shader_pixel_local_storage : require\n");
bconcat(ext, glsl);
bassign(glsl, ext);
bdestroy(ext);
switch (ui32BindingPoint)
{
case GMEM_PLS_RO_SLOT:
bcatcstr(glsl, "__pixel_local_inEXT PLS_STRUCT_READ_ONLY");
break;
case GMEM_PLS_WO_SLOT:
bcatcstr(glsl, "__pixel_local_outEXT PLS_STRUCT_WRITE_ONLY");
break;
case GMEM_PLS_RW_SLOT:
bcatcstr(glsl, "__pixel_localEXT PLS_STRUCT_READ_WRITE");
break;
default:
ASSERT(0);
}
bcatcstr(glsl, "\n{\n");
ASSERT(plsVar->ui32NumVars == 1);
ASSERT(plsVar->asVars[0].sType.Members != 0);
DeclarePLSStructVars(psContext, plsVar->asVars[0].sType.Name, &plsVar->asVars[0].sType);
bcatcstr(glsl, "\n} ");
ConvertToUAVName(glsl, psContext->psShader, Name);
bcatcstr(glsl, ";\n\n");
}
void DeclareStructConstants(HLSLCrossCompilerContext* psContext, const uint32_t ui32BindingPoint, ConstantBuffer* psCBuf, const Operand* psOperand)
{
bstring glsl = *psContext->currentGLSLString;
uint32_t i;
for (i = 0; i < psCBuf->ui32NumVars; ++i)
{
PreDeclareStructType(psContext, psCBuf->asVars[i].sType.Name, &psCBuf->asVars[i].sType);
}
/* [layout (location = X)] uniform vec4 HLSLConstantBufferName[numConsts]; */
if (HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage, psContext->psShader->extensions) && (psContext->flags & HLSLCC_FLAG_AVOID_RESOURCE_BINDINGS_AND_LOCATIONS) == 0)
{
bformata(glsl, "layout(location = %d) ", ui32BindingPoint);
}
bcatcstr(glsl, "uniform struct ");
TranslateOperand(psContext, psOperand, TO_FLAG_DECLARATION_NAME);
bcatcstr(glsl, "_Type {\n");
for (i = 0; i < psCBuf->ui32NumVars; ++i)
{
DeclareConstBufferShaderVariable(psContext, psCBuf->asVars[i].sType.Name, &psCBuf->asVars[i].sType, 0);
}
bcatcstr(glsl, "} ");
TranslateOperand(psContext, psOperand, TO_FLAG_DECLARATION_NAME);
bcatcstr(glsl, ";\n");
}
void TranslateDeclaration(HLSLCrossCompilerContext* psContext, const Declaration* psDecl)
{
bstring glsl = *psContext->currentGLSLString;
Shader* psShader = psContext->psShader;
switch (psDecl->eOpcode)
{
case OPCODE_DCL_INPUT_SGV:
case OPCODE_DCL_INPUT_PS_SGV:
case OPCODE_DCL_INPUT_PS_SIV:
{
const SPECIAL_NAME eSpecialName = psDecl->asOperands[0].eSpecialName;
switch (eSpecialName)
{
case NAME_POSITION:
{
if (psShader->eShaderType == PIXEL_SHADER)
{
AddBuiltinInput(psContext, psDecl, "gl_FragCoord", 4);
}
else
{
AddBuiltinInput(psContext, psDecl, "gl_Position", 4);
}
break;
}
case NAME_RENDER_TARGET_ARRAY_INDEX:
{
AddBuiltinInput(psContext, psDecl, "gl_Layer", 1);
break;
}
case NAME_CLIP_DISTANCE:
{
AddBuiltinInput(psContext, psDecl, "gl_ClipDistance", 4);
break;
}
case NAME_VIEWPORT_ARRAY_INDEX:
{
AddBuiltinInput(psContext, psDecl, "gl_ViewportIndex", 1);
break;
}
case NAME_INSTANCE_ID:
{
AddBuiltinInput(psContext, psDecl, "uint(gl_InstanceID)", 1);
break;
}
case NAME_IS_FRONT_FACE:
{
/*
Cast to uint used because
if(gl_FrontFacing != 0) failed to compiled on Intel HD 4000.
Suggests no implicit conversion for bool<->uint.
*/
AddBuiltinInput(psContext, psDecl, "uint(gl_FrontFacing)", 1);
break;
}
case NAME_SAMPLE_INDEX:
{
AddBuiltinInput(psContext, psDecl, "gl_SampleID", 1);
break;
}
case NAME_VERTEX_ID:
{
AddBuiltinInput(psContext, psDecl, "uint(gl_VertexID)", 1);
break;
}
case NAME_PRIMITIVE_ID:
{
AddBuiltinInput(psContext, psDecl, "gl_PrimitiveID", 1);
break;
}
default:
{
bformata(glsl, "in vec4 %s;\n", psDecl->asOperands[0].pszSpecialName);
bcatcstr(glsl, "#define ");
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
bformata(glsl, " %s\n", psDecl->asOperands[0].pszSpecialName);
break;
}
}
break;
}
case OPCODE_DCL_OUTPUT_SIV:
{
switch (psDecl->asOperands[0].eSpecialName)
{
case NAME_POSITION:
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT4, 0, "gl_Position");
break;
}
case NAME_RENDER_TARGET_ARRAY_INDEX:
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_INT, 0, "gl_Layer");
break;
}
case NAME_CLIP_DISTANCE:
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_ClipDistance");
break;
}
case NAME_VIEWPORT_ARRAY_INDEX:
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_INT, 0, "gl_ViewportIndex");
break;
}
case NAME_VERTEX_ID:
{
ASSERT(0); //VertexID is not an output
break;
}
case NAME_PRIMITIVE_ID:
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_INT, 0, "gl_PrimitiveID");
break;
}
case NAME_INSTANCE_ID:
{
ASSERT(0); //InstanceID is not an output
break;
}
case NAME_IS_FRONT_FACE:
{
ASSERT(0); //FrontFacing is not an output
break;
}
case NAME_FINAL_QUAD_U_EQ_0_EDGE_TESSFACTOR:
{
if (psContext->psShader->aIndexedOutput[psDecl->asOperands[0].ui32RegisterNumber])
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 4, "gl_TessLevelOuter");
}
else
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[0]");
}
break;
}
case NAME_FINAL_QUAD_V_EQ_0_EDGE_TESSFACTOR:
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[1]");
break;
}
case NAME_FINAL_QUAD_U_EQ_1_EDGE_TESSFACTOR:
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[2]");
break;
}
case NAME_FINAL_QUAD_V_EQ_1_EDGE_TESSFACTOR:
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[3]");
break;
}
case NAME_FINAL_TRI_U_EQ_0_EDGE_TESSFACTOR:
{
if (psContext->psShader->aIndexedOutput[psDecl->asOperands[0].ui32RegisterNumber])
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 3, "gl_TessLevelOuter");
}
else
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[0]");
}
break;
}
case NAME_FINAL_TRI_V_EQ_0_EDGE_TESSFACTOR:
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[1]");
break;
}
case NAME_FINAL_TRI_W_EQ_0_EDGE_TESSFACTOR:
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[2]");
break;
}
case NAME_FINAL_LINE_DENSITY_TESSFACTOR:
{
if (psContext->psShader->aIndexedOutput[psDecl->asOperands[0].ui32RegisterNumber])
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 2, "gl_TessLevelOuter");
}
else
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[0]");
}
break;
}
case NAME_FINAL_LINE_DETAIL_TESSFACTOR:
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[1]");
break;
}
case NAME_FINAL_TRI_INSIDE_TESSFACTOR:
case NAME_FINAL_QUAD_U_INSIDE_TESSFACTOR:
{
if (psContext->psShader->aIndexedOutput[psDecl->asOperands[0].ui32RegisterNumber])
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 2, "gl_TessLevelInner");
}
else
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelInner[0]");
}
break;
}
case NAME_FINAL_QUAD_V_INSIDE_TESSFACTOR:
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelInner[1]");
break;
}
default:
{
bformata(glsl, "out vec4 %s;\n", psDecl->asOperands[0].pszSpecialName);
bcatcstr(glsl, "#define ");
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
bformata(glsl, " %s\n", psDecl->asOperands[0].pszSpecialName);
break;
}
}
break;
}
case OPCODE_DCL_INPUT:
{
const Operand* psOperand = &psDecl->asOperands[0];
//Force the number of components to be 4.
/*dcl_output o3.xy
dcl_output o3.z
Would generate a vec2 and a vec3. We discard the second one making .z invalid!
*/
int iNumComponents = 4; //GetMaxComponentFromComponentMask(psOperand);
const char* StorageQualifier = "attribute";
char* InputName;
const char* Precision = "";
if ((psOperand->eType == OPERAND_TYPE_INPUT_DOMAIN_POINT) ||
(psOperand->eType == OPERAND_TYPE_OUTPUT_CONTROL_POINT_ID) ||
(psOperand->eType == OPERAND_TYPE_INPUT_COVERAGE_MASK) ||
(psOperand->eType == OPERAND_TYPE_INPUT_THREAD_ID) ||
(psOperand->eType == OPERAND_TYPE_INPUT_THREAD_GROUP_ID) ||
(psOperand->eType == OPERAND_TYPE_INPUT_THREAD_ID_IN_GROUP) ||
(psOperand->eType == OPERAND_TYPE_INPUT_THREAD_ID_IN_GROUP_FLATTENED))
{
break;
}
//Already declared as part of an array.
if (psShader->aIndexedInput[psDecl->asOperands[0].ui32RegisterNumber] == -1)
{
break;
}
InputName = GetDeclaredInputName(psContext, psShader->eShaderType, psOperand);
if (InOutSupported(psContext->psShader->eTargetLanguage))
{
StorageQualifier = "in";
}
if (HavePrecisionQualifers(psShader->eTargetLanguage))
{
switch (psOperand->eMinPrecision)
{
case OPERAND_MIN_PRECISION_DEFAULT:
{
Precision = "highp";
break;
}
case OPERAND_MIN_PRECISION_FLOAT_16:
{
Precision = "mediump";
break;
}
case OPERAND_MIN_PRECISION_FLOAT_2_8:
{
Precision = "lowp";
break;
}
case OPERAND_MIN_PRECISION_SINT_16:
{
Precision = "mediump";
break;
}
case OPERAND_MIN_PRECISION_UINT_16:
{
Precision = "mediump";
break;
}
}
}
DeclareInput(psContext, psDecl,
"", StorageQualifier, Precision, iNumComponents, (OPERAND_INDEX_DIMENSION)psOperand->iIndexDims, InputName);
bcstrfree(InputName);
break;
}
case OPCODE_DCL_INPUT_SIV:
{
if (psShader->eShaderType == PIXEL_SHADER)
{
psShader->sInfo.aePixelInputInterpolation[psDecl->asOperands[0].ui32RegisterNumber] = psDecl->value.eInterpolation;
}
break;
}
case OPCODE_DCL_INPUT_PS:
{
const Operand* psOperand = &psDecl->asOperands[0];
int iNumComponents = 4; //GetMaxComponentFromComponentMask(psOperand);
const char* StorageQualifier = "varying";
const char* Precision = "";
char* InputName = GetDeclaredInputName(psContext, PIXEL_SHADER, psOperand);
const char* Interpolation = "";
//Already declared as part of an array.
if (psShader->aIndexedInput[psDecl->asOperands[0].ui32RegisterNumber] == -1)
{
break;
}
if (InOutSupported(psContext->psShader->eTargetLanguage))
{
StorageQualifier = "in";
}
switch (psDecl->value.eInterpolation)
{
case INTERPOLATION_CONSTANT:
{
Interpolation = "flat";
break;
}
case INTERPOLATION_LINEAR:
{
break;
}
case INTERPOLATION_LINEAR_CENTROID:
{
Interpolation = "centroid";
break;
}
case INTERPOLATION_LINEAR_NOPERSPECTIVE:
{
Interpolation = "noperspective";
break;
}
case INTERPOLATION_LINEAR_NOPERSPECTIVE_CENTROID:
{
Interpolation = "noperspective centroid";
break;
}
case INTERPOLATION_LINEAR_SAMPLE:
{
Interpolation = "sample";
break;
}
case INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE:
{
Interpolation = "noperspective sample";
break;
}
}
if (HavePrecisionQualifers(psShader->eTargetLanguage))
{
switch (psOperand->eMinPrecision)
{
case OPERAND_MIN_PRECISION_DEFAULT:
{
Precision = "highp";
break;
}
case OPERAND_MIN_PRECISION_FLOAT_16:
{
Precision = "mediump";
break;
}
case OPERAND_MIN_PRECISION_FLOAT_2_8:
{
Precision = "lowp";
break;
}
case OPERAND_MIN_PRECISION_SINT_16:
{
Precision = "mediump";
break;
}
case OPERAND_MIN_PRECISION_UINT_16:
{
Precision = "mediump";
break;
}
}
}
DeclareInput(psContext, psDecl,
Interpolation, StorageQualifier, Precision, iNumComponents, INDEX_1D, InputName);
bcstrfree(InputName);
break;
}
case OPCODE_DCL_TEMPS:
{
const uint32_t ui32NumTemps = psDecl->value.ui32NumTemps;
if (psContext->flags & HLSLCC_FLAG_AVOID_TEMP_REGISTER_ALIASING && psContext->psShader->eShaderType != HULL_SHADER)
{
break;
}
if (ui32NumTemps > 0)
{
bformata(glsl, "vec4 Temp[%d];\n", ui32NumTemps);
if (psContext->psShader->bUseTempCopy)
{
bcatcstr(glsl, "vec4 TempCopy;\n");
}
bformata(glsl, "ivec4 Temp_int[%d];\n", ui32NumTemps);
if (psContext->psShader->bUseTempCopy)
{
bcatcstr(glsl, "vec4 TempCopy_int;\n");
}
if (HaveUVec(psShader->eTargetLanguage))
{
bformata(glsl, "uvec4 Temp_uint[%d];\n", ui32NumTemps);
if (psContext->psShader->bUseTempCopy)
{
bcatcstr(glsl, "uvec4 TempCopy_uint;\n");
}
}
if (psShader->fp64)
{
bformata(glsl, "dvec4 Temp_double[%d];\n", ui32NumTemps);
if (psContext->psShader->bUseTempCopy)
{
bcatcstr(glsl, "dvec4 TempCopy_double;\n");
}
}
}
break;
}
case OPCODE_SPECIAL_DCL_IMMCONST:
{
const Operand* psDest = &psDecl->asOperands[0];
const Operand* psSrc = &psDecl->asOperands[1];
ASSERT(psSrc->eType == OPERAND_TYPE_IMMEDIATE32);
if (psDest->eType == OPERAND_TYPE_SPECIAL_IMMCONSTINT)
{
bformata(glsl, "const ivec4 IntImmConst%d = ", psDest->ui32RegisterNumber);
}
else
{
bformata(glsl, "const vec4 ImmConst%d = ", psDest->ui32RegisterNumber);
AddToDx9ImmConstIndexableArray(psContext, psDest);
}
TranslateOperand(psContext, psSrc, TO_FLAG_NONE);
bcatcstr(glsl, ";\n");
break;
}
case OPCODE_DCL_CONSTANT_BUFFER:
{
const Operand* psOperand = &psDecl->asOperands[0];
const uint32_t ui32BindingPoint = psOperand->aui32ArraySizes[0];
ConstantBuffer* psCBuf = NULL;
GetConstantBufferFromBindingPoint(RGROUP_CBUFFER, ui32BindingPoint, &psContext->psShader->sInfo, &psCBuf);
if (psCBuf)
{
// Constant buffers declared as "dynamicIndexed" are declared as raw vec4 arrays, as there is no general way to retrieve the member corresponding to a dynamic index.
// Simple cases can probably be handled easily, but for example when arrays (possibly nested with structs) are contained in the constant buffer and the shader reads
// from a dynamic index we would need to "undo" the operations done in order to compute the variable offset, and such a feature is not available at the moment.
psCBuf->blob = psDecl->value.eCBAccessPattern == CONSTANT_BUFFER_ACCESS_PATTERN_DYNAMICINDEXED;
}
// We don't have a original resource name, maybe generate one???
if (!psCBuf)
{
if (HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage, psContext->psShader->extensions) && (psContext->flags & HLSLCC_FLAG_AVOID_RESOURCE_BINDINGS_AND_LOCATIONS) == 0)
{
bformata(glsl, "layout(location = %d) ", ui32BindingPoint);
}
bformata(glsl, "layout(std140) uniform ConstantBuffer%d {\n\tvec4 data[%d];\n} cb%d;\n", ui32BindingPoint, psOperand->aui32ArraySizes[1], ui32BindingPoint);
break;
}
else if (psCBuf->blob)
{
if (HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage, psContext->psShader->extensions) && (psContext->flags & HLSLCC_FLAG_AVOID_RESOURCE_BINDINGS_AND_LOCATIONS) == 0)
{
bformata(glsl, "layout(location = %d) ", ui32BindingPoint);
}
bcatcstr(glsl, "layout(std140) uniform ");
ConvertToUniformBufferName(glsl, psShader, psCBuf->Name);
bcatcstr(glsl, " {\n\tvec4 ");
ConvertToUniformBufferName(glsl, psShader, psCBuf->Name);
bformata(glsl, "_data[%d];\n};\n", psOperand->aui32ArraySizes[1]);
break;
}
if (psContext->flags & HLSLCC_FLAG_UNIFORM_BUFFER_OBJECT)
{
if (psContext->flags & HLSLCC_FLAG_GLOBAL_CONSTS_NEVER_IN_UBO && psCBuf->Name[0] == '$')
{
DeclareStructConstants(psContext, ui32BindingPoint, psCBuf, psOperand);
}
else
{
DeclareUBOConstants(psContext, ui32BindingPoint, psCBuf);
}
}
else
{
DeclareStructConstants(psContext, ui32BindingPoint, psCBuf, psOperand);
}
break;
}
case OPCODE_DCL_RESOURCE:
{
bool isGmemResource = false;
const int initialMemSize = 64;
bstring earlyMain = bfromcstralloc(initialMemSize, "");
if (IsGmemReservedSlot(FBF_EXT_COLOR, psDecl->asOperands[0].ui32RegisterNumber))
{
// A GMEM reserve slot was used.
// This is not a resource but an inout RT of the pixel shader
int regNum = GetGmemInputResourceSlot(psDecl->asOperands[0].ui32RegisterNumber);
// FXC thinks this is a texture so we can't trust the number of elements. We get that from the "register number".
int numElements = GetGmemInputResourceNumElements(psDecl->asOperands[0].ui32RegisterNumber);
ASSERT(numElements);
const char* Precision = "highp";
const char* outputName = "PixOutput";
bformata(glsl, "layout(location = %d) ", regNum);
bformata(glsl, "inout %s vec%d %s%d;\n", Precision, numElements, outputName, regNum);
const char* mask[] = { "x", "y", "z", "w" };
// Since we are using Textures as GMEM inputs FXC will threat them as vec4 values. The rendertarget may not be a vec4 (numElements != 4)
// so we create a new variable (GMEM_InputXX) at the beginning of the shader that wraps the rendertarget value.
bformata(earlyMain, "%s vec4 GMEM_Input%d = %s vec4(%s%d.", Precision, regNum, Precision, outputName, regNum);
for (int i = 0; i < 4; ++i)
{
bformata(earlyMain, "%s", i < numElements ? mask[i] : mask[numElements - 1]);
}
bcatcstr(earlyMain, ");\n");
isGmemResource = true;
}
else if (IsGmemReservedSlot(FBF_ARM_COLOR, psDecl->asOperands[0].ui32RegisterNumber))
{
bcatcstr(earlyMain, "vec4 GMEM_Input0 = vec4(gl_LastFragColorARM);\n");
isGmemResource = true;
}
else if (IsGmemReservedSlot(FBF_ARM_DEPTH, psDecl->asOperands[0].ui32RegisterNumber))
{
bcatcstr(earlyMain, "vec4 GMEM_Depth = vec4(gl_LastFragDepthARM);\n");
isGmemResource = true;
}
else if (IsGmemReservedSlot(FBF_ARM_STENCIL, psDecl->asOperands[0].ui32RegisterNumber))
{
bcatcstr(earlyMain, "ivec4 GMEM_Stencil = ivec4(gl_LastFragStencilARM);\n");
isGmemResource = true;
}
if (isGmemResource)
{
if (earlyMain->slen)
{
bstring* savedStringPtr = psContext->currentGLSLString;
psContext->currentGLSLString = &psContext->earlyMain;
psContext->indent++;
AddIndentation(psContext);
bconcat(*psContext->currentGLSLString, earlyMain);
psContext->indent--;
psContext->currentGLSLString = savedStringPtr;
}
break;
}
char* szResourceTypeName = "";
uint32_t bCanBeCompare;
uint32_t i;
SamplerMask sMask;
if (HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage, psContext->psShader->extensions) && (psContext->flags & HLSLCC_FLAG_AVOID_RESOURCE_BINDINGS_AND_LOCATIONS) == 0)
{
//Constant buffer locations start at 0. Resource locations start at ui32NumConstantBuffers.
bformata(glsl, "layout(location = %d) ", psContext->psShader->sInfo.ui32NumConstantBuffers + psDecl->asOperands[0].ui32RegisterNumber);
}
switch (psDecl->value.eResourceDimension)
{
case RESOURCE_DIMENSION_BUFFER:
szResourceTypeName = "Buffer";
bCanBeCompare = 0;
break;
case RESOURCE_DIMENSION_TEXTURE1D:
szResourceTypeName = "1D";
bCanBeCompare = 1;
break;
case RESOURCE_DIMENSION_TEXTURE2D:
szResourceTypeName = "2D";
bCanBeCompare = 1;
break;
case RESOURCE_DIMENSION_TEXTURE2DMS:
szResourceTypeName = "2DMS";
bCanBeCompare = 0;
break;
case RESOURCE_DIMENSION_TEXTURE3D:
szResourceTypeName = "3D";
bCanBeCompare = 0;
break;
case RESOURCE_DIMENSION_TEXTURECUBE:
szResourceTypeName = "Cube";
bCanBeCompare = 1;
break;
case RESOURCE_DIMENSION_TEXTURE1DARRAY:
szResourceTypeName = "1DArray";
bCanBeCompare = 1;
break;
case RESOURCE_DIMENSION_TEXTURE2DARRAY:
szResourceTypeName = "2DArray";
bCanBeCompare = 1;
break;
case RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
szResourceTypeName = "2DMSArray";
bCanBeCompare = 0;
break;
case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
szResourceTypeName = "CubeArray";
bCanBeCompare = 1;
break;
}
for (i = 0; i < psShader->sInfo.ui32NumSamplers; ++i)
{
if (psShader->sInfo.asSamplers[i].sMask.ui10TextureBindPoint == psDecl->asOperands[0].ui32RegisterNumber)
{
sMask = psShader->sInfo.asSamplers[i].sMask;
if (bCanBeCompare && sMask.bCompareSample) // Sampled with depth comparison
{
bformata(glsl, "uniform sampler%sShadow ", szResourceTypeName);
TextureName(*psContext->currentGLSLString, psContext->psShader, psDecl->asOperands[0].ui32RegisterNumber, sMask.ui10SamplerBindPoint, 1);
bcatcstr(glsl, ";\n");
}
if (sMask.bNormalSample || !sMask.bCompareSample) // Either sampled normally or with texelFetch
{
if (psDecl->ui32TexReturnType == RETURN_TYPE_SINT)
{
bformata(glsl, "uniform isampler%s ", szResourceTypeName);
}
else if (psDecl->ui32TexReturnType == RETURN_TYPE_UINT)
{
bformata(glsl, "uniform usampler%s ", szResourceTypeName);
}
else
{
bformata(glsl, "uniform sampler%s ", szResourceTypeName);
}
TextureName(*psContext->currentGLSLString, psContext->psShader, psDecl->asOperands[0].ui32RegisterNumber, sMask.ui10SamplerBindPoint, 0);
bcatcstr(glsl, ";\n");
}
}
}
ASSERT(psDecl->asOperands[0].ui32RegisterNumber < MAX_TEXTURES);
psShader->aeResourceDims[psDecl->asOperands[0].ui32RegisterNumber] = psDecl->value.eResourceDimension;
break;
}
case OPCODE_DCL_OUTPUT:
{
if (psShader->eShaderType == HULL_SHADER && psDecl->asOperands[0].ui32RegisterNumber == 0)
{
AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT4, 0, "gl_out[gl_InvocationID].gl_Position");
}
else
{
AddUserOutput(psContext, psDecl);
}
break;
}
case OPCODE_DCL_GLOBAL_FLAGS:
{
uint32_t ui32Flags = psDecl->value.ui32GlobalFlags;
// OpenGL versions lower than 4.1 don't support the
// layout(early_fragment_tests) directive and will fail to compile
// the shader
if (ui32Flags & GLOBAL_FLAG_FORCE_EARLY_DEPTH_STENCIL && EarlyDepthTestSupported(psShader->eTargetLanguage) &&
!(psShader->eGmemType & (FBF_ARM_DEPTH | FBF_ARM_STENCIL))) // Early fragment test is not allowed when fetching from the depth/stencil buffer.
{
bcatcstr(glsl, "layout(early_fragment_tests) in;\n");
}
if (!(ui32Flags & GLOBAL_FLAG_REFACTORING_ALLOWED))
{
//TODO add precise
//HLSL precise - http://msdn.microsoft.com/en-us/library/windows/desktop/hh447204(v=vs.85).aspx
}
if (ui32Flags & GLOBAL_FLAG_ENABLE_DOUBLE_PRECISION_FLOAT_OPS)
{
bcatcstr(glsl, "#extension GL_ARB_gpu_shader_fp64 : enable\n");
psShader->fp64 = 1;
}
break;
}
case OPCODE_DCL_THREAD_GROUP:
{
bformata(glsl, "layout(local_size_x = %d, local_size_y = %d, local_size_z = %d) in;\n",
psDecl->value.aui32WorkGroupSize[0],
psDecl->value.aui32WorkGroupSize[1],
psDecl->value.aui32WorkGroupSize[2]);
break;
}
case OPCODE_DCL_TESS_OUTPUT_PRIMITIVE:
{
if (psContext->psShader->eShaderType == HULL_SHADER)
{
psContext->psShader->sInfo.eTessOutPrim = psDecl->value.eTessOutPrim;
}
break;
}
case OPCODE_DCL_TESS_DOMAIN:
{
if (psContext->psShader->eShaderType == DOMAIN_SHADER)
{
switch (psDecl->value.eTessDomain)
{
case TESSELLATOR_DOMAIN_ISOLINE:
{
bcatcstr(glsl, "layout(isolines) in;\n");
break;
}
case TESSELLATOR_DOMAIN_TRI:
{
bcatcstr(glsl, "layout(triangles) in;\n");
break;
}
case TESSELLATOR_DOMAIN_QUAD:
{
bcatcstr(glsl, "layout(quads) in;\n");
break;
}
default:
{
break;
}
}
}
break;
}
case OPCODE_DCL_TESS_PARTITIONING:
{
if (psContext->psShader->eShaderType == HULL_SHADER)
{
psContext->psShader->sInfo.eTessPartitioning = psDecl->value.eTessPartitioning;
}
break;
}
case OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY:
{
switch (psDecl->value.eOutputPrimitiveTopology)
{
case PRIMITIVE_TOPOLOGY_POINTLIST:
{
bcatcstr(glsl, "layout(points) out;\n");
break;
}
case PRIMITIVE_TOPOLOGY_LINELIST_ADJ:
case PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ:
case PRIMITIVE_TOPOLOGY_LINELIST:
case PRIMITIVE_TOPOLOGY_LINESTRIP:
{
bcatcstr(glsl, "layout(line_strip) out;\n");
break;
}
case PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ:
case PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ:
case PRIMITIVE_TOPOLOGY_TRIANGLESTRIP:
case PRIMITIVE_TOPOLOGY_TRIANGLELIST:
{
bcatcstr(glsl, "layout(triangle_strip) out;\n");
break;
}
default:
{
break;
}
}
break;
}
case OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT:
{
bformata(glsl, "layout(max_vertices = %d) out;\n", psDecl->value.ui32MaxOutputVertexCount);
break;
}
case OPCODE_DCL_GS_INPUT_PRIMITIVE:
{
switch (psDecl->value.eInputPrimitive)
{
case PRIMITIVE_POINT:
{
bcatcstr(glsl, "layout(points) in;\n");
break;
}
case PRIMITIVE_LINE:
{
bcatcstr(glsl, "layout(lines) in;\n");
break;
}
case PRIMITIVE_LINE_ADJ:
{
bcatcstr(glsl, "layout(lines_adjacency) in;\n");
break;
}
case PRIMITIVE_TRIANGLE:
{
bcatcstr(glsl, "layout(triangles) in;\n");
break;
}
case PRIMITIVE_TRIANGLE_ADJ:
{
bcatcstr(glsl, "layout(triangles_adjacency) in;\n");
break;
}
default:
{
break;
}
}
break;
}
case OPCODE_DCL_INTERFACE:
{
const uint32_t interfaceID = psDecl->value.interface.ui32InterfaceID;
const uint32_t numUniforms = psDecl->value.interface.ui32ArraySize;
const uint32_t ui32NumBodiesPerTable = psContext->psShader->funcPointer[interfaceID].ui32NumBodiesPerTable;
ShaderVar* psVar;
uint32_t varFound;
const char* uniformName;
varFound = GetInterfaceVarFromOffset(interfaceID, &psContext->psShader->sInfo, &psVar);
ASSERT(varFound);
uniformName = &psVar->sType.Name[0];
bformata(glsl, "subroutine uniform SubroutineType %s[%d*%d];\n", uniformName, numUniforms, ui32NumBodiesPerTable);
break;
}
case OPCODE_DCL_FUNCTION_BODY:
{
//bformata(glsl, "void Func%d();//%d\n", psDecl->asOperands[0].ui32RegisterNumber, psDecl->asOperands[0].eType);
break;
}
case OPCODE_DCL_FUNCTION_TABLE:
{
break;
}
case OPCODE_CUSTOMDATA:
{
const uint32_t ui32NumVec4 = psDecl->ui32NumOperands;
const uint32_t ui32NumVec4Minus1 = (ui32NumVec4 - 1);
uint32_t ui32ConstIndex = 0;
int integerCoords[4];
bool qualcommWorkaround = (psContext->flags & HLSLCC_FLAG_QUALCOMM_GLES30_DRIVER_WORKAROUND) != 0;
if (qualcommWorkaround)
{
bformata(glsl, "const ");
}
bformata(glsl, "ivec4 immediateConstBufferInt[%d] = ivec4[%d] (\n", ui32NumVec4, ui32NumVec4);
for (ui32ConstIndex = 0; ui32ConstIndex < ui32NumVec4Minus1; ui32ConstIndex++)
{
integerCoords[0] = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].a;
integerCoords[1] = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].b;
integerCoords[2] = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].c;
integerCoords[3] = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].d;
bformata(glsl, "\tivec4(%d, %d, %d, %d), \n", integerCoords[0], integerCoords[1], integerCoords[2], integerCoords[3]);
}
//No trailing comma on this one
integerCoords[0] = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].a;
integerCoords[1] = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].b;
integerCoords[2] = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].c;
integerCoords[3] = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].d;
bformata(glsl, "\tivec4(%d, %d, %d, %d)\n", integerCoords[0], integerCoords[1], integerCoords[2], integerCoords[3]);
bcatcstr(glsl, ");\n");
//If ShaderBitEncodingSupported then 1 integer buffer, use intBitsToFloat to get float values. - More instructions.
//else 2 buffers - one integer and one float. - More data
if (ShaderBitEncodingSupported(psShader->eTargetLanguage) == 0)
{
float floatCoords[4];
bcatcstr(glsl, "#define immediateConstBufferI(idx) immediateConstBufferInt[idx]\n");
bcatcstr(glsl, "#define immediateConstBufferF(idx) immediateConstBuffer[idx]\n");
bformata(glsl, "vec4 immediateConstBuffer[%d] = vec4[%d] (\n", ui32NumVec4, ui32NumVec4);
for (ui32ConstIndex = 0; ui32ConstIndex < ui32NumVec4Minus1; ui32ConstIndex++)
{
floatCoords[0] = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].a;
floatCoords[1] = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].b;
floatCoords[2] = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].c;
floatCoords[3] = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].d;
//A single vec4 can mix integer and float types.
//Forced NAN and INF to zero inside the immediate constant buffer. This will allow the shader to compile.
if (fpcheck(floatCoords[0]))
{
floatCoords[0] = 0;
}
if (fpcheck(floatCoords[1]))
{
floatCoords[1] = 0;
}
if (fpcheck(floatCoords[2]))
{
floatCoords[2] = 0;
}
if (fpcheck(floatCoords[3]))
{
floatCoords[3] = 0;
}
bformata(glsl, "\tvec4(%e, %e, %e, %e), \n", floatCoords[0], floatCoords[1], floatCoords[2], floatCoords[3]);
}
//No trailing comma on this one
floatCoords[0] = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].a;
floatCoords[1] = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].b;
floatCoords[2] = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].c;
floatCoords[3] = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].d;
if (fpcheck(floatCoords[0]))
{
floatCoords[0] = 0;
}
if (fpcheck(floatCoords[1]))
{
floatCoords[1] = 0;
}
if (fpcheck(floatCoords[2]))
{
floatCoords[2] = 0;
}
if (fpcheck(floatCoords[3]))
{
floatCoords[3] = 0;
}
bformata(glsl, "\tvec4(%e, %e, %e, %e)\n", floatCoords[0], floatCoords[1], floatCoords[2], floatCoords[3]);
bcatcstr(glsl, ");\n");
}
else
{
if (qualcommWorkaround)
{
bcatcstr(glsl, "ivec4 immediateConstBufferI(int idx) { return immediateConstBufferInt[idx]; }\n");
bcatcstr(glsl, "vec4 immediateConstBufferF(int idx) { return intBitsToFloat(immediateConstBufferInt[idx]); }\n");
}
else
{
bcatcstr(glsl, "#define immediateConstBufferI(idx) immediateConstBufferInt[idx]\n");
bcatcstr(glsl, "#define immediateConstBufferF(idx) intBitsToFloat(immediateConstBufferInt[idx])\n");
}
}
break;
}
case OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT:
{
const uint32_t forkPhaseNum = psDecl->value.aui32HullPhaseInstanceInfo[0];
const uint32_t instanceCount = psDecl->value.aui32HullPhaseInstanceInfo[1];
bformata(glsl, "const int HullPhase%dInstanceCount = %d;\n", forkPhaseNum, instanceCount);
break;
}
case OPCODE_DCL_INDEXABLE_TEMP:
{
const uint32_t ui32RegIndex = psDecl->sIdxTemp.ui32RegIndex;
const uint32_t ui32RegCount = psDecl->sIdxTemp.ui32RegCount;
const uint32_t ui32RegComponentSize = psDecl->sIdxTemp.ui32RegComponentSize;
bformata(glsl, "vec%d TempArray%d[%d];\n", ui32RegComponentSize, ui32RegIndex, ui32RegCount);
bformata(glsl, "ivec%d TempArray%d_int[%d];\n", ui32RegComponentSize, ui32RegIndex, ui32RegCount);
if (HaveUVec(psShader->eTargetLanguage))
{
bformata(glsl, "uvec%d TempArray%d_uint[%d];\n", ui32RegComponentSize, ui32RegIndex, ui32RegCount);
}
if (psShader->fp64)
{
bformata(glsl, "dvec%d TempArray%d_double[%d];\n", ui32RegComponentSize, ui32RegIndex, ui32RegCount);
}
break;
}
case OPCODE_DCL_INDEX_RANGE:
{
break;
}
case OPCODE_HS_DECLS:
{
break;
}
case OPCODE_DCL_INPUT_CONTROL_POINT_COUNT:
{
break;
}
case OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT:
{
if (psContext->psShader->eShaderType == HULL_SHADER)
{
bformata(glsl, "layout(vertices=%d) out;\n", psDecl->value.ui32MaxOutputVertexCount);
}
break;
}
case OPCODE_HS_FORK_PHASE:
{
break;
}
case OPCODE_HS_JOIN_PHASE:
{
break;
}
case OPCODE_DCL_SAMPLER:
{
break;
}
case OPCODE_DCL_HS_MAX_TESSFACTOR:
{
//For GLSL the max tessellation factor is fixed to the value of gl_MaxTessGenLevel.
break;
}
case OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED:
{
if (psDecl->sUAV.ui32GloballyCoherentAccess & GLOBALLY_COHERENT_ACCESS)
{
bcatcstr(glsl, "coherent ");
}
if (psShader->aiOpcodeUsed[OPCODE_LD_UAV_TYPED] == 0)
{
bcatcstr(glsl, "writeonly ");
}
else
{
if (psShader->aiOpcodeUsed[OPCODE_STORE_UAV_TYPED] == 0)
{
bcatcstr(glsl, "readonly ");
}
switch (psDecl->sUAV.Type)
{
case RETURN_TYPE_FLOAT:
bcatcstr(glsl, "layout(rgba32f) ");
break;
case RETURN_TYPE_UNORM:
bcatcstr(glsl, "layout(rgba8) ");
break;
case RETURN_TYPE_SNORM:
bcatcstr(glsl, "layout(rgba8_snorm) ");
break;
case RETURN_TYPE_UINT:
bcatcstr(glsl, "layout(rgba32ui) ");
break;
case RETURN_TYPE_SINT:
bcatcstr(glsl, "layout(rgba32i) ");
break;
default:
ASSERT(0);
}
}
{
char* prefix = "";
switch (psDecl->sUAV.Type)
{
case RETURN_TYPE_UINT:
prefix = "u";
break;
case RETURN_TYPE_SINT:
prefix = "i";
break;
default:
break;
}
switch (psDecl->value.eResourceDimension)
{
case RESOURCE_DIMENSION_BUFFER:
bformata(glsl, "uniform %simageBuffer ", prefix);
break;
case RESOURCE_DIMENSION_TEXTURE1D:
bformata(glsl, "uniform %simage1D ", prefix);
break;
case RESOURCE_DIMENSION_TEXTURE2D:
bformata(glsl, "uniform %simage2D ", prefix);
break;
case RESOURCE_DIMENSION_TEXTURE2DMS:
bformata(glsl, "uniform %simage2DMS ", prefix);
break;
case RESOURCE_DIMENSION_TEXTURE3D:
bformata(glsl, "uniform %simage3D ", prefix);
break;
case RESOURCE_DIMENSION_TEXTURECUBE:
bformata(glsl, "uniform %simageCube ", prefix);
break;
case RESOURCE_DIMENSION_TEXTURE1DARRAY:
bformata(glsl, "uniform %simage1DArray ", prefix);
break;
case RESOURCE_DIMENSION_TEXTURE2DARRAY:
bformata(glsl, "uniform %simage2DArray ", prefix);
break;
case RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
bformata(glsl, "uniform %simage3DArray ", prefix);
break;
case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
bformata(glsl, "uniform %simageCubeArray ", prefix);
break;
}
}
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
bcatcstr(glsl, ";\n");
break;
}
case OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED:
{
const uint32_t ui32BindingPoint = psDecl->asOperands[0].aui32ArraySizes[0];
ConstantBuffer* psCBuf = NULL;
if (psDecl->sUAV.bCounter)
{
bformata(glsl, "layout (binding = 1) uniform atomic_uint UAV%d_counter;\n", psDecl->asOperands[0].ui32RegisterNumber);
}
GetConstantBufferFromBindingPoint(RGROUP_UAV, ui32BindingPoint, &psContext->psShader->sInfo, &psCBuf);
if (ui32BindingPoint >= GMEM_PLS_RO_SLOT && ui32BindingPoint <= GMEM_PLS_RW_SLOT)
{
DeclarePLSVariable(psContext, ui32BindingPoint, psCBuf, &psDecl->asOperands[0], psDecl->sUAV.ui32GloballyCoherentAccess, RTYPE_UAV_RWSTRUCTURED);
}
else
{
DeclareBufferVariable(psContext, ui32BindingPoint, psCBuf, &psDecl->asOperands[0], psDecl->sUAV.ui32GloballyCoherentAccess, RTYPE_UAV_RWSTRUCTURED);
}
break;
}
case OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW:
{
bstring varName;
if (psDecl->sUAV.bCounter)
{
bformata(glsl, "layout (binding = 1) uniform atomic_uint UAV%d_counter;\n", psDecl->asOperands[0].ui32RegisterNumber);
}
varName = bfromcstralloc(16, "");
bformata(varName, "UAV%d", psDecl->asOperands[0].ui32RegisterNumber);
bformata(glsl, "buffer Block%d {\n\tuint ", psDecl->asOperands[0].ui32RegisterNumber);
ShaderVarName(glsl, psShader, bstr2cstr(varName, '\0'));
bcatcstr(glsl, "[];\n};\n");
bdestroy(varName);
break;
}
case OPCODE_DCL_RESOURCE_STRUCTURED:
{
ConstantBuffer* psCBuf = NULL;
GetConstantBufferFromBindingPoint(RGROUP_TEXTURE, psDecl->asOperands[0].ui32RegisterNumber, &psContext->psShader->sInfo, &psCBuf);
DeclareBufferVariable(psContext, psDecl->asOperands[0].ui32RegisterNumber, psCBuf, &psDecl->asOperands[0], 0, RTYPE_STRUCTURED);
break;
}
case OPCODE_DCL_RESOURCE_RAW:
{
bstring varName = bfromcstralloc(16, "");
bformata(varName, "RawRes%d", psDecl->asOperands[0].ui32RegisterNumber);
bformata(glsl, "buffer Block%d {\n\tuint ", psDecl->asOperands[0].ui32RegisterNumber);
ShaderVarName(glsl, psContext->psShader, bstr2cstr(varName, '\0'));
bcatcstr(glsl, "[];\n};\n");
bdestroy(varName);
break;
}
case OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW:
{
ShaderVarType* psVarType = &psShader->sGroupSharedVarType[psDecl->asOperands[0].ui32RegisterNumber];
ASSERT(psDecl->asOperands[0].ui32RegisterNumber < MAX_GROUPSHARED);
ASSERT(psDecl->sTGSM.ui32Count == 1);
bcatcstr(glsl, "shared uint ");
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
bformata(glsl, "[%d];\n", psDecl->sTGSM.ui32Count);
memset(psVarType, 0, sizeof(ShaderVarType));
strcpy(psVarType->Name, "$Element");
psVarType->Columns = psDecl->sTGSM.ui32Stride / 4;
psVarType->Elements = psDecl->sTGSM.ui32Count;
psVarType->Type = SVT_UINT;
break;
}
case OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED:
{
ShaderVarType* psVarType = &psShader->sGroupSharedVarType[psDecl->asOperands[0].ui32RegisterNumber];
ASSERT(psDecl->asOperands[0].ui32RegisterNumber < MAX_GROUPSHARED);
bcatcstr(glsl, "shared struct {\n");
bformata(glsl, "uint value[%d];\n", psDecl->sTGSM.ui32Stride / 4);
bcatcstr(glsl, "} ");
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
bformata(glsl, "[%d];\n",
psDecl->sTGSM.ui32Count);
memset(psVarType, 0, sizeof(ShaderVarType));
strcpy(psVarType->Name, "$Element");
psVarType->Columns = psDecl->sTGSM.ui32Stride / 4;
psVarType->Elements = psDecl->sTGSM.ui32Count;
psVarType->Type = SVT_UINT;
break;
}
case OPCODE_DCL_STREAM:
{
ASSERT(psDecl->asOperands[0].eType == OPERAND_TYPE_STREAM);
psShader->ui32CurrentVertexOutputStream = psDecl->asOperands[0].ui32RegisterNumber;
bformata(glsl, "layout(stream = %d) out;\n", psShader->ui32CurrentVertexOutputStream);
break;
}
case OPCODE_DCL_GS_INSTANCE_COUNT:
{
bformata(glsl, "layout(invocations = %d) in;\n", psDecl->value.ui32GSInstanceCount);
break;
}
default:
{
ASSERT(0);
break;
}
}
}
//Convert from per-phase temps to global temps for GLSL.
void ConsolidateHullTempVars(Shader* psShader)
{
uint32_t i, k;
const uint32_t ui32NumDeclLists = 3 + psShader->ui32ForkPhaseCount;
Declaration* pasDeclArray[3 + MAX_FORK_PHASES];
uint32_t aui32DeclCounts[3 + MAX_FORK_PHASES];
uint32_t ui32NumTemps = 0;
i = 0;
pasDeclArray[i] = psShader->psHSDecl;
aui32DeclCounts[i++] = psShader->ui32HSDeclCount;
pasDeclArray[i] = psShader->psHSControlPointPhaseDecl;
aui32DeclCounts[i++] = psShader->ui32HSControlPointDeclCount;
for (k = 0; k < psShader->ui32ForkPhaseCount; ++k)
{
pasDeclArray[i] = psShader->apsHSForkPhaseDecl[k];
aui32DeclCounts[i++] = psShader->aui32HSForkDeclCount[k];
}
pasDeclArray[i] = psShader->psHSJoinPhaseDecl;
aui32DeclCounts[i++] = psShader->ui32HSJoinDeclCount;
for (k = 0; k < ui32NumDeclLists; ++k)
{
for (i = 0; i < aui32DeclCounts[k]; ++i)
{
Declaration* psDecl = pasDeclArray[k] + i;
if (psDecl->eOpcode == OPCODE_DCL_TEMPS)
{
if (ui32NumTemps < psDecl->value.ui32NumTemps)
{
//Find the total max number of temps needed by the entire
//shader.
ui32NumTemps = psDecl->value.ui32NumTemps;
}
//Only want one global temp declaration.
psDecl->value.ui32NumTemps = 0;
}
}
}
//Find the first temp declaration and make it
//declare the max needed amount of temps.
for (k = 0; k < ui32NumDeclLists; ++k)
{
for (i = 0; i < aui32DeclCounts[k]; ++i)
{
Declaration* psDecl = pasDeclArray[k] + i;
if (psDecl->eOpcode == OPCODE_DCL_TEMPS)
{
psDecl->value.ui32NumTemps = ui32NumTemps;
return;
}
}
}
}
const char* GetMangleSuffix(const SHADER_TYPE eShaderType)
{
switch (eShaderType)
{
case VERTEX_SHADER:
return "VS";
case PIXEL_SHADER:
return "PS";
case GEOMETRY_SHADER:
return "GS";
case HULL_SHADER:
return "HS";
case DOMAIN_SHADER:
return "DS";
case COMPUTE_SHADER:
return "CS";
}
ASSERT(0);
return "";
}