mirror of
https://github.com/love2d/love.git
synced 2026-08-19 12:14:20 +02:00
Update spirv-cross
This commit is contained in:
@@ -54,11 +54,11 @@
|
|||||||
typedef unsigned int SpvId;
|
typedef unsigned int SpvId;
|
||||||
|
|
||||||
#define SPV_VERSION 0x10500
|
#define SPV_VERSION 0x10500
|
||||||
#define SPV_REVISION 1
|
#define SPV_REVISION 3
|
||||||
|
|
||||||
static const unsigned int SpvMagicNumber = 0x07230203;
|
static const unsigned int SpvMagicNumber = 0x07230203;
|
||||||
static const unsigned int SpvVersion = 0x00010500;
|
static const unsigned int SpvVersion = 0x00010500;
|
||||||
static const unsigned int SpvRevision = 1;
|
static const unsigned int SpvRevision = 3;
|
||||||
static const unsigned int SpvOpCodeMask = 0xffff;
|
static const unsigned int SpvOpCodeMask = 0xffff;
|
||||||
static const unsigned int SpvWordCountShift = 16;
|
static const unsigned int SpvWordCountShift = 16;
|
||||||
|
|
||||||
@@ -1899,6 +1899,13 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy
|
|||||||
case SpvOpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break;
|
case SpvOpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
case SpvOpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break;
|
case SpvOpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
case SpvOpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break;
|
case SpvOpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpTypeRayQueryProvisionalKHR: *hasResult = true; *hasResultType = false; break;
|
||||||
|
case SpvOpRayQueryInitializeKHR: *hasResult = false; *hasResultType = false; break;
|
||||||
|
case SpvOpRayQueryTerminateKHR: *hasResult = false; *hasResultType = false; break;
|
||||||
|
case SpvOpRayQueryGenerateIntersectionKHR: *hasResult = false; *hasResultType = false; break;
|
||||||
|
case SpvOpRayQueryConfirmIntersectionKHR: *hasResult = false; *hasResultType = false; break;
|
||||||
|
case SpvOpRayQueryProceedKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetIntersectionTypeKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
case SpvOpGroupIAddNonUniformAMD: *hasResult = true; *hasResultType = true; break;
|
case SpvOpGroupIAddNonUniformAMD: *hasResult = true; *hasResultType = true; break;
|
||||||
case SpvOpGroupFAddNonUniformAMD: *hasResult = true; *hasResultType = true; break;
|
case SpvOpGroupFAddNonUniformAMD: *hasResult = true; *hasResultType = true; break;
|
||||||
case SpvOpGroupFMinNonUniformAMD: *hasResult = true; *hasResultType = true; break;
|
case SpvOpGroupFMinNonUniformAMD: *hasResult = true; *hasResultType = true; break;
|
||||||
@@ -1918,30 +1925,6 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy
|
|||||||
case SpvOpTerminateRayNV: *hasResult = false; *hasResultType = false; break;
|
case SpvOpTerminateRayNV: *hasResult = false; *hasResultType = false; break;
|
||||||
case SpvOpTraceNV: *hasResult = false; *hasResultType = false; break;
|
case SpvOpTraceNV: *hasResult = false; *hasResultType = false; break;
|
||||||
case SpvOpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break;
|
case SpvOpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break;
|
||||||
case SpvOpTypeRayQueryProvisionalKHR: *hasResult = true; *hasResultType = false; break;
|
|
||||||
case SpvOpRayQueryInitializeKHR: *hasResult = false; *hasResultType = false; break;
|
|
||||||
case SpvOpRayQueryTerminateKHR: *hasResult = false; *hasResultType = false; break;
|
|
||||||
case SpvOpRayQueryGenerateIntersectionKHR: *hasResult = false; *hasResultType = false; break;
|
|
||||||
case SpvOpRayQueryConfirmIntersectionKHR: *hasResult = false; *hasResultType = false; break;
|
|
||||||
case SpvOpRayQueryProceedKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetIntersectionTypeKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetRayTMinKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetRayFlagsKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetIntersectionTKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetIntersectionInstanceCustomIndexKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetIntersectionInstanceIdKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetIntersectionGeometryIndexKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetIntersectionPrimitiveIndexKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetIntersectionBarycentricsKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetIntersectionFrontFaceKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetIntersectionCandidateAABBOpaqueKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetIntersectionObjectRayDirectionKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetIntersectionObjectRayOriginKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetWorldRayDirectionKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetWorldRayOriginKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetIntersectionObjectToWorldKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpRayQueryGetIntersectionWorldToObjectKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case SpvOpExecuteCallableNV: *hasResult = false; *hasResultType = false; break;
|
case SpvOpExecuteCallableNV: *hasResult = false; *hasResultType = false; break;
|
||||||
case SpvOpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break;
|
case SpvOpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break;
|
||||||
case SpvOpCooperativeMatrixLoadNV: *hasResult = true; *hasResultType = true; break;
|
case SpvOpCooperativeMatrixLoadNV: *hasResult = true; *hasResultType = true; break;
|
||||||
@@ -2096,6 +2079,23 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy
|
|||||||
case SpvOpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break;
|
case SpvOpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break;
|
||||||
case SpvOpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break;
|
case SpvOpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break;
|
||||||
case SpvOpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break;
|
case SpvOpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetRayTMinKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetRayFlagsKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetIntersectionTKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetIntersectionInstanceCustomIndexKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetIntersectionInstanceIdKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetIntersectionGeometryIndexKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetIntersectionPrimitiveIndexKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetIntersectionBarycentricsKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetIntersectionFrontFaceKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetIntersectionCandidateAABBOpaqueKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetIntersectionObjectRayDirectionKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetIntersectionObjectRayOriginKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetWorldRayDirectionKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetWorldRayOriginKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetIntersectionObjectToWorldKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case SpvOpRayQueryGetIntersectionWorldToObjectKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* SPV_ENABLE_UTILITY_CODE */
|
#endif /* SPV_ENABLE_UTILITY_CODE */
|
||||||
|
|||||||
@@ -50,11 +50,11 @@ namespace spv {
|
|||||||
typedef unsigned int Id;
|
typedef unsigned int Id;
|
||||||
|
|
||||||
#define SPV_VERSION 0x10500
|
#define SPV_VERSION 0x10500
|
||||||
#define SPV_REVISION 1
|
#define SPV_REVISION 3
|
||||||
|
|
||||||
static const unsigned int MagicNumber = 0x07230203;
|
static const unsigned int MagicNumber = 0x07230203;
|
||||||
static const unsigned int Version = 0x00010500;
|
static const unsigned int Version = 0x00010500;
|
||||||
static const unsigned int Revision = 1;
|
static const unsigned int Revision = 3;
|
||||||
static const unsigned int OpCodeMask = 0xffff;
|
static const unsigned int OpCodeMask = 0xffff;
|
||||||
static const unsigned int WordCountShift = 16;
|
static const unsigned int WordCountShift = 16;
|
||||||
|
|
||||||
@@ -1895,6 +1895,13 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) {
|
|||||||
case OpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break;
|
case OpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
case OpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break;
|
case OpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
case OpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break;
|
case OpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpTypeRayQueryProvisionalKHR: *hasResult = true; *hasResultType = false; break;
|
||||||
|
case OpRayQueryInitializeKHR: *hasResult = false; *hasResultType = false; break;
|
||||||
|
case OpRayQueryTerminateKHR: *hasResult = false; *hasResultType = false; break;
|
||||||
|
case OpRayQueryGenerateIntersectionKHR: *hasResult = false; *hasResultType = false; break;
|
||||||
|
case OpRayQueryConfirmIntersectionKHR: *hasResult = false; *hasResultType = false; break;
|
||||||
|
case OpRayQueryProceedKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetIntersectionTypeKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
case OpGroupIAddNonUniformAMD: *hasResult = true; *hasResultType = true; break;
|
case OpGroupIAddNonUniformAMD: *hasResult = true; *hasResultType = true; break;
|
||||||
case OpGroupFAddNonUniformAMD: *hasResult = true; *hasResultType = true; break;
|
case OpGroupFAddNonUniformAMD: *hasResult = true; *hasResultType = true; break;
|
||||||
case OpGroupFMinNonUniformAMD: *hasResult = true; *hasResultType = true; break;
|
case OpGroupFMinNonUniformAMD: *hasResult = true; *hasResultType = true; break;
|
||||||
@@ -1914,30 +1921,6 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) {
|
|||||||
case OpTerminateRayNV: *hasResult = false; *hasResultType = false; break;
|
case OpTerminateRayNV: *hasResult = false; *hasResultType = false; break;
|
||||||
case OpTraceNV: *hasResult = false; *hasResultType = false; break;
|
case OpTraceNV: *hasResult = false; *hasResultType = false; break;
|
||||||
case OpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break;
|
case OpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break;
|
||||||
case OpTypeRayQueryProvisionalKHR: *hasResult = true; *hasResultType = false; break;
|
|
||||||
case OpRayQueryInitializeKHR: *hasResult = false; *hasResultType = false; break;
|
|
||||||
case OpRayQueryTerminateKHR: *hasResult = false; *hasResultType = false; break;
|
|
||||||
case OpRayQueryGenerateIntersectionKHR: *hasResult = false; *hasResultType = false; break;
|
|
||||||
case OpRayQueryConfirmIntersectionKHR: *hasResult = false; *hasResultType = false; break;
|
|
||||||
case OpRayQueryProceedKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetIntersectionTypeKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetRayTMinKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetRayFlagsKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetIntersectionTKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetIntersectionInstanceCustomIndexKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetIntersectionInstanceIdKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetIntersectionGeometryIndexKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetIntersectionPrimitiveIndexKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetIntersectionBarycentricsKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetIntersectionFrontFaceKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetIntersectionCandidateAABBOpaqueKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetIntersectionObjectRayDirectionKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetIntersectionObjectRayOriginKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetWorldRayDirectionKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetWorldRayOriginKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetIntersectionObjectToWorldKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpRayQueryGetIntersectionWorldToObjectKHR: *hasResult = true; *hasResultType = true; break;
|
|
||||||
case OpExecuteCallableNV: *hasResult = false; *hasResultType = false; break;
|
case OpExecuteCallableNV: *hasResult = false; *hasResultType = false; break;
|
||||||
case OpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break;
|
case OpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break;
|
||||||
case OpCooperativeMatrixLoadNV: *hasResult = true; *hasResultType = true; break;
|
case OpCooperativeMatrixLoadNV: *hasResult = true; *hasResultType = true; break;
|
||||||
@@ -2092,6 +2075,23 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) {
|
|||||||
case OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break;
|
case OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break;
|
||||||
case OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break;
|
case OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break;
|
||||||
case OpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break;
|
case OpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetRayTMinKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetRayFlagsKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetIntersectionTKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetIntersectionInstanceCustomIndexKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetIntersectionInstanceIdKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetIntersectionGeometryIndexKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetIntersectionPrimitiveIndexKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetIntersectionBarycentricsKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetIntersectionFrontFaceKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetIntersectionCandidateAABBOpaqueKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetIntersectionObjectRayDirectionKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetIntersectionObjectRayOriginKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetWorldRayDirectionKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetWorldRayOriginKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetIntersectionObjectToWorldKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
|
case OpRayQueryGetIntersectionWorldToObjectKHR: *hasResult = true; *hasResultType = true; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* SPV_ENABLE_UTILITY_CODE */
|
#endif /* SPV_ENABLE_UTILITY_CODE */
|
||||||
|
|||||||
@@ -558,11 +558,16 @@ struct SPIRType : IVariant
|
|||||||
// Keep track of how many pointer layers we have.
|
// Keep track of how many pointer layers we have.
|
||||||
uint32_t pointer_depth = 0;
|
uint32_t pointer_depth = 0;
|
||||||
bool pointer = false;
|
bool pointer = false;
|
||||||
|
bool forward_pointer = false;
|
||||||
|
|
||||||
spv::StorageClass storage = spv::StorageClassGeneric;
|
spv::StorageClass storage = spv::StorageClassGeneric;
|
||||||
|
|
||||||
SmallVector<TypeID> member_types;
|
SmallVector<TypeID> member_types;
|
||||||
|
|
||||||
|
// If member order has been rewritten to handle certain scenarios with Offset,
|
||||||
|
// allow codegen to rewrite the index.
|
||||||
|
SmallVector<uint32_t> member_type_index_redirection;
|
||||||
|
|
||||||
struct ImageType
|
struct ImageType
|
||||||
{
|
{
|
||||||
TypeID type;
|
TypeID type;
|
||||||
@@ -776,7 +781,7 @@ struct SPIRBlock : IVariant
|
|||||||
ComplexLoop
|
ComplexLoop
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum : uint32_t
|
||||||
{
|
{
|
||||||
NoDominator = 0xffffffffu
|
NoDominator = 0xffffffffu
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1659,6 +1659,13 @@ size_t Compiler::get_declared_struct_member_size(const SPIRType &struct_type, ui
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type.pointer && type.storage == StorageClassPhysicalStorageBuffer)
|
||||||
|
{
|
||||||
|
// Check if this is a top-level pointer type, and not an array of pointers.
|
||||||
|
if (type.pointer_depth > get<SPIRType>(type.parent_type).pointer_depth)
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
if (!type.array.empty())
|
if (!type.array.empty())
|
||||||
{
|
{
|
||||||
// For arrays, we can use ArrayStride to get an easy check.
|
// For arrays, we can use ArrayStride to get an easy check.
|
||||||
@@ -4204,19 +4211,22 @@ Bitset Compiler::combined_decoration_for_member(const SPIRType &type, uint32_t i
|
|||||||
|
|
||||||
if (type_meta)
|
if (type_meta)
|
||||||
{
|
{
|
||||||
auto &memb = type_meta->members;
|
auto &members = type_meta->members;
|
||||||
if (index >= memb.size())
|
if (index >= members.size())
|
||||||
return flags;
|
return flags;
|
||||||
auto &dec = memb[index];
|
auto &dec = members[index];
|
||||||
|
|
||||||
// If our type is a struct, traverse all the members as well recursively.
|
|
||||||
flags.merge_or(dec.decoration_flags);
|
flags.merge_or(dec.decoration_flags);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < type.member_types.size(); i++)
|
auto &member_type = get<SPIRType>(type.member_types[index]);
|
||||||
|
|
||||||
|
// If our member type is a struct, traverse all the child members as well recursively.
|
||||||
|
auto &member_childs = member_type.member_types;
|
||||||
|
for (uint32_t i = 0; i < member_childs.size(); i++)
|
||||||
{
|
{
|
||||||
auto &memb_type = get<SPIRType>(type.member_types[i]);
|
auto &child_member_type = get<SPIRType>(member_childs[i]);
|
||||||
if (!memb_type.pointer)
|
if (!child_member_type.pointer)
|
||||||
flags.merge_or(combined_decoration_for_member(memb_type, i));
|
flags.merge_or(combined_decoration_for_member(member_type, i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4634,6 +4644,12 @@ bool Compiler::type_is_array_of_pointers(const SPIRType &type) const
|
|||||||
return type.pointer_depth == get<SPIRType>(type.parent_type).pointer_depth;
|
return type.pointer_depth == get<SPIRType>(type.parent_type).pointer_depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Compiler::type_is_top_level_physical_pointer(const SPIRType &type) const
|
||||||
|
{
|
||||||
|
return type.pointer && type.storage == StorageClassPhysicalStorageBuffer &&
|
||||||
|
type.pointer_depth > get<SPIRType>(type.parent_type).pointer_depth;
|
||||||
|
}
|
||||||
|
|
||||||
bool Compiler::flush_phi_required(BlockID from, BlockID to) const
|
bool Compiler::flush_phi_required(BlockID from, BlockID to) const
|
||||||
{
|
{
|
||||||
auto &child = get<SPIRBlock>(to);
|
auto &child = get<SPIRBlock>(to);
|
||||||
|
|||||||
@@ -1037,6 +1037,7 @@ protected:
|
|||||||
void unset_extended_member_decoration(uint32_t type, uint32_t index, ExtendedDecorations decoration);
|
void unset_extended_member_decoration(uint32_t type, uint32_t index, ExtendedDecorations decoration);
|
||||||
|
|
||||||
bool type_is_array_of_pointers(const SPIRType &type) const;
|
bool type_is_array_of_pointers(const SPIRType &type) const;
|
||||||
|
bool type_is_top_level_physical_pointer(const SPIRType &type) const;
|
||||||
bool type_is_block_like(const SPIRType &type) const;
|
bool type_is_block_like(const SPIRType &type) const;
|
||||||
bool type_is_opaque_value(const SPIRType &type) const;
|
bool type_is_opaque_value(const SPIRType &type) const;
|
||||||
|
|
||||||
|
|||||||
@@ -485,6 +485,10 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
|
|||||||
case SPVC_COMPILER_OPTION_HLSL_NONWRITABLE_UAV_TEXTURE_AS_SRV:
|
case SPVC_COMPILER_OPTION_HLSL_NONWRITABLE_UAV_TEXTURE_AS_SRV:
|
||||||
options->hlsl.nonwritable_uav_texture_as_srv = value != 0;
|
options->hlsl.nonwritable_uav_texture_as_srv = value != 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SPVC_COMPILER_OPTION_HLSL_ENABLE_16BIT_TYPES:
|
||||||
|
options->hlsl.enable_16bit_types = value != 0;
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if SPIRV_CROSS_C_API_MSL
|
#if SPIRV_CROSS_C_API_MSL
|
||||||
@@ -1017,12 +1021,8 @@ spvc_result spvc_compiler_msl_add_vertex_attribute(spvc_compiler compiler, const
|
|||||||
auto &msl = *static_cast<CompilerMSL *>(compiler->compiler.get());
|
auto &msl = *static_cast<CompilerMSL *>(compiler->compiler.get());
|
||||||
MSLVertexAttr attr;
|
MSLVertexAttr attr;
|
||||||
attr.location = va->location;
|
attr.location = va->location;
|
||||||
attr.msl_buffer = va->msl_buffer;
|
|
||||||
attr.msl_offset = va->msl_offset;
|
|
||||||
attr.msl_stride = va->msl_stride;
|
|
||||||
attr.format = static_cast<MSLVertexFormat>(va->format);
|
attr.format = static_cast<MSLVertexFormat>(va->format);
|
||||||
attr.builtin = static_cast<spv::BuiltIn>(va->builtin);
|
attr.builtin = static_cast<spv::BuiltIn>(va->builtin);
|
||||||
attr.per_instance = va->per_instance != 0;
|
|
||||||
msl.add_msl_vertex_attribute(attr);
|
msl.add_msl_vertex_attribute(attr);
|
||||||
return SPVC_SUCCESS;
|
return SPVC_SUCCESS;
|
||||||
#else
|
#else
|
||||||
@@ -2260,12 +2260,8 @@ void spvc_msl_vertex_attribute_init(spvc_msl_vertex_attribute *attr)
|
|||||||
// Crude, but works.
|
// Crude, but works.
|
||||||
MSLVertexAttr attr_default;
|
MSLVertexAttr attr_default;
|
||||||
attr->location = attr_default.location;
|
attr->location = attr_default.location;
|
||||||
attr->per_instance = attr_default.per_instance ? SPVC_TRUE : SPVC_FALSE;
|
|
||||||
attr->format = static_cast<spvc_msl_vertex_format>(attr_default.format);
|
attr->format = static_cast<spvc_msl_vertex_format>(attr_default.format);
|
||||||
attr->builtin = static_cast<SpvBuiltIn>(attr_default.builtin);
|
attr->builtin = static_cast<SpvBuiltIn>(attr_default.builtin);
|
||||||
attr->msl_buffer = attr_default.msl_buffer;
|
|
||||||
attr->msl_offset = attr_default.msl_offset;
|
|
||||||
attr->msl_stride = attr_default.msl_stride;
|
|
||||||
#else
|
#else
|
||||||
memset(attr, 0, sizeof(*attr));
|
memset(attr, 0, sizeof(*attr));
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ extern "C" {
|
|||||||
/* Bumped if ABI or API breaks backwards compatibility. */
|
/* Bumped if ABI or API breaks backwards compatibility. */
|
||||||
#define SPVC_C_API_VERSION_MAJOR 0
|
#define SPVC_C_API_VERSION_MAJOR 0
|
||||||
/* Bumped if APIs or enumerations are added in a backwards compatible way. */
|
/* Bumped if APIs or enumerations are added in a backwards compatible way. */
|
||||||
#define SPVC_C_API_VERSION_MINOR 33
|
#define SPVC_C_API_VERSION_MINOR 34
|
||||||
/* Bumped if internal implementation details change. */
|
/* Bumped if internal implementation details change. */
|
||||||
#define SPVC_C_API_VERSION_PATCH 0
|
#define SPVC_C_API_VERSION_PATCH 0
|
||||||
|
|
||||||
@@ -270,10 +270,16 @@ typedef enum spvc_msl_vertex_format
|
|||||||
typedef struct spvc_msl_vertex_attribute
|
typedef struct spvc_msl_vertex_attribute
|
||||||
{
|
{
|
||||||
unsigned location;
|
unsigned location;
|
||||||
|
|
||||||
|
/* Obsolete, do not use. Only lingers on for ABI compatibility. */
|
||||||
unsigned msl_buffer;
|
unsigned msl_buffer;
|
||||||
|
/* Obsolete, do not use. Only lingers on for ABI compatibility. */
|
||||||
unsigned msl_offset;
|
unsigned msl_offset;
|
||||||
|
/* Obsolete, do not use. Only lingers on for ABI compatibility. */
|
||||||
unsigned msl_stride;
|
unsigned msl_stride;
|
||||||
|
/* Obsolete, do not use. Only lingers on for ABI compatibility. */
|
||||||
spvc_bool per_instance;
|
spvc_bool per_instance;
|
||||||
|
|
||||||
spvc_msl_vertex_format format;
|
spvc_msl_vertex_format format;
|
||||||
SpvBuiltIn builtin;
|
SpvBuiltIn builtin;
|
||||||
} spvc_msl_vertex_attribute;
|
} spvc_msl_vertex_attribute;
|
||||||
@@ -588,6 +594,8 @@ typedef enum spvc_compiler_option
|
|||||||
SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_STENCIL_REF_BUILTIN = 58 | SPVC_COMPILER_OPTION_MSL_BIT,
|
SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_STENCIL_REF_BUILTIN = 58 | SPVC_COMPILER_OPTION_MSL_BIT,
|
||||||
SPVC_COMPILER_OPTION_MSL_ENABLE_CLIP_DISTANCE_USER_VARYING = 59 | SPVC_COMPILER_OPTION_MSL_BIT,
|
SPVC_COMPILER_OPTION_MSL_ENABLE_CLIP_DISTANCE_USER_VARYING = 59 | SPVC_COMPILER_OPTION_MSL_BIT,
|
||||||
|
|
||||||
|
SPVC_COMPILER_OPTION_HLSL_ENABLE_16BIT_TYPES = 60 | SPVC_COMPILER_OPTION_HLSL_BIT,
|
||||||
|
|
||||||
SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
|
SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff
|
||||||
} spvc_compiler_option;
|
} spvc_compiler_option;
|
||||||
|
|
||||||
|
|||||||
@@ -731,6 +731,13 @@ void CompilerGLSL::emit_header()
|
|||||||
statement("#endif");
|
statement("#endif");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (!options.vulkan_semantics && ext == "GL_ARB_shader_draw_parameters")
|
||||||
|
{
|
||||||
|
// Soft-enable this extension on plain GLSL.
|
||||||
|
statement("#ifdef ", ext);
|
||||||
|
statement("#extension ", ext, " : enable");
|
||||||
|
statement("#endif");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
statement("#extension ", ext, " : require");
|
statement("#extension ", ext, " : require");
|
||||||
}
|
}
|
||||||
@@ -2943,16 +2950,28 @@ void CompilerGLSL::emit_resources()
|
|||||||
}
|
}
|
||||||
else if (id.get_type() == TypeType)
|
else if (id.get_type() == TypeType)
|
||||||
{
|
{
|
||||||
auto &type = id.get<SPIRType>();
|
auto *type = &id.get<SPIRType>();
|
||||||
if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer &&
|
|
||||||
(!ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) &&
|
bool is_natural_struct =
|
||||||
!ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock)))
|
type->basetype == SPIRType::Struct && type->array.empty() && !type->pointer &&
|
||||||
|
(!has_decoration(type->self, DecorationBlock) && !has_decoration(type->self, DecorationBufferBlock));
|
||||||
|
|
||||||
|
// Special case, ray payload and hit attribute blocks are not really blocks, just regular structs.
|
||||||
|
if (type->basetype == SPIRType::Struct && type->pointer && has_decoration(type->self, DecorationBlock) &&
|
||||||
|
(type->storage == StorageClassRayPayloadNV || type->storage == StorageClassIncomingRayPayloadNV ||
|
||||||
|
type->storage == StorageClassHitAttributeNV))
|
||||||
|
{
|
||||||
|
type = &get<SPIRType>(type->parent_type);
|
||||||
|
is_natural_struct = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_natural_struct)
|
||||||
{
|
{
|
||||||
if (emitted)
|
if (emitted)
|
||||||
statement("");
|
statement("");
|
||||||
emitted = false;
|
emitted = false;
|
||||||
|
|
||||||
emit_struct(type);
|
emit_struct(*type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3070,6 +3089,8 @@ void CompilerGLSL::emit_resources()
|
|||||||
statement("");
|
statement("");
|
||||||
emitted = false;
|
emitted = false;
|
||||||
|
|
||||||
|
bool emitted_base_instance = false;
|
||||||
|
|
||||||
// Output in/out interfaces.
|
// Output in/out interfaces.
|
||||||
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
|
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
|
||||||
auto &type = this->get<SPIRType>(var.basetype);
|
auto &type = this->get<SPIRType>(var.basetype);
|
||||||
@@ -3092,13 +3113,42 @@ void CompilerGLSL::emit_resources()
|
|||||||
}
|
}
|
||||||
else if (is_builtin_variable(var))
|
else if (is_builtin_variable(var))
|
||||||
{
|
{
|
||||||
|
auto builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn));
|
||||||
// For gl_InstanceIndex emulation on GLES, the API user needs to
|
// For gl_InstanceIndex emulation on GLES, the API user needs to
|
||||||
// supply this uniform.
|
// supply this uniform.
|
||||||
if (options.vertex.support_nonzero_base_instance &&
|
|
||||||
ir.meta[var.self].decoration.builtin_type == BuiltInInstanceIndex && !options.vulkan_semantics)
|
// The draw parameter extension is soft-enabled on GL with some fallbacks.
|
||||||
|
if (!options.vulkan_semantics)
|
||||||
{
|
{
|
||||||
statement("uniform int SPIRV_Cross_BaseInstance;");
|
if (!emitted_base_instance &&
|
||||||
emitted = true;
|
((options.vertex.support_nonzero_base_instance && builtin == BuiltInInstanceIndex) ||
|
||||||
|
(builtin == BuiltInBaseInstance)))
|
||||||
|
{
|
||||||
|
statement("#ifdef GL_ARB_shader_draw_parameters");
|
||||||
|
statement("#define SPIRV_Cross_BaseInstance gl_BaseInstanceARB");
|
||||||
|
statement("#else");
|
||||||
|
// A crude, but simple workaround which should be good enough for non-indirect draws.
|
||||||
|
statement("uniform int SPIRV_Cross_BaseInstance;");
|
||||||
|
statement("#endif");
|
||||||
|
emitted = true;
|
||||||
|
emitted_base_instance = true;
|
||||||
|
}
|
||||||
|
else if (builtin == BuiltInBaseVertex)
|
||||||
|
{
|
||||||
|
statement("#ifdef GL_ARB_shader_draw_parameters");
|
||||||
|
statement("#define SPIRV_Cross_BaseVertex gl_BaseVertexARB");
|
||||||
|
statement("#else");
|
||||||
|
// A crude, but simple workaround which should be good enough for non-indirect draws.
|
||||||
|
statement("uniform int SPIRV_Cross_BaseVertex;");
|
||||||
|
statement("#endif");
|
||||||
|
}
|
||||||
|
else if (builtin == BuiltInDrawIndex)
|
||||||
|
{
|
||||||
|
statement("#ifndef GL_ARB_shader_draw_parameters");
|
||||||
|
// Cannot really be worked around.
|
||||||
|
statement("#error GL_ARB_shader_draw_parameters is not supported.");
|
||||||
|
statement("#endif");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -6792,8 +6842,21 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
|
|||||||
return "gl_VertexID";
|
return "gl_VertexID";
|
||||||
case BuiltInInstanceId:
|
case BuiltInInstanceId:
|
||||||
if (options.vulkan_semantics)
|
if (options.vulkan_semantics)
|
||||||
SPIRV_CROSS_THROW(
|
{
|
||||||
"Cannot implement gl_InstanceID in Vulkan GLSL. This shader was created with GL semantics.");
|
auto model = get_entry_point().model;
|
||||||
|
switch (model)
|
||||||
|
{
|
||||||
|
case spv::ExecutionModelIntersectionKHR:
|
||||||
|
case spv::ExecutionModelAnyHitKHR:
|
||||||
|
case spv::ExecutionModelClosestHitKHR:
|
||||||
|
// gl_InstanceID is allowed in these shaders.
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
SPIRV_CROSS_THROW(
|
||||||
|
"Cannot implement gl_InstanceID in Vulkan GLSL. This shader was created with GL semantics.");
|
||||||
|
}
|
||||||
|
}
|
||||||
return "gl_InstanceID";
|
return "gl_InstanceID";
|
||||||
case BuiltInVertexIndex:
|
case BuiltInVertexIndex:
|
||||||
if (options.vulkan_semantics)
|
if (options.vulkan_semantics)
|
||||||
@@ -6804,7 +6867,14 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
|
|||||||
if (options.vulkan_semantics)
|
if (options.vulkan_semantics)
|
||||||
return "gl_InstanceIndex";
|
return "gl_InstanceIndex";
|
||||||
else if (options.vertex.support_nonzero_base_instance)
|
else if (options.vertex.support_nonzero_base_instance)
|
||||||
|
{
|
||||||
|
if (!options.vulkan_semantics)
|
||||||
|
{
|
||||||
|
// This is a soft-enable. We will opt-in to using gl_BaseInstanceARB if supported.
|
||||||
|
require_extension_internal("GL_ARB_shader_draw_parameters");
|
||||||
|
}
|
||||||
return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
|
return "(gl_InstanceID + SPIRV_Cross_BaseInstance)"; // ... but not gl_InstanceID.
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return "gl_InstanceID";
|
return "gl_InstanceID";
|
||||||
case BuiltInPrimitiveId:
|
case BuiltInPrimitiveId:
|
||||||
@@ -6846,33 +6916,69 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
|
|||||||
return "gl_LocalInvocationIndex";
|
return "gl_LocalInvocationIndex";
|
||||||
case BuiltInHelperInvocation:
|
case BuiltInHelperInvocation:
|
||||||
return "gl_HelperInvocation";
|
return "gl_HelperInvocation";
|
||||||
|
|
||||||
case BuiltInBaseVertex:
|
case BuiltInBaseVertex:
|
||||||
if (options.es)
|
if (options.es)
|
||||||
SPIRV_CROSS_THROW("BaseVertex not supported in ES profile.");
|
SPIRV_CROSS_THROW("BaseVertex not supported in ES profile.");
|
||||||
if (options.version < 460)
|
|
||||||
|
if (options.vulkan_semantics)
|
||||||
{
|
{
|
||||||
require_extension_internal("GL_ARB_shader_draw_parameters");
|
if (options.version < 460)
|
||||||
return "gl_BaseVertexARB";
|
{
|
||||||
|
require_extension_internal("GL_ARB_shader_draw_parameters");
|
||||||
|
return "gl_BaseVertexARB";
|
||||||
|
}
|
||||||
|
return "gl_BaseVertex";
|
||||||
}
|
}
|
||||||
return "gl_BaseVertex";
|
else
|
||||||
|
{
|
||||||
|
// On regular GL, this is soft-enabled and we emit ifdefs in code.
|
||||||
|
require_extension_internal("GL_ARB_shader_draw_parameters");
|
||||||
|
return "SPIRV_Cross_BaseVertex";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case BuiltInBaseInstance:
|
case BuiltInBaseInstance:
|
||||||
if (options.es)
|
if (options.es)
|
||||||
SPIRV_CROSS_THROW("BaseInstance not supported in ES profile.");
|
SPIRV_CROSS_THROW("BaseInstance not supported in ES profile.");
|
||||||
if (options.version < 460)
|
|
||||||
|
if (options.vulkan_semantics)
|
||||||
{
|
{
|
||||||
require_extension_internal("GL_ARB_shader_draw_parameters");
|
if (options.version < 460)
|
||||||
return "gl_BaseInstanceARB";
|
{
|
||||||
|
require_extension_internal("GL_ARB_shader_draw_parameters");
|
||||||
|
return "gl_BaseInstanceARB";
|
||||||
|
}
|
||||||
|
return "gl_BaseInstance";
|
||||||
}
|
}
|
||||||
return "gl_BaseInstance";
|
else
|
||||||
|
{
|
||||||
|
// On regular GL, this is soft-enabled and we emit ifdefs in code.
|
||||||
|
require_extension_internal("GL_ARB_shader_draw_parameters");
|
||||||
|
return "SPIRV_Cross_BaseInstance";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case BuiltInDrawIndex:
|
case BuiltInDrawIndex:
|
||||||
if (options.es)
|
if (options.es)
|
||||||
SPIRV_CROSS_THROW("DrawIndex not supported in ES profile.");
|
SPIRV_CROSS_THROW("DrawIndex not supported in ES profile.");
|
||||||
if (options.version < 460)
|
|
||||||
|
if (options.vulkan_semantics)
|
||||||
{
|
{
|
||||||
|
if (options.version < 460)
|
||||||
|
{
|
||||||
|
require_extension_internal("GL_ARB_shader_draw_parameters");
|
||||||
|
return "gl_DrawIDARB";
|
||||||
|
}
|
||||||
|
return "gl_DrawID";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// On regular GL, this is soft-enabled and we emit ifdefs in code.
|
||||||
require_extension_internal("GL_ARB_shader_draw_parameters");
|
require_extension_internal("GL_ARB_shader_draw_parameters");
|
||||||
return "gl_DrawIDARB";
|
return "gl_DrawIDARB";
|
||||||
}
|
}
|
||||||
return "gl_DrawID";
|
break;
|
||||||
|
|
||||||
case BuiltInSampleId:
|
case BuiltInSampleId:
|
||||||
if (options.es && options.version < 320)
|
if (options.es && options.version < 320)
|
||||||
@@ -8591,7 +8697,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
|||||||
var->static_expression = ops[1];
|
var->static_expression = ops[1];
|
||||||
else if (var && var->loop_variable && !var->loop_variable_enable)
|
else if (var && var->loop_variable && !var->loop_variable_enable)
|
||||||
var->static_expression = ops[1];
|
var->static_expression = ops[1];
|
||||||
else if (var && var->remapped_variable)
|
else if (var && var->remapped_variable && var->static_expression)
|
||||||
{
|
{
|
||||||
// Skip the write.
|
// Skip the write.
|
||||||
}
|
}
|
||||||
@@ -9794,15 +9900,33 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
|||||||
}
|
}
|
||||||
|
|
||||||
case OpAtomicLoad:
|
case OpAtomicLoad:
|
||||||
flush_all_atomic_capable_variables();
|
{
|
||||||
// FIXME: Image?
|
// In plain GLSL, we have no atomic loads, so emulate this by fetch adding by 0 and hope compiler figures it out.
|
||||||
// OpAtomicLoad seems to only be relevant for atomic counters.
|
// Alternatively, we could rely on KHR_memory_model, but that's not very helpful for GL.
|
||||||
|
auto &type = expression_type(ops[2]);
|
||||||
forced_temporaries.insert(ops[1]);
|
forced_temporaries.insert(ops[1]);
|
||||||
GLSL_UFOP(atomicCounter);
|
bool atomic_image = check_atomic_image(ops[2]);
|
||||||
|
bool unsigned_type = (type.basetype == SPIRType::UInt) ||
|
||||||
|
(atomic_image && get<SPIRType>(type.image.type).basetype == SPIRType::UInt);
|
||||||
|
const char *op = atomic_image ? "imageAtomicAdd" : "atomicAdd";
|
||||||
|
const char *increment = unsigned_type ? "0u" : "0";
|
||||||
|
emit_op(ops[0], ops[1], join(op, "(", to_expression(ops[2]), ", ", increment, ")"), false);
|
||||||
|
flush_all_atomic_capable_variables();
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case OpAtomicStore:
|
case OpAtomicStore:
|
||||||
SPIRV_CROSS_THROW("Unsupported opcode OpAtomicStore.");
|
{
|
||||||
|
// In plain GLSL, we have no atomic stores, so emulate this with an atomic exchange where we don't consume the result.
|
||||||
|
// Alternatively, we could rely on KHR_memory_model, but that's not very helpful for GL.
|
||||||
|
uint32_t ptr = ops[0];
|
||||||
|
// Ignore semantics for now, probably only relevant to CL.
|
||||||
|
uint32_t val = ops[3];
|
||||||
|
const char *op = check_atomic_image(ptr) ? "imageAtomicExchange" : "atomicExchange";
|
||||||
|
statement(op, "(", to_expression(ptr), ", ", to_expression(val), ");");
|
||||||
|
flush_all_atomic_capable_variables();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case OpAtomicIIncrement:
|
case OpAtomicIIncrement:
|
||||||
case OpAtomicIDecrement:
|
case OpAtomicIDecrement:
|
||||||
@@ -10761,21 +10885,26 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
|
|||||||
|
|
||||||
case OpReportIntersectionNV:
|
case OpReportIntersectionNV:
|
||||||
statement("reportIntersectionNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
|
statement("reportIntersectionNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
|
||||||
|
flush_control_dependent_expressions(current_emitting_block->self);
|
||||||
break;
|
break;
|
||||||
case OpIgnoreIntersectionNV:
|
case OpIgnoreIntersectionNV:
|
||||||
statement("ignoreIntersectionNV();");
|
statement("ignoreIntersectionNV();");
|
||||||
|
flush_control_dependent_expressions(current_emitting_block->self);
|
||||||
break;
|
break;
|
||||||
case OpTerminateRayNV:
|
case OpTerminateRayNV:
|
||||||
statement("terminateRayNV();");
|
statement("terminateRayNV();");
|
||||||
|
flush_control_dependent_expressions(current_emitting_block->self);
|
||||||
break;
|
break;
|
||||||
case OpTraceNV:
|
case OpTraceNV:
|
||||||
statement("traceNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]), ", ",
|
statement("traceNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ", ", to_expression(ops[2]), ", ",
|
||||||
to_expression(ops[3]), ", ", to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
|
to_expression(ops[3]), ", ", to_expression(ops[4]), ", ", to_expression(ops[5]), ", ",
|
||||||
to_expression(ops[6]), ", ", to_expression(ops[7]), ", ", to_expression(ops[8]), ", ",
|
to_expression(ops[6]), ", ", to_expression(ops[7]), ", ", to_expression(ops[8]), ", ",
|
||||||
to_expression(ops[9]), ", ", to_expression(ops[10]), ");");
|
to_expression(ops[9]), ", ", to_expression(ops[10]), ");");
|
||||||
|
flush_control_dependent_expressions(current_emitting_block->self);
|
||||||
break;
|
break;
|
||||||
case OpExecuteCallableNV:
|
case OpExecuteCallableNV:
|
||||||
statement("executeCallableNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
|
statement("executeCallableNV(", to_expression(ops[0]), ", ", to_expression(ops[1]), ");");
|
||||||
|
flush_control_dependent_expressions(current_emitting_block->self);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OpConvertUToPtr:
|
case OpConvertUToPtr:
|
||||||
@@ -13376,6 +13505,7 @@ void CompilerGLSL::bitcast_from_builtin_load(uint32_t source_id, std::string &ex
|
|||||||
case BuiltInBaseInstance:
|
case BuiltInBaseInstance:
|
||||||
case BuiltInDrawIndex:
|
case BuiltInDrawIndex:
|
||||||
case BuiltInFragStencilRefEXT:
|
case BuiltInFragStencilRefEXT:
|
||||||
|
case BuiltInInstanceCustomIndexNV:
|
||||||
expected_type = SPIRType::Int;
|
expected_type = SPIRType::Int;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -13385,6 +13515,9 @@ void CompilerGLSL::bitcast_from_builtin_load(uint32_t source_id, std::string &ex
|
|||||||
case BuiltInLocalInvocationIndex:
|
case BuiltInLocalInvocationIndex:
|
||||||
case BuiltInWorkgroupSize:
|
case BuiltInWorkgroupSize:
|
||||||
case BuiltInNumWorkgroups:
|
case BuiltInNumWorkgroups:
|
||||||
|
case BuiltInIncomingRayFlagsNV:
|
||||||
|
case BuiltInLaunchIdNV:
|
||||||
|
case BuiltInLaunchSizeNV:
|
||||||
expected_type = SPIRType::UInt;
|
expected_type = SPIRType::UInt;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,41 @@ using namespace spv;
|
|||||||
using namespace SPIRV_CROSS_NAMESPACE;
|
using namespace SPIRV_CROSS_NAMESPACE;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
enum class ImageFormatNormalizedState
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Unorm = 1,
|
||||||
|
Snorm = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
static ImageFormatNormalizedState image_format_to_normalized_state(ImageFormat fmt)
|
||||||
|
{
|
||||||
|
switch (fmt)
|
||||||
|
{
|
||||||
|
case ImageFormatR8:
|
||||||
|
case ImageFormatR16:
|
||||||
|
case ImageFormatRg8:
|
||||||
|
case ImageFormatRg16:
|
||||||
|
case ImageFormatRgba8:
|
||||||
|
case ImageFormatRgba16:
|
||||||
|
case ImageFormatRgb10A2:
|
||||||
|
return ImageFormatNormalizedState::Unorm;
|
||||||
|
|
||||||
|
case ImageFormatR8Snorm:
|
||||||
|
case ImageFormatR16Snorm:
|
||||||
|
case ImageFormatRg8Snorm:
|
||||||
|
case ImageFormatRg16Snorm:
|
||||||
|
case ImageFormatRgba8Snorm:
|
||||||
|
case ImageFormatRgba16Snorm:
|
||||||
|
return ImageFormatNormalizedState::Snorm;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ImageFormatNormalizedState::None;
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned image_format_to_components(ImageFormat fmt)
|
static unsigned image_format_to_components(ImageFormat fmt)
|
||||||
{
|
{
|
||||||
switch (fmt)
|
switch (fmt)
|
||||||
@@ -395,7 +430,20 @@ string CompilerHLSL::type_to_glsl(const SPIRType &type, uint32_t id)
|
|||||||
case SPIRType::AtomicCounter:
|
case SPIRType::AtomicCounter:
|
||||||
return "atomic_uint";
|
return "atomic_uint";
|
||||||
case SPIRType::Half:
|
case SPIRType::Half:
|
||||||
return "min16float";
|
if (hlsl_options.enable_16bit_types)
|
||||||
|
return "half";
|
||||||
|
else
|
||||||
|
return "min16float";
|
||||||
|
case SPIRType::Short:
|
||||||
|
if (hlsl_options.enable_16bit_types)
|
||||||
|
return "int16_t";
|
||||||
|
else
|
||||||
|
return "min16int";
|
||||||
|
case SPIRType::UShort:
|
||||||
|
if (hlsl_options.enable_16bit_types)
|
||||||
|
return "uint16_t";
|
||||||
|
else
|
||||||
|
return "min16uint";
|
||||||
case SPIRType::Float:
|
case SPIRType::Float:
|
||||||
return "float";
|
return "float";
|
||||||
case SPIRType::Double:
|
case SPIRType::Double:
|
||||||
@@ -423,7 +471,11 @@ string CompilerHLSL::type_to_glsl(const SPIRType &type, uint32_t id)
|
|||||||
case SPIRType::UInt:
|
case SPIRType::UInt:
|
||||||
return join("uint", type.vecsize);
|
return join("uint", type.vecsize);
|
||||||
case SPIRType::Half:
|
case SPIRType::Half:
|
||||||
return join("min16float", type.vecsize);
|
return join(hlsl_options.enable_16bit_types ? "half" : "min16float", type.vecsize);
|
||||||
|
case SPIRType::Short:
|
||||||
|
return join(hlsl_options.enable_16bit_types ? "int16_t" : "min16int", type.vecsize);
|
||||||
|
case SPIRType::UShort:
|
||||||
|
return join(hlsl_options.enable_16bit_types ? "uint16_t" : "min16uint", type.vecsize);
|
||||||
case SPIRType::Float:
|
case SPIRType::Float:
|
||||||
return join("float", type.vecsize);
|
return join("float", type.vecsize);
|
||||||
case SPIRType::Double:
|
case SPIRType::Double:
|
||||||
@@ -447,7 +499,11 @@ string CompilerHLSL::type_to_glsl(const SPIRType &type, uint32_t id)
|
|||||||
case SPIRType::UInt:
|
case SPIRType::UInt:
|
||||||
return join("uint", type.columns, "x", type.vecsize);
|
return join("uint", type.columns, "x", type.vecsize);
|
||||||
case SPIRType::Half:
|
case SPIRType::Half:
|
||||||
return join("min16float", type.columns, "x", type.vecsize);
|
return join(hlsl_options.enable_16bit_types ? "half" : "min16float", type.columns, "x", type.vecsize);
|
||||||
|
case SPIRType::Short:
|
||||||
|
return join(hlsl_options.enable_16bit_types ? "int16_t" : "min16int", type.columns, "x", type.vecsize);
|
||||||
|
case SPIRType::UShort:
|
||||||
|
return join(hlsl_options.enable_16bit_types ? "uint16_t" : "min16uint", type.columns, "x", type.vecsize);
|
||||||
case SPIRType::Float:
|
case SPIRType::Float:
|
||||||
return join("float", type.columns, "x", type.vecsize);
|
return join("float", type.columns, "x", type.vecsize);
|
||||||
case SPIRType::Double:
|
case SPIRType::Double:
|
||||||
@@ -1423,66 +1479,14 @@ void CompilerHLSL::emit_resources()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (required_textureSizeVariants != 0)
|
emit_texture_size_variants(required_texture_size_variants.srv, "4", false, "");
|
||||||
|
for (uint32_t norm = 0; norm < 3; norm++)
|
||||||
{
|
{
|
||||||
static const char *types[QueryTypeCount] = { "float4", "int4", "uint4" };
|
for (uint32_t comp = 0; comp < 4; comp++)
|
||||||
static const char *dims[QueryDimCount] = { "Texture1D", "Texture1DArray", "Texture2D", "Texture2DArray",
|
|
||||||
"Texture3D", "Buffer", "TextureCube", "TextureCubeArray",
|
|
||||||
"Texture2DMS", "Texture2DMSArray" };
|
|
||||||
|
|
||||||
static const bool has_lod[QueryDimCount] = { true, true, true, true, true, false, true, true, false, false };
|
|
||||||
|
|
||||||
static const char *ret_types[QueryDimCount] = {
|
|
||||||
"uint", "uint2", "uint2", "uint3", "uint3", "uint", "uint2", "uint3", "uint2", "uint3",
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint32_t return_arguments[QueryDimCount] = {
|
|
||||||
1, 2, 2, 3, 3, 1, 2, 3, 2, 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (uint32_t index = 0; index < QueryDimCount; index++)
|
|
||||||
{
|
{
|
||||||
for (uint32_t type_index = 0; type_index < QueryTypeCount; type_index++)
|
static const char *qualifiers[] = { "", "unorm ", "snorm " };
|
||||||
{
|
static const char *vecsizes[] = { "", "2", "3", "4" };
|
||||||
uint32_t bit = 16 * type_index + index;
|
emit_texture_size_variants(required_texture_size_variants.uav[norm][comp], vecsizes[comp], true, qualifiers[norm]);
|
||||||
uint64_t mask = 1ull << bit;
|
|
||||||
|
|
||||||
if ((required_textureSizeVariants & mask) == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
statement(ret_types[index], " SPIRV_Cross_textureSize(", dims[index], "<", types[type_index],
|
|
||||||
"> Tex, uint Level, out uint Param)");
|
|
||||||
begin_scope();
|
|
||||||
statement(ret_types[index], " ret;");
|
|
||||||
switch (return_arguments[index])
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
if (has_lod[index])
|
|
||||||
statement("Tex.GetDimensions(Level, ret.x, Param);");
|
|
||||||
else
|
|
||||||
{
|
|
||||||
statement("Tex.GetDimensions(ret.x);");
|
|
||||||
statement("Param = 0u;");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (has_lod[index])
|
|
||||||
statement("Tex.GetDimensions(Level, ret.x, ret.y, Param);");
|
|
||||||
else
|
|
||||||
statement("Tex.GetDimensions(ret.x, ret.y, Param);");
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if (has_lod[index])
|
|
||||||
statement("Tex.GetDimensions(Level, ret.x, ret.y, ret.z, Param);");
|
|
||||||
else
|
|
||||||
statement("Tex.GetDimensions(ret.x, ret.y, ret.z, Param);");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
statement("return ret;");
|
|
||||||
end_scope();
|
|
||||||
statement("");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1845,6 +1849,83 @@ void CompilerHLSL::emit_resources()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CompilerHLSL::emit_texture_size_variants(uint64_t variant_mask, const char *vecsize_qualifier, bool uav, const char *type_qualifier)
|
||||||
|
{
|
||||||
|
if (variant_mask == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
static const char *types[QueryTypeCount] = { "float", "int", "uint" };
|
||||||
|
static const char *dims[QueryDimCount] = { "Texture1D", "Texture1DArray", "Texture2D", "Texture2DArray",
|
||||||
|
"Texture3D", "Buffer", "TextureCube", "TextureCubeArray",
|
||||||
|
"Texture2DMS", "Texture2DMSArray" };
|
||||||
|
|
||||||
|
static const bool has_lod[QueryDimCount] = { true, true, true, true, true, false, true, true, false, false };
|
||||||
|
|
||||||
|
static const char *ret_types[QueryDimCount] = {
|
||||||
|
"uint", "uint2", "uint2", "uint3", "uint3", "uint", "uint2", "uint3", "uint2", "uint3",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t return_arguments[QueryDimCount] = {
|
||||||
|
1, 2, 2, 3, 3, 1, 2, 3, 2, 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (uint32_t index = 0; index < QueryDimCount; index++)
|
||||||
|
{
|
||||||
|
for (uint32_t type_index = 0; type_index < QueryTypeCount; type_index++)
|
||||||
|
{
|
||||||
|
uint32_t bit = 16 * type_index + index;
|
||||||
|
uint64_t mask = 1ull << bit;
|
||||||
|
|
||||||
|
if ((variant_mask & mask) == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
statement(ret_types[index], " SPIRV_Cross_", (uav ? "image" : "texture"), "Size(", (uav ? "RW" : ""),
|
||||||
|
dims[index], "<", type_qualifier, types[type_index], vecsize_qualifier,
|
||||||
|
"> Tex, ", (uav ? "" : "uint Level, "), "out uint Param)");
|
||||||
|
begin_scope();
|
||||||
|
statement(ret_types[index], " ret;");
|
||||||
|
switch (return_arguments[index])
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
if (has_lod[index] && !uav)
|
||||||
|
statement("Tex.GetDimensions(Level, ret.x, Param);");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
statement("Tex.GetDimensions(ret.x);");
|
||||||
|
statement("Param = 0u;");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (has_lod[index] && !uav)
|
||||||
|
statement("Tex.GetDimensions(Level, ret.x, ret.y, Param);");
|
||||||
|
else if (!uav)
|
||||||
|
statement("Tex.GetDimensions(ret.x, ret.y, Param);");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
statement("Tex.GetDimensions(ret.x, ret.y);");
|
||||||
|
statement("Param = 0u;");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (has_lod[index] && !uav)
|
||||||
|
statement("Tex.GetDimensions(Level, ret.x, ret.y, ret.z, Param);");
|
||||||
|
else if (!uav)
|
||||||
|
statement("Tex.GetDimensions(ret.x, ret.y, ret.z, Param);");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
statement("Tex.GetDimensions(ret.x, ret.y, ret.z);");
|
||||||
|
statement("Param = 0u;");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
statement("return ret;");
|
||||||
|
end_scope();
|
||||||
|
statement("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string CompilerHLSL::layout_for_member(const SPIRType &type, uint32_t index)
|
string CompilerHLSL::layout_for_member(const SPIRType &type, uint32_t index)
|
||||||
{
|
{
|
||||||
auto &flags = get_member_decoration_bitset(type.self, index);
|
auto &flags = get_member_decoration_bitset(type.self, index);
|
||||||
@@ -1906,7 +1987,7 @@ void CompilerHLSL::emit_buffer_block(const SPIRVariable &var)
|
|||||||
if (is_uav)
|
if (is_uav)
|
||||||
{
|
{
|
||||||
Bitset flags = ir.get_buffer_block_flags(var);
|
Bitset flags = ir.get_buffer_block_flags(var);
|
||||||
bool is_readonly = flags.get(DecorationNonWritable) && !hlsl_options.force_storage_buffer_as_uav;
|
bool is_readonly = flags.get(DecorationNonWritable) && !is_hlsl_force_storage_buffer_as_uav(var.self);
|
||||||
bool is_coherent = flags.get(DecorationCoherent) && !is_readonly;
|
bool is_coherent = flags.get(DecorationCoherent) && !is_readonly;
|
||||||
bool is_interlocked = interlocked_resources.count(var.self) > 0;
|
bool is_interlocked = interlocked_resources.count(var.self) > 0;
|
||||||
const char *type_name = "ByteAddressBuffer ";
|
const char *type_name = "ByteAddressBuffer ";
|
||||||
@@ -3038,7 +3119,7 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
|
|||||||
if (has_decoration(type.self, DecorationBufferBlock))
|
if (has_decoration(type.self, DecorationBufferBlock))
|
||||||
{
|
{
|
||||||
Bitset flags = ir.get_buffer_block_flags(var);
|
Bitset flags = ir.get_buffer_block_flags(var);
|
||||||
bool is_readonly = flags.get(DecorationNonWritable) && !hlsl_options.force_storage_buffer_as_uav;
|
bool is_readonly = flags.get(DecorationNonWritable) && !is_hlsl_force_storage_buffer_as_uav(var.self);
|
||||||
space = is_readonly ? 't' : 'u'; // UAV
|
space = is_readonly ? 't' : 'u'; // UAV
|
||||||
resource_flags = is_readonly ? HLSL_BINDING_AUTO_SRV_BIT : HLSL_BINDING_AUTO_UAV_BIT;
|
resource_flags = is_readonly ? HLSL_BINDING_AUTO_SRV_BIT : HLSL_BINDING_AUTO_UAV_BIT;
|
||||||
}
|
}
|
||||||
@@ -3057,7 +3138,7 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
|
|||||||
{
|
{
|
||||||
// UAV or SRV depending on readonly flag.
|
// UAV or SRV depending on readonly flag.
|
||||||
Bitset flags = ir.get_buffer_block_flags(var);
|
Bitset flags = ir.get_buffer_block_flags(var);
|
||||||
bool is_readonly = flags.get(DecorationNonWritable) && !hlsl_options.force_storage_buffer_as_uav;
|
bool is_readonly = flags.get(DecorationNonWritable) && !is_hlsl_force_storage_buffer_as_uav(var.self);
|
||||||
space = is_readonly ? 't' : 'u';
|
space = is_readonly ? 't' : 'u';
|
||||||
resource_flags = is_readonly ? HLSL_BINDING_AUTO_SRV_BIT : HLSL_BINDING_AUTO_UAV_BIT;
|
resource_flags = is_readonly ? HLSL_BINDING_AUTO_SRV_BIT : HLSL_BINDING_AUTO_UAV_BIT;
|
||||||
}
|
}
|
||||||
@@ -3587,11 +3668,16 @@ void CompilerHLSL::read_access_chain(string *expr, const string &lhs, const SPIR
|
|||||||
read_access_chain_struct(lhs, chain);
|
read_access_chain_struct(lhs, chain);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (type.width != 32)
|
else if (type.width != 32 && !hlsl_options.enable_16bit_types)
|
||||||
SPIRV_CROSS_THROW("Reading types other than 32-bit from ByteAddressBuffer not yet supported.");
|
SPIRV_CROSS_THROW("Reading types other than 32-bit from ByteAddressBuffer not yet supported, unless SM 6.2 and native 16-bit types are enabled.");
|
||||||
|
|
||||||
|
bool templated_load = hlsl_options.shader_model >= 62;
|
||||||
string load_expr;
|
string load_expr;
|
||||||
|
|
||||||
|
string template_expr;
|
||||||
|
if (templated_load)
|
||||||
|
template_expr = join("<", type_to_glsl(type), ">");
|
||||||
|
|
||||||
// Load a vector or scalar.
|
// Load a vector or scalar.
|
||||||
if (type.columns == 1 && !chain.row_major_matrix)
|
if (type.columns == 1 && !chain.row_major_matrix)
|
||||||
{
|
{
|
||||||
@@ -3614,12 +3700,24 @@ void CompilerHLSL::read_access_chain(string *expr, const string &lhs, const SPIR
|
|||||||
SPIRV_CROSS_THROW("Unknown vector size.");
|
SPIRV_CROSS_THROW("Unknown vector size.");
|
||||||
}
|
}
|
||||||
|
|
||||||
load_expr = join(chain.base, ".", load_op, "(", chain.dynamic_index, chain.static_index, ")");
|
if (templated_load)
|
||||||
|
load_op = "Load";
|
||||||
|
|
||||||
|
load_expr = join(chain.base, ".", load_op, template_expr, "(", chain.dynamic_index, chain.static_index, ")");
|
||||||
}
|
}
|
||||||
else if (type.columns == 1)
|
else if (type.columns == 1)
|
||||||
{
|
{
|
||||||
// Strided load since we are loading a column from a row-major matrix.
|
// Strided load since we are loading a column from a row-major matrix.
|
||||||
if (type.vecsize > 1)
|
if (templated_load)
|
||||||
|
{
|
||||||
|
auto scalar_type = type;
|
||||||
|
scalar_type.vecsize = 1;
|
||||||
|
scalar_type.columns = 1;
|
||||||
|
template_expr = join("<", type_to_glsl(scalar_type), ">");
|
||||||
|
if (type.vecsize > 1)
|
||||||
|
load_expr += type_to_glsl(type) + "(";
|
||||||
|
}
|
||||||
|
else if (type.vecsize > 1)
|
||||||
{
|
{
|
||||||
load_expr = type_to_glsl(target_type);
|
load_expr = type_to_glsl(target_type);
|
||||||
load_expr += "(";
|
load_expr += "(";
|
||||||
@@ -3628,7 +3726,7 @@ void CompilerHLSL::read_access_chain(string *expr, const string &lhs, const SPIR
|
|||||||
for (uint32_t r = 0; r < type.vecsize; r++)
|
for (uint32_t r = 0; r < type.vecsize; r++)
|
||||||
{
|
{
|
||||||
load_expr +=
|
load_expr +=
|
||||||
join(chain.base, ".Load(", chain.dynamic_index, chain.static_index + r * chain.matrix_stride, ")");
|
join(chain.base, ".Load", template_expr, "(", chain.dynamic_index, chain.static_index + r * chain.matrix_stride, ")");
|
||||||
if (r + 1 < type.vecsize)
|
if (r + 1 < type.vecsize)
|
||||||
load_expr += ", ";
|
load_expr += ", ";
|
||||||
}
|
}
|
||||||
@@ -3658,13 +3756,25 @@ void CompilerHLSL::read_access_chain(string *expr, const string &lhs, const SPIR
|
|||||||
SPIRV_CROSS_THROW("Unknown vector size.");
|
SPIRV_CROSS_THROW("Unknown vector size.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note, this loading style in HLSL is *actually* row-major, but we always treat matrices as transposed in this backend,
|
if (templated_load)
|
||||||
// so row-major is technically column-major ...
|
{
|
||||||
load_expr = type_to_glsl(target_type);
|
auto vector_type = type;
|
||||||
|
vector_type.columns = 1;
|
||||||
|
template_expr = join("<", type_to_glsl(vector_type), ">");
|
||||||
|
load_expr = type_to_glsl(type);
|
||||||
|
load_op = "Load";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Note, this loading style in HLSL is *actually* row-major, but we always treat matrices as transposed in this backend,
|
||||||
|
// so row-major is technically column-major ...
|
||||||
|
load_expr = type_to_glsl(target_type);
|
||||||
|
}
|
||||||
load_expr += "(";
|
load_expr += "(";
|
||||||
|
|
||||||
for (uint32_t c = 0; c < type.columns; c++)
|
for (uint32_t c = 0; c < type.columns; c++)
|
||||||
{
|
{
|
||||||
load_expr += join(chain.base, ".", load_op, "(", chain.dynamic_index,
|
load_expr += join(chain.base, ".", load_op, template_expr, "(", chain.dynamic_index,
|
||||||
chain.static_index + c * chain.matrix_stride, ")");
|
chain.static_index + c * chain.matrix_stride, ")");
|
||||||
if (c + 1 < type.columns)
|
if (c + 1 < type.columns)
|
||||||
load_expr += ", ";
|
load_expr += ", ";
|
||||||
@@ -3676,13 +3786,24 @@ void CompilerHLSL::read_access_chain(string *expr, const string &lhs, const SPIR
|
|||||||
// Pick out elements one by one ... Hopefully compilers are smart enough to recognize this pattern
|
// Pick out elements one by one ... Hopefully compilers are smart enough to recognize this pattern
|
||||||
// considering HLSL is "row-major decl", but "column-major" memory layout (basically implicit transpose model, ugh) ...
|
// considering HLSL is "row-major decl", but "column-major" memory layout (basically implicit transpose model, ugh) ...
|
||||||
|
|
||||||
load_expr = type_to_glsl(target_type);
|
if (templated_load)
|
||||||
|
{
|
||||||
|
load_expr = type_to_glsl(type);
|
||||||
|
auto scalar_type = type;
|
||||||
|
scalar_type.vecsize = 1;
|
||||||
|
scalar_type.columns = 1;
|
||||||
|
template_expr = join("<", type_to_glsl(scalar_type), ">");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
load_expr = type_to_glsl(target_type);
|
||||||
|
|
||||||
load_expr += "(";
|
load_expr += "(";
|
||||||
|
|
||||||
for (uint32_t c = 0; c < type.columns; c++)
|
for (uint32_t c = 0; c < type.columns; c++)
|
||||||
{
|
{
|
||||||
for (uint32_t r = 0; r < type.vecsize; r++)
|
for (uint32_t r = 0; r < type.vecsize; r++)
|
||||||
{
|
{
|
||||||
load_expr += join(chain.base, ".Load(", chain.dynamic_index,
|
load_expr += join(chain.base, ".Load", template_expr, "(", chain.dynamic_index,
|
||||||
chain.static_index + c * (type.width / 8) + r * chain.matrix_stride, ")");
|
chain.static_index + c * (type.width / 8) + r * chain.matrix_stride, ")");
|
||||||
|
|
||||||
if ((r + 1 < type.vecsize) || (c + 1 < type.columns))
|
if ((r + 1 < type.vecsize) || (c + 1 < type.columns))
|
||||||
@@ -3692,9 +3813,12 @@ void CompilerHLSL::read_access_chain(string *expr, const string &lhs, const SPIR
|
|||||||
load_expr += ")";
|
load_expr += ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto bitcast_op = bitcast_glsl_op(type, target_type);
|
if (!templated_load)
|
||||||
if (!bitcast_op.empty())
|
{
|
||||||
load_expr = join(bitcast_op, "(", load_expr, ")");
|
auto bitcast_op = bitcast_glsl_op(type, target_type);
|
||||||
|
if (!bitcast_op.empty())
|
||||||
|
load_expr = join(bitcast_op, "(", load_expr, ")");
|
||||||
|
}
|
||||||
|
|
||||||
if (lhs.empty())
|
if (lhs.empty())
|
||||||
{
|
{
|
||||||
@@ -3877,8 +4001,14 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val
|
|||||||
register_write(chain.self);
|
register_write(chain.self);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (type.width != 32)
|
else if (type.width != 32 && !hlsl_options.enable_16bit_types)
|
||||||
SPIRV_CROSS_THROW("Writing types other than 32-bit to RWByteAddressBuffer not yet supported.");
|
SPIRV_CROSS_THROW("Writing types other than 32-bit to RWByteAddressBuffer not yet supported, unless SM 6.2 and native 16-bit types are enabled.");
|
||||||
|
|
||||||
|
bool templated_store = hlsl_options.shader_model >= 62;
|
||||||
|
|
||||||
|
string template_expr;
|
||||||
|
if (templated_store)
|
||||||
|
template_expr = join("<", type_to_glsl(type), ">");
|
||||||
|
|
||||||
if (type.columns == 1 && !chain.row_major_matrix)
|
if (type.columns == 1 && !chain.row_major_matrix)
|
||||||
{
|
{
|
||||||
@@ -3902,13 +4032,27 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto store_expr = write_access_chain_value(value, composite_chain, false);
|
auto store_expr = write_access_chain_value(value, composite_chain, false);
|
||||||
auto bitcast_op = bitcast_glsl_op(target_type, type);
|
|
||||||
if (!bitcast_op.empty())
|
if (!templated_store)
|
||||||
store_expr = join(bitcast_op, "(", store_expr, ")");
|
{
|
||||||
statement(chain.base, ".", store_op, "(", chain.dynamic_index, chain.static_index, ", ", store_expr, ");");
|
auto bitcast_op = bitcast_glsl_op(target_type, type);
|
||||||
|
if (!bitcast_op.empty())
|
||||||
|
store_expr = join(bitcast_op, "(", store_expr, ")");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
store_op = "Store";
|
||||||
|
statement(chain.base, ".", store_op, template_expr, "(", chain.dynamic_index, chain.static_index, ", ", store_expr, ");");
|
||||||
}
|
}
|
||||||
else if (type.columns == 1)
|
else if (type.columns == 1)
|
||||||
{
|
{
|
||||||
|
if (templated_store)
|
||||||
|
{
|
||||||
|
auto scalar_type = type;
|
||||||
|
scalar_type.vecsize = 1;
|
||||||
|
scalar_type.columns = 1;
|
||||||
|
template_expr = join("<", type_to_glsl(scalar_type), ">");
|
||||||
|
}
|
||||||
|
|
||||||
// Strided store.
|
// Strided store.
|
||||||
for (uint32_t r = 0; r < type.vecsize; r++)
|
for (uint32_t r = 0; r < type.vecsize; r++)
|
||||||
{
|
{
|
||||||
@@ -3920,10 +4064,14 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val
|
|||||||
}
|
}
|
||||||
remove_duplicate_swizzle(store_expr);
|
remove_duplicate_swizzle(store_expr);
|
||||||
|
|
||||||
auto bitcast_op = bitcast_glsl_op(target_type, type);
|
if (!templated_store)
|
||||||
if (!bitcast_op.empty())
|
{
|
||||||
store_expr = join(bitcast_op, "(", store_expr, ")");
|
auto bitcast_op = bitcast_glsl_op(target_type, type);
|
||||||
statement(chain.base, ".Store(", chain.dynamic_index, chain.static_index + chain.matrix_stride * r, ", ",
|
if (!bitcast_op.empty())
|
||||||
|
store_expr = join(bitcast_op, "(", store_expr, ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
statement(chain.base, ".Store", template_expr, "(", chain.dynamic_index, chain.static_index + chain.matrix_stride * r, ", ",
|
||||||
store_expr, ");");
|
store_expr, ");");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3948,18 +4096,39 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val
|
|||||||
SPIRV_CROSS_THROW("Unknown vector size.");
|
SPIRV_CROSS_THROW("Unknown vector size.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (templated_store)
|
||||||
|
{
|
||||||
|
store_op = "Store";
|
||||||
|
auto vector_type = type;
|
||||||
|
vector_type.columns = 1;
|
||||||
|
template_expr = join("<", type_to_glsl(vector_type), ">");
|
||||||
|
}
|
||||||
|
|
||||||
for (uint32_t c = 0; c < type.columns; c++)
|
for (uint32_t c = 0; c < type.columns; c++)
|
||||||
{
|
{
|
||||||
auto store_expr = join(write_access_chain_value(value, composite_chain, true), "[", c, "]");
|
auto store_expr = join(write_access_chain_value(value, composite_chain, true), "[", c, "]");
|
||||||
auto bitcast_op = bitcast_glsl_op(target_type, type);
|
|
||||||
if (!bitcast_op.empty())
|
if (!templated_store)
|
||||||
store_expr = join(bitcast_op, "(", store_expr, ")");
|
{
|
||||||
statement(chain.base, ".", store_op, "(", chain.dynamic_index, chain.static_index + c * chain.matrix_stride,
|
auto bitcast_op = bitcast_glsl_op(target_type, type);
|
||||||
|
if (!bitcast_op.empty())
|
||||||
|
store_expr = join(bitcast_op, "(", store_expr, ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
statement(chain.base, ".", store_op, template_expr, "(", chain.dynamic_index, chain.static_index + c * chain.matrix_stride,
|
||||||
", ", store_expr, ");");
|
", ", store_expr, ");");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (templated_store)
|
||||||
|
{
|
||||||
|
auto scalar_type = type;
|
||||||
|
scalar_type.vecsize = 1;
|
||||||
|
scalar_type.columns = 1;
|
||||||
|
template_expr = join("<", type_to_glsl(scalar_type), ">");
|
||||||
|
}
|
||||||
|
|
||||||
for (uint32_t r = 0; r < type.vecsize; r++)
|
for (uint32_t r = 0; r < type.vecsize; r++)
|
||||||
{
|
{
|
||||||
for (uint32_t c = 0; c < type.columns; c++)
|
for (uint32_t c = 0; c < type.columns; c++)
|
||||||
@@ -3970,7 +4139,7 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val
|
|||||||
auto bitcast_op = bitcast_glsl_op(target_type, type);
|
auto bitcast_op = bitcast_glsl_op(target_type, type);
|
||||||
if (!bitcast_op.empty())
|
if (!bitcast_op.empty())
|
||||||
store_expr = join(bitcast_op, "(", store_expr, ")");
|
store_expr = join(bitcast_op, "(", store_expr, ")");
|
||||||
statement(chain.base, ".Store(", chain.dynamic_index,
|
statement(chain.base, ".Store", template_expr, "(", chain.dynamic_index,
|
||||||
chain.static_index + c * (type.width / 8) + r * chain.matrix_stride, ", ", store_expr, ");");
|
chain.static_index + c * (type.width / 8) + r * chain.matrix_stride, ", ", store_expr, ");");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4087,9 +4256,11 @@ void CompilerHLSL::emit_atomic(const uint32_t *ops, uint32_t length, spv::Op op)
|
|||||||
const char *atomic_op = nullptr;
|
const char *atomic_op = nullptr;
|
||||||
|
|
||||||
string value_expr;
|
string value_expr;
|
||||||
if (op != OpAtomicIDecrement && op != OpAtomicIIncrement)
|
if (op != OpAtomicIDecrement && op != OpAtomicIIncrement && op != OpAtomicLoad && op != OpAtomicStore)
|
||||||
value_expr = to_expression(ops[op == OpAtomicCompareExchange ? 6 : 5]);
|
value_expr = to_expression(ops[op == OpAtomicCompareExchange ? 6 : 5]);
|
||||||
|
|
||||||
|
bool is_atomic_store = false;
|
||||||
|
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case OpAtomicIIncrement:
|
case OpAtomicIIncrement:
|
||||||
@@ -4102,6 +4273,11 @@ void CompilerHLSL::emit_atomic(const uint32_t *ops, uint32_t length, spv::Op op)
|
|||||||
value_expr = "-1";
|
value_expr = "-1";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OpAtomicLoad:
|
||||||
|
atomic_op = "InterlockedAdd";
|
||||||
|
value_expr = "0";
|
||||||
|
break;
|
||||||
|
|
||||||
case OpAtomicISub:
|
case OpAtomicISub:
|
||||||
atomic_op = "InterlockedAdd";
|
atomic_op = "InterlockedAdd";
|
||||||
value_expr = join("-", enclose_expression(value_expr));
|
value_expr = join("-", enclose_expression(value_expr));
|
||||||
@@ -4137,6 +4313,11 @@ void CompilerHLSL::emit_atomic(const uint32_t *ops, uint32_t length, spv::Op op)
|
|||||||
atomic_op = "InterlockedExchange";
|
atomic_op = "InterlockedExchange";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OpAtomicStore:
|
||||||
|
atomic_op = "InterlockedExchange";
|
||||||
|
is_atomic_store = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case OpAtomicCompareExchange:
|
case OpAtomicCompareExchange:
|
||||||
if (length < 8)
|
if (length < 8)
|
||||||
SPIRV_CROSS_THROW("Not enough data for opcode.");
|
SPIRV_CROSS_THROW("Not enough data for opcode.");
|
||||||
@@ -4148,31 +4329,57 @@ void CompilerHLSL::emit_atomic(const uint32_t *ops, uint32_t length, spv::Op op)
|
|||||||
SPIRV_CROSS_THROW("Unknown atomic opcode.");
|
SPIRV_CROSS_THROW("Unknown atomic opcode.");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t result_type = ops[0];
|
if (is_atomic_store)
|
||||||
uint32_t id = ops[1];
|
|
||||||
forced_temporaries.insert(ops[1]);
|
|
||||||
|
|
||||||
auto &type = get<SPIRType>(result_type);
|
|
||||||
statement(variable_decl(type, to_name(id)), ";");
|
|
||||||
|
|
||||||
auto &data_type = expression_type(ops[2]);
|
|
||||||
auto *chain = maybe_get<SPIRAccessChain>(ops[2]);
|
|
||||||
SPIRType::BaseType expr_type;
|
|
||||||
if (data_type.storage == StorageClassImage || !chain)
|
|
||||||
{
|
{
|
||||||
statement(atomic_op, "(", to_expression(ops[2]), ", ", value_expr, ", ", to_name(id), ");");
|
auto &data_type = expression_type(ops[0]);
|
||||||
expr_type = data_type.basetype;
|
auto *chain = maybe_get<SPIRAccessChain>(ops[0]);
|
||||||
|
|
||||||
|
auto &tmp_id = extra_sub_expressions[ops[0]];
|
||||||
|
if (!tmp_id)
|
||||||
|
{
|
||||||
|
tmp_id = ir.increase_bound_by(1);
|
||||||
|
emit_uninitialized_temporary_expression(get_pointee_type(data_type).self, tmp_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data_type.storage == StorageClassImage || !chain)
|
||||||
|
{
|
||||||
|
statement(atomic_op, "(", to_expression(ops[0]), ", ", to_expression(ops[3]), ", ", to_expression(tmp_id), ");");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// RWByteAddress buffer is always uint in its underlying type.
|
||||||
|
statement(chain->base, ".", atomic_op, "(", chain->dynamic_index, chain->static_index, ", ", to_expression(ops[3]),
|
||||||
|
", ", to_expression(tmp_id), ");");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// RWByteAddress buffer is always uint in its underlying type.
|
uint32_t result_type = ops[0];
|
||||||
expr_type = SPIRType::UInt;
|
uint32_t id = ops[1];
|
||||||
statement(chain->base, ".", atomic_op, "(", chain->dynamic_index, chain->static_index, ", ", value_expr, ", ",
|
forced_temporaries.insert(ops[1]);
|
||||||
to_name(id), ");");
|
|
||||||
}
|
|
||||||
|
|
||||||
auto expr = bitcast_expression(type, expr_type, to_name(id));
|
auto &type = get<SPIRType>(result_type);
|
||||||
set<SPIRExpression>(id, expr, result_type, true);
|
statement(variable_decl(type, to_name(id)), ";");
|
||||||
|
|
||||||
|
auto &data_type = expression_type(ops[2]);
|
||||||
|
auto *chain = maybe_get<SPIRAccessChain>(ops[2]);
|
||||||
|
SPIRType::BaseType expr_type;
|
||||||
|
if (data_type.storage == StorageClassImage || !chain)
|
||||||
|
{
|
||||||
|
statement(atomic_op, "(", to_expression(ops[2]), ", ", value_expr, ", ", to_name(id), ");");
|
||||||
|
expr_type = data_type.basetype;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// RWByteAddress buffer is always uint in its underlying type.
|
||||||
|
expr_type = SPIRType::UInt;
|
||||||
|
statement(chain->base, ".", atomic_op, "(", chain->dynamic_index, chain->static_index, ", ", value_expr,
|
||||||
|
", ", to_name(id), ");");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto expr = bitcast_expression(type, expr_type, to_name(id));
|
||||||
|
set<SPIRExpression>(id, expr, result_type, true);
|
||||||
|
}
|
||||||
flush_all_atomic_capable_variables();
|
flush_all_atomic_capable_variables();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4796,8 +5003,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
|
|||||||
auto result_type = ops[0];
|
auto result_type = ops[0];
|
||||||
auto id = ops[1];
|
auto id = ops[1];
|
||||||
|
|
||||||
require_texture_query_variant(expression_type(ops[2]));
|
require_texture_query_variant(ops[2]);
|
||||||
|
|
||||||
auto dummy_samples_levels = join(get_fallback_name(id), "_dummy_parameter");
|
auto dummy_samples_levels = join(get_fallback_name(id), "_dummy_parameter");
|
||||||
statement("uint ", dummy_samples_levels, ";");
|
statement("uint ", dummy_samples_levels, ";");
|
||||||
|
|
||||||
@@ -4815,12 +5021,22 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
|
|||||||
auto result_type = ops[0];
|
auto result_type = ops[0];
|
||||||
auto id = ops[1];
|
auto id = ops[1];
|
||||||
|
|
||||||
require_texture_query_variant(expression_type(ops[2]));
|
require_texture_query_variant(ops[2]);
|
||||||
|
bool uav = expression_type(ops[2]).image.sampled == 2;
|
||||||
|
|
||||||
|
if (const auto *var = maybe_get_backing_variable(ops[2]))
|
||||||
|
if (hlsl_options.nonwritable_uav_texture_as_srv && has_decoration(var->self, DecorationNonWritable))
|
||||||
|
uav = false;
|
||||||
|
|
||||||
auto dummy_samples_levels = join(get_fallback_name(id), "_dummy_parameter");
|
auto dummy_samples_levels = join(get_fallback_name(id), "_dummy_parameter");
|
||||||
statement("uint ", dummy_samples_levels, ";");
|
statement("uint ", dummy_samples_levels, ";");
|
||||||
|
|
||||||
auto expr = join("SPIRV_Cross_textureSize(", to_expression(ops[2]), ", 0u, ", dummy_samples_levels, ")");
|
string expr;
|
||||||
|
if (uav)
|
||||||
|
expr = join("SPIRV_Cross_imageSize(", to_expression(ops[2]), ", ", dummy_samples_levels, ")");
|
||||||
|
else
|
||||||
|
expr = join("SPIRV_Cross_textureSize(", to_expression(ops[2]), ", 0u, ", dummy_samples_levels, ")");
|
||||||
|
|
||||||
auto &restype = get<SPIRType>(ops[0]);
|
auto &restype = get<SPIRType>(ops[0]);
|
||||||
expr = bitcast_expression(restype, SPIRType::UInt, expr);
|
expr = bitcast_expression(restype, SPIRType::UInt, expr);
|
||||||
emit_op(result_type, id, expr, true);
|
emit_op(result_type, id, expr, true);
|
||||||
@@ -4833,14 +5049,25 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
|
|||||||
auto result_type = ops[0];
|
auto result_type = ops[0];
|
||||||
auto id = ops[1];
|
auto id = ops[1];
|
||||||
|
|
||||||
require_texture_query_variant(expression_type(ops[2]));
|
require_texture_query_variant(ops[2]);
|
||||||
|
bool uav = expression_type(ops[2]).image.sampled == 2;
|
||||||
|
if (opcode == OpImageQueryLevels && uav)
|
||||||
|
SPIRV_CROSS_THROW("Cannot query levels for UAV images.");
|
||||||
|
|
||||||
|
if (const auto *var = maybe_get_backing_variable(ops[2]))
|
||||||
|
if (hlsl_options.nonwritable_uav_texture_as_srv && has_decoration(var->self, DecorationNonWritable))
|
||||||
|
uav = false;
|
||||||
|
|
||||||
// Keep it simple and do not emit special variants to make this look nicer ...
|
// Keep it simple and do not emit special variants to make this look nicer ...
|
||||||
// This stuff is barely, if ever, used.
|
// This stuff is barely, if ever, used.
|
||||||
forced_temporaries.insert(id);
|
forced_temporaries.insert(id);
|
||||||
auto &type = get<SPIRType>(result_type);
|
auto &type = get<SPIRType>(result_type);
|
||||||
statement(variable_decl(type, to_name(id)), ";");
|
statement(variable_decl(type, to_name(id)), ";");
|
||||||
statement("SPIRV_Cross_textureSize(", to_expression(ops[2]), ", 0u, ", to_name(id), ");");
|
|
||||||
|
if (uav)
|
||||||
|
statement("SPIRV_Cross_imageSize(", to_expression(ops[2]), ", ", to_name(id), ");");
|
||||||
|
else
|
||||||
|
statement("SPIRV_Cross_textureSize(", to_expression(ops[2]), ", 0u, ", to_name(id), ");");
|
||||||
|
|
||||||
auto &restype = get<SPIRType>(ops[0]);
|
auto &restype = get<SPIRType>(ops[0]);
|
||||||
auto expr = bitcast_expression(restype, SPIRType::UInt, to_name(id));
|
auto expr = bitcast_expression(restype, SPIRType::UInt, to_name(id));
|
||||||
@@ -4967,6 +5194,8 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
|
|||||||
case OpAtomicIAdd:
|
case OpAtomicIAdd:
|
||||||
case OpAtomicIIncrement:
|
case OpAtomicIIncrement:
|
||||||
case OpAtomicIDecrement:
|
case OpAtomicIDecrement:
|
||||||
|
case OpAtomicLoad:
|
||||||
|
case OpAtomicStore:
|
||||||
{
|
{
|
||||||
emit_atomic(ops, instruction.length, opcode);
|
emit_atomic(ops, instruction.length, opcode);
|
||||||
break;
|
break;
|
||||||
@@ -5152,8 +5381,16 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerHLSL::require_texture_query_variant(const SPIRType &type)
|
void CompilerHLSL::require_texture_query_variant(uint32_t var_id)
|
||||||
{
|
{
|
||||||
|
if (const auto *var = maybe_get_backing_variable(var_id))
|
||||||
|
var_id = var->self;
|
||||||
|
|
||||||
|
auto &type = expression_type(var_id);
|
||||||
|
bool uav = type.image.sampled == 2;
|
||||||
|
if (hlsl_options.nonwritable_uav_texture_as_srv && has_decoration(var_id, DecorationNonWritable))
|
||||||
|
uav = false;
|
||||||
|
|
||||||
uint32_t bit = 0;
|
uint32_t bit = 0;
|
||||||
switch (type.image.dim)
|
switch (type.image.dim)
|
||||||
{
|
{
|
||||||
@@ -5202,11 +5439,15 @@ void CompilerHLSL::require_texture_query_variant(const SPIRType &type)
|
|||||||
SPIRV_CROSS_THROW("Unsupported query type.");
|
SPIRV_CROSS_THROW("Unsupported query type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto norm_state = image_format_to_normalized_state(type.image.format);
|
||||||
|
auto &variant = uav ? required_texture_size_variants.uav[uint32_t(norm_state)][image_format_to_components(type.image.format) - 1] :
|
||||||
|
required_texture_size_variants.srv;
|
||||||
|
|
||||||
uint64_t mask = 1ull << bit;
|
uint64_t mask = 1ull << bit;
|
||||||
if ((required_textureSizeVariants & mask) == 0)
|
if ((variant & mask) == 0)
|
||||||
{
|
{
|
||||||
force_recompile();
|
force_recompile();
|
||||||
required_textureSizeVariants |= mask;
|
variant |= mask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5291,6 +5532,9 @@ void CompilerHLSL::validate_shader_model()
|
|||||||
|
|
||||||
if (ir.addressing_model != AddressingModelLogical)
|
if (ir.addressing_model != AddressingModelLogical)
|
||||||
SPIRV_CROSS_THROW("Only Logical addressing model can be used with HLSL.");
|
SPIRV_CROSS_THROW("Only Logical addressing model can be used with HLSL.");
|
||||||
|
|
||||||
|
if (hlsl_options.enable_16bit_types && hlsl_options.shader_model < 62)
|
||||||
|
SPIRV_CROSS_THROW("Need at least shader model 6.2 when enabling native 16-bit type support.");
|
||||||
}
|
}
|
||||||
|
|
||||||
string CompilerHLSL::compile()
|
string CompilerHLSL::compile()
|
||||||
@@ -5413,3 +5657,22 @@ CompilerHLSL::BitcastType CompilerHLSL::get_bitcast_type(uint32_t result_type, u
|
|||||||
|
|
||||||
return BitcastType::TypeNormal;
|
return BitcastType::TypeNormal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CompilerHLSL::is_hlsl_force_storage_buffer_as_uav(ID id) const
|
||||||
|
{
|
||||||
|
if (hlsl_options.force_storage_buffer_as_uav)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t desc_set = get_decoration(id, spv::DecorationDescriptorSet);
|
||||||
|
const uint32_t binding = get_decoration(id, spv::DecorationBinding);
|
||||||
|
|
||||||
|
return (force_uav_buffer_bindings.find({desc_set, binding}) != force_uav_buffer_bindings.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompilerHLSL::set_hlsl_force_storage_buffer_as_uav(uint32_t desc_set, uint32_t binding)
|
||||||
|
{
|
||||||
|
SetBindingPair pair = { desc_set, binding };
|
||||||
|
force_uav_buffer_bindings.insert(pair);
|
||||||
|
}
|
||||||
|
|||||||
@@ -112,12 +112,18 @@ public:
|
|||||||
|
|
||||||
// Forces a storage buffer to always be declared as UAV, even if the readonly decoration is used.
|
// Forces a storage buffer to always be declared as UAV, even if the readonly decoration is used.
|
||||||
// By default, a readonly storage buffer will be declared as ByteAddressBuffer (SRV) instead.
|
// By default, a readonly storage buffer will be declared as ByteAddressBuffer (SRV) instead.
|
||||||
|
// Alternatively, use set_hlsl_force_storage_buffer_as_uav to specify individually.
|
||||||
bool force_storage_buffer_as_uav = false;
|
bool force_storage_buffer_as_uav = false;
|
||||||
|
|
||||||
// Forces any storage image type marked as NonWritable to be considered an SRV instead.
|
// Forces any storage image type marked as NonWritable to be considered an SRV instead.
|
||||||
// For this to work with function call parameters, NonWritable must be considered to be part of the type system
|
// For this to work with function call parameters, NonWritable must be considered to be part of the type system
|
||||||
// so that NonWritable image arguments are also translated to Texture rather than RWTexture.
|
// so that NonWritable image arguments are also translated to Texture rather than RWTexture.
|
||||||
bool nonwritable_uav_texture_as_srv = false;
|
bool nonwritable_uav_texture_as_srv = false;
|
||||||
|
|
||||||
|
// Enables native 16-bit types. Needs SM 6.2.
|
||||||
|
// Uses half/int16_t/uint16_t instead of min16* types.
|
||||||
|
// Also adds support for 16-bit load-store from (RW)ByteAddressBuffer.
|
||||||
|
bool enable_16bit_types = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit CompilerHLSL(std::vector<uint32_t> spirv_)
|
explicit CompilerHLSL(std::vector<uint32_t> spirv_)
|
||||||
@@ -186,6 +192,9 @@ public:
|
|||||||
void add_hlsl_resource_binding(const HLSLResourceBinding &resource);
|
void add_hlsl_resource_binding(const HLSLResourceBinding &resource);
|
||||||
bool is_hlsl_resource_binding_used(spv::ExecutionModel model, uint32_t set, uint32_t binding) const;
|
bool is_hlsl_resource_binding_used(spv::ExecutionModel model, uint32_t set, uint32_t binding) const;
|
||||||
|
|
||||||
|
// Controls which storage buffer bindings will be forced to be declared as UAVs.
|
||||||
|
void set_hlsl_force_storage_buffer_as_uav(uint32_t desc_set, uint32_t binding);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override;
|
std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override;
|
||||||
std::string image_type_hlsl(const SPIRType &type, uint32_t id);
|
std::string image_type_hlsl(const SPIRType &type, uint32_t id);
|
||||||
@@ -245,6 +254,8 @@ private:
|
|||||||
const char *to_storage_qualifiers_glsl(const SPIRVariable &var) override;
|
const char *to_storage_qualifiers_glsl(const SPIRVariable &var) override;
|
||||||
void replace_illegal_names() override;
|
void replace_illegal_names() override;
|
||||||
|
|
||||||
|
bool is_hlsl_force_storage_buffer_as_uav(ID id) const;
|
||||||
|
|
||||||
Options hlsl_options;
|
Options hlsl_options;
|
||||||
|
|
||||||
// TODO: Refactor this to be more similar to MSL, maybe have some common system in place?
|
// TODO: Refactor this to be more similar to MSL, maybe have some common system in place?
|
||||||
@@ -264,8 +275,23 @@ private:
|
|||||||
bool requires_scalar_reflect = false;
|
bool requires_scalar_reflect = false;
|
||||||
bool requires_scalar_refract = false;
|
bool requires_scalar_refract = false;
|
||||||
bool requires_scalar_faceforward = false;
|
bool requires_scalar_faceforward = false;
|
||||||
uint64_t required_textureSizeVariants = 0;
|
|
||||||
void require_texture_query_variant(const SPIRType &type);
|
struct TextureSizeVariants
|
||||||
|
{
|
||||||
|
// MSVC 2013 workaround.
|
||||||
|
TextureSizeVariants()
|
||||||
|
{
|
||||||
|
srv = 0;
|
||||||
|
for (auto &unorm : uav)
|
||||||
|
for (auto &u : unorm)
|
||||||
|
u = 0;
|
||||||
|
}
|
||||||
|
uint64_t srv;
|
||||||
|
uint64_t uav[3][4];
|
||||||
|
} required_texture_size_variants;
|
||||||
|
|
||||||
|
void require_texture_query_variant(uint32_t var_id);
|
||||||
|
void emit_texture_size_variants(uint64_t variant_mask, const char *vecsize_qualifier, bool uav, const char *type_qualifier);
|
||||||
|
|
||||||
enum TextureQueryVariantDim
|
enum TextureQueryVariantDim
|
||||||
{
|
{
|
||||||
@@ -323,6 +349,8 @@ private:
|
|||||||
|
|
||||||
std::unordered_map<StageSetBinding, std::pair<HLSLResourceBinding, bool>, InternalHasher> resource_bindings;
|
std::unordered_map<StageSetBinding, std::pair<HLSLResourceBinding, bool>, InternalHasher> resource_bindings;
|
||||||
void remap_hlsl_resource_binding(HLSLBindingFlagBits type, uint32_t &desc_set, uint32_t &binding);
|
void remap_hlsl_resource_binding(HLSLBindingFlagBits type, uint32_t &desc_set, uint32_t &binding);
|
||||||
|
|
||||||
|
std::unordered_set<SetBindingPair, InternalHasher> force_uav_buffer_bindings;
|
||||||
};
|
};
|
||||||
} // namespace SPIRV_CROSS_NAMESPACE
|
} // namespace SPIRV_CROSS_NAMESPACE
|
||||||
|
|
||||||
|
|||||||
@@ -3087,11 +3087,11 @@ bool CompilerMSL::validate_member_packing_rules_msl(const SPIRType &type, uint32
|
|||||||
{
|
{
|
||||||
// If we have an array type, array stride must match exactly with SPIR-V.
|
// If we have an array type, array stride must match exactly with SPIR-V.
|
||||||
|
|
||||||
// An exception to this requirement is if we have one array element and a packed decoration.
|
// An exception to this requirement is if we have one array element.
|
||||||
// This comes from DX scalar layout workaround.
|
// This comes from DX scalar layout workaround.
|
||||||
// If app tries to be cheeky and access the member out of bounds, this will not work, but this is the best we can do.
|
// If app tries to be cheeky and access the member out of bounds, this will not work, but this is the best we can do.
|
||||||
bool relax_array_stride = has_extended_member_decoration(type.self, index, SPIRVCrossDecorationPhysicalTypePacked) &&
|
// In OpAccessChain with logical memory models, access chains must be in-bounds in SPIR-V specification.
|
||||||
mbr_type.array.back() == 1 && mbr_type.array_size_literal.back();
|
bool relax_array_stride = mbr_type.array.back() == 1 && mbr_type.array_size_literal.back();
|
||||||
|
|
||||||
if (!relax_array_stride)
|
if (!relax_array_stride)
|
||||||
{
|
{
|
||||||
@@ -3137,7 +3137,9 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in
|
|||||||
SPIRV_CROSS_THROW("Cannot perform any repacking for structs when it is used as a member of another struct.");
|
SPIRV_CROSS_THROW("Cannot perform any repacking for structs when it is used as a member of another struct.");
|
||||||
|
|
||||||
// Perform remapping here.
|
// Perform remapping here.
|
||||||
set_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
|
// There is nothing to be gained by using packed scalars, so don't attempt it.
|
||||||
|
if (!is_scalar(ib_type))
|
||||||
|
set_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
|
||||||
|
|
||||||
// Try validating again, now with packed.
|
// Try validating again, now with packed.
|
||||||
if (validate_member_packing_rules_msl(ib_type, index))
|
if (validate_member_packing_rules_msl(ib_type, index))
|
||||||
@@ -7038,7 +7040,11 @@ void CompilerMSL::emit_atomic_func_op(uint32_t result_type, uint32_t result_id,
|
|||||||
exp += string(", ") + get_memory_order(mem_order_2);
|
exp += string(", ") + get_memory_order(mem_order_2);
|
||||||
|
|
||||||
exp += ")";
|
exp += ")";
|
||||||
emit_op(result_type, result_id, exp, false);
|
|
||||||
|
if (strcmp(op, "atomic_store_explicit") != 0)
|
||||||
|
emit_op(result_type, result_id, exp, false);
|
||||||
|
else
|
||||||
|
statement(exp, ";");
|
||||||
}
|
}
|
||||||
|
|
||||||
flush_all_atomic_capable_variables();
|
flush_all_atomic_capable_variables();
|
||||||
@@ -8662,7 +8668,7 @@ string CompilerMSL::to_struct_member(const SPIRType &type, uint32_t member_type_
|
|||||||
td_line += ";";
|
td_line += ";";
|
||||||
add_typedef_line(td_line);
|
add_typedef_line(td_line);
|
||||||
}
|
}
|
||||||
else
|
else if (!is_scalar(physical_type)) // scalar type is already packed.
|
||||||
pack_pfx = "packed_";
|
pack_pfx = "packed_";
|
||||||
}
|
}
|
||||||
else if (row_major)
|
else if (row_major)
|
||||||
@@ -9185,7 +9191,14 @@ string CompilerMSL::get_type_address_space(const SPIRType &type, uint32_t id, bo
|
|||||||
addr_space = "constant";
|
addr_space = "constant";
|
||||||
}
|
}
|
||||||
else if (!argument)
|
else if (!argument)
|
||||||
|
{
|
||||||
addr_space = "constant";
|
addr_space = "constant";
|
||||||
|
}
|
||||||
|
else if (type_is_msl_framebuffer_fetch(type))
|
||||||
|
{
|
||||||
|
// Subpass inputs are passed around by value.
|
||||||
|
addr_space = "";
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case StorageClassFunction:
|
case StorageClassFunction:
|
||||||
@@ -9626,8 +9639,7 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args)
|
|||||||
|
|
||||||
// Use Metal's native frame-buffer fetch API for subpass inputs.
|
// Use Metal's native frame-buffer fetch API for subpass inputs.
|
||||||
const auto &basetype = get<SPIRType>(var.basetype);
|
const auto &basetype = get<SPIRType>(var.basetype);
|
||||||
if (basetype.image.dim != DimSubpassData || !msl_options.is_ios() ||
|
if (!type_is_msl_framebuffer_fetch(basetype))
|
||||||
!msl_options.ios_use_framebuffer_fetch_subpasses)
|
|
||||||
{
|
{
|
||||||
ep_args += image_type_glsl(type, var_id) + " " + r.name;
|
ep_args += image_type_glsl(type, var_id) + " " + r.name;
|
||||||
if (r.plane > 0)
|
if (r.plane > 0)
|
||||||
@@ -9639,7 +9651,7 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ep_args += image_type_glsl(type, var_id) + "4 " + r.name;
|
ep_args += image_type_glsl(type, var_id) + " " + r.name;
|
||||||
ep_args += " [[color(" + convert_to_string(r.index) + ")]]";
|
ep_args += " [[color(" + convert_to_string(r.index) + ")]]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -10125,6 +10137,12 @@ uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable &var, SPIRType::Base
|
|||||||
return resource_index;
|
return resource_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CompilerMSL::type_is_msl_framebuffer_fetch(const SPIRType &type) const
|
||||||
|
{
|
||||||
|
return type.basetype == SPIRType::Image && type.image.dim == DimSubpassData &&
|
||||||
|
msl_options.is_ios() && msl_options.ios_use_framebuffer_fetch_subpasses;
|
||||||
|
}
|
||||||
|
|
||||||
string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
|
string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
|
||||||
{
|
{
|
||||||
auto &var = get<SPIRVariable>(arg.id);
|
auto &var = get<SPIRVariable>(arg.id);
|
||||||
@@ -10140,6 +10158,9 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
|
|||||||
name_id = var.basevariable;
|
name_id = var.basevariable;
|
||||||
|
|
||||||
bool constref = !arg.alias_global_variable && is_pointer && arg.write_count == 0;
|
bool constref = !arg.alias_global_variable && is_pointer && arg.write_count == 0;
|
||||||
|
// Framebuffer fetch is plain value, const looks out of place, but it is not wrong.
|
||||||
|
if (type_is_msl_framebuffer_fetch(type))
|
||||||
|
constref = false;
|
||||||
|
|
||||||
bool type_is_image = type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage ||
|
bool type_is_image = type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage ||
|
||||||
type.basetype == SPIRType::Sampler;
|
type.basetype == SPIRType::Sampler;
|
||||||
@@ -10638,6 +10659,9 @@ void CompilerMSL::replace_illegal_names()
|
|||||||
|
|
||||||
string CompilerMSL::to_member_reference(uint32_t base, const SPIRType &type, uint32_t index, bool ptr_chain)
|
string CompilerMSL::to_member_reference(uint32_t base, const SPIRType &type, uint32_t index, bool ptr_chain)
|
||||||
{
|
{
|
||||||
|
if (index < uint32_t(type.member_type_index_redirection.size()))
|
||||||
|
index = type.member_type_index_redirection[index];
|
||||||
|
|
||||||
auto *var = maybe_get<SPIRVariable>(base);
|
auto *var = maybe_get<SPIRVariable>(base);
|
||||||
// If this is a buffer array, we have to dereference the buffer pointers.
|
// If this is a buffer array, we have to dereference the buffer pointers.
|
||||||
// Otherwise, if this is a pointer expression, dereference it.
|
// Otherwise, if this is a pointer expression, dereference it.
|
||||||
@@ -10983,10 +11007,11 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Use Metal's native frame-buffer fetch API for subpass inputs.
|
// Use Metal's native frame-buffer fetch API for subpass inputs.
|
||||||
if (img_type.dim == DimSubpassData && msl_options.is_ios() &&
|
if (type_is_msl_framebuffer_fetch(type))
|
||||||
msl_options.ios_use_framebuffer_fetch_subpasses)
|
|
||||||
{
|
{
|
||||||
return type_to_glsl(get<SPIRType>(img_type.type));
|
auto img_type_4 = get<SPIRType>(img_type.type);
|
||||||
|
img_type_4.vecsize = 4;
|
||||||
|
return type_to_glsl(img_type_4);
|
||||||
}
|
}
|
||||||
if (img_type.ms && img_type.arrayed)
|
if (img_type.ms && img_type.arrayed)
|
||||||
{
|
{
|
||||||
@@ -12437,9 +12462,28 @@ void CompilerMSL::MemberSorter::sort()
|
|||||||
// the members should be reordered, based on builtin and sorting aspect meta info.
|
// the members should be reordered, based on builtin and sorting aspect meta info.
|
||||||
size_t mbr_cnt = type.member_types.size();
|
size_t mbr_cnt = type.member_types.size();
|
||||||
SmallVector<uint32_t> mbr_idxs(mbr_cnt);
|
SmallVector<uint32_t> mbr_idxs(mbr_cnt);
|
||||||
iota(mbr_idxs.begin(), mbr_idxs.end(), 0); // Fill with consecutive indices
|
std::iota(mbr_idxs.begin(), mbr_idxs.end(), 0); // Fill with consecutive indices
|
||||||
std::stable_sort(mbr_idxs.begin(), mbr_idxs.end(), *this); // Sort member indices based on sorting aspect
|
std::stable_sort(mbr_idxs.begin(), mbr_idxs.end(), *this); // Sort member indices based on sorting aspect
|
||||||
|
|
||||||
|
bool sort_is_identity = true;
|
||||||
|
for (uint32_t mbr_idx = 0; mbr_idx < mbr_cnt; mbr_idx++)
|
||||||
|
{
|
||||||
|
if (mbr_idx != mbr_idxs[mbr_idx])
|
||||||
|
{
|
||||||
|
sort_is_identity = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sort_is_identity)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (meta.members.size() < type.member_types.size())
|
||||||
|
{
|
||||||
|
// This should never trigger in normal circumstances, but to be safe.
|
||||||
|
meta.members.resize(type.member_types.size());
|
||||||
|
}
|
||||||
|
|
||||||
// Move type and meta member info to the order defined by the sorted member indices.
|
// Move type and meta member info to the order defined by the sorted member indices.
|
||||||
// This is done by creating temporary copies of both member types and meta, and then
|
// This is done by creating temporary copies of both member types and meta, and then
|
||||||
// copying back to the original content at the sorted indices.
|
// copying back to the original content at the sorted indices.
|
||||||
@@ -12450,6 +12494,13 @@ void CompilerMSL::MemberSorter::sort()
|
|||||||
type.member_types[mbr_idx] = mbr_types_cpy[mbr_idxs[mbr_idx]];
|
type.member_types[mbr_idx] = mbr_types_cpy[mbr_idxs[mbr_idx]];
|
||||||
meta.members[mbr_idx] = mbr_meta_cpy[mbr_idxs[mbr_idx]];
|
meta.members[mbr_idx] = mbr_meta_cpy[mbr_idxs[mbr_idx]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sort_aspect == SortAspect::Offset)
|
||||||
|
{
|
||||||
|
// If we're sorting by Offset, this might affect user code which accesses a buffer block.
|
||||||
|
// We will need to redirect member indices from one index to sorted index.
|
||||||
|
type.member_type_index_redirection = std::move(mbr_idxs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort first by builtin status (put builtins at end), then by the sorting aspect.
|
// Sort first by builtin status (put builtins at end), then by the sorting aspect.
|
||||||
|
|||||||
@@ -43,10 +43,6 @@ enum MSLVertexFormat
|
|||||||
struct MSLVertexAttr
|
struct MSLVertexAttr
|
||||||
{
|
{
|
||||||
uint32_t location = 0;
|
uint32_t location = 0;
|
||||||
uint32_t msl_buffer = 0;
|
|
||||||
uint32_t msl_offset = 0;
|
|
||||||
uint32_t msl_stride = 0;
|
|
||||||
bool per_instance = false;
|
|
||||||
MSLVertexFormat format = MSL_VERTEX_FORMAT_OTHER;
|
MSLVertexFormat format = MSL_VERTEX_FORMAT_OTHER;
|
||||||
spv::BuiltIn builtin = spv::BuiltInMax;
|
spv::BuiltIn builtin = spv::BuiltInMax;
|
||||||
};
|
};
|
||||||
@@ -324,12 +320,12 @@ public:
|
|||||||
// can be read in subsequent stages.
|
// can be read in subsequent stages.
|
||||||
bool enable_clip_distance_user_varying = true;
|
bool enable_clip_distance_user_varying = true;
|
||||||
|
|
||||||
bool is_ios()
|
bool is_ios() const
|
||||||
{
|
{
|
||||||
return platform == iOS;
|
return platform == iOS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_macos()
|
bool is_macos() const
|
||||||
{
|
{
|
||||||
return platform == macOS;
|
return platform == macOS;
|
||||||
}
|
}
|
||||||
@@ -898,6 +894,8 @@ protected:
|
|||||||
|
|
||||||
void activate_argument_buffer_resources();
|
void activate_argument_buffer_resources();
|
||||||
|
|
||||||
|
bool type_is_msl_framebuffer_fetch(const SPIRType &type) const;
|
||||||
|
|
||||||
// OpcodeHandler that handles several MSL preprocessing operations.
|
// OpcodeHandler that handles several MSL preprocessing operations.
|
||||||
struct OpCodePreprocessor : OpcodeHandler
|
struct OpCodePreprocessor : OpcodeHandler
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -119,6 +119,16 @@ void Parser::parse()
|
|||||||
for (auto &i : instructions)
|
for (auto &i : instructions)
|
||||||
parse(i);
|
parse(i);
|
||||||
|
|
||||||
|
for (auto &fixup : forward_pointer_fixups)
|
||||||
|
{
|
||||||
|
auto &target = get<SPIRType>(fixup.first);
|
||||||
|
auto &source = get<SPIRType>(fixup.second);
|
||||||
|
target.member_types = source.member_types;
|
||||||
|
target.basetype = source.basetype;
|
||||||
|
target.self = source.self;
|
||||||
|
}
|
||||||
|
forward_pointer_fixups.clear();
|
||||||
|
|
||||||
if (current_function)
|
if (current_function)
|
||||||
SPIRV_CROSS_THROW("Function was not terminated.");
|
SPIRV_CROSS_THROW("Function was not terminated.");
|
||||||
if (current_block)
|
if (current_block)
|
||||||
@@ -543,6 +553,11 @@ void Parser::parse(const Instruction &instruction)
|
|||||||
auto *c = maybe_get<SPIRConstant>(cid);
|
auto *c = maybe_get<SPIRConstant>(cid);
|
||||||
bool literal = c && !c->specialization;
|
bool literal = c && !c->specialization;
|
||||||
|
|
||||||
|
// We're copying type information into Array types, so we'll need a fixup for any physical pointer
|
||||||
|
// references.
|
||||||
|
if (base.forward_pointer)
|
||||||
|
forward_pointer_fixups.push_back({ id, tid });
|
||||||
|
|
||||||
arraybase.array_size_literal.push_back(literal);
|
arraybase.array_size_literal.push_back(literal);
|
||||||
arraybase.array.push_back(literal ? c->scalar() : cid);
|
arraybase.array.push_back(literal ? c->scalar() : cid);
|
||||||
// Do NOT set arraybase.self!
|
// Do NOT set arraybase.self!
|
||||||
@@ -556,6 +571,11 @@ void Parser::parse(const Instruction &instruction)
|
|||||||
auto &base = get<SPIRType>(ops[1]);
|
auto &base = get<SPIRType>(ops[1]);
|
||||||
auto &arraybase = set<SPIRType>(id);
|
auto &arraybase = set<SPIRType>(id);
|
||||||
|
|
||||||
|
// We're copying type information into Array types, so we'll need a fixup for any physical pointer
|
||||||
|
// references.
|
||||||
|
if (base.forward_pointer)
|
||||||
|
forward_pointer_fixups.push_back({ id, ops[1] });
|
||||||
|
|
||||||
arraybase = base;
|
arraybase = base;
|
||||||
arraybase.array.push_back(0);
|
arraybase.array.push_back(0);
|
||||||
arraybase.array_size_literal.push_back(true);
|
arraybase.array_size_literal.push_back(true);
|
||||||
@@ -614,6 +634,9 @@ void Parser::parse(const Instruction &instruction)
|
|||||||
if (ptrbase.storage == StorageClassAtomicCounter)
|
if (ptrbase.storage == StorageClassAtomicCounter)
|
||||||
ptrbase.basetype = SPIRType::AtomicCounter;
|
ptrbase.basetype = SPIRType::AtomicCounter;
|
||||||
|
|
||||||
|
if (base.forward_pointer)
|
||||||
|
forward_pointer_fixups.push_back({ id, ops[2] });
|
||||||
|
|
||||||
ptrbase.parent_type = ops[2];
|
ptrbase.parent_type = ops[2];
|
||||||
|
|
||||||
// Do NOT set ptrbase.self!
|
// Do NOT set ptrbase.self!
|
||||||
@@ -627,6 +650,7 @@ void Parser::parse(const Instruction &instruction)
|
|||||||
ptrbase.pointer = true;
|
ptrbase.pointer = true;
|
||||||
ptrbase.pointer_depth++;
|
ptrbase.pointer_depth++;
|
||||||
ptrbase.storage = static_cast<StorageClass>(ops[1]);
|
ptrbase.storage = static_cast<StorageClass>(ops[1]);
|
||||||
|
ptrbase.forward_pointer = true;
|
||||||
|
|
||||||
if (ptrbase.storage == StorageClassAtomicCounter)
|
if (ptrbase.storage == StorageClassAtomicCounter)
|
||||||
ptrbase.basetype = SPIRType::AtomicCounter;
|
ptrbase.basetype = SPIRType::AtomicCounter;
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ private:
|
|||||||
|
|
||||||
// This must be an ordered data structure so we always pick the same type aliases.
|
// This must be an ordered data structure so we always pick the same type aliases.
|
||||||
SmallVector<uint32_t> global_struct_cache;
|
SmallVector<uint32_t> global_struct_cache;
|
||||||
|
SmallVector<std::pair<uint32_t, uint32_t>> forward_pointer_fixups;
|
||||||
|
|
||||||
bool types_are_logically_equivalent(const SPIRType &a, const SPIRType &b) const;
|
bool types_are_logically_equivalent(const SPIRType &a, const SPIRType &b) const;
|
||||||
bool variable_storage_is_aliased(const SPIRVariable &v) const;
|
bool variable_storage_is_aliased(const SPIRVariable &v) const;
|
||||||
|
|||||||
@@ -277,23 +277,54 @@ string CompilerReflection::compile()
|
|||||||
return json_stream->str();
|
return json_stream->str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool naturally_emit_type(const SPIRType &type)
|
||||||
|
{
|
||||||
|
return type.basetype == SPIRType::Struct && !type.pointer && type.array.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompilerReflection::type_is_reference(const SPIRType &type) const
|
||||||
|
{
|
||||||
|
// Physical pointers and arrays of physical pointers need to refer to the pointee's type.
|
||||||
|
return type_is_top_level_physical_pointer(type) ||
|
||||||
|
(!type.array.empty() && type_is_top_level_physical_pointer(get<SPIRType>(type.parent_type)));
|
||||||
|
}
|
||||||
|
|
||||||
void CompilerReflection::emit_types()
|
void CompilerReflection::emit_types()
|
||||||
{
|
{
|
||||||
bool emitted_open_tag = false;
|
bool emitted_open_tag = false;
|
||||||
|
|
||||||
ir.for_each_typed_id<SPIRType>([&](uint32_t, SPIRType &type) {
|
SmallVector<uint32_t> physical_pointee_types;
|
||||||
if (type.basetype == SPIRType::Struct && !type.pointer && type.array.empty())
|
|
||||||
emit_type(type, emitted_open_tag);
|
// If we have physical pointers or arrays of physical pointers, it's also helpful to emit the pointee type
|
||||||
|
// and chain the type hierarchy. For POD, arrays can emit the entire type in-place.
|
||||||
|
ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &type) {
|
||||||
|
if (naturally_emit_type(type))
|
||||||
|
{
|
||||||
|
emit_type(self, emitted_open_tag);
|
||||||
|
}
|
||||||
|
else if (type_is_reference(type))
|
||||||
|
{
|
||||||
|
if (!naturally_emit_type(this->get<SPIRType>(type.parent_type)) &&
|
||||||
|
find(physical_pointee_types.begin(), physical_pointee_types.end(),
|
||||||
|
type.parent_type) == physical_pointee_types.end())
|
||||||
|
{
|
||||||
|
physical_pointee_types.push_back(type.parent_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for (uint32_t pointee_type : physical_pointee_types)
|
||||||
|
emit_type(pointee_type, emitted_open_tag);
|
||||||
|
|
||||||
if (emitted_open_tag)
|
if (emitted_open_tag)
|
||||||
{
|
{
|
||||||
json_stream->end_json_object();
|
json_stream->end_json_object();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilerReflection::emit_type(const SPIRType &type, bool &emitted_open_tag)
|
void CompilerReflection::emit_type(uint32_t type_id, bool &emitted_open_tag)
|
||||||
{
|
{
|
||||||
|
auto &type = get<SPIRType>(type_id);
|
||||||
auto name = type_to_glsl(type);
|
auto name = type_to_glsl(type);
|
||||||
|
|
||||||
if (type.type_alias != TypeID(0))
|
if (type.type_alias != TypeID(0))
|
||||||
@@ -304,26 +335,42 @@ void CompilerReflection::emit_type(const SPIRType &type, bool &emitted_open_tag)
|
|||||||
json_stream->emit_json_key_object("types");
|
json_stream->emit_json_key_object("types");
|
||||||
emitted_open_tag = true;
|
emitted_open_tag = true;
|
||||||
}
|
}
|
||||||
json_stream->emit_json_key_object("_" + std::to_string(type.self));
|
json_stream->emit_json_key_object("_" + std::to_string(type_id));
|
||||||
json_stream->emit_json_key_value("name", name);
|
json_stream->emit_json_key_value("name", name);
|
||||||
json_stream->emit_json_key_array("members");
|
|
||||||
// FIXME ideally we'd like to emit the size of a structure as a
|
if (type_is_top_level_physical_pointer(type))
|
||||||
// convenience to people parsing the reflected JSON. The problem
|
|
||||||
// is that there's no implicit size for a type. It's final size
|
|
||||||
// will be determined by the top level declaration in which it's
|
|
||||||
// included. So there might be one size for the struct if it's
|
|
||||||
// included in a std140 uniform block and another if it's included
|
|
||||||
// in a std430 uniform block.
|
|
||||||
// The solution is to include *all* potential sizes as a map of
|
|
||||||
// layout type name to integer, but that will probably require
|
|
||||||
// some additional logic being written in this class, or in the
|
|
||||||
// parent CompilerGLSL class.
|
|
||||||
auto size = type.member_types.size();
|
|
||||||
for (uint32_t i = 0; i < size; ++i)
|
|
||||||
{
|
{
|
||||||
emit_type_member(type, i);
|
json_stream->emit_json_key_value("type", "_" + std::to_string(type.parent_type));
|
||||||
|
json_stream->emit_json_key_value("physical_pointer", true);
|
||||||
}
|
}
|
||||||
json_stream->end_json_array();
|
else if (!type.array.empty())
|
||||||
|
{
|
||||||
|
emit_type_array(type);
|
||||||
|
json_stream->emit_json_key_value("type", "_" + std::to_string(type.parent_type));
|
||||||
|
json_stream->emit_json_key_value("array_stride", get_decoration(type_id, DecorationArrayStride));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
json_stream->emit_json_key_array("members");
|
||||||
|
// FIXME ideally we'd like to emit the size of a structure as a
|
||||||
|
// convenience to people parsing the reflected JSON. The problem
|
||||||
|
// is that there's no implicit size for a type. It's final size
|
||||||
|
// will be determined by the top level declaration in which it's
|
||||||
|
// included. So there might be one size for the struct if it's
|
||||||
|
// included in a std140 uniform block and another if it's included
|
||||||
|
// in a std430 uniform block.
|
||||||
|
// The solution is to include *all* potential sizes as a map of
|
||||||
|
// layout type name to integer, but that will probably require
|
||||||
|
// some additional logic being written in this class, or in the
|
||||||
|
// parent CompilerGLSL class.
|
||||||
|
auto size = type.member_types.size();
|
||||||
|
for (uint32_t i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
emit_type_member(type, i);
|
||||||
|
}
|
||||||
|
json_stream->end_json_array();
|
||||||
|
}
|
||||||
|
|
||||||
json_stream->end_json_object();
|
json_stream->end_json_object();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,7 +382,12 @@ void CompilerReflection::emit_type_member(const SPIRType &type, uint32_t index)
|
|||||||
// FIXME we'd like to emit the offset of each member, but such offsets are
|
// FIXME we'd like to emit the offset of each member, but such offsets are
|
||||||
// context dependent. See the comment above regarding structure sizes
|
// context dependent. See the comment above regarding structure sizes
|
||||||
json_stream->emit_json_key_value("name", name);
|
json_stream->emit_json_key_value("name", name);
|
||||||
if (membertype.basetype == SPIRType::Struct)
|
|
||||||
|
if (type_is_reference(membertype))
|
||||||
|
{
|
||||||
|
json_stream->emit_json_key_value("type", "_" + std::to_string(membertype.parent_type));
|
||||||
|
}
|
||||||
|
else if (membertype.basetype == SPIRType::Struct)
|
||||||
{
|
{
|
||||||
json_stream->emit_json_key_value("type", "_" + std::to_string(membertype.self));
|
json_stream->emit_json_key_value("type", "_" + std::to_string(membertype.self));
|
||||||
}
|
}
|
||||||
@@ -349,7 +401,7 @@ void CompilerReflection::emit_type_member(const SPIRType &type, uint32_t index)
|
|||||||
|
|
||||||
void CompilerReflection::emit_type_array(const SPIRType &type)
|
void CompilerReflection::emit_type_array(const SPIRType &type)
|
||||||
{
|
{
|
||||||
if (!type.array.empty())
|
if (!type_is_top_level_physical_pointer(type) && !type.array.empty())
|
||||||
{
|
{
|
||||||
json_stream->emit_json_key_array("array");
|
json_stream->emit_json_key_array("array");
|
||||||
// Note that we emit the zeros here as a means of identifying
|
// Note that we emit the zeros here as a means of identifying
|
||||||
@@ -388,6 +440,9 @@ void CompilerReflection::emit_type_member_qualifiers(const SPIRType &type, uint3
|
|||||||
json_stream->emit_json_key_value("matrix_stride", dec.matrix_stride);
|
json_stream->emit_json_key_value("matrix_stride", dec.matrix_stride);
|
||||||
if (dec.decoration_flags.get(DecorationRowMajor))
|
if (dec.decoration_flags.get(DecorationRowMajor))
|
||||||
json_stream->emit_json_key_value("row_major", true);
|
json_stream->emit_json_key_value("row_major", true);
|
||||||
|
|
||||||
|
if (type_is_top_level_physical_pointer(membertype))
|
||||||
|
json_stream->emit_json_key_value("physical_pointer", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,11 +67,12 @@ private:
|
|||||||
void emit_resources();
|
void emit_resources();
|
||||||
void emit_specialization_constants();
|
void emit_specialization_constants();
|
||||||
|
|
||||||
void emit_type(const SPIRType &type, bool &emitted_open_tag);
|
void emit_type(uint32_t type_id, bool &emitted_open_tag);
|
||||||
void emit_type_member(const SPIRType &type, uint32_t index);
|
void emit_type_member(const SPIRType &type, uint32_t index);
|
||||||
void emit_type_member_qualifiers(const SPIRType &type, uint32_t index);
|
void emit_type_member_qualifiers(const SPIRType &type, uint32_t index);
|
||||||
void emit_type_array(const SPIRType &type);
|
void emit_type_array(const SPIRType &type);
|
||||||
void emit_resources(const char *tag, const SmallVector<Resource> &resources);
|
void emit_resources(const char *tag, const SmallVector<Resource> &resources);
|
||||||
|
bool type_is_reference(const SPIRType &type) const;
|
||||||
|
|
||||||
std::string to_member_name(const SPIRType &type, uint32_t index) const;
|
std::string to_member_name(const SPIRType &type, uint32_t index) const;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user