Files
o3de/Code/Tools/HLSLCrossCompilerMETAL/src/toGLSLDeclaration.c
T

2679 lines
94 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 "bstrlib.h"
#include "internal_includes/debug.h"
#include "internal_includes/hlslcc_malloc.h"
#include <math.h>
#include <float.h>
#ifdef _MSC_VER
#ifndef isnan
#define isnan(x) _isnan(x)
#endif
#ifndef isinf
#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);
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 AddToDx9ImmConstIndexableArray(HLSLCrossCompilerContext* psContext, const Operand* psOperand)
{
bstring* savedStringPtr = psContext->currentShaderString;
psContext->currentShaderString = &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->currentShaderString = savedStringPtr;
}
void DeclareConstBufferShaderVariable(bstring glsl, const char* Name, const struct ShaderVarType_TAG* psType, int unsizedArray)
//const SHADER_VARIABLE_CLASS eClass, const SHADER_VARIABLE_TYPE eType,
//const char* pszName)
{
if(psType->Class == SVC_STRUCT)
{
bformata(glsl, "\t%s_Type %s", Name, Name);
}
else if(psType->Class == SVC_MATRIX_COLUMNS || psType->Class == SVC_MATRIX_ROWS)
{
switch(psType->Type)
{
case SVT_FLOAT:
{
bformata(glsl, "\tmat4 %s", Name);
break;
}
default:
{
ASSERT(0);
break;
}
}
if(psType->Elements > 1)
{
bformata(glsl, "[%d]", psType->Elements);
}
}
else
if(psType->Class == SVC_VECTOR)
{
switch(psType->Type)
{
case SVT_FLOAT:
{
bformata(glsl, "\tvec%d %s", psType->Columns, Name);
break;
}
case SVT_UINT:
{
bformata(glsl, "\tuvec%d %s", psType->Columns, Name);
break;
}
case SVT_INT:
{
bformata(glsl, "\tivec%d %s", psType->Columns, Name);
break;
}
case SVT_DOUBLE:
{
bformata(glsl, "\tdvec%d %s", psType->Columns, Name);
break;
}
case SVT_BOOL:
{
bformata(glsl, "\tbvec%d %s", psType->Columns, Name);
break;
}
default:
{
ASSERT(0);
break;
}
}
if(psType->Elements > 1)
{
bformata(glsl, "[%d]", psType->Elements);
}
}
else
if(psType->Class == SVC_SCALAR)
{
switch(psType->Type)
{
case SVT_FLOAT:
{
bformata(glsl, "\tfloat %s", Name);
break;
}
case SVT_UINT:
{
bformata(glsl, "\tuint %s", Name);
break;
}
case SVT_INT:
{
bformata(glsl, "\tint %s", Name);
break;
}
case SVT_DOUBLE:
{
bformata(glsl, "\tdouble %s", Name);
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 %s", Name);
// Also change the definition in the type tree.
((ShaderVarType *)psType)->Type = SVT_INT;
break;
}
default:
{
ASSERT(0);
break;
}
}
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(bstring glsl, const char* Name, const struct ShaderVarType_TAG* psType)
{
uint32_t i;
for(i=0; i<psType->MemberCount; ++i)
{
if(psType->Members[i].Class == SVC_STRUCT)
{
PreDeclareStructType(glsl, psType->Members[i].Name, &psType->Members[i]);
}
}
if(psType->Class == SVC_STRUCT)
{
#if defined(_DEBUG)
uint32_t unnamed_struct = strcmp(Name, "$Element") == 0 ? 1 : 0;
#endif
//Not supported at the moment
ASSERT(!unnamed_struct);
bformata(glsl, "struct %s_Type {\n", Name);
for(i=0; i<psType->MemberCount; ++i)
{
ASSERT(psType->Members != 0);
DeclareConstBufferShaderVariable(glsl, psType->Members[i].Name, &psType->Members[i], 0);
}
bformata(glsl, "};\n");
}
}
const char* GetDeclaredInputName(const HLSLCrossCompilerContext* psContext, const SHADER_TYPE eShaderType, const Operand* psOperand)
{
bstring inputName;
char* cstr;
InOutSignature* psIn;
int found = GetInputSignatureFromRegister(psOperand->ui32RegisterNumber, &psContext->psShader->sInfo, &psIn);
if((psContext->flags & HLSLCC_FLAG_INOUT_SEMANTIC_NAMES) && found)
{
if (eShaderType == VERTEX_SHADER) /* We cannot have input and output names conflict, but vs output must match ps input. Prefix vs input. */
inputName = bformat("in_%s%d", psIn->SemanticName, psIn->ui32SemanticIndex);
else
inputName = bformat("%s%d", psIn->SemanticName, psIn->ui32SemanticIndex);
}
else 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_APPEND_SEMANTIC_NAMES) && found)
{
bformata(inputName,"_%s%d", psIn->SemanticName, psIn->ui32SemanticIndex);
}
cstr = bstr2cstr(inputName, '\0');
bdestroy(inputName);
return cstr;
}
const char* GetDeclaredOutputName(const HLSLCrossCompilerContext* psContext,
const SHADER_TYPE eShaderType,
const Operand* psOperand,
int* piStream)
{
bstring outputName;
char* cstr;
InOutSignature* psOut;
#if defined(_DEBUG)
int foundOutput =
#endif
GetOutputSignatureFromRegister(
psContext->currentPhase,
psOperand->ui32RegisterNumber,
psOperand->ui32CompMask,
psContext->psShader->ui32CurrentVertexOutputStream,
&psContext->psShader->sInfo,
&psOut);
ASSERT(foundOutput);
if(psContext->flags & HLSLCC_FLAG_INOUT_SEMANTIC_NAMES)
{
outputName = bformat("%s%d", psOut->SemanticName, psOut->ui32SemanticIndex);
}
else 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_APPEND_SEMANTIC_NAMES)
{
bformata(outputName, "_%s%d", psOut->SemanticName, psOut->ui32SemanticIndex);
}
cstr = bstr2cstr(outputName, '\0');
bdestroy(outputName);
return cstr;
}
const char* GetInterpolationString(INTERPOLATION_MODE eMode)
{
switch(eMode)
{
case INTERPOLATION_CONSTANT:
{
return "flat";
}
case INTERPOLATION_LINEAR:
{
return "";
}
case INTERPOLATION_LINEAR_CENTROID:
{
return "centroid";
}
case INTERPOLATION_LINEAR_NOPERSPECTIVE:
{
return "noperspective";
break;
}
case INTERPOLATION_LINEAR_NOPERSPECTIVE_CENTROID:
{
return "noperspective centroid";
}
case INTERPOLATION_LINEAR_SAMPLE:
{
return "sample";
}
case INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE:
{
return "noperspective sample";
}
default:
{
return "";
}
}
}
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)
{
ShaderData* psShader = psContext->psShader;
bstring glsl = *psContext->currentShaderString;
// 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 (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions, psContext->flags) ||
(psShader->eShaderType == VERTEX_SHADER && HaveLimitedInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->flags)))
{
// Skip location if requested by the flags.
if (!(psContext->flags & HLSLCC_FLAG_DISABLE_EXPLICIT_LOCATIONS))
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%d Input%d[%d];\n", 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%d Input%d[%d];\n", 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%d Input%d;\n", vecType, iNumComponents, psDecl->asOperands[0].ui32RegisterNumber);
psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] = -1;
}
}
break;
}
}
}
if(psShader->abInputReferencedByInstruction[psDecl->asOperands[0].ui32RegisterNumber])
{
psContext->currentShaderString = &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->currentShaderString = &psContext->mainShader;
}
}
void AddBuiltinInput(HLSLCrossCompilerContext* psContext, const Declaration* psDecl, const char* builtinName)
{
bstring glsl = *psContext->currentShaderString;
ShaderData* psShader = psContext->psShader;
if(psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] == 0)
{
SHADER_VARIABLE_TYPE eType = GetOperandDataType(psContext, &psDecl->asOperands[0]);
switch(eType)
{
case SVT_INT:
bformata(glsl, "ivec4 ");
break;
case SVT_UINT:
bformata(glsl, "uvec4 ");
break;
case SVT_BOOL:
bformata(glsl, "bvec4 ");
break;
default:
bformata(glsl, "vec4 ");
break;
}
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->currentShaderString = &psContext->earlyMain;
psContext->indent++;
AddIndentation(psContext);
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_DESTINATION);
bformata(psContext->earlyMain, " = %s", builtinName);
switch(psDecl->asOperands[0].eSpecialName)
{
case NAME_POSITION:
TranslateOperandSwizzle(psContext, &psDecl->asOperands[0]);
break;
default:
//Scalar built-in. Don't apply swizzle.
break;
}
bcatcstr(psContext->earlyMain, ";\n");
psContext->indent--;
psContext->currentShaderString = &psContext->mainShader;
}
int OutputNeedsDeclaring(HLSLCrossCompilerContext* psContext, const Operand* psOperand, const int count)
{
ShaderData* psShader = psContext->psShader;
const uint32_t declared = ((psContext->currentPhase + 1) << 3) | psShader->ui32CurrentVertexOutputStream;
if(psShader->aiOutputDeclared[psOperand->ui32RegisterNumber] != declared)
{
int offset;
for(offset = 0; offset < count; offset++)
{
psShader->aiOutputDeclared[psOperand->ui32RegisterNumber+offset] = declared;
}
return 1;
}
if(psShader->eShaderType == PIXEL_SHADER)
{
if(psOperand->eType == OPERAND_TYPE_OUTPUT_DEPTH_GREATER_EQUAL ||
psOperand->eType == OPERAND_TYPE_OUTPUT_DEPTH_LESS_EQUAL)
{
return 1;
}
}
return 0;
}
void AddBuiltinOutput(HLSLCrossCompilerContext* psContext, const Declaration* psDecl, const GLVARTYPE type, int arrayElements, const char* builtinName)
{
bstring glsl = *psContext->currentShaderString;
ShaderData* psShader = psContext->psShader;
psContext->havePostShaderCode[psContext->currentPhase] = 1;
if(OutputNeedsDeclaring(psContext, &psDecl->asOperands[0], arrayElements ? arrayElements : 1))
{
InOutSignature* psSignature = NULL;
GetOutputSignatureFromRegister(
psContext->currentPhase,
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");
switch (type)
{
case GLVARTYPE_INT:
bcatcstr(glsl, "ivec4 ");
break;
default:
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->currentShaderString = &psContext->postShaderCode[psContext->currentPhase];
glsl = *psContext->currentShaderString;
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], type == GLVARTYPE_INT ? TO_FLAG_INTEGER : TO_FLAG_NONE);
bformata(glsl, ");\n");
}
}
}
psContext->indent--;
psContext->currentShaderString = &psContext->mainShader;
}
}
void AddUserOutput(HLSLCrossCompilerContext* psContext, const Declaration* psDecl)
{
bstring glsl = *psContext->currentShaderString;
ShaderData* 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(
psContext->currentPhase,
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;
const char* OutputName = GetDeclaredOutputName(psContext, PIXEL_SHADER, psOperand, &stream);
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions, psContext->flags) || HaveLimitedInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->flags))
{
uint32_t index = 0;
uint32_t renderTarget = psDecl->asOperands[0].ui32RegisterNumber;
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);
}
}
break;
}
}
break;
}
case VERTEX_SHADER:
{
int iNumComponents = 4;//GetMaxComponentFromComponentMask(&psDecl->asOperands[0]);
const char* Interpolation = "";
int stream = 0;
const char* OutputName = GetDeclaredOutputName(psContext, VERTEX_SHADER, psOperand, &stream);
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions, psContext->flags))
{
if (!(psContext->flags & HLSLCC_FLAG_DISABLE_EXPLICIT_LOCATIONS))
bformata(glsl, "layout(location = %d) ", psDecl->asOperands[0].ui32RegisterNumber);
}
if(InOutSupported(psContext->psShader->eTargetLanguage))
{
bformata(glsl, "%s out %s %s%d %s;\n", Interpolation, Precision, type, iNumComponents, OutputName);
}
else
{
bformata(glsl, "%s varying %s %s%d %s;\n", Interpolation, Precision, type, iNumComponents, OutputName);
}
bformata(glsl, "#define Output%d %s\n", psDecl->asOperands[0].ui32RegisterNumber, OutputName);
break;
}
case GEOMETRY_SHADER:
{
int stream = 0;
const char* OutputName = GetDeclaredOutputName(psContext, GEOMETRY_SHADER, psOperand, &stream);
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions, psContext->flags))
{
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);
}
break;
}
case HULL_SHADER:
{
int stream = 0;
const 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(psContext->currentPhase == HS_JOIN_PHASE)
{
bformata(glsl, "out patch %s4 %s[];\n", type, OutputName);
}
else
{
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions, psContext->flags))
{
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);
break;
}
case DOMAIN_SHADER:
{
int stream = 0;
const char* OutputName = GetDeclaredOutputName(psContext, DOMAIN_SHADER, psOperand, &stream);
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions, psContext->flags))
{
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);
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/HLSLCC_FLAG_INOUT_APPEND_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|HLSLCC_FLAG_INOUT_APPEND_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;
const char* OutputName = GetDeclaredOutputName(psContext, psShader->eShaderType, psOperand, &stream);
GetOutputSignatureFromRegister(
psContext->currentPhase,
psOperand->ui32RegisterNumber,
psOperand->ui32CompMask,
0,
&psShader->sInfo,
&psSignature);
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions, psContext->flags))
{
if (!((psShader->eShaderType == VERTEX_SHADER) && (psContext->flags & HLSLCC_FLAG_DISABLE_EXPLICIT_LOCATIONS)))
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->currentShaderString = &psContext->postShaderCode[psContext->currentPhase];
glsl = *psContext->currentShaderString;
bcatcstr(glsl, OutputName);
AddSwizzleUsingElementCount(psContext, GetNumSwizzleElements(psOperand));
bformata(glsl, " = Output%d", psOperand->ui32RegisterNumber);
TranslateOperandSwizzle(psContext, psOperand);
bcatcstr(glsl, ";\n");
psContext->currentShaderString = &psContext->mainShader;
glsl = *psContext->currentShaderString;
}
}
}
void DeclareUBOConstants(HLSLCrossCompilerContext* psContext, const uint32_t ui32BindingPoint,
ConstantBuffer* psCBuf,
bstring glsl)
{
uint32_t i;
const char* Name = psCBuf->Name;
if(psCBuf->Name[0] == '$') //For $Globals
{
Name++;
}
for(i=0; i < psCBuf->ui32NumVars; ++i)
{
PreDeclareStructType(glsl,
psCBuf->asVars[i].Name,
&psCBuf->asVars[i].sType);
}
/* [layout (location = X)] uniform vec4 HLSLConstantBufferName[numConsts]; */
if (HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage, psContext->psShader->extensions, psContext->flags))
bformata(glsl, "layout(binding = %d) ", ui32BindingPoint);
bformata(glsl, "uniform %s {\n ", Name);
for(i=0; i < psCBuf->ui32NumVars; ++i)
{
DeclareConstBufferShaderVariable(glsl,
psCBuf->asVars[i].Name,
&psCBuf->asVars[i].sType, 0);
}
bcatcstr(glsl, "};\n");
}
void DeclareBufferVariable(HLSLCrossCompilerContext* psContext, const uint32_t ui32BindingPoint,
ConstantBuffer* psCBuf, const Operand* psOperand,
const uint32_t ui32GloballyCoherentAccess,
const ResourceType eResourceType,
bstring glsl)
{
bstring StructName;
#if defined(_DEBUG)
uint32_t unnamed_struct =
#endif
strcmp(psCBuf->asVars[0].Name, "$Element") == 0 ? 1 : 0;
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
{
ResourceName(StructName, psContext, RGROUP_UAV, psOperand->ui32RegisterNumber, 0);
}
PreDeclareStructType(glsl,
bstr2cstr(StructName, '\0'),
&psCBuf->asVars[0].sType);
/* [layout (location = X)] uniform vec4 HLSLConstantBufferName[numConsts]; */
if (HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage, psContext->psShader->extensions, psContext->flags))
bformata(glsl, "layout(binding = %d) ", ui32BindingPoint);
if(ui32GloballyCoherentAccess & GLOBALLY_COHERENT_ACCESS)
{
bcatcstr(glsl, "coherent ");
}
if(eResourceType == RTYPE_STRUCTURED)
{
bcatcstr(glsl, "readonly ");
}
bformata(glsl, "buffer Block%d {\n", psOperand->ui32RegisterNumber);
DeclareConstBufferShaderVariable(glsl,
bstr2cstr(StructName, '\0'),
&psCBuf->asVars[0].sType,
1);
bcatcstr(glsl, "};\n");
bdestroy(StructName);
}
void DeclareStructConstants(HLSLCrossCompilerContext* psContext, const uint32_t ui32BindingPoint,
ConstantBuffer* psCBuf, const Operand* psOperand,
bstring glsl)
{
uint32_t i;
int useGlobalsStruct = 1;
if(psContext->flags & HLSLCC_FLAG_DISABLE_GLOBALS_STRUCT && psCBuf->Name[0] == '$')
useGlobalsStruct = 0;
if(useGlobalsStruct)
{
for(i=0; i < psCBuf->ui32NumVars; ++i)
{
PreDeclareStructType(glsl,
psCBuf->asVars[i].Name,
&psCBuf->asVars[i].sType);
}
}
/* [layout (location = X)] uniform vec4 HLSLConstantBufferName[numConsts]; */
if (HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage, psContext->psShader->extensions, psContext->flags))
bformata(glsl, "layout(location = %d) ", ui32BindingPoint);
if(useGlobalsStruct)
{
bcatcstr(glsl, "uniform struct ");
TranslateOperand(psContext, psOperand, TO_FLAG_DECLARATION_NAME);
bcatcstr(glsl, "_Type {\n");
}
for(i=0; i < psCBuf->ui32NumVars; ++i)
{
if(!useGlobalsStruct)
bcatcstr(glsl, "uniform ");
DeclareConstBufferShaderVariable(glsl,
psCBuf->asVars[i].Name,
&psCBuf->asVars[i].sType, 0);
}
if(useGlobalsStruct)
{
bcatcstr(glsl, "} ");
TranslateOperand(psContext, psOperand, TO_FLAG_DECLARATION_NAME);
bcatcstr(glsl, ";\n");
}
}
char* GetSamplerType(HLSLCrossCompilerContext* psContext,
const RESOURCE_DIMENSION eDimension,
const uint32_t ui32RegisterNumber)
{
ResourceBinding* psBinding = 0;
RESOURCE_RETURN_TYPE eType = RETURN_TYPE_UNORM;
int found;
found = GetResourceFromBindingPoint(RGROUP_TEXTURE, ui32RegisterNumber, &psContext->psShader->sInfo, &psBinding);
if(found)
{
eType = (RESOURCE_RETURN_TYPE)psBinding->ui32ReturnType;
}
switch(eDimension)
{
case RESOURCE_DIMENSION_BUFFER:
{
switch(eType)
{
case RETURN_TYPE_SINT:
return "isamplerBuffer";
case RETURN_TYPE_UINT:
return "usamplerBuffer";
default:
return "samplerBuffer";
}
break;
}
case RESOURCE_DIMENSION_TEXTURE1D:
{
switch(eType)
{
case RETURN_TYPE_SINT:
return "isampler1D";
case RETURN_TYPE_UINT:
return "usampler1D";
default:
return "sampler1D";
}
break;
}
case RESOURCE_DIMENSION_TEXTURE2D:
{
switch(eType)
{
case RETURN_TYPE_SINT:
return "isampler2D";
case RETURN_TYPE_UINT:
return "usampler2D";
default:
return "sampler2D";
}
break;
}
case RESOURCE_DIMENSION_TEXTURE2DMS:
{
switch(eType)
{
case RETURN_TYPE_SINT:
return "isampler2DMS";
case RETURN_TYPE_UINT:
return "usampler2DMS";
default:
return "sampler2DMS";
}
break;
}
case RESOURCE_DIMENSION_TEXTURE3D:
{
switch(eType)
{
case RETURN_TYPE_SINT:
return "isampler3D";
case RETURN_TYPE_UINT:
return "usampler3D";
default:
return "sampler3D";
}
break;
}
case RESOURCE_DIMENSION_TEXTURECUBE:
{
switch(eType)
{
case RETURN_TYPE_SINT:
return "isamplerCube";
case RETURN_TYPE_UINT:
return "usamplerCube";
default:
return "samplerCube";
}
break;
}
case RESOURCE_DIMENSION_TEXTURE1DARRAY:
{
switch(eType)
{
case RETURN_TYPE_SINT:
return "isampler1DArray";
case RETURN_TYPE_UINT:
return "usampler1DArray";
default:
return "sampler1DArray";
}
break;
}
case RESOURCE_DIMENSION_TEXTURE2DARRAY:
{
switch(eType)
{
case RETURN_TYPE_SINT:
return "isampler2DArray";
case RETURN_TYPE_UINT:
return "usampler2DArray";
default:
return "sampler2DArray";
}
break;
}
case RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
{
switch(eType)
{
case RETURN_TYPE_SINT:
return "isampler2DMSArray";
case RETURN_TYPE_UINT:
return "usampler2DMSArray";
default:
return "sampler2DMSArray";
}
break;
}
case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
{
switch(eType)
{
case RETURN_TYPE_SINT:
return "isamplerCubeArray";
case RETURN_TYPE_UINT:
return "usamplerCubeArray";
default:
return "samplerCubeArray";
}
break;
}
}
return "sampler2D";
}
static void TranslateResourceTexture(HLSLCrossCompilerContext* psContext, const Declaration* psDecl, uint32_t samplerCanDoShadowCmp)
{
bstring glsl = *psContext->currentShaderString;
ShaderData* psShader = psContext->psShader;
uint32_t i;
const char* samplerTypeName = GetSamplerType(psContext,
psDecl->value.eResourceDimension,
psDecl->asOperands[0].ui32RegisterNumber);
if (psContext->flags & HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS)
{
if(samplerCanDoShadowCmp && psDecl->ui32IsShadowTex)
{
for (i = 0; i < psDecl->ui32SamplerUsedCount; i++)
{
bcatcstr(glsl, "uniform ");
bcatcstr(glsl, samplerTypeName);
bcatcstr(glsl, "Shadow ");
ConcatTextureSamplerName(glsl, &psShader->sInfo, psDecl->asOperands[0].ui32RegisterNumber, psDecl->ui32SamplerUsed[i], 1);
bcatcstr(glsl, ";\n");
}
}
for (i = 0; i < psDecl->ui32SamplerUsedCount; i++)
{
bcatcstr(glsl, "uniform ");
bcatcstr(glsl, samplerTypeName);
bcatcstr(glsl, " ");
ConcatTextureSamplerName(glsl, &psShader->sInfo, psDecl->asOperands[0].ui32RegisterNumber, psDecl->ui32SamplerUsed[i], 0);
bcatcstr(glsl, ";\n");
}
}
if(samplerCanDoShadowCmp && psDecl->ui32IsShadowTex)
{
//Create shadow and non-shadow sampler.
//HLSL does not have separate types for depth compare, just different functions.
bcatcstr(glsl, "uniform ");
bcatcstr(glsl, samplerTypeName);
bcatcstr(glsl, "Shadow ");
ResourceName(glsl, psContext, RGROUP_TEXTURE, psDecl->asOperands[0].ui32RegisterNumber, 1);
bcatcstr(glsl, ";\n");
}
bcatcstr(glsl, "uniform ");
bcatcstr(glsl, samplerTypeName);
bcatcstr(glsl, " ");
ResourceName(glsl, psContext, RGROUP_TEXTURE, psDecl->asOperands[0].ui32RegisterNumber, 0);
bcatcstr(glsl, ";\n");
}
void TranslateDeclaration(HLSLCrossCompilerContext* psContext, const Declaration* psDecl)
{
bstring glsl = *psContext->currentShaderString;
ShaderData* psShader = psContext->psShader;
switch(psDecl->eOpcode)
{
case OPCODE_DCL_INPUT_SGV:
case OPCODE_DCL_INPUT_PS_SGV:
{
const SPECIAL_NAME eSpecialName = psDecl->asOperands[0].eSpecialName;
switch(eSpecialName)
{
case NAME_POSITION:
{
AddBuiltinInput(psContext, psDecl, "gl_Position");
break;
}
case NAME_RENDER_TARGET_ARRAY_INDEX:
{
AddBuiltinInput(psContext, psDecl, "gl_Layer");
break;
}
case NAME_CLIP_DISTANCE:
{
AddBuiltinInput(psContext, psDecl, "gl_ClipDistance");
break;
}
case NAME_VIEWPORT_ARRAY_INDEX:
{
AddBuiltinInput(psContext, psDecl, "gl_ViewportIndex");
break;
}
case NAME_INSTANCE_ID:
{
AddBuiltinInput(psContext, psDecl, "gl_InstanceID");
break;
}
case NAME_IS_FRONT_FACE:
{
/*
Cast to int used because
if(gl_FrontFacing != 0) failed to compiled on Intel HD 4000.
Suggests no implicit conversion for bool<->int.
*/
AddBuiltinInput(psContext, psDecl, "int(gl_FrontFacing)");
break;
}
case NAME_SAMPLE_INDEX:
{
AddBuiltinInput(psContext, psDecl, "gl_SampleID");
break;
}
case NAME_VERTEX_ID:
{
AddBuiltinInput(psContext, psDecl, "gl_VertexID");
break;
}
case NAME_PRIMITIVE_ID:
{
AddBuiltinInput(psContext, psDecl, "gl_PrimitiveID");
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";
const 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) ||
(psOperand->eType == OPERAND_TYPE_INPUT_FORK_INSTANCE_ID))
{
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);
break;
}
case OPCODE_DCL_INPUT_PS_SIV:
{
switch(psDecl->asOperands[0].eSpecialName)
{
case NAME_POSITION:
{
AddBuiltinInput(psContext, psDecl, "gl_FragCoord");
break;
}
}
break;
}
case OPCODE_DCL_INPUT_SIV:
{
break;
}
case OPCODE_DCL_INPUT_PS:
{
const Operand* psOperand = &psDecl->asOperands[0];
int iNumComponents = 4;//GetMaxComponentFromComponentMask(psOperand);
const char* StorageQualifier = "varying";
const char* Precision = "";
const char* InputName = GetDeclaredInputName(psContext, PIXEL_SHADER, psOperand);
const char* Interpolation = "";
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);
break;
}
case OPCODE_DCL_TEMPS:
{
const uint32_t ui32NumTemps = psDecl->value.ui32NumTemps;
if(ui32NumTemps > 0)
{
bformata(glsl, "vec4 Temp[%d];\n", ui32NumTemps);
bformata(glsl, "ivec4 Temp_int[%d];\n", ui32NumTemps);
if(HaveUVec(psShader->eTargetLanguage))
{
bformata(glsl, "uvec4 Temp_uint[%d];\n", ui32NumTemps);
}
if(psShader->fp64)
{
bformata(glsl, "dvec4 Temp_double[%d];\n", ui32NumTemps);
}
}
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, psDest->eType == OPERAND_TYPE_SPECIAL_IMMCONSTINT ? TO_FLAG_INTEGER : TO_AUTO_BITCAST_TO_FLOAT);
bcatcstr(glsl, ";\n");
break;
}
case OPCODE_DCL_CONSTANT_BUFFER:
{
const Operand* psOperand = &psDecl->asOperands[0];
const uint32_t ui32BindingPoint = psOperand->aui32ArraySizes[0];
const char* StageName = "VS";
switch(psContext->psShader->eShaderType)
{
case PIXEL_SHADER:
{
StageName = "PS";
break;
}
case HULL_SHADER:
{
StageName = "HS";
break;
}
case DOMAIN_SHADER:
{
StageName = "DS";
break;
}
case GEOMETRY_SHADER:
{
StageName = "GS";
break;
}
case COMPUTE_SHADER:
{
StageName = "CS";
break;
}
default:
{
break;
}
}
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))
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)
{
bformata(glsl, "layout(std140) uniform %s%s {\n\tvec4 %s%s_data[%d];\n};\n", psCBuf->Name, StageName, psCBuf->Name, StageName, 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, glsl);
}
else
{
DeclareUBOConstants(psContext, ui32BindingPoint, psCBuf, glsl);
}
}
else
{
DeclareStructConstants(psContext, ui32BindingPoint, psCBuf, psOperand, glsl);
}
break;
}
case OPCODE_DCL_RESOURCE:
{
if (HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage, psContext->psShader->extensions, psContext->flags))
{
// Explicit layout bindings are not currently compatible with combined texture samplers. The layout below assumes there is exactly one GLSL sampler
// for each HLSL texture declaration, but when combining textures+samplers, there can be multiple OGL samplers for each HLSL texture declaration.
if((psContext->flags & HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS) != HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS)
{
//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:
{
bformata(glsl, "uniform %s ", GetSamplerType(psContext,
RESOURCE_DIMENSION_BUFFER,
psDecl->asOperands[0].ui32RegisterNumber));
TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
bcatcstr(glsl, ";\n");
break;
}
case RESOURCE_DIMENSION_TEXTURE1D:
{
TranslateResourceTexture(psContext, psDecl, 1);
break;
}
case RESOURCE_DIMENSION_TEXTURE2D:
{
TranslateResourceTexture(psContext, psDecl, 1);
break;
}
case RESOURCE_DIMENSION_TEXTURE2DMS:
{
TranslateResourceTexture(psContext, psDecl, 0);
break;
}
case RESOURCE_DIMENSION_TEXTURE3D:
{
TranslateResourceTexture(psContext, psDecl, 0);
break;
}
case RESOURCE_DIMENSION_TEXTURECUBE:
{
TranslateResourceTexture(psContext, psDecl, 1);
break;
}
case RESOURCE_DIMENSION_TEXTURE1DARRAY:
{
TranslateResourceTexture(psContext, psDecl, 1);
break;
}
case RESOURCE_DIMENSION_TEXTURE2DARRAY:
{
TranslateResourceTexture(psContext, psDecl, 1);
break;
}
case RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
{
TranslateResourceTexture(psContext, psDecl, 0);
break;
}
case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
{
TranslateResourceTexture(psContext, psDecl, 1);
break;
}
}
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;
if(ui32Flags & GLOBAL_FLAG_FORCE_EARLY_DEPTH_STENCIL)
{
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->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;
float x, y, z, w;
//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)
{
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 < ui32NumVec4Minus1; ui32ConstIndex++)
{
float loopLocalX, loopLocalY, loopLocalZ, loopLocalW;
loopLocalX = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].a;
loopLocalY = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].b;
loopLocalZ = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].c;
loopLocalW = *(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(loopLocalX))
{
loopLocalX = 0;
}
if(fpcheck(loopLocalY))
{
loopLocalY = 0;
}
if(fpcheck(loopLocalZ))
{
loopLocalZ = 0;
}
if(fpcheck(loopLocalW))
{
loopLocalW = 0;
}
bformata(glsl, "\tvec4(%f, %f, %f, %f), \n", loopLocalX, loopLocalY, loopLocalZ, loopLocalW);
}
//No trailing comma on this one
x = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].a;
y = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].b;
z = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].c;
w = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].d;
if(fpcheck(x))
{
x = 0;
}
if(fpcheck(y))
{
y = 0;
}
if(fpcheck(z))
{
z = 0;
}
if(fpcheck(w))
{
w = 0;
}
bformata(glsl, "\tvec4(%f, %f, %f, %f)\n", x, y, z, w);
bcatcstr(glsl, ");\n");
}
else
{
bcatcstr(glsl, "#define immediateConstBufferI(idx) immediateConstBufferInt[idx]\n");
bcatcstr(glsl, "#define immediateConstBufferF(idx) intBitsToFloat(immediateConstBufferInt[idx])\n");
}
{
uint32_t ui32ConstIndex2 = 0;
int x2, y2, z2, w2;
bformata(glsl, "ivec4 immediateConstBufferInt[%d] = ivec4[%d] (\n", ui32NumVec4, ui32NumVec4);
for (; ui32ConstIndex2 < ui32NumVec4Minus1; ui32ConstIndex2++)
{
int loopLocalX, loopLocalY, loopLocalZ, loopLocalW;
loopLocalX = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex2].a;
loopLocalY = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex2].b;
loopLocalZ = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex2].c;
loopLocalW = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex2].d;
bformata(glsl, "\tivec4(%d, %d, %d, %d), \n", loopLocalX, loopLocalY, loopLocalZ, loopLocalW);
}
//No trailing comma on this one
x2 = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex2].a;
y2 = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex2].b;
z2 = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex2].c;
w2 = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex2].d;
bformata(glsl, "\tivec4(%d, %d, %d, %d)\n", x2, y2, z2, w2);
bcatcstr(glsl, ");\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:
{
// non-float images need either 'i' or 'u' prefix.
char imageTypePrefix[2] = { 0, 0 };
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) ");
imageTypePrefix[0] = 'u';
break;
case RETURN_TYPE_SINT:
bcatcstr(glsl, "layout(rgba32i) ");
imageTypePrefix[0] = 'i';
break;
default:
ASSERT(0);
}
}
switch(psDecl->value.eResourceDimension)
{
case RESOURCE_DIMENSION_BUFFER:
{
bformata(glsl, "uniform %simageBuffer ", imageTypePrefix);
break;
}
case RESOURCE_DIMENSION_TEXTURE1D:
{
bformata(glsl, "uniform %simage1D ", imageTypePrefix);
break;
}
case RESOURCE_DIMENSION_TEXTURE2D:
{
bformata(glsl, "uniform %simage2D ", imageTypePrefix);
break;
}
case RESOURCE_DIMENSION_TEXTURE2DMS:
{
bformata(glsl, "uniform %simage2DMS ", imageTypePrefix);
break;
}
case RESOURCE_DIMENSION_TEXTURE3D:
{
bformata(glsl, "uniform %simage3D ", imageTypePrefix);
break;
}
case RESOURCE_DIMENSION_TEXTURECUBE:
{
bformata(glsl, "uniform %simageCube ", imageTypePrefix);
break;
}
case RESOURCE_DIMENSION_TEXTURE1DARRAY:
{
bformata(glsl, "uniform %simage1DArray ", imageTypePrefix);
break;
}
case RESOURCE_DIMENSION_TEXTURE2DARRAY:
{
bformata(glsl, "uniform %simage2DArray ", imageTypePrefix);
break;
}
case RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
{
bformata(glsl, "uniform %simage3DArray ", imageTypePrefix);
break;
}
case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
{
bformata(glsl, "uniform %simageCubeArray ", imageTypePrefix);
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 ");
ResourceName(glsl, psContext, RGROUP_UAV, psDecl->asOperands[0].ui32RegisterNumber, 0);
bformata(glsl, "_counter; \n");
}
GetConstantBufferFromBindingPoint(RGROUP_UAV, ui32BindingPoint, &psContext->psShader->sInfo, &psCBuf);
DeclareBufferVariable(psContext, ui32BindingPoint, psCBuf, &psDecl->asOperands[0],
psDecl->sUAV.ui32GloballyCoherentAccess, RTYPE_UAV_RWSTRUCTURED, glsl);
break;
}
case OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW:
{
if(psDecl->sUAV.bCounter)
{
bformata(glsl, "layout (binding = 1) uniform atomic_uint ");
ResourceName(glsl, psContext, RGROUP_UAV, psDecl->asOperands[0].ui32RegisterNumber, 0);
bformata(glsl, "_counter; \n");
}
bformata(glsl, "buffer Block%d {\n\tuint ", psDecl->asOperands[0].ui32RegisterNumber);
ResourceName(glsl, psContext, RGROUP_UAV, psDecl->asOperands[0].ui32RegisterNumber, 0);
bcatcstr(glsl, "[];\n};\n");
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, glsl);
break;
}
case OPCODE_DCL_RESOURCE_RAW:
{
bformata(glsl, "buffer Block%d {\n\tuint RawRes%d[];\n};\n", psDecl->asOperands[0].ui32RegisterNumber, psDecl->asOperands[0].ui32RegisterNumber);
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;
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(ShaderData* psShader)
{
uint32_t i, k;
uint32_t ui32Phase, ui32Instance;
const uint32_t ui32NumDeclLists = psShader->asPhase[HS_FORK_PHASE].ui32InstanceCount +
psShader->asPhase[HS_CTRL_POINT_PHASE].ui32InstanceCount +
psShader->asPhase[HS_JOIN_PHASE].ui32InstanceCount +
psShader->asPhase[HS_GLOBAL_DECL].ui32InstanceCount;
Declaration** pasDeclArray = hlslcc_malloc(sizeof(Declaration*) * ui32NumDeclLists);
uint32_t* pui32DeclCounts = hlslcc_malloc(sizeof(uint32_t) * ui32NumDeclLists);
uint32_t ui32NumTemps = 0;
i=0;
for(ui32Phase = HS_GLOBAL_DECL; ui32Phase < NUM_PHASES; ui32Phase++)
{
for(ui32Instance = 0; ui32Instance < psShader->asPhase[ui32Phase].ui32InstanceCount; ++ui32Instance)
{
pasDeclArray[i] = psShader->asPhase[ui32Phase].ppsDecl[ui32Instance];
pui32DeclCounts[i++] = psShader->asPhase[ui32Phase].pui32DeclCount[ui32Instance];
}
}
for(k = 0; k < ui32NumDeclLists; ++k)
{
for(i=0; i < pui32DeclCounts[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 < pui32DeclCounts[k]; ++i)
{
Declaration* psDecl = pasDeclArray[k]+i;
if(psDecl->eOpcode == OPCODE_DCL_TEMPS)
{
psDecl->value.ui32NumTemps = ui32NumTemps;
return;
}
}
}
hlslcc_free(pasDeclArray);
hlslcc_free(pui32DeclCounts);
}