mirror of
https://github.com/love2d/love.git
synced 2026-08-16 08:11:02 +02:00
metal: update spirv-cross
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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,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,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,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.
|
||||
|
||||
@@ -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,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 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
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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,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
|
||||
|
||||
|
||||
@@ -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,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.
|
||||
|
||||
Reference in New Issue
Block a user