Collection of updates from Unity internal repo at changeset 17a9acd02335496aff4e2eec1b2685085c9b5b0d

This commit is contained in:
Mikko Strandborg 2017-03-21 15:40:07 +02:00
parent d8176fd55a
commit 5f8fc43675
28 changed files with 1341 additions and 374 deletions

View File

@ -43,7 +43,9 @@ typedef struct GlExtensions {
uint32_t ARB_explicit_attrib_location : 1;
uint32_t ARB_explicit_uniform_location : 1;
uint32_t ARB_shading_language_420pack : 1;
}GlExtensions;
uint32_t OVR_multiview : 1;
uint32_t EXT_shader_framebuffer_fetch : 1;
} GlExtensions;
#include "ShaderInfo.h"
@ -197,13 +199,17 @@ private:
}
}
typedef std::map<std::string, uint32_t> SpecializationConstantMap;
SpecializationConstantMap m_SpecConstantMap;
uint32_t m_NextSpecID;
public:
GLSLCrossDependencyData()
: eTessPartitioning(),
eTessOutPrim(),
ui32ProgramStages(0)
ui32ProgramStages(0),
m_ExtBlendModes(),
m_NextSpecID(0)
{
memset(nextAvailableVaryingLocation, 0, sizeof(nextAvailableVaryingLocation));
memset(m_NextAvailableVulkanResourceBinding, 0, sizeof(m_NextAvailableVulkanResourceBinding));
@ -288,6 +294,8 @@ public:
// Bitfield for the shader stages this program is going to include (see PS_FLAG_*).
// Needed so we can construct proper shader input and output names
uint32_t ui32ProgramStages;
std::vector<std::string> m_ExtBlendModes; // The blend modes (from KHR_blend_equation_advanced) requested for this shader. See ext spec for list.
inline INTERPOLATION_MODE GetInterpolationMode(uint32_t regNo)
{
@ -313,9 +321,21 @@ public:
varyingLocationsMap[i].clear();
nextAvailableVaryingLocation[i] = 0;
}
m_NextSpecID = 0;
m_SpecConstantMap.clear();
}
// Retrieve or allocate a layout slot for Vulkan specialization constant
inline uint32_t GetSpecializationConstantSlot(const std::string &name)
{
SpecializationConstantMap::iterator itr = m_SpecConstantMap.find(name);
if (itr != m_SpecConstantMap.end())
return itr->second;
m_SpecConstantMap.insert(std::make_pair(std::string(name), m_NextSpecID));
return m_NextSpecID++;
}
};
struct GLSLShader
@ -339,16 +359,17 @@ public:
virtual void OnInputBinding(const std::string &name, int bindIndex) {}
// Returns false if this constant buffer is not needed for this shader. This info can be used for pruning unused
// constant buffers and vars from compute shaders where we need broader context than a single kernel to know
// if something can be dropped, as the constant buffers are shared between all kernels in a .compute file.
virtual bool OnConstantBuffer(const std::string &name, size_t bufferSize, size_t memberCount) { return true; }
// Returns false if this constant var is not needed for this shader. See above.
virtual bool OnConstant(const std::string &name, int bindIndex, SHADER_VARIABLE_TYPE cType, int rows, int cols, bool isMatrix, int arraySize) { return true; }
virtual void OnConstantBufferBinding(const std::string &name, int bindIndex) {}
virtual void OnTextureBinding(const std::string &name, int bindIndex, HLSLCC_TEX_DIMENSION dim, bool isUAV) {}
virtual void OnTextureBinding(const std::string &name, int bindIndex, int samplerIndex, HLSLCC_TEX_DIMENSION dim, bool isUAV) {}
virtual void OnBufferBinding(const std::string &name, int bindIndex, bool isUAV) {}
virtual void OnThreadGroupSize(unsigned int xSize, unsigned int ySize, unsigned int zSize) {}
};
@ -423,6 +444,16 @@ static const unsigned int HLSLCC_FLAG_VULKAN_BINDINGS = 0x40000;
// If set, metal output will use linear sampler for shadow compares, otherwise point sampler.
static const unsigned int HLSLCC_FLAG_METAL_SHADOW_SAMPLER_LINEAR = 0x80000;
// If set, emits for NVN, the Nvidia-provided graphics API for Nintendo Switch.
static const unsigned int HLSLCC_FLAG_NVN_TARGET = 0x100000;
// If set, and generating Vulkan shaders, attempts to detect static branching and transforms them into specialization constants
static const unsigned int HLSLCC_FLAG_VULKAN_SPECIALIZATION_CONSTANTS = 0x200000;
// If set, this shader uses the GLSL extension EXT_shader_framebuffer_fetch
static const unsigned int HLSLCC_FLAG_SHADER_FRAMEBUFFER_FETCH = 0x400000;
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -250,11 +250,10 @@ void HLSLcc::DataTypeAnalysis::SetDataTypes(HLSLCrossCompilerContext* psContext,
// Only ever to int->float promotion (or int->uint), never the other way around
for (i = 0; i < (uint32_t)instructions.size(); ++i, psInst++)
{
int k = 0;
if (psInst->ui32NumOperands == 0)
continue;
#ifdef _DEBUG
for (k = 0; k < (int)psInst->ui32NumOperands; k++)
for (int k = 0; k < (int)psInst->ui32NumOperands; k++)
{
if (psInst->asOperands[k].eType == OPERAND_TYPE_TEMP)
{

View File

@ -95,6 +95,14 @@ void HLSLCrossCompilerContext::AddIndentation()
}
}
void HLSLCrossCompilerContext::RequireExtension(const std::string &extName)
{
if (m_EnabledExtensions.find(extName) != m_EnabledExtensions.end())
return;
m_EnabledExtensions.insert(extName);
bformata(extensions, "#extension %s : require\n", extName.c_str());
}
std::string HLSLCrossCompilerContext::GetDeclaredInputName(const Operand* psOperand, int *piRebase, int iIgnoreRedirect, uint32_t *puiIgnoreSwizzle) const
{
@ -186,7 +194,13 @@ std::string HLSLCrossCompilerContext::GetDeclaredOutputName(const Operand* psOpe
std::string res = "";
if (psTranslator->TranslateSystemValue(psOperand, psOut, res, puiIgnoreSwizzle, psShader->aIndexedOutput[regSpace][psOperand->ui32RegisterNumber], false))
{
if (psShader->eTargetLanguage == LANG_METAL && (iIgnoreRedirect == 0))
// HACK: i couldnt find better way to handle it
// clip planes will always have interim variable, as HLSL operates on float4 but we need to size output accordingly with actual planes count
// for some reason TranslateSystemValue return *outSkipPrefix = true for ALL system vars and then we simply ignore it here
const bool isClipPlanes = psOut && psOut->eSystemValueType == NAME_CLIP_DISTANCE;
if (psShader->eTargetLanguage == LANG_METAL && (iIgnoreRedirect == 0) && !isClipPlanes)
return outputPrefix + res;
else
return res;
@ -247,8 +261,15 @@ bool HLSLCrossCompilerContext::OutputNeedsDeclaring(const Operand* psOperand, co
{
psShader->acOutputDeclared[regSpace][startIndex + offset] |= compMask;
}
if (psSignature && (psSignature->semanticName == "PSIZE") && (psShader->eTargetLanguage != LANG_METAL))
{
// gl_PointSize, doesn't need declaring. TODO: Metal doesn't have pointsize at all?
return false;
}
return true;
}
return false;
}
}

View File

@ -402,11 +402,13 @@ namespace HLSLcc
case RESOURCE_DIMENSION_TEXTURE1D:
return 1;
case RESOURCE_DIMENSION_TEXTURE2D:
case RESOURCE_DIMENSION_TEXTURE2DMS:
case RESOURCE_DIMENSION_TEXTURE1DARRAY:
case RESOURCE_DIMENSION_TEXTURECUBE:
return 2;
case RESOURCE_DIMENSION_TEXTURE3D:
case RESOURCE_DIMENSION_TEXTURE2DARRAY:
case RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
return 3;
default:

View File

@ -123,10 +123,17 @@ static Operand *GetSrcSwizzleOperand(Instruction *psInst)
case OPCODE_LD_STRUCTURED:
return &psInst->asOperands[3];
case OPCODE_SAMPLE_INFO:
return &psInst->asOperands[1];
case OPCODE_ISHL:
case OPCODE_ISHR:
case OPCODE_USHR:
return &psInst->asOperands[1];
// sm4 variant has single component selection on src1 -> only src0 has swizzle
if (psInst->asOperands[2].eSelMode == OPERAND_4_COMPONENT_SELECT_1_MODE)
return &psInst->asOperands[1];
else // whereas sm5 variant has swizzle also on src1
return NULL;
default:
ASSERT(0);

View File

@ -274,7 +274,7 @@ SHADER_VARIABLE_TYPE Operand::GetDataType(HLSLCrossCompilerContext* psContext, S
{
case OPERAND_TYPE_TEMP:
{
SHADER_VARIABLE_TYPE eCurrentType;
SHADER_VARIABLE_TYPE eCurrentType = SVT_FLOAT;
int i = 0;
if (eSelMode == OPERAND_4_COMPONENT_SELECT_1_MODE)

View File

@ -861,6 +861,7 @@ void ShaderPhase::ExpandSWAPCs()
swapItr->eOpcode = OPCODE_MOVC;
swapItr->ui32NumOperands = 4;
swapItr->ui32FirstSrc = 1;
swapItr->asOperands[0] = origSwapInst.asOperands[0];
swapItr->asOperands[0].eType = OPERAND_TYPE_TEMP;
swapItr->asOperands[0].ui32RegisterNumber = extraTemp;
// mask is already fine
@ -923,19 +924,18 @@ void Shader::ForcePositionToHighp()
{
if (decl.eOpcode == OPCODE_DCL_OUTPUT_SIV)
{
if (decl.asOperands[0].eSpecialName == NAME_POSITION)
return true;
if (decl.asOperands[0].eSpecialName != NAME_UNDEFINED)
return false;
// This might be SV_Position (because d3dcompiler is weird). Get signature and check
const ShaderInfo::InOutSignature *sig = NULL;
sInfo.GetOutputSignatureFromRegister(decl.asOperands[0].ui32RegisterNumber, decl.asOperands[0].GetAccessMask(), 0, &sig);
ASSERT(sig != NULL);
if ((sig->eSystemValueType == NAME_POSITION || sig->semanticName == "POS") && sig->ui32SemanticIndex == 0)
const SPECIAL_NAME specialName = decl.asOperands[0].eSpecialName;
if (specialName == NAME_POSITION ||
specialName == NAME_UNDEFINED) // This might be SV_Position (because d3dcompiler is weird).
{
((ShaderInfo::InOutSignature *)sig)->eMinPrec = MIN_PRECISION_DEFAULT;
return true;
const ShaderInfo::InOutSignature *sig = NULL;
sInfo.GetOutputSignatureFromRegister(decl.asOperands[0].ui32RegisterNumber, decl.asOperands[0].GetAccessMask(), 0, &sig);
ASSERT(sig != NULL);
if ((sig->eSystemValueType == NAME_POSITION || sig->semanticName == "POS") && sig->ui32SemanticIndex == 0)
{
((ShaderInfo::InOutSignature *)sig)->eMinPrec = MIN_PRECISION_DEFAULT;
return true;
}
}
return false;
}

View File

@ -145,10 +145,6 @@ static DefineUseChainEntry *GetOrCreateDefinition(const BasicBlock::Definition &
// Do flow control analysis on the instructions and build the define-use and use-define chains
void BuildUseDefineChains(std::vector<Instruction> &instructions, uint32_t ui32NumTemps, DefineUseChains &psDUChain, UseDefineChains &psUDChain, HLSLcc::ControlFlow::ControlFlowGraph &cfg)
{
Instruction *psFirstInstruction = &instructions[0];
Instruction *psLastInstruction = &instructions[instructions.size() - 1];
ActiveDefinitions lastSeenDefinitions(ui32NumTemps * 4, NULL); // Array of pointers to the currently active definition for each temp
psDUChain.clear();

View File

@ -193,10 +193,6 @@ int i, l, c;
}
static size_t readNothing (void *buff, size_t elsize, size_t nelem, void *parm) {
buff = buff;
elsize = elsize;
nelem = nelem;
parm = parm;
return 0; /* Immediately indicate EOF. */
}

View File

@ -178,7 +178,7 @@ static void MarkTextureSamplerPair(ShaderInfo* psShaderInfo, std::vector<Declara
// set::insert returns a pair of which .second tells whether a new element was actually added
if (psDecl->samplersUsed.insert(psSamplerOperand->ui32RegisterNumber).second)
{
// Record the texturename_X_samplername string in the TextureSamplerPair array that we return to the client
// Record the <texturename>TEX_with_SMP<samplername> string in the TextureSamplerPair array that we return to the client
std::string combinedname = TextureSamplerName(psShaderInfo, psTextureOperand->ui32RegisterNumber, psSamplerOperand->ui32RegisterNumber, psDecl->ui32IsShadowTex);
samplers.push_back(combinedname);
}
@ -1112,7 +1112,7 @@ const uint32_t* DecodeInstruction(const uint32_t* pui32Token, Instruction* psIns
{
psInst->ui32NumOperands = 4;
if(eOpcode == OPCODE_IMUL)
if(eOpcode == OPCODE_IMUL || eOpcode == OPCODE_UDIV)
{
psInst->ui32FirstSrc = 2;
}
@ -1244,6 +1244,16 @@ const uint32_t* DecodeInstruction(const uint32_t* pui32Token, Instruction* psIns
ui32OperandOffset += DecodeOperand(pui32Token+ui32OperandOffset, &psInst->asOperands[2]);
break;
}
case OPCODE_SAMPLE_INFO:
{
psInst->ui32NumOperands = 2;
psInst->eResInfoReturnType = DecodeResInfoReturnType(pui32Token[0]);
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[0]);
ui32OperandOffset += DecodeOperand(pui32Token + ui32OperandOffset, &psInst->asOperands[1]);
break;
}
case OPCODE_MSAD:
default:
{
@ -1254,8 +1264,8 @@ const uint32_t* DecodeInstruction(const uint32_t* pui32Token, Instruction* psIns
// For opcodes that sample textures, mark which samplers are used by each texture
{
uint32_t ui32TextureRegisterNumber;
uint32_t ui32SamplerRegisterNumber;
uint32_t ui32TextureRegisterNumber = 0;
uint32_t ui32SamplerRegisterNumber = 0;
uint32_t bTextureSampleInstruction = 0;
switch (eOpcode)
{

View File

@ -2,6 +2,7 @@
#include <stdint.h>
#include <string>
#include <set>
#include "bstrlib.h"
class Shader;
@ -47,4 +48,8 @@ public:
bool OutputNeedsDeclaring(const Operand* psOperand, const int count);
void RequireExtension(const std::string &extName);
private:
std::set<std::string> m_EnabledExtensions;
};

View File

@ -3,6 +3,7 @@
#include "bstrlib.h"
#include <vector>
#include <string>
#include <algorithm>
#include "internal_includes/Instruction.h"
#include "internal_includes/Operand.h"

View File

@ -30,6 +30,8 @@ struct Instruction
, m_SkipTranslation(false)
, m_InductorRegister(0)
, bSaturate(0)
, m_IsStaticBranch(false)
, m_StaticBranchCondition(NULL)
{
m_LoopInductors[0] = m_LoopInductors[1] = m_LoopInductors[2] = m_LoopInductors[3] = 0;
}
@ -85,6 +87,20 @@ struct Instruction
asOperands[3].eSelMode = OPERAND_4_COMPONENT_MASK_MODE;
}
// Returns true if this instruction is a conditional branch
bool IsConditionalBranchInstruction() const
{
switch (eOpcode)
{
case OPCODE_IF:
case OPCODE_BREAKC:
case OPCODE_CONTINUEC:
case OPCODE_RETC:
return true;
default:
return false;
}
}
bool IsPartialPrecisionSamplerInstruction(const ShaderInfo &info, OPERAND_MIN_PRECISION *pType) const;
@ -114,6 +130,10 @@ struct Instruction
RESOURCE_DIMENSION eResDim;
int8_t iCausedSplit; // Nonzero if has caused a temp split. Later used by sampler datatype tweaking
bool m_IsStaticBranch; // If true, this instruction is a static branch
const Instruction *m_StaticBranchCondition; // If this is a static branch, this instruction points to the condition instruction. Can also be NULL if the operand itself is the condition
std::string m_StaticBranchName; // The name of the static branch variable, with the condition encoded in it.
struct Use
{
Use() : m_Inst(0), m_Op(0) {}

View File

@ -104,6 +104,9 @@ public:
uint32_t m_NextFreeTempRegister; // A counter for creating new temporaries for for-loops.
uint32_t m_NextTexCoordTemp; // A counter for creating tex coord temps for driver issue workarounds
// Instructions that are static branches (branches based on constant buffer values only)
std::vector<Instruction *> m_StaticBranchInstructions;
private:
bool m_CFGInitialized;
HLSLcc::ControlFlow::ControlFlowGraph m_CFG;
@ -142,10 +145,7 @@ public:
ui32CurrentVertexOutputStream(0),
textureSamplers(),
aui32StructuredBufferBindingPoints(MAX_RESOURCE_BINDINGS, 0),
ui32CurrentStructuredBufferIndex(),
m_CubemapArrayExtensionDeclared(false),
m_TextureBufferExtensionDeclared(false),
m_ClipDistanceExtensionDeclared(false)
ui32CurrentStructuredBufferIndex()
{
}
@ -246,10 +246,6 @@ public:
std::vector<uint32_t> aui32StructuredBufferBindingPoints;
uint32_t ui32CurrentStructuredBufferIndex;
bool m_CubemapArrayExtensionDeclared;
bool m_TextureBufferExtensionDeclared;
bool m_ClipDistanceExtensionDeclared;
std::vector<char> psIntTempSizes; // Array for whether this temp register needs declaration as int temp
std::vector<char> psInt16TempSizes; // min16ints
std::vector<char> psInt12TempSizes; // min12ints

View File

@ -12,7 +12,9 @@ static void CustomAssert(int expression)
}
}
#else
#define ASSERT(expr)
#define UNUSED(EXPR_) \
do { if (false) (void)(EXPR_); } while(0)
#define ASSERT(expr) UNUSED(expr)
#endif
#endif

View File

@ -2,6 +2,8 @@
#define LANGUAGES_H
#include "hlslcc.h"
#include "HLSLCrossCompilerContext.h"
#include "Shader.h"
static int InOutSupported(const GLLang eLang)
{
@ -42,9 +44,13 @@ static int HaveOverloadedTextureFuncs(const GLLang eLang)
}
//Only enable for ES.
//Not present in 120, ignored in other desktop languages.
static int HavePrecisionQualifers(const GLLang eLang)
//Not present in 120, ignored in other desktop languages. Specifically enabled on Vulkan.
static int HavePrecisionQualifiers(const HLSLCrossCompilerContext *psContext)
{
if ((psContext->flags & HLSLCC_FLAG_VULKAN_BINDINGS) != 0)
return 1;
const GLLang eLang = psContext->psShader->eTargetLanguage;
if(eLang >= LANG_ES_100 && eLang <= LANG_ES_310)
{
return 1;

View File

@ -20,10 +20,17 @@ public:
virtual void SetIOPrefixes();
private:
// Vulkan-only: detect which branches only depend on uniforms and immediate values and can be turned into specialization constants.
void IdentifyStaticBranches(ShaderPhase *psPhase);
void BuildStaticBranchNameForInstruction(Instruction &inst);
void DeclareSpecializationConstants(ShaderPhase &phase);
void TranslateOperand(bstring glsl, const Operand *psOp, uint32_t flags, uint32_t ui32ComponentMask = OPERAND_4_COMPONENT_MASK_ALL);
void TranslateOperand(const Operand *psOp, uint32_t flags, uint32_t ui32ComponentMask = OPERAND_4_COMPONENT_MASK_ALL);
void TranslateInstruction(Instruction* psInst, bool isEmbedded = false);
void TranslateVariableNameWithMask(bstring glsl, const Operand* psOperand, uint32_t ui32TOFlag, uint32_t* pui32IgnoreSwizzle, uint32_t ui32CompMask, int *piRebase);
void TranslateVariableNameWithMask(const Operand* psOperand, uint32_t ui32TOFlag, uint32_t* pui32IgnoreSwizzle, uint32_t ui32CompMask, int *piRebase);
void TranslateOperandIndex(const Operand* psOperand, int index);

View File

@ -12,6 +12,7 @@ class HLSLCrossCompilerContext;
//void TranslateOperandWithMask(HLSLCrossCompilerContext* psContext, const Operand* psOperand, uint32_t ui32TOFlag, uint32_t ui32ComponentMask);
void TranslateOperandSwizzle(HLSLCrossCompilerContext* psContext, const Operand* psOperand, int iRebase);
void TranslateOperandSwizzleWithMask(bstring glsl, HLSLCrossCompilerContext* psContext, const Operand* psOperand, uint32_t ui32ComponentMask, int iRebase);
void TranslateOperandSwizzleWithMask(HLSLCrossCompilerContext* psContext, const Operand* psOperand, uint32_t ui32ComponentMask, int iRebase);
void ResourceName(bstring targetStr, HLSLCrossCompilerContext* psContext, ResourceGroup group, const uint32_t ui32RegisterNumber, const int bZCompare);

View File

@ -26,7 +26,11 @@ class BindingSlotAllocator
typedef std::map<uint32_t, uint32_t> SlotMap;
SlotMap m_Allocations;
public:
BindingSlotAllocator() : m_Allocations(), m_NextFreeSlot(0) {}
BindingSlotAllocator() : m_Allocations()
{
for(int i = MAX_RESOURCE_BINDINGS-1; i >= 0; i --)
m_FreeSlots.push_back(i);
}
enum BindType
{
@ -36,23 +40,54 @@ public:
UAV
};
// isUAV is only meaningful for texture slots
uint32_t GetBindingSlot(uint32_t regNo, BindType type)
{
// The key is regNumber with the bindtype stored to highest 16 bits
uint32_t key = regNo | (uint32_t(type) << 16);
SlotMap::iterator itr = m_Allocations.find(key);
if (itr == m_Allocations.end())
if(itr == m_Allocations.end())
{
m_Allocations.insert(std::make_pair(key, m_NextFreeSlot));
return m_NextFreeSlot++;
uint32_t slot = m_FreeSlots.back();
m_FreeSlots.pop_back();
m_Allocations.insert(std::make_pair(key, slot));
return slot;
}
return itr->second;
}
// Func for reserving binding slots with the original reg number.
// Used for fragment shader UAVs (SetRandomWriteTarget etc).
void ReserveBindingSlot(uint32_t regNo, BindType type)
{
uint32_t key = regNo | (uint32_t(type) << 16);
m_Allocations.insert(std::make_pair(key, regNo));
// Remove regNo from free slots
for (int i = m_FreeSlots.size() - 1; i >= 0; i--)
{
if (m_FreeSlots[i] == regNo)
{
m_FreeSlots.erase(m_FreeSlots.begin() + i);
return;
}
}
}
private:
uint32_t m_NextFreeSlot;
std::vector<uint32_t> m_FreeSlots;
};
struct SamplerDesc
{
std::string name;
uint32_t reg, slot;
};
struct TextureSamplerDesc
{
std::string name;
int textureBind, samplerBind;
HLSLCC_TEX_DIMENSION dim;
bool uav;
};
@ -61,7 +96,12 @@ class ToMetal : public Translator
protected:
GLLang language;
public:
explicit ToMetal(HLSLCrossCompilerContext *ctx) : Translator(ctx), m_ShadowSamplerDeclared(false) {}
explicit ToMetal(HLSLCrossCompilerContext *ctx)
: Translator(ctx)
, m_ShadowSamplerDeclared(false)
, m_NeedFBOutputRemapDecl(false)
, m_NeedFBInputRemapDecl(false)
{}
virtual bool Translate();
virtual void TranslateDeclaration(const Declaration *psDecl);
@ -75,6 +115,8 @@ private:
void DeclareBuiltinInput(const Declaration *psDecl);
void DeclareBuiltinOutput(const Declaration *psDecl);
void DeclareClipPlanes(const Declaration* decl, unsigned declCount);
void GenerateTexturesReflection(HLSLccReflection* refl);
// Retrieve the name of the output struct for this shader
std::string GetOutputStructName() const;
@ -88,7 +130,7 @@ private:
void DeclareStructType(const std::string &name, const std::vector<ShaderVarType> &contents, bool withinCB = false, uint32_t cumulativeOffset = 0);
void DeclareStructVariable(const std::string &parentName, const ShaderVar &var, bool withinCB = false, uint32_t cumulativeOffset = 0);
void DeclareStructVariable(const std::string &parentName, const ShaderVarType &var, bool withinCB = false, uint32_t cumulativeOffset = 0);
void DeclareBufferVariable(const Declaration *psDecl, const bool isRaw, const bool isUAV);
void DeclareBufferVariable(const Declaration *psDecl, bool isRaw, bool isUAV);
void DeclareResource(const Declaration *psDecl);
void TranslateResourceTexture(const Declaration* psDecl, uint32_t samplerCanDoShadowCmp, HLSLCC_TEX_DIMENSION texDim);
@ -174,11 +216,18 @@ private:
// A <function name, body text> map of extra helper functions we'll need.
FunctionDefinitions m_FunctionDefinitions;
BindingSlotAllocator m_TextureSlots;
BindingSlotAllocator m_TextureSlots, m_SamplerSlots;
BindingSlotAllocator m_BufferSlots;
std::vector<SamplerDesc> m_Samplers;
std::vector<TextureSamplerDesc> m_Textures;
std::string m_ExtraGlobalDefinitions;
// Flags for whether we need to add the declaration for the FB IO remaps
bool m_NeedFBInputRemapDecl;
bool m_NeedFBOutputRemapDecl;
bool m_ShadowSamplerDeclared;
void EnsureShadowSamplerDeclared();
@ -188,6 +237,9 @@ private:
// Move all lowp -> mediump
void ClampPartialPrecisions();
// Reseve UAV slots in advance to match the original HLSL bindings -> correct bindings in SetRandomWriteTarget()
void ReserveUAVBindingSlots(ShaderPhase *phase);
};

View File

@ -306,7 +306,6 @@ static const uint32_t* ReadConstantBuffer(ShaderInfo* psShaderInfo,
//D3D11_SHADER_VARIABLE_DESC
ShaderVar * const psVar = &psBuffer->asVars[i];
uint32_t ui32Flags;
uint32_t ui32TypeOffset;
uint32_t ui32DefaultValueOffset;
@ -317,7 +316,10 @@ static const uint32_t* ReadConstantBuffer(ShaderInfo* psShaderInfo,
psVar->ui32StartOffset = *pui32VarToken++;
psVar->ui32Size = *pui32VarToken++;
ui32Flags = *pui32VarToken++;
//skip ui32Flags
pui32VarToken++;
ui32TypeOffset = *pui32VarToken++;
psVar->sType.name = psVar->name;
@ -367,12 +369,12 @@ static const uint32_t* ReadConstantBuffer(ShaderInfo* psShaderInfo,
{
uint32_t ui32Flags;
uint32_t ui32BufferType;
psBuffer->ui32TotalSizeInBytes = *pui32Tokens++;
ui32Flags = *pui32Tokens++;
ui32BufferType = *pui32Tokens++;
//skip ui32Flags
pui32Tokens++;
//skip ui32BufferType
pui32Tokens++;
}
return pui32Tokens;

View File

@ -58,20 +58,20 @@ void ToGLSL::SetIOPrefixes()
case PIXEL_SHADER:
// The inputs can come from geom shader, domain shader or directly from vertex shader
if (psContext->psDependencies)
{
{
if (psContext->psDependencies->ui32ProgramStages & PS_FLAG_GEOMETRY_SHADER)
{
{
psContext->inputPrefix = "gs_";
}
}
else if (psContext->psDependencies->ui32ProgramStages & PS_FLAG_DOMAIN_SHADER)
{
psContext->inputPrefix = "ds_";
}
}
else
{
{
psContext->inputPrefix = "vs_";
}
}
}
}
else
{
psContext->inputPrefix = "vs_";
@ -95,6 +95,7 @@ static void AddVersionDependentCode(HLSLCrossCompilerContext* psContext)
bstring glsl = *psContext->currentGLSLString;
bstring extensions = psContext->extensions;
bool isES = (psContext->psShader->eTargetLanguage >= LANG_ES_100 && psContext->psShader->eTargetLanguage <= LANG_ES_310);
bool GL_ARB_shader_storage_buffer_object = false;
bool GL_ARB_shader_image_load_store = false;
if(psContext->psShader->ui32MajorVersion > 3 && psContext->psShader->eTargetLanguage != LANG_ES_300 && psContext->psShader->eTargetLanguage != LANG_ES_310 && !(psContext->psShader->eTargetLanguage >= LANG_330))
@ -114,7 +115,7 @@ static void AddVersionDependentCode(HLSLCrossCompilerContext* psContext)
psContext->psShader->aiOpcodeUsed[OPCODE_DCL_RESOURCE_STRUCTURED] ||
psContext->psShader->aiOpcodeUsed[OPCODE_DCL_RESOURCE_RAW])
{
bcatcstr(extensions, "#extension GL_ARB_shader_storage_buffer_object : enable\n");
GL_ARB_shader_storage_buffer_object = true;
}
}
@ -129,25 +130,28 @@ static void AddVersionDependentCode(HLSLCrossCompilerContext* psContext)
}
}
if (!HaveImageAtomics(psContext->psShader->eTargetLanguage))
if (psContext->psShader->aiOpcodeUsed[OPCODE_ATOMIC_CMP_STORE] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_AND] ||
psContext->psShader->aiOpcodeUsed[OPCODE_ATOMIC_AND] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_IADD] ||
psContext->psShader->aiOpcodeUsed[OPCODE_ATOMIC_IADD] ||
psContext->psShader->aiOpcodeUsed[OPCODE_ATOMIC_OR] ||
psContext->psShader->aiOpcodeUsed[OPCODE_ATOMIC_XOR] ||
psContext->psShader->aiOpcodeUsed[OPCODE_ATOMIC_IMIN] ||
psContext->psShader->aiOpcodeUsed[OPCODE_ATOMIC_UMIN] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_IMAX] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_IMIN] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_UMAX] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_UMIN] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_OR] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_XOR] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_EXCH] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_CMP_EXCH])
{
if (psContext->psShader->aiOpcodeUsed[OPCODE_ATOMIC_CMP_STORE] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_AND] ||
psContext->psShader->aiOpcodeUsed[OPCODE_ATOMIC_AND] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_IADD] ||
psContext->psShader->aiOpcodeUsed[OPCODE_ATOMIC_IADD] ||
psContext->psShader->aiOpcodeUsed[OPCODE_ATOMIC_OR] ||
psContext->psShader->aiOpcodeUsed[OPCODE_ATOMIC_XOR] ||
psContext->psShader->aiOpcodeUsed[OPCODE_ATOMIC_IMIN] ||
psContext->psShader->aiOpcodeUsed[OPCODE_ATOMIC_UMIN] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_IMAX] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_IMIN] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_UMAX] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_UMIN] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_OR] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_XOR] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_EXCH] ||
psContext->psShader->aiOpcodeUsed[OPCODE_IMM_ATOMIC_CMP_EXCH])
if (!HaveAtomicMem(psContext->psShader->eTargetLanguage))
GL_ARB_shader_storage_buffer_object = true;
if (!HaveImageAtomics(psContext->psShader->eTargetLanguage))
{
if (isES)
bcatcstr(extensions, "#extension GL_OES_shader_image_atomic : enable\n");
@ -189,9 +193,15 @@ static void AddVersionDependentCode(HLSLCrossCompilerContext* psContext)
if(psContext->psShader->aiOpcodeUsed[OPCODE_RESINFO])
{
bcatcstr(extensions,"#extension GL_ARB_texture_query_levels : enable\n");
bcatcstr(extensions, "#extension GL_ARB_shader_image_size : enable\n");
}
}
if (psContext->psShader->aiOpcodeUsed[OPCODE_SAMPLE_INFO ])
{
bcatcstr(extensions, "#extension GL_ARB_shader_texture_image_samples : enable\n");
}
if(!HaveImageLoadStore(psContext->psShader->eTargetLanguage))
{
if(psContext->psShader->aiOpcodeUsed[OPCODE_STORE_UAV_TYPED] ||
@ -236,9 +246,24 @@ static void AddVersionDependentCode(HLSLCrossCompilerContext* psContext)
}
}
if (GL_ARB_shader_storage_buffer_object)
bcatcstr(extensions, "#extension GL_ARB_shader_storage_buffer_object : enable\n");
if (GL_ARB_shader_image_load_store)
bcatcstr(extensions, "#extension GL_ARB_shader_image_load_store : enable\n");
if(psContext->psShader->eShaderType == PIXEL_SHADER && psContext->psShader->eTargetLanguage >= LANG_120 && !HaveFragmentCoordConventions(psContext->psShader->eTargetLanguage))
{
bcatcstr(extensions,"#extension GL_ARB_fragment_coord_conventions : require\n");
}
if (psContext->psShader->extensions->EXT_shader_framebuffer_fetch && psContext->psShader->eShaderType == PIXEL_SHADER && psContext->flags & HLSLCC_FLAG_SHADER_FRAMEBUFFER_FETCH)
{
bcatcstr(extensions, "#ifdef GL_EXT_shader_framebuffer_fetch\n");
bcatcstr(extensions, "#extension GL_EXT_shader_framebuffer_fetch : enable\n");
bcatcstr(extensions, "#endif\n");
}
//Handle fragment shader default precision
if ((psContext->psShader->eShaderType == PIXEL_SHADER) &&
(psContext->psShader->eTargetLanguage == LANG_ES_100 || psContext->psShader->eTargetLanguage == LANG_ES_300 || psContext->psShader->eTargetLanguage == LANG_ES_310))
@ -253,11 +278,6 @@ static void AddVersionDependentCode(HLSLCrossCompilerContext* psContext)
bcatcstr(glsl, "precision highp int;\n");
}
if(psContext->psShader->eShaderType == PIXEL_SHADER && psContext->psShader->eTargetLanguage >= LANG_120 && !HaveFragmentCoordConventions(psContext->psShader->eTargetLanguage))
{
bcatcstr(extensions,"#extension GL_ARB_fragment_coord_conventions : require\n");
}
if(psContext->psShader->eShaderType == PIXEL_SHADER && psContext->psShader->eTargetLanguage >= LANG_150)
{
if(psContext->flags & HLSLCC_FLAG_ORIGIN_UPPER_LEFT)
@ -435,7 +455,7 @@ static void DoHullShaderPassthrough(HLSLCrossCompilerContext *psContext)
outputName = oss.str();
}
const char * prec = HavePrecisionQualifers(psContext->psShader->eTargetLanguage) ? "highp ": "";
const char * prec = HavePrecisionQualifiers(psContext) ? "highp ": "";
psContext->AddIndentation();
if (ui32NumComponents > 1) // TODO Precision
@ -519,6 +539,8 @@ bool ToGLSL::Translate()
if (psShader->extensions)
{
if(psContext->flags & HLSLCC_FLAG_NVN_TARGET)
bcatcstr(extensions, "#extension GL_ARB_separate_shader_objects : enable\n");
if (psShader->extensions->ARB_explicit_attrib_location)
bcatcstr(extensions, "#extension GL_ARB_explicit_attrib_location : require\n");
if (psShader->extensions->ARB_explicit_uniform_location)
@ -531,6 +553,25 @@ bool ToGLSL::Translate()
AddVersionDependentCode(psContext);
if(psShader->eShaderType == VERTEX_SHADER &&
HaveLimitedInOutLocationQualifier(language, psShader->extensions) &&
psContext->flags & HLSLCC_FLAG_NVN_TARGET)
{
bcatcstr(glsl, "out gl_PerVertex { vec4 gl_Position; };\n");
}
if (!psContext->psDependencies->m_ExtBlendModes.empty() && psShader->eShaderType == PIXEL_SHADER)
{
bcatcstr(extensions, "#extension GL_KHR_blend_equation_advanced : enable\n");
bcatcstr(glsl, "#if GL_KHR_blend_equation_advanced\n");
for (i = 0; i < psContext->psDependencies->m_ExtBlendModes.size(); i++)
{
bformata(glsl, "layout(%s) out;\n", psContext->psDependencies->m_ExtBlendModes[i].c_str());
}
bcatcstr(glsl, "#endif\n");
}
psShader->PrepareStructuredBufferBindingSlots();
for (ui32Phase = 0; ui32Phase < psShader->asPhases.size(); ui32Phase++)
@ -541,6 +582,7 @@ bool ToGLSL::Translate()
phase.ResolveUAVProperties();
psShader->ResolveStructuredBufferBindingSlots(&phase);
phase.PruneConstArrays();
}
psShader->PruneTempRegisters();
@ -550,6 +592,12 @@ bool ToGLSL::Translate()
// Loop transform can only be done after the temps have been pruned
ShaderPhase &phase = psShader->asPhases[ui32Phase];
HLSLcc::DoLoopTransform(phase);
if ((psContext->flags & HLSLCC_FLAG_VULKAN_SPECIALIZATION_CONSTANTS) != 0)
{
IdentifyStaticBranches(&phase);
}
}
//Special case. Can have multiple phases.
@ -593,6 +641,12 @@ bool ToGLSL::Translate()
TranslateDeclaration(&psPhase->psDecl[i]);
}
if ((psContext->flags & HLSLCC_FLAG_VULKAN_SPECIALIZATION_CONSTANTS) != 0)
{
DeclareSpecializationConstants(psShader->asPhases[i]);
}
bformata(glsl, "void %s%d(int phaseInstanceID)\n{\n", GetPhaseFuncName(psPhase->ePhase), ui32Phase);
psContext->indent++;
@ -768,6 +822,11 @@ bool ToGLSL::Translate()
TranslateDeclaration(&psShader->asPhases[0].psDecl[i]);
}
if ((psContext->flags & HLSLCC_FLAG_VULKAN_SPECIALIZATION_CONSTANTS) != 0)
{
DeclareSpecializationConstants(psShader->asPhases[0]);
}
bcatcstr(glsl, "void main()\n{\n");
psContext->indent++;
@ -803,4 +862,215 @@ bool ToGLSL::Translate()
return true;
}
void ToGLSL::DeclareSpecializationConstants(ShaderPhase &phase)
{
bstring glsl = psContext->glsl;
// There may be several uses for the same branch condition, so we'll need to keep track of what we've already declared.
std::set<uint32_t> alreadyDeclared;
for (std::vector<Instruction *>::iterator itr = phase.m_StaticBranchInstructions.begin(); itr != phase.m_StaticBranchInstructions.end(); itr++)
{
Instruction &i = **itr;
uint32_t slot = psContext->psDependencies->GetSpecializationConstantSlot(i.m_StaticBranchName);
if(alreadyDeclared.insert(slot).second) // Only declare if the insertion actually succeeded
bformata(glsl, "layout(constant_id = %d) const bool %s = false;\n", slot, i.m_StaticBranchName.c_str());
}
}
std::string to64(uint32_t in)
{
const char to64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
char c_[2];
c_[0] = to64[in];
c_[1] = 0;
char c = c_[0];
if (c == 'X')
return "XX";
if (c == '+')
return "XA";
if (c == '/')
return "XB";
return std::string(c_);
}
// Slightly custom base64, espace non-identifier chars with 'X'
static void Base64Encode(const std::string &in, std::string& result)
{
size_t len = in.length();
size_t outputLen = (len + 2) / 3 * 4;
unsigned char *bytes = (unsigned char *)&in[0];
result.clear();
result.reserve(outputLen);
int i = 0;
unsigned char b1, b2, b3;
for (int chunk = 0; len > 0; len -= 3, chunk++) {
b1 = bytes[i++];
b2 = len > 1 ? bytes[i++] : '\0';
result += to64(b1 >> 2);
result += to64(((b1 & 3) << 4) | ((b2 & 0xf0) >> 4));
if (len > 2)
{
b3 = bytes[i++];
result += to64(((b2 & 0xF) << 2) | ((b3 & 0xC0) >> 6));
result += to64(b3 & 0x3F);
}
else if (len == 2)
{
result += to64((b2 & 0xF) << 2);
result += "XC";
break;
}
else /* len == 1 */
{
result += "XC";
break;
}
}
}
void ToGLSL::BuildStaticBranchNameForInstruction(Instruction &inst)
{
std::ostringstream oss;
if (!inst.m_StaticBranchCondition)
{
// Simple case, just get the value, check if nonzero
bstring varname = bfromcstr("");
SHADER_VARIABLE_TYPE argType = inst.asOperands[0].GetDataType(psContext);
uint32_t flag = TO_FLAG_NONE;
switch (argType)
{
case SVT_BOOL:
flag = TO_FLAG_BOOL;
break;
case SVT_INT:
case SVT_INT12:
case SVT_INT16:
flag = TO_FLAG_INTEGER;
break;
case SVT_UINT:
case SVT_UINT16:
case SVT_UINT8:
flag = TO_FLAG_UNSIGNED_INTEGER;
break;
default:
break;
}
TranslateOperand(varname, &inst.asOperands[0], flag);
char *str = bstr2cstr(varname, '\0');
oss << str;
bcstrfree(str);
bdestroy(varname);
oss << "!=0";
Base64Encode(oss.str(), inst.m_StaticBranchName);
}
else
{
// Indirect, just store the whole previous instruction and then the condition
bstring res = bfromcstr("");
bstring *oldglsl = psContext->currentGLSLString;
psContext->currentGLSLString = &res;
TranslateInstruction((Instruction *)inst.m_StaticBranchCondition, true);
psContext->currentGLSLString = oldglsl;
SHADER_VARIABLE_TYPE argType = inst.asOperands[0].GetDataType(psContext);
uint32_t flag = TO_FLAG_NONE;
switch (argType)
{
case SVT_BOOL:
flag = TO_FLAG_BOOL;
break;
case SVT_INT:
case SVT_INT12:
case SVT_INT16:
flag = TO_FLAG_INTEGER;
break;
case SVT_UINT:
case SVT_UINT16:
case SVT_UINT8:
flag = TO_FLAG_UNSIGNED_INTEGER;
break;
default:
break;
}
if (argType == SVT_BOOL)
{
if (inst.eBooleanTestType == INSTRUCTION_TEST_ZERO)
bcatcstr(res, "!");
}
TranslateOperand(res, &inst.asOperands[0], flag);
char *str = bstr2cstr(res, '\0');
oss << str;
bcstrfree(str);
bdestroy(res);
if(argType != SVT_BOOL)
oss << "!=0";
Base64Encode(oss.str(), inst.m_StaticBranchName);
}
}
void ToGLSL::IdentifyStaticBranches(ShaderPhase *psPhase)
{
for (std::vector<Instruction>::iterator itr = psPhase->psInst.begin(); itr != psPhase->psInst.end(); itr++)
{
Instruction &i = *itr;
if (!i.IsConditionalBranchInstruction())
continue;
// Simple case, direct conditional branch
if (i.asOperands[0].eType == OPERAND_TYPE_CONSTANT_BUFFER)
{
psPhase->m_StaticBranchInstructions.push_back(&i);
i.m_IsStaticBranch = true;
i.m_StaticBranchCondition = NULL;
BuildStaticBranchNameForInstruction(i);
}
// Indirect, comparison via another instruction
if (i.asOperands[0].eType == OPERAND_TYPE_TEMP)
{
// Check that the temp only has one visible definition
if (i.asOperands[0].m_Defines.size() == 1)
{
// ...and that it only uses constant buffers and immediates
Instruction &def = *i.asOperands[0].m_Defines[0].m_Inst;
bool isStatic = true;
for (uint32_t k = def.ui32FirstSrc; k < def.ui32NumOperands; k++)
{
Operand &o = def.asOperands[k];
if (!(o.eType == OPERAND_TYPE_CONSTANT_BUFFER || o.eType == OPERAND_TYPE_IMMEDIATE32))
{
isStatic = false;
break;
}
// Also check that the constant buffer access is "simple"
if (o.eType == OPERAND_TYPE_CONSTANT_BUFFER)
{
if (o.m_SubOperands[0].get() || o.m_SubOperands[1].get())
{
isStatic = false;
break;
}
}
}
if (isStatic)
{
psPhase->m_StaticBranchInstructions.push_back(&i);
i.m_IsStaticBranch = true;
i.m_StaticBranchCondition = &def;
BuildStaticBranchNameForInstruction(i);
}
}
}
}
}

View File

@ -237,7 +237,8 @@ static void DeclareInput(
std::string locationQualifier = "";
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage))
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage) ||
((psContext->flags & HLSLCC_FLAG_NVN_TARGET) && HaveLimitedInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions)))
{
bool addLocation = false;
@ -365,10 +366,9 @@ void ToGLSL::AddBuiltinOutput(const Declaration* psDecl, int arrayElements, cons
{
int max = psDecl->asOperands[0].GetMaxComponent();
if (IsESLanguage(psShader->eTargetLanguage) && !psShader->m_ClipDistanceExtensionDeclared)
if (IsESLanguage(psShader->eTargetLanguage))
{
bcatcstr(psContext->extensions, "#extension GL_EXT_clip_cull_distance : require\n");
psShader->m_ClipDistanceExtensionDeclared = true;
psContext->RequireExtension("GL_EXT_clip_cull_distance");
}
int applySwizzle = psDecl->asOperands[0].GetNumSwizzleElements() > 1 ? 1 : 0;
@ -551,7 +551,7 @@ void ToGLSL::AddUserOutput(const Declaration* psDecl)
const Operand* psOperand = &psDecl->asOperands[0];
const char* Precision = "";
int iNumComponents;
bstring type;
bstring type = NULL;
int regSpace = psDecl->asOperands[0].GetRegisterSpace(psContext);
uint32_t ui32Reg = psDecl->asOperands[0].ui32RegisterNumber;
@ -604,7 +604,7 @@ void ToGLSL::AddUserOutput(const Declaration* psDecl)
break;
}
if(HavePrecisionQualifers(psShader->eTargetLanguage))
if(HavePrecisionQualifiers(psContext))
{
switch(psOperand->eMinPrecision)
{
@ -664,8 +664,7 @@ void ToGLSL::AddUserOutput(const Declaration* psDecl)
{
bcatcstr(extensions, "#ifdef GL_ARB_conservative_depth\n");
bcatcstr(extensions, "#extension GL_ARB_conservative_depth : enable\n");
bcatcstr(extensions, "layout (depth_less) out float gl_FragDepth;\n");
bcatcstr(glsl, "#endif\n");
bcatcstr(extensions, "#endif\n");
bcatcstr(glsl, "#ifdef GL_ARB_conservative_depth\n");
bcatcstr(glsl, "layout (depth_less) out float gl_FragDepth;\n");
bcatcstr(glsl, "#endif\n");
@ -685,6 +684,13 @@ void ToGLSL::AddUserOutput(const Declaration* psDecl)
strncpy(OutputName, (char *)oname->data, 512);
bdestroy(oname);
bstring layoutQualifier = bformat("");
bool haveFramebufferFetch = (psShader->extensions->EXT_shader_framebuffer_fetch &&
psShader->eShaderType == PIXEL_SHADER &&
psContext->flags & HLSLCC_FLAG_SHADER_FRAMEBUFFER_FETCH);
if (haveFramebufferFetch)
bcatcstr(glsl, "#ifdef GL_EXT_shader_framebuffer_fetch\n");
if (HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage) ||
HaveLimitedInOutLocationQualifier(psContext->psShader->eTargetLanguage, psContext->psShader->extensions))
{
@ -698,15 +704,23 @@ void ToGLSL::AddUserOutput(const Declaration* psDecl)
renderTarget = 0;
index = 1;
}
bformata(glsl, "layout(location = %d, index = %d) ", renderTarget, index);
layoutQualifier = bformat("layout(location = %d, index = %d) ", renderTarget, index);
}
else
{
bformata(glsl, "layout(location = %d) ", renderTarget);
layoutQualifier = bformat("layout(location = %d) ", renderTarget);
}
}
bformata(glsl, "out %s%s %s;\n", Precision, type->data, OutputName);
if (haveFramebufferFetch)
{
bformata(glsl, "%sinout %s%s %s;\n", bstr2cstr(layoutQualifier, '\0'), Precision, type->data, OutputName);
bcatcstr(glsl, "#else\n");
bformata(glsl, "%sout %s%s %s;\n", bstr2cstr(layoutQualifier, '\0'), Precision, type->data, OutputName);
bcatcstr(glsl, "#endif\n");
}
else
bformata(glsl, "%sout %s%s %s;\n", bstr2cstr(layoutQualifier, '\0'), Precision, type->data, OutputName);
}
break;
}
@ -1005,6 +1019,8 @@ static const char* GetSamplerType(HLSLCrossCompilerContext* psContext,
{
case RESOURCE_DIMENSION_BUFFER:
{
if (IsESLanguage(psContext->psShader->eTargetLanguage))
psContext->RequireExtension("GL_EXT_texture_buffer");
switch(eType)
{
case RETURN_TYPE_SINT:
@ -1151,9 +1167,9 @@ static const char* GetSamplerType(HLSLCrossCompilerContext* psContext,
return "sampler2D";
}
static const char *GetSamplerPrecision(GLLang langVersion, REFLECT_RESOURCE_PRECISION ePrec)
static const char *GetSamplerPrecision(const HLSLCrossCompilerContext *psContext, REFLECT_RESOURCE_PRECISION ePrec)
{
if (!HavePrecisionQualifers(langVersion))
if (!HavePrecisionQualifiers(psContext))
return " ";
switch (ePrec)
@ -1181,23 +1197,20 @@ static void TranslateResourceTexture(HLSLCrossCompilerContext* psContext, const
psDecl->asOperands[0].ui32RegisterNumber);
if (psDecl->value.eResourceDimension == RESOURCE_DIMENSION_TEXTURECUBEARRAY
&& !HaveCubemapArray(psContext->psShader->eTargetLanguage)
&& !psContext->psShader->m_CubemapArrayExtensionDeclared)
&& !HaveCubemapArray(psContext->psShader->eTargetLanguage))
{
// Need to enable extension (either OES or ARB), but we only need to add it once
if (IsESLanguage(psContext->psShader->eTargetLanguage))
bformata(psContext->extensions, "#extension GL_OES_texture_cube_map_array : enable\n");
psContext->RequireExtension("GL_OES_texture_cube_map_array");
else
bformata(psContext->extensions, "#extension GL_ARB_texture_cube_map_array : enable\n");
psContext->psShader->m_CubemapArrayExtensionDeclared = true;
psContext->RequireExtension("GL_ARB_texture_cube_map_array");
}
const ResourceBinding *psBinding = NULL;
psShader->sInfo.GetResourceFromBindingPoint(RGROUP_TEXTURE, psDecl->asOperands[0].ui32RegisterNumber, &psBinding);
ASSERT(psBinding != NULL);
samplerPrecision = GetSamplerPrecision(psContext->psShader->eTargetLanguage, psBinding ? psBinding->ePrecision : REFLECT_RESOURCE_PRECISION_UNKNOWN);
samplerPrecision = GetSamplerPrecision(psContext, psBinding ? psBinding->ePrecision : REFLECT_RESOURCE_PRECISION_UNKNOWN);
if (psContext->flags & HLSLCC_FLAG_COMBINE_TEXTURE_SAMPLERS)
{
@ -1669,7 +1682,7 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
StorageQualifier = "in";
}
if(HavePrecisionQualifers(psShader->eTargetLanguage))
if(HavePrecisionQualifiers(psContext))
{
switch(psOperand->eMinPrecision)
{
@ -1741,6 +1754,16 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
const char* Interpolation = "";
int hasNoPerspective = psContext->psShader->eTargetLanguage <= LANG_ES_310 ? 0 : 1;
inputName = psContext->GetDeclaredInputName(psOperand, NULL, 1, NULL);
// If this is a SV_Target input and framebuffer fetch is enabled then skip the declaration
if (psShader->extensions->EXT_shader_framebuffer_fetch &&
psShader->eShaderType == PIXEL_SHADER &&
psContext->flags & HLSLCC_FLAG_SHADER_FRAMEBUFFER_FETCH)
{
if(inputName == "vs_SV_Target0")
break;
}
if (InOutSupported(psContext->psShader->eTargetLanguage))
{
StorageQualifier = "in";
@ -1787,7 +1810,7 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
break;
}
if(HavePrecisionQualifers(psShader->eTargetLanguage))
if(HavePrecisionQualifiers(psContext))
{
switch(psOperand->eMinPrecision)
{
@ -1830,7 +1853,7 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
{
uint32_t i = 0;
const uint32_t ui32NumTemps = psDecl->value.ui32NumTemps;
bool usePrecision = (HavePrecisionQualifers(psShader->eTargetLanguage) != 0);
bool usePrecision = (HavePrecisionQualifiers(psContext) != 0);
for (i = 0; i < ui32NumTemps; i++)
{
@ -1867,8 +1890,6 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
const Operand* psOperand = &psDecl->asOperands[0];
const uint32_t ui32BindingPoint = psOperand->aui32ArraySizes[0];
const char* StageName = "VS";
const ConstantBuffer* psCBuf = NULL;
psContext->psShader->sInfo.GetConstantBufferFromBindingPoint(RGROUP_CBUFFER, ui32BindingPoint, &psCBuf);
@ -1881,37 +1902,109 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
bformata(glsl, "layout(std140) uniform ConstantBuffer%d {\n\tvec4 data[%d];\n} cb%d;\n", ui32BindingPoint,psOperand->aui32ArraySizes[1],ui32BindingPoint);
break;
}
switch(psContext->psShader->eShaderType)
if (psCBuf->name.substr(0, 20) == "hlslcc_SubpassInput_" && psCBuf->name.length() >= 23 && !psCBuf->asVars.empty())
{
case PIXEL_SHADER:
// Special case for vulkan subpass input.
// The multisample versions have multiple members in the cbuffer, but we must only declare once.
// We still need to loop through all the variables and adjust names
// Pick up the type and index
char ty = psCBuf->name[20];
int idx = psCBuf->name[22] - '0';
bool isMS = false;
std::pair<uint32_t, uint32_t> binding = psContext->psDependencies->GetVulkanResourceBinding((std::string &)psCBuf->name, false, 2);
bool declared = false;
for (std::vector<ShaderVar>::const_iterator itr = psCBuf->asVars.begin(); itr != psCBuf->asVars.end(); itr++)
{
StageName = "PS";
break;
ShaderVar &sv = (ShaderVar &)*itr;
if (sv.name.substr(0, 15) == "hlslcc_fbinput_")
{
if (!declared)
{
switch (ty)
{
case 'f':
bformata(glsl, "layout(input_attachment_index = %d, set = %d, binding = %d) uniform highp subpassInput %s;\n", idx, binding.first, binding.second, sv.name.c_str());
break;
case 'h':
bformata(glsl, "layout(input_attachment_index = %d, set = %d, binding = %d) uniform mediump subpassInput %s;\n", idx, binding.first, binding.second, sv.name.c_str());
break;
case 'i':
bformata(glsl, "layout(input_attachment_index = %d, set = %d, binding = %d) uniform isubpassInput %s;\n", idx, binding.first, binding.second, sv.name.c_str());
break;
case 'u':
bformata(glsl, "layout(input_attachment_index = %d, set = %d, binding = %d) uniform usubpassInput %s;\n", idx, binding.first, binding.second, sv.name.c_str());
break;
case 'F':
bformata(glsl, "layout(input_attachment_index = %d, set = %d, binding = %d) uniform highp subpassInputMS %s;\n", idx, binding.first, binding.second, sv.name.substr(0, 16).c_str());
isMS = true;
break;
case 'H':
bformata(glsl, "layout(input_attachment_index = %d, set = %d, binding = %d) uniform mediump subpassInputMS %s;\n", idx, binding.first, binding.second, sv.name.substr(0, 16).c_str());
isMS = true;
break;
case 'I':
bformata(glsl, "layout(input_attachment_index = %d, set = %d, binding = %d) uniform isubpassInputMS %s;\n", idx, binding.first, binding.second, sv.name.substr(0, 16).c_str());
isMS = true;
break;
case 'U':
bformata(glsl, "layout(input_attachment_index = %d, set = %d, binding = %d) uniform usubpassInputMS %s;\n", idx, binding.first, binding.second, sv.name.substr(0, 16).c_str());
isMS = true;
break;
default:
break;
}
declared = true;
}
else
{
if (ty == 'F' || ty == 'I' || ty == 'U')
isMS = true;
}
// Munge the name so it'll get the correct function call in GLSL directly
sv.name.insert(0, "subpassLoad(");
if (isMS)
sv.name[sv.name.length() - 2] = ',';
sv.name.append(")");
// Also update the type name
sv.sType.name = sv.name;
sv.sType.fullName = sv.name;
}
}
case HULL_SHADER:
// Break out so this doesn't get declared.
break;
}
if(psCBuf->name == "OVR_multiview")
{
// Special case for piggy-backing multiview info out
// This is not really a cbuffer, but if we see this being accessed, we know we need viewID
// Extract numViews
uint32_t numViews = 0;
for(std::vector<ShaderVar>::const_iterator itr = psCBuf->asVars.begin(); itr != psCBuf->asVars.end(); itr++)
{
StageName = "HS";
break;
if(strncmp(itr->name.c_str(), "numViews_", 9) == 0)
{
// I really don't think we'll ever have more than 9 multiviews
numViews = itr->name[9] - '0';
break;
}
}
case DOMAIN_SHADER:
if(numViews > 0 && numViews < 10)
{
StageName = "DS";
break;
}
case GEOMETRY_SHADER:
{
StageName = "GS";
break;
}
case COMPUTE_SHADER:
{
StageName = "CS";
break;
}
default:
{
break;
bcatcstr(extensions, "#extension GL_OVR_multiview : require\n");
bcatcstr(extensions, "#extension GL_OVR_multiview2 : enable\n");
if(psShader->eShaderType == VERTEX_SHADER)
bformata(glsl, "layout(num_views = %d) in;\n", numViews);
break; // Break out so we don't actually declare this cbuffer
}
}
@ -1934,7 +2027,9 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
}
case OPCODE_DCL_RESOURCE:
{
if (HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage, psContext->psShader->extensions, psContext->flags))
// Skip the location declaration on Vulkan
if (HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage, psContext->psShader->extensions, psContext->flags)
&& ((psContext->flags & HLSLCC_FLAG_VULKAN_BINDINGS) == 0))
{
// 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.
@ -1950,7 +2045,19 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
{
case RESOURCE_DIMENSION_BUFFER:
{
bformata(glsl, "uniform %s ", GetSamplerType(psContext,
if ((psContext->flags & HLSLCC_FLAG_VULKAN_BINDINGS) != 0)
{
const ResourceBinding *psBinding = NULL;
psShader->sInfo.GetResourceFromBindingPoint(RGROUP_TEXTURE, psDecl->asOperands[0].ui32RegisterNumber, &psBinding);
std::string tname = psBinding->name;
GLSLCrossDependencyData::VulkanResourceBinding binding = psContext->psDependencies->GetVulkanResourceBinding(tname);
bformata(glsl, "layout(set = %d, binding = %d) ", binding.first, binding.second);
}
bcatcstr(glsl, "uniform ");
if (IsESLanguage(psContext->psShader->eTargetLanguage))
bcatcstr(glsl, "highp ");
bformata(glsl, "%s ", GetSamplerType(psContext,
RESOURCE_DIMENSION_BUFFER,
psDecl->asOperands[0].ui32RegisterNumber));
TranslateOperand(&psDecl->asOperands[0], TO_FLAG_NONE);
@ -2347,7 +2454,7 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
}
if (HavePrecisionQualifers(psShader->eTargetLanguage))
if (HavePrecisionQualifiers(psContext))
{
switch (psSignature->eMinPrec) // TODO What if the inputs in the indexed range are of different precisions?
{
@ -2560,7 +2667,7 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
// non-float images need either 'i' or 'u' prefix.
char imageTypePrefix[2] = { 0, 0 };
uint32_t bindpoint = psDecl->asOperands[0].ui32RegisterNumber;
const bool isVulkan = (psContext->flags & HLSLCC_FLAG_VULKAN_BINDINGS);
const bool isVulkan = (psContext->flags & HLSLCC_FLAG_VULKAN_BINDINGS) != 0;
if(psDecl->sUAV.ui32GloballyCoherentAccess & GLOBALLY_COHERENT_ACCESS)
{
@ -2585,12 +2692,7 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
if ((psDecl->sUAV.ui32AccessFlags & ACCESS_FLAG_WRITE) && IsESLanguage(psShader->eTargetLanguage))
{
// Need to require the extension
if (!psShader->m_TextureBufferExtensionDeclared)
{
bcatcstr(psContext->extensions, "#extension GL_EXT_texture_buffer : require\n");
psShader->m_TextureBufferExtensionDeclared = true;
}
psContext->RequireExtension("GL_EXT_texture_buffer");
}
if(isVulkan)
@ -2642,6 +2744,9 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
{
case RESOURCE_DIMENSION_BUFFER:
{
if(IsESLanguage(psShader->eTargetLanguage))
psContext->RequireExtension("GL_EXT_texture_buffer");
bformata(glsl, "uniform %simageBuffer ", imageTypePrefix);
break;
}
@ -2701,7 +2806,7 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
}
case OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED:
{
const bool isVulkan = (psContext->flags & HLSLCC_FLAG_VULKAN_BINDINGS);
const bool isVulkan = (psContext->flags & HLSLCC_FLAG_VULKAN_BINDINGS) != 0;
if(psDecl->sUAV.bCounter)
{
if (isVulkan)
@ -2715,7 +2820,7 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
{
bcatcstr(glsl, "layout (binding = 0) uniform ");
if (HavePrecisionQualifers(psShader->eTargetLanguage))
if (HavePrecisionQualifiers(psContext))
bcatcstr(glsl, "highp ");
bcatcstr(glsl, "atomic_uint ");
ResourceName(glsl, psContext, RGROUP_UAV, psDecl->asOperands[0].ui32RegisterNumber, 0);
@ -2729,7 +2834,7 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
}
case OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW:
{
const bool isVulkan = (psContext->flags & HLSLCC_FLAG_VULKAN_BINDINGS);
const bool isVulkan = (psContext->flags & HLSLCC_FLAG_VULKAN_BINDINGS) != 0;
if(psDecl->sUAV.bCounter)
{
if (isVulkan)
@ -2742,7 +2847,7 @@ void ToGLSL::TranslateDeclaration(const Declaration* psDecl)
else
{
bcatcstr(glsl, "layout (binding = 0) uniform ");
if (HavePrecisionQualifers(psShader->eTargetLanguage))
if (HavePrecisionQualifiers(psContext))
bcatcstr(glsl, "highp ");
bcatcstr(glsl, "atomic_uint ");
ResourceName(glsl, psContext, RGROUP_UAV, psDecl->asOperands[0].ui32RegisterNumber, 0);
@ -2850,7 +2955,7 @@ bool ToGLSL::TranslateSystemValue(const Operand *psOperand, const ShaderInfo::In
}
switch (sig->eSystemValueType)
{
{
case NAME_POSITION:
if (psContext->psShader->eShaderType == PIXEL_SHADER)
result = "gl_FragCoord";
@ -2863,13 +2968,13 @@ bool ToGLSL::TranslateSystemValue(const Operand *psOperand, const ShaderInfo::In
*pui32IgnoreSwizzle = 1;
return true;
case NAME_CLIP_DISTANCE:
{
{
// This is always routed through temp
std::ostringstream oss;
oss << "phase" << psContext->currentPhase << "_glClipDistance" << sig->ui32SemanticIndex;
result = oss.str();
return true;
}
}
case NAME_VIEWPORT_ARRAY_INDEX:
result = "gl_ViewportIndex";
if (pui32IgnoreSwizzle)
@ -2918,7 +3023,7 @@ bool ToGLSL::TranslateSystemValue(const Operand *psOperand, const ShaderInfo::In
{
result = "gl_TessLevelOuter";
return true;
}
}
else
{
result = "gl_TessLevelOuter[0]";
@ -2951,9 +3056,9 @@ bool ToGLSL::TranslateSystemValue(const Operand *psOperand, const ShaderInfo::In
{
result = "gl_TessLevelInner";
return true;
}
}
else
{
{
result = "gl_TessLevelInner[0]";
return true;
}
@ -2967,12 +3072,12 @@ bool ToGLSL::TranslateSystemValue(const Operand *psOperand, const ShaderInfo::In
}
if (psContext->psShader->asPhases[psContext->currentPhase].ePhase == HS_CTRL_POINT_PHASE)
{
{
if (sig->semanticName == "POS" && sig->ui32SemanticIndex == 0)
{
{
result = "gl_out[gl_InvocationID].gl_Position";
return true;
}
}
std::ostringstream oss;
if(isInput)
oss << psContext->inputPrefix << sig->semanticName << sig->ui32SemanticIndex;
@ -2980,7 +3085,7 @@ bool ToGLSL::TranslateSystemValue(const Operand *psOperand, const ShaderInfo::In
oss << psContext->outputPrefix << sig->semanticName << sig->ui32SemanticIndex << "[gl_InvocationID]";
result = oss.str();
return true;
}
}
// TODO: Add other builtins here.
if (sig->eSystemValueType == NAME_POSITION || (sig->semanticName == "POS" && sig->ui32SemanticIndex == 0 && psContext->psShader->eShaderType == VERTEX_SHADER))
@ -2989,6 +3094,13 @@ bool ToGLSL::TranslateSystemValue(const Operand *psOperand, const ShaderInfo::In
return true;
}
if (sig->semanticName == "PSIZE")
{
result = "gl_PointSize";
if (pui32IgnoreSwizzle)
*pui32IgnoreSwizzle = 1;
return true;
}
return false;
}

View File

@ -90,7 +90,7 @@ void ToGLSL::AddOpAssignToDestWithMask(const Operand* psDest,
case SVT_FLOAT:
case SVT_FLOAT10:
case SVT_FLOAT16:
ASSERT(eSrcType != SVT_INT12 || eSrcType != SVT_INT16 && eSrcType != SVT_UINT16);
ASSERT(eSrcType != SVT_INT12 || (eSrcType != SVT_INT16 && eSrcType != SVT_UINT16));
if (psContext->psShader->ui32MajorVersion > 3)
{
if (eSrcType == SVT_INT)
@ -892,7 +892,8 @@ void ToGLSL::GetResInfoData(Instruction* psInst, int index, int destElem)
bstring glsl = *psContext->currentGLSLString;
int numParenthesis = 0;
const RESINFO_RETURN_TYPE eResInfoReturnType = psInst->eResInfoReturnType;
const int isUAV = (psInst->asOperands[2].eType == OPERAND_TYPE_UNORDERED_ACCESS_VIEW);
bool isUAV = (psInst->asOperands[2].eType == OPERAND_TYPE_UNORDERED_ACCESS_VIEW);
bool isMS = psInst->eResDim == RESOURCE_DIMENSION_TEXTURE2DMS || psInst->eResDim == RESOURCE_DIMENSION_TEXTURE2DMSARRAY;
psContext->AddIndentation();
AddOpAssignToDestWithMask(&psInst->asOperands[0], eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_UINT ? SVT_UINT : SVT_FLOAT, 1, "=", &numParenthesis, 1 << destElem);
@ -922,7 +923,7 @@ void ToGLSL::GetResInfoData(Instruction* psInst, int index, int destElem)
TranslateOperand(&psInst->asOperands[2], TO_FLAG_NONE);
if (!isUAV)
if (!isUAV && !isMS)
{
bcatcstr(glsl, ", ");
TranslateOperand(&psInst->asOperands[1], TO_FLAG_INTEGER);
@ -1077,7 +1078,7 @@ void ToGLSL::TranslateTextureSample(Instruction* psInst,
if (ui32Flags & TEXSMP_FLAG_GATHER)
funcName = "textureGather";
uint32_t uniqueNameCounter;
uint32_t uniqueNameCounter = 0;
// In GLSL, for every texture sampling func overload, except for cubemap arrays, the
// depth compare reference value is given as the last component of the texture coord vector.
@ -1391,7 +1392,6 @@ void ToGLSL::TranslateShaderStorageLoad(Instruction* psInst)
}
for (component = 0; component < 4; component++)
{
const ShaderVarType *psVar = NULL;
int addedBitcast = 0;
if (!(destMask & (1 << component)))
continue;
@ -1835,6 +1835,14 @@ void ToGLSL::TranslateConditional(
statement = "return";
}
if (psInst->m_IsStaticBranch)
{
// Instead of the actual condition, use the specialization constant instead
// But first we'll have to make sure the original values don't get dropped out (we rely on glslang not being very smart)
bcatcstr(glsl, "if(false)\n {\n");
}
SHADER_VARIABLE_TYPE argType = psInst->asOperands[0].GetDataType(psContext);
if (argType == SVT_BOOL)
{
@ -1884,6 +1892,32 @@ void ToGLSL::TranslateConditional(
bcatcstr(glsl, " {\n");
}
}
if (psInst->m_IsStaticBranch)
{
if (psInst->eOpcode == OPCODE_IF)
{
bcatcstr(glsl, "}\n}\n");
}
else
{
bcatcstr(glsl, "}\n");
}
bcatcstr(glsl, "if(");
if (psInst->eBooleanTestType != INSTRUCTION_TEST_NONZERO)
bcatcstr(glsl, "!");
bcatcstr(glsl, psInst->m_StaticBranchName.c_str());
if (psInst->eOpcode != OPCODE_IF)
{
bformata(glsl, "){%s;}\n", statement);
}
else
{
bcatcstr(glsl, "){\n");
}
return;
}
}
void ToGLSL::TranslateInstruction(Instruction* psInst, bool isEmbedded /* = false */)
@ -1896,8 +1930,9 @@ void ToGLSL::TranslateInstruction(Instruction* psInst, bool isEmbedded /* = fals
{
#ifdef _DEBUG
psContext->AddIndentation();
bformata(glsl, "//Instruction %d\n", psInst->id);
// Uncomment to print instruction IDs
//psContext->AddIndentation();
//bformata(glsl, "//Instruction %d\n", psInst->id);
#if 0
if (psInst->id == 73)
{
@ -2751,10 +2786,7 @@ void ToGLSL::TranslateInstruction(Instruction* psInst, bool isEmbedded /* = fals
uint32_t varFound;
uint32_t funcPointer;
uint32_t funcTableIndex;
uint32_t funcTable;
uint32_t funcBodyIndex;
uint32_t funcBody;
uint32_t ui32NumBodiesPerTable;
#ifdef _DEBUG
@ -2765,15 +2797,10 @@ void ToGLSL::TranslateInstruction(Instruction* psInst, bool isEmbedded /* = fals
ASSERT(psInst->asOperands[0].eIndexRep[0] == OPERAND_INDEX_IMMEDIATE32);
funcPointer = psInst->asOperands[0].aui32ArraySizes[0];
funcTableIndex = psInst->asOperands[0].aui32ArraySizes[1];
funcBodyIndex = psInst->ui32FuncIndexWithinInterface;
ui32NumBodiesPerTable = psContext->psShader->funcPointer[funcPointer].ui32NumBodiesPerTable;
funcTable = psContext->psShader->funcPointer[funcPointer].aui32FuncTables[funcTableIndex];
funcBody = psContext->psShader->funcTable[funcTable].aui32FuncBodies[funcBodyIndex];
varFound = psContext->psShader->sInfo.GetInterfaceVarFromOffset(funcPointer, &psVar);
ASSERT(varFound);
@ -3630,7 +3657,7 @@ void ToGLSL::TranslateInstruction(Instruction* psInst, bool isEmbedded /* = fals
break;
}
SHADER_VARIABLE_TYPE srcDataType;
SHADER_VARIABLE_TYPE srcDataType = SVT_FLOAT;
const ResourceBinding* psBinding = 0;
psContext->psShader->sInfo.GetResourceFromBindingPoint(RGROUP_UAV, psSrc->ui32RegisterNumber, &psBinding);
switch (psBinding->ui32ReturnType)
@ -4005,13 +4032,13 @@ void ToGLSL::TranslateInstruction(Instruction* psInst, bool isEmbedded /* = fals
psContext->AddIndentation();
AddAssignToDest(&psInst->asOperands[0], SVT_UINT, 1, &numParenthesis);
if (isVulkan)
bcatcstr(glsl, "atomicAdd(");
bcatcstr(glsl, "(atomicAdd(");
else
bcatcstr(glsl, "atomicCounterDecrement(");
ResourceName(glsl, psContext, RGROUP_UAV, psInst->asOperands[1].ui32RegisterNumber, 0);
bformata(glsl, "_counter");
if (isVulkan)
bcatcstr(glsl, ", 0xffffffffu)");
bcatcstr(glsl, ", 0xffffffffu) + 0xffffffffu)");
else
bcatcstr(glsl, ")");
AddAssignPrologue(numParenthesis);
@ -4071,7 +4098,21 @@ void ToGLSL::TranslateInstruction(Instruction* psInst, bool isEmbedded /* = fals
AddAssignPrologue(numParenthesis);
break;
}
case OPCODE_SAMPLE_INFO:
{
#ifdef _DEBUG
psContext->AddIndentation();
bcatcstr(glsl, "//SAMPLE_INFO\n");
#endif
const RESINFO_RETURN_TYPE eResInfoReturnType = psInst->eResInfoReturnType;
psContext->AddIndentation();
AddAssignToDest(&psInst->asOperands[0], eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_UINT ? SVT_UINT : SVT_FLOAT, 1, &numParenthesis);
bcatcstr(glsl, "textureSamples(");
TranslateOperand(&psInst->asOperands[1], TO_FLAG_NAME_ONLY);
bcatcstr(glsl, ")");
AddAssignPrologue(numParenthesis);
break;
}
case OPCODE_DMAX:
case OPCODE_DMIN:
case OPCODE_DMUL:

View File

@ -6,6 +6,7 @@
#include "internal_includes/debug.h"
#include "internal_includes/Shader.h"
#include "internal_includes/toGLSL.h"
#include "internal_includes/languages.h"
#include <cmath>
#include <sstream>
@ -57,7 +58,11 @@ void TranslateOperandSwizzle(HLSLCrossCompilerContext* psContext, const Operand*
void TranslateOperandSwizzleWithMask(HLSLCrossCompilerContext* psContext, const Operand* psOperand, uint32_t ui32ComponentMask, int iRebase)
{
bstring glsl = *psContext->currentGLSLString;
TranslateOperandSwizzleWithMask(*psContext->currentGLSLString, psContext, psOperand, ui32ComponentMask, iRebase);
}
void TranslateOperandSwizzleWithMask(bstring glsl, HLSLCrossCompilerContext* psContext, const Operand* psOperand, uint32_t ui32ComponentMask, int iRebase)
{
uint32_t accessMask = ui32ComponentMask & psOperand->GetAccessMask();
if(psOperand->eType == OPERAND_TYPE_INPUT)
{
@ -400,11 +405,15 @@ static void printImmediate32(HLSLCrossCompilerContext *psContext, uint32_t value
}
void ToGLSL::TranslateVariableNameWithMask(const Operand* psOperand, uint32_t ui32TOFlag, uint32_t* pui32IgnoreSwizzle, uint32_t ui32CompMask, int *piRebase)
{
TranslateVariableNameWithMask(*psContext->currentGLSLString, psOperand, ui32TOFlag, pui32IgnoreSwizzle, ui32CompMask, piRebase);
}
void ToGLSL::TranslateVariableNameWithMask(bstring glsl, const Operand* psOperand, uint32_t ui32TOFlag, uint32_t* pui32IgnoreSwizzle, uint32_t ui32CompMask, int *piRebase)
{
int numParenthesis = 0;
int hasCtor = 0;
int needsBoolUpscale = 0; // If nonzero, bools need * 0xffffffff in them
bstring glsl = *psContext->currentGLSLString;
SHADER_VARIABLE_TYPE requestedType = TypeFlagsToSVTType(ui32TOFlag);
SHADER_VARIABLE_TYPE eType = psOperand->GetDataType(psContext, requestedType);
int numComponents = psOperand->GetNumSwizzleElements(ui32CompMask);
@ -606,7 +615,21 @@ void ToGLSL::TranslateVariableNameWithMask(const Operand* psOperand, uint32_t ui
else
{
std::string name = psContext->GetDeclaredInputName(psOperand, piRebase, 0, pui32IgnoreSwizzle);
bcatcstr(glsl, name.c_str());
// Rewrite the variable name if we're using framebuffer fetch
if (psContext->psShader->extensions->EXT_shader_framebuffer_fetch &&
psContext->psShader->eShaderType == PIXEL_SHADER &&
psContext->flags & HLSLCC_FLAG_SHADER_FRAMEBUFFER_FETCH)
{
if(name == "vs_SV_Target0")
bcatcstr(glsl, "SV_Target0");
else
bcatcstr(glsl, name.c_str());
}
else
{
bcatcstr(glsl, name.c_str());
}
}
}
break;
@ -781,7 +804,7 @@ void ToGLSL::TranslateVariableNameWithMask(const Operand* psOperand, uint32_t ui
const ShaderVarType* psVarType = NULL;
int32_t index = -1;
std::vector<uint32_t> arrayIndices;
bool isArray;
bool isArray = false;
psContext->psShader->sInfo.GetConstantBufferFromBindingPoint(RGROUP_CBUFFER, psOperand->aui32ArraySizes[0], &psCBuf);
switch(psContext->psShader->eShaderType)
@ -817,6 +840,14 @@ void ToGLSL::TranslateVariableNameWithMask(const Operand* psOperand, uint32_t ui
}
}
if(psCBuf && psCBuf->name == "OVR_multiview")
{
pui32IgnoreSwizzle[0] = 1;
bformata(glsl, "gl_ViewID_OVR");
break;
}
if(ui32TOFlag & TO_FLAG_DECLARATION_NAME)
{
pui32IgnoreSwizzle[0] = 1;
@ -1411,7 +1442,11 @@ void ToGLSL::TranslateVariableNameWithMask(const Operand* psOperand, uint32_t ui
void ToGLSL::TranslateOperand(const Operand* psOperand, uint32_t ui32TOFlag, uint32_t ui32ComponentMask)
{
bstring glsl = *psContext->currentGLSLString;
TranslateOperand(*psContext->currentGLSLString, psOperand, ui32TOFlag, ui32ComponentMask);
}
void ToGLSL::TranslateOperand(bstring glsl, const Operand* psOperand, uint32_t ui32TOFlag, uint32_t ui32ComponentMask)
{
uint32_t ui32IgnoreSwizzle = 0;
int iRebase = 0;
@ -1426,7 +1461,7 @@ void ToGLSL::TranslateOperand(const Operand* psOperand, uint32_t ui32TOFlag, uin
if(ui32TOFlag & TO_FLAG_NAME_ONLY)
{
TranslateVariableNameWithMask(psOperand, ui32TOFlag, &ui32IgnoreSwizzle, OPERAND_4_COMPONENT_MASK_ALL, &iRebase);
TranslateVariableNameWithMask(glsl, psOperand, ui32TOFlag, &ui32IgnoreSwizzle, OPERAND_4_COMPONENT_MASK_ALL, &iRebase);
return;
}
@ -1453,7 +1488,7 @@ void ToGLSL::TranslateOperand(const Operand* psOperand, uint32_t ui32TOFlag, uin
}
}
TranslateVariableNameWithMask(psOperand, ui32TOFlag, &ui32IgnoreSwizzle, ui32ComponentMask, &iRebase);
TranslateVariableNameWithMask(glsl, psOperand, ui32TOFlag, &ui32IgnoreSwizzle, ui32ComponentMask, &iRebase);
if(psContext->psShader->eShaderType == HULL_SHADER && psOperand->eType == OPERAND_TYPE_OUTPUT &&
psOperand->ui32RegisterNumber != 0 && psOperand->iArrayElements != 0 && psOperand->eIndexRep[0] != OPERAND_INDEX_IMMEDIATE32_PLUS_RELATIVE
@ -1464,7 +1499,7 @@ void ToGLSL::TranslateOperand(const Operand* psOperand, uint32_t ui32TOFlag, uin
if(!ui32IgnoreSwizzle)
{
TranslateOperandSwizzleWithMask(psContext, psOperand, ui32ComponentMask, iRebase);
TranslateOperandSwizzleWithMask(glsl, psContext, psOperand, ui32ComponentMask, iRebase);
}
switch(psOperand->eModifier)
@ -1592,18 +1627,11 @@ std::string TextureSamplerName(ShaderInfo* psShaderInfo, const uint32_t ui32Text
if(ui32ArrayOffset)
{
oss << texName << ui32ArrayOffset << "_X_" << psSamplerBinding->name;
oss << texName << ui32ArrayOffset << "TEX_with_SMP" << psSamplerBinding->name;
}
else
{
if((i>0) && (texName[i-1] == '_'))//Prevent double underscore which is reserved
{
oss << texName << "X_" << psSamplerBinding->name;
}
else
{
oss << texName << "_X_" << psSamplerBinding->name;
}
oss << texName << "TEX_with_SMP" << psSamplerBinding->name;
}
return oss.str();

View File

@ -81,13 +81,11 @@ bool ToMetal::Translate()
ClampPartialPrecisions();
psShader->PrepareStructuredBufferBindingSlots();
ShaderPhase &phase = psShader->asPhases[0];
phase.UnvectorizeImmMoves();
psContext->DoDataTypeAnalysis(&phase);
phase.ResolveUAVProperties();
psShader->ResolveStructuredBufferBindingSlots(&phase);
ReserveUAVBindingSlots(&phase); // TODO: unify slot allocation code between gl/metal/vulkan
phase.PruneConstArrays();
HLSLcc::DoLoopTransform(phase);
@ -95,11 +93,17 @@ bool ToMetal::Translate()
bcatcstr(glsl, "#include <metal_stdlib>\n#include <metal_texture>\nusing namespace metal;\n");
for (i = 0; i < psShader->asPhases[0].psDecl.size(); ++i)
{
TranslateDeclaration(&psShader->asPhases[0].psDecl[i]);
}
// Output default implementations for framebuffer index remap if needed
if(m_NeedFBOutputRemapDecl)
bcatcstr(glsl, "#ifndef XLT_REMAP_O\n#define XLT_REMAP_O {0, 1, 2, 3, 4, 5, 6, 7}\n#endif\nconstexpr constant uint xlt_remap_o[] = XLT_REMAP_O;\n");
if(m_NeedFBInputRemapDecl)
bcatcstr(glsl, "#ifndef XLT_REMAP_I\n#define XLT_REMAP_I {0, 1, 2, 3, 4, 5, 6, 7}\n#endif\nconstexpr constant uint xlt_remap_i[] = XLT_REMAP_I;\n");
DeclareClipPlanes(&psShader->asPhases[0].psDecl[0], psShader->asPhases[0].psDecl.size());
GenerateTexturesReflection(&psContext->m_Reflection);
if (m_StructDefinitions[GetInputStructName()].m_Members.size() > 0)
{
@ -263,3 +267,25 @@ void ToMetal::ClampPartialPrecisions()
o->eMinPrecision = OPERAND_MIN_PRECISION_FLOAT_16;
});
}
void ToMetal::ReserveUAVBindingSlots(ShaderPhase *phase)
{
for (uint32_t p = 0; p < phase->psDecl.size(); ++p)
{
uint32_t regNo = phase->psDecl[p].asOperands[0].ui32RegisterNumber;
if (phase->psDecl[p].eOpcode == OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW ||
phase->psDecl[p].eOpcode == OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED)
{
m_BufferSlots.ReserveBindingSlot(regNo, BindingSlotAllocator::RWBuffer);
}
else if (phase->psDecl[p].eOpcode == OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED)
{
// Typed buffers are atm faked using structured buffers -> bind in buffer space
if (phase->psDecl[p].value.eResourceDimension == RESOURCE_DIMENSION_BUFFER)
m_BufferSlots.ReserveBindingSlot(regNo, BindingSlotAllocator::RWBuffer);
else
m_TextureSlots.ReserveBindingSlot(regNo, BindingSlotAllocator::UAV);
}
}
}

View File

@ -36,9 +36,13 @@ bool ToMetal::TranslateSystemValue(const Operand *psOperand, const ShaderInfo::I
if (outSkipPrefix != NULL) *outSkipPrefix = true;
return true;
case NAME_CLIP_DISTANCE:
result = "mtl_ClipDistance";
{
// this is temp variabe, declaration and redirecting to actual output is handled in DeclareClipPlanes
char tmpName[128]; sprintf(tmpName, "phase%d_ClipDistance%d", psContext->currentPhase, sig->ui32SemanticIndex);
result = tmpName;
if (outSkipPrefix != NULL) *outSkipPrefix = true;
return true;
}
/* case NAME_VIEWPORT_ARRAY_INDEX:
result = "gl_ViewportIndex";
if (puiIgnoreSwizzle)
@ -179,6 +183,80 @@ void ToMetal::DeclareBuiltinInput(const Declaration *psDecl)
}
}
void ToMetal::DeclareClipPlanes(const Declaration* decl, unsigned declCount)
{
unsigned planeCount = 0;
for(unsigned i = 0, n = declCount ; i < n ; ++i)
{
const Operand* operand = &decl[i].asOperands[0];
if(operand->eSpecialName == NAME_CLIP_DISTANCE)
planeCount += operand->GetMaxComponent();
}
if(planeCount == 0) return;
std::ostringstream oss; oss << "float mtl_ClipDistance [[ clip_distance ]]";
if(planeCount > 1) oss << "[" << planeCount << "]";
m_StructDefinitions[GetOutputStructName()].m_Members.push_back(oss.str());
Shader* shader = psContext->psShader;
unsigned compCount = 1;
const ShaderInfo::InOutSignature* psFirstClipSignature;
if(shader->sInfo.GetOutputSignatureFromSystemValue(NAME_CLIP_DISTANCE, 0, &psFirstClipSignature))
{
if(psFirstClipSignature->ui32Mask & (1 << 3)) compCount = 4;
else if(psFirstClipSignature->ui32Mask & (1 << 2)) compCount = 3;
else if(psFirstClipSignature->ui32Mask & (1 << 1)) compCount = 2;
}
ShaderPhase* phase = &shader->asPhases[psContext->currentPhase];
for(unsigned i = 0, n = declCount ; i < n ; ++i)
{
const Operand* operand = &decl[i].asOperands[0];
if(operand->eSpecialName != NAME_CLIP_DISTANCE) continue;
const ShaderInfo::InOutSignature* signature = 0;
shader->sInfo.GetOutputSignatureFromRegister(operand->ui32RegisterNumber, operand->ui32CompMask, 0, &signature);
const int semanticIndex = signature->ui32SemanticIndex;
bformata(phase->earlyMain, " float4 phase%d_ClipDistance%d;\n", psContext->currentPhase, signature->ui32SemanticIndex);
const char* swizzleStr[] = { "x", "y", "z", "w" };
phase->hasPostShaderCode = 1;
if(planeCount > 1)
{
for(int i = 0 ; i < compCount ; ++i)
{
bformata(phase->postShaderCode, " %s.mtl_ClipDistance[%d] = phase%d_ClipDistance%d.%s;\n",
"output", semanticIndex*compCount + i, psContext->currentPhase, semanticIndex, swizzleStr[i]
);
}
}
else
{
bformata(phase->postShaderCode, " %s.mtl_ClipDistance = phase%d_ClipDistance%d.x;\n", "output", psContext->currentPhase, semanticIndex);
}
}
}
void ToMetal::GenerateTexturesReflection(HLSLccReflection* refl)
{
for(unsigned i = 0, n = m_Textures.size() ; i < n ; ++i)
{
const std::string samplerName1 = m_Textures[i].name, samplerName2 = "sampler"+m_Textures[i].name;
for(unsigned j = 0, m = m_Samplers.size() ; j < m ; ++j)
{
if(m_Samplers[j].name == samplerName1 || m_Samplers[j].name == samplerName2)
{
m_Textures[i].samplerBind = m_Samplers[j].slot;
break;
}
}
}
for(unsigned i = 0, n = m_Textures.size() ; i < n ; ++i)
refl->OnTextureBinding(m_Textures[i].name, m_Textures[i].textureBind, m_Textures[i].samplerBind, m_Textures[i].dim, m_Textures[i].uav);
}
void ToMetal::DeclareBuiltinOutput(const Declaration *psDecl)
{
std::string out = GetOutputStructName();
@ -198,7 +276,7 @@ void ToMetal::DeclareBuiltinOutput(const Declaration *psDecl)
#endif
break;
case NAME_CLIP_DISTANCE:
m_StructDefinitions[out].m_Members.push_back("float4 mtl_ClipDistance [[ clip_distance ]]");
// it will be done separately in DeclareClipPlanes
break;
case NAME_VIEWPORT_ARRAY_INDEX:
@ -329,7 +407,6 @@ void ToMetal::HandleOutputRedirect(const Declaration *psDecl, const std::string
{
const Operand *psOperand = &psDecl->asOperands[0];
Shader *psShader = psContext->psShader;
bstring glsl = *psContext->currentGLSLString;
int needsRedirect = 0;
const ShaderInfo::InOutSignature *psSig = NULL;
@ -425,7 +502,6 @@ void ToMetal::HandleInputRedirect(const Declaration *psDecl, const std::string &
{
Operand *psOperand = (Operand *)&psDecl->asOperands[0];
Shader *psShader = psContext->psShader;
bstring glsl = *psContext->currentGLSLString;
int needsRedirect = 0;
const ShaderInfo::InOutSignature *psSig = NULL;
@ -525,7 +601,7 @@ void ToMetal::HandleInputRedirect(const Declaration *psDecl, const std::string &
}
static std::string TranslateResourceDeclaration(HLSLCrossCompilerContext* psContext,
const Declaration *psDecl,
const Declaration *psDecl, const std::string& textureName,
bool isDepthSampler, bool isUAV)
{
std::ostringstream oss;
@ -591,7 +667,15 @@ static std::string TranslateResourceDeclaration(HLSLCrossCompilerContext* psCont
access = "read";
}
std::string typeName = HLSLcc::GetConstructorForTypeMetal(HLSLcc::ResourceReturnTypeToSVTType(eType, ePrec), 1);
SHADER_VARIABLE_TYPE svtType = HLSLcc::ResourceReturnTypeToSVTType(eType, ePrec);
std::string typeName = HLSLcc::GetConstructorForTypeMetal(svtType, 1);
if ((textureName == "_CameraDepthTexture" || textureName == "_LastCameraDepthTexture") && svtType != SVT_FLOAT)
{
std::string msg = textureName + " should be float on Metal (use sampler2D or sampler2D_float). Incorrect type "
"can cause Metal validation failures or undefined results on some devices.";
psContext->m_Reflection.OnDiagnostics(msg, 0, false);
}
switch (eDimension)
{
@ -870,19 +954,16 @@ void ToMetal::DeclareConstantBuffer(const ConstantBuffer *psCBuf, uint32_t ui32B
}
void ToMetal::DeclareBufferVariable(const Declaration *psDecl, const bool isRaw, const bool isUAV)
void ToMetal::DeclareBufferVariable(const Declaration *psDecl, bool isRaw, bool isUAV)
{
uint32_t ui32BindingPoint = psDecl->asOperands[0].ui32RegisterNumber;
std::string BufName, BufType;
uint32_t regNo = psDecl->asOperands[0].ui32RegisterNumber;
std::string BufName, BufType, BufConst;
BufName = "";
BufType = "";
BufConst = "";
// Use original HLSL bindings for UAVs only. For non-UAV buffers we have resolved new binding points from the same register space.
if (!isUAV)
ui32BindingPoint = psContext->psShader->aui32StructuredBufferBindingPoints[psContext->psShader->ui32CurrentStructuredBufferIndex++];
BufName = ResourceName(isUAV ? RGROUP_UAV : RGROUP_TEXTURE, psDecl->asOperands[0].ui32RegisterNumber);
BufName = ResourceName(isUAV ? RGROUP_UAV : RGROUP_TEXTURE, regNo);
if (!isRaw) // declare struct containing uint array when needed
{
@ -898,7 +979,8 @@ void ToMetal::DeclareBufferVariable(const Declaration *psDecl, const bool isRaw,
if (!isUAV || ((psDecl->sUAV.ui32AccessFlags & ACCESS_FLAG_WRITE) == 0))
{
oss << "const ";
BufConst = "const ";
oss << BufConst;
}
else
{
@ -911,11 +993,138 @@ void ToMetal::DeclareBufferVariable(const Declaration *psDecl, const bool isRaw,
else
oss << "device " << BufType << " *" << BufName;
uint32_t loc = m_BufferSlots.GetBindingSlot(ui32BindingPoint, BindingSlotAllocator::RWBuffer);
uint32_t loc = m_BufferSlots.GetBindingSlot(regNo, isUAV ? BindingSlotAllocator::RWBuffer : BindingSlotAllocator::Texture);
oss << " [[ buffer(" << loc << ") ]]";
m_StructDefinitions[""].m_Members.push_back(oss.str());
psContext->m_Reflection.OnBufferBinding(BufName, loc, isUAV);
// In addition to the actual declaration, we need pointer modification and possible counter declaration
// in early main:
std::ostringstream earlymainoss;
// Possible counter is always in the beginning of the buffer
if (isUAV && psDecl->sUAV.bCounter)
{
earlymainoss << " device atomic_uint *" << BufName << "_counter = reinterpret_cast<device atomic_uint *> (" << BufName << ");\n";
}
// Some GPUs don't allow memory access below buffer binding offset in the shader so always bind compute buffer
// at offset 0 instead of GetDataOffset().
// We can't tell at shader compile time if the buffer actually has counter or not. Therefore we'll always reserve
// space for the counter and bump the data pointer to beginning of the actual data here.
earlymainoss << " " << BufName << " = reinterpret_cast<" << BufConst
<< "device " << (isRaw ? "uint" : BufType) << " *> (reinterpret_cast<device "
<< BufConst << "atomic_uint *> (" << BufName << ") + 1);\n";
bformata(psContext->psShader->asPhases[psContext->currentPhase].earlyMain, earlymainoss.str().c_str());
}
static int ParseInlineSamplerWrapMode(const std::string& samplerName, const std::string& wrapName)
{
int res = 0;
const bool hasWrap = (samplerName.find(wrapName) != std::string::npos);
if (!hasWrap)
return res;
const bool hasU = (samplerName.find(wrapName + 'u') != std::string::npos);
const bool hasV = (samplerName.find(wrapName + 'v') != std::string::npos);
const bool hasW = (samplerName.find(wrapName + 'w') != std::string::npos);
if (hasWrap) res |= 1;
if (hasU) res |= 2;
if (hasV) res |= 4;
if (hasW) res |= 8;
return res;
}
static bool EmitInlineSampler(HLSLCrossCompilerContext* ctx, const std::string& name)
{
// See if it's a sampler that goes with the texture, or an "inline" sampler
// where sampler states are hardcoded in the shader directly.
//
// The logic for "inline" samplers below must match what is recognized
// by other shader platforms in Unity (ParseInlineSamplerName function
// in the shader compiler).
std::string samplerName(name); std::transform(samplerName.begin(), samplerName.end(), samplerName.begin(), ::tolower);
// filter modes
const bool hasPoint = (samplerName.find("point") != std::string::npos);
const bool hasTrilinear = (samplerName.find("trilinear") != std::string::npos);
const bool hasLinear = (samplerName.find("linear") != std::string::npos);
const bool hasAnyFilter = hasPoint || hasTrilinear || hasLinear;
// wrap modes
const int bitsClamp = ParseInlineSamplerWrapMode(samplerName, "clamp");
const int bitsRepeat = ParseInlineSamplerWrapMode(samplerName, "repeat");
const int bitsMirror = ParseInlineSamplerWrapMode(samplerName, "mirror");
const int bitsMirrorOnce = ParseInlineSamplerWrapMode(samplerName, "mirroronce");
const bool hasAnyWrap = bitsClamp != 0 || bitsRepeat != 0 || bitsMirror != 0 || bitsMirrorOnce != 0;
// depth comparison
const bool hasCompare = (samplerName.find("compare") != std::string::npos);
// name must contain a filter mode and a wrap mode at least
if (!hasAnyFilter || !hasAnyWrap)
{
return false;
}
bstring str = ctx->psShader->asPhases[ctx->currentPhase].earlyMain;
bformata(str, "\tconstexpr sampler %s(", name.c_str());
if (hasCompare)
bformata(str, "compare_func::greater_equal,");
if (hasTrilinear)
bformata(str, "filter::linear,mip_filter::linear,");
else if (hasLinear)
bformata(str, "filter::linear,");
else
bformata(str, "filter::nearest,");
const char* kTexWrapClamp = "clamp_to_edge";
const char* kTexWrapRepeat = "repeat";
const char* kTexWrapMirror = "mirrored_repeat";
const char* kTexWrapMirrorOnce = "mirrored_repeat"; // currently Metal shading language does not have syntax for inline sampler state that would do "mirror clamp to edge"
const char* wrapU = kTexWrapRepeat;
const char* wrapV = kTexWrapRepeat;
const char* wrapW = kTexWrapRepeat;
if (bitsClamp == 1) wrapU = wrapV = wrapW = kTexWrapClamp;
else if (bitsRepeat == 1) wrapU = wrapV = wrapW = kTexWrapRepeat;
else if (bitsMirrorOnce == 1) wrapU = wrapV = wrapW = kTexWrapMirrorOnce;
else if (bitsMirror == 1) wrapU = wrapV = wrapW = kTexWrapMirror;
if ((bitsClamp & 2) != 0) wrapU = kTexWrapClamp;
if ((bitsClamp & 4) != 0) wrapV = kTexWrapClamp;
if ((bitsClamp & 8) != 0) wrapW = kTexWrapClamp;
if ((bitsRepeat & 2) != 0) wrapU = kTexWrapRepeat;
if ((bitsRepeat & 4) != 0) wrapV = kTexWrapRepeat;
if ((bitsRepeat & 8) != 0) wrapW = kTexWrapRepeat;
if ((bitsMirrorOnce & 2) != 0) wrapU = kTexWrapMirrorOnce;
if ((bitsMirrorOnce & 4) != 0) wrapV = kTexWrapMirrorOnce;
if ((bitsMirrorOnce & 8) != 0) wrapW = kTexWrapMirrorOnce;
if ((bitsMirror & 2) != 0) wrapU = kTexWrapMirror;
if ((bitsMirror & 4) != 0) wrapV = kTexWrapMirror;
if ((bitsMirror & 8) != 0) wrapW = kTexWrapMirror;
if (wrapU == wrapV && wrapU == wrapW)
bformata(str, "address::%s", wrapU);
else
bformata(str, "s_address::%s,t_address::%s,r_address::%s", wrapU, wrapV, wrapW);
bformata(str, ");\n");
return true;
}
@ -946,12 +1155,10 @@ void ToMetal::TranslateDeclaration(const Declaration* psDecl)
std::string name = psContext->GetDeclaredInputName(psOperand, nullptr, 1, nullptr);
//Already declared as part of an array?
if (psShader->aIndexedInput[0][psDecl->asOperands[0].ui32RegisterNumber] == -1)
{
ASSERT(0); // Find out what's happening
break;
}
// NB: unlike GL we keep arrays of 2-component vectors as is (without collapsing into float4)
// if(psShader->aIndexedInput[0][psDecl->asOperands[0].ui32RegisterNumber] == -1)
// break;
// Already declared?
if ((ui32CompMask != 0) && ((ui32CompMask & ~psShader->acInputDeclared[0][ui32Reg]) == 0))
{
@ -1041,7 +1248,8 @@ void ToMetal::TranslateDeclaration(const Declaration* psDecl)
//
// TODO: Improve later when GLES3 support arrives, it requires
// single declaration through inout
oss << "color(" << psSig->ui32SemanticIndex << ")";
oss << "color(xlt_remap_i[" << psSig->ui32SemanticIndex << "])";
m_NeedFBInputRemapDecl = true;
}
else
{
@ -1115,6 +1323,49 @@ void ToMetal::TranslateDeclaration(const Declaration* psDecl)
const ConstantBuffer* psCBuf = NULL;
psContext->psShader->sInfo.GetConstantBufferFromBindingPoint(RGROUP_CBUFFER, psDecl->asOperands[0].aui32ArraySizes[0], &psCBuf);
ASSERT(psCBuf != NULL);
if (psCBuf->name.substr(0, 20) == "hlslcc_SubpassInput_" && psCBuf->name.length() >= 23 && !psCBuf->asVars.empty())
{
// Special case for framebuffer fetch.
char ty = psCBuf->name[20];
int idx = psCBuf->name[22] - '0';
const ShaderVar &sv = psCBuf->asVars[0];
if (sv.name.substr(0, 15) == "hlslcc_fbinput_")
{
// Pick up the type and index
std::ostringstream oss;
m_NeedFBInputRemapDecl = true;
switch (ty)
{
case 'f':
case 'F':
oss << "float4 " << sv.name << " [[ color(xlt_remap_i["<< idx <<"]) ]]";
m_StructDefinitions[""].m_Members.push_back(oss.str());
break;
case 'h':
case 'H':
oss << "half4 " << sv.name << " [[ color(xlt_remap_i[" << idx << "]) ]]";
m_StructDefinitions[""].m_Members.push_back(oss.str());
break;
case 'i':
case 'I':
oss << "int4 " << sv.name << " [[ color(xlt_remap_i[" << idx << "]) ]]";
m_StructDefinitions[""].m_Members.push_back(oss.str());
break;
case 'u':
case 'U':
oss << "uint4 " << sv.name << " [[ color(xlt_remap_i[" << idx << "]) ]]";
m_StructDefinitions[""].m_Members.push_back(oss.str());
break;
default:
break;
}
}
// Break out so this doesn't get declared.
break;
}
DeclareConstantBuffer(psCBuf, psDecl->asOperands[0].aui32ArraySizes[0]);
break;
}
@ -1373,9 +1624,9 @@ void ToMetal::TranslateDeclaration(const Declaration* psDecl)
uint32_t destMask = psDecl->asOperands[0].ui32CompMask;
uint32_t rebase = 0;
const ShaderInfo::InOutSignature *psSig = NULL;
uint32_t regSpace = psDecl->asOperands[0].GetRegisterSpace(psContext) == 0;
uint32_t regSpace = psDecl->asOperands[0].GetRegisterSpace(psContext);
if (regSpace)
if (regSpace == 0)
if (isInput)
psContext->psShader->sInfo.GetInputSignatureFromRegister(startReg + i, destMask, &psSig);
else
@ -1414,8 +1665,9 @@ void ToMetal::TranslateDeclaration(const Declaration* psDecl)
}
}
}
bcatcstr(glsl, " = ");
bcatcstr(glsl, realName.c_str());
// for some reason input struct is missed here from GetDeclaredInputName result, so add it manually
bformata(glsl, " = input.%s", realName.c_str());
if (destMask != OPERAND_4_COMPONENT_MASK_ALL && destMask != psSig->ui32Mask)
{
int k;
@ -1537,25 +1789,20 @@ void ToMetal::TranslateDeclaration(const Declaration* psDecl)
}
case OPCODE_DCL_SAMPLER:
{
// Find out if the sampler is good for a builtin
std::string name = TranslateOperand(&psDecl->asOperands[0], TO_FLAG_NAME_ONLY);
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
bool linear = (name.find("linear") != std::string::npos);
bool point = (name.find("point") != std::string::npos);
bool clamp = (name.find("clamp") != std::string::npos);
bool repeat = (name.find("repeat") != std::string::npos);
// Declare only builtin samplers here. Default samplers are declared together with the texture.
if ((linear != point) && (clamp != repeat))
if (!EmitInlineSampler(psContext, name))
{
std::ostringstream oss;
oss << "constexpr sampler " << TranslateOperand(&psDecl->asOperands[0], TO_FLAG_NAME_ONLY) << "(";
oss << (linear ? "filter::linear, " : "filter::nearest, ");
oss << (clamp ? "address::clamp_to_edge" : "address::repeat");
oss << ")";
bformata(psContext->psShader->asPhases[psContext->currentPhase].earlyMain, "\t%s;\n", oss.str().c_str());
// for some reason we have some samplers start with "sampler" and some not
const bool startsWithSampler = name.find("sampler") == 0;
const uint32_t slot = m_SamplerSlots.GetBindingSlot(psDecl->asOperands[0].ui32RegisterNumber, BindingSlotAllocator::Texture);
std::ostringstream oss; oss << "sampler " << (startsWithSampler ? "" : "sampler") << name << " [[ sampler (" << slot << ") ]]";
m_StructDefinitions[""].m_Members.push_back(oss.str());
SamplerDesc desc = { name, psDecl->asOperands[0].ui32RegisterNumber, slot };
m_Samplers.push_back(desc);
}
break;
}
case OPCODE_DCL_HS_MAX_TESSFACTOR:
@ -1565,57 +1812,48 @@ void ToMetal::TranslateDeclaration(const Declaration* psDecl)
}
case OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED:
{
std::string samplerTypeName = TranslateResourceDeclaration(psContext,
psDecl, false, true);
// A hack to support single component 32bit RWBuffers: Declare as raw buffer.
// TODO: Use textures for RWBuffers when the scripting API has actual format selection etc
// way to flag the created ComputeBuffer as typed. Even then might want to leave this
// hack path for 32bit (u)int typed buffers to continue support atomic ops on those formats.
if (psDecl->value.eResourceDimension == RESOURCE_DIMENSION_BUFFER)
{
DeclareBufferVariable(psDecl, true, true);
break;
}
std::string texName = ResourceName(RGROUP_UAV, psDecl->asOperands[0].ui32RegisterNumber);
std::string samplerTypeName = TranslateResourceDeclaration(psContext, psDecl, texName, false, true);
uint32_t slot = m_TextureSlots.GetBindingSlot(psDecl->asOperands[0].ui32RegisterNumber, BindingSlotAllocator::UAV); std::ostringstream oss;
oss << samplerTypeName << " " << texName
<< " [[ texture (" << slot << ") ]] ";
m_StructDefinitions[""].m_Members.push_back(oss.str());
psContext->m_Reflection.OnTextureBinding(texName, slot, TD_2D, true); // TODO: translate psDecl->value.eResourceDimension into HLSLCC_TEX_DIMENSION
// TODO: translate psDecl->value.eResourceDimension into HLSLCC_TEX_DIMENSION
TextureSamplerDesc desc = {texName, (int)slot, -1, TD_2D, true};
m_Textures.push_back(desc);
break;
}
case OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED:
{
if (psDecl->sUAV.bCounter)
{
std::ostringstream oss;
std::string bufName = ResourceName(RGROUP_UAV, psDecl->asOperands[0].ui32RegisterNumber);
// Some GPUs don't allow memory access below buffer binding offset in the shader so always bind compute buffer
// at offset 0 instead of GetDataOffset() to access counter value and translate the buffer pointer in the shader.
oss << "device atomic_uint *" << bufName << "_counter = reinterpret_cast<device atomic_uint *> (" << bufName << ");";
oss << "\n " << bufName << " = reinterpret_cast<device " << bufName << "_Type *> (reinterpret_cast<device atomic_uint *> (" << bufName << ") + 1)";
bformata(psContext->psShader->asPhases[psContext->currentPhase].earlyMain, " %s;\n", oss.str().c_str());
}
DeclareBufferVariable(psDecl, 0, 1);
DeclareBufferVariable(psDecl, false, true);
break;
}
case OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW:
{
if (psDecl->sUAV.bCounter)
{
std::ostringstream oss;
std::string bufName = ResourceName(RGROUP_UAV, psDecl->asOperands[0].ui32RegisterNumber);
oss << "device atomic_uint *" << bufName << "_counter = reinterpret_cast<atomic_uint *> (" << bufName << ") - 1";
bformata(psContext->psShader->asPhases[psContext->currentPhase].earlyMain, "\t%s;\n", oss.str().c_str()); }
DeclareBufferVariable(psDecl, 1, 1);
DeclareBufferVariable(psDecl, true, true);
break;
}
case OPCODE_DCL_RESOURCE_STRUCTURED:
{
DeclareBufferVariable(psDecl, 0, 0);
DeclareBufferVariable(psDecl, false, false);
break;
}
case OPCODE_DCL_RESOURCE_RAW:
{
DeclareBufferVariable(psDecl, 1, 0);
DeclareBufferVariable(psDecl, true, false);
break;
}
case OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED:
@ -1718,22 +1956,19 @@ std::string ToMetal::ResourceName(ResourceGroup group, const uint32_t ui32Regist
void ToMetal::TranslateResourceTexture(const Declaration* psDecl, uint32_t samplerCanDoShadowCmp, HLSLCC_TEX_DIMENSION texDim)
{
std::string texName = ResourceName(RGROUP_TEXTURE, psDecl->asOperands[0].ui32RegisterNumber);
std::string samplerTypeName = TranslateResourceDeclaration(psContext,
psDecl, (samplerCanDoShadowCmp && psDecl->ui32IsShadowTex), false);
psDecl, texName, (samplerCanDoShadowCmp && psDecl->ui32IsShadowTex), false);
uint32_t slot = m_TextureSlots.GetBindingSlot(psDecl->asOperands[0].ui32RegisterNumber, BindingSlotAllocator::Texture);
std::string texName = ResourceName(RGROUP_TEXTURE, psDecl->asOperands[0].ui32RegisterNumber);
std::ostringstream oss;
oss << samplerTypeName << " " << texName
<< " [[ texture (" << slot << ") ]] ";
m_StructDefinitions[""].m_Members.push_back(oss.str());
psContext->m_Reflection.OnTextureBinding(texName, slot, texDim, false);
oss.str("");
// the default sampler for a texture is named after the texture with a "sampler" prefix
oss << "sampler sampler" << texName
<< " [[ sampler (" << slot << ") ]] ";
m_StructDefinitions[""].m_Members.push_back(oss.str());
TextureSamplerDesc desc = {texName, (int)slot, -1, texDim, false};
m_Textures.push_back(desc);
if (samplerCanDoShadowCmp && psDecl->ui32IsShadowTex)
EnsureShadowSamplerDeclared();
@ -1746,17 +1981,21 @@ void ToMetal::DeclareResource(const Declaration *psDecl)
{
case RESOURCE_DIMENSION_BUFFER:
{
uint32_t slot = m_TextureSlots.GetBindingSlot(psDecl->asOperands[0].ui32RegisterNumber, BindingSlotAllocator::Texture);
// Fake single comp 32bit texel buffers by using raw buffer
DeclareBufferVariable(psDecl, true, false);
break;
/* TODO: re-enable this code for buffer textures when sripting API has proper support for it
uint32_t slot = m_TextureSlots.GetBindingSlot(psDecl->asOperands[0].ui32RegisterNumber, BindingSlotAllocator::Texture);
std::string texName = TranslateOperand(&psDecl->asOperands[0], TO_FLAG_NAME_ONLY);
std::ostringstream oss;
oss << "device " << TranslateResourceDeclaration(psContext,
psDecl, false, false);
oss << "device " << TranslateResourceDeclaration(psContext, psDecl, texName, false, false);
oss << texName << " [[ texture(" << slot << ") ]]";
m_StructDefinitions[""].m_Members.push_back(oss.str());
psContext->m_Reflection.OnTextureBinding(texName, slot, TD_2D, false); //TODO: correct HLSLCC_TEX_DIMENSION?
break;
break;*/
}
default:
@ -1816,7 +2055,6 @@ void ToMetal::DeclareResource(const Declaration *psDecl)
void ToMetal::DeclareOutput(const Declaration *psDecl)
{
bstring glsl = *psContext->currentGLSLString;
Shader* psShader = psContext->psShader;
if (!psContext->OutputNeedsDeclaring(&psDecl->asOperands[0], 1))
@ -1934,7 +2172,8 @@ void ToMetal::DeclareOutput(const Declaration *psDecl)
default:
{
std::ostringstream oss;
oss << type << " " << name << " [[ color(" << psSignature->ui32SemanticIndex << ") ]]";
oss << type << " " << name << " [[ color(xlt_remap_o[" << psSignature->ui32SemanticIndex << "]) ]]";
m_NeedFBOutputRemapDecl = true;
m_StructDefinitions[GetOutputStructName()].m_Members.push_back(oss.str());
}
}

View File

@ -111,7 +111,7 @@ void ToMetal::AddOpAssignToDestWithMask(const Operand* psDest,
case SVT_FLOAT:
case SVT_FLOAT10:
case SVT_FLOAT16:
ASSERT(eSrcType != SVT_INT12 || eSrcType != SVT_INT16 && eSrcType != SVT_UINT16);
ASSERT(eSrcType != SVT_INT12 || (eSrcType != SVT_INT16 && eSrcType != SVT_UINT16));
if (psContext->psShader->ui32MajorVersion > 3)
{
if (ui32DestElementCount > 1)
@ -646,7 +646,6 @@ void ToMetal::TranslateTexelFetch(
bstring glsl)
{
int numParenthesis = 0;
uint32_t destCount = psInst->asOperands[0].GetNumSwizzleElements();
psContext->AddIndentation();
AddAssignToDest(&psInst->asOperands[0], psContext->psShader->sInfo.GetTextureDataType(psInst->asOperands[2].ui32RegisterNumber), 4, &numParenthesis);
glsl << TranslateOperand(&psInst->asOperands[2], TO_FLAG_NONE);
@ -714,7 +713,7 @@ void ToMetal::TranslateTexelFetch(
}
bcatcstr(glsl, ")");
AddSwizzleUsingElementCount(glsl, destCount);
glsl << TranslateOperandSwizzle(&psInst->asOperands[2], psInst->asOperands[0].GetAccessMask(), 0);
AddAssignPrologue(numParenthesis);
}
@ -724,7 +723,6 @@ void ToMetal::TranslateTexelFetchOffset(
bstring glsl)
{
int numParenthesis = 0;
uint32_t destCount = psInst->asOperands[0].GetNumSwizzleElements();
psContext->AddIndentation();
AddAssignToDest(&psInst->asOperands[0], psContext->psShader->sInfo.GetTextureDataType(psInst->asOperands[2].ui32RegisterNumber), 4, &numParenthesis);
@ -799,7 +797,7 @@ void ToMetal::TranslateTexelFetchOffset(
}
bcatcstr(glsl, ")");
AddSwizzleUsingElementCount(glsl, destCount);
glsl << TranslateOperandSwizzle(&psInst->asOperands[2], psInst->asOperands[0].GetAccessMask(), 0);
AddAssignPrologue(numParenthesis);
}
@ -813,6 +811,7 @@ void ToMetal::TranslateTexCoord(
{
uint32_t flags = TO_AUTO_BITCAST_TO_FLOAT;
uint32_t opMask = OPERAND_4_COMPONENT_MASK_ALL;
bool isArray = false;
switch (eResDim)
{
@ -822,8 +821,21 @@ void ToMetal::TranslateTexCoord(
opMask = OPERAND_4_COMPONENT_MASK_X;
break;
}
case RESOURCE_DIMENSION_TEXTURE2D:
case RESOURCE_DIMENSION_TEXTURE1DARRAY:
{
// x for coord, y for array element
opMask = OPERAND_4_COMPONENT_MASK_X;
bstring glsl = *psContext->currentGLSLString;
glsl << TranslateOperand(psTexCoordOperand, flags, opMask);
bcatcstr(glsl, ", round(");
opMask = OPERAND_4_COMPONENT_MASK_Y;
flags = TO_AUTO_BITCAST_TO_FLOAT;
isArray = true;
break;
}
case RESOURCE_DIMENSION_TEXTURE2D:
{
//Vec2 texcoord. Mask out the other components.
opMask = OPERAND_4_COMPONENT_MASK_X | OPERAND_4_COMPONENT_MASK_Y;
@ -840,22 +852,34 @@ void ToMetal::TranslateTexCoord(
}
case RESOURCE_DIMENSION_TEXTURE2DARRAY:
{
// xy for coord, z for array element
opMask = OPERAND_4_COMPONENT_MASK_X | OPERAND_4_COMPONENT_MASK_Y;
flags |= TO_AUTO_EXPAND_TO_VEC2;
bstring glsl = *psContext->currentGLSLString;
glsl << TranslateOperand(psTexCoordOperand, flags, opMask);
bcatcstr(glsl, ", ");
bcatcstr(glsl, ", round(");
opMask = OPERAND_4_COMPONENT_MASK_Z;
flags = TO_AUTO_BITCAST_TO_FLOAT;
isArray = true;
break;
}
case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
{
flags |= TO_AUTO_EXPAND_TO_VEC4;
// xyz for coord, w for array element
opMask = OPERAND_4_COMPONENT_MASK_X | OPERAND_4_COMPONENT_MASK_Y | OPERAND_4_COMPONENT_MASK_Z;
flags |= TO_AUTO_EXPAND_TO_VEC3;
bstring glsl = *psContext->currentGLSLString;
glsl << TranslateOperand(psTexCoordOperand, flags, opMask);
bcatcstr(glsl, ", round(");
opMask = OPERAND_4_COMPONENT_MASK_W;
flags = TO_AUTO_BITCAST_TO_FLOAT;
isArray = true;
break;
}
default:
@ -868,6 +892,10 @@ void ToMetal::TranslateTexCoord(
//FIXME detect when integer coords are needed.
bstring glsl = *psContext->currentGLSLString;
glsl << TranslateOperand(psTexCoordOperand, flags, opMask);
if (isArray)
bcatcstr(glsl, ")");
}
void ToMetal::GetResInfoData(Instruction* psInst, int index, int destElem)
@ -875,12 +903,11 @@ void ToMetal::GetResInfoData(Instruction* psInst, int index, int destElem)
bstring glsl = *psContext->currentGLSLString;
int numParenthesis = 0;
const RESINFO_RETURN_TYPE eResInfoReturnType = psInst->eResInfoReturnType;
const int isUAV = (psInst->asOperands[2].eType == OPERAND_TYPE_UNORDERED_ACCESS_VIEW);
psContext->AddIndentation();
AddOpAssignToDestWithMask(&psInst->asOperands[0], eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_UINT ? SVT_UINT : SVT_FLOAT, 1, "=", &numParenthesis, 1 << destElem);
const char *metalGetters[] = { ".get_width()", ".get_height()", ".get_depth()", ".get_num_mip_levels()" };
const char *metalGetters[] = { ".get_width(", ".get_height(", ".get_depth(", ".get_num_mip_levels()" };
int dim = GetNumTextureDimensions(psInst->eResDim);
if (dim < (index + 1) && index != 3)
{
@ -899,17 +926,25 @@ void ToMetal::GetResInfoData(Instruction* psInst, int index, int destElem)
numParenthesis++;
}
glsl << TranslateOperand(&psInst->asOperands[2], TO_FLAG_NONE);
if (index == 2 &&
(psInst->eResDim == RESOURCE_DIMENSION_TEXTURE1DARRAY ||
psInst->eResDim == RESOURCE_DIMENSION_TEXTURE2DARRAY ||
psInst->eResDim == RESOURCE_DIMENSION_TEXTURE2DMSARRAY))
if ((index == 1 && psInst->eResDim == RESOURCE_DIMENSION_TEXTURE1DARRAY) ||
(index == 2 && (psInst->eResDim == RESOURCE_DIMENSION_TEXTURE2DARRAY ||
psInst->eResDim == RESOURCE_DIMENSION_TEXTURE2DMSARRAY)))
{
bcatcstr(glsl, ".get_array_size()");
}
else
{
bcatcstr(glsl, metalGetters[index]);
// TODO Metal has no way to query for info on lower mip levels, now always returns info for highest.
if (index < 3)
{
if (psInst->eResDim != RESOURCE_DIMENSION_TEXTURE2DMS &&
psInst->eResDim != RESOURCE_DIMENSION_TEXTURE2DMSARRAY)
glsl << TranslateOperand(&psInst->asOperands[1], TO_FLAG_INTEGER); //mip level
bcatcstr(glsl, ")");
}
}
}
AddAssignPrologue(numParenthesis);
}
@ -933,7 +968,6 @@ void ToMetal::TranslateTextureSample(Instruction* psInst,
Operand* psSrcBias = (ui32Flags & TEXSMP_FLAG_BIAS) ? &psInst->asOperands[4] : 0;
const char *funcName = "";
const char* offset = "";
const char* gradSwizzle = "";
const char *gradientName = "";
@ -1165,7 +1199,6 @@ void ToMetal::TranslateTextureSample(Instruction* psInst,
AddAssignPrologue(numParenthesis);
}
static const char* swizzleString[] = { ".x", ".y", ".z", ".w" };
// Handle cases where vector components are accessed with dynamic index ([] notation).
// A bit ugly hack because compiled HLSL uses byte offsets to access data in structs => we are converting
@ -1212,6 +1245,7 @@ void ToMetal::TranslateShaderStorageStore(Instruction* psInst)
break;
case OPCODE_STORE_RAW:
case OPCODE_STORE_UAV_TYPED: // Hack typed buffer as raw buf
psDest = &psInst->asOperands[0];
psDestByteOff = &psInst->asOperands[1];
psSrc = &psInst->asOperands[2];
@ -1243,18 +1277,24 @@ void ToMetal::TranslateShaderStorageStore(Instruction* psInst)
bcatcstr(glsl, "[(");
glsl << TranslateOperand(psDestByteOff, dstOffFlag);
bcatcstr(glsl, " >> 2");
if (dstOffFlag == TO_FLAG_UNSIGNED_INTEGER)
bcatcstr(glsl, "u");
bcatcstr(glsl, ")");
if (component != 0)
if (psInst->eOpcode == OPCODE_STORE_UAV_TYPED)
{
bformata(glsl, " + %d", component);
bcatcstr(glsl, ")");
}
else
{
bcatcstr(glsl, " >> 2");
if (dstOffFlag == TO_FLAG_UNSIGNED_INTEGER)
bcatcstr(glsl, "u");
}
bcatcstr(glsl, ")");
if (component != 0)
{
bformata(glsl, " + %d", component);
if (dstOffFlag == TO_FLAG_UNSIGNED_INTEGER)
bcatcstr(glsl, "u");
}
}
bcatcstr(glsl, "]");
//Dest type is currently always a uint array.
@ -1287,6 +1327,7 @@ void ToMetal::TranslateShaderStorageLoad(Instruction* psInst)
psSrc = &psInst->asOperands[3];
break;
case OPCODE_LD_RAW:
case OPCODE_LD_UAV_TYPED: // Hack typed buffer as raw buf
psDest = &psInst->asOperands[0];
psSrcByteOff = &psInst->asOperands[1];
psSrc = &psInst->asOperands[2];
@ -1348,14 +1389,20 @@ void ToMetal::TranslateShaderStorageLoad(Instruction* psInst)
}
bcatcstr(glsl, "[(");
glsl << TranslateOperand(psSrcByteOff, srcOffFlag);
bcatcstr(glsl, " >> 2");
if (srcOffFlag == TO_FLAG_UNSIGNED_INTEGER)
bcatcstr(glsl, "u");
bformata(glsl, ") + %d", psSrc->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE ? psSrc->aui32Swizzle[component] : component);
if (srcOffFlag == TO_FLAG_UNSIGNED_INTEGER)
bcatcstr(glsl, "u");
if (psInst->eOpcode == OPCODE_LD_UAV_TYPED)
{
bcatcstr(glsl, ")");
}
else
{
bcatcstr(glsl, " >> 2");
if (srcOffFlag == TO_FLAG_UNSIGNED_INTEGER)
bcatcstr(glsl, "u");
bformata(glsl, ") + %d", psSrc->eSelMode == OPERAND_4_COMPONENT_SWIZZLE_MODE ? psSrc->aui32Swizzle[component] : component);
if (srcOffFlag == TO_FLAG_UNSIGNED_INTEGER)
bcatcstr(glsl, "u");
}
bcatcstr(glsl, "]");
if (addedBitcast)
@ -1635,9 +1682,9 @@ void ToMetal::TranslateAtomicMemOp(Instruction* psInst)
psContext->AddIndentation();
const ResourceBinding* psBinding = 0;
if (dest->eType != OPERAND_TYPE_THREAD_GROUP_SHARED_MEMORY)
{
const ResourceBinding* psBinding = 0;
psContext->psShader->sInfo.GetResourceFromBindingPoint(RGROUP_UAV, dest->ui32RegisterNumber, &psBinding);
if (psBinding->eType == RTYPE_UAV_RWTYPED)
@ -1662,6 +1709,8 @@ void ToMetal::TranslateAtomicMemOp(Instruction* psInst)
case REFLECT_RESOURCE_DIMENSION_TEXTURECUBEARRAY:
texDim = 3;
break;
case REFLECT_RESOURCE_DIMENSION_BUFFER: // Hack typed buffer as raw buf
break;
default:
ASSERT(0);
break;
@ -1683,14 +1732,14 @@ void ToMetal::TranslateAtomicMemOp(Instruction* psInst)
if (shouldExtractCompare)
{
bcatcstr(glsl, "{\n");
psContext->AddIndentation();
++psContext->indent;
psContext->AddIndentation();
bcatcstr(glsl, "uint compare_value = ");
glsl << TranslateOperand(compare, ui32DataTypeFlag);
bcatcstr(glsl, "; ");
bcatcstr(glsl, ";\n");
psContext->AddIndentation();
}
if (previousValue)
else if (previousValue)
AddAssignToDest(previousValue, isUint ? SVT_UINT : SVT_INT, 1, &numParenthesis);
bcatcstr(glsl, func);
@ -1709,18 +1758,20 @@ void ToMetal::TranslateAtomicMemOp(Instruction* psInst)
bcatcstr(glsl, "[");
glsl << TranslateOperand(destAddr, destAddrFlag, OPERAND_4_COMPONENT_MASK_X);
// Structured buf if we have both x & y swizzles. Raw buf has only x -> no .value[]
if (destAddr->GetNumSwizzleElements(OPERAND_4_COMPONENT_MASK_X | OPERAND_4_COMPONENT_MASK_Y) == 2)
if (!psBinding || psBinding->eType != RTYPE_UAV_RWTYPED)
{
bcatcstr(glsl, "]");
bcatcstr(glsl, ".value[");
glsl << TranslateOperand(destAddr, destAddrFlag, OPERAND_4_COMPONENT_MASK_Y);
}
bcatcstr(glsl, " >> 2");//bytes to floats
if (destAddrFlag == TO_FLAG_UNSIGNED_INTEGER)
bcatcstr(glsl, "u");
// Structured buf if we have both x & y swizzles. Raw buf has only x -> no .value[]
if (destAddr->GetNumSwizzleElements(OPERAND_4_COMPONENT_MASK_X | OPERAND_4_COMPONENT_MASK_Y) == 2)
{
bcatcstr(glsl, "]");
bcatcstr(glsl, ".value[");
glsl << TranslateOperand(destAddr, destAddrFlag, OPERAND_4_COMPONENT_MASK_Y);
}
bcatcstr(glsl, " >> 2");//bytes to floats
if (destAddrFlag == TO_FLAG_UNSIGNED_INTEGER)
bcatcstr(glsl, "u");
}
bcatcstr(glsl, "]), ");
if (compare)
@ -1750,6 +1801,14 @@ void ToMetal::TranslateAtomicMemOp(Instruction* psInst)
if (shouldExtractCompare)
{
if (previousValue)
{
psContext->AddIndentation();
AddAssignToDest(previousValue, SVT_UINT, 1, &numParenthesis);
bcatcstr(glsl, "compare_value");
AddAssignPrologue(numParenthesis);
}
--psContext->indent;
psContext->AddIndentation();
bcatcstr(glsl, "}\n");
}
@ -1834,8 +1893,9 @@ void ToMetal::TranslateInstruction(Instruction* psInst)
int numParenthesis = 0;
#ifdef _DEBUG
psContext->AddIndentation();
bformata(glsl, "//Instruction %d\n", psInst->id);
// Uncomment to print instruction IDs
//psContext->AddIndentation();
//bformata(glsl, "//Instruction %d\n", psInst->id);
#if 0
if(psInst->id == 73)
{
@ -2003,7 +2063,6 @@ void ToMetal::TranslateInstruction(Instruction* psInst)
psContext->AddIndentation();
bcatcstr(glsl, "//OR\n");
#endif
uint32_t destMask = psInst->asOperands[0].GetAccessMask();
if (psInst->asOperands[0].GetDataType(psContext) == SVT_BOOL)
{
uint32_t destMask = psInst->asOperands[0].GetAccessMask();
@ -3010,6 +3069,16 @@ void ToMetal::TranslateInstruction(Instruction* psInst)
#endif
psContext->psShader->sInfo.GetResourceFromBindingPoint(RGROUP_TEXTURE, psInst->asOperands[2].ui32RegisterNumber, &psBinding);
if (psInst->eResDim == RESOURCE_DIMENSION_BUFFER) // Hack typed buffer as raw buf
{
psInst->eOpcode = OPCODE_LD_UAV_TYPED;
psInst->asOperands[1].eSelMode = OPERAND_4_COMPONENT_SELECT_1_MODE;
if (psInst->asOperands[1].eType == OPERAND_TYPE_IMMEDIATE32)
psInst->asOperands[1].iNumComponents = 1;
TranslateShaderStorageLoad(psInst);
break;
}
if (psInst->bAddressOffset)
{
@ -3153,6 +3222,20 @@ void ToMetal::TranslateInstruction(Instruction* psInst)
Operand* psSrc = &psInst->asOperands[2];
Operand* psSrcAddr = &psInst->asOperands[1];
const ResourceBinding* psRes = 0;
psContext->psShader->sInfo.GetResourceFromBindingPoint(RGROUP_UAV, psSrc->ui32RegisterNumber, &psRes);
SHADER_VARIABLE_TYPE srcDataType = ResourceReturnTypeToSVTType(psRes->ui32ReturnType, psRes->ePrecision);
if (psInst->eResDim == RESOURCE_DIMENSION_BUFFER) // Hack typed buffer as raw buf
{
psSrc->aeDataType[0] = srcDataType;
psSrcAddr->eSelMode = OPERAND_4_COMPONENT_SELECT_1_MODE;
if (psSrcAddr->eType == OPERAND_TYPE_IMMEDIATE32)
psSrcAddr->iNumComponents = 1;
TranslateShaderStorageLoad(psInst);
break;
}
int srcCount = psSrc->GetNumSwizzleElements();
int numParenthesis = 0;
uint32_t compMask = 0;
@ -3177,25 +3260,6 @@ void ToMetal::TranslateInstruction(Instruction* psInst)
break;
}
SHADER_VARIABLE_TYPE srcDataType;
const ResourceBinding* psBinding = 0;
psContext->psShader->sInfo.GetResourceFromBindingPoint(RGROUP_UAV, psSrc->ui32RegisterNumber, &psBinding);
switch (psBinding->ui32ReturnType)
{
case RETURN_TYPE_FLOAT:
srcDataType = SVT_FLOAT;
break;
case RETURN_TYPE_SINT:
srcDataType = SVT_INT;
break;
case RETURN_TYPE_UINT:
srcDataType = SVT_UINT;
break;
default:
ASSERT(0);
break;
}
psContext->AddIndentation();
AddAssignToDest(psDest, srcDataType, srcCount, &numParenthesis);
glsl << TranslateOperand(psSrc, TO_FLAG_NAME_ONLY);
@ -3235,14 +3299,23 @@ void ToMetal::TranslateInstruction(Instruction* psInst)
psContext->AddIndentation();
bcatcstr(glsl, "//STORE_UAV_TYPED\n");
#endif
psContext->AddIndentation();
foundResource = psContext->psShader->sInfo.GetResourceFromBindingPoint(RGROUP_UAV,
psInst->asOperands[0].ui32RegisterNumber,
&psRes);
ASSERT(foundResource);
if (psRes->eDimension == REFLECT_RESOURCE_DIMENSION_BUFFER) // Hack typed buffer as raw buf
{
psInst->asOperands[0].aeDataType[0] = ResourceReturnTypeToSVTType(psRes->ui32ReturnType, psRes->ePrecision);
psInst->asOperands[1].eSelMode = OPERAND_4_COMPONENT_SELECT_1_MODE;
if (psInst->asOperands[1].eType == OPERAND_TYPE_IMMEDIATE32)
psInst->asOperands[1].iNumComponents = 1;
TranslateShaderStorageStore(psInst);
break;
}
psContext->AddIndentation();
glsl << TranslateOperand(&psInst->asOperands[0], TO_FLAG_NAME_ONLY);
bcatcstr(glsl, ".write(");
@ -3684,6 +3757,21 @@ template <int N> vec<int, N> bitFieldExtractI(const vec<uint, N> width, const ve
psContext->m_Reflection.OnDiagnostics("Metal shading language does not support buffer size query from shader. Pass the size to shader as const instead.\n", 0, false); // TODO: change this into error after modifying gfx-test 450
break;
}
case OPCODE_SAMPLE_INFO:
{
#ifdef _DEBUG
psContext->AddIndentation();
bcatcstr(glsl, "//SAMPLE_INFO\n");
#endif
const RESINFO_RETURN_TYPE eResInfoReturnType = psInst->eResInfoReturnType;
psContext->AddIndentation();
AddAssignToDest(&psInst->asOperands[0], eResInfoReturnType == RESINFO_INSTRUCTION_RETURN_UINT ? SVT_UINT : SVT_FLOAT, 1, &numParenthesis);
TranslateOperand(&psInst->asOperands[1], TO_FLAG_NAME_ONLY);
bcatcstr(glsl, ".get_num_samples()");
AddAssignPrologue(numParenthesis);
break;
}
case OPCODE_DMAX:
case OPCODE_DMIN:

View File

@ -14,7 +14,11 @@
using namespace HLSLcc;
#ifdef _MSC_VER
#if _MSC_VER < 1900
#define snprintf _snprintf
#endif
#define fpcheck(x) (_isnan(x) || !_finite(x))
#else
#define fpcheck(x) (std::isnan(x) || std::isinf(x))
@ -379,6 +383,7 @@ std::string ToMetal::TranslateVariableName(const Operand* psOperand, uint32_t ui
((Operand *)psOperand)->aeDataType[3] = requestedType;
}
bool bitcast = false;
if (AreTypesCompatible(eType, ui32TOFlag) == 0)
{
if (CanDoDirectCast(eType, requestedType))
@ -394,15 +399,16 @@ std::string ToMetal::TranslateVariableName(const Operand* psOperand, uint32_t ui
// Direct cast not possible, need to do bitcast.
oss << "as_type<"<< GetConstructorForTypeMetal(requestedType, requestedComponents) << ">(";
hasCtor = 1;
bitcast = true;
numParenthesis++;
}
}
// Add ctor if needed (upscaling). Type conversion is already handled above, so here we must
// use the original type to not make type conflicts in bitcasts
if (((numComponents < requestedComponents)||(scalarWithSwizzle != 0)) && (hasCtor == 0))
if (((numComponents < requestedComponents)||(scalarWithSwizzle != 0)) && (hasCtor == 0 || bitcast))
{
oss << GetConstructorForType(psContext, requestedType, requestedComponents, false) << "(";
oss << GetConstructorForType(psContext, eType, requestedComponents, false) << "(";
numParenthesis++;
hasCtor = 1;
@ -623,7 +629,7 @@ std::string ToMetal::TranslateVariableName(const Operand* psOperand, uint32_t ui
const ShaderVarType* psVarType = NULL;
int32_t index = -1;
std::vector<uint32_t> arrayIndices;
bool isArray;
bool isArray = false;
psContext->psShader->sInfo.GetConstantBufferFromBindingPoint(RGROUP_CBUFFER, psOperand->aui32ArraySizes[0], &psCBuf);
ASSERT(psCBuf != NULL);
@ -644,6 +650,9 @@ std::string ToMetal::TranslateVariableName(const Operand* psOperand, uint32_t ui
cbName = psCBuf->name;
}
cbName += ".";
// Drop the constant buffer name from subpass inputs
if (cbName.substr(0, 19) == "hlslcc_SubpassInput")
cbName = "";
}
if((ui32TOFlag & TO_FLAG_DECLARATION_NAME) != TO_FLAG_DECLARATION_NAME)