mirror of
				https://github.com/godotengine/godot.git
				synced 2025-11-04 07:31:16 +00:00 
			
		
		
		
	* Shader compilation is now cached. Subsequent loads take less than a millisecond. * Improved game, editor and project manager startup time. * Editor uses .godot/shader_cache to store shaders. * Game uses user://shader_cache * Project manager uses $config_dir/shader_cache * Options to tweak shader caching in project settings. * Editor path configuration moved from EditorSettings to new class, EditorPaths, so it can be available early on (before shaders are compiled). * Reworked ShaderCompilerRD to ensure deterministic shader code creation (else shader may change and cache will be invalidated). * Added shader compression with SMOLV: https://github.com/aras-p/smol-v
		
			
				
	
	
		
			2108 lines
		
	
	
	
		
			60 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			2108 lines
		
	
	
	
		
			60 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// smol-v - public domain - https://github.com/aras-p/smol-v
 | 
						|
// authored 2016-2020 by Aras Pranckevicius
 | 
						|
// no warranty implied; use at your own risk
 | 
						|
// See end of file for license information.
 | 
						|
 | 
						|
#include "smolv.h"
 | 
						|
#include <stdint.h>
 | 
						|
#include <vector>
 | 
						|
#include <algorithm>
 | 
						|
#include <cstdio>
 | 
						|
#include <cstring>
 | 
						|
 | 
						|
#if !defined(_MSC_VER) && __cplusplus < 201103L
 | 
						|
#define static_assert(x,y)
 | 
						|
#endif
 | 
						|
 | 
						|
#define _SMOLV_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
 | 
						|
 | 
						|
// --------------------------------------------------------------------------------------------
 | 
						|
// Metadata about known SPIR-V operations
 | 
						|
 | 
						|
enum SpvOp
 | 
						|
{
 | 
						|
	SpvOpNop = 0,
 | 
						|
	SpvOpUndef = 1,
 | 
						|
	SpvOpSourceContinued = 2,
 | 
						|
	SpvOpSource = 3,
 | 
						|
	SpvOpSourceExtension = 4,
 | 
						|
	SpvOpName = 5,
 | 
						|
	SpvOpMemberName = 6,
 | 
						|
	SpvOpString = 7,
 | 
						|
	SpvOpLine = 8,
 | 
						|
	SpvOpExtension = 10,
 | 
						|
	SpvOpExtInstImport = 11,
 | 
						|
	SpvOpExtInst = 12,
 | 
						|
	SpvOpVectorShuffleCompact = 13, // not in SPIR-V, added for SMOL-V!
 | 
						|
	SpvOpMemoryModel = 14,
 | 
						|
	SpvOpEntryPoint = 15,
 | 
						|
	SpvOpExecutionMode = 16,
 | 
						|
	SpvOpCapability = 17,
 | 
						|
	SpvOpTypeVoid = 19,
 | 
						|
	SpvOpTypeBool = 20,
 | 
						|
	SpvOpTypeInt = 21,
 | 
						|
	SpvOpTypeFloat = 22,
 | 
						|
	SpvOpTypeVector = 23,
 | 
						|
	SpvOpTypeMatrix = 24,
 | 
						|
	SpvOpTypeImage = 25,
 | 
						|
	SpvOpTypeSampler = 26,
 | 
						|
	SpvOpTypeSampledImage = 27,
 | 
						|
	SpvOpTypeArray = 28,
 | 
						|
	SpvOpTypeRuntimeArray = 29,
 | 
						|
	SpvOpTypeStruct = 30,
 | 
						|
	SpvOpTypeOpaque = 31,
 | 
						|
	SpvOpTypePointer = 32,
 | 
						|
	SpvOpTypeFunction = 33,
 | 
						|
	SpvOpTypeEvent = 34,
 | 
						|
	SpvOpTypeDeviceEvent = 35,
 | 
						|
	SpvOpTypeReserveId = 36,
 | 
						|
	SpvOpTypeQueue = 37,
 | 
						|
	SpvOpTypePipe = 38,
 | 
						|
	SpvOpTypeForwardPointer = 39,
 | 
						|
	SpvOpConstantTrue = 41,
 | 
						|
	SpvOpConstantFalse = 42,
 | 
						|
	SpvOpConstant = 43,
 | 
						|
	SpvOpConstantComposite = 44,
 | 
						|
	SpvOpConstantSampler = 45,
 | 
						|
	SpvOpConstantNull = 46,
 | 
						|
	SpvOpSpecConstantTrue = 48,
 | 
						|
	SpvOpSpecConstantFalse = 49,
 | 
						|
	SpvOpSpecConstant = 50,
 | 
						|
	SpvOpSpecConstantComposite = 51,
 | 
						|
	SpvOpSpecConstantOp = 52,
 | 
						|
	SpvOpFunction = 54,
 | 
						|
	SpvOpFunctionParameter = 55,
 | 
						|
	SpvOpFunctionEnd = 56,
 | 
						|
	SpvOpFunctionCall = 57,
 | 
						|
	SpvOpVariable = 59,
 | 
						|
	SpvOpImageTexelPointer = 60,
 | 
						|
	SpvOpLoad = 61,
 | 
						|
	SpvOpStore = 62,
 | 
						|
	SpvOpCopyMemory = 63,
 | 
						|
	SpvOpCopyMemorySized = 64,
 | 
						|
	SpvOpAccessChain = 65,
 | 
						|
	SpvOpInBoundsAccessChain = 66,
 | 
						|
	SpvOpPtrAccessChain = 67,
 | 
						|
	SpvOpArrayLength = 68,
 | 
						|
	SpvOpGenericPtrMemSemantics = 69,
 | 
						|
	SpvOpInBoundsPtrAccessChain = 70,
 | 
						|
	SpvOpDecorate = 71,
 | 
						|
	SpvOpMemberDecorate = 72,
 | 
						|
	SpvOpDecorationGroup = 73,
 | 
						|
	SpvOpGroupDecorate = 74,
 | 
						|
	SpvOpGroupMemberDecorate = 75,
 | 
						|
	SpvOpVectorExtractDynamic = 77,
 | 
						|
	SpvOpVectorInsertDynamic = 78,
 | 
						|
	SpvOpVectorShuffle = 79,
 | 
						|
	SpvOpCompositeConstruct = 80,
 | 
						|
	SpvOpCompositeExtract = 81,
 | 
						|
	SpvOpCompositeInsert = 82,
 | 
						|
	SpvOpCopyObject = 83,
 | 
						|
	SpvOpTranspose = 84,
 | 
						|
	SpvOpSampledImage = 86,
 | 
						|
	SpvOpImageSampleImplicitLod = 87,
 | 
						|
	SpvOpImageSampleExplicitLod = 88,
 | 
						|
	SpvOpImageSampleDrefImplicitLod = 89,
 | 
						|
	SpvOpImageSampleDrefExplicitLod = 90,
 | 
						|
	SpvOpImageSampleProjImplicitLod = 91,
 | 
						|
	SpvOpImageSampleProjExplicitLod = 92,
 | 
						|
	SpvOpImageSampleProjDrefImplicitLod = 93,
 | 
						|
	SpvOpImageSampleProjDrefExplicitLod = 94,
 | 
						|
	SpvOpImageFetch = 95,
 | 
						|
	SpvOpImageGather = 96,
 | 
						|
	SpvOpImageDrefGather = 97,
 | 
						|
	SpvOpImageRead = 98,
 | 
						|
	SpvOpImageWrite = 99,
 | 
						|
	SpvOpImage = 100,
 | 
						|
	SpvOpImageQueryFormat = 101,
 | 
						|
	SpvOpImageQueryOrder = 102,
 | 
						|
	SpvOpImageQuerySizeLod = 103,
 | 
						|
	SpvOpImageQuerySize = 104,
 | 
						|
	SpvOpImageQueryLod = 105,
 | 
						|
	SpvOpImageQueryLevels = 106,
 | 
						|
	SpvOpImageQuerySamples = 107,
 | 
						|
	SpvOpConvertFToU = 109,
 | 
						|
	SpvOpConvertFToS = 110,
 | 
						|
	SpvOpConvertSToF = 111,
 | 
						|
	SpvOpConvertUToF = 112,
 | 
						|
	SpvOpUConvert = 113,
 | 
						|
	SpvOpSConvert = 114,
 | 
						|
	SpvOpFConvert = 115,
 | 
						|
	SpvOpQuantizeToF16 = 116,
 | 
						|
	SpvOpConvertPtrToU = 117,
 | 
						|
	SpvOpSatConvertSToU = 118,
 | 
						|
	SpvOpSatConvertUToS = 119,
 | 
						|
	SpvOpConvertUToPtr = 120,
 | 
						|
	SpvOpPtrCastToGeneric = 121,
 | 
						|
	SpvOpGenericCastToPtr = 122,
 | 
						|
	SpvOpGenericCastToPtrExplicit = 123,
 | 
						|
	SpvOpBitcast = 124,
 | 
						|
	SpvOpSNegate = 126,
 | 
						|
	SpvOpFNegate = 127,
 | 
						|
	SpvOpIAdd = 128,
 | 
						|
	SpvOpFAdd = 129,
 | 
						|
	SpvOpISub = 130,
 | 
						|
	SpvOpFSub = 131,
 | 
						|
	SpvOpIMul = 132,
 | 
						|
	SpvOpFMul = 133,
 | 
						|
	SpvOpUDiv = 134,
 | 
						|
	SpvOpSDiv = 135,
 | 
						|
	SpvOpFDiv = 136,
 | 
						|
	SpvOpUMod = 137,
 | 
						|
	SpvOpSRem = 138,
 | 
						|
	SpvOpSMod = 139,
 | 
						|
	SpvOpFRem = 140,
 | 
						|
	SpvOpFMod = 141,
 | 
						|
	SpvOpVectorTimesScalar = 142,
 | 
						|
	SpvOpMatrixTimesScalar = 143,
 | 
						|
	SpvOpVectorTimesMatrix = 144,
 | 
						|
	SpvOpMatrixTimesVector = 145,
 | 
						|
	SpvOpMatrixTimesMatrix = 146,
 | 
						|
	SpvOpOuterProduct = 147,
 | 
						|
	SpvOpDot = 148,
 | 
						|
	SpvOpIAddCarry = 149,
 | 
						|
	SpvOpISubBorrow = 150,
 | 
						|
	SpvOpUMulExtended = 151,
 | 
						|
	SpvOpSMulExtended = 152,
 | 
						|
	SpvOpAny = 154,
 | 
						|
	SpvOpAll = 155,
 | 
						|
	SpvOpIsNan = 156,
 | 
						|
	SpvOpIsInf = 157,
 | 
						|
	SpvOpIsFinite = 158,
 | 
						|
	SpvOpIsNormal = 159,
 | 
						|
	SpvOpSignBitSet = 160,
 | 
						|
	SpvOpLessOrGreater = 161,
 | 
						|
	SpvOpOrdered = 162,
 | 
						|
	SpvOpUnordered = 163,
 | 
						|
	SpvOpLogicalEqual = 164,
 | 
						|
	SpvOpLogicalNotEqual = 165,
 | 
						|
	SpvOpLogicalOr = 166,
 | 
						|
	SpvOpLogicalAnd = 167,
 | 
						|
	SpvOpLogicalNot = 168,
 | 
						|
	SpvOpSelect = 169,
 | 
						|
	SpvOpIEqual = 170,
 | 
						|
	SpvOpINotEqual = 171,
 | 
						|
	SpvOpUGreaterThan = 172,
 | 
						|
	SpvOpSGreaterThan = 173,
 | 
						|
	SpvOpUGreaterThanEqual = 174,
 | 
						|
	SpvOpSGreaterThanEqual = 175,
 | 
						|
	SpvOpULessThan = 176,
 | 
						|
	SpvOpSLessThan = 177,
 | 
						|
	SpvOpULessThanEqual = 178,
 | 
						|
	SpvOpSLessThanEqual = 179,
 | 
						|
	SpvOpFOrdEqual = 180,
 | 
						|
	SpvOpFUnordEqual = 181,
 | 
						|
	SpvOpFOrdNotEqual = 182,
 | 
						|
	SpvOpFUnordNotEqual = 183,
 | 
						|
	SpvOpFOrdLessThan = 184,
 | 
						|
	SpvOpFUnordLessThan = 185,
 | 
						|
	SpvOpFOrdGreaterThan = 186,
 | 
						|
	SpvOpFUnordGreaterThan = 187,
 | 
						|
	SpvOpFOrdLessThanEqual = 188,
 | 
						|
	SpvOpFUnordLessThanEqual = 189,
 | 
						|
	SpvOpFOrdGreaterThanEqual = 190,
 | 
						|
	SpvOpFUnordGreaterThanEqual = 191,
 | 
						|
	SpvOpShiftRightLogical = 194,
 | 
						|
	SpvOpShiftRightArithmetic = 195,
 | 
						|
	SpvOpShiftLeftLogical = 196,
 | 
						|
	SpvOpBitwiseOr = 197,
 | 
						|
	SpvOpBitwiseXor = 198,
 | 
						|
	SpvOpBitwiseAnd = 199,
 | 
						|
	SpvOpNot = 200,
 | 
						|
	SpvOpBitFieldInsert = 201,
 | 
						|
	SpvOpBitFieldSExtract = 202,
 | 
						|
	SpvOpBitFieldUExtract = 203,
 | 
						|
	SpvOpBitReverse = 204,
 | 
						|
	SpvOpBitCount = 205,
 | 
						|
	SpvOpDPdx = 207,
 | 
						|
	SpvOpDPdy = 208,
 | 
						|
	SpvOpFwidth = 209,
 | 
						|
	SpvOpDPdxFine = 210,
 | 
						|
	SpvOpDPdyFine = 211,
 | 
						|
	SpvOpFwidthFine = 212,
 | 
						|
	SpvOpDPdxCoarse = 213,
 | 
						|
	SpvOpDPdyCoarse = 214,
 | 
						|
	SpvOpFwidthCoarse = 215,
 | 
						|
	SpvOpEmitVertex = 218,
 | 
						|
	SpvOpEndPrimitive = 219,
 | 
						|
	SpvOpEmitStreamVertex = 220,
 | 
						|
	SpvOpEndStreamPrimitive = 221,
 | 
						|
	SpvOpControlBarrier = 224,
 | 
						|
	SpvOpMemoryBarrier = 225,
 | 
						|
	SpvOpAtomicLoad = 227,
 | 
						|
	SpvOpAtomicStore = 228,
 | 
						|
	SpvOpAtomicExchange = 229,
 | 
						|
	SpvOpAtomicCompareExchange = 230,
 | 
						|
	SpvOpAtomicCompareExchangeWeak = 231,
 | 
						|
	SpvOpAtomicIIncrement = 232,
 | 
						|
	SpvOpAtomicIDecrement = 233,
 | 
						|
	SpvOpAtomicIAdd = 234,
 | 
						|
	SpvOpAtomicISub = 235,
 | 
						|
	SpvOpAtomicSMin = 236,
 | 
						|
	SpvOpAtomicUMin = 237,
 | 
						|
	SpvOpAtomicSMax = 238,
 | 
						|
	SpvOpAtomicUMax = 239,
 | 
						|
	SpvOpAtomicAnd = 240,
 | 
						|
	SpvOpAtomicOr = 241,
 | 
						|
	SpvOpAtomicXor = 242,
 | 
						|
	SpvOpPhi = 245,
 | 
						|
	SpvOpLoopMerge = 246,
 | 
						|
	SpvOpSelectionMerge = 247,
 | 
						|
	SpvOpLabel = 248,
 | 
						|
	SpvOpBranch = 249,
 | 
						|
	SpvOpBranchConditional = 250,
 | 
						|
	SpvOpSwitch = 251,
 | 
						|
	SpvOpKill = 252,
 | 
						|
	SpvOpReturn = 253,
 | 
						|
	SpvOpReturnValue = 254,
 | 
						|
	SpvOpUnreachable = 255,
 | 
						|
	SpvOpLifetimeStart = 256,
 | 
						|
	SpvOpLifetimeStop = 257,
 | 
						|
	SpvOpGroupAsyncCopy = 259,
 | 
						|
	SpvOpGroupWaitEvents = 260,
 | 
						|
	SpvOpGroupAll = 261,
 | 
						|
	SpvOpGroupAny = 262,
 | 
						|
	SpvOpGroupBroadcast = 263,
 | 
						|
	SpvOpGroupIAdd = 264,
 | 
						|
	SpvOpGroupFAdd = 265,
 | 
						|
	SpvOpGroupFMin = 266,
 | 
						|
	SpvOpGroupUMin = 267,
 | 
						|
	SpvOpGroupSMin = 268,
 | 
						|
	SpvOpGroupFMax = 269,
 | 
						|
	SpvOpGroupUMax = 270,
 | 
						|
	SpvOpGroupSMax = 271,
 | 
						|
	SpvOpReadPipe = 274,
 | 
						|
	SpvOpWritePipe = 275,
 | 
						|
	SpvOpReservedReadPipe = 276,
 | 
						|
	SpvOpReservedWritePipe = 277,
 | 
						|
	SpvOpReserveReadPipePackets = 278,
 | 
						|
	SpvOpReserveWritePipePackets = 279,
 | 
						|
	SpvOpCommitReadPipe = 280,
 | 
						|
	SpvOpCommitWritePipe = 281,
 | 
						|
	SpvOpIsValidReserveId = 282,
 | 
						|
	SpvOpGetNumPipePackets = 283,
 | 
						|
	SpvOpGetMaxPipePackets = 284,
 | 
						|
	SpvOpGroupReserveReadPipePackets = 285,
 | 
						|
	SpvOpGroupReserveWritePipePackets = 286,
 | 
						|
	SpvOpGroupCommitReadPipe = 287,
 | 
						|
	SpvOpGroupCommitWritePipe = 288,
 | 
						|
	SpvOpEnqueueMarker = 291,
 | 
						|
	SpvOpEnqueueKernel = 292,
 | 
						|
	SpvOpGetKernelNDrangeSubGroupCount = 293,
 | 
						|
	SpvOpGetKernelNDrangeMaxSubGroupSize = 294,
 | 
						|
	SpvOpGetKernelWorkGroupSize = 295,
 | 
						|
	SpvOpGetKernelPreferredWorkGroupSizeMultiple = 296,
 | 
						|
	SpvOpRetainEvent = 297,
 | 
						|
	SpvOpReleaseEvent = 298,
 | 
						|
	SpvOpCreateUserEvent = 299,
 | 
						|
	SpvOpIsValidEvent = 300,
 | 
						|
	SpvOpSetUserEventStatus = 301,
 | 
						|
	SpvOpCaptureEventProfilingInfo = 302,
 | 
						|
	SpvOpGetDefaultQueue = 303,
 | 
						|
	SpvOpBuildNDRange = 304,
 | 
						|
	SpvOpImageSparseSampleImplicitLod = 305,
 | 
						|
	SpvOpImageSparseSampleExplicitLod = 306,
 | 
						|
	SpvOpImageSparseSampleDrefImplicitLod = 307,
 | 
						|
	SpvOpImageSparseSampleDrefExplicitLod = 308,
 | 
						|
	SpvOpImageSparseSampleProjImplicitLod = 309,
 | 
						|
	SpvOpImageSparseSampleProjExplicitLod = 310,
 | 
						|
	SpvOpImageSparseSampleProjDrefImplicitLod = 311,
 | 
						|
	SpvOpImageSparseSampleProjDrefExplicitLod = 312,
 | 
						|
	SpvOpImageSparseFetch = 313,
 | 
						|
	SpvOpImageSparseGather = 314,
 | 
						|
	SpvOpImageSparseDrefGather = 315,
 | 
						|
	SpvOpImageSparseTexelsResident = 316,
 | 
						|
	SpvOpNoLine = 317,
 | 
						|
	SpvOpAtomicFlagTestAndSet = 318,
 | 
						|
	SpvOpAtomicFlagClear = 319,
 | 
						|
	SpvOpImageSparseRead = 320,
 | 
						|
	SpvOpSizeOf = 321,
 | 
						|
	SpvOpTypePipeStorage = 322,
 | 
						|
	SpvOpConstantPipeStorage = 323,
 | 
						|
	SpvOpCreatePipeFromPipeStorage = 324,
 | 
						|
	SpvOpGetKernelLocalSizeForSubgroupCount = 325,
 | 
						|
	SpvOpGetKernelMaxNumSubgroups = 326,
 | 
						|
	SpvOpTypeNamedBarrier = 327,
 | 
						|
	SpvOpNamedBarrierInitialize = 328,
 | 
						|
	SpvOpMemoryNamedBarrier = 329,
 | 
						|
	SpvOpModuleProcessed = 330,
 | 
						|
	SpvOpExecutionModeId = 331,
 | 
						|
	SpvOpDecorateId = 332,
 | 
						|
	SpvOpGroupNonUniformElect = 333,
 | 
						|
	SpvOpGroupNonUniformAll = 334,
 | 
						|
	SpvOpGroupNonUniformAny = 335,
 | 
						|
	SpvOpGroupNonUniformAllEqual = 336,
 | 
						|
	SpvOpGroupNonUniformBroadcast = 337,
 | 
						|
	SpvOpGroupNonUniformBroadcastFirst = 338,
 | 
						|
	SpvOpGroupNonUniformBallot = 339,
 | 
						|
	SpvOpGroupNonUniformInverseBallot = 340,
 | 
						|
	SpvOpGroupNonUniformBallotBitExtract = 341,
 | 
						|
	SpvOpGroupNonUniformBallotBitCount = 342,
 | 
						|
	SpvOpGroupNonUniformBallotFindLSB = 343,
 | 
						|
	SpvOpGroupNonUniformBallotFindMSB = 344,
 | 
						|
	SpvOpGroupNonUniformShuffle = 345,
 | 
						|
	SpvOpGroupNonUniformShuffleXor = 346,
 | 
						|
	SpvOpGroupNonUniformShuffleUp = 347,
 | 
						|
	SpvOpGroupNonUniformShuffleDown = 348,
 | 
						|
	SpvOpGroupNonUniformIAdd = 349,
 | 
						|
	SpvOpGroupNonUniformFAdd = 350,
 | 
						|
	SpvOpGroupNonUniformIMul = 351,
 | 
						|
	SpvOpGroupNonUniformFMul = 352,
 | 
						|
	SpvOpGroupNonUniformSMin = 353,
 | 
						|
	SpvOpGroupNonUniformUMin = 354,
 | 
						|
	SpvOpGroupNonUniformFMin = 355,
 | 
						|
	SpvOpGroupNonUniformSMax = 356,
 | 
						|
	SpvOpGroupNonUniformUMax = 357,
 | 
						|
	SpvOpGroupNonUniformFMax = 358,
 | 
						|
	SpvOpGroupNonUniformBitwiseAnd = 359,
 | 
						|
	SpvOpGroupNonUniformBitwiseOr = 360,
 | 
						|
	SpvOpGroupNonUniformBitwiseXor = 361,
 | 
						|
	SpvOpGroupNonUniformLogicalAnd = 362,
 | 
						|
	SpvOpGroupNonUniformLogicalOr = 363,
 | 
						|
	SpvOpGroupNonUniformLogicalXor = 364,
 | 
						|
	SpvOpGroupNonUniformQuadBroadcast = 365,
 | 
						|
	SpvOpGroupNonUniformQuadSwap = 366,
 | 
						|
};
 | 
						|
static const int kKnownOpsCount = SpvOpGroupNonUniformQuadSwap+1;
 | 
						|
 | 
						|
 | 
						|
static const char* kSpirvOpNames[] =
 | 
						|
{
 | 
						|
	"Nop",
 | 
						|
	"Undef",
 | 
						|
	"SourceContinued",
 | 
						|
	"Source",
 | 
						|
	"SourceExtension",
 | 
						|
	"Name",
 | 
						|
	"MemberName",
 | 
						|
	"String",
 | 
						|
	"Line",
 | 
						|
	"#9",
 | 
						|
	"Extension",
 | 
						|
	"ExtInstImport",
 | 
						|
	"ExtInst",
 | 
						|
	"VectorShuffleCompact",
 | 
						|
	"MemoryModel",
 | 
						|
	"EntryPoint",
 | 
						|
	"ExecutionMode",
 | 
						|
	"Capability",
 | 
						|
	"#18",
 | 
						|
	"TypeVoid",
 | 
						|
	"TypeBool",
 | 
						|
	"TypeInt",
 | 
						|
	"TypeFloat",
 | 
						|
	"TypeVector",
 | 
						|
	"TypeMatrix",
 | 
						|
	"TypeImage",
 | 
						|
	"TypeSampler",
 | 
						|
	"TypeSampledImage",
 | 
						|
	"TypeArray",
 | 
						|
	"TypeRuntimeArray",
 | 
						|
	"TypeStruct",
 | 
						|
	"TypeOpaque",
 | 
						|
	"TypePointer",
 | 
						|
	"TypeFunction",
 | 
						|
	"TypeEvent",
 | 
						|
	"TypeDeviceEvent",
 | 
						|
	"TypeReserveId",
 | 
						|
	"TypeQueue",
 | 
						|
	"TypePipe",
 | 
						|
	"TypeForwardPointer",
 | 
						|
	"#40",
 | 
						|
	"ConstantTrue",
 | 
						|
	"ConstantFalse",
 | 
						|
	"Constant",
 | 
						|
	"ConstantComposite",
 | 
						|
	"ConstantSampler",
 | 
						|
	"ConstantNull",
 | 
						|
	"#47",
 | 
						|
	"SpecConstantTrue",
 | 
						|
	"SpecConstantFalse",
 | 
						|
	"SpecConstant",
 | 
						|
	"SpecConstantComposite",
 | 
						|
	"SpecConstantOp",
 | 
						|
	"#53",
 | 
						|
	"Function",
 | 
						|
	"FunctionParameter",
 | 
						|
	"FunctionEnd",
 | 
						|
	"FunctionCall",
 | 
						|
	"#58",
 | 
						|
	"Variable",
 | 
						|
	"ImageTexelPointer",
 | 
						|
	"Load",
 | 
						|
	"Store",
 | 
						|
	"CopyMemory",
 | 
						|
	"CopyMemorySized",
 | 
						|
	"AccessChain",
 | 
						|
	"InBoundsAccessChain",
 | 
						|
	"PtrAccessChain",
 | 
						|
	"ArrayLength",
 | 
						|
	"GenericPtrMemSemantics",
 | 
						|
	"InBoundsPtrAccessChain",
 | 
						|
	"Decorate",
 | 
						|
	"MemberDecorate",
 | 
						|
	"DecorationGroup",
 | 
						|
	"GroupDecorate",
 | 
						|
	"GroupMemberDecorate",
 | 
						|
	"#76",
 | 
						|
	"VectorExtractDynamic",
 | 
						|
	"VectorInsertDynamic",
 | 
						|
	"VectorShuffle",
 | 
						|
	"CompositeConstruct",
 | 
						|
	"CompositeExtract",
 | 
						|
	"CompositeInsert",
 | 
						|
	"CopyObject",
 | 
						|
	"Transpose",
 | 
						|
	"#85",
 | 
						|
	"SampledImage",
 | 
						|
	"ImageSampleImplicitLod",
 | 
						|
	"ImageSampleExplicitLod",
 | 
						|
	"ImageSampleDrefImplicitLod",
 | 
						|
	"ImageSampleDrefExplicitLod",
 | 
						|
	"ImageSampleProjImplicitLod",
 | 
						|
	"ImageSampleProjExplicitLod",
 | 
						|
	"ImageSampleProjDrefImplicitLod",
 | 
						|
	"ImageSampleProjDrefExplicitLod",
 | 
						|
	"ImageFetch",
 | 
						|
	"ImageGather",
 | 
						|
	"ImageDrefGather",
 | 
						|
	"ImageRead",
 | 
						|
	"ImageWrite",
 | 
						|
	"Image",
 | 
						|
	"ImageQueryFormat",
 | 
						|
	"ImageQueryOrder",
 | 
						|
	"ImageQuerySizeLod",
 | 
						|
	"ImageQuerySize",
 | 
						|
	"ImageQueryLod",
 | 
						|
	"ImageQueryLevels",
 | 
						|
	"ImageQuerySamples",
 | 
						|
	"#108",
 | 
						|
	"ConvertFToU",
 | 
						|
	"ConvertFToS",
 | 
						|
	"ConvertSToF",
 | 
						|
	"ConvertUToF",
 | 
						|
	"UConvert",
 | 
						|
	"SConvert",
 | 
						|
	"FConvert",
 | 
						|
	"QuantizeToF16",
 | 
						|
	"ConvertPtrToU",
 | 
						|
	"SatConvertSToU",
 | 
						|
	"SatConvertUToS",
 | 
						|
	"ConvertUToPtr",
 | 
						|
	"PtrCastToGeneric",
 | 
						|
	"GenericCastToPtr",
 | 
						|
	"GenericCastToPtrExplicit",
 | 
						|
	"Bitcast",
 | 
						|
	"#125",
 | 
						|
	"SNegate",
 | 
						|
	"FNegate",
 | 
						|
	"IAdd",
 | 
						|
	"FAdd",
 | 
						|
	"ISub",
 | 
						|
	"FSub",
 | 
						|
	"IMul",
 | 
						|
	"FMul",
 | 
						|
	"UDiv",
 | 
						|
	"SDiv",
 | 
						|
	"FDiv",
 | 
						|
	"UMod",
 | 
						|
	"SRem",
 | 
						|
	"SMod",
 | 
						|
	"FRem",
 | 
						|
	"FMod",
 | 
						|
	"VectorTimesScalar",
 | 
						|
	"MatrixTimesScalar",
 | 
						|
	"VectorTimesMatrix",
 | 
						|
	"MatrixTimesVector",
 | 
						|
	"MatrixTimesMatrix",
 | 
						|
	"OuterProduct",
 | 
						|
	"Dot",
 | 
						|
	"IAddCarry",
 | 
						|
	"ISubBorrow",
 | 
						|
	"UMulExtended",
 | 
						|
	"SMulExtended",
 | 
						|
	"#153",
 | 
						|
	"Any",
 | 
						|
	"All",
 | 
						|
	"IsNan",
 | 
						|
	"IsInf",
 | 
						|
	"IsFinite",
 | 
						|
	"IsNormal",
 | 
						|
	"SignBitSet",
 | 
						|
	"LessOrGreater",
 | 
						|
	"Ordered",
 | 
						|
	"Unordered",
 | 
						|
	"LogicalEqual",
 | 
						|
	"LogicalNotEqual",
 | 
						|
	"LogicalOr",
 | 
						|
	"LogicalAnd",
 | 
						|
	"LogicalNot",
 | 
						|
	"Select",
 | 
						|
	"IEqual",
 | 
						|
	"INotEqual",
 | 
						|
	"UGreaterThan",
 | 
						|
	"SGreaterThan",
 | 
						|
	"UGreaterThanEqual",
 | 
						|
	"SGreaterThanEqual",
 | 
						|
	"ULessThan",
 | 
						|
	"SLessThan",
 | 
						|
	"ULessThanEqual",
 | 
						|
	"SLessThanEqual",
 | 
						|
	"FOrdEqual",
 | 
						|
	"FUnordEqual",
 | 
						|
	"FOrdNotEqual",
 | 
						|
	"FUnordNotEqual",
 | 
						|
	"FOrdLessThan",
 | 
						|
	"FUnordLessThan",
 | 
						|
	"FOrdGreaterThan",
 | 
						|
	"FUnordGreaterThan",
 | 
						|
	"FOrdLessThanEqual",
 | 
						|
	"FUnordLessThanEqual",
 | 
						|
	"FOrdGreaterThanEqual",
 | 
						|
	"FUnordGreaterThanEqual",
 | 
						|
	"#192",
 | 
						|
	"#193",
 | 
						|
	"ShiftRightLogical",
 | 
						|
	"ShiftRightArithmetic",
 | 
						|
	"ShiftLeftLogical",
 | 
						|
	"BitwiseOr",
 | 
						|
	"BitwiseXor",
 | 
						|
	"BitwiseAnd",
 | 
						|
	"Not",
 | 
						|
	"BitFieldInsert",
 | 
						|
	"BitFieldSExtract",
 | 
						|
	"BitFieldUExtract",
 | 
						|
	"BitReverse",
 | 
						|
	"BitCount",
 | 
						|
	"#206",
 | 
						|
	"DPdx",
 | 
						|
	"DPdy",
 | 
						|
	"Fwidth",
 | 
						|
	"DPdxFine",
 | 
						|
	"DPdyFine",
 | 
						|
	"FwidthFine",
 | 
						|
	"DPdxCoarse",
 | 
						|
	"DPdyCoarse",
 | 
						|
	"FwidthCoarse",
 | 
						|
	"#216",
 | 
						|
	"#217",
 | 
						|
	"EmitVertex",
 | 
						|
	"EndPrimitive",
 | 
						|
	"EmitStreamVertex",
 | 
						|
	"EndStreamPrimitive",
 | 
						|
	"#222",
 | 
						|
	"#223",
 | 
						|
	"ControlBarrier",
 | 
						|
	"MemoryBarrier",
 | 
						|
	"#226",
 | 
						|
	"AtomicLoad",
 | 
						|
	"AtomicStore",
 | 
						|
	"AtomicExchange",
 | 
						|
	"AtomicCompareExchange",
 | 
						|
	"AtomicCompareExchangeWeak",
 | 
						|
	"AtomicIIncrement",
 | 
						|
	"AtomicIDecrement",
 | 
						|
	"AtomicIAdd",
 | 
						|
	"AtomicISub",
 | 
						|
	"AtomicSMin",
 | 
						|
	"AtomicUMin",
 | 
						|
	"AtomicSMax",
 | 
						|
	"AtomicUMax",
 | 
						|
	"AtomicAnd",
 | 
						|
	"AtomicOr",
 | 
						|
	"AtomicXor",
 | 
						|
	"#243",
 | 
						|
	"#244",
 | 
						|
	"Phi",
 | 
						|
	"LoopMerge",
 | 
						|
	"SelectionMerge",
 | 
						|
	"Label",
 | 
						|
	"Branch",
 | 
						|
	"BranchConditional",
 | 
						|
	"Switch",
 | 
						|
	"Kill",
 | 
						|
	"Return",
 | 
						|
	"ReturnValue",
 | 
						|
	"Unreachable",
 | 
						|
	"LifetimeStart",
 | 
						|
	"LifetimeStop",
 | 
						|
	"#258",
 | 
						|
	"GroupAsyncCopy",
 | 
						|
	"GroupWaitEvents",
 | 
						|
	"GroupAll",
 | 
						|
	"GroupAny",
 | 
						|
	"GroupBroadcast",
 | 
						|
	"GroupIAdd",
 | 
						|
	"GroupFAdd",
 | 
						|
	"GroupFMin",
 | 
						|
	"GroupUMin",
 | 
						|
	"GroupSMin",
 | 
						|
	"GroupFMax",
 | 
						|
	"GroupUMax",
 | 
						|
	"GroupSMax",
 | 
						|
	"#272",
 | 
						|
	"#273",
 | 
						|
	"ReadPipe",
 | 
						|
	"WritePipe",
 | 
						|
	"ReservedReadPipe",
 | 
						|
	"ReservedWritePipe",
 | 
						|
	"ReserveReadPipePackets",
 | 
						|
	"ReserveWritePipePackets",
 | 
						|
	"CommitReadPipe",
 | 
						|
	"CommitWritePipe",
 | 
						|
	"IsValidReserveId",
 | 
						|
	"GetNumPipePackets",
 | 
						|
	"GetMaxPipePackets",
 | 
						|
	"GroupReserveReadPipePackets",
 | 
						|
	"GroupReserveWritePipePackets",
 | 
						|
	"GroupCommitReadPipe",
 | 
						|
	"GroupCommitWritePipe",
 | 
						|
	"#289",
 | 
						|
	"#290",
 | 
						|
	"EnqueueMarker",
 | 
						|
	"EnqueueKernel",
 | 
						|
	"GetKernelNDrangeSubGroupCount",
 | 
						|
	"GetKernelNDrangeMaxSubGroupSize",
 | 
						|
	"GetKernelWorkGroupSize",
 | 
						|
	"GetKernelPreferredWorkGroupSizeMultiple",
 | 
						|
	"RetainEvent",
 | 
						|
	"ReleaseEvent",
 | 
						|
	"CreateUserEvent",
 | 
						|
	"IsValidEvent",
 | 
						|
	"SetUserEventStatus",
 | 
						|
	"CaptureEventProfilingInfo",
 | 
						|
	"GetDefaultQueue",
 | 
						|
	"BuildNDRange",
 | 
						|
	"ImageSparseSampleImplicitLod",
 | 
						|
	"ImageSparseSampleExplicitLod",
 | 
						|
	"ImageSparseSampleDrefImplicitLod",
 | 
						|
	"ImageSparseSampleDrefExplicitLod",
 | 
						|
	"ImageSparseSampleProjImplicitLod",
 | 
						|
	"ImageSparseSampleProjExplicitLod",
 | 
						|
	"ImageSparseSampleProjDrefImplicitLod",
 | 
						|
	"ImageSparseSampleProjDrefExplicitLod",
 | 
						|
	"ImageSparseFetch",
 | 
						|
	"ImageSparseGather",
 | 
						|
	"ImageSparseDrefGather",
 | 
						|
	"ImageSparseTexelsResident",
 | 
						|
	"NoLine",
 | 
						|
	"AtomicFlagTestAndSet",
 | 
						|
	"AtomicFlagClear",
 | 
						|
	"ImageSparseRead",
 | 
						|
	"SizeOf",
 | 
						|
	"TypePipeStorage",
 | 
						|
	"ConstantPipeStorage",
 | 
						|
	"CreatePipeFromPipeStorage",
 | 
						|
	"GetKernelLocalSizeForSubgroupCount",
 | 
						|
	"GetKernelMaxNumSubgroups",
 | 
						|
	"TypeNamedBarrier",
 | 
						|
	"NamedBarrierInitialize",
 | 
						|
	"MemoryNamedBarrier",
 | 
						|
	"ModuleProcessed",
 | 
						|
	"ExecutionModeId",
 | 
						|
	"DecorateId",
 | 
						|
	"GroupNonUniformElect",
 | 
						|
	"GroupNonUniformAll",
 | 
						|
	"GroupNonUniformAny",
 | 
						|
	"GroupNonUniformAllEqual",
 | 
						|
	"GroupNonUniformBroadcast",
 | 
						|
	"GroupNonUniformBroadcastFirst",
 | 
						|
	"GroupNonUniformBallot",
 | 
						|
	"GroupNonUniformInverseBallot",
 | 
						|
	"GroupNonUniformBallotBitExtract",
 | 
						|
	"GroupNonUniformBallotBitCount",
 | 
						|
	"GroupNonUniformBallotFindLSB",
 | 
						|
	"GroupNonUniformBallotFindMSB",
 | 
						|
	"GroupNonUniformShuffle",
 | 
						|
	"GroupNonUniformShuffleXor",
 | 
						|
	"GroupNonUniformShuffleUp",
 | 
						|
	"GroupNonUniformShuffleDown",
 | 
						|
	"GroupNonUniformIAdd",
 | 
						|
	"GroupNonUniformFAdd",
 | 
						|
	"GroupNonUniformIMul",
 | 
						|
	"GroupNonUniformFMul",
 | 
						|
	"GroupNonUniformSMin",
 | 
						|
	"GroupNonUniformUMin",
 | 
						|
	"GroupNonUniformFMin",
 | 
						|
	"GroupNonUniformSMax",
 | 
						|
	"GroupNonUniformUMax",
 | 
						|
	"GroupNonUniformFMax",
 | 
						|
	"GroupNonUniformBitwiseAnd",
 | 
						|
	"GroupNonUniformBitwiseOr",
 | 
						|
	"GroupNonUniformBitwiseXor",
 | 
						|
	"GroupNonUniformLogicalAnd",
 | 
						|
	"GroupNonUniformLogicalOr",
 | 
						|
	"GroupNonUniformLogicalXor",
 | 
						|
	"GroupNonUniformQuadBroadcast",
 | 
						|
	"GroupNonUniformQuadSwap",
 | 
						|
};
 | 
						|
static_assert(_SMOLV_ARRAY_SIZE(kSpirvOpNames) == kKnownOpsCount, "kSpirvOpNames table mismatch with known SpvOps");
 | 
						|
 | 
						|
 | 
						|
struct OpData
 | 
						|
{
 | 
						|
	uint8_t hasResult;	// does it have result ID?
 | 
						|
	uint8_t hasType;	// does it have type ID?
 | 
						|
	uint8_t deltaFromResult; // How many words after (optional) type+result to write out as deltas from result?
 | 
						|
	uint8_t varrest;	// should the rest of words be written in varint encoding?
 | 
						|
};
 | 
						|
static const OpData kSpirvOpData[] =
 | 
						|
{
 | 
						|
	{0, 0, 0, 0}, // Nop
 | 
						|
	{1, 1, 0, 0}, // Undef
 | 
						|
	{0, 0, 0, 0}, // SourceContinued
 | 
						|
	{0, 0, 0, 1}, // Source
 | 
						|
	{0, 0, 0, 0}, // SourceExtension
 | 
						|
	{0, 0, 0, 0}, // Name
 | 
						|
	{0, 0, 0, 0}, // MemberName
 | 
						|
	{0, 0, 0, 0}, // String
 | 
						|
	{0, 0, 0, 1}, // Line
 | 
						|
	{1, 1, 0, 0}, // #9
 | 
						|
	{0, 0, 0, 0}, // Extension
 | 
						|
	{1, 0, 0, 0}, // ExtInstImport
 | 
						|
	{1, 1, 0, 1}, // ExtInst
 | 
						|
	{1, 1, 2, 1}, // VectorShuffleCompact - new in SMOLV
 | 
						|
	{0, 0, 0, 1}, // MemoryModel
 | 
						|
	{0, 0, 0, 1}, // EntryPoint
 | 
						|
	{0, 0, 0, 1}, // ExecutionMode
 | 
						|
	{0, 0, 0, 1}, // Capability
 | 
						|
	{1, 1, 0, 0}, // #18
 | 
						|
	{1, 0, 0, 1}, // TypeVoid
 | 
						|
	{1, 0, 0, 1}, // TypeBool
 | 
						|
	{1, 0, 0, 1}, // TypeInt
 | 
						|
	{1, 0, 0, 1}, // TypeFloat
 | 
						|
	{1, 0, 0, 1}, // TypeVector
 | 
						|
	{1, 0, 0, 1}, // TypeMatrix
 | 
						|
	{1, 0, 0, 1}, // TypeImage
 | 
						|
	{1, 0, 0, 1}, // TypeSampler
 | 
						|
	{1, 0, 0, 1}, // TypeSampledImage
 | 
						|
	{1, 0, 0, 1}, // TypeArray
 | 
						|
	{1, 0, 0, 1}, // TypeRuntimeArray
 | 
						|
	{1, 0, 0, 1}, // TypeStruct
 | 
						|
	{1, 0, 0, 1}, // TypeOpaque
 | 
						|
	{1, 0, 0, 1}, // TypePointer
 | 
						|
	{1, 0, 0, 1}, // TypeFunction
 | 
						|
	{1, 0, 0, 1}, // TypeEvent
 | 
						|
	{1, 0, 0, 1}, // TypeDeviceEvent
 | 
						|
	{1, 0, 0, 1}, // TypeReserveId
 | 
						|
	{1, 0, 0, 1}, // TypeQueue
 | 
						|
	{1, 0, 0, 1}, // TypePipe
 | 
						|
	{0, 0, 0, 1}, // TypeForwardPointer
 | 
						|
	{1, 1, 0, 0}, // #40
 | 
						|
	{1, 1, 0, 0}, // ConstantTrue
 | 
						|
	{1, 1, 0, 0}, // ConstantFalse
 | 
						|
	{1, 1, 0, 0}, // Constant
 | 
						|
	{1, 1, 9, 0}, // ConstantComposite
 | 
						|
	{1, 1, 0, 1}, // ConstantSampler
 | 
						|
	{1, 1, 0, 0}, // ConstantNull
 | 
						|
	{1, 1, 0, 0}, // #47
 | 
						|
	{1, 1, 0, 0}, // SpecConstantTrue
 | 
						|
	{1, 1, 0, 0}, // SpecConstantFalse
 | 
						|
	{1, 1, 0, 0}, // SpecConstant
 | 
						|
	{1, 1, 9, 0}, // SpecConstantComposite
 | 
						|
	{1, 1, 0, 0}, // SpecConstantOp
 | 
						|
	{1, 1, 0, 0}, // #53
 | 
						|
	{1, 1, 0, 1}, // Function
 | 
						|
	{1, 1, 0, 0}, // FunctionParameter
 | 
						|
	{0, 0, 0, 0}, // FunctionEnd
 | 
						|
	{1, 1, 9, 0}, // FunctionCall
 | 
						|
	{1, 1, 0, 0}, // #58
 | 
						|
	{1, 1, 0, 1}, // Variable
 | 
						|
	{1, 1, 0, 0}, // ImageTexelPointer
 | 
						|
	{1, 1, 1, 1}, // Load
 | 
						|
	{0, 0, 2, 1}, // Store
 | 
						|
	{0, 0, 0, 0}, // CopyMemory
 | 
						|
	{0, 0, 0, 0}, // CopyMemorySized
 | 
						|
	{1, 1, 0, 1}, // AccessChain
 | 
						|
	{1, 1, 0, 0}, // InBoundsAccessChain
 | 
						|
	{1, 1, 0, 0}, // PtrAccessChain
 | 
						|
	{1, 1, 0, 0}, // ArrayLength
 | 
						|
	{1, 1, 0, 0}, // GenericPtrMemSemantics
 | 
						|
	{1, 1, 0, 0}, // InBoundsPtrAccessChain
 | 
						|
	{0, 0, 0, 1}, // Decorate
 | 
						|
	{0, 0, 0, 1}, // MemberDecorate
 | 
						|
	{1, 0, 0, 0}, // DecorationGroup
 | 
						|
	{0, 0, 0, 0}, // GroupDecorate
 | 
						|
	{0, 0, 0, 0}, // GroupMemberDecorate
 | 
						|
	{1, 1, 0, 0}, // #76
 | 
						|
	{1, 1, 1, 1}, // VectorExtractDynamic
 | 
						|
	{1, 1, 2, 1}, // VectorInsertDynamic
 | 
						|
	{1, 1, 2, 1}, // VectorShuffle
 | 
						|
	{1, 1, 9, 0}, // CompositeConstruct
 | 
						|
	{1, 1, 1, 1}, // CompositeExtract
 | 
						|
	{1, 1, 2, 1}, // CompositeInsert
 | 
						|
	{1, 1, 1, 0}, // CopyObject
 | 
						|
	{1, 1, 0, 0}, // Transpose
 | 
						|
	{1, 1, 0, 0}, // #85
 | 
						|
	{1, 1, 0, 0}, // SampledImage
 | 
						|
	{1, 1, 2, 1}, // ImageSampleImplicitLod
 | 
						|
	{1, 1, 2, 1}, // ImageSampleExplicitLod
 | 
						|
	{1, 1, 3, 1}, // ImageSampleDrefImplicitLod
 | 
						|
	{1, 1, 3, 1}, // ImageSampleDrefExplicitLod
 | 
						|
	{1, 1, 2, 1}, // ImageSampleProjImplicitLod
 | 
						|
	{1, 1, 2, 1}, // ImageSampleProjExplicitLod
 | 
						|
	{1, 1, 3, 1}, // ImageSampleProjDrefImplicitLod
 | 
						|
	{1, 1, 3, 1}, // ImageSampleProjDrefExplicitLod
 | 
						|
	{1, 1, 2, 1}, // ImageFetch
 | 
						|
	{1, 1, 3, 1}, // ImageGather
 | 
						|
	{1, 1, 3, 1}, // ImageDrefGather
 | 
						|
	{1, 1, 2, 1}, // ImageRead
 | 
						|
	{0, 0, 3, 1}, // ImageWrite
 | 
						|
	{1, 1, 1, 0}, // Image
 | 
						|
	{1, 1, 1, 0}, // ImageQueryFormat
 | 
						|
	{1, 1, 1, 0}, // ImageQueryOrder
 | 
						|
	{1, 1, 2, 0}, // ImageQuerySizeLod
 | 
						|
	{1, 1, 1, 0}, // ImageQuerySize
 | 
						|
	{1, 1, 2, 0}, // ImageQueryLod
 | 
						|
	{1, 1, 1, 0}, // ImageQueryLevels
 | 
						|
	{1, 1, 1, 0}, // ImageQuerySamples
 | 
						|
	{1, 1, 0, 0}, // #108
 | 
						|
	{1, 1, 1, 0}, // ConvertFToU
 | 
						|
	{1, 1, 1, 0}, // ConvertFToS
 | 
						|
	{1, 1, 1, 0}, // ConvertSToF
 | 
						|
	{1, 1, 1, 0}, // ConvertUToF
 | 
						|
	{1, 1, 1, 0}, // UConvert
 | 
						|
	{1, 1, 1, 0}, // SConvert
 | 
						|
	{1, 1, 1, 0}, // FConvert
 | 
						|
	{1, 1, 1, 0}, // QuantizeToF16
 | 
						|
	{1, 1, 1, 0}, // ConvertPtrToU
 | 
						|
	{1, 1, 1, 0}, // SatConvertSToU
 | 
						|
	{1, 1, 1, 0}, // SatConvertUToS
 | 
						|
	{1, 1, 1, 0}, // ConvertUToPtr
 | 
						|
	{1, 1, 1, 0}, // PtrCastToGeneric
 | 
						|
	{1, 1, 1, 0}, // GenericCastToPtr
 | 
						|
	{1, 1, 1, 1}, // GenericCastToPtrExplicit
 | 
						|
	{1, 1, 1, 0}, // Bitcast
 | 
						|
	{1, 1, 0, 0}, // #125
 | 
						|
	{1, 1, 1, 0}, // SNegate
 | 
						|
	{1, 1, 1, 0}, // FNegate
 | 
						|
	{1, 1, 2, 0}, // IAdd
 | 
						|
	{1, 1, 2, 0}, // FAdd
 | 
						|
	{1, 1, 2, 0}, // ISub
 | 
						|
	{1, 1, 2, 0}, // FSub
 | 
						|
	{1, 1, 2, 0}, // IMul
 | 
						|
	{1, 1, 2, 0}, // FMul
 | 
						|
	{1, 1, 2, 0}, // UDiv
 | 
						|
	{1, 1, 2, 0}, // SDiv
 | 
						|
	{1, 1, 2, 0}, // FDiv
 | 
						|
	{1, 1, 2, 0}, // UMod
 | 
						|
	{1, 1, 2, 0}, // SRem
 | 
						|
	{1, 1, 2, 0}, // SMod
 | 
						|
	{1, 1, 2, 0}, // FRem
 | 
						|
	{1, 1, 2, 0}, // FMod
 | 
						|
	{1, 1, 2, 0}, // VectorTimesScalar
 | 
						|
	{1, 1, 2, 0}, // MatrixTimesScalar
 | 
						|
	{1, 1, 2, 0}, // VectorTimesMatrix
 | 
						|
	{1, 1, 2, 0}, // MatrixTimesVector
 | 
						|
	{1, 1, 2, 0}, // MatrixTimesMatrix
 | 
						|
	{1, 1, 2, 0}, // OuterProduct
 | 
						|
	{1, 1, 2, 0}, // Dot
 | 
						|
	{1, 1, 2, 0}, // IAddCarry
 | 
						|
	{1, 1, 2, 0}, // ISubBorrow
 | 
						|
	{1, 1, 2, 0}, // UMulExtended
 | 
						|
	{1, 1, 2, 0}, // SMulExtended
 | 
						|
	{1, 1, 0, 0}, // #153
 | 
						|
	{1, 1, 1, 0}, // Any
 | 
						|
	{1, 1, 1, 0}, // All
 | 
						|
	{1, 1, 1, 0}, // IsNan
 | 
						|
	{1, 1, 1, 0}, // IsInf
 | 
						|
	{1, 1, 1, 0}, // IsFinite
 | 
						|
	{1, 1, 1, 0}, // IsNormal
 | 
						|
	{1, 1, 1, 0}, // SignBitSet
 | 
						|
	{1, 1, 2, 0}, // LessOrGreater
 | 
						|
	{1, 1, 2, 0}, // Ordered
 | 
						|
	{1, 1, 2, 0}, // Unordered
 | 
						|
	{1, 1, 2, 0}, // LogicalEqual
 | 
						|
	{1, 1, 2, 0}, // LogicalNotEqual
 | 
						|
	{1, 1, 2, 0}, // LogicalOr
 | 
						|
	{1, 1, 2, 0}, // LogicalAnd
 | 
						|
	{1, 1, 1, 0}, // LogicalNot
 | 
						|
	{1, 1, 3, 0}, // Select
 | 
						|
	{1, 1, 2, 0}, // IEqual
 | 
						|
	{1, 1, 2, 0}, // INotEqual
 | 
						|
	{1, 1, 2, 0}, // UGreaterThan
 | 
						|
	{1, 1, 2, 0}, // SGreaterThan
 | 
						|
	{1, 1, 2, 0}, // UGreaterThanEqual
 | 
						|
	{1, 1, 2, 0}, // SGreaterThanEqual
 | 
						|
	{1, 1, 2, 0}, // ULessThan
 | 
						|
	{1, 1, 2, 0}, // SLessThan
 | 
						|
	{1, 1, 2, 0}, // ULessThanEqual
 | 
						|
	{1, 1, 2, 0}, // SLessThanEqual
 | 
						|
	{1, 1, 2, 0}, // FOrdEqual
 | 
						|
	{1, 1, 2, 0}, // FUnordEqual
 | 
						|
	{1, 1, 2, 0}, // FOrdNotEqual
 | 
						|
	{1, 1, 2, 0}, // FUnordNotEqual
 | 
						|
	{1, 1, 2, 0}, // FOrdLessThan
 | 
						|
	{1, 1, 2, 0}, // FUnordLessThan
 | 
						|
	{1, 1, 2, 0}, // FOrdGreaterThan
 | 
						|
	{1, 1, 2, 0}, // FUnordGreaterThan
 | 
						|
	{1, 1, 2, 0}, // FOrdLessThanEqual
 | 
						|
	{1, 1, 2, 0}, // FUnordLessThanEqual
 | 
						|
	{1, 1, 2, 0}, // FOrdGreaterThanEqual
 | 
						|
	{1, 1, 2, 0}, // FUnordGreaterThanEqual
 | 
						|
	{1, 1, 0, 0}, // #192
 | 
						|
	{1, 1, 0, 0}, // #193
 | 
						|
	{1, 1, 2, 0}, // ShiftRightLogical
 | 
						|
	{1, 1, 2, 0}, // ShiftRightArithmetic
 | 
						|
	{1, 1, 2, 0}, // ShiftLeftLogical
 | 
						|
	{1, 1, 2, 0}, // BitwiseOr
 | 
						|
	{1, 1, 2, 0}, // BitwiseXor
 | 
						|
	{1, 1, 2, 0}, // BitwiseAnd
 | 
						|
	{1, 1, 1, 0}, // Not
 | 
						|
	{1, 1, 4, 0}, // BitFieldInsert
 | 
						|
	{1, 1, 3, 0}, // BitFieldSExtract
 | 
						|
	{1, 1, 3, 0}, // BitFieldUExtract
 | 
						|
	{1, 1, 1, 0}, // BitReverse
 | 
						|
	{1, 1, 1, 0}, // BitCount
 | 
						|
	{1, 1, 0, 0}, // #206
 | 
						|
	{1, 1, 0, 0}, // DPdx
 | 
						|
	{1, 1, 0, 0}, // DPdy
 | 
						|
	{1, 1, 0, 0}, // Fwidth
 | 
						|
	{1, 1, 0, 0}, // DPdxFine
 | 
						|
	{1, 1, 0, 0}, // DPdyFine
 | 
						|
	{1, 1, 0, 0}, // FwidthFine
 | 
						|
	{1, 1, 0, 0}, // DPdxCoarse
 | 
						|
	{1, 1, 0, 0}, // DPdyCoarse
 | 
						|
	{1, 1, 0, 0}, // FwidthCoarse
 | 
						|
	{1, 1, 0, 0}, // #216
 | 
						|
	{1, 1, 0, 0}, // #217
 | 
						|
	{0, 0, 0, 0}, // EmitVertex
 | 
						|
	{0, 0, 0, 0}, // EndPrimitive
 | 
						|
	{0, 0, 0, 0}, // EmitStreamVertex
 | 
						|
	{0, 0, 0, 0}, // EndStreamPrimitive
 | 
						|
	{1, 1, 0, 0}, // #222
 | 
						|
	{1, 1, 0, 0}, // #223
 | 
						|
	{0, 0, 3, 0}, // ControlBarrier
 | 
						|
	{0, 0, 2, 0}, // MemoryBarrier
 | 
						|
	{1, 1, 0, 0}, // #226
 | 
						|
	{1, 1, 0, 0}, // AtomicLoad
 | 
						|
	{0, 0, 0, 0}, // AtomicStore
 | 
						|
	{1, 1, 0, 0}, // AtomicExchange
 | 
						|
	{1, 1, 0, 0}, // AtomicCompareExchange
 | 
						|
	{1, 1, 0, 0}, // AtomicCompareExchangeWeak
 | 
						|
	{1, 1, 0, 0}, // AtomicIIncrement
 | 
						|
	{1, 1, 0, 0}, // AtomicIDecrement
 | 
						|
	{1, 1, 0, 0}, // AtomicIAdd
 | 
						|
	{1, 1, 0, 0}, // AtomicISub
 | 
						|
	{1, 1, 0, 0}, // AtomicSMin
 | 
						|
	{1, 1, 0, 0}, // AtomicUMin
 | 
						|
	{1, 1, 0, 0}, // AtomicSMax
 | 
						|
	{1, 1, 0, 0}, // AtomicUMax
 | 
						|
	{1, 1, 0, 0}, // AtomicAnd
 | 
						|
	{1, 1, 0, 0}, // AtomicOr
 | 
						|
	{1, 1, 0, 0}, // AtomicXor
 | 
						|
	{1, 1, 0, 0}, // #243
 | 
						|
	{1, 1, 0, 0}, // #244
 | 
						|
	{1, 1, 0, 0}, // Phi
 | 
						|
	{0, 0, 2, 1}, // LoopMerge
 | 
						|
	{0, 0, 1, 1}, // SelectionMerge
 | 
						|
	{1, 0, 0, 0}, // Label
 | 
						|
	{0, 0, 1, 0}, // Branch
 | 
						|
	{0, 0, 3, 1}, // BranchConditional
 | 
						|
	{0, 0, 0, 0}, // Switch
 | 
						|
	{0, 0, 0, 0}, // Kill
 | 
						|
	{0, 0, 0, 0}, // Return
 | 
						|
	{0, 0, 0, 0}, // ReturnValue
 | 
						|
	{0, 0, 0, 0}, // Unreachable
 | 
						|
	{0, 0, 0, 0}, // LifetimeStart
 | 
						|
	{0, 0, 0, 0}, // LifetimeStop
 | 
						|
	{1, 1, 0, 0}, // #258
 | 
						|
	{1, 1, 0, 0}, // GroupAsyncCopy
 | 
						|
	{0, 0, 0, 0}, // GroupWaitEvents
 | 
						|
	{1, 1, 0, 0}, // GroupAll
 | 
						|
	{1, 1, 0, 0}, // GroupAny
 | 
						|
	{1, 1, 0, 0}, // GroupBroadcast
 | 
						|
	{1, 1, 0, 0}, // GroupIAdd
 | 
						|
	{1, 1, 0, 0}, // GroupFAdd
 | 
						|
	{1, 1, 0, 0}, // GroupFMin
 | 
						|
	{1, 1, 0, 0}, // GroupUMin
 | 
						|
	{1, 1, 0, 0}, // GroupSMin
 | 
						|
	{1, 1, 0, 0}, // GroupFMax
 | 
						|
	{1, 1, 0, 0}, // GroupUMax
 | 
						|
	{1, 1, 0, 0}, // GroupSMax
 | 
						|
	{1, 1, 0, 0}, // #272
 | 
						|
	{1, 1, 0, 0}, // #273
 | 
						|
	{1, 1, 0, 0}, // ReadPipe
 | 
						|
	{1, 1, 0, 0}, // WritePipe
 | 
						|
	{1, 1, 0, 0}, // ReservedReadPipe
 | 
						|
	{1, 1, 0, 0}, // ReservedWritePipe
 | 
						|
	{1, 1, 0, 0}, // ReserveReadPipePackets
 | 
						|
	{1, 1, 0, 0}, // ReserveWritePipePackets
 | 
						|
	{0, 0, 0, 0}, // CommitReadPipe
 | 
						|
	{0, 0, 0, 0}, // CommitWritePipe
 | 
						|
	{1, 1, 0, 0}, // IsValidReserveId
 | 
						|
	{1, 1, 0, 0}, // GetNumPipePackets
 | 
						|
	{1, 1, 0, 0}, // GetMaxPipePackets
 | 
						|
	{1, 1, 0, 0}, // GroupReserveReadPipePackets
 | 
						|
	{1, 1, 0, 0}, // GroupReserveWritePipePackets
 | 
						|
	{0, 0, 0, 0}, // GroupCommitReadPipe
 | 
						|
	{0, 0, 0, 0}, // GroupCommitWritePipe
 | 
						|
	{1, 1, 0, 0}, // #289
 | 
						|
	{1, 1, 0, 0}, // #290
 | 
						|
	{1, 1, 0, 0}, // EnqueueMarker
 | 
						|
	{1, 1, 0, 0}, // EnqueueKernel
 | 
						|
	{1, 1, 0, 0}, // GetKernelNDrangeSubGroupCount
 | 
						|
	{1, 1, 0, 0}, // GetKernelNDrangeMaxSubGroupSize
 | 
						|
	{1, 1, 0, 0}, // GetKernelWorkGroupSize
 | 
						|
	{1, 1, 0, 0}, // GetKernelPreferredWorkGroupSizeMultiple
 | 
						|
	{0, 0, 0, 0}, // RetainEvent
 | 
						|
	{0, 0, 0, 0}, // ReleaseEvent
 | 
						|
	{1, 1, 0, 0}, // CreateUserEvent
 | 
						|
	{1, 1, 0, 0}, // IsValidEvent
 | 
						|
	{0, 0, 0, 0}, // SetUserEventStatus
 | 
						|
	{0, 0, 0, 0}, // CaptureEventProfilingInfo
 | 
						|
	{1, 1, 0, 0}, // GetDefaultQueue
 | 
						|
	{1, 1, 0, 0}, // BuildNDRange
 | 
						|
	{1, 1, 2, 1}, // ImageSparseSampleImplicitLod
 | 
						|
	{1, 1, 2, 1}, // ImageSparseSampleExplicitLod
 | 
						|
	{1, 1, 3, 1}, // ImageSparseSampleDrefImplicitLod
 | 
						|
	{1, 1, 3, 1}, // ImageSparseSampleDrefExplicitLod
 | 
						|
	{1, 1, 2, 1}, // ImageSparseSampleProjImplicitLod
 | 
						|
	{1, 1, 2, 1}, // ImageSparseSampleProjExplicitLod
 | 
						|
	{1, 1, 3, 1}, // ImageSparseSampleProjDrefImplicitLod
 | 
						|
	{1, 1, 3, 1}, // ImageSparseSampleProjDrefExplicitLod
 | 
						|
	{1, 1, 2, 1}, // ImageSparseFetch
 | 
						|
	{1, 1, 3, 1}, // ImageSparseGather
 | 
						|
	{1, 1, 3, 1}, // ImageSparseDrefGather
 | 
						|
	{1, 1, 1, 0}, // ImageSparseTexelsResident
 | 
						|
	{0, 0, 0, 0}, // NoLine
 | 
						|
	{1, 1, 0, 0}, // AtomicFlagTestAndSet
 | 
						|
	{0, 0, 0, 0}, // AtomicFlagClear
 | 
						|
	{1, 1, 0, 0}, // ImageSparseRead
 | 
						|
	{1, 1, 0, 0}, // SizeOf
 | 
						|
	{1, 1, 0, 0}, // TypePipeStorage
 | 
						|
	{1, 1, 0, 0}, // ConstantPipeStorage
 | 
						|
	{1, 1, 0, 0}, // CreatePipeFromPipeStorage
 | 
						|
	{1, 1, 0, 0}, // GetKernelLocalSizeForSubgroupCount
 | 
						|
	{1, 1, 0, 0}, // GetKernelMaxNumSubgroups
 | 
						|
	{1, 1, 0, 0}, // TypeNamedBarrier
 | 
						|
	{1, 1, 0, 1}, // NamedBarrierInitialize
 | 
						|
	{0, 0, 2, 1}, // MemoryNamedBarrier
 | 
						|
	{1, 1, 0, 0}, // ModuleProcessed
 | 
						|
	{0, 0, 0, 1}, // ExecutionModeId
 | 
						|
	{0, 0, 0, 1}, // DecorateId
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformElect
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformAll
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformAny
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformAllEqual
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformBroadcast
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformBroadcastFirst
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformBallot
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformInverseBallot
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformBallotBitExtract
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformBallotBitCount
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformBallotFindLSB
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformBallotFindMSB
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformShuffle
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformShuffleXor
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformShuffleUp
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformShuffleDown
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformIAdd
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformFAdd
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformIMul
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformFMul
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformSMin
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformUMin
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformFMin
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformSMax
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformUMax
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformFMax
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformBitwiseAnd
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformBitwiseOr
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformBitwiseXor
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformLogicalAnd
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformLogicalOr
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformLogicalXor
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformQuadBroadcast
 | 
						|
	{1, 1, 1, 1}, // GroupNonUniformQuadSwap
 | 
						|
};
 | 
						|
static_assert(_SMOLV_ARRAY_SIZE(kSpirvOpData) == kKnownOpsCount, "kSpirvOpData table mismatch with known SpvOps");
 | 
						|
 | 
						|
// Instruction encoding depends on the table that describes the various SPIR-V opcodes.
 | 
						|
// Whenever we change or expand the table, we need to bump up the SMOL-V version, and make
 | 
						|
// sure that we can still decode files encoded by an older version.
 | 
						|
static int smolv_GetKnownOpsCount(int version)
 | 
						|
{
 | 
						|
	if (version == 0)
 | 
						|
		return SpvOpModuleProcessed+1;
 | 
						|
	if (version == 1) // 2020 February, version 1 added ExecutionModeId..GroupNonUniformQuadSwap
 | 
						|
		return SpvOpGroupNonUniformQuadSwap+1;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static bool smolv_OpHasResult(SpvOp op, int opsCount)
 | 
						|
{
 | 
						|
	if (op < 0 || op >= opsCount)
 | 
						|
		return false;
 | 
						|
	return kSpirvOpData[op].hasResult != 0;
 | 
						|
}
 | 
						|
 | 
						|
static bool smolv_OpHasType(SpvOp op, int opsCount)
 | 
						|
{
 | 
						|
	if (op < 0 || op >= opsCount)
 | 
						|
		return false;
 | 
						|
	return kSpirvOpData[op].hasType != 0;
 | 
						|
}
 | 
						|
 | 
						|
static int smolv_OpDeltaFromResult(SpvOp op, int opsCount)
 | 
						|
{
 | 
						|
	if (op < 0 || op >= opsCount)
 | 
						|
		return 0;
 | 
						|
	return kSpirvOpData[op].deltaFromResult;
 | 
						|
}
 | 
						|
 | 
						|
static bool smolv_OpVarRest(SpvOp op, int opsCount)
 | 
						|
{
 | 
						|
	if (op < 0 || op >= opsCount)
 | 
						|
		return false;
 | 
						|
	return kSpirvOpData[op].varrest != 0;
 | 
						|
}
 | 
						|
 | 
						|
static bool smolv_OpDebugInfo(SpvOp op, int opsCount)
 | 
						|
{
 | 
						|
	return
 | 
						|
		op == SpvOpSourceContinued ||
 | 
						|
		op == SpvOpSource ||
 | 
						|
		op == SpvOpSourceExtension ||
 | 
						|
		op == SpvOpName ||
 | 
						|
		op == SpvOpMemberName ||
 | 
						|
		op == SpvOpString ||
 | 
						|
		op == SpvOpLine ||
 | 
						|
		op == SpvOpNoLine ||
 | 
						|
		op == SpvOpModuleProcessed;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int smolv_DecorationExtraOps(int dec)
 | 
						|
{
 | 
						|
	if (dec == 0 || (dec >= 2 && dec <= 5)) // RelaxedPrecision, Block..ColMajor
 | 
						|
		return 0;
 | 
						|
	if (dec >= 29 && dec <= 37) // Stream..XfbStride
 | 
						|
		return 1;
 | 
						|
	return -1; // unknown, encode length
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// --------------------------------------------------------------------------------------------
 | 
						|
 | 
						|
 | 
						|
static bool smolv_CheckGenericHeader(const uint32_t* words, size_t wordCount, uint32_t expectedMagic, uint32_t versionMask)
 | 
						|
{
 | 
						|
	if (!words)
 | 
						|
		return false;
 | 
						|
	if (wordCount < 5)
 | 
						|
		return false;
 | 
						|
	
 | 
						|
	uint32_t headerMagic = words[0];
 | 
						|
	if (headerMagic != expectedMagic)
 | 
						|
		return false;
 | 
						|
	uint32_t headerVersion = words[1] & versionMask;
 | 
						|
	if (headerVersion < 0x00010000 || headerVersion > 0x00010500)
 | 
						|
		return false; // only support 1.0 through 1.5
 | 
						|
	
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
static const int kSpirVHeaderMagic = 0x07230203;
 | 
						|
static const int kSmolHeaderMagic = 0x534D4F4C; // "SMOL"
 | 
						|
 | 
						|
static const int kSmolCurrEncodingVersion = 1;
 | 
						|
 | 
						|
static bool smolv_CheckSpirVHeader(const uint32_t* words, size_t wordCount)
 | 
						|
{
 | 
						|
	//@TODO: if SPIR-V header magic was reversed, that means the file got written
 | 
						|
	// in a "big endian" order. Need to byteswap all words then.
 | 
						|
	return smolv_CheckGenericHeader(words, wordCount, kSpirVHeaderMagic, 0xFFFFFFFF);
 | 
						|
}
 | 
						|
static bool smolv_CheckSmolHeader(const uint8_t* bytes, size_t byteCount)
 | 
						|
{
 | 
						|
	if (!smolv_CheckGenericHeader((const uint32_t*)bytes, byteCount/4, kSmolHeaderMagic, 0x00FFFFFF))
 | 
						|
		return false;
 | 
						|
	if (byteCount < 24) // one more word past header to store decoded length
 | 
						|
		return false;
 | 
						|
	// SMOL-V version
 | 
						|
	int smolVersion = ((const uint32_t*)bytes)[1] >> 24;
 | 
						|
	if (smolVersion < 0 || smolVersion > kSmolCurrEncodingVersion)
 | 
						|
		return false;
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void smolv_Write4(smolv::ByteArray& arr, uint32_t v)
 | 
						|
{
 | 
						|
	arr.push_back(v & 0xFF);
 | 
						|
	arr.push_back((v >> 8) & 0xFF);
 | 
						|
	arr.push_back((v >> 16) & 0xFF);
 | 
						|
	arr.push_back(v >> 24);
 | 
						|
}
 | 
						|
 | 
						|
static void smolv_Write4(uint8_t*& buf, uint32_t v)
 | 
						|
{
 | 
						|
	memcpy(buf, &v, 4);
 | 
						|
	buf += 4;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static bool smolv_Read4(const uint8_t*& data, const uint8_t* dataEnd, uint32_t& outv)
 | 
						|
{
 | 
						|
	if (data + 4 > dataEnd)
 | 
						|
		return false;
 | 
						|
	outv = (data[0]) | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
 | 
						|
	data += 4;
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// --------------------------------------------------------------------------------------------
 | 
						|
 | 
						|
// Variable-length integer encoding for unsigned integers. In each byte:
 | 
						|
// - highest bit set if more bytes follow, cleared if this is last byte.
 | 
						|
// - other 7 bits are the actual value payload.
 | 
						|
// Takes 1-5 bytes to encode an integer (values between 0 and 127 take one byte, etc.).
 | 
						|
 | 
						|
static void smolv_WriteVarint(smolv::ByteArray& arr, uint32_t v)
 | 
						|
{
 | 
						|
	while (v > 127)
 | 
						|
	{
 | 
						|
		arr.push_back((v & 127) | 128);
 | 
						|
		v >>= 7;
 | 
						|
	}
 | 
						|
	arr.push_back(v & 127);
 | 
						|
}
 | 
						|
 | 
						|
static bool smolv_ReadVarint(const uint8_t*& data, const uint8_t* dataEnd, uint32_t& outVal)
 | 
						|
{
 | 
						|
	uint32_t v = 0;
 | 
						|
	uint32_t shift = 0;
 | 
						|
	while (data < dataEnd)
 | 
						|
	{
 | 
						|
		uint8_t b = *data;
 | 
						|
		v |= (b & 127) << shift;
 | 
						|
		shift += 7;
 | 
						|
		data++;
 | 
						|
		if (!(b & 128))
 | 
						|
			break;
 | 
						|
	}
 | 
						|
	outVal = v;
 | 
						|
	return true; //@TODO: report failures
 | 
						|
}
 | 
						|
 | 
						|
static uint32_t smolv_ZigEncode(int32_t i)
 | 
						|
{
 | 
						|
	return (uint32_t(i) << 1) ^ (i >> 31);
 | 
						|
}
 | 
						|
 | 
						|
static int32_t smolv_ZigDecode(uint32_t u)
 | 
						|
{
 | 
						|
	 return (u & 1) ? ((u >> 1) ^ ~0) : (u >> 1);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Remap most common Op codes (Load, Store, Decorate, VectorShuffle etc.) to be in < 16 range, for
 | 
						|
// more compact varint encoding. This basically swaps rarely used op values that are < 16 with the
 | 
						|
// ones that are common.
 | 
						|
 | 
						|
static SpvOp smolv_RemapOp(SpvOp op)
 | 
						|
{
 | 
						|
#	define _SMOLV_SWAP_OP(op1,op2) if (op==op1) return op2; if (op==op2) return op1
 | 
						|
	_SMOLV_SWAP_OP(SpvOpDecorate,SpvOpNop); // 0: 24%
 | 
						|
	_SMOLV_SWAP_OP(SpvOpLoad,SpvOpUndef); // 1: 17%
 | 
						|
	_SMOLV_SWAP_OP(SpvOpStore,SpvOpSourceContinued); // 2: 9%
 | 
						|
	_SMOLV_SWAP_OP(SpvOpAccessChain,SpvOpSource); // 3: 7.2%
 | 
						|
	_SMOLV_SWAP_OP(SpvOpVectorShuffle,SpvOpSourceExtension); // 4: 5.0%
 | 
						|
	// Name - already small enum value - 5: 4.4%
 | 
						|
	// MemberName - already small enum value - 6: 2.9%
 | 
						|
	_SMOLV_SWAP_OP(SpvOpMemberDecorate,SpvOpString); // 7: 4.0%
 | 
						|
	_SMOLV_SWAP_OP(SpvOpLabel,SpvOpLine); // 8: 0.9%
 | 
						|
	_SMOLV_SWAP_OP(SpvOpVariable,(SpvOp)9); // 9: 3.9%
 | 
						|
	_SMOLV_SWAP_OP(SpvOpFMul,SpvOpExtension); // 10: 3.9%
 | 
						|
	_SMOLV_SWAP_OP(SpvOpFAdd,SpvOpExtInstImport); // 11: 2.5%
 | 
						|
	// ExtInst - already small enum value - 12: 1.2%
 | 
						|
	// VectorShuffleCompact - already small enum value - used for compact shuffle encoding
 | 
						|
	_SMOLV_SWAP_OP(SpvOpTypePointer,SpvOpMemoryModel); // 14: 2.2%
 | 
						|
	_SMOLV_SWAP_OP(SpvOpFNegate,SpvOpEntryPoint); // 15: 1.1%
 | 
						|
#	undef _SMOLV_SWAP_OP
 | 
						|
	return op;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// For most compact varint encoding of common instructions, the instruction length should come out
 | 
						|
// into 3 bits (be <8). SPIR-V instruction lengths are always at least 1, and for some other
 | 
						|
// instructions they are guaranteed to be some other minimum length. Adjust the length before encoding,
 | 
						|
// and after decoding accordingly.
 | 
						|
 | 
						|
static uint32_t smolv_EncodeLen(SpvOp op, uint32_t len)
 | 
						|
{
 | 
						|
	len--;
 | 
						|
	if (op == SpvOpVectorShuffle)			len -= 4;
 | 
						|
	if (op == SpvOpVectorShuffleCompact)	len -= 4;
 | 
						|
	if (op == SpvOpDecorate)				len -= 2;
 | 
						|
	if (op == SpvOpLoad)					len -= 3;
 | 
						|
	if (op == SpvOpAccessChain)				len -= 3;
 | 
						|
	return len;
 | 
						|
}
 | 
						|
 | 
						|
static uint32_t smolv_DecodeLen(SpvOp op, uint32_t len)
 | 
						|
{
 | 
						|
	len++;
 | 
						|
	if (op == SpvOpVectorShuffle)			len += 4;
 | 
						|
	if (op == SpvOpVectorShuffleCompact)	len += 4;
 | 
						|
	if (op == SpvOpDecorate)				len += 2;
 | 
						|
	if (op == SpvOpLoad)					len += 3;
 | 
						|
	if (op == SpvOpAccessChain)				len += 3;
 | 
						|
	return len;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Shuffling bits of length + opcode to be more compact in varint encoding in typical cases:
 | 
						|
// 0x LLLL OOOO is how SPIR-V encodes it (L=length, O=op), we shuffle into:
 | 
						|
// 0x LLLO OOLO, so that common case (op<16, len<8) is encoded into one byte.
 | 
						|
 | 
						|
static bool smolv_WriteLengthOp(smolv::ByteArray& arr, uint32_t len, SpvOp op)
 | 
						|
{
 | 
						|
	len = smolv_EncodeLen(op, len);
 | 
						|
	// SPIR-V length field is 16 bits; if we get a larger value that means something
 | 
						|
	// was wrong, e.g. a vector shuffle instruction with less than 4 words (and our
 | 
						|
	// adjustment to common lengths in smolv_EncodeLen wrapped around)
 | 
						|
	if (len > 0xFFFF)
 | 
						|
		return false;
 | 
						|
	op = smolv_RemapOp(op);
 | 
						|
	uint32_t oplen = ((len >> 4) << 20) | ((op >> 4) << 8) | ((len & 0xF) << 4) | (op & 0xF);
 | 
						|
	smolv_WriteVarint(arr, oplen);
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
static bool smolv_ReadLengthOp(const uint8_t*& data, const uint8_t* dataEnd, uint32_t& outLen, SpvOp& outOp)
 | 
						|
{
 | 
						|
	uint32_t val;
 | 
						|
	if (!smolv_ReadVarint(data, dataEnd, val))
 | 
						|
		return false;
 | 
						|
	outLen = ((val >> 20) << 4) | ((val >> 4) & 0xF);
 | 
						|
	outOp = (SpvOp)(((val >> 4) & 0xFFF0) | (val & 0xF));
 | 
						|
 | 
						|
	outOp = smolv_RemapOp(outOp);
 | 
						|
	outLen = smolv_DecodeLen(outOp, outLen);
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
#define _SMOLV_READ_OP(len, words, op) \
 | 
						|
	uint32_t len = words[0] >> 16; \
 | 
						|
	if (len < 1) return false; /* malformed instruction, length needs to be at least 1 */ \
 | 
						|
	if (words + len > wordsEnd) return false; /* malformed instruction, goes past end of data */ \
 | 
						|
	SpvOp op = (SpvOp)(words[0] & 0xFFFF)
 | 
						|
 | 
						|
 | 
						|
bool smolv::Encode(const void* spirvData, size_t spirvSize, ByteArray& outSmolv, uint32_t flags, StripOpNameFilterFunc stripFilter)
 | 
						|
{
 | 
						|
	const size_t wordCount = spirvSize / 4;
 | 
						|
	if (wordCount * 4 != spirvSize)
 | 
						|
		return false;
 | 
						|
	const uint32_t* words = (const uint32_t*)spirvData;
 | 
						|
	const uint32_t* wordsEnd = words + wordCount;
 | 
						|
	if (!smolv_CheckSpirVHeader(words, wordCount))
 | 
						|
		return false;
 | 
						|
 | 
						|
	// reserve space in output (typical compression is to about 30%; reserve half of input space)
 | 
						|
	outSmolv.reserve(outSmolv.size() + spirvSize/2);
 | 
						|
 | 
						|
	// header (matches SPIR-V one, except different magic)
 | 
						|
	smolv_Write4(outSmolv, kSmolHeaderMagic);
 | 
						|
	smolv_Write4(outSmolv, (words[1] & 0x00FFFFFF) + (kSmolCurrEncodingVersion<<24)); // SPIR-V version (_XXX) + SMOL-V version (X___)
 | 
						|
	smolv_Write4(outSmolv, words[2]); // generator
 | 
						|
	smolv_Write4(outSmolv, words[3]); // bound
 | 
						|
	smolv_Write4(outSmolv, words[4]); // schema
 | 
						|
 | 
						|
	const size_t headerSpirvSizeOffset = outSmolv.size(); // size field may get updated later if stripping is enabled
 | 
						|
	smolv_Write4(outSmolv, (uint32_t)spirvSize); // space needed to decode (i.e. original SPIR-V size)
 | 
						|
 | 
						|
	size_t strippedSpirvWordCount = wordCount;
 | 
						|
	uint32_t prevResult = 0;
 | 
						|
	uint32_t prevDecorate = 0;
 | 
						|
	
 | 
						|
	const int knownOpsCount = smolv_GetKnownOpsCount(kSmolCurrEncodingVersion);
 | 
						|
 | 
						|
	words += 5;
 | 
						|
	while (words < wordsEnd)
 | 
						|
	{
 | 
						|
		_SMOLV_READ_OP(instrLen, words, op);
 | 
						|
 | 
						|
		if ((flags & kEncodeFlagStripDebugInfo) && smolv_OpDebugInfo(op, knownOpsCount))
 | 
						|
		{
 | 
						|
			if (!stripFilter || op != SpvOpName || !stripFilter(reinterpret_cast<const char*>(&words[2])))
 | 
						|
			{
 | 
						|
				strippedSpirvWordCount -= instrLen;
 | 
						|
				words += instrLen;
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// A usual case of vector shuffle, with less than 4 components, each with a value
 | 
						|
		// in [0..3] range: encode it in a more compact form, with the swizzle pattern in one byte.
 | 
						|
		// Turn this into a VectorShuffleCompact instruction, that takes up unused slot in Ops.
 | 
						|
		uint32_t swizzle = 0;
 | 
						|
		if (op == SpvOpVectorShuffle && instrLen <= 9)
 | 
						|
		{
 | 
						|
			uint32_t swz0 = instrLen > 5 ? words[5] : 0;
 | 
						|
			uint32_t swz1 = instrLen > 6 ? words[6] : 0;
 | 
						|
			uint32_t swz2 = instrLen > 7 ? words[7] : 0;
 | 
						|
			uint32_t swz3 = instrLen > 8 ? words[8] : 0;
 | 
						|
			if (swz0 < 4 && swz1 < 4 && swz2 < 4 && swz3 < 4)
 | 
						|
			{
 | 
						|
				op = SpvOpVectorShuffleCompact;
 | 
						|
				swizzle = (swz0 << 6) | (swz1 << 4) | (swz2 << 2) | (swz3);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// length + opcode
 | 
						|
		if (!smolv_WriteLengthOp(outSmolv, instrLen, op))
 | 
						|
			return false;
 | 
						|
 | 
						|
		size_t ioffs = 1;
 | 
						|
		// write type as varint, if we have it
 | 
						|
		if (smolv_OpHasType(op, knownOpsCount))
 | 
						|
		{
 | 
						|
			if (ioffs >= instrLen)
 | 
						|
				return false;
 | 
						|
			smolv_WriteVarint(outSmolv, words[ioffs]);
 | 
						|
			ioffs++;
 | 
						|
		}
 | 
						|
		// write result as delta+zig+varint, if we have it
 | 
						|
		if (smolv_OpHasResult(op, knownOpsCount))
 | 
						|
		{
 | 
						|
			if (ioffs >= instrLen)
 | 
						|
				return false;
 | 
						|
			uint32_t v = words[ioffs];
 | 
						|
			smolv_WriteVarint(outSmolv, smolv_ZigEncode(v - prevResult)); // some deltas are negative, use zig
 | 
						|
			prevResult = v;
 | 
						|
			ioffs++;
 | 
						|
		}
 | 
						|
 | 
						|
		// Decorate & MemberDecorate: IDs relative to previous decorate
 | 
						|
		if (op == SpvOpDecorate || op == SpvOpMemberDecorate)
 | 
						|
		{
 | 
						|
			if (ioffs >= instrLen)
 | 
						|
				return false;
 | 
						|
			uint32_t v = words[ioffs];
 | 
						|
			smolv_WriteVarint(outSmolv, smolv_ZigEncode(v - prevDecorate)); // spirv-remapped deltas often negative, use zig
 | 
						|
			prevDecorate = v;
 | 
						|
			ioffs++;
 | 
						|
		}
 | 
						|
 | 
						|
		// MemberDecorate special encoding: whole row of MemberDecorate instructions is often referring
 | 
						|
		// to the same type and linearly increasing member indices. Scan ahead to see how many we have,
 | 
						|
		// and encode whole bunch as one.
 | 
						|
		if (op == SpvOpMemberDecorate)
 | 
						|
		{
 | 
						|
			// scan ahead until we reach end, non-member-decoration or different type
 | 
						|
			const uint32_t decorationType = words[ioffs-1];
 | 
						|
			const uint32_t* memberWords = words;
 | 
						|
			uint32_t prevIndex = 0;
 | 
						|
			uint32_t prevOffset = 0;
 | 
						|
			// write a byte on how many we have encoded as a bunch
 | 
						|
			size_t countLocation = outSmolv.size();
 | 
						|
			outSmolv.push_back(0);
 | 
						|
			int count = 0;
 | 
						|
			while (memberWords < wordsEnd && count < 255)
 | 
						|
			{
 | 
						|
				_SMOLV_READ_OP(memberLen, memberWords, memberOp);
 | 
						|
				if (memberOp != SpvOpMemberDecorate)
 | 
						|
					break;
 | 
						|
				if (memberLen < 4)
 | 
						|
					return false; // invalid input
 | 
						|
				if (memberWords[1] != decorationType)
 | 
						|
					break;
 | 
						|
 | 
						|
				// write member index as delta from previous
 | 
						|
				uint32_t memberIndex = memberWords[2];
 | 
						|
				smolv_WriteVarint(outSmolv, memberIndex - prevIndex);
 | 
						|
				prevIndex = memberIndex;
 | 
						|
 | 
						|
				// decoration (and length if not common/known)
 | 
						|
				uint32_t memberDec = memberWords[3];
 | 
						|
				smolv_WriteVarint(outSmolv, memberDec);
 | 
						|
				const int knownExtraOps = smolv_DecorationExtraOps(memberDec);
 | 
						|
				if (knownExtraOps == -1)
 | 
						|
					smolv_WriteVarint(outSmolv, memberLen-4);
 | 
						|
				else if (unsigned(knownExtraOps) + 4 != memberLen)
 | 
						|
					return false; // invalid input
 | 
						|
 | 
						|
				// Offset decorations are most often linearly increasing, so encode as deltas
 | 
						|
				if (memberDec == 35) // Offset
 | 
						|
				{
 | 
						|
					if (memberLen != 5)
 | 
						|
						return false;
 | 
						|
					smolv_WriteVarint(outSmolv, memberWords[4]-prevOffset);
 | 
						|
					prevOffset = memberWords[4];
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					// write rest of decorations as varint
 | 
						|
					for (uint32_t i = 4; i < memberLen; ++i)
 | 
						|
						smolv_WriteVarint(outSmolv, memberWords[i]);
 | 
						|
				}
 | 
						|
 | 
						|
				memberWords += memberLen;
 | 
						|
				++count;
 | 
						|
			}
 | 
						|
			outSmolv[countLocation] = uint8_t(count);
 | 
						|
			words = memberWords;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		// Write out this many IDs, encoding them relative+zigzag to result ID
 | 
						|
		int relativeCount = smolv_OpDeltaFromResult(op, knownOpsCount);
 | 
						|
		for (int i = 0; i < relativeCount && ioffs < instrLen; ++i, ++ioffs)
 | 
						|
		{
 | 
						|
			if (ioffs >= instrLen)
 | 
						|
				return false;
 | 
						|
			uint32_t delta = prevResult - words[ioffs];
 | 
						|
			// some deltas are negative (often on branches, or if program was processed by spirv-remap),
 | 
						|
			// so use zig encoding
 | 
						|
			smolv_WriteVarint(outSmolv, smolv_ZigEncode(delta));
 | 
						|
		}
 | 
						|
 | 
						|
		if (op == SpvOpVectorShuffleCompact)
 | 
						|
		{
 | 
						|
			// compact vector shuffle, just write out single swizzle byte
 | 
						|
			outSmolv.push_back(uint8_t(swizzle));
 | 
						|
			ioffs = instrLen;
 | 
						|
		}
 | 
						|
		else if (smolv_OpVarRest(op, knownOpsCount))
 | 
						|
		{
 | 
						|
			// write out rest of words with variable encoding (expected to be small integers)
 | 
						|
			for (; ioffs < instrLen; ++ioffs)
 | 
						|
				smolv_WriteVarint(outSmolv, words[ioffs]);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			// write out rest of words without any encoding
 | 
						|
			for (; ioffs < instrLen; ++ioffs)
 | 
						|
				smolv_Write4(outSmolv, words[ioffs]);
 | 
						|
		}
 | 
						|
		
 | 
						|
		words += instrLen;
 | 
						|
	}
 | 
						|
 | 
						|
	if (strippedSpirvWordCount != wordCount)
 | 
						|
	{
 | 
						|
		uint8_t* headerSpirvSize = &outSmolv[headerSpirvSizeOffset];
 | 
						|
		smolv_Write4(headerSpirvSize, (uint32_t)strippedSpirvWordCount * 4);
 | 
						|
	}
 | 
						|
	
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
size_t smolv::GetDecodedBufferSize(const void* smolvData, size_t smolvSize)
 | 
						|
{
 | 
						|
	if (!smolv_CheckSmolHeader((const uint8_t*)smolvData, smolvSize))
 | 
						|
		return 0;
 | 
						|
	const uint32_t* words = (const uint32_t*)smolvData;
 | 
						|
	return words[5];
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool smolv::Decode(const void* smolvData, size_t smolvSize, void* spirvOutputBuffer, size_t spirvOutputBufferSize, uint32_t flags)
 | 
						|
{
 | 
						|
	// check header, and whether we have enough output buffer space
 | 
						|
	const size_t neededBufferSize = GetDecodedBufferSize(smolvData, smolvSize);
 | 
						|
	if (neededBufferSize == 0)
 | 
						|
		return false; // invalid SMOL-V
 | 
						|
	if (spirvOutputBufferSize < neededBufferSize)
 | 
						|
		return false; // not enough space in output buffer
 | 
						|
	if (spirvOutputBuffer == NULL)
 | 
						|
		return false; // output buffer is null
 | 
						|
 | 
						|
	const uint8_t* bytes = (const uint8_t*)smolvData;
 | 
						|
	const uint8_t* bytesEnd = bytes + smolvSize;
 | 
						|
 | 
						|
	uint8_t* outSpirv = (uint8_t*)spirvOutputBuffer;
 | 
						|
	
 | 
						|
	uint32_t val;
 | 
						|
	int smolVersion = 0;
 | 
						|
 | 
						|
	// header
 | 
						|
	smolv_Write4(outSpirv, kSpirVHeaderMagic); bytes += 4;
 | 
						|
	smolv_Read4(bytes, bytesEnd, val); smolVersion = val >> 24; val &= 0x00FFFFFF; smolv_Write4(outSpirv, val); // version
 | 
						|
	smolv_Read4(bytes, bytesEnd, val); smolv_Write4(outSpirv, val); // generator
 | 
						|
	smolv_Read4(bytes, bytesEnd, val); smolv_Write4(outSpirv, val); // bound
 | 
						|
	smolv_Read4(bytes, bytesEnd, val); smolv_Write4(outSpirv, val); // schema
 | 
						|
	bytes += 4; // decode buffer size
 | 
						|
	
 | 
						|
	// there are two SMOL-V encoding versions, both not indicating anything in their header version field:
 | 
						|
	// one that is called "before zero" here (2016-08-31 code). Support decoding that one only by presence
 | 
						|
	// of this special flag.
 | 
						|
	const bool beforeZeroVersion = smolVersion == 0 && (flags & kDecodeFlagUse20160831AsZeroVersion) != 0;
 | 
						|
 | 
						|
	const int knownOpsCount = smolv_GetKnownOpsCount(smolVersion);
 | 
						|
 | 
						|
	uint32_t prevResult = 0;
 | 
						|
	uint32_t prevDecorate = 0;
 | 
						|
 | 
						|
	while (bytes < bytesEnd)
 | 
						|
	{
 | 
						|
		// read length + opcode
 | 
						|
		uint32_t instrLen;
 | 
						|
		SpvOp op;
 | 
						|
		if (!smolv_ReadLengthOp(bytes, bytesEnd, instrLen, op))
 | 
						|
			return false;
 | 
						|
		const bool wasSwizzle = (op == SpvOpVectorShuffleCompact);
 | 
						|
		if (wasSwizzle)
 | 
						|
			op = SpvOpVectorShuffle;
 | 
						|
		smolv_Write4(outSpirv, (instrLen << 16) | op);
 | 
						|
 | 
						|
		size_t ioffs = 1;
 | 
						|
 | 
						|
		// read type as varint, if we have it
 | 
						|
		if (smolv_OpHasType(op, knownOpsCount))
 | 
						|
		{
 | 
						|
			if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
 | 
						|
			smolv_Write4(outSpirv, val);
 | 
						|
			ioffs++;
 | 
						|
		}
 | 
						|
		// read result as delta+varint, if we have it
 | 
						|
		if (smolv_OpHasResult(op, knownOpsCount))
 | 
						|
		{
 | 
						|
			if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
 | 
						|
			val = prevResult + smolv_ZigDecode(val);
 | 
						|
			smolv_Write4(outSpirv, val);
 | 
						|
			prevResult = val;
 | 
						|
			ioffs++;
 | 
						|
		}
 | 
						|
		
 | 
						|
		// Decorate: IDs relative to previous decorate
 | 
						|
		if (op == SpvOpDecorate || op == SpvOpMemberDecorate)
 | 
						|
		{
 | 
						|
			if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
 | 
						|
			// "before zero" version did not use zig encoding for the value
 | 
						|
			val = prevDecorate + (beforeZeroVersion ? val : smolv_ZigDecode(val));
 | 
						|
			smolv_Write4(outSpirv, val);
 | 
						|
			prevDecorate = val;
 | 
						|
			ioffs++;
 | 
						|
		}
 | 
						|
 | 
						|
		// MemberDecorate special decoding
 | 
						|
		if (op == SpvOpMemberDecorate && !beforeZeroVersion)
 | 
						|
		{
 | 
						|
			if (bytes >= bytesEnd)
 | 
						|
				return false; // broken input
 | 
						|
			int count = *bytes++;
 | 
						|
			int prevIndex = 0;
 | 
						|
			int prevOffset = 0;
 | 
						|
			for (int m = 0; m < count; ++m)
 | 
						|
			{
 | 
						|
				// read member index
 | 
						|
				uint32_t memberIndex;
 | 
						|
				if (!smolv_ReadVarint(bytes, bytesEnd, memberIndex)) return false;
 | 
						|
				memberIndex += prevIndex;
 | 
						|
				prevIndex = memberIndex;
 | 
						|
				
 | 
						|
				// decoration (and length if not common/known)
 | 
						|
				uint32_t memberDec;
 | 
						|
				if (!smolv_ReadVarint(bytes, bytesEnd, memberDec)) return false;
 | 
						|
				const int knownExtraOps = smolv_DecorationExtraOps(memberDec);
 | 
						|
				uint32_t memberLen;
 | 
						|
				if (knownExtraOps == -1)
 | 
						|
				{
 | 
						|
					if (!smolv_ReadVarint(bytes, bytesEnd, memberLen)) return false;
 | 
						|
					memberLen += 4;
 | 
						|
				}
 | 
						|
				else
 | 
						|
					memberLen = 4 + knownExtraOps;
 | 
						|
 | 
						|
				// write SPIR-V op+length (unless it's first member decoration, in which case it was written before)
 | 
						|
				if (m != 0)
 | 
						|
				{
 | 
						|
					smolv_Write4(outSpirv, (memberLen << 16) | op);
 | 
						|
					smolv_Write4(outSpirv, prevDecorate);
 | 
						|
				}
 | 
						|
				smolv_Write4(outSpirv, memberIndex);
 | 
						|
				smolv_Write4(outSpirv, memberDec);
 | 
						|
				// Special case for Offset decorations
 | 
						|
				if (memberDec == 35) // Offset
 | 
						|
				{
 | 
						|
					if (memberLen != 5)
 | 
						|
						return false;
 | 
						|
					if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
 | 
						|
					val += prevOffset;
 | 
						|
					smolv_Write4(outSpirv, val);
 | 
						|
					prevOffset = val;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					for (uint32_t i = 4; i < memberLen; ++i)
 | 
						|
					{
 | 
						|
						if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
 | 
						|
						smolv_Write4(outSpirv, val);
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		// Read this many IDs, that are relative to result ID
 | 
						|
		int relativeCount = smolv_OpDeltaFromResult(op, knownOpsCount);
 | 
						|
		// "before zero" version only used zig encoding for IDs of several ops; after
 | 
						|
		// that ops got zig encoding for their IDs
 | 
						|
		bool zigDecodeVals = true;
 | 
						|
		if (beforeZeroVersion)
 | 
						|
		{
 | 
						|
			if (op != SpvOpControlBarrier && op != SpvOpMemoryBarrier && op != SpvOpLoopMerge && op != SpvOpSelectionMerge && op != SpvOpBranch && op != SpvOpBranchConditional && op != SpvOpMemoryNamedBarrier)
 | 
						|
				zigDecodeVals = false;
 | 
						|
		}
 | 
						|
		for (int i = 0; i < relativeCount && ioffs < instrLen; ++i, ++ioffs)
 | 
						|
		{
 | 
						|
			if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
 | 
						|
			if (zigDecodeVals)
 | 
						|
				val = smolv_ZigDecode(val);
 | 
						|
			smolv_Write4(outSpirv, prevResult - val);
 | 
						|
		}
 | 
						|
 | 
						|
		if (wasSwizzle && instrLen <= 9)
 | 
						|
		{
 | 
						|
			uint32_t swizzle = *bytes++;
 | 
						|
			if (instrLen > 5) smolv_Write4(outSpirv, (swizzle >> 6) & 3);
 | 
						|
			if (instrLen > 6) smolv_Write4(outSpirv, (swizzle >> 4) & 3);
 | 
						|
			if (instrLen > 7) smolv_Write4(outSpirv, (swizzle >> 2) & 3);
 | 
						|
			if (instrLen > 8) smolv_Write4(outSpirv, swizzle & 3);
 | 
						|
		}
 | 
						|
		else if (smolv_OpVarRest(op, knownOpsCount))
 | 
						|
		{
 | 
						|
			// read rest of words with variable encoding
 | 
						|
			for (; ioffs < instrLen; ++ioffs)
 | 
						|
			{
 | 
						|
				if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
 | 
						|
				smolv_Write4(outSpirv, val);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			// read rest of words without any encoding
 | 
						|
			for (; ioffs < instrLen; ++ioffs)
 | 
						|
			{
 | 
						|
				if (!smolv_Read4(bytes, bytesEnd, val)) return false;
 | 
						|
				smolv_Write4(outSpirv, val);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if ((uint8_t*)spirvOutputBuffer + neededBufferSize != outSpirv)
 | 
						|
		return false; // something went wrong during decoding? we should have decoded to exact output size
 | 
						|
	
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
// --------------------------------------------------------------------------------------------
 | 
						|
// Calculating instruction count / space stats on SPIR-V and SMOL-V
 | 
						|
 | 
						|
 | 
						|
struct smolv::Stats
 | 
						|
{
 | 
						|
	Stats() { memset(this, 0, sizeof(*this)); }
 | 
						|
	size_t opCounts[kKnownOpsCount];
 | 
						|
	size_t opSizes[kKnownOpsCount];
 | 
						|
	size_t smolOpSizes[kKnownOpsCount];
 | 
						|
	size_t varintCountsOp[6];
 | 
						|
	size_t varintCountsType[6];
 | 
						|
	size_t varintCountsRes[6];
 | 
						|
	size_t varintCountsOther[6];
 | 
						|
	size_t totalOps;
 | 
						|
	size_t totalSize;
 | 
						|
	size_t totalSizeSmol;
 | 
						|
	size_t inputCount;
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
smolv::Stats* smolv::StatsCreate()
 | 
						|
{
 | 
						|
	return new Stats();
 | 
						|
}
 | 
						|
 | 
						|
void smolv::StatsDelete(smolv::Stats *s)
 | 
						|
{
 | 
						|
	delete s;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool smolv::StatsCalculate(smolv::Stats* stats, const void* spirvData, size_t spirvSize)
 | 
						|
{
 | 
						|
	if (!stats)
 | 
						|
		return false;
 | 
						|
 | 
						|
	const size_t wordCount = spirvSize / 4;
 | 
						|
	if (wordCount * 4 != spirvSize)
 | 
						|
		return false;
 | 
						|
	const uint32_t* words = (const uint32_t*)spirvData;
 | 
						|
	const uint32_t* wordsEnd = words + wordCount;
 | 
						|
	if (!smolv_CheckSpirVHeader(words, wordCount))
 | 
						|
		return false;
 | 
						|
	words += 5;
 | 
						|
	
 | 
						|
	stats->inputCount++;
 | 
						|
	stats->totalSize += wordCount;
 | 
						|
 | 
						|
	while (words < wordsEnd)
 | 
						|
	{
 | 
						|
		_SMOLV_READ_OP(instrLen, words, op);
 | 
						|
 | 
						|
		if (op < kKnownOpsCount)
 | 
						|
		{
 | 
						|
			stats->opCounts[op]++;
 | 
						|
			stats->opSizes[op] += instrLen;
 | 
						|
		}
 | 
						|
		words += instrLen;
 | 
						|
		stats->totalOps++;
 | 
						|
	}
 | 
						|
	
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
bool smolv::StatsCalculateSmol(smolv::Stats* stats, const void* smolvData, size_t smolvSize)
 | 
						|
{
 | 
						|
	if (!stats)
 | 
						|
		return false;
 | 
						|
 | 
						|
	// debugging helper to dump all encoded bytes to stdout, keep at "if 0"
 | 
						|
#	if 0
 | 
						|
#		define _SMOLV_DEBUG_PRINT_ENCODED_BYTES() { \
 | 
						|
			printf("Op %-22s ", op < kKnownOpsCount ? kSpirvOpNames[op] : "???"); \
 | 
						|
			for (const uint8_t* b = instrBegin; b < bytes; ++b) \
 | 
						|
				printf("%02x ", *b); \
 | 
						|
			printf("\n"); \
 | 
						|
		}
 | 
						|
#	else
 | 
						|
#		define _SMOLV_DEBUG_PRINT_ENCODED_BYTES() {}
 | 
						|
#	endif
 | 
						|
	
 | 
						|
	const uint8_t* bytes = (const uint8_t*)smolvData;
 | 
						|
	const uint8_t* bytesEnd = bytes + smolvSize;
 | 
						|
	if (!smolv_CheckSmolHeader(bytes, smolvSize))
 | 
						|
		return false;
 | 
						|
 | 
						|
	uint32_t val;
 | 
						|
	int smolVersion;
 | 
						|
	bytes += 4;
 | 
						|
	smolv_Read4(bytes, bytesEnd, val); smolVersion = val >> 24;
 | 
						|
	const int knownOpsCount = smolv_GetKnownOpsCount(smolVersion);
 | 
						|
	bytes += 16;
 | 
						|
	
 | 
						|
	stats->totalSizeSmol += smolvSize;
 | 
						|
	
 | 
						|
	while (bytes < bytesEnd)
 | 
						|
	{
 | 
						|
		const uint8_t* instrBegin = bytes;
 | 
						|
		const uint8_t* varBegin;
 | 
						|
 | 
						|
		// read length + opcode
 | 
						|
		uint32_t instrLen;
 | 
						|
		SpvOp op;
 | 
						|
		varBegin = bytes;
 | 
						|
		if (!smolv_ReadLengthOp(bytes, bytesEnd, instrLen, op))
 | 
						|
			return false;
 | 
						|
		const bool wasSwizzle = (op == SpvOpVectorShuffleCompact);
 | 
						|
		if (wasSwizzle)
 | 
						|
			op = SpvOpVectorShuffle;
 | 
						|
		stats->varintCountsOp[bytes-varBegin]++;
 | 
						|
		
 | 
						|
		size_t ioffs = 1;
 | 
						|
		if (smolv_OpHasType(op, knownOpsCount))
 | 
						|
		{
 | 
						|
			varBegin = bytes;
 | 
						|
			if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
 | 
						|
			stats->varintCountsType[bytes-varBegin]++;
 | 
						|
			ioffs++;
 | 
						|
		}
 | 
						|
		if (smolv_OpHasResult(op, knownOpsCount))
 | 
						|
		{
 | 
						|
			varBegin = bytes;
 | 
						|
			if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
 | 
						|
			stats->varintCountsRes[bytes-varBegin]++;
 | 
						|
			ioffs++;
 | 
						|
		}
 | 
						|
		
 | 
						|
		if (op == SpvOpDecorate || op == SpvOpMemberDecorate)
 | 
						|
		{
 | 
						|
			if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
 | 
						|
			ioffs++;
 | 
						|
		}
 | 
						|
		// MemberDecorate special decoding
 | 
						|
		if (op == SpvOpMemberDecorate)
 | 
						|
		{
 | 
						|
			if (bytes >= bytesEnd)
 | 
						|
				return false; // broken input
 | 
						|
			int count = *bytes++;
 | 
						|
			for (int m = 0; m < count; ++m)
 | 
						|
			{
 | 
						|
				uint32_t memberIndex;
 | 
						|
				if (!smolv_ReadVarint(bytes, bytesEnd, memberIndex)) return false;
 | 
						|
				uint32_t memberDec;
 | 
						|
				if (!smolv_ReadVarint(bytes, bytesEnd, memberDec)) return false;
 | 
						|
				const int knownExtraOps = smolv_DecorationExtraOps(memberDec);
 | 
						|
				uint32_t memberLen;
 | 
						|
				if (knownExtraOps == -1)
 | 
						|
				{
 | 
						|
					if (!smolv_ReadVarint(bytes, bytesEnd, memberLen)) return false;
 | 
						|
					memberLen += 4;
 | 
						|
				}
 | 
						|
				else
 | 
						|
					memberLen = 4 + knownExtraOps;
 | 
						|
				for (uint32_t i = 4; i < memberLen; ++i)
 | 
						|
				{
 | 
						|
					if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			stats->smolOpSizes[op] += bytes - instrBegin;
 | 
						|
			_SMOLV_DEBUG_PRINT_ENCODED_BYTES();
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		int relativeCount = smolv_OpDeltaFromResult(op, knownOpsCount);
 | 
						|
		for (int i = 0; i < relativeCount && ioffs < instrLen; ++i, ++ioffs)
 | 
						|
		{
 | 
						|
			varBegin = bytes;
 | 
						|
			if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
 | 
						|
			stats->varintCountsRes[bytes-varBegin]++;
 | 
						|
		}
 | 
						|
 | 
						|
		if (wasSwizzle && instrLen <= 9)
 | 
						|
		{
 | 
						|
			bytes++;
 | 
						|
		}
 | 
						|
		else if (smolv_OpVarRest(op, knownOpsCount))
 | 
						|
		{
 | 
						|
			for (; ioffs < instrLen; ++ioffs)
 | 
						|
			{
 | 
						|
				varBegin = bytes;
 | 
						|
				if (!smolv_ReadVarint(bytes, bytesEnd, val)) return false;
 | 
						|
				stats->varintCountsOther[bytes-varBegin]++;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			for (; ioffs < instrLen; ++ioffs)
 | 
						|
			{
 | 
						|
				if (!smolv_Read4(bytes, bytesEnd, val)) return false;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		
 | 
						|
		if (op < kKnownOpsCount)
 | 
						|
		{
 | 
						|
			stats->smolOpSizes[op] += bytes - instrBegin;
 | 
						|
		}
 | 
						|
		_SMOLV_DEBUG_PRINT_ENCODED_BYTES();
 | 
						|
	}
 | 
						|
	
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
static bool CompareOpCounters (std::pair<SpvOp,size_t> a, std::pair<SpvOp,size_t> b)
 | 
						|
{
 | 
						|
	return a.second > b.second;
 | 
						|
}
 | 
						|
 | 
						|
void smolv::StatsPrint(const Stats* stats)
 | 
						|
{
 | 
						|
	if (!stats)
 | 
						|
		return;
 | 
						|
 | 
						|
	typedef std::pair<SpvOp,size_t> OpCounter;
 | 
						|
	OpCounter counts[kKnownOpsCount];
 | 
						|
	OpCounter sizes[kKnownOpsCount];
 | 
						|
	OpCounter sizesSmol[kKnownOpsCount];
 | 
						|
	for (int i = 0; i < kKnownOpsCount; ++i)
 | 
						|
	{
 | 
						|
		counts[i].first = (SpvOp)i;
 | 
						|
		counts[i].second = stats->opCounts[i];
 | 
						|
		sizes[i].first = (SpvOp)i;
 | 
						|
		sizes[i].second = stats->opSizes[i];
 | 
						|
		sizesSmol[i].first = (SpvOp)i;
 | 
						|
		sizesSmol[i].second = stats->smolOpSizes[i];
 | 
						|
	}
 | 
						|
	std::sort(counts, counts + kKnownOpsCount, CompareOpCounters);
 | 
						|
	std::sort(sizes, sizes + kKnownOpsCount, CompareOpCounters);
 | 
						|
	std::sort(sizesSmol, sizesSmol + kKnownOpsCount, CompareOpCounters);
 | 
						|
	
 | 
						|
	printf("Stats for %i SPIR-V inputs, total size %i words (%.1fKB):\n", (int)stats->inputCount, (int)stats->totalSize, stats->totalSize * 4.0f / 1024.0f);
 | 
						|
	printf("Most occuring ops:\n");
 | 
						|
	for (int i = 0; i < 30; ++i)
 | 
						|
	{
 | 
						|
		SpvOp op = counts[i].first;
 | 
						|
		printf(" #%2i: %4i %-20s %4i (%4.1f%%)\n", i, op, kSpirvOpNames[op], (int)counts[i].second, (float)counts[i].second / (float)stats->totalOps * 100.0f);
 | 
						|
	}
 | 
						|
	printf("Largest total size of ops:\n");
 | 
						|
	for (int i = 0; i < 30; ++i)
 | 
						|
	{
 | 
						|
		SpvOp op = sizes[i].first;
 | 
						|
		printf(" #%2i: %-22s %6i (%4.1f%%) avg len %.1f\n",
 | 
						|
			   i,
 | 
						|
			   kSpirvOpNames[op],
 | 
						|
			   (int)sizes[i].second*4,
 | 
						|
			   (float)sizes[i].second / (float)stats->totalSize * 100.0f,
 | 
						|
			   (float)sizes[i].second*4 / (float)stats->opCounts[op]
 | 
						|
		);
 | 
						|
	}
 | 
						|
	printf("SMOL varint encoding counts per byte length:\n");
 | 
						|
	printf("  B: %6s %6s %6s %6s\n", "Op", "Type", "Result", "Other");
 | 
						|
	for (int i = 1; i < 6; ++i)
 | 
						|
	{
 | 
						|
		printf("  %i: %6i %6i %6i %6i\n", i, (int)stats->varintCountsOp[i], (int)stats->varintCountsType[i], (int)stats->varintCountsRes[i], (int)stats->varintCountsOther[i]);
 | 
						|
	}
 | 
						|
	printf("Largest total size of ops in SMOL:\n");
 | 
						|
	for (int i = 0; i < 30; ++i)
 | 
						|
	{
 | 
						|
		SpvOp op = sizesSmol[i].first;
 | 
						|
		printf(" #%2i: %-22s %6i (%4.1f%%) avg len %.1f\n",
 | 
						|
			   i,
 | 
						|
			   kSpirvOpNames[op],
 | 
						|
			   (int)sizesSmol[i].second,
 | 
						|
			   (float)sizesSmol[i].second / (float)stats->totalSizeSmol * 100.0f,
 | 
						|
			   (float)sizesSmol[i].second / (float)stats->opCounts[op]
 | 
						|
		);
 | 
						|
	}	
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// ------------------------------------------------------------------------------
 | 
						|
// This software is available under 2 licenses -- choose whichever you prefer.
 | 
						|
// ------------------------------------------------------------------------------
 | 
						|
// ALTERNATIVE A - MIT License
 | 
						|
// Copyright (c) 2016-2020 Aras Pranckevicius
 | 
						|
// Permission is hereby granted, free of charge, to any person obtaining a copy of
 | 
						|
// this software and associated documentation files (the "Software"), to deal in
 | 
						|
// the Software without restriction, including without limitation the rights to
 | 
						|
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 | 
						|
// of the Software, and to permit persons to whom the Software is furnished to do
 | 
						|
// so, subject to the following conditions:
 | 
						|
// The above copyright notice and this permission notice shall be included in all
 | 
						|
// copies or substantial portions of the Software.
 | 
						|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
						|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
						|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
						|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
						|
// SOFTWARE.
 | 
						|
// ------------------------------------------------------------------------------
 | 
						|
// ALTERNATIVE B - Public Domain (www.unlicense.org)
 | 
						|
// This is free and unencumbered software released into the public domain.
 | 
						|
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
 | 
						|
// software, either in source code form or as a compiled binary, for any purpose,
 | 
						|
// commercial or non-commercial, and by any means.
 | 
						|
// In jurisdictions that recognize copyright laws, the author or authors of this
 | 
						|
// software dedicate any and all copyright interest in the software to the public
 | 
						|
// domain. We make this dedication for the benefit of the public at large and to
 | 
						|
// the detriment of our heirs and successors. We intend this dedication to be an
 | 
						|
// overt act of relinquishment in perpetuity of all present and future rights to
 | 
						|
// this software under copyright law.
 | 
						|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
						|
// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 | 
						|
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 | 
						|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | 
						|
// ------------------------------------------------------------------------------
 |