metal: update spirv-cross

This commit is contained in:
Alex Szpakowski
2020-04-26 11:44:53 -03:00
parent ceb1e4459b
commit 910ede47cc
28 changed files with 2138 additions and 376 deletions
@@ -85,7 +85,7 @@ struct sampler2DBase : spirv_cross_sampler_2d
std::vector<spirv_cross_miplevel> mips;
spirv_cross_format format;
spirv_cross_wrap wrap_s;
spirv_cross_format wrap_t;
spirv_cross_wrap wrap_t;
spirv_cross_filter min_filter;
spirv_cross_filter mag_filter;
spirv_cross_mipfilter mip_filter;
+134 -2
View File
@@ -1,5 +1,5 @@
/*
** Copyright (c) 2014-2019 The Khronos Group Inc.
** Copyright (c) 2014-2020 The Khronos Group Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and/or associated documentation files (the "Materials"),
@@ -57,7 +57,7 @@ typedef unsigned int SpvId;
#define SPV_REVISION 1
static const unsigned int SpvMagicNumber = 0x07230203;
static const unsigned int SpvVersion = 0x00010400;
static const unsigned int SpvVersion = 0x00010500;
static const unsigned int SpvRevision = 1;
static const unsigned int SpvOpCodeMask = 0xffff;
static const unsigned int SpvWordCountShift = 16;
@@ -82,11 +82,17 @@ typedef enum SpvExecutionModel_ {
SpvExecutionModelKernel = 6,
SpvExecutionModelTaskNV = 5267,
SpvExecutionModelMeshNV = 5268,
SpvExecutionModelRayGenerationKHR = 5313,
SpvExecutionModelRayGenerationNV = 5313,
SpvExecutionModelIntersectionKHR = 5314,
SpvExecutionModelIntersectionNV = 5314,
SpvExecutionModelAnyHitKHR = 5315,
SpvExecutionModelAnyHitNV = 5315,
SpvExecutionModelClosestHitKHR = 5316,
SpvExecutionModelClosestHitNV = 5316,
SpvExecutionModelMissKHR = 5317,
SpvExecutionModelMissNV = 5317,
SpvExecutionModelCallableKHR = 5318,
SpvExecutionModelCallableNV = 5318,
SpvExecutionModelMax = 0x7fffffff,
} SpvExecutionModel;
@@ -183,11 +189,17 @@ typedef enum SpvStorageClass_ {
SpvStorageClassAtomicCounter = 10,
SpvStorageClassImage = 11,
SpvStorageClassStorageBuffer = 12,
SpvStorageClassCallableDataKHR = 5328,
SpvStorageClassCallableDataNV = 5328,
SpvStorageClassIncomingCallableDataKHR = 5329,
SpvStorageClassIncomingCallableDataNV = 5329,
SpvStorageClassRayPayloadKHR = 5338,
SpvStorageClassRayPayloadNV = 5338,
SpvStorageClassHitAttributeKHR = 5339,
SpvStorageClassHitAttributeNV = 5339,
SpvStorageClassIncomingRayPayloadKHR = 5342,
SpvStorageClassIncomingRayPayloadNV = 5342,
SpvStorageClassShaderRecordBufferKHR = 5343,
SpvStorageClassShaderRecordBufferNV = 5343,
SpvStorageClassPhysicalStorageBuffer = 5349,
SpvStorageClassPhysicalStorageBufferEXT = 5349,
@@ -562,20 +574,35 @@ typedef enum SpvBuiltIn_ {
SpvBuiltInFragmentSizeNV = 5292,
SpvBuiltInFragInvocationCountEXT = 5293,
SpvBuiltInInvocationsPerPixelNV = 5293,
SpvBuiltInLaunchIdKHR = 5319,
SpvBuiltInLaunchIdNV = 5319,
SpvBuiltInLaunchSizeKHR = 5320,
SpvBuiltInLaunchSizeNV = 5320,
SpvBuiltInWorldRayOriginKHR = 5321,
SpvBuiltInWorldRayOriginNV = 5321,
SpvBuiltInWorldRayDirectionKHR = 5322,
SpvBuiltInWorldRayDirectionNV = 5322,
SpvBuiltInObjectRayOriginKHR = 5323,
SpvBuiltInObjectRayOriginNV = 5323,
SpvBuiltInObjectRayDirectionKHR = 5324,
SpvBuiltInObjectRayDirectionNV = 5324,
SpvBuiltInRayTminKHR = 5325,
SpvBuiltInRayTminNV = 5325,
SpvBuiltInRayTmaxKHR = 5326,
SpvBuiltInRayTmaxNV = 5326,
SpvBuiltInInstanceCustomIndexKHR = 5327,
SpvBuiltInInstanceCustomIndexNV = 5327,
SpvBuiltInObjectToWorldKHR = 5330,
SpvBuiltInObjectToWorldNV = 5330,
SpvBuiltInWorldToObjectKHR = 5331,
SpvBuiltInWorldToObjectNV = 5331,
SpvBuiltInHitTKHR = 5332,
SpvBuiltInHitTNV = 5332,
SpvBuiltInHitKindKHR = 5333,
SpvBuiltInHitKindNV = 5333,
SpvBuiltInIncomingRayFlagsKHR = 5351,
SpvBuiltInIncomingRayFlagsNV = 5351,
SpvBuiltInRayGeometryIndexKHR = 5352,
SpvBuiltInWarpsPerSMNV = 5374,
SpvBuiltInSMCountNV = 5375,
SpvBuiltInWarpIDNV = 5376,
@@ -713,6 +740,7 @@ typedef enum SpvScope_ {
SpvScopeInvocation = 4,
SpvScopeQueueFamily = 5,
SpvScopeQueueFamilyKHR = 5,
SpvScopeShaderCallKHR = 6,
SpvScopeMax = 0x7fffffff,
} SpvScope;
@@ -837,6 +865,8 @@ typedef enum SpvCapability_ {
SpvCapabilitySignedZeroInfNanPreserve = 4466,
SpvCapabilityRoundingModeRTE = 4467,
SpvCapabilityRoundingModeRTZ = 4468,
SpvCapabilityRayQueryProvisionalKHR = 4471,
SpvCapabilityRayTraversalPrimitiveCullingProvisionalKHR = 4478,
SpvCapabilityFloat16ImageAMD = 5008,
SpvCapabilityImageGatherBiasLodAMD = 5009,
SpvCapabilityFragmentMaskAMD = 5010,
@@ -890,6 +920,7 @@ typedef enum SpvCapability_ {
SpvCapabilityPhysicalStorageBufferAddresses = 5347,
SpvCapabilityPhysicalStorageBufferAddressesEXT = 5347,
SpvCapabilityComputeDerivativeGroupLinearNV = 5350,
SpvCapabilityRayTracingProvisionalKHR = 5353,
SpvCapabilityCooperativeMatrixNV = 5357,
SpvCapabilityFragmentShaderSampleInterlockEXT = 5363,
SpvCapabilityFragmentShaderShadingRateInterlockEXT = 5372,
@@ -907,6 +938,53 @@ typedef enum SpvCapability_ {
SpvCapabilityMax = 0x7fffffff,
} SpvCapability;
typedef enum SpvRayFlagsShift_ {
SpvRayFlagsOpaqueKHRShift = 0,
SpvRayFlagsNoOpaqueKHRShift = 1,
SpvRayFlagsTerminateOnFirstHitKHRShift = 2,
SpvRayFlagsSkipClosestHitShaderKHRShift = 3,
SpvRayFlagsCullBackFacingTrianglesKHRShift = 4,
SpvRayFlagsCullFrontFacingTrianglesKHRShift = 5,
SpvRayFlagsCullOpaqueKHRShift = 6,
SpvRayFlagsCullNoOpaqueKHRShift = 7,
SpvRayFlagsSkipTrianglesKHRShift = 8,
SpvRayFlagsSkipAABBsKHRShift = 9,
SpvRayFlagsMax = 0x7fffffff,
} SpvRayFlagsShift;
typedef enum SpvRayFlagsMask_ {
SpvRayFlagsMaskNone = 0,
SpvRayFlagsOpaqueKHRMask = 0x00000001,
SpvRayFlagsNoOpaqueKHRMask = 0x00000002,
SpvRayFlagsTerminateOnFirstHitKHRMask = 0x00000004,
SpvRayFlagsSkipClosestHitShaderKHRMask = 0x00000008,
SpvRayFlagsCullBackFacingTrianglesKHRMask = 0x00000010,
SpvRayFlagsCullFrontFacingTrianglesKHRMask = 0x00000020,
SpvRayFlagsCullOpaqueKHRMask = 0x00000040,
SpvRayFlagsCullNoOpaqueKHRMask = 0x00000080,
SpvRayFlagsSkipTrianglesKHRMask = 0x00000100,
SpvRayFlagsSkipAABBsKHRMask = 0x00000200,
} SpvRayFlagsMask;
typedef enum SpvRayQueryIntersection_ {
SpvRayQueryIntersectionRayQueryCandidateIntersectionKHR = 0,
SpvRayQueryIntersectionRayQueryCommittedIntersectionKHR = 1,
SpvRayQueryIntersectionMax = 0x7fffffff,
} SpvRayQueryIntersection;
typedef enum SpvRayQueryCommittedIntersectionType_ {
SpvRayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionNoneKHR = 0,
SpvRayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionTriangleKHR = 1,
SpvRayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionGeneratedKHR = 2,
SpvRayQueryCommittedIntersectionTypeMax = 0x7fffffff,
} SpvRayQueryCommittedIntersectionType;
typedef enum SpvRayQueryCandidateIntersectionType_ {
SpvRayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionTriangleKHR = 0,
SpvRayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionAABBKHR = 1,
SpvRayQueryCandidateIntersectionTypeMax = 0x7fffffff,
} SpvRayQueryCandidateIntersectionType;
typedef enum SpvOp_ {
SpvOpNop = 0,
SpvOpUndef = 1,
@@ -1258,6 +1336,13 @@ typedef enum SpvOp_ {
SpvOpSubgroupAnyKHR = 4429,
SpvOpSubgroupAllEqualKHR = 4430,
SpvOpSubgroupReadInvocationKHR = 4432,
SpvOpTypeRayQueryProvisionalKHR = 4472,
SpvOpRayQueryInitializeKHR = 4473,
SpvOpRayQueryTerminateKHR = 4474,
SpvOpRayQueryGenerateIntersectionKHR = 4475,
SpvOpRayQueryConfirmIntersectionKHR = 4476,
SpvOpRayQueryProceedKHR = 4477,
SpvOpRayQueryGetIntersectionTypeKHR = 4479,
SpvOpGroupIAddNonUniformAMD = 5000,
SpvOpGroupFAddNonUniformAMD = 5001,
SpvOpGroupFMinNonUniformAMD = 5002,
@@ -1272,11 +1357,17 @@ typedef enum SpvOp_ {
SpvOpImageSampleFootprintNV = 5283,
SpvOpGroupNonUniformPartitionNV = 5296,
SpvOpWritePackedPrimitiveIndices4x8NV = 5299,
SpvOpReportIntersectionKHR = 5334,
SpvOpReportIntersectionNV = 5334,
SpvOpIgnoreIntersectionKHR = 5335,
SpvOpIgnoreIntersectionNV = 5335,
SpvOpTerminateRayKHR = 5336,
SpvOpTerminateRayNV = 5336,
SpvOpTraceNV = 5337,
SpvOpTraceRayKHR = 5337,
SpvOpTypeAccelerationStructureKHR = 5341,
SpvOpTypeAccelerationStructureNV = 5341,
SpvOpExecuteCallableKHR = 5344,
SpvOpExecuteCallableNV = 5344,
SpvOpTypeCooperativeMatrixNV = 5358,
SpvOpCooperativeMatrixLoadNV = 5359,
@@ -1433,6 +1524,23 @@ typedef enum SpvOp_ {
SpvOpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814,
SpvOpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815,
SpvOpSubgroupAvcSicGetInterRawSadsINTEL = 5816,
SpvOpRayQueryGetRayTMinKHR = 6016,
SpvOpRayQueryGetRayFlagsKHR = 6017,
SpvOpRayQueryGetIntersectionTKHR = 6018,
SpvOpRayQueryGetIntersectionInstanceCustomIndexKHR = 6019,
SpvOpRayQueryGetIntersectionInstanceIdKHR = 6020,
SpvOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR = 6021,
SpvOpRayQueryGetIntersectionGeometryIndexKHR = 6022,
SpvOpRayQueryGetIntersectionPrimitiveIndexKHR = 6023,
SpvOpRayQueryGetIntersectionBarycentricsKHR = 6024,
SpvOpRayQueryGetIntersectionFrontFaceKHR = 6025,
SpvOpRayQueryGetIntersectionCandidateAABBOpaqueKHR = 6026,
SpvOpRayQueryGetIntersectionObjectRayDirectionKHR = 6027,
SpvOpRayQueryGetIntersectionObjectRayOriginKHR = 6028,
SpvOpRayQueryGetWorldRayDirectionKHR = 6029,
SpvOpRayQueryGetWorldRayOriginKHR = 6030,
SpvOpRayQueryGetIntersectionObjectToWorldKHR = 6031,
SpvOpRayQueryGetIntersectionWorldToObjectKHR = 6032,
SpvOpMax = 0x7fffffff,
} SpvOp;
@@ -1810,6 +1918,30 @@ inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultTy
case SpvOpTerminateRayNV: *hasResult = false; *hasResultType = false; break;
case SpvOpTraceNV: *hasResult = false; *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 SpvOpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break;
case SpvOpCooperativeMatrixLoadNV: *hasResult = true; *hasResultType = true; break;
+135 -2
View File
@@ -1,4 +1,4 @@
// Copyright (c) 2014-2019 The Khronos Group Inc.
// Copyright (c) 2014-2020 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and/or associated documentation files (the "Materials"),
@@ -53,7 +53,7 @@ typedef unsigned int Id;
#define SPV_REVISION 1
static const unsigned int MagicNumber = 0x07230203;
static const unsigned int Version = 0x00010400;
static const unsigned int Version = 0x00010500;
static const unsigned int Revision = 1;
static const unsigned int OpCodeMask = 0xffff;
static const unsigned int WordCountShift = 16;
@@ -78,11 +78,17 @@ enum ExecutionModel {
ExecutionModelKernel = 6,
ExecutionModelTaskNV = 5267,
ExecutionModelMeshNV = 5268,
ExecutionModelRayGenerationKHR = 5313,
ExecutionModelRayGenerationNV = 5313,
ExecutionModelIntersectionKHR = 5314,
ExecutionModelIntersectionNV = 5314,
ExecutionModelAnyHitKHR = 5315,
ExecutionModelAnyHitNV = 5315,
ExecutionModelClosestHitKHR = 5316,
ExecutionModelClosestHitNV = 5316,
ExecutionModelMissKHR = 5317,
ExecutionModelMissNV = 5317,
ExecutionModelCallableKHR = 5318,
ExecutionModelCallableNV = 5318,
ExecutionModelMax = 0x7fffffff,
};
@@ -179,11 +185,17 @@ enum StorageClass {
StorageClassAtomicCounter = 10,
StorageClassImage = 11,
StorageClassStorageBuffer = 12,
StorageClassCallableDataKHR = 5328,
StorageClassCallableDataNV = 5328,
StorageClassIncomingCallableDataKHR = 5329,
StorageClassIncomingCallableDataNV = 5329,
StorageClassRayPayloadKHR = 5338,
StorageClassRayPayloadNV = 5338,
StorageClassHitAttributeKHR = 5339,
StorageClassHitAttributeNV = 5339,
StorageClassIncomingRayPayloadKHR = 5342,
StorageClassIncomingRayPayloadNV = 5342,
StorageClassShaderRecordBufferKHR = 5343,
StorageClassShaderRecordBufferNV = 5343,
StorageClassPhysicalStorageBuffer = 5349,
StorageClassPhysicalStorageBufferEXT = 5349,
@@ -558,20 +570,35 @@ enum BuiltIn {
BuiltInFragmentSizeNV = 5292,
BuiltInFragInvocationCountEXT = 5293,
BuiltInInvocationsPerPixelNV = 5293,
BuiltInLaunchIdKHR = 5319,
BuiltInLaunchIdNV = 5319,
BuiltInLaunchSizeKHR = 5320,
BuiltInLaunchSizeNV = 5320,
BuiltInWorldRayOriginKHR = 5321,
BuiltInWorldRayOriginNV = 5321,
BuiltInWorldRayDirectionKHR = 5322,
BuiltInWorldRayDirectionNV = 5322,
BuiltInObjectRayOriginKHR = 5323,
BuiltInObjectRayOriginNV = 5323,
BuiltInObjectRayDirectionKHR = 5324,
BuiltInObjectRayDirectionNV = 5324,
BuiltInRayTminKHR = 5325,
BuiltInRayTminNV = 5325,
BuiltInRayTmaxKHR = 5326,
BuiltInRayTmaxNV = 5326,
BuiltInInstanceCustomIndexKHR = 5327,
BuiltInInstanceCustomIndexNV = 5327,
BuiltInObjectToWorldKHR = 5330,
BuiltInObjectToWorldNV = 5330,
BuiltInWorldToObjectKHR = 5331,
BuiltInWorldToObjectNV = 5331,
BuiltInHitTKHR = 5332,
BuiltInHitTNV = 5332,
BuiltInHitKindKHR = 5333,
BuiltInHitKindNV = 5333,
BuiltInIncomingRayFlagsKHR = 5351,
BuiltInIncomingRayFlagsNV = 5351,
BuiltInRayGeometryIndexKHR = 5352,
BuiltInWarpsPerSMNV = 5374,
BuiltInSMCountNV = 5375,
BuiltInWarpIDNV = 5376,
@@ -709,6 +736,7 @@ enum Scope {
ScopeInvocation = 4,
ScopeQueueFamily = 5,
ScopeQueueFamilyKHR = 5,
ScopeShaderCallKHR = 6,
ScopeMax = 0x7fffffff,
};
@@ -833,6 +861,8 @@ enum Capability {
CapabilitySignedZeroInfNanPreserve = 4466,
CapabilityRoundingModeRTE = 4467,
CapabilityRoundingModeRTZ = 4468,
CapabilityRayQueryProvisionalKHR = 4471,
CapabilityRayTraversalPrimitiveCullingProvisionalKHR = 4478,
CapabilityFloat16ImageAMD = 5008,
CapabilityImageGatherBiasLodAMD = 5009,
CapabilityFragmentMaskAMD = 5010,
@@ -886,6 +916,7 @@ enum Capability {
CapabilityPhysicalStorageBufferAddresses = 5347,
CapabilityPhysicalStorageBufferAddressesEXT = 5347,
CapabilityComputeDerivativeGroupLinearNV = 5350,
CapabilityRayTracingProvisionalKHR = 5353,
CapabilityCooperativeMatrixNV = 5357,
CapabilityFragmentShaderSampleInterlockEXT = 5363,
CapabilityFragmentShaderShadingRateInterlockEXT = 5372,
@@ -903,6 +934,53 @@ enum Capability {
CapabilityMax = 0x7fffffff,
};
enum RayFlagsShift {
RayFlagsOpaqueKHRShift = 0,
RayFlagsNoOpaqueKHRShift = 1,
RayFlagsTerminateOnFirstHitKHRShift = 2,
RayFlagsSkipClosestHitShaderKHRShift = 3,
RayFlagsCullBackFacingTrianglesKHRShift = 4,
RayFlagsCullFrontFacingTrianglesKHRShift = 5,
RayFlagsCullOpaqueKHRShift = 6,
RayFlagsCullNoOpaqueKHRShift = 7,
RayFlagsSkipTrianglesKHRShift = 8,
RayFlagsSkipAABBsKHRShift = 9,
RayFlagsMax = 0x7fffffff,
};
enum RayFlagsMask {
RayFlagsMaskNone = 0,
RayFlagsOpaqueKHRMask = 0x00000001,
RayFlagsNoOpaqueKHRMask = 0x00000002,
RayFlagsTerminateOnFirstHitKHRMask = 0x00000004,
RayFlagsSkipClosestHitShaderKHRMask = 0x00000008,
RayFlagsCullBackFacingTrianglesKHRMask = 0x00000010,
RayFlagsCullFrontFacingTrianglesKHRMask = 0x00000020,
RayFlagsCullOpaqueKHRMask = 0x00000040,
RayFlagsCullNoOpaqueKHRMask = 0x00000080,
RayFlagsSkipTrianglesKHRMask = 0x00000100,
RayFlagsSkipAABBsKHRMask = 0x00000200,
};
enum RayQueryIntersection {
RayQueryIntersectionRayQueryCandidateIntersectionKHR = 0,
RayQueryIntersectionRayQueryCommittedIntersectionKHR = 1,
RayQueryIntersectionMax = 0x7fffffff,
};
enum RayQueryCommittedIntersectionType {
RayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionNoneKHR = 0,
RayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionTriangleKHR = 1,
RayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionGeneratedKHR = 2,
RayQueryCommittedIntersectionTypeMax = 0x7fffffff,
};
enum RayQueryCandidateIntersectionType {
RayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionTriangleKHR = 0,
RayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionAABBKHR = 1,
RayQueryCandidateIntersectionTypeMax = 0x7fffffff,
};
enum Op {
OpNop = 0,
OpUndef = 1,
@@ -1254,6 +1332,13 @@ enum Op {
OpSubgroupAnyKHR = 4429,
OpSubgroupAllEqualKHR = 4430,
OpSubgroupReadInvocationKHR = 4432,
OpTypeRayQueryProvisionalKHR = 4472,
OpRayQueryInitializeKHR = 4473,
OpRayQueryTerminateKHR = 4474,
OpRayQueryGenerateIntersectionKHR = 4475,
OpRayQueryConfirmIntersectionKHR = 4476,
OpRayQueryProceedKHR = 4477,
OpRayQueryGetIntersectionTypeKHR = 4479,
OpGroupIAddNonUniformAMD = 5000,
OpGroupFAddNonUniformAMD = 5001,
OpGroupFMinNonUniformAMD = 5002,
@@ -1268,11 +1353,17 @@ enum Op {
OpImageSampleFootprintNV = 5283,
OpGroupNonUniformPartitionNV = 5296,
OpWritePackedPrimitiveIndices4x8NV = 5299,
OpReportIntersectionKHR = 5334,
OpReportIntersectionNV = 5334,
OpIgnoreIntersectionKHR = 5335,
OpIgnoreIntersectionNV = 5335,
OpTerminateRayKHR = 5336,
OpTerminateRayNV = 5336,
OpTraceNV = 5337,
OpTraceRayKHR = 5337,
OpTypeAccelerationStructureKHR = 5341,
OpTypeAccelerationStructureNV = 5341,
OpExecuteCallableKHR = 5344,
OpExecuteCallableNV = 5344,
OpTypeCooperativeMatrixNV = 5358,
OpCooperativeMatrixLoadNV = 5359,
@@ -1429,6 +1520,23 @@ enum Op {
OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814,
OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815,
OpSubgroupAvcSicGetInterRawSadsINTEL = 5816,
OpRayQueryGetRayTMinKHR = 6016,
OpRayQueryGetRayFlagsKHR = 6017,
OpRayQueryGetIntersectionTKHR = 6018,
OpRayQueryGetIntersectionInstanceCustomIndexKHR = 6019,
OpRayQueryGetIntersectionInstanceIdKHR = 6020,
OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR = 6021,
OpRayQueryGetIntersectionGeometryIndexKHR = 6022,
OpRayQueryGetIntersectionPrimitiveIndexKHR = 6023,
OpRayQueryGetIntersectionBarycentricsKHR = 6024,
OpRayQueryGetIntersectionFrontFaceKHR = 6025,
OpRayQueryGetIntersectionCandidateAABBOpaqueKHR = 6026,
OpRayQueryGetIntersectionObjectRayDirectionKHR = 6027,
OpRayQueryGetIntersectionObjectRayOriginKHR = 6028,
OpRayQueryGetWorldRayDirectionKHR = 6029,
OpRayQueryGetWorldRayOriginKHR = 6030,
OpRayQueryGetIntersectionObjectToWorldKHR = 6031,
OpRayQueryGetIntersectionWorldToObjectKHR = 6032,
OpMax = 0x7fffffff,
};
@@ -1806,6 +1914,30 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) {
case OpTerminateRayNV: *hasResult = false; *hasResultType = false; break;
case OpTraceNV: *hasResult = false; *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 OpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break;
case OpCooperativeMatrixLoadNV: *hasResult = true; *hasResultType = true; break;
@@ -1974,6 +2106,7 @@ inline FunctionControlMask operator|(FunctionControlMask a, FunctionControlMask
inline MemorySemanticsMask operator|(MemorySemanticsMask a, MemorySemanticsMask b) { return MemorySemanticsMask(unsigned(a) | unsigned(b)); }
inline MemoryAccessMask operator|(MemoryAccessMask a, MemoryAccessMask b) { return MemoryAccessMask(unsigned(a) | unsigned(b)); }
inline KernelProfilingInfoMask operator|(KernelProfilingInfoMask a, KernelProfilingInfoMask b) { return KernelProfilingInfoMask(unsigned(a) | unsigned(b)); }
inline RayFlagsMask operator|(RayFlagsMask a, RayFlagsMask b) { return RayFlagsMask(unsigned(a) | unsigned(b)); }
} // end namespace spv
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2019 Arm Limited
* Copyright 2016-2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2019 Arm Limited
* Copyright 2016-2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
+76 -6
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 Arm Limited
* Copyright 2015-2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -209,9 +209,12 @@ inline std::string convert_to_string(const T &t)
#define SPIRV_CROSS_FLT_FMT "%.32g"
#endif
#ifdef _MSC_VER
// sprintf warning.
// We cannot rely on snprintf existing because, ..., MSVC.
// Disable sprintf and strcat warnings.
// We cannot rely on snprintf and family existing because, ..., MSVC.
#if defined(__clang__) || defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#elif defined(_MSC_VER)
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
@@ -259,7 +262,9 @@ inline std::string convert_to_string(double t, char locale_radix_point)
return buf;
}
#ifdef _MSC_VER
#if defined(__clang__) || defined(__GNUC__)
#pragma GCC diagnostic pop
#elif defined(_MSC_VER)
#pragma warning(pop)
#endif
@@ -525,7 +530,8 @@ struct SPIRType : IVariant
Image,
SampledImage,
Sampler,
AccelerationStructureNV,
AccelerationStructure,
RayQuery,
// Keep internal types at the end.
ControlPointArray,
@@ -638,6 +644,7 @@ struct SPIREntryPoint
uint32_t invocations = 0;
uint32_t output_vertices = 0;
spv::ExecutionModel model = spv::ExecutionModelMax;
bool geometry_passthrough = false;
};
struct SPIRExpression : IVariant
@@ -938,6 +945,11 @@ struct SPIRFunction : IVariant
// Intentionally not a small vector, this one is rare, and std::function can be large.
Vector<std::function<void()>> fixup_hooks_in;
// On function entry, make sure to copy a constant array into thread addr space to work around
// the case where we are passing a constant array by value to a function on backends which do not
// consider arrays value types.
SmallVector<ID> constant_arrays_needed_on_stack;
bool active = false;
bool flush_undeclared = true;
bool do_combined_parameters = true;
@@ -1570,6 +1582,8 @@ struct Meta
uint32_t set = 0;
uint32_t binding = 0;
uint32_t offset = 0;
uint32_t xfb_buffer = 0;
uint32_t xfb_stride = 0;
uint32_t array_stride = 0;
uint32_t matrix_stride = 0;
uint32_t input_attachment = 0;
@@ -1694,6 +1708,62 @@ static inline bool opcode_is_sign_invariant(spv::Op opcode)
return false;
}
}
struct SetBindingPair
{
uint32_t desc_set;
uint32_t binding;
inline bool operator==(const SetBindingPair &other) const
{
return desc_set == other.desc_set && binding == other.binding;
}
inline bool operator<(const SetBindingPair &other) const
{
return desc_set < other.desc_set || (desc_set == other.desc_set && binding < other.binding);
}
};
struct StageSetBinding
{
spv::ExecutionModel model;
uint32_t desc_set;
uint32_t binding;
inline bool operator==(const StageSetBinding &other) const
{
return model == other.model && desc_set == other.desc_set && binding == other.binding;
}
};
struct InternalHasher
{
inline size_t operator()(const SetBindingPair &value) const
{
// Quality of hash doesn't really matter here.
auto hash_set = std::hash<uint32_t>()(value.desc_set);
auto hash_binding = std::hash<uint32_t>()(value.binding);
return (hash_set * 0x10001b31) ^ hash_binding;
}
inline size_t operator()(const StageSetBinding &value) const
{
// Quality of hash doesn't really matter here.
auto hash_model = std::hash<uint32_t>()(value.model);
auto hash_set = std::hash<uint32_t>()(value.desc_set);
auto tmp_hash = (hash_model * 0x10001b31) ^ hash_set;
return (tmp_hash * 0x10001b31) ^ value.binding;
}
};
// Special constant used in a {MSL,HLSL}ResourceBinding desc_set
// element to indicate the bindings for the push constants.
static const uint32_t ResourceBindingPushConstantDescriptorSet = ~(0u);
// Special constant used in a {MSL,HLSL}ResourceBinding binding
// element to indicate the bindings for the push constants.
static const uint32_t ResourceBindingPushConstantBinding = 0;
} // namespace SPIRV_CROSS_NAMESPACE
namespace std
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 Arm Limited
* Copyright 2015-2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 Arm Limited
* Copyright 2015-2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 Arm Limited
* Copyright 2015-2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -871,7 +871,7 @@ ShaderResources Compiler::get_shader_resources(const unordered_set<VariableID> *
res.atomic_counters.push_back({ var.self, var.basetype, type.self, get_name(var.self) });
}
// Acceleration structures
else if (type.storage == StorageClassUniformConstant && type.basetype == SPIRType::AccelerationStructureNV)
else if (type.storage == StorageClassUniformConstant && type.basetype == SPIRType::AccelerationStructure)
{
res.acceleration_structures.push_back({ var.self, var.basetype, type.self, get_name(var.self) });
}
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 Arm Limited
* Copyright 2015-2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
+150 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2019 Hans-Kristian Arntzen
* Copyright 2019-2020 Hans-Kristian Arntzen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -420,6 +420,12 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
case SPVC_COMPILER_OPTION_EMIT_LINE_DIRECTIVES:
options->glsl.emit_line_directives = value != 0;
break;
case SPVC_COMPILER_OPTION_ENABLE_STORAGE_IMAGE_QUALIFIER_DEDUCTION:
options->glsl.enable_storage_image_qualifier_deduction = value != 0;
break;
case SPVC_COMPILER_OPTION_FORCE_ZERO_INITIALIZED_VARIABLES:
options->glsl.force_zero_initialized_variables = value != 0;
break;
case SPVC_COMPILER_OPTION_GLSL_SUPPORT_NONZERO_BASE_INSTANCE:
options->glsl.vertex.support_nonzero_base_instance = value != 0;
@@ -471,6 +477,14 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
case SPVC_COMPILER_OPTION_HLSL_SUPPORT_NONZERO_BASE_VERTEX_BASE_INSTANCE:
options->hlsl.support_nonzero_base_vertex_base_instance = value != 0;
break;
case SPVC_COMPILER_OPTION_HLSL_FORCE_STORAGE_BUFFER_AS_UAV:
options->hlsl.force_storage_buffer_as_uav = value != 0;
break;
case SPVC_COMPILER_OPTION_HLSL_NONWRITABLE_UAV_TEXTURE_AS_SRV:
options->hlsl.nonwritable_uav_texture_as_srv = value != 0;
break;
#endif
#if SPIRV_CROSS_C_API_MSL
@@ -593,6 +607,30 @@ spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_c
case SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING:
options->msl.enable_decoration_binding = value != 0;
break;
case SPVC_COMPILER_OPTION_MSL_FORCE_ACTIVE_ARGUMENT_BUFFER_RESOURCES:
options->msl.force_active_argument_buffer_resources = value != 0;
break;
case SPVC_COMPILER_OPTION_MSL_FORCE_NATIVE_ARRAYS:
options->msl.force_native_arrays = value != 0;
break;
case SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_OUTPUT_MASK:
options->msl.enable_frag_output_mask = value;
break;
case SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_DEPTH_BUILTIN:
options->msl.enable_frag_depth_builtin = value != 0;
break;
case SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_STENCIL_REF_BUILTIN:
options->msl.enable_frag_stencil_ref_builtin = value != 0;
break;
case SPVC_COMPILER_OPTION_MSL_ENABLE_CLIP_DISTANCE_USER_VARYING:
options->msl.enable_clip_distance_user_varying = value != 0;
break;
#endif
default:
@@ -689,6 +727,23 @@ spvc_result spvc_compiler_flatten_buffer_block(spvc_compiler compiler, spvc_vari
#endif
}
spvc_bool spvc_compiler_variable_is_depth_or_compare(spvc_compiler compiler, spvc_variable_id id)
{
#if SPIRV_CROSS_C_API_GLSL
if (compiler->backend == SPVC_BACKEND_NONE)
{
compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection.");
return SPVC_ERROR_INVALID_ARGUMENT;
}
return static_cast<CompilerGLSL *>(compiler->compiler.get())->variable_is_depth_or_compare(id) ? SPVC_TRUE : SPVC_FALSE;
#else
(void)id;
compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection.");
return SPVC_FALSE;
#endif
}
spvc_result spvc_compiler_hlsl_set_root_constants_layout(spvc_compiler compiler,
const spvc_hlsl_root_constants *constant_info,
size_t count)
@@ -789,6 +844,60 @@ spvc_result spvc_compiler_hlsl_set_resource_binding_flags(spvc_compiler compiler
#endif
}
spvc_result spvc_compiler_hlsl_add_resource_binding(spvc_compiler compiler,
const spvc_hlsl_resource_binding *binding)
{
#if SPIRV_CROSS_C_API_HLSL
if (compiler->backend != SPVC_BACKEND_HLSL)
{
compiler->context->report_error("HLSL function used on a non-HLSL backend.");
return SPVC_ERROR_INVALID_ARGUMENT;
}
auto &hlsl = *static_cast<CompilerHLSL *>(compiler->compiler.get());
HLSLResourceBinding bind;
bind.binding = binding->binding;
bind.desc_set = binding->desc_set;
bind.stage = static_cast<spv::ExecutionModel>(binding->stage);
bind.cbv.register_binding = binding->cbv.register_binding;
bind.cbv.register_space = binding->cbv.register_space;
bind.uav.register_binding = binding->uav.register_binding;
bind.uav.register_space = binding->uav.register_space;
bind.srv.register_binding = binding->srv.register_binding;
bind.srv.register_space = binding->srv.register_space;
bind.sampler.register_binding = binding->sampler.register_binding;
bind.sampler.register_space = binding->sampler.register_space;
hlsl.add_hlsl_resource_binding(bind);
return SPVC_SUCCESS;
#else
(void)binding;
compiler->context->report_error("HLSL function used on a non-HLSL backend.");
return SPVC_ERROR_INVALID_ARGUMENT;
#endif
}
spvc_bool spvc_compiler_hlsl_is_resource_used(spvc_compiler compiler, SpvExecutionModel model, unsigned set,
unsigned binding)
{
#if SPIRV_CROSS_C_API_HLSL
if (compiler->backend != SPVC_BACKEND_HLSL)
{
compiler->context->report_error("HLSL function used on a non-HLSL backend.");
return SPVC_FALSE;
}
auto &hlsl = *static_cast<CompilerHLSL *>(compiler->compiler.get());
return hlsl.is_hlsl_resource_binding_used(static_cast<spv::ExecutionModel>(model), set, binding) ? SPVC_TRUE :
SPVC_FALSE;
#else
(void)model;
(void)set;
(void)binding;
compiler->context->report_error("HLSL function used on a non-HLSL backend.");
return SPVC_FALSE;
#endif
}
spvc_bool spvc_compiler_msl_is_rasterization_disabled(spvc_compiler compiler)
{
#if SPIRV_CROSS_C_API_MSL
@@ -971,6 +1080,26 @@ spvc_result spvc_compiler_msl_add_dynamic_buffer(spvc_compiler compiler, unsigne
#endif
}
spvc_result spvc_compiler_msl_add_inline_uniform_block(spvc_compiler compiler, unsigned desc_set, unsigned binding)
{
#if SPIRV_CROSS_C_API_MSL
if (compiler->backend != SPVC_BACKEND_MSL)
{
compiler->context->report_error("MSL function used on a non-MSL backend.");
return SPVC_ERROR_INVALID_ARGUMENT;
}
auto &msl = *static_cast<CompilerMSL *>(compiler->compiler.get());
msl.add_inline_uniform_block(desc_set, binding);
return SPVC_SUCCESS;
#else
(void)binding;
(void)desc_set;
compiler->context->report_error("MSL function used on a non-MSL backend.");
return SPVC_ERROR_INVALID_ARGUMENT;
#endif
}
spvc_result spvc_compiler_msl_add_discrete_descriptor_set(spvc_compiler compiler, unsigned desc_set)
{
#if SPIRV_CROSS_C_API_MSL
@@ -2157,6 +2286,26 @@ void spvc_msl_resource_binding_init(spvc_msl_resource_binding *binding)
#endif
}
void spvc_hlsl_resource_binding_init(spvc_hlsl_resource_binding *binding)
{
#if SPIRV_CROSS_C_API_HLSL
HLSLResourceBinding binding_default;
binding->desc_set = binding_default.desc_set;
binding->binding = binding_default.binding;
binding->cbv.register_binding = binding_default.cbv.register_binding;
binding->cbv.register_space = binding_default.cbv.register_space;
binding->srv.register_binding = binding_default.srv.register_binding;
binding->srv.register_space = binding_default.srv.register_space;
binding->uav.register_binding = binding_default.uav.register_binding;
binding->uav.register_space = binding_default.uav.register_space;
binding->sampler.register_binding = binding_default.sampler.register_binding;
binding->sampler.register_space = binding_default.sampler.register_space;
binding->stage = static_cast<SpvExecutionModel>(binding_default.stage);
#else
memset(binding, 0, sizeof(*binding));
#endif
}
void spvc_msl_constexpr_sampler_init(spvc_msl_constexpr_sampler *sampler)
{
#if SPIRV_CROSS_C_API_MSL
+55 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2019 Hans-Kristian Arntzen
* Copyright 2019-2020 Hans-Kristian Arntzen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,7 +33,7 @@ extern "C" {
/* Bumped if ABI or API breaks backwards compatibility. */
#define SPVC_C_API_VERSION_MAJOR 0
/* Bumped if APIs or enumerations are added in a backwards compatible way. */
#define SPVC_C_API_VERSION_MINOR 21
#define SPVC_C_API_VERSION_MINOR 33
/* Bumped if internal implementation details change. */
#define SPVC_C_API_VERSION_PATCH 0
@@ -210,6 +210,7 @@ typedef enum spvc_resource_type
SPVC_RESOURCE_TYPE_SEPARATE_IMAGE = 10,
SPVC_RESOURCE_TYPE_SEPARATE_SAMPLERS = 11,
SPVC_RESOURCE_TYPE_ACCELERATION_STRUCTURE = 12,
SPVC_RESOURCE_TYPE_RAY_QUERY = 13,
SPVC_RESOURCE_TYPE_INT_MAX = 0x7fffffff
} spvc_resource_type;
@@ -469,6 +470,7 @@ SPVC_PUBLIC_API void spvc_msl_sampler_ycbcr_conversion_init(spvc_msl_sampler_ycb
/* Maps to C++ API. */
typedef enum spvc_hlsl_binding_flag_bits
{
SPVC_HLSL_BINDING_AUTO_NONE_BIT = 0,
SPVC_HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT = 1 << 0,
SPVC_HLSL_BINDING_AUTO_CBV_BIT = 1 << 1,
SPVC_HLSL_BINDING_AUTO_SRV_BIT = 1 << 2,
@@ -478,6 +480,31 @@ typedef enum spvc_hlsl_binding_flag_bits
} spvc_hlsl_binding_flag_bits;
typedef unsigned spvc_hlsl_binding_flags;
#define SPVC_HLSL_PUSH_CONSTANT_DESC_SET (~(0u))
#define SPVC_HLSL_PUSH_CONSTANT_BINDING (0)
/* Maps to C++ API. */
typedef struct spvc_hlsl_resource_binding_mapping
{
unsigned register_space;
unsigned register_binding;
} spvc_hlsl_resource_binding_mapping;
typedef struct spvc_hlsl_resource_binding
{
SpvExecutionModel stage;
unsigned desc_set;
unsigned binding;
spvc_hlsl_resource_binding_mapping cbv, uav, srv, sampler;
} spvc_hlsl_resource_binding;
/*
* Initializes the resource binding struct.
* The defaults are non-zero.
*/
SPVC_PUBLIC_API void spvc_hlsl_resource_binding_init(spvc_hlsl_resource_binding *binding);
/* Maps to the various spirv_cross::Compiler*::Option structures. See C++ API for defaults and details. */
typedef enum spvc_compiler_option
{
@@ -545,6 +572,21 @@ typedef enum spvc_compiler_option
SPVC_COMPILER_OPTION_MSL_INVARIANT_FP_MATH = 47 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_EMULATE_CUBEMAP_ARRAY = 48 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING = 49 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_FORCE_ACTIVE_ARGUMENT_BUFFER_RESOURCES = 50 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_FORCE_NATIVE_ARRAYS = 51 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_ENABLE_STORAGE_IMAGE_QUALIFIER_DEDUCTION = 52 | SPVC_COMPILER_OPTION_COMMON_BIT,
SPVC_COMPILER_OPTION_HLSL_FORCE_STORAGE_BUFFER_AS_UAV = 53 | SPVC_COMPILER_OPTION_HLSL_BIT,
SPVC_COMPILER_OPTION_FORCE_ZERO_INITIALIZED_VARIABLES = 54 | SPVC_COMPILER_OPTION_COMMON_BIT,
SPVC_COMPILER_OPTION_HLSL_NONWRITABLE_UAV_TEXTURE_AS_SRV = 55 | SPVC_COMPILER_OPTION_HLSL_BIT,
SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_OUTPUT_MASK = 56 | SPVC_COMPILER_OPTION_MSL_BIT,
SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_DEPTH_BUILTIN = 57 | 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_INT_MAX = 0x7fffffff
} spvc_compiler_option;
@@ -606,6 +648,8 @@ SPVC_PUBLIC_API spvc_result spvc_compiler_add_header_line(spvc_compiler compiler
SPVC_PUBLIC_API spvc_result spvc_compiler_require_extension(spvc_compiler compiler, const char *ext);
SPVC_PUBLIC_API spvc_result spvc_compiler_flatten_buffer_block(spvc_compiler compiler, spvc_variable_id id);
SPVC_PUBLIC_API spvc_bool spvc_compiler_variable_is_depth_or_compare(spvc_compiler compiler, spvc_variable_id id);
/*
* HLSL specifics.
* Maps to C++ API.
@@ -621,6 +665,13 @@ SPVC_PUBLIC_API spvc_variable_id spvc_compiler_hlsl_remap_num_workgroups_builtin
SPVC_PUBLIC_API spvc_result spvc_compiler_hlsl_set_resource_binding_flags(spvc_compiler compiler,
spvc_hlsl_binding_flags flags);
SPVC_PUBLIC_API spvc_result spvc_compiler_hlsl_add_resource_binding(spvc_compiler compiler,
const spvc_hlsl_resource_binding *binding);
SPVC_PUBLIC_API spvc_bool spvc_compiler_hlsl_is_resource_used(spvc_compiler compiler,
SpvExecutionModel model,
unsigned set,
unsigned binding);
/*
* MSL specifics.
* Maps to C++ API.
@@ -657,6 +708,8 @@ SPVC_PUBLIC_API unsigned spvc_compiler_msl_get_automatic_resource_binding_second
SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_dynamic_buffer(spvc_compiler compiler, unsigned desc_set, unsigned binding, unsigned index);
SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_inline_uniform_block(spvc_compiler compiler, unsigned desc_set, unsigned binding);
/*
* Reflect resources.
* Maps almost 1:1 to C++ API.
@@ -1,5 +1,5 @@
/*
* Copyright 2019 Hans-Kristian Arntzen
* Copyright 2019-2020 Hans-Kristian Arntzen
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,8 +21,10 @@
#include <algorithm>
#include <functional>
#include <iterator>
#include <limits>
#include <memory>
#include <stack>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -85,72 +87,72 @@ template <typename T>
class VectorView
{
public:
T &operator[](size_t i)
T &operator[](size_t i) SPIRV_CROSS_NOEXCEPT
{
return ptr[i];
}
const T &operator[](size_t i) const
const T &operator[](size_t i) const SPIRV_CROSS_NOEXCEPT
{
return ptr[i];
}
bool empty() const
bool empty() const SPIRV_CROSS_NOEXCEPT
{
return buffer_size == 0;
}
size_t size() const
size_t size() const SPIRV_CROSS_NOEXCEPT
{
return buffer_size;
}
T *data()
T *data() SPIRV_CROSS_NOEXCEPT
{
return ptr;
}
const T *data() const
const T *data() const SPIRV_CROSS_NOEXCEPT
{
return ptr;
}
T *begin()
T *begin() SPIRV_CROSS_NOEXCEPT
{
return ptr;
}
T *end()
T *end() SPIRV_CROSS_NOEXCEPT
{
return ptr + buffer_size;
}
const T *begin() const
const T *begin() const SPIRV_CROSS_NOEXCEPT
{
return ptr;
}
const T *end() const
const T *end() const SPIRV_CROSS_NOEXCEPT
{
return ptr + buffer_size;
}
T &front()
T &front() SPIRV_CROSS_NOEXCEPT
{
return ptr[0];
}
const T &front() const
const T &front() const SPIRV_CROSS_NOEXCEPT
{
return ptr[0];
}
T &back()
T &back() SPIRV_CROSS_NOEXCEPT
{
return ptr[buffer_size - 1];
}
const T &back() const
const T &back() const SPIRV_CROSS_NOEXCEPT
{
return ptr[buffer_size - 1];
}
@@ -194,14 +196,13 @@ template <typename T, size_t N = 8>
class SmallVector : public VectorView<T>
{
public:
SmallVector()
SmallVector() SPIRV_CROSS_NOEXCEPT
{
this->ptr = stack_storage.data();
buffer_capacity = N;
}
SmallVector(const T *arg_list_begin, const T *arg_list_end)
: SmallVector()
SmallVector(const T *arg_list_begin, const T *arg_list_end) SPIRV_CROSS_NOEXCEPT : SmallVector()
{
auto count = size_t(arg_list_end - arg_list_begin);
reserve(count);
@@ -245,14 +246,16 @@ public:
return *this;
}
SmallVector(const SmallVector &other)
: SmallVector()
SmallVector(const SmallVector &other) SPIRV_CROSS_NOEXCEPT : SmallVector()
{
*this = other;
}
SmallVector &operator=(const SmallVector &other)
SmallVector &operator=(const SmallVector &other) SPIRV_CROSS_NOEXCEPT
{
if (this == &other)
return *this;
clear();
reserve(other.buffer_size);
for (size_t i = 0; i < other.buffer_size; i++)
@@ -261,8 +264,7 @@ public:
return *this;
}
explicit SmallVector(size_t count)
: SmallVector()
explicit SmallVector(size_t count) SPIRV_CROSS_NOEXCEPT : SmallVector()
{
resize(count);
}
@@ -274,28 +276,28 @@ public:
free(this->ptr);
}
void clear()
void clear() SPIRV_CROSS_NOEXCEPT
{
for (size_t i = 0; i < this->buffer_size; i++)
this->ptr[i].~T();
this->buffer_size = 0;
}
void push_back(const T &t)
void push_back(const T &t) SPIRV_CROSS_NOEXCEPT
{
reserve(this->buffer_size + 1);
new (&this->ptr[this->buffer_size]) T(t);
this->buffer_size++;
}
void push_back(T &&t)
void push_back(T &&t) SPIRV_CROSS_NOEXCEPT
{
reserve(this->buffer_size + 1);
new (&this->ptr[this->buffer_size]) T(std::move(t));
this->buffer_size++;
}
void pop_back()
void pop_back() SPIRV_CROSS_NOEXCEPT
{
// Work around false positive warning on GCC 8.3.
// Calling pop_back on empty vector is undefined.
@@ -304,15 +306,22 @@ public:
}
template <typename... Ts>
void emplace_back(Ts &&... ts)
void emplace_back(Ts &&... ts) SPIRV_CROSS_NOEXCEPT
{
reserve(this->buffer_size + 1);
new (&this->ptr[this->buffer_size]) T(std::forward<Ts>(ts)...);
this->buffer_size++;
}
void reserve(size_t count)
void reserve(size_t count) SPIRV_CROSS_NOEXCEPT
{
if ((count > std::numeric_limits<size_t>::max() / sizeof(T)) ||
(count > std::numeric_limits<size_t>::max() / 2))
{
// Only way this should ever happen is with garbage input, terminate.
std::terminate();
}
if (count > buffer_capacity)
{
size_t target_capacity = buffer_capacity;
@@ -321,14 +330,17 @@ public:
if (target_capacity < N)
target_capacity = N;
// Need to ensure there is a POT value of target capacity which is larger than count,
// otherwise this will overflow.
while (target_capacity < count)
target_capacity <<= 1u;
T *new_buffer =
target_capacity > N ? static_cast<T *>(malloc(target_capacity * sizeof(T))) : stack_storage.data();
// If we actually fail this malloc, we are hosed anyways, there is no reason to attempt recovery.
if (!new_buffer)
SPIRV_CROSS_THROW("Out of memory.");
std::terminate();
// In case for some reason two allocations both come from same stack.
if (new_buffer != this->ptr)
@@ -348,7 +360,7 @@ public:
}
}
void insert(T *itr, const T *insert_begin, const T *insert_end)
void insert(T *itr, const T *insert_begin, const T *insert_end) SPIRV_CROSS_NOEXCEPT
{
auto count = size_t(insert_end - insert_begin);
if (itr == this->end())
@@ -374,8 +386,10 @@ public:
// Need to allocate new buffer. Move everything to a new buffer.
T *new_buffer =
target_capacity > N ? static_cast<T *>(malloc(target_capacity * sizeof(T))) : stack_storage.data();
// If we actually fail this malloc, we are hosed anyways, there is no reason to attempt recovery.
if (!new_buffer)
SPIRV_CROSS_THROW("Out of memory.");
std::terminate();
// First, move elements from source buffer to new buffer.
// We don't deal with types which can throw in move constructor.
@@ -447,19 +461,19 @@ public:
}
}
void insert(T *itr, const T &value)
void insert(T *itr, const T &value) SPIRV_CROSS_NOEXCEPT
{
insert(itr, &value, &value + 1);
}
T *erase(T *itr)
T *erase(T *itr) SPIRV_CROSS_NOEXCEPT
{
std::move(itr + 1, this->end(), itr);
this->ptr[--this->buffer_size].~T();
return itr;
}
void erase(T *start_erase, T *end_erase)
void erase(T *start_erase, T *end_erase) SPIRV_CROSS_NOEXCEPT
{
if (end_erase == this->end())
{
@@ -473,7 +487,7 @@ public:
}
}
void resize(size_t new_size)
void resize(size_t new_size) SPIRV_CROSS_NOEXCEPT
{
if (new_size < this->buffer_size)
{
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 Arm Limited
* Copyright 2015-2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2019 Arm Limited
* Copyright 2018-2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -266,6 +266,14 @@ void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument)
dec.offset = argument;
break;
case DecorationXfbBuffer:
dec.xfb_buffer = argument;
break;
case DecorationXfbStride:
dec.xfb_stride = argument;
break;
case DecorationArrayStride:
dec.array_stride = argument;
break;
@@ -337,6 +345,14 @@ void ParsedIR::set_member_decoration(TypeID id, uint32_t index, Decoration decor
dec.offset = argument;
break;
case DecorationXfbBuffer:
dec.xfb_buffer = argument;
break;
case DecorationXfbStride:
dec.xfb_stride = argument;
break;
case DecorationSpecId:
dec.spec_id = argument;
break;
@@ -450,6 +466,10 @@ uint32_t ParsedIR::get_decoration(ID id, Decoration decoration) const
return dec.component;
case DecorationOffset:
return dec.offset;
case DecorationXfbBuffer:
return dec.xfb_buffer;
case DecorationXfbStride:
return dec.xfb_stride;
case DecorationBinding:
return dec.binding;
case DecorationDescriptorSet:
@@ -514,6 +534,14 @@ void ParsedIR::unset_decoration(ID id, Decoration decoration)
dec.offset = 0;
break;
case DecorationXfbBuffer:
dec.xfb_buffer = 0;
break;
case DecorationXfbStride:
dec.xfb_stride = 0;
break;
case DecorationBinding:
dec.binding = 0;
break;
@@ -584,6 +612,10 @@ uint32_t ParsedIR::get_member_decoration(TypeID id, uint32_t index, Decoration d
return dec.binding;
case DecorationOffset:
return dec.offset;
case DecorationXfbBuffer:
return dec.xfb_buffer;
case DecorationXfbStride:
return dec.xfb_stride;
case DecorationSpecId:
return dec.spec_id;
case DecorationIndex:
@@ -672,6 +704,14 @@ void ParsedIR::unset_member_decoration(TypeID id, uint32_t index, Decoration dec
dec.offset = 0;
break;
case DecorationXfbBuffer:
dec.xfb_buffer = 0;
break;
case DecorationXfbStride:
dec.xfb_stride = 0;
break;
case DecorationSpecId:
dec.spec_id = 0;
break;
@@ -814,4 +854,57 @@ ParsedIR::LoopLock &ParsedIR::LoopLock::operator=(LoopLock &&other) SPIRV_CROSS_
return *this;
}
void ParsedIR::make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set)
{
auto &constant_type = get<SPIRType>(type);
if (constant_type.pointer)
{
if (add_to_typed_id_set)
add_typed_id(TypeConstant, id);
auto &constant = variant_set<SPIRConstant>(ids[id], type);
constant.self = id;
constant.make_null(constant_type);
}
else if (!constant_type.array.empty())
{
assert(constant_type.parent_type);
uint32_t parent_id = increase_bound_by(1);
make_constant_null(parent_id, constant_type.parent_type, add_to_typed_id_set);
if (!constant_type.array_size_literal.back())
SPIRV_CROSS_THROW("Array size of OpConstantNull must be a literal.");
SmallVector<uint32_t> elements(constant_type.array.back());
for (uint32_t i = 0; i < constant_type.array.back(); i++)
elements[i] = parent_id;
if (add_to_typed_id_set)
add_typed_id(TypeConstant, id);
variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id;
}
else if (!constant_type.member_types.empty())
{
uint32_t member_ids = increase_bound_by(uint32_t(constant_type.member_types.size()));
SmallVector<uint32_t> elements(constant_type.member_types.size());
for (uint32_t i = 0; i < constant_type.member_types.size(); i++)
{
make_constant_null(member_ids + i, constant_type.member_types[i], add_to_typed_id_set);
elements[i] = member_ids + i;
}
if (add_to_typed_id_set)
add_typed_id(TypeConstant, id);
variant_set<SPIRConstant>(ids[id], type, elements.data(), uint32_t(elements.size()), false).self = id;
}
else
{
if (add_to_typed_id_set)
add_typed_id(TypeConstant, id);
auto &constant = variant_set<SPIRConstant>(ids[id], type);
constant.self = id;
constant.make_null(constant_type);
}
}
} // namespace SPIRV_CROSS_NAMESPACE
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2019 Arm Limited
* Copyright 2018-2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -206,6 +206,8 @@ public:
return empty_string;
}
void make_constant_null(uint32_t id, uint32_t type, bool add_to_typed_id_set);
private:
template <typename T>
T &get(uint32_t id)
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 Arm Limited
* Copyright 2015-2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 Arm Limited
* Copyright 2015-2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
File diff suppressed because it is too large Load Diff
+41 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 Arm Limited
* Copyright 2015-2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -108,6 +108,18 @@ public:
// May not correspond exactly to original source, but should be a good approximation.
bool emit_line_directives = false;
// In cases where readonly/writeonly decoration are not used at all,
// we try to deduce which qualifier(s) we should actually used, since actually emitting
// read-write decoration is very rare, and older glslang/HLSL compilers tend to just emit readwrite as a matter of fact.
// The default (true) is to enable automatic deduction for these cases, but if you trust the decorations set
// by the SPIR-V, it's recommended to set this to false.
bool enable_storage_image_qualifier_deduction = true;
// On some targets (WebGPU), uninitialized variables are banned.
// If this is enabled, all variables (temporaries, Private, Function)
// which would otherwise be uninitialized will now be initialized to 0 instead.
bool force_zero_initialized_variables = false;
enum Precision
{
DontCare,
@@ -149,6 +161,10 @@ public:
remap_pls_variables();
}
// Redirect a subpassInput reading from input_attachment_index to instead load its value from
// the color attachment at location = color_location. Requires ESSL.
void remap_ext_framebuffer_fetch(uint32_t input_attachment_index, uint32_t color_location);
explicit CompilerGLSL(std::vector<uint32_t> spirv_)
: Compiler(std::move(spirv_))
{
@@ -212,6 +228,14 @@ public:
// The name of the uniform array will be the same as the interface block name.
void flatten_buffer_block(VariableID id);
// After compilation, query if a variable ID was used as a depth resource.
// This is meaningful for MSL since descriptor types depend on this knowledge.
// Cases which return true:
// - Images which are declared with depth = 1 image type.
// - Samplers which are statically used at least once with Dref opcodes.
// - Images which are statically used at least once with Dref opcodes.
bool variable_is_depth_or_compare(VariableID id) const;
protected:
void reset();
void emit_function(SPIRFunction &func, const Bitset &return_flags);
@@ -431,6 +455,7 @@ protected:
void emit_buffer_block_legacy(const SPIRVariable &var);
void emit_buffer_block_flattened(const SPIRVariable &type);
void emit_declared_builtin_block(spv::StorageClass storage, spv::ExecutionModel model);
bool should_force_emit_builtin_block(spv::StorageClass storage);
void emit_push_constant_block_vulkan(const SPIRVariable &var);
void emit_push_constant_block_glsl(const SPIRVariable &var);
void emit_interface_block(const SPIRVariable &type);
@@ -467,6 +492,8 @@ protected:
SPIRType::BaseType input_type, SPIRType::BaseType expected_result_type);
void emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op,
SPIRType::BaseType input_type, bool skip_cast_if_equal_type);
void emit_binary_func_op_cast_clustered(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
const char *op, SPIRType::BaseType input_type);
void emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2,
const char *op, SPIRType::BaseType input_type);
void emit_trinary_func_op_bitextract(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
@@ -487,6 +514,8 @@ protected:
SPIRType binary_op_bitcast_helper(std::string &cast_op0, std::string &cast_op1, SPIRType::BaseType &input_type,
uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type);
virtual bool emit_complex_bitcast(uint32_t result_type, uint32_t id, uint32_t op0);
std::string to_ternary_expression(const SPIRType &result_type, uint32_t select, uint32_t true_value,
uint32_t false_value);
@@ -562,6 +591,8 @@ protected:
spv::StorageClass rhs_storage);
virtual void emit_block_hints(const SPIRBlock &block);
virtual std::string to_initializer_expression(const SPIRVariable &var);
virtual std::string to_zero_initialized_expression(uint32_t type_id);
bool type_can_zero_initialize(const SPIRType &type) const;
bool buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing,
uint32_t *failed_index = nullptr, uint32_t start_offset = 0,
@@ -588,6 +619,7 @@ protected:
bool check_atomic_image(uint32_t id);
virtual void replace_illegal_names();
void replace_illegal_names(const std::unordered_set<std::string> &keywords);
virtual void emit_entry_point_declarations();
void replace_fragment_output(SPIRVariable &var);
@@ -652,6 +684,14 @@ protected:
void emit_pls();
void remap_pls_variables();
// GL_EXT_shader_framebuffer_fetch support.
std::vector<std::pair<uint32_t, uint32_t>> subpass_to_framebuffer_fetch_attachment;
std::unordered_set<uint32_t> inout_color_attachments;
bool subpass_input_is_framebuffer_fetch(uint32_t id) const;
void emit_inout_fragment_outputs_copy_to_subpass_inputs();
const SPIRVariable *find_subpass_input_by_attachment_index(uint32_t index) const;
const SPIRVariable *find_color_output_by_location(uint32_t location) const;
// A variant which takes two sets of name. The secondary is only used to verify there are no collisions,
// but the set is not updated when we have found a new name.
// Used primarily when adding block interface names.
+232 -34
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2019 Robert Konrad
* Copyright 2016-2020 Robert Konrad
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -210,6 +210,8 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t id)
bool typed_load = false;
uint32_t components = 4;
bool force_image_srv = hlsl_options.nonwritable_uav_texture_as_srv && has_decoration(id, DecorationNonWritable);
switch (type.image.dim)
{
case Dim1D:
@@ -239,7 +241,14 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t id)
if (interlocked_resources.count(id))
return join("RasterizerOrderedBuffer<", image_format_to_type(type.image.format, imagetype.basetype),
">");
return join("RWBuffer<", image_format_to_type(type.image.format, imagetype.basetype), ">");
typed_load = !force_image_srv && type.image.sampled == 2;
const char *rw = force_image_srv ? "" : "RW";
return join(rw, "Buffer<",
typed_load ? image_format_to_type(type.image.format, imagetype.basetype) :
join(type_to_glsl(imagetype), components),
">");
}
else
SPIRV_CROSS_THROW("Sampler buffers must be either sampled or unsampled. Cannot deduce in runtime.");
@@ -252,9 +261,14 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type, uint32_t id)
}
const char *arrayed = type.image.arrayed ? "Array" : "";
const char *ms = type.image.ms ? "MS" : "";
const char *rw = typed_load ? "RW" : "";
const char *rw = typed_load && !force_image_srv ? "RW" : "";
if (force_image_srv)
typed_load = false;
if (typed_load && interlocked_resources.count(id))
rw = "RasterizerOrdered";
return join(rw, "Texture", dim, ms, arrayed, "<",
typed_load ? image_format_to_type(type.image.format, imagetype.basetype) :
join(type_to_glsl(imagetype), components),
@@ -387,8 +401,12 @@ string CompilerHLSL::type_to_glsl(const SPIRType &type, uint32_t id)
case SPIRType::Double:
return "double";
case SPIRType::Int64:
if (hlsl_options.shader_model < 60)
SPIRV_CROSS_THROW("64-bit integers only supported in SM 6.0.");
return "int64_t";
case SPIRType::UInt64:
if (hlsl_options.shader_model < 60)
SPIRV_CROSS_THROW("64-bit integers only supported in SM 6.0.");
return "uint64_t";
default:
return "???";
@@ -1113,16 +1131,25 @@ void CompilerHLSL::replace_illegal_names()
"line", "linear", "matrix", "point", "row_major", "sampler",
};
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
if (!is_hidden_variable(var))
{
auto &m = ir.meta[var.self].decoration;
if (keywords.find(m.alias) != end(keywords))
m.alias = join("_", m.alias);
}
CompilerGLSL::replace_illegal_names(keywords);
CompilerGLSL::replace_illegal_names();
}
void CompilerHLSL::declare_undefined_values()
{
bool emitted = false;
ir.for_each_typed_id<SPIRUndef>([&](uint32_t, const SPIRUndef &undef) {
string initializer;
if (options.force_zero_initialized_variables && type_can_zero_initialize(this->get<SPIRType>(undef.basetype)))
initializer = join(" = ", to_zero_initialized_expression(undef.basetype));
statement("static ", variable_decl(this->get<SPIRType>(undef.basetype), to_name(undef.self), undef.self),
initializer, ";");
emitted = true;
});
CompilerGLSL::replace_illegal_names();
if (emitted)
statement("");
}
void CompilerHLSL::emit_resources()
@@ -1358,7 +1385,15 @@ void CompilerHLSL::emit_resources()
storage = "static";
break;
}
statement(storage, " ", variable_decl(var), ";");
string initializer;
if (options.force_zero_initialized_variables && var.storage == StorageClassPrivate &&
!var.initializer && !var.static_expression && type_can_zero_initialize(get_variable_data_type(var)))
{
initializer = join(" = ", to_zero_initialized_expression(get_variable_data_type_id(var)));
}
statement(storage, " ", variable_decl(var), initializer, ";");
emitted = true;
}
}
@@ -1468,6 +1503,24 @@ void CompilerHLSL::emit_resources()
statement("");
}
if (requires_uint2_packing)
{
statement("uint64_t SPIRV_Cross_packUint2x32(uint2 value)");
begin_scope();
statement("return (uint64_t(value.y) << 32) | uint64_t(value.x);");
end_scope();
statement("");
statement("uint2 SPIRV_Cross_unpackUint2x32(uint64_t value)");
begin_scope();
statement("uint2 Unpacked;");
statement("Unpacked.x = uint(value & 0xffffffff);");
statement("Unpacked.y = uint(value >> 32);");
statement("return Unpacked;");
end_scope();
statement("");
}
if (requires_explicit_fp16_packing)
{
// HLSL does not pack into a single word sadly :(
@@ -1853,8 +1906,8 @@ void CompilerHLSL::emit_buffer_block(const SPIRVariable &var)
if (is_uav)
{
Bitset flags = ir.get_buffer_block_flags(var);
bool is_readonly = flags.get(DecorationNonWritable);
bool is_coherent = flags.get(DecorationCoherent);
bool is_readonly = flags.get(DecorationNonWritable) && !hlsl_options.force_storage_buffer_as_uav;
bool is_coherent = flags.get(DecorationCoherent) && !is_readonly;
bool is_interlocked = interlocked_resources.count(var.self) > 0;
const char *type_name = "ByteAddressBuffer ";
if (!is_readonly)
@@ -2934,16 +2987,15 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
{
// TODO: Basic implementation, might need special consideration for RW/RO structured buffers,
// RW/RO images, and so on.
const auto &type = get<SPIRType>(var.basetype);
if (!has_decoration(var.self, DecorationBinding))
// We can remap push constant blocks, even if they don't have any binding decoration.
if (type.storage != StorageClassPushConstant && !has_decoration(var.self, DecorationBinding))
return "";
const auto &type = get<SPIRType>(var.basetype);
char space = '\0';
HLSLBindingFlags resource_flags = 0;
HLSLBindingFlagBits resource_flags = HLSL_BINDING_AUTO_NONE_BIT;
switch (type.basetype)
{
@@ -2955,8 +3007,16 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
case SPIRType::Image:
if (type.image.sampled == 2 && type.image.dim != DimSubpassData)
{
space = 'u'; // UAV
resource_flags = HLSL_BINDING_AUTO_UAV_BIT;
if (has_decoration(var.self, DecorationNonWritable) && hlsl_options.nonwritable_uav_texture_as_srv)
{
space = 't'; // SRV
resource_flags = HLSL_BINDING_AUTO_SRV_BIT;
}
else
{
space = 'u'; // UAV
resource_flags = HLSL_BINDING_AUTO_UAV_BIT;
}
}
else
{
@@ -2978,7 +3038,7 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
if (has_decoration(type.self, DecorationBufferBlock))
{
Bitset flags = ir.get_buffer_block_flags(var);
bool is_readonly = flags.get(DecorationNonWritable);
bool is_readonly = flags.get(DecorationNonWritable) && !hlsl_options.force_storage_buffer_as_uav;
space = is_readonly ? 't' : 'u'; // UAV
resource_flags = is_readonly ? HLSL_BINDING_AUTO_SRV_BIT : HLSL_BINDING_AUTO_UAV_BIT;
}
@@ -2997,7 +3057,7 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
{
// UAV or SRV depending on readonly flag.
Bitset flags = ir.get_buffer_block_flags(var);
bool is_readonly = flags.get(DecorationNonWritable);
bool is_readonly = flags.get(DecorationNonWritable) && !hlsl_options.force_storage_buffer_as_uav;
space = is_readonly ? 't' : 'u';
resource_flags = is_readonly ? HLSL_BINDING_AUTO_SRV_BIT : HLSL_BINDING_AUTO_UAV_BIT;
}
@@ -3011,8 +3071,16 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var)
if (!space)
return "";
return to_resource_register(resource_flags, space, get_decoration(var.self, DecorationBinding),
get_decoration(var.self, DecorationDescriptorSet));
uint32_t desc_set =
resource_flags == HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT ? ResourceBindingPushConstantDescriptorSet : 0u;
uint32_t binding = resource_flags == HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT ? ResourceBindingPushConstantBinding : 0u;
if (has_decoration(var.self, DecorationBinding))
binding = get_decoration(var.self, DecorationBinding);
if (has_decoration(var.self, DecorationDescriptorSet))
desc_set = get_decoration(var.self, DecorationDescriptorSet);
return to_resource_register(resource_flags, space, binding, desc_set);
}
string CompilerHLSL::to_resource_binding_sampler(const SPIRVariable &var)
@@ -3025,10 +3093,54 @@ string CompilerHLSL::to_resource_binding_sampler(const SPIRVariable &var)
get_decoration(var.self, DecorationDescriptorSet));
}
string CompilerHLSL::to_resource_register(uint32_t flags, char space, uint32_t binding, uint32_t space_set)
void CompilerHLSL::remap_hlsl_resource_binding(HLSLBindingFlagBits type, uint32_t &desc_set, uint32_t &binding)
{
if ((flags & resource_binding_flags) == 0)
auto itr = resource_bindings.find({ get_execution_model(), desc_set, binding });
if (itr != end(resource_bindings))
{
auto &remap = itr->second;
remap.second = true;
switch (type)
{
case HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT:
case HLSL_BINDING_AUTO_CBV_BIT:
desc_set = remap.first.cbv.register_space;
binding = remap.first.cbv.register_binding;
break;
case HLSL_BINDING_AUTO_SRV_BIT:
desc_set = remap.first.srv.register_space;
binding = remap.first.srv.register_binding;
break;
case HLSL_BINDING_AUTO_SAMPLER_BIT:
desc_set = remap.first.sampler.register_space;
binding = remap.first.sampler.register_binding;
break;
case HLSL_BINDING_AUTO_UAV_BIT:
desc_set = remap.first.uav.register_space;
binding = remap.first.uav.register_binding;
break;
default:
break;
}
}
}
string CompilerHLSL::to_resource_register(HLSLBindingFlagBits flag, char space, uint32_t binding, uint32_t space_set)
{
if ((flag & resource_binding_flags) == 0)
{
remap_hlsl_resource_binding(flag, space_set, binding);
// The push constant block did not have a binding, and there were no remap for it,
// so, declare without register binding.
if (flag == HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT && space_set == ResourceBindingPushConstantDescriptorSet)
return "";
if (hlsl_options.shader_model >= 51)
return join(" : register(", space, binding, ", space", space_set, ")");
else
@@ -3104,6 +3216,11 @@ void CompilerHLSL::emit_uniform(const SPIRVariable &var)
emit_legacy_uniform(var);
}
bool CompilerHLSL::emit_complex_bitcast(uint32_t, uint32_t, uint32_t)
{
return false;
}
string CompilerHLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in_type)
{
if (out_type.basetype == SPIRType::UInt && in_type.basetype == SPIRType::Int)
@@ -3955,6 +4072,9 @@ void CompilerHLSL::emit_access_chain(const Instruction &instruction)
inherit_expression_dependencies(ops[1], ops[i]);
add_implied_read_expression(e, ops[i]);
}
if (has_decoration(ops[1], DecorationNonUniformEXT))
propagate_nonuniform_qualifier(ops[1]);
}
else
{
@@ -4079,6 +4199,11 @@ void CompilerHLSL::emit_subgroup_op(const Instruction &i)
return join(expr, " * ", to_expression(ops[4]));
};
// If we need to do implicit bitcasts, make sure we do it with the correct type.
uint32_t integer_width = get_integer_width_for_instruction(i);
auto int_type = to_signed_basetype(integer_width);
auto uint_type = to_unsigned_basetype(integer_width);
#define make_inclusive_BitAnd(expr) ""
#define make_inclusive_BitOr(expr) ""
#define make_inclusive_BitXor(expr) ""
@@ -4187,20 +4312,34 @@ case OpGroupNonUniform##op: \
SPIRV_CROSS_THROW("Invalid group operation."); \
break; \
}
#define HLSL_GROUP_OP_CAST(op, hlsl_op, type) \
case OpGroupNonUniform##op: \
{ \
auto operation = static_cast<GroupOperation>(ops[3]); \
if (operation == GroupOperationReduce) \
emit_unary_func_op_cast(result_type, id, ops[4], "WaveActive" #hlsl_op, type, type); \
else \
SPIRV_CROSS_THROW("Invalid group operation."); \
break; \
}
HLSL_GROUP_OP(FAdd, Sum, true)
HLSL_GROUP_OP(FMul, Product, true)
HLSL_GROUP_OP(FMin, Min, false)
HLSL_GROUP_OP(FMax, Max, false)
HLSL_GROUP_OP(IAdd, Sum, true)
HLSL_GROUP_OP(IMul, Product, true)
HLSL_GROUP_OP(SMin, Min, false)
HLSL_GROUP_OP(SMax, Max, false)
HLSL_GROUP_OP(UMin, Min, false)
HLSL_GROUP_OP(UMax, Max, false)
HLSL_GROUP_OP_CAST(SMin, Min, int_type)
HLSL_GROUP_OP_CAST(SMax, Max, int_type)
HLSL_GROUP_OP_CAST(UMin, Min, uint_type)
HLSL_GROUP_OP_CAST(UMax, Max, uint_type)
HLSL_GROUP_OP(BitwiseAnd, BitAnd, false)
HLSL_GROUP_OP(BitwiseOr, BitOr, false)
HLSL_GROUP_OP(BitwiseXor, BitXor, false)
#undef HLSL_GROUP_OP
#undef HLSL_GROUP_OP_CAST
// clang-format on
case OpGroupNonUniformQuadSwap:
@@ -4260,6 +4399,27 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
emit_access_chain(instruction);
break;
}
case OpBitcast:
{
auto bitcast_type = get_bitcast_type(ops[0], ops[2]);
if (bitcast_type == CompilerHLSL::TypeNormal)
CompilerGLSL::emit_instruction(instruction);
else
{
if (!requires_uint2_packing)
{
requires_uint2_packing = true;
force_recompile();
}
if (bitcast_type == CompilerHLSL::TypePackUint2x32)
emit_unary_func_op(ops[0], ops[1], ops[2], "SPIRV_Cross_packUint2x32");
else
emit_unary_func_op(ops[0], ops[1], ops[2], "SPIRV_Cross_unpackUint2x32");
}
break;
}
case OpStore:
{
@@ -4723,7 +4883,12 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
imgexpr = join(to_expression(ops[2]), "[", to_expression(ops[3]), "]");
// The underlying image type in HLSL depends on the image format, unlike GLSL, where all images are "vec4",
// except that the underlying type changes how the data is interpreted.
if (var && !subpass_data)
bool force_srv =
hlsl_options.nonwritable_uav_texture_as_srv && var && has_decoration(var->self, DecorationNonWritable);
pure = force_srv;
if (var && !subpass_data && !force_srv)
imgexpr = remap_swizzle(get<SPIRType>(result_type),
image_format_to_components(get<SPIRType>(var->basetype).image.format), imgexpr);
}
@@ -4774,8 +4939,13 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction)
{
uint32_t result_type = ops[0];
uint32_t id = ops[1];
auto &e =
set<SPIRExpression>(id, join(to_expression(ops[2]), "[", to_expression(ops[3]), "]"), result_type, true);
auto expr = to_expression(ops[2]);
if (has_decoration(id, DecorationNonUniformEXT) || has_decoration(ops[2], DecorationNonUniformEXT))
convert_non_uniform_expression(expression_type(ops[2]), expr);
expr += join("[", to_expression(ops[3]), "]");
auto &e = set<SPIRExpression>(id, expr, result_type, true);
// When using the pointer, we need to know which variable it is actually loaded from.
auto *var = maybe_get_backing_variable(ops[2]);
@@ -5215,3 +5385,31 @@ string CompilerHLSL::get_unique_identifier()
{
return join("_", unique_identifier_count++, "ident");
}
void CompilerHLSL::add_hlsl_resource_binding(const HLSLResourceBinding &binding)
{
StageSetBinding tuple = { binding.stage, binding.desc_set, binding.binding };
resource_bindings[tuple] = { binding, false };
}
bool CompilerHLSL::is_hlsl_resource_binding_used(ExecutionModel model, uint32_t desc_set, uint32_t binding) const
{
StageSetBinding tuple = { model, desc_set, binding };
auto itr = resource_bindings.find(tuple);
return itr != end(resource_bindings) && itr->second.second;
}
CompilerHLSL::BitcastType CompilerHLSL::get_bitcast_type(uint32_t result_type, uint32_t op0)
{
auto &rslt_type = get<SPIRType>(result_type);
auto &expr_type = expression_type(op0);
if (rslt_type.basetype == SPIRType::BaseType::UInt64 && expr_type.basetype == SPIRType::BaseType::UInt &&
expr_type.vecsize == 2)
return BitcastType::TypePackUint2x32;
else if (rslt_type.basetype == SPIRType::BaseType::UInt && rslt_type.vecsize == 2 &&
expr_type.basetype == SPIRType::BaseType::UInt64)
return BitcastType::TypeUnpackUint64;
return BitcastType::TypeNormal;
}
+58 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2019 Robert Konrad
* Copyright 2016-2020 Robert Konrad
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,6 +44,8 @@ struct RootConstants
// For finer control, decorations may be removed from specific resources instead with unset_decoration().
enum HLSLBindingFlagBits
{
HLSL_BINDING_AUTO_NONE_BIT = 0,
// Push constant (root constant) resources will be declared as CBVs (b-space) without a register() declaration.
// A register will be automatically assigned by the D3D compiler, but must therefore be reflected in D3D-land.
// Push constants do not normally have a DecorationBinding set, but if they do, this can be used to ignore it.
@@ -67,6 +69,28 @@ enum HLSLBindingFlagBits
};
using HLSLBindingFlags = uint32_t;
// By matching stage, desc_set and binding for a SPIR-V resource,
// register bindings are set based on whether the HLSL resource is a
// CBV, UAV, SRV or Sampler. A single binding in SPIR-V might contain multiple
// resource types, e.g. COMBINED_IMAGE_SAMPLER, and SRV/Sampler bindings will be used respectively.
// On SM 5.0 and lower, register_space is ignored.
//
// To remap a push constant block which does not have any desc_set/binding associated with it,
// use ResourceBindingPushConstant{DescriptorSet,Binding} as values for desc_set/binding.
// For deeper control of push constants, set_root_constant_layouts() can be used instead.
struct HLSLResourceBinding
{
spv::ExecutionModel stage = spv::ExecutionModelMax;
uint32_t desc_set = 0;
uint32_t binding = 0;
struct Binding
{
uint32_t register_space = 0;
uint32_t register_binding = 0;
} cbv, uav, srv, sampler;
};
class CompilerHLSL : public CompilerGLSL
{
public:
@@ -85,6 +109,15 @@ public:
// Set to false if you know you will never use base instance or base vertex
// functionality as it might remove an internal cbuffer.
bool support_nonzero_base_vertex_base_instance = false;
// 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.
bool force_storage_buffer_as_uav = false;
// 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
// so that NonWritable image arguments are also translated to Texture rather than RWTexture.
bool nonwritable_uav_texture_as_srv = false;
};
explicit CompilerHLSL(std::vector<uint32_t> spirv_)
@@ -145,6 +178,14 @@ public:
// Controls how resource bindings are declared in the output HLSL.
void set_resource_binding_flags(HLSLBindingFlags flags);
// resource is a resource binding to indicate the HLSL CBV, SRV, UAV or sampler binding
// to use for a particular SPIR-V description set
// and binding. If resource bindings are provided,
// is_hlsl_resource_binding_used() will return true after calling ::compile() if
// the set/binding combination was used by the HLSL code.
void add_hlsl_resource_binding(const HLSLResourceBinding &resource);
bool is_hlsl_resource_binding_used(spv::ExecutionModel model, uint32_t set, uint32_t binding) const;
private:
std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override;
std::string image_type_hlsl(const SPIRType &type, uint32_t id);
@@ -154,6 +195,7 @@ private:
void emit_hlsl_entry_point();
void emit_header() override;
void emit_resources();
void declare_undefined_values() override;
void emit_interface_block_globally(const SPIRVariable &type);
void emit_interface_block_in_struct(const SPIRVariable &type, std::unordered_set<uint32_t> &active_locations);
void emit_builtin_inputs_in_struct();
@@ -174,11 +216,12 @@ private:
std::string layout_for_member(const SPIRType &type, uint32_t index) override;
std::string to_interpolation_qualifiers(const Bitset &flags) override;
std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type) override;
bool emit_complex_bitcast(uint32_t result_type, uint32_t id, uint32_t op0) override;
std::string to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_t id) override;
std::string to_sampler_expression(uint32_t id);
std::string to_resource_binding(const SPIRVariable &var);
std::string to_resource_binding_sampler(const SPIRVariable &var);
std::string to_resource_register(HLSLBindingFlags flags, char space, uint32_t binding, uint32_t set);
std::string to_resource_register(HLSLBindingFlagBits flag, char space, uint32_t binding, uint32_t set);
void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id) override;
void emit_access_chain(const Instruction &instruction);
void emit_load(const Instruction &instruction);
@@ -207,6 +250,7 @@ private:
// TODO: Refactor this to be more similar to MSL, maybe have some common system in place?
bool requires_op_fmod = false;
bool requires_fp16_packing = false;
bool requires_uint2_packing = false;
bool requires_explicit_fp16_packing = false;
bool requires_unorm8_packing = false;
bool requires_snorm8_packing = false;
@@ -246,6 +290,15 @@ private:
QueryTypeCount = 3
};
enum BitcastType
{
TypeNormal,
TypePackUint2x32,
TypeUnpackUint64
};
BitcastType get_bitcast_type(uint32_t result_type, uint32_t op0);
void emit_builtin_variables();
bool require_output = false;
bool require_input = false;
@@ -267,6 +320,9 @@ private:
std::string get_unique_identifier();
uint32_t unique_identifier_count = 0;
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);
};
} // namespace SPIRV_CROSS_NAMESPACE
+386 -116
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2019 The Brenwill Workshop Ltd.
* Copyright 2016-2020 The Brenwill Workshop Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -68,6 +68,12 @@ void CompilerMSL::add_dynamic_buffer(uint32_t desc_set, uint32_t binding, uint32
buffers_requiring_dynamic_offset[pair] = { index, 0 };
}
void CompilerMSL::add_inline_uniform_block(uint32_t desc_set, uint32_t binding)
{
SetBindingPair pair = { desc_set, binding };
inline_uniform_blocks.insert(pair);
}
void CompilerMSL::add_discrete_descriptor_set(uint32_t desc_set)
{
if (desc_set < kMaxArgumentBuffers)
@@ -90,7 +96,7 @@ bool CompilerMSL::is_msl_vertex_attribute_used(uint32_t location)
return vtx_attrs_in_use.count(location) != 0;
}
bool CompilerMSL::is_msl_resource_binding_used(ExecutionModel model, uint32_t desc_set, uint32_t binding)
bool CompilerMSL::is_msl_resource_binding_used(ExecutionModel model, uint32_t desc_set, uint32_t binding) const
{
StageSetBinding tuple = { model, desc_set, binding };
auto itr = resource_bindings.find(tuple);
@@ -168,6 +174,7 @@ void CompilerMSL::build_implicit_builtins()
if (need_subpass_input && (!msl_options.is_ios() || !msl_options.ios_use_framebuffer_fetch_subpasses) &&
builtin == BuiltInFragCoord)
{
mark_implicit_builtin(StorageClassInput, BuiltInFragCoord, var.self);
builtin_frag_coord_id = var.self;
has_frag_coord = true;
}
@@ -175,6 +182,7 @@ void CompilerMSL::build_implicit_builtins()
if (need_sample_pos && builtin == BuiltInSampleId)
{
builtin_sample_id_id = var.self;
mark_implicit_builtin(StorageClassInput, BuiltInSampleId, var.self);
has_sample_id = true;
}
@@ -184,18 +192,22 @@ void CompilerMSL::build_implicit_builtins()
{
case BuiltInVertexIndex:
builtin_vertex_idx_id = var.self;
mark_implicit_builtin(StorageClassInput, BuiltInVertexIndex, var.self);
has_vertex_idx = true;
break;
case BuiltInBaseVertex:
builtin_base_vertex_id = var.self;
mark_implicit_builtin(StorageClassInput, BuiltInBaseVertex, var.self);
has_base_vertex = true;
break;
case BuiltInInstanceIndex:
builtin_instance_idx_id = var.self;
mark_implicit_builtin(StorageClassInput, BuiltInInstanceIndex, var.self);
has_instance_idx = true;
break;
case BuiltInBaseInstance:
builtin_base_instance_id = var.self;
mark_implicit_builtin(StorageClassInput, BuiltInBaseInstance, var.self);
has_base_instance = true;
break;
default:
@@ -209,10 +221,12 @@ void CompilerMSL::build_implicit_builtins()
{
case BuiltInInvocationId:
builtin_invocation_id_id = var.self;
mark_implicit_builtin(StorageClassInput, BuiltInInvocationId, var.self);
has_invocation_id = true;
break;
case BuiltInPrimitiveId:
builtin_primitive_id_id = var.self;
mark_implicit_builtin(StorageClassInput, BuiltInPrimitiveId, var.self);
has_primitive_id = true;
break;
default:
@@ -223,12 +237,14 @@ void CompilerMSL::build_implicit_builtins()
if ((need_subgroup_mask || needs_subgroup_invocation_id) && builtin == BuiltInSubgroupLocalInvocationId)
{
builtin_subgroup_invocation_id_id = var.self;
mark_implicit_builtin(StorageClassInput, BuiltInSubgroupLocalInvocationId, var.self);
has_subgroup_invocation_id = true;
}
if (need_subgroup_ge_mask && builtin == BuiltInSubgroupSize)
{
builtin_subgroup_size_id = var.self;
mark_implicit_builtin(StorageClassInput, BuiltInSubgroupSize, var.self);
has_subgroup_size = true;
}
@@ -239,10 +255,12 @@ void CompilerMSL::build_implicit_builtins()
case BuiltInInstanceIndex:
// The view index here is derived from the instance index.
builtin_instance_idx_id = var.self;
mark_implicit_builtin(StorageClassInput, BuiltInInstanceIndex, var.self);
has_instance_idx = true;
break;
case BuiltInViewIndex:
builtin_view_idx_id = var.self;
mark_implicit_builtin(StorageClassInput, BuiltInViewIndex, var.self);
has_view_idx = true;
break;
default:
@@ -639,7 +657,10 @@ void CompilerMSL::mark_implicit_builtin(StorageClass storage, BuiltIn builtin, u
assert(active_builtins != nullptr);
active_builtins->set(builtin);
get_entry_point().interface_variables.push_back(id);
auto &var = get_entry_point().interface_variables;
if (find(begin(var), end(var), VariableID(id)) == end(var))
var.push_back(id);
}
uint32_t CompilerMSL::build_constant_uint_array_pointer()
@@ -884,7 +905,7 @@ void CompilerMSL::emit_entry_point_declarations()
SPIRV_CROSS_THROW("Runtime arrays with dynamic offsets are not supported yet.");
else
{
use_builtin_array = true;
is_using_builtin_array = true;
statement(get_argument_address_space(var), " ", type_to_glsl(type), "* ", to_restrict(var_id), name,
type_to_array_glsl(type), " =");
@@ -915,7 +936,7 @@ void CompilerMSL::emit_entry_point_declarations()
}
end_scope_decl();
statement_no_indent("");
use_builtin_array = false;
is_using_builtin_array = false;
}
}
else
@@ -944,6 +965,16 @@ void CompilerMSL::emit_entry_point_declarations()
}
// For some reason, without this, we end up emitting the arrays twice.
buffer_arrays.clear();
// Emit disabled fragment outputs.
std::sort(disabled_frag_outputs.begin(), disabled_frag_outputs.end());
for (uint32_t var_id : disabled_frag_outputs)
{
auto &var = get<SPIRVariable>(var_id);
add_local_variable_name(var_id);
statement(variable_decl(var), ";");
var.deferred_declaration = false;
}
}
string CompilerMSL::compile()
@@ -973,15 +1004,17 @@ string CompilerMSL::compile()
backend.native_row_major_matrix = false;
backend.unsized_array_supported = false;
backend.can_declare_arrays_inline = false;
backend.can_return_array = true; // <-- Allow Metal to use the array<T> template
backend.allow_truncated_access_chain = true;
backend.array_is_value_type = true; // <-- Allow Metal to use the array<T> template to make arrays a value type
backend.comparison_image_samples_scalar = true;
backend.native_pointers = true;
backend.nonuniform_qualifier = "";
backend.support_small_type_sampling_result = true;
backend.supports_empty_struct = true;
// Allow Metal to use the array<T> template unless we force it off.
backend.can_return_array = !msl_options.force_native_arrays;
backend.array_is_value_type = !msl_options.force_native_arrays;
capture_output_to_buffer = msl_options.capture_output_to_buffer;
is_rasterization_disabled = msl_options.disable_rasterization || capture_output_to_buffer;
@@ -1003,6 +1036,9 @@ string CompilerMSL::compile()
fixup_image_load_store_access();
set_enabled_interface_variables(get_active_interface_variables());
if (msl_options.force_active_argument_buffer_resources)
activate_argument_buffer_resources();
if (swizzle_buffer_id)
active_interface_variables.insert(swizzle_buffer_id);
if (buffer_size_buffer_id)
@@ -1701,6 +1737,7 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
set_name(var.self, builtin_to_glsl(builtin, StorageClassFunction));
bool flatten_from_ib_var = false;
string flatten_from_ib_mbr_name;
if (storage == StorageClassOutput && is_builtin && builtin == BuiltInClipDistance)
{
@@ -1708,11 +1745,16 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
uint32_t clip_array_mbr_idx = uint32_t(ib_type.member_types.size());
ib_type.member_types.push_back(get_variable_data_type_id(var));
set_member_decoration(ib_type.self, clip_array_mbr_idx, DecorationBuiltIn, BuiltInClipDistance);
set_member_name(ib_type.self, clip_array_mbr_idx, builtin_to_glsl(BuiltInClipDistance, StorageClassOutput));
flatten_from_ib_mbr_name = builtin_to_glsl(BuiltInClipDistance, StorageClassOutput);
set_member_name(ib_type.self, clip_array_mbr_idx, flatten_from_ib_mbr_name);
// When we flatten, we flatten directly from the "out" struct,
// not from a function variable.
flatten_from_ib_var = true;
if (!msl_options.enable_clip_distance_user_varying)
return;
}
else if (!meta.strip_array)
{
@@ -1817,7 +1859,8 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage
";");
}
else if (flatten_from_ib_var)
statement(ib_var_ref, ".", mbr_name, " = ", ib_var_ref, ".", to_name(var.self), "[", i, "];");
statement(ib_var_ref, ".", mbr_name, " = ", ib_var_ref, ".", flatten_from_ib_mbr_name, "[", i,
"];");
else
statement(ib_var_ref, ".", mbr_name, " = ", to_name(var.self), "[", i, "];");
});
@@ -1902,6 +1945,7 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
usable_type = &get<SPIRType>(usable_type->parent_type);
bool flatten_from_ib_var = false;
string flatten_from_ib_mbr_name;
if (storage == StorageClassOutput && is_builtin && builtin == BuiltInClipDistance)
{
@@ -1909,11 +1953,16 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
uint32_t clip_array_mbr_idx = uint32_t(ib_type.member_types.size());
ib_type.member_types.push_back(mbr_type_id);
set_member_decoration(ib_type.self, clip_array_mbr_idx, DecorationBuiltIn, BuiltInClipDistance);
set_member_name(ib_type.self, clip_array_mbr_idx, builtin_to_glsl(BuiltInClipDistance, StorageClassOutput));
flatten_from_ib_mbr_name = builtin_to_glsl(BuiltInClipDistance, StorageClassOutput);
set_member_name(ib_type.self, clip_array_mbr_idx, flatten_from_ib_mbr_name);
// When we flatten, we flatten directly from the "out" struct,
// not from a function variable.
flatten_from_ib_var = true;
if (!msl_options.enable_clip_distance_user_varying)
return;
}
for (uint32_t i = 0; i < elem_cnt; i++)
@@ -1983,8 +2032,8 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass
entry_func.fixup_hooks_out.push_back([=, &var, &var_type]() {
if (flatten_from_ib_var)
{
statement(ib_var_ref, ".", mbr_name, " = ", ib_var_ref, ".", to_member_name(var_type, mbr_idx),
"[", i, "];");
statement(ib_var_ref, ".", mbr_name, " = ", ib_var_ref, ".", flatten_from_ib_mbr_name, "[", i,
"];");
}
else
{
@@ -2409,6 +2458,7 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
bool is_builtin = is_builtin_variable(var);
auto bi_type = BuiltIn(get_decoration(var_id, DecorationBuiltIn));
uint32_t location = get_decoration(var_id, DecorationLocation);
// These builtins are part of the stage in/out structs.
bool is_interface_block_builtin =
@@ -2434,6 +2484,21 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
if (bi_type == BuiltInClipDistance)
hidden = false;
// It's not enough to simply avoid marking fragment outputs if the pipeline won't
// accept them. We can't put them in the struct at all, or otherwise the compiler
// complains that the outputs weren't explicitly marked.
if (get_execution_model() == ExecutionModelFragment && storage == StorageClassOutput && !patch &&
((is_builtin && ((bi_type == BuiltInFragDepth && !msl_options.enable_frag_depth_builtin) ||
(bi_type == BuiltInFragStencilRefEXT && !msl_options.enable_frag_stencil_ref_builtin))) ||
(!is_builtin && !(msl_options.enable_frag_output_mask & (1 << location)))))
{
hidden = true;
disabled_frag_outputs.push_back(var_id);
// If a builtin, force it to have the proper name.
if (is_builtin)
set_name(var_id, builtin_to_glsl(bi_type, StorageClassFunction));
}
// Barycentric inputs must be emitted in stage-in, because they can have interpolation arguments.
if (is_active && (bi_type == BuiltInBaryCoordNV || bi_type == BuiltInBaryCoordNoPerspNV))
{
@@ -2463,7 +2528,6 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
SPIRV_CROSS_THROW("Component decoration is not supported in tessellation shaders.");
else if (pack_components)
{
uint32_t location = get_decoration(var_id, DecorationLocation);
auto &location_meta = meta.location_meta[location];
location_meta.num_components = std::max(location_meta.num_components, component + type.vecsize);
}
@@ -3022,10 +3086,20 @@ bool CompilerMSL::validate_member_packing_rules_msl(const SPIRType &type, uint32
if (!mbr_type.array.empty())
{
// If we have an array type, array stride must match exactly with SPIR-V.
uint32_t spirv_array_stride = type_struct_member_array_stride(type, index);
uint32_t msl_array_stride = get_declared_struct_member_array_stride_msl(type, index);
if (spirv_array_stride != msl_array_stride)
return false;
// An exception to this requirement is if we have one array element and a packed decoration.
// 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.
bool relax_array_stride = has_extended_member_decoration(type.self, index, SPIRVCrossDecorationPhysicalTypePacked) &&
mbr_type.array.back() == 1 && mbr_type.array_size_literal.back();
if (!relax_array_stride)
{
uint32_t spirv_array_stride = type_struct_member_array_stride(type, index);
uint32_t msl_array_stride = get_declared_struct_member_array_stride_msl(type, index);
if (spirv_array_stride != msl_array_stride)
return false;
}
}
if (is_matrix(mbr_type))
@@ -3137,6 +3211,77 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in
else
unset_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
}
else
SPIRV_CROSS_THROW("Found a buffer packing case which we cannot represent in MSL.");
// Try validating again, now with physical type remapping.
if (validate_member_packing_rules_msl(ib_type, index))
return;
// We might have a particular odd scalar layout case where the last element of an array
// does not take up as much space as the ArrayStride or MatrixStride. This can happen with DX cbuffers.
// The "proper" workaround for this is extremely painful and essentially impossible in the edge case of float3[],
// so we hack around it by declaring the offending array or matrix with one less array size/col/row,
// and rely on padding to get the correct value. We will technically access arrays out of bounds into the padding region,
// but it should spill over gracefully without too much trouble. We rely on behavior like this for unsized arrays anyways.
// E.g. we might observe a physical layout of:
// { float2 a[2]; float b; } in cbuffer layout where ArrayStride of a is 16, but offset of b is 24, packed right after a[1] ...
uint32_t type_id = get_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypeID);
auto &type = get<SPIRType>(type_id);
// Modify the physical type in-place. This is safe since each physical type workaround is a copy.
if (is_array(type))
{
if (type.array.back() > 1)
{
if (!type.array_size_literal.back())
SPIRV_CROSS_THROW("Cannot apply scalar layout workaround with spec constant array size.");
type.array.back() -= 1;
}
else
{
// We have an array of size 1, so we cannot decrement that. Our only option now is to
// force a packed layout instead, and drop the physical type remap since ArrayStride is meaningless now.
unset_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypeID);
set_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypePacked);
}
}
else if (is_matrix(type))
{
bool row_major = has_member_decoration(ib_type.self, index, DecorationRowMajor);
if (!row_major)
{
// Slice off one column. If we only have 2 columns, this might turn the matrix into a vector with one array element instead.
if (type.columns > 2)
{
type.columns--;
}
else if (type.columns == 2)
{
type.columns = 1;
assert(type.array.empty());
type.array.push_back(1);
type.array_size_literal.push_back(true);
}
}
else
{
// Slice off one row. If we only have 2 rows, this might turn the matrix into a vector with one array element instead.
if (type.vecsize > 2)
{
type.vecsize--;
}
else if (type.vecsize == 2)
{
type.vecsize = type.columns;
type.columns = 1;
assert(type.array.empty());
type.array.push_back(1);
type.array_size_literal.push_back(true);
}
}
}
// This better validate now, or we must fail gracefully.
if (!validate_member_packing_rules_msl(ib_type, index))
@@ -6691,29 +6836,6 @@ void CompilerMSL::emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uin
bar_stmt += "mem_flags::mem_none";
}
if (msl_options.is_ios() && (msl_options.supports_msl_version(2) && !msl_options.supports_msl_version(2, 1)))
{
bar_stmt += ", ";
switch (mem_scope)
{
case ScopeCrossDevice:
case ScopeDevice:
bar_stmt += "memory_scope_device";
break;
case ScopeSubgroup:
case ScopeInvocation:
bar_stmt += "memory_scope_simdgroup";
break;
case ScopeWorkgroup:
default:
bar_stmt += "memory_scope_threadgroup";
break;
}
}
bar_stmt += ");";
statement(bar_stmt);
@@ -6735,7 +6857,7 @@ void CompilerMSL::emit_array_copy(const string &lhs, uint32_t rhs_id, StorageCla
// If threadgroup storage qualifiers are *not* used:
// Avoid spvCopy* wrapper functions; Otherwise, spvUnsafeArray<> template cannot be used with that storage qualifier.
if (lhs_thread && rhs_thread && !use_builtin_array)
if (lhs_thread && rhs_thread && !using_builtin_array())
{
statement(lhs, " = ", to_expression(rhs_id), ";");
}
@@ -6789,9 +6911,9 @@ void CompilerMSL::emit_array_copy(const string &lhs, uint32_t rhs_id, StorageCla
SPIRV_CROSS_THROW("Unknown storage class used for copying arrays.");
// Pass internal array of spvUnsafeArray<> into wrapper functions
if (lhs_thread)
if (lhs_thread && !msl_options.force_native_arrays)
statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ".elements, ", to_expression(rhs_id), ");");
else if (rhs_thread)
else if (rhs_thread && !msl_options.force_native_arrays)
statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ", ", to_expression(rhs_id), ".elements);");
else
statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ", ", to_expression(rhs_id), ");");
@@ -7241,11 +7363,31 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, const Bitset &)
auto &type = get<SPIRType>(func.return_type);
decl += func_type_decl(type);
if (!type.array.empty() && msl_options.force_native_arrays)
{
// We cannot return native arrays in MSL, so "return" through an out variable.
decl += "void";
}
else
{
decl += func_type_decl(type);
}
decl += " ";
decl += to_name(func.self);
decl += "(";
if (!type.array.empty() && msl_options.force_native_arrays)
{
// Fake arrays returns by writing to an out array instead.
decl += "thread ";
decl += type_to_glsl(type);
decl += " (&SPIRV_Cross_return_value)";
decl += type_to_array_glsl(type);
if (!func.arguments.empty())
decl += ", ";
}
if (processing_entry_point)
{
if (msl_options.argument_buffers)
@@ -8190,7 +8332,29 @@ string CompilerMSL::to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_
if (is_dynamic_img_sampler && !arg_is_dynamic_img_sampler)
arg_str = join("spvDynamicImageSampler<", type_to_glsl(get<SPIRType>(type.image.type)), ">(");
arg_str += CompilerGLSL::to_func_call_arg(arg, id);
auto *c = maybe_get<SPIRConstant>(id);
if (msl_options.force_native_arrays && c && !get<SPIRType>(c->constant_type).array.empty())
{
// If we are passing a constant array directly to a function for some reason,
// the callee will expect an argument in thread const address space
// (since we can only bind to arrays with references in MSL).
// To resolve this, we must emit a copy in this address space.
// This kind of code gen should be rare enough that performance is not a real concern.
// Inline the SPIR-V to avoid this kind of suboptimal codegen.
//
// We risk calling this inside a continue block (invalid code),
// so just create a thread local copy in the current function.
arg_str = join("_", id, "_array_copy");
auto &constants = current_function->constant_arrays_needed_on_stack;
auto itr = find(begin(constants), end(constants), ID(id));
if (itr == end(constants))
{
force_recompile();
constants.push_back(id);
}
}
else
arg_str += CompilerGLSL::to_func_call_arg(arg, id);
// Need to check the base variable in case we need to apply a qualified alias.
uint32_t var_id = 0;
@@ -8465,9 +8629,9 @@ string CompilerMSL::to_struct_member(const SPIRType &type, uint32_t member_type_
// address space.
// Array of resources should also be declared as builtin arrays.
if (has_member_decoration(type.self, index, DecorationOffset))
use_builtin_array = true;
is_using_builtin_array = true;
else if (has_extended_member_decoration(type.self, index, SPIRVCrossDecorationResourceIndexPrimary))
use_builtin_array = true;
is_using_builtin_array = true;
if (member_is_packed_physical_type(type, index))
{
@@ -8523,14 +8687,14 @@ string CompilerMSL::to_struct_member(const SPIRType &type, uint32_t member_type_
{
BuiltIn builtin = BuiltInMax;
if (is_member_builtin(type, index, &builtin))
use_builtin_array = true;
is_using_builtin_array = true;
array_type = type_to_array_glsl(physical_type);
}
auto result = join(pack_pfx, type_to_glsl(*declared_type, orig_id), " ", qualifier, to_member_name(type, index),
member_attribute_qualifier(type, index), array_type, ";");
use_builtin_array = false;
is_using_builtin_array = false;
return result;
}
@@ -8825,12 +8989,23 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in
switch (builtin)
{
case BuiltInFragStencilRefEXT:
// Similar to PointSize, only mark FragStencilRef if there's a stencil buffer.
// Some shaders may include a FragStencilRef builtin even when used to render
// without a stencil attachment, and Metal will reject this builtin
// when compiling the shader into a render pipeline that does not set
// stencilAttachmentPixelFormat.
if (!msl_options.enable_frag_stencil_ref_builtin)
return "";
if (!msl_options.supports_msl_version(2, 1))
SPIRV_CROSS_THROW("Stencil export only supported in MSL 2.1 and up.");
return string(" [[") + builtin_qualifier(builtin) + "]]";
case BuiltInSampleMask:
case BuiltInFragDepth:
// Ditto FragDepth.
if (!msl_options.enable_frag_depth_builtin)
return "";
/* fallthrough */
case BuiltInSampleMask:
return string(" [[") + builtin_qualifier(builtin) + "]]";
default:
@@ -8838,6 +9013,9 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in
}
}
uint32_t locn = get_ordered_member_location(type.self, index);
// Metal will likely complain about missing color attachments, too.
if (locn != k_unknown_location && !(msl_options.enable_frag_output_mask & (1 << locn)))
return "";
if (locn != k_unknown_location && has_member_decoration(type.self, index, DecorationIndex))
return join(" [[color(", locn, "), index(", get_member_decoration(type.self, index, DecorationIndex),
")]]");
@@ -9407,7 +9585,7 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args)
SPIRV_CROSS_THROW("Unsized arrays of buffers are not supported in MSL.");
// Allow Metal to use the array<T> template to make arrays a value type
use_builtin_array = true;
is_using_builtin_array = true;
buffer_arrays.push_back(var_id);
for (uint32_t i = 0; i < array_size; ++i)
{
@@ -9420,7 +9598,7 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args)
ep_args += ", raster_order_group(0)";
ep_args += "]]";
}
use_builtin_array = false;
is_using_builtin_array = false;
}
else
{
@@ -9902,6 +10080,11 @@ uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable &var, SPIRType::Base
// If we did not explicitly remap, allocate bindings on demand.
// We cannot reliably use Binding decorations since SPIR-V and MSL's binding models are very different.
bool allocate_argument_buffer_ids = false;
if (var.storage != StorageClassPushConstant)
allocate_argument_buffer_ids = descriptor_set_is_argument_buffer(var_desc_set);
uint32_t binding_stride = 1;
auto &type = get<SPIRType>(var.basetype);
for (uint32_t i = 0; i < uint32_t(type.array.size()); i++)
@@ -9912,20 +10095,11 @@ uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable &var, SPIRType::Base
// If a binding has not been specified, revert to incrementing resource indices.
uint32_t resource_index;
bool allocate_argument_buffer_ids = false;
uint32_t desc_set = 0;
if (var.storage != StorageClassPushConstant)
{
desc_set = get_decoration(var.self, DecorationDescriptorSet);
allocate_argument_buffer_ids = descriptor_set_is_argument_buffer(desc_set);
}
if (allocate_argument_buffer_ids)
{
// Allocate from a flat ID binding space.
resource_index = next_metal_resource_ids[desc_set];
next_metal_resource_ids[desc_set] += binding_stride;
resource_index = next_metal_resource_ids[var_desc_set];
next_metal_resource_ids[var_desc_set] += binding_stride;
}
else
{
@@ -9990,9 +10164,9 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
// Allow Metal to use the array<T> template to make arrays a value type
string address_space = get_argument_address_space(var);
bool builtin = is_builtin_variable(var);
use_builtin_array = builtin;
is_using_builtin_array = builtin;
if (address_space == "threadgroup")
use_builtin_array = true;
is_using_builtin_array = true;
if (var.basevariable && (var.basevariable == stage_in_ptr_var_id || var.basevariable == stage_out_ptr_var_id))
decl += type_to_glsl(type, arg.id);
@@ -10000,7 +10174,7 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
decl += builtin_type_decl(static_cast<BuiltIn>(get_decoration(arg.id, DecorationBuiltIn)), arg.id);
else if ((storage == StorageClassUniform || storage == StorageClassStorageBuffer) && is_array(type))
{
use_builtin_array = true;
is_using_builtin_array = true;
decl += join(type_to_glsl(type, arg.id), "*");
}
else if (is_dynamic_img_sampler)
@@ -10018,10 +10192,34 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
(storage == StorageClassFunction || storage == StorageClassGeneric))
{
// If the argument is a pure value and not an opaque type, we will pass by value.
if (!address_space.empty())
decl = join(address_space, " ", decl);
decl += " ";
decl += to_expression(name_id);
if (msl_options.force_native_arrays && is_array(type))
{
// We are receiving an array by value. This is problematic.
// We cannot be sure of the target address space since we are supposed to receive a copy,
// but this is not possible with MSL without some extra work.
// We will have to assume we're getting a reference in thread address space.
// If we happen to get a reference in constant address space, the caller must emit a copy and pass that.
// Thread const therefore becomes the only logical choice, since we cannot "create" a constant array from
// non-constant arrays, but we can create thread const from constant.
decl = string("thread const ") + decl;
decl += " (&";
const char *restrict_kw = to_restrict(name_id);
if (*restrict_kw)
{
decl += " ";
decl += restrict_kw;
}
decl += to_expression(name_id);
decl += ")";
decl += type_to_array_glsl(type);
}
else
{
if (!address_space.empty())
decl = join(address_space, " ", decl);
decl += " ";
decl += to_expression(name_id);
}
}
else if (is_array(type) && !type_is_image)
{
@@ -10097,7 +10295,7 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg)
decl += "* " + to_expression(name_id) + "_atomic";
}
use_builtin_array = false;
is_using_builtin_array = false;
return decl;
}
@@ -10395,19 +10593,31 @@ void CompilerMSL::replace_illegal_names()
};
ir.for_each_typed_id<SPIRVariable>([&](uint32_t self, SPIRVariable &) {
auto &dec = ir.meta[self].decoration;
auto *meta = ir.find_meta(self);
if (!meta)
return;
auto &dec = meta->decoration;
if (keywords.find(dec.alias) != end(keywords))
dec.alias += "0";
});
ir.for_each_typed_id<SPIRFunction>([&](uint32_t self, SPIRFunction &) {
auto &dec = ir.meta[self].decoration;
auto *meta = ir.find_meta(self);
if (!meta)
return;
auto &dec = meta->decoration;
if (illegal_func_names.find(dec.alias) != end(illegal_func_names))
dec.alias += "0";
});
ir.for_each_typed_id<SPIRType>([&](uint32_t self, SPIRType &) {
for (auto &mbr_dec : ir.meta[self].members)
auto *meta = ir.find_meta(self);
if (!meta)
return;
for (auto &mbr_dec : meta->members)
if (keywords.find(mbr_dec.alias) != end(keywords))
mbr_dec.alias += "0";
});
@@ -10436,7 +10646,12 @@ string CompilerMSL::to_member_reference(uint32_t base, const SPIRType &type, uin
if (var)
{
bool is_buffer_variable = var->storage == StorageClassUniform || var->storage == StorageClassStorageBuffer;
// Only allow -> dereference for block types. This is so we get expressions like
// buffer[i]->first_member.second_member, rather than buffer[i]->first->second.
bool is_block = has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock);
bool is_buffer_variable =
is_block && (var->storage == StorageClassUniform || var->storage == StorageClassStorageBuffer);
declared_as_pointer = is_buffer_variable && is_array(get<SPIRType>(var->basetype));
}
@@ -10570,7 +10785,7 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id)
if (type.vecsize > 1)
type_name += to_string(type.vecsize);
if (type.array.empty() || use_builtin_array)
if (type.array.empty() || using_builtin_array())
{
return type_name;
}
@@ -10606,7 +10821,7 @@ string CompilerMSL::type_to_array_glsl(const SPIRType &type)
}
default:
{
if (use_builtin_array)
if (using_builtin_array())
return CompilerGLSL::type_to_array_glsl(type);
else
return "";
@@ -10619,12 +10834,12 @@ std::string CompilerMSL::variable_decl(const SPIRVariable &variable)
{
if (variable.storage == StorageClassWorkgroup)
{
use_builtin_array = true;
is_using_builtin_array = true;
}
std::string expr = CompilerGLSL::variable_decl(variable);
if (variable.storage == StorageClassWorkgroup)
{
use_builtin_array = false;
is_using_builtin_array = false;
}
return expr;
}
@@ -10860,6 +11075,11 @@ void CompilerMSL::emit_subgroup_op(const Instruction &i)
if (!msl_options.supports_msl_version(2))
SPIRV_CROSS_THROW("Subgroups are only supported in Metal 2.0 and up.");
// If we need to do implicit bitcasts, make sure we do it with the correct type.
uint32_t integer_width = get_integer_width_for_instruction(i);
auto int_type = to_signed_basetype(integer_width);
auto uint_type = to_unsigned_basetype(integer_width);
if (msl_options.is_ios())
{
switch (op)
@@ -10882,7 +11102,7 @@ void CompilerMSL::emit_subgroup_op(const Instruction &i)
switch (op)
{
default:
SPIRV_CROSS_THROW("Subgroup ops beyond broadcast and shuffle on macOS require Metal 2.0 and up.");
SPIRV_CROSS_THROW("Subgroup ops beyond broadcast and shuffle on macOS require Metal 2.1 and up.");
case OpGroupNonUniformBroadcast:
case OpGroupNonUniformShuffle:
case OpGroupNonUniformShuffleXor:
@@ -11010,6 +11230,7 @@ case OpGroupNonUniform##op: \
MSL_GROUP_OP(IMul, product)
#undef MSL_GROUP_OP
// The others, unfortunately, don't support InclusiveScan or ExclusiveScan.
#define MSL_GROUP_OP(op, msl_op) \
case OpGroupNonUniform##op: \
{ \
@@ -11032,12 +11253,36 @@ case OpGroupNonUniform##op: \
SPIRV_CROSS_THROW("Invalid group operation."); \
break; \
}
#define MSL_GROUP_OP_CAST(op, msl_op, type) \
case OpGroupNonUniform##op: \
{ \
auto operation = static_cast<GroupOperation>(ops[3]); \
if (operation == GroupOperationReduce) \
emit_unary_func_op_cast(result_type, id, ops[4], "simd_" #msl_op, type, type); \
else if (operation == GroupOperationInclusiveScan) \
SPIRV_CROSS_THROW("Metal doesn't support InclusiveScan for OpGroupNonUniform" #op "."); \
else if (operation == GroupOperationExclusiveScan) \
SPIRV_CROSS_THROW("Metal doesn't support ExclusiveScan for OpGroupNonUniform" #op "."); \
else if (operation == GroupOperationClusteredReduce) \
{ \
/* Only cluster sizes of 4 are supported. */ \
uint32_t cluster_size = get<SPIRConstant>(ops[5]).scalar(); \
if (cluster_size != 4) \
SPIRV_CROSS_THROW("Metal only supports quad ClusteredReduce."); \
emit_unary_func_op_cast(result_type, id, ops[4], "quad_" #msl_op, type, type); \
} \
else \
SPIRV_CROSS_THROW("Invalid group operation."); \
break; \
}
MSL_GROUP_OP(FMin, min)
MSL_GROUP_OP(FMax, max)
MSL_GROUP_OP(SMin, min)
MSL_GROUP_OP(SMax, max)
MSL_GROUP_OP(UMin, min)
MSL_GROUP_OP(UMax, max)
MSL_GROUP_OP_CAST(SMin, min, int_type)
MSL_GROUP_OP_CAST(SMax, max, int_type)
MSL_GROUP_OP_CAST(UMin, min, uint_type)
MSL_GROUP_OP_CAST(UMax, max, uint_type)
MSL_GROUP_OP(BitwiseAnd, and)
MSL_GROUP_OP(BitwiseOr, or)
MSL_GROUP_OP(BitwiseXor, xor)
@@ -11045,6 +11290,8 @@ case OpGroupNonUniform##op: \
MSL_GROUP_OP(LogicalOr, or)
MSL_GROUP_OP(LogicalXor, xor)
// clang-format on
#undef MSL_GROUP_OP
#undef MSL_GROUP_OP_CAST
case OpGroupNonUniformQuadSwap:
{
@@ -11099,6 +11346,11 @@ string CompilerMSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in
}
}
bool CompilerMSL::emit_complex_bitcast(uint32_t, uint32_t, uint32_t)
{
return false;
}
// Returns an MSL string identifying the name of a SPIR-V builtin.
// Output builtins are qualified with the name of the stage out structure.
string CompilerMSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
@@ -11224,13 +11476,17 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage)
if (!msl_options.supports_msl_version(2, 0))
SPIRV_CROSS_THROW("ViewportIndex requires Metal 2.0.");
/* fallthrough */
case BuiltInFragDepth:
case BuiltInFragStencilRefEXT:
if ((builtin == BuiltInFragDepth && !msl_options.enable_frag_depth_builtin) ||
(builtin == BuiltInFragStencilRefEXT && !msl_options.enable_frag_stencil_ref_builtin))
break;
/* fallthrough */
case BuiltInPosition:
case BuiltInPointSize:
case BuiltInClipDistance:
case BuiltInCullDistance:
case BuiltInLayer:
case BuiltInFragDepth:
case BuiltInFragStencilRefEXT:
case BuiltInSampleMask:
if (get_execution_model() == ExecutionModelTessellationControl)
break;
@@ -11654,7 +11910,7 @@ uint32_t CompilerMSL::get_declared_type_matrix_stride_msl(const SPIRType &type,
// For packed matrices, we just use the size of the vector type.
// Otherwise, MatrixStride == alignment, which is the size of the underlying vector type.
if (packed)
return (type.width / 8) * (row_major ? type.columns : type.vecsize);
return (type.width / 8) * ((row_major && type.columns > 1) ? type.columns : type.vecsize);
else
return get_declared_type_alignment_msl(type, false, row_major);
}
@@ -11732,7 +11988,7 @@ uint32_t CompilerMSL::get_declared_type_size_msl(const SPIRType &type, bool is_p
uint32_t vecsize = type.vecsize;
uint32_t columns = type.columns;
if (row_major)
if (row_major && columns > 1)
swap(vecsize, columns);
if (vecsize == 3)
@@ -11793,7 +12049,7 @@ uint32_t CompilerMSL::get_declared_type_alignment_msl(const SPIRType &type, bool
else
{
// This is the general rule for MSL. Size == alignment.
uint32_t vecsize = row_major ? type.columns : type.vecsize;
uint32_t vecsize = (row_major && type.columns > 1) ? type.columns : type.vecsize;
return (type.width / 8) * (vecsize == 3 ? 4 : vecsize);
}
}
@@ -12349,7 +12605,7 @@ void CompilerMSL::bitcast_to_builtin_store(uint32_t target_id, std::string &expr
}
}
std::string CompilerMSL::to_initializer_expression(const SPIRVariable &var)
string CompilerMSL::to_initializer_expression(const SPIRVariable &var)
{
// We risk getting an array initializer here with MSL. If we have an array.
// FIXME: We cannot handle non-constant arrays being initialized.
@@ -12362,6 +12618,11 @@ std::string CompilerMSL::to_initializer_expression(const SPIRVariable &var)
return CompilerGLSL::to_initializer_expression(var);
}
string CompilerMSL::to_zero_initialized_expression(uint32_t)
{
return "{}";
}
bool CompilerMSL::descriptor_set_is_argument_buffer(uint32_t desc_set) const
{
if (!msl_options.argument_buffers)
@@ -12394,6 +12655,7 @@ void CompilerMSL::analyze_argument_buffers()
uint32_t plane;
};
SmallVector<Resource> resources_in_set[kMaxArgumentBuffers];
SmallVector<uint32_t> inline_block_vars;
bool set_needs_swizzle_buffer[kMaxArgumentBuffers] = {};
bool set_needs_buffer_sizes[kMaxArgumentBuffers] = {};
@@ -12426,6 +12688,7 @@ void CompilerMSL::analyze_argument_buffers()
}
}
uint32_t binding = get_decoration(var_id, DecorationBinding);
if (type.basetype == SPIRType::SampledImage)
{
add_resource_name(var_id);
@@ -12448,9 +12711,14 @@ void CompilerMSL::analyze_argument_buffers()
{ &var, to_sampler_expression(var_id), SPIRType::Sampler, sampler_resource_index, 0 });
}
}
else if (inline_uniform_blocks.count(SetBindingPair{ desc_set, binding }))
{
inline_block_vars.push_back(var_id);
}
else if (!constexpr_sampler)
{
// constexpr samplers are not declared as resources.
// Inline uniform blocks are always emitted at the end.
if (!msl_options.is_ios() || type.basetype != SPIRType::Image || type.image.sampled != 2)
{
add_resource_name(var_id);
@@ -12525,6 +12793,16 @@ void CompilerMSL::analyze_argument_buffers()
}
}
// Now add inline uniform blocks.
for (uint32_t var_id : inline_block_vars)
{
auto &var = get<SPIRVariable>(var_id);
uint32_t desc_set = get_decoration(var_id, DecorationDescriptorSet);
add_resource_name(var_id);
resources_in_set[desc_set].push_back(
{ &var, to_name(var_id), SPIRType::Struct, get_metal_resource_index(var, SPIRType::Struct), 0 });
}
for (uint32_t desc_set = 0; desc_set < kMaxArgumentBuffers; desc_set++)
{
auto &resources = resources_in_set[desc_set];
@@ -12622,6 +12900,12 @@ void CompilerMSL::analyze_argument_buffers()
buffer_type.member_types.push_back(var.basetype);
buffers_requiring_dynamic_offset[pair].second = var.self;
}
else if (inline_uniform_blocks.count(pair))
{
// Put the buffer block itself into the argument buffer.
buffer_type.member_types.push_back(get_variable_data_type_id(var));
set_qualified_name(var.self, join(to_name(buffer_variable_id), ".", mbr_name));
}
else
{
// Resources will be declared as pointers not references, so automatically dereference as appropriate.
@@ -12642,34 +12926,20 @@ void CompilerMSL::analyze_argument_buffers()
}
}
bool CompilerMSL::SetBindingPair::operator==(const SetBindingPair &other) const
void CompilerMSL::activate_argument_buffer_resources()
{
return desc_set == other.desc_set && binding == other.binding;
// For ABI compatibility, force-enable all resources which are part of argument buffers.
ir.for_each_typed_id<SPIRVariable>([&](uint32_t self, const SPIRVariable &) {
if (!has_decoration(self, DecorationDescriptorSet))
return;
uint32_t desc_set = get_decoration(self, DecorationDescriptorSet);
if (descriptor_set_is_argument_buffer(desc_set))
active_interface_variables.insert(self);
});
}
bool CompilerMSL::SetBindingPair::operator<(const SetBindingPair &other) const
bool CompilerMSL::using_builtin_array() const
{
return desc_set < other.desc_set || (desc_set == other.desc_set && binding < other.binding);
}
bool CompilerMSL::StageSetBinding::operator==(const StageSetBinding &other) const
{
return model == other.model && desc_set == other.desc_set && binding == other.binding;
}
size_t CompilerMSL::InternalHasher::operator()(const SetBindingPair &value) const
{
// Quality of hash doesn't really matter here.
auto hash_set = std::hash<uint32_t>()(value.desc_set);
auto hash_binding = std::hash<uint32_t>()(value.binding);
return (hash_set * 0x10001b31) ^ hash_binding;
}
size_t CompilerMSL::InternalHasher::operator()(const StageSetBinding &value) const
{
// Quality of hash doesn't really matter here.
auto hash_model = std::hash<uint32_t>()(value.model);
auto hash_set = std::hash<uint32_t>()(value.desc_set);
auto tmp_hash = (hash_model * 0x10001b31) ^ hash_set;
return (tmp_hash * 0x10001b31) ^ value.binding;
return msl_options.force_native_arrays || is_using_builtin_array;
}
+42 -27
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2019 The Brenwill Workshop Ltd.
* Copyright 2016-2020 The Brenwill Workshop Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -218,11 +218,13 @@ struct MSLConstexprSampler
// Special constant used in a MSLResourceBinding desc_set
// element to indicate the bindings for the push constants.
static const uint32_t kPushConstDescSet = ~(0u);
// Kinda deprecated. Just use ResourceBindingPushConstant{DescriptorSet,Binding} directly.
static const uint32_t kPushConstDescSet = ResourceBindingPushConstantDescriptorSet;
// Special constant used in a MSLResourceBinding binding
// element to indicate the bindings for the push constants.
static const uint32_t kPushConstBinding = 0;
// Kinda deprecated. Just use ResourceBindingPushConstant{DescriptorSet,Binding} directly.
static const uint32_t kPushConstBinding = ResourceBindingPushConstantBinding;
// Special constant used in a MSLResourceBinding binding
// element to indicate the buffer binding for swizzle buffers.
@@ -266,7 +268,10 @@ public:
uint32_t dynamic_offsets_buffer_index = 23;
uint32_t shader_input_wg_index = 0;
uint32_t device_index = 0;
uint32_t enable_frag_output_mask = 0xffffffff;
bool enable_point_size_builtin = true;
bool enable_frag_depth_builtin = true;
bool enable_frag_stencil_ref_builtin = true;
bool disable_rasterization = false;
bool capture_output_to_buffer = false;
bool swizzle_texture_samples = false;
@@ -305,6 +310,20 @@ public:
// Requires MSL 2.1, use the native support for texel buffers.
bool texture_buffer_native = false;
// Forces all resources which are part of an argument buffer to be considered active.
// This ensures ABI compatibility between shaders where some resources might be unused,
// and would otherwise declare a different IAB.
bool force_active_argument_buffer_resources = false;
// Forces the use of plain arrays, which works around certain driver bugs on certain versions
// of Intel Macbooks. See https://github.com/KhronosGroup/SPIRV-Cross/issues/1210.
// May reduce performance in scenarios where arrays are copied around as value-types.
bool force_native_arrays = false;
// If a shader writes clip distance, also emit user varyings which
// can be read in subsequent stages.
bool enable_clip_distance_user_varying = true;
bool is_ios()
{
return platform == iOS;
@@ -425,6 +444,13 @@ public:
// an offset taken from the dynamic offset buffer.
void add_dynamic_buffer(uint32_t desc_set, uint32_t binding, uint32_t index);
// desc_set and binding are the SPIR-V descriptor set and binding of a buffer resource
// in this shader. This function marks that resource as an inline uniform block
// (VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT). This function only has any effect if argument buffers
// are enabled. If so, the buffer block will be directly embedded into the argument
// buffer, instead of being referenced indirectly via pointer.
void add_inline_uniform_block(uint32_t desc_set, uint32_t binding);
// When using MSL argument buffers, we can force "classic" MSL 1.0 binding schemes for certain descriptor sets.
// This corresponds to VK_KHR_push_descriptor in Vulkan.
void add_discrete_descriptor_set(uint32_t desc_set);
@@ -440,7 +466,7 @@ public:
// Constexpr samplers are always assumed to be emitted.
// No specific MSLResourceBinding remapping is required for constexpr samplers as long as they are remapped
// by remap_constexpr_sampler(_by_binding).
bool is_msl_resource_binding_used(spv::ExecutionModel model, uint32_t set, uint32_t binding);
bool is_msl_resource_binding_used(spv::ExecutionModel model, uint32_t set, uint32_t binding) const;
// This must only be called after a successful call to CompilerMSL::compile().
// For a variable resource ID obtained through reflection API, report the automatically assigned resource index.
@@ -600,6 +626,7 @@ protected:
uint32_t grad_y, uint32_t lod, uint32_t coffset, uint32_t offset, uint32_t bias,
uint32_t comp, uint32_t sample, uint32_t minlod, bool *p_forward) override;
std::string to_initializer_expression(const SPIRVariable &var) override;
std::string to_zero_initialized_expression(uint32_t type_id) override;
std::string unpack_expression_type(std::string expr_str, const SPIRType &type, uint32_t physical_type_id,
bool is_packed, bool row_major) override;
@@ -608,6 +635,7 @@ protected:
bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const override;
std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type) override;
bool emit_complex_bitcast(uint32_t result_id, uint32_t id, uint32_t op0) override;
bool skip_argument(uint32_t id) const override;
std::string to_member_reference(uint32_t base, const SPIRType &type, uint32_t index, bool ptr_chain) override;
std::string to_qualifiers_glsl(uint32_t id) override;
@@ -786,28 +814,6 @@ protected:
std::set<std::string> typedef_lines;
SmallVector<uint32_t> vars_needing_early_declaration;
struct SetBindingPair
{
uint32_t desc_set;
uint32_t binding;
bool operator==(const SetBindingPair &other) const;
bool operator<(const SetBindingPair &other) const;
};
struct StageSetBinding
{
spv::ExecutionModel model;
uint32_t desc_set;
uint32_t binding;
bool operator==(const StageSetBinding &other) const;
};
struct InternalHasher
{
size_t operator()(const SetBindingPair &value) const;
size_t operator()(const StageSetBinding &value) const;
};
std::unordered_map<StageSetBinding, std::pair<MSLResourceBinding, bool>, InternalHasher> resource_bindings;
uint32_t next_metal_resource_index_buffer = 0;
@@ -835,7 +841,10 @@ protected:
bool has_sampled_images = false;
bool builtin_declaration = false; // Handle HLSL-style 0-based vertex/instance index.
bool use_builtin_array = false; // Force the use of C style array declaration.
bool is_using_builtin_array = false; // Force the use of C style array declaration.
bool using_builtin_array() const;
bool is_rasterization_disabled = false;
bool capture_output_to_buffer = false;
bool needs_swizzle_buffer_def = false;
@@ -869,6 +878,10 @@ protected:
// Must be ordered since array is in a specific order.
std::map<SetBindingPair, std::pair<uint32_t, uint32_t>> buffers_requiring_dynamic_offset;
SmallVector<uint32_t> disabled_frag_outputs;
std::unordered_set<SetBindingPair, InternalHasher> inline_uniform_blocks;
uint32_t argument_buffer_ids[kMaxArgumentBuffers];
uint32_t argument_buffer_discrete_mask = 0;
uint32_t argument_buffer_device_storage_mask = 0;
@@ -883,6 +896,8 @@ protected:
void add_spv_func_and_recompile(SPVFuncImpl spv_func);
void activate_argument_buffer_resources();
// OpcodeHandler that handles several MSL preprocessing operations.
struct OpCodePreprocessor : OpcodeHandler
{
+17 -55
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2019 Arm Limited
* Copyright 2018-2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -86,6 +86,11 @@ void Parser::parse()
SPIRV_CROSS_THROW("Invalid SPIRV format.");
uint32_t bound = s[3];
const uint32_t MaximumNumberOfIDs = 0x3fffff;
if (bound > MaximumNumberOfIDs)
SPIRV_CROSS_THROW("ID bound exceeds limit of 0x3fffff.\n");
ir.set_id_bounds(bound);
uint32_t offset = 5;
@@ -678,11 +683,19 @@ void Parser::parse(const Instruction &instruction)
break;
}
case OpTypeAccelerationStructureNV:
case OpTypeAccelerationStructureKHR:
{
uint32_t id = ops[0];
auto &type = set<SPIRType>(id);
type.basetype = SPIRType::AccelerationStructureNV;
type.basetype = SPIRType::AccelerationStructure;
break;
}
case OpTypeRayQueryProvisionalKHR:
{
uint32_t id = ops[0];
auto &type = set<SPIRType>(id);
type.basetype = SPIRType::RayQuery;
break;
}
@@ -703,15 +716,6 @@ void Parser::parse(const Instruction &instruction)
}
set<SPIRVariable>(id, type, storage, initializer);
// hlsl based shaders don't have those decorations. force them and then reset when reading/writing images
auto &ttype = get<SPIRType>(type);
if (ttype.basetype == SPIRType::BaseType::Image)
{
ir.set_decoration(id, DecorationNonWritable);
ir.set_decoration(id, DecorationNonReadable);
}
break;
}
@@ -775,7 +779,7 @@ void Parser::parse(const Instruction &instruction)
{
uint32_t id = ops[1];
uint32_t type = ops[0];
make_constant_null(id, type);
ir.make_constant_null(id, type, true);
break;
}
@@ -1140,46 +1144,4 @@ bool Parser::variable_storage_is_aliased(const SPIRVariable &v) const
return !is_restrict && (ssbo || image || counter);
}
void Parser::make_constant_null(uint32_t id, uint32_t type)
{
auto &constant_type = get<SPIRType>(type);
if (constant_type.pointer)
{
auto &constant = set<SPIRConstant>(id, type);
constant.make_null(constant_type);
}
else if (!constant_type.array.empty())
{
assert(constant_type.parent_type);
uint32_t parent_id = ir.increase_bound_by(1);
make_constant_null(parent_id, constant_type.parent_type);
if (!constant_type.array_size_literal.back())
SPIRV_CROSS_THROW("Array size of OpConstantNull must be a literal.");
SmallVector<uint32_t> elements(constant_type.array.back());
for (uint32_t i = 0; i < constant_type.array.back(); i++)
elements[i] = parent_id;
set<SPIRConstant>(id, type, elements.data(), uint32_t(elements.size()), false);
}
else if (!constant_type.member_types.empty())
{
uint32_t member_ids = ir.increase_bound_by(uint32_t(constant_type.member_types.size()));
SmallVector<uint32_t> elements(constant_type.member_types.size());
for (uint32_t i = 0; i < constant_type.member_types.size(); i++)
{
make_constant_null(member_ids + i, constant_type.member_types[i]);
elements[i] = member_ids + i;
}
set<SPIRConstant>(id, type, elements.data(), uint32_t(elements.size()), false);
}
else
{
auto &constant = set<SPIRConstant>(id, type);
constant.make_null(constant_type);
}
}
} // namespace SPIRV_CROSS_NAMESPACE
+1 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2019 Arm Limited
* Copyright 2018-2020 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -87,7 +87,6 @@ private:
bool types_are_logically_equivalent(const SPIRType &a, const SPIRType &b) const;
bool variable_storage_is_aliased(const SPIRVariable &v) const;
void make_constant_null(uint32_t id, uint32_t type);
};
} // namespace SPIRV_CROSS_NAMESPACE
+18 -5
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2019 Bradley Austin Davis
* Copyright 2018-2020 Bradley Austin Davis
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -358,15 +358,16 @@ void CompilerReflection::emit_type_array(const SPIRType &type)
for (const auto &value : type.array)
json_stream->emit_json_array_value(value);
json_stream->end_json_array();
json_stream->emit_json_key_array("array_size_is_literal");
for (const auto &value : type.array_size_literal)
json_stream->emit_json_array_value(value);
json_stream->end_json_array();
}
}
void CompilerReflection::emit_type_member_qualifiers(const SPIRType &type, uint32_t index)
{
auto flags = combined_decoration_for_member(type, index);
if (flags.get(DecorationRowMajor))
json_stream->emit_json_key_value("row_major", true);
auto &membertype = get<SPIRType>(type.member_types[index]);
emit_type_array(membertype);
auto &memb = ir.meta[type.self].members;
@@ -377,6 +378,16 @@ void CompilerReflection::emit_type_member_qualifiers(const SPIRType &type, uint3
json_stream->emit_json_key_value("location", dec.location);
if (dec.decoration_flags.get(DecorationOffset))
json_stream->emit_json_key_value("offset", dec.offset);
// Array stride is a property of the array type, not the struct.
if (has_decoration(type.member_types[index], DecorationArrayStride))
json_stream->emit_json_key_value("array_stride",
get_decoration(type.member_types[index], DecorationArrayStride));
if (dec.decoration_flags.get(DecorationMatrixStride))
json_stream->emit_json_key_value("matrix_stride", dec.matrix_stride);
if (dec.decoration_flags.get(DecorationRowMajor))
json_stream->emit_json_key_value("row_major", true);
}
}
@@ -590,8 +601,10 @@ void CompilerReflection::emit_specialization_constants()
auto &c = get<SPIRConstant>(spec_const.id);
auto type = get<SPIRType>(c.constant_type);
json_stream->begin_json_object();
json_stream->emit_json_key_value("name", get_name(spec_const.id));
json_stream->emit_json_key_value("id", spec_const.constant_id);
json_stream->emit_json_key_value("type", type_to_glsl(type));
json_stream->emit_json_key_value("variable_id", spec_const.id);
switch (type.basetype)
{
case SPIRType::UInt:
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2019 Bradley Austin Davis
* Copyright 2018-2020 Bradley Austin Davis
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.