From 9d92b4fd0e1ca655179619fbacf0325c735b6f38 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 27 Apr 2015 21:13:44 -0700 Subject: [PATCH 01/55] nir: Import the revision 30 SPIR-V header from Khronos --- src/glsl/nir/spirv.h | 1304 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1304 insertions(+) create mode 100644 src/glsl/nir/spirv.h diff --git a/src/glsl/nir/spirv.h b/src/glsl/nir/spirv.h new file mode 100644 index 00000000000..93135c09596 --- /dev/null +++ b/src/glsl/nir/spirv.h @@ -0,0 +1,1304 @@ +/* +** Copyright (c) 2015 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"), +** to deal in the Materials without restriction, including without limitation +** the rights to use, copy, modify, merge, publish, distribute, sublicense, +** and/or sell copies of the Materials, and to permit persons to whom the +** Materials are 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 Materials. +** +** MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS +** STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND +** HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/ +** +** THE MATERIALS ARE 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 MATERIALS OR THE USE OR OTHER DEALINGS +** IN THE MATERIALS. +*/ + +/* +** This header is automatically generated by the same tool that creates +** the Binary Section of the SPIR-V specification. +*/ + +/* +** Specification revision 30. +** Enumeration tokens for SPIR-V, in three styles: C, C++, generic. +** - C++ will have the tokens in the "spv" name space, with no prefix. +** - C will have tokens with as "Spv" prefix. +** +** Some tokens act like mask values, which can be OR'd together, +** while others are mutually exclusive. The mask-like ones have +** "Mask" in their name, and a parallel enum that has the shift +** amount (1 << x) for each corresponding enumerant. +*/ + +#ifndef spirv_H +#define spirv_H + +#ifdef __cplusplus + +namespace spv { + +const int MagicNumber = 0x07230203; +const int Version = 99; + +typedef unsigned int Id; + +const unsigned int OpCodeMask = 0xFFFF; +const unsigned int WordCountShift = 16; + +enum SourceLanguage { + SourceLanguageUnknown = 0, + SourceLanguageESSL = 1, + SourceLanguageGLSL = 2, + SourceLanguageOpenCL = 3, +}; + +enum ExecutionModel { + ExecutionModelVertex = 0, + ExecutionModelTessellationControl = 1, + ExecutionModelTessellationEvaluation = 2, + ExecutionModelGeometry = 3, + ExecutionModelFragment = 4, + ExecutionModelGLCompute = 5, + ExecutionModelKernel = 6, +}; + +enum AddressingModel { + AddressingModelLogical = 0, + AddressingModelPhysical32 = 1, + AddressingModelPhysical64 = 2, +}; + +enum MemoryModel { + MemoryModelSimple = 0, + MemoryModelGLSL450 = 1, + MemoryModelOpenCL12 = 2, + MemoryModelOpenCL20 = 3, + MemoryModelOpenCL21 = 4, +}; + +enum ExecutionMode { + ExecutionModeInvocations = 0, + ExecutionModeSpacingEqual = 1, + ExecutionModeSpacingFractionalEven = 2, + ExecutionModeSpacingFractionalOdd = 3, + ExecutionModeVertexOrderCw = 4, + ExecutionModeVertexOrderCcw = 5, + ExecutionModePixelCenterInteger = 6, + ExecutionModeOriginUpperLeft = 7, + ExecutionModeEarlyFragmentTests = 8, + ExecutionModePointMode = 9, + ExecutionModeXfb = 10, + ExecutionModeDepthReplacing = 11, + ExecutionModeDepthAny = 12, + ExecutionModeDepthGreater = 13, + ExecutionModeDepthLess = 14, + ExecutionModeDepthUnchanged = 15, + ExecutionModeLocalSize = 16, + ExecutionModeLocalSizeHint = 17, + ExecutionModeInputPoints = 18, + ExecutionModeInputLines = 19, + ExecutionModeInputLinesAdjacency = 20, + ExecutionModeInputTriangles = 21, + ExecutionModeInputTrianglesAdjacency = 22, + ExecutionModeInputQuads = 23, + ExecutionModeInputIsolines = 24, + ExecutionModeOutputVertices = 25, + ExecutionModeOutputPoints = 26, + ExecutionModeOutputLineStrip = 27, + ExecutionModeOutputTriangleStrip = 28, + ExecutionModeVecTypeHint = 29, + ExecutionModeContractionOff = 30, +}; + +enum StorageClass { + StorageClassUniformConstant = 0, + StorageClassInput = 1, + StorageClassUniform = 2, + StorageClassOutput = 3, + StorageClassWorkgroupLocal = 4, + StorageClassWorkgroupGlobal = 5, + StorageClassPrivateGlobal = 6, + StorageClassFunction = 7, + StorageClassGeneric = 8, + StorageClassPrivate = 9, + StorageClassAtomicCounter = 10, +}; + +enum Dim { + Dim1D = 0, + Dim2D = 1, + Dim3D = 2, + DimCube = 3, + DimRect = 4, + DimBuffer = 5, +}; + +enum SamplerAddressingMode { + SamplerAddressingModeNone = 0, + SamplerAddressingModeClampToEdge = 1, + SamplerAddressingModeClamp = 2, + SamplerAddressingModeRepeat = 3, + SamplerAddressingModeRepeatMirrored = 4, +}; + +enum SamplerFilterMode { + SamplerFilterModeNearest = 0, + SamplerFilterModeLinear = 1, +}; + +enum FPFastMathModeShift { + FPFastMathModeNotNaNShift = 0, + FPFastMathModeNotInfShift = 1, + FPFastMathModeNSZShift = 2, + FPFastMathModeAllowRecipShift = 3, + FPFastMathModeFastShift = 4, +}; + +enum FPFastMathModeMask { + FPFastMathModeMaskNone = 0, + FPFastMathModeNotNaNMask = 0x00000001, + FPFastMathModeNotInfMask = 0x00000002, + FPFastMathModeNSZMask = 0x00000004, + FPFastMathModeAllowRecipMask = 0x00000008, + FPFastMathModeFastMask = 0x00000010, +}; + +enum FPRoundingMode { + FPRoundingModeRTE = 0, + FPRoundingModeRTZ = 1, + FPRoundingModeRTP = 2, + FPRoundingModeRTN = 3, +}; + +enum LinkageType { + LinkageTypeExport = 0, + LinkageTypeImport = 1, +}; + +enum AccessQualifier { + AccessQualifierReadOnly = 0, + AccessQualifierWriteOnly = 1, + AccessQualifierReadWrite = 2, +}; + +enum FunctionParameterAttribute { + FunctionParameterAttributeZext = 0, + FunctionParameterAttributeSext = 1, + FunctionParameterAttributeByVal = 2, + FunctionParameterAttributeSret = 3, + FunctionParameterAttributeNoAlias = 4, + FunctionParameterAttributeNoCapture = 5, + FunctionParameterAttributeSVM = 6, + FunctionParameterAttributeNoWrite = 7, + FunctionParameterAttributeNoReadWrite = 8, +}; + +enum Decoration { + DecorationPrecisionLow = 0, + DecorationPrecisionMedium = 1, + DecorationPrecisionHigh = 2, + DecorationBlock = 3, + DecorationBufferBlock = 4, + DecorationRowMajor = 5, + DecorationColMajor = 6, + DecorationGLSLShared = 7, + DecorationGLSLStd140 = 8, + DecorationGLSLStd430 = 9, + DecorationGLSLPacked = 10, + DecorationSmooth = 11, + DecorationNoperspective = 12, + DecorationFlat = 13, + DecorationPatch = 14, + DecorationCentroid = 15, + DecorationSample = 16, + DecorationInvariant = 17, + DecorationRestrict = 18, + DecorationAliased = 19, + DecorationVolatile = 20, + DecorationConstant = 21, + DecorationCoherent = 22, + DecorationNonwritable = 23, + DecorationNonreadable = 24, + DecorationUniform = 25, + DecorationNoStaticUse = 26, + DecorationCPacked = 27, + DecorationSaturatedConversion = 28, + DecorationStream = 29, + DecorationLocation = 30, + DecorationComponent = 31, + DecorationIndex = 32, + DecorationBinding = 33, + DecorationDescriptorSet = 34, + DecorationOffset = 35, + DecorationAlignment = 36, + DecorationXfbBuffer = 37, + DecorationStride = 38, + DecorationBuiltIn = 39, + DecorationFuncParamAttr = 40, + DecorationFPRoundingMode = 41, + DecorationFPFastMathMode = 42, + DecorationLinkageAttributes = 43, + DecorationSpecId = 44, +}; + +enum BuiltIn { + BuiltInPosition = 0, + BuiltInPointSize = 1, + BuiltInClipVertex = 2, + BuiltInClipDistance = 3, + BuiltInCullDistance = 4, + BuiltInVertexId = 5, + BuiltInInstanceId = 6, + BuiltInPrimitiveId = 7, + BuiltInInvocationId = 8, + BuiltInLayer = 9, + BuiltInViewportIndex = 10, + BuiltInTessLevelOuter = 11, + BuiltInTessLevelInner = 12, + BuiltInTessCoord = 13, + BuiltInPatchVertices = 14, + BuiltInFragCoord = 15, + BuiltInPointCoord = 16, + BuiltInFrontFacing = 17, + BuiltInSampleId = 18, + BuiltInSamplePosition = 19, + BuiltInSampleMask = 20, + BuiltInFragColor = 21, + BuiltInFragDepth = 22, + BuiltInHelperInvocation = 23, + BuiltInNumWorkgroups = 24, + BuiltInWorkgroupSize = 25, + BuiltInWorkgroupId = 26, + BuiltInLocalInvocationId = 27, + BuiltInGlobalInvocationId = 28, + BuiltInLocalInvocationIndex = 29, + BuiltInWorkDim = 30, + BuiltInGlobalSize = 31, + BuiltInEnqueuedWorkgroupSize = 32, + BuiltInGlobalOffset = 33, + BuiltInGlobalLinearId = 34, + BuiltInWorkgroupLinearId = 35, + BuiltInSubgroupSize = 36, + BuiltInSubgroupMaxSize = 37, + BuiltInNumSubgroups = 38, + BuiltInNumEnqueuedSubgroups = 39, + BuiltInSubgroupId = 40, + BuiltInSubgroupLocalInvocationId = 41, +}; + +enum SelectionControlShift { + SelectionControlFlattenShift = 0, + SelectionControlDontFlattenShift = 1, +}; + +enum SelectionControlMask { + SelectionControlMaskNone = 0, + SelectionControlFlattenMask = 0x00000001, + SelectionControlDontFlattenMask = 0x00000002, +}; + +enum LoopControlShift { + LoopControlUnrollShift = 0, + LoopControlDontUnrollShift = 1, +}; + +enum LoopControlMask { + LoopControlMaskNone = 0, + LoopControlUnrollMask = 0x00000001, + LoopControlDontUnrollMask = 0x00000002, +}; + +enum FunctionControlShift { + FunctionControlInlineShift = 0, + FunctionControlDontInlineShift = 1, + FunctionControlPureShift = 2, + FunctionControlConstShift = 3, +}; + +enum FunctionControlMask { + FunctionControlMaskNone = 0, + FunctionControlInlineMask = 0x00000001, + FunctionControlDontInlineMask = 0x00000002, + FunctionControlPureMask = 0x00000004, + FunctionControlConstMask = 0x00000008, +}; + +enum MemorySemanticsShift { + MemorySemanticsRelaxedShift = 0, + MemorySemanticsSequentiallyConsistentShift = 1, + MemorySemanticsAcquireShift = 2, + MemorySemanticsReleaseShift = 3, + MemorySemanticsUniformMemoryShift = 4, + MemorySemanticsSubgroupMemoryShift = 5, + MemorySemanticsWorkgroupLocalMemoryShift = 6, + MemorySemanticsWorkgroupGlobalMemoryShift = 7, + MemorySemanticsAtomicCounterMemoryShift = 8, + MemorySemanticsImageMemoryShift = 9, +}; + +enum MemorySemanticsMask { + MemorySemanticsMaskNone = 0, + MemorySemanticsRelaxedMask = 0x00000001, + MemorySemanticsSequentiallyConsistentMask = 0x00000002, + MemorySemanticsAcquireMask = 0x00000004, + MemorySemanticsReleaseMask = 0x00000008, + MemorySemanticsUniformMemoryMask = 0x00000010, + MemorySemanticsSubgroupMemoryMask = 0x00000020, + MemorySemanticsWorkgroupLocalMemoryMask = 0x00000040, + MemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080, + MemorySemanticsAtomicCounterMemoryMask = 0x00000100, + MemorySemanticsImageMemoryMask = 0x00000200, +}; + +enum MemoryAccessShift { + MemoryAccessVolatileShift = 0, + MemoryAccessAlignedShift = 1, +}; + +enum MemoryAccessMask { + MemoryAccessMaskNone = 0, + MemoryAccessVolatileMask = 0x00000001, + MemoryAccessAlignedMask = 0x00000002, +}; + +enum ExecutionScope { + ExecutionScopeCrossDevice = 0, + ExecutionScopeDevice = 1, + ExecutionScopeWorkgroup = 2, + ExecutionScopeSubgroup = 3, +}; + +enum GroupOperation { + GroupOperationReduce = 0, + GroupOperationInclusiveScan = 1, + GroupOperationExclusiveScan = 2, +}; + +enum KernelEnqueueFlags { + KernelEnqueueFlagsNoWait = 0, + KernelEnqueueFlagsWaitKernel = 1, + KernelEnqueueFlagsWaitWorkGroup = 2, +}; + +enum KernelProfilingInfoShift { + KernelProfilingInfoCmdExecTimeShift = 0, +}; + +enum KernelProfilingInfoMask { + KernelProfilingInfoMaskNone = 0, + KernelProfilingInfoCmdExecTimeMask = 0x00000001, +}; + +enum Op { + OpNop = 0, + OpSource = 1, + OpSourceExtension = 2, + OpExtension = 3, + OpExtInstImport = 4, + OpMemoryModel = 5, + OpEntryPoint = 6, + OpExecutionMode = 7, + OpTypeVoid = 8, + OpTypeBool = 9, + OpTypeInt = 10, + OpTypeFloat = 11, + OpTypeVector = 12, + OpTypeMatrix = 13, + OpTypeSampler = 14, + OpTypeFilter = 15, + OpTypeArray = 16, + OpTypeRuntimeArray = 17, + OpTypeStruct = 18, + OpTypeOpaque = 19, + OpTypePointer = 20, + OpTypeFunction = 21, + OpTypeEvent = 22, + OpTypeDeviceEvent = 23, + OpTypeReserveId = 24, + OpTypeQueue = 25, + OpTypePipe = 26, + OpConstantTrue = 27, + OpConstantFalse = 28, + OpConstant = 29, + OpConstantComposite = 30, + OpConstantSampler = 31, + OpConstantNullPointer = 32, + OpConstantNullObject = 33, + OpSpecConstantTrue = 34, + OpSpecConstantFalse = 35, + OpSpecConstant = 36, + OpSpecConstantComposite = 37, + OpVariable = 38, + OpVariableArray = 39, + OpFunction = 40, + OpFunctionParameter = 41, + OpFunctionEnd = 42, + OpFunctionCall = 43, + OpExtInst = 44, + OpUndef = 45, + OpLoad = 46, + OpStore = 47, + OpPhi = 48, + OpDecorationGroup = 49, + OpDecorate = 50, + OpMemberDecorate = 51, + OpGroupDecorate = 52, + OpGroupMemberDecorate = 53, + OpName = 54, + OpMemberName = 55, + OpString = 56, + OpLine = 57, + OpVectorExtractDynamic = 58, + OpVectorInsertDynamic = 59, + OpVectorShuffle = 60, + OpCompositeConstruct = 61, + OpCompositeExtract = 62, + OpCompositeInsert = 63, + OpCopyObject = 64, + OpCopyMemory = 65, + OpCopyMemorySized = 66, + OpSampler = 67, + OpTextureSample = 68, + OpTextureSampleDref = 69, + OpTextureSampleLod = 70, + OpTextureSampleProj = 71, + OpTextureSampleGrad = 72, + OpTextureSampleOffset = 73, + OpTextureSampleProjLod = 74, + OpTextureSampleProjGrad = 75, + OpTextureSampleLodOffset = 76, + OpTextureSampleProjOffset = 77, + OpTextureSampleGradOffset = 78, + OpTextureSampleProjLodOffset = 79, + OpTextureSampleProjGradOffset = 80, + OpTextureFetchTexelLod = 81, + OpTextureFetchTexelOffset = 82, + OpTextureFetchSample = 83, + OpTextureFetchTexel = 84, + OpTextureGather = 85, + OpTextureGatherOffset = 86, + OpTextureGatherOffsets = 87, + OpTextureQuerySizeLod = 88, + OpTextureQuerySize = 89, + OpTextureQueryLod = 90, + OpTextureQueryLevels = 91, + OpTextureQuerySamples = 92, + OpAccessChain = 93, + OpInBoundsAccessChain = 94, + OpSNegate = 95, + OpFNegate = 96, + OpNot = 97, + OpAny = 98, + OpAll = 99, + OpConvertFToU = 100, + OpConvertFToS = 101, + OpConvertSToF = 102, + OpConvertUToF = 103, + OpUConvert = 104, + OpSConvert = 105, + OpFConvert = 106, + OpConvertPtrToU = 107, + OpConvertUToPtr = 108, + OpPtrCastToGeneric = 109, + OpGenericCastToPtr = 110, + OpBitcast = 111, + OpTranspose = 112, + OpIsNan = 113, + OpIsInf = 114, + OpIsFinite = 115, + OpIsNormal = 116, + OpSignBitSet = 117, + OpLessOrGreater = 118, + OpOrdered = 119, + OpUnordered = 120, + OpArrayLength = 121, + OpIAdd = 122, + OpFAdd = 123, + OpISub = 124, + OpFSub = 125, + OpIMul = 126, + OpFMul = 127, + OpUDiv = 128, + OpSDiv = 129, + OpFDiv = 130, + OpUMod = 131, + OpSRem = 132, + OpSMod = 133, + OpFRem = 134, + OpFMod = 135, + OpVectorTimesScalar = 136, + OpMatrixTimesScalar = 137, + OpVectorTimesMatrix = 138, + OpMatrixTimesVector = 139, + OpMatrixTimesMatrix = 140, + OpOuterProduct = 141, + OpDot = 142, + OpShiftRightLogical = 143, + OpShiftRightArithmetic = 144, + OpShiftLeftLogical = 145, + OpLogicalOr = 146, + OpLogicalXor = 147, + OpLogicalAnd = 148, + OpBitwiseOr = 149, + OpBitwiseXor = 150, + OpBitwiseAnd = 151, + OpSelect = 152, + OpIEqual = 153, + OpFOrdEqual = 154, + OpFUnordEqual = 155, + OpINotEqual = 156, + OpFOrdNotEqual = 157, + OpFUnordNotEqual = 158, + OpULessThan = 159, + OpSLessThan = 160, + OpFOrdLessThan = 161, + OpFUnordLessThan = 162, + OpUGreaterThan = 163, + OpSGreaterThan = 164, + OpFOrdGreaterThan = 165, + OpFUnordGreaterThan = 166, + OpULessThanEqual = 167, + OpSLessThanEqual = 168, + OpFOrdLessThanEqual = 169, + OpFUnordLessThanEqual = 170, + OpUGreaterThanEqual = 171, + OpSGreaterThanEqual = 172, + OpFOrdGreaterThanEqual = 173, + OpFUnordGreaterThanEqual = 174, + OpDPdx = 175, + OpDPdy = 176, + OpFwidth = 177, + OpDPdxFine = 178, + OpDPdyFine = 179, + OpFwidthFine = 180, + OpDPdxCoarse = 181, + OpDPdyCoarse = 182, + OpFwidthCoarse = 183, + OpEmitVertex = 184, + OpEndPrimitive = 185, + OpEmitStreamVertex = 186, + OpEndStreamPrimitive = 187, + OpControlBarrier = 188, + OpMemoryBarrier = 189, + OpImagePointer = 190, + OpAtomicInit = 191, + OpAtomicLoad = 192, + OpAtomicStore = 193, + OpAtomicExchange = 194, + OpAtomicCompareExchange = 195, + OpAtomicCompareExchangeWeak = 196, + OpAtomicIIncrement = 197, + OpAtomicIDecrement = 198, + OpAtomicIAdd = 199, + OpAtomicISub = 200, + OpAtomicUMin = 201, + OpAtomicUMax = 202, + OpAtomicAnd = 203, + OpAtomicOr = 204, + OpAtomicXor = 205, + OpLoopMerge = 206, + OpSelectionMerge = 207, + OpLabel = 208, + OpBranch = 209, + OpBranchConditional = 210, + OpSwitch = 211, + OpKill = 212, + OpReturn = 213, + OpReturnValue = 214, + OpUnreachable = 215, + OpLifetimeStart = 216, + OpLifetimeStop = 217, + OpCompileFlag = 218, + OpAsyncGroupCopy = 219, + OpWaitGroupEvents = 220, + OpGroupAll = 221, + OpGroupAny = 222, + OpGroupBroadcast = 223, + OpGroupIAdd = 224, + OpGroupFAdd = 225, + OpGroupFMin = 226, + OpGroupUMin = 227, + OpGroupSMin = 228, + OpGroupFMax = 229, + OpGroupUMax = 230, + OpGroupSMax = 231, + OpGenericCastToPtrExplicit = 232, + OpGenericPtrMemSemantics = 233, + OpReadPipe = 234, + OpWritePipe = 235, + OpReservedReadPipe = 236, + OpReservedWritePipe = 237, + OpReserveReadPipePackets = 238, + OpReserveWritePipePackets = 239, + OpCommitReadPipe = 240, + OpCommitWritePipe = 241, + OpIsValidReserveId = 242, + OpGetNumPipePackets = 243, + OpGetMaxPipePackets = 244, + OpGroupReserveReadPipePackets = 245, + OpGroupReserveWritePipePackets = 246, + OpGroupCommitReadPipe = 247, + OpGroupCommitWritePipe = 248, + OpEnqueueMarker = 249, + OpEnqueueKernel = 250, + OpGetKernelNDrangeSubGroupCount = 251, + OpGetKernelNDrangeMaxSubGroupSize = 252, + OpGetKernelWorkGroupSize = 253, + OpGetKernelPreferredWorkGroupSizeMultiple = 254, + OpRetainEvent = 255, + OpReleaseEvent = 256, + OpCreateUserEvent = 257, + OpIsValidEvent = 258, + OpSetUserEventStatus = 259, + OpCaptureEventProfilingInfo = 260, + OpGetDefaultQueue = 261, + OpBuildNDRange = 262, + OpSatConvertSToU = 263, + OpSatConvertUToS = 264, + OpAtomicIMin = 265, + OpAtomicIMax = 266, +}; + +}; // end namespace spv + +#endif // #ifdef __cplusplus + + +#ifndef __cplusplus + +const int SpvMagicNumber = 0x07230203; +const int SpvVersion = 99; + +typedef unsigned int SpvId; + +const unsigned int SpvOpCodeMask = 0xFFFF; +const unsigned int SpvWordCountShift = 16; + +typedef enum SpvSourceLanguage_ { + SpvSourceLanguageUnknown = 0, + SpvSourceLanguageESSL = 1, + SpvSourceLanguageGLSL = 2, + SpvSourceLanguageOpenCL = 3, +} SpvSourceLanguage; + +typedef enum SpvExecutionModel_ { + SpvExecutionModelVertex = 0, + SpvExecutionModelTessellationControl = 1, + SpvExecutionModelTessellationEvaluation = 2, + SpvExecutionModelGeometry = 3, + SpvExecutionModelFragment = 4, + SpvExecutionModelGLCompute = 5, + SpvExecutionModelKernel = 6, +} SpvExecutionModel; + +typedef enum SpvAddressingModel_ { + SpvAddressingModelLogical = 0, + SpvAddressingModelPhysical32 = 1, + SpvAddressingModelPhysical64 = 2, +} SpvAddressingModel; + +typedef enum SpvMemoryModel_ { + SpvMemoryModelSimple = 0, + SpvMemoryModelGLSL450 = 1, + SpvMemoryModelOpenCL12 = 2, + SpvMemoryModelOpenCL20 = 3, + SpvMemoryModelOpenCL21 = 4, +} SpvMemoryModel; + +typedef enum SpvExecutionMode_ { + SpvExecutionModeInvocations = 0, + SpvExecutionModeSpacingEqual = 1, + SpvExecutionModeSpacingFractionalEven = 2, + SpvExecutionModeSpacingFractionalOdd = 3, + SpvExecutionModeVertexOrderCw = 4, + SpvExecutionModeVertexOrderCcw = 5, + SpvExecutionModePixelCenterInteger = 6, + SpvExecutionModeOriginUpperLeft = 7, + SpvExecutionModeEarlyFragmentTests = 8, + SpvExecutionModePointMode = 9, + SpvExecutionModeXfb = 10, + SpvExecutionModeDepthReplacing = 11, + SpvExecutionModeDepthAny = 12, + SpvExecutionModeDepthGreater = 13, + SpvExecutionModeDepthLess = 14, + SpvExecutionModeDepthUnchanged = 15, + SpvExecutionModeLocalSize = 16, + SpvExecutionModeLocalSizeHint = 17, + SpvExecutionModeInputPoints = 18, + SpvExecutionModeInputLines = 19, + SpvExecutionModeInputLinesAdjacency = 20, + SpvExecutionModeInputTriangles = 21, + SpvExecutionModeInputTrianglesAdjacency = 22, + SpvExecutionModeInputQuads = 23, + SpvExecutionModeInputIsolines = 24, + SpvExecutionModeOutputVertices = 25, + SpvExecutionModeOutputPoints = 26, + SpvExecutionModeOutputLineStrip = 27, + SpvExecutionModeOutputTriangleStrip = 28, + SpvExecutionModeVecTypeHint = 29, + SpvExecutionModeContractionOff = 30, +} SpvExecutionMode; + +typedef enum SpvStorageClass_ { + SpvStorageClassUniformConstant = 0, + SpvStorageClassInput = 1, + SpvStorageClassUniform = 2, + SpvStorageClassOutput = 3, + SpvStorageClassWorkgroupLocal = 4, + SpvStorageClassWorkgroupGlobal = 5, + SpvStorageClassPrivateGlobal = 6, + SpvStorageClassFunction = 7, + SpvStorageClassGeneric = 8, + SpvStorageClassPrivate = 9, + SpvStorageClassAtomicCounter = 10, +} SpvStorageClass; + +typedef enum SpvDim_ { + SpvDim1D = 0, + SpvDim2D = 1, + SpvDim3D = 2, + SpvDimCube = 3, + SpvDimRect = 4, + SpvDimBuffer = 5, +} SpvDim; + +typedef enum SpvSamplerAddressingMode_ { + SpvSamplerAddressingModeNone = 0, + SpvSamplerAddressingModeClampToEdge = 1, + SpvSamplerAddressingModeClamp = 2, + SpvSamplerAddressingModeRepeat = 3, + SpvSamplerAddressingModeRepeatMirrored = 4, +} SpvSamplerAddressingMode; + +typedef enum SpvSamplerFilterMode_ { + SpvSamplerFilterModeNearest = 0, + SpvSamplerFilterModeLinear = 1, +} SpvSamplerFilterMode; + +typedef enum SpvFPFastMathModeShift_ { + SpvFPFastMathModeNotNaNShift = 0, + SpvFPFastMathModeNotInfShift = 1, + SpvFPFastMathModeNSZShift = 2, + SpvFPFastMathModeAllowRecipShift = 3, + SpvFPFastMathModeFastShift = 4, +} SpvFPFastMathModeShift; + +typedef enum SpvFPFastMathModeMask_ { + SpvFPFastMathModeMaskNone = 0, + SpvFPFastMathModeNotNaNMask = 0x00000001, + SpvFPFastMathModeNotInfMask = 0x00000002, + SpvFPFastMathModeNSZMask = 0x00000004, + SpvFPFastMathModeAllowRecipMask = 0x00000008, + SpvFPFastMathModeFastMask = 0x00000010, +} SpvFPFastMathModeMask; + +typedef enum SpvFPRoundingMode_ { + SpvFPRoundingModeRTE = 0, + SpvFPRoundingModeRTZ = 1, + SpvFPRoundingModeRTP = 2, + SpvFPRoundingModeRTN = 3, +} SpvFPRoundingMode; + +typedef enum SpvLinkageType_ { + SpvLinkageTypeExport = 0, + SpvLinkageTypeImport = 1, +} SpvLinkageType; + +typedef enum SpvAccessQualifier_ { + SpvAccessQualifierReadOnly = 0, + SpvAccessQualifierWriteOnly = 1, + SpvAccessQualifierReadWrite = 2, +} SpvAccessQualifier; + +typedef enum SpvFunctionParameterAttribute_ { + SpvFunctionParameterAttributeZext = 0, + SpvFunctionParameterAttributeSext = 1, + SpvFunctionParameterAttributeByVal = 2, + SpvFunctionParameterAttributeSret = 3, + SpvFunctionParameterAttributeNoAlias = 4, + SpvFunctionParameterAttributeNoCapture = 5, + SpvFunctionParameterAttributeSVM = 6, + SpvFunctionParameterAttributeNoWrite = 7, + SpvFunctionParameterAttributeNoReadWrite = 8, +} SpvFunctionParameterAttribute; + +typedef enum SpvDecoration_ { + SpvDecorationPrecisionLow = 0, + SpvDecorationPrecisionMedium = 1, + SpvDecorationPrecisionHigh = 2, + SpvDecorationBlock = 3, + SpvDecorationBufferBlock = 4, + SpvDecorationRowMajor = 5, + SpvDecorationColMajor = 6, + SpvDecorationGLSLShared = 7, + SpvDecorationGLSLStd140 = 8, + SpvDecorationGLSLStd430 = 9, + SpvDecorationGLSLPacked = 10, + SpvDecorationSmooth = 11, + SpvDecorationNoperspective = 12, + SpvDecorationFlat = 13, + SpvDecorationPatch = 14, + SpvDecorationCentroid = 15, + SpvDecorationSample = 16, + SpvDecorationInvariant = 17, + SpvDecorationRestrict = 18, + SpvDecorationAliased = 19, + SpvDecorationVolatile = 20, + SpvDecorationConstant = 21, + SpvDecorationCoherent = 22, + SpvDecorationNonwritable = 23, + SpvDecorationNonreadable = 24, + SpvDecorationUniform = 25, + SpvDecorationNoStaticUse = 26, + SpvDecorationCPacked = 27, + SpvDecorationSaturatedConversion = 28, + SpvDecorationStream = 29, + SpvDecorationLocation = 30, + SpvDecorationComponent = 31, + SpvDecorationIndex = 32, + SpvDecorationBinding = 33, + SpvDecorationDescriptorSet = 34, + SpvDecorationOffset = 35, + SpvDecorationAlignment = 36, + SpvDecorationXfbBuffer = 37, + SpvDecorationStride = 38, + SpvDecorationBuiltIn = 39, + SpvDecorationFuncParamAttr = 40, + SpvDecorationFPRoundingMode = 41, + SpvDecorationFPFastMathMode = 42, + SpvDecorationLinkageAttributes = 43, + SpvDecorationSpecId = 44, +} SpvDecoration; + +typedef enum SpvBuiltIn_ { + SpvBuiltInPosition = 0, + SpvBuiltInPointSize = 1, + SpvBuiltInClipVertex = 2, + SpvBuiltInClipDistance = 3, + SpvBuiltInCullDistance = 4, + SpvBuiltInVertexId = 5, + SpvBuiltInInstanceId = 6, + SpvBuiltInPrimitiveId = 7, + SpvBuiltInInvocationId = 8, + SpvBuiltInLayer = 9, + SpvBuiltInViewportIndex = 10, + SpvBuiltInTessLevelOuter = 11, + SpvBuiltInTessLevelInner = 12, + SpvBuiltInTessCoord = 13, + SpvBuiltInPatchVertices = 14, + SpvBuiltInFragCoord = 15, + SpvBuiltInPointCoord = 16, + SpvBuiltInFrontFacing = 17, + SpvBuiltInSampleId = 18, + SpvBuiltInSamplePosition = 19, + SpvBuiltInSampleMask = 20, + SpvBuiltInFragColor = 21, + SpvBuiltInFragDepth = 22, + SpvBuiltInHelperInvocation = 23, + SpvBuiltInNumWorkgroups = 24, + SpvBuiltInWorkgroupSize = 25, + SpvBuiltInWorkgroupId = 26, + SpvBuiltInLocalInvocationId = 27, + SpvBuiltInGlobalInvocationId = 28, + SpvBuiltInLocalInvocationIndex = 29, + SpvBuiltInWorkDim = 30, + SpvBuiltInGlobalSize = 31, + SpvBuiltInEnqueuedWorkgroupSize = 32, + SpvBuiltInGlobalOffset = 33, + SpvBuiltInGlobalLinearId = 34, + SpvBuiltInWorkgroupLinearId = 35, + SpvBuiltInSubgroupSize = 36, + SpvBuiltInSubgroupMaxSize = 37, + SpvBuiltInNumSubgroups = 38, + SpvBuiltInNumEnqueuedSubgroups = 39, + SpvBuiltInSubgroupId = 40, + SpvBuiltInSubgroupLocalInvocationId = 41, +} SpvBuiltIn; + +typedef enum SpvSelectionControlShift_ { + SpvSelectionControlFlattenShift = 0, + SpvSelectionControlDontFlattenShift = 1, +} SpvSelectionControlShift; + +typedef enum SpvSelectionControlMask_ { + SpvSelectionControlMaskNone = 0, + SpvSelectionControlFlattenMask = 0x00000001, + SpvSelectionControlDontFlattenMask = 0x00000002, +} SpvSelectionControlMask; + +typedef enum SpvLoopControlShift_ { + SpvLoopControlUnrollShift = 0, + SpvLoopControlDontUnrollShift = 1, +} SpvLoopControlShift; + +typedef enum SpvLoopControlMask_ { + SpvLoopControlMaskNone = 0, + SpvLoopControlUnrollMask = 0x00000001, + SpvLoopControlDontUnrollMask = 0x00000002, +} SpvLoopControlMask; + +typedef enum SpvFunctionControlShift_ { + SpvFunctionControlInlineShift = 0, + SpvFunctionControlDontInlineShift = 1, + SpvFunctionControlPureShift = 2, + SpvFunctionControlConstShift = 3, +} SpvFunctionControlShift; + +typedef enum SpvFunctionControlMask_ { + SpvFunctionControlMaskNone = 0, + SpvFunctionControlInlineMask = 0x00000001, + SpvFunctionControlDontInlineMask = 0x00000002, + SpvFunctionControlPureMask = 0x00000004, + SpvFunctionControlConstMask = 0x00000008, +} SpvFunctionControlMask; + +typedef enum SpvMemorySemanticsShift_ { + SpvMemorySemanticsRelaxedShift = 0, + SpvMemorySemanticsSequentiallyConsistentShift = 1, + SpvMemorySemanticsAcquireShift = 2, + SpvMemorySemanticsReleaseShift = 3, + SpvMemorySemanticsUniformMemoryShift = 4, + SpvMemorySemanticsSubgroupMemoryShift = 5, + SpvMemorySemanticsWorkgroupLocalMemoryShift = 6, + SpvMemorySemanticsWorkgroupGlobalMemoryShift = 7, + SpvMemorySemanticsAtomicCounterMemoryShift = 8, + SpvMemorySemanticsImageMemoryShift = 9, +} SpvMemorySemanticsShift; + +typedef enum SpvMemorySemanticsMask_ { + SpvMemorySemanticsMaskNone = 0, + SpvMemorySemanticsRelaxedMask = 0x00000001, + SpvMemorySemanticsSequentiallyConsistentMask = 0x00000002, + SpvMemorySemanticsAcquireMask = 0x00000004, + SpvMemorySemanticsReleaseMask = 0x00000008, + SpvMemorySemanticsUniformMemoryMask = 0x00000010, + SpvMemorySemanticsSubgroupMemoryMask = 0x00000020, + SpvMemorySemanticsWorkgroupLocalMemoryMask = 0x00000040, + SpvMemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080, + SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000100, + SpvMemorySemanticsImageMemoryMask = 0x00000200, +} SpvMemorySemanticsMask; + +typedef enum SpvMemoryAccessShift_ { + SpvMemoryAccessVolatileShift = 0, + SpvMemoryAccessAlignedShift = 1, +} SpvMemoryAccessShift; + +typedef enum SpvMemoryAccessMask_ { + SpvMemoryAccessMaskNone = 0, + SpvMemoryAccessVolatileMask = 0x00000001, + SpvMemoryAccessAlignedMask = 0x00000002, +} SpvMemoryAccessMask; + +typedef enum SpvExecutionScope_ { + SpvExecutionScopeCrossDevice = 0, + SpvExecutionScopeDevice = 1, + SpvExecutionScopeWorkgroup = 2, + SpvExecutionScopeSubgroup = 3, +} SpvExecutionScope; + +typedef enum SpvGroupOperation_ { + SpvGroupOperationReduce = 0, + SpvGroupOperationInclusiveScan = 1, + SpvGroupOperationExclusiveScan = 2, +} SpvGroupOperation; + +typedef enum SpvKernelEnqueueFlags_ { + SpvKernelEnqueueFlagsNoWait = 0, + SpvKernelEnqueueFlagsWaitKernel = 1, + SpvKernelEnqueueFlagsWaitWorkGroup = 2, +} SpvKernelEnqueueFlags; + +typedef enum SpvKernelProfilingInfoShift_ { + SpvKernelProfilingInfoCmdExecTimeShift = 0, +} SpvKernelProfilingInfoShift; + +typedef enum SpvKernelProfilingInfoMask_ { + SpvKernelProfilingInfoMaskNone = 0, + SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001, +} SpvKernelProfilingInfoMask; + +typedef enum SpvOp_ { + SpvOpNop = 0, + SpvOpSource = 1, + SpvOpSourceExtension = 2, + SpvOpExtension = 3, + SpvOpExtInstImport = 4, + SpvOpMemoryModel = 5, + SpvOpEntryPoint = 6, + SpvOpExecutionMode = 7, + SpvOpTypeVoid = 8, + SpvOpTypeBool = 9, + SpvOpTypeInt = 10, + SpvOpTypeFloat = 11, + SpvOpTypeVector = 12, + SpvOpTypeMatrix = 13, + SpvOpTypeSampler = 14, + SpvOpTypeFilter = 15, + SpvOpTypeArray = 16, + SpvOpTypeRuntimeArray = 17, + SpvOpTypeStruct = 18, + SpvOpTypeOpaque = 19, + SpvOpTypePointer = 20, + SpvOpTypeFunction = 21, + SpvOpTypeEvent = 22, + SpvOpTypeDeviceEvent = 23, + SpvOpTypeReserveId = 24, + SpvOpTypeQueue = 25, + SpvOpTypePipe = 26, + SpvOpConstantTrue = 27, + SpvOpConstantFalse = 28, + SpvOpConstant = 29, + SpvOpConstantComposite = 30, + SpvOpConstantSampler = 31, + SpvOpConstantNullPointer = 32, + SpvOpConstantNullObject = 33, + SpvOpSpecConstantTrue = 34, + SpvOpSpecConstantFalse = 35, + SpvOpSpecConstant = 36, + SpvOpSpecConstantComposite = 37, + SpvOpVariable = 38, + SpvOpVariableArray = 39, + SpvOpFunction = 40, + SpvOpFunctionParameter = 41, + SpvOpFunctionEnd = 42, + SpvOpFunctionCall = 43, + SpvOpExtInst = 44, + SpvOpUndef = 45, + SpvOpLoad = 46, + SpvOpStore = 47, + SpvOpPhi = 48, + SpvOpDecorationGroup = 49, + SpvOpDecorate = 50, + SpvOpMemberDecorate = 51, + SpvOpGroupDecorate = 52, + SpvOpGroupMemberDecorate = 53, + SpvOpName = 54, + SpvOpMemberName = 55, + SpvOpString = 56, + SpvOpLine = 57, + SpvOpVectorExtractDynamic = 58, + SpvOpVectorInsertDynamic = 59, + SpvOpVectorShuffle = 60, + SpvOpCompositeConstruct = 61, + SpvOpCompositeExtract = 62, + SpvOpCompositeInsert = 63, + SpvOpCopyObject = 64, + SpvOpCopyMemory = 65, + SpvOpCopyMemorySized = 66, + SpvOpSampler = 67, + SpvOpTextureSample = 68, + SpvOpTextureSampleDref = 69, + SpvOpTextureSampleLod = 70, + SpvOpTextureSampleProj = 71, + SpvOpTextureSampleGrad = 72, + SpvOpTextureSampleOffset = 73, + SpvOpTextureSampleProjLod = 74, + SpvOpTextureSampleProjGrad = 75, + SpvOpTextureSampleLodOffset = 76, + SpvOpTextureSampleProjOffset = 77, + SpvOpTextureSampleGradOffset = 78, + SpvOpTextureSampleProjLodOffset = 79, + SpvOpTextureSampleProjGradOffset = 80, + SpvOpTextureFetchTexelLod = 81, + SpvOpTextureFetchTexelOffset = 82, + SpvOpTextureFetchSample = 83, + SpvOpTextureFetchTexel = 84, + SpvOpTextureGather = 85, + SpvOpTextureGatherOffset = 86, + SpvOpTextureGatherOffsets = 87, + SpvOpTextureQuerySizeLod = 88, + SpvOpTextureQuerySize = 89, + SpvOpTextureQueryLod = 90, + SpvOpTextureQueryLevels = 91, + SpvOpTextureQuerySamples = 92, + SpvOpAccessChain = 93, + SpvOpInBoundsAccessChain = 94, + SpvOpSNegate = 95, + SpvOpFNegate = 96, + SpvOpNot = 97, + SpvOpAny = 98, + SpvOpAll = 99, + SpvOpConvertFToU = 100, + SpvOpConvertFToS = 101, + SpvOpConvertSToF = 102, + SpvOpConvertUToF = 103, + SpvOpUConvert = 104, + SpvOpSConvert = 105, + SpvOpFConvert = 106, + SpvOpConvertPtrToU = 107, + SpvOpConvertUToPtr = 108, + SpvOpPtrCastToGeneric = 109, + SpvOpGenericCastToPtr = 110, + SpvOpBitcast = 111, + SpvOpTranspose = 112, + SpvOpIsNan = 113, + SpvOpIsInf = 114, + SpvOpIsFinite = 115, + SpvOpIsNormal = 116, + SpvOpSignBitSet = 117, + SpvOpLessOrGreater = 118, + SpvOpOrdered = 119, + SpvOpUnordered = 120, + SpvOpArrayLength = 121, + SpvOpIAdd = 122, + SpvOpFAdd = 123, + SpvOpISub = 124, + SpvOpFSub = 125, + SpvOpIMul = 126, + SpvOpFMul = 127, + SpvOpUDiv = 128, + SpvOpSDiv = 129, + SpvOpFDiv = 130, + SpvOpUMod = 131, + SpvOpSRem = 132, + SpvOpSMod = 133, + SpvOpFRem = 134, + SpvOpFMod = 135, + SpvOpVectorTimesScalar = 136, + SpvOpMatrixTimesScalar = 137, + SpvOpVectorTimesMatrix = 138, + SpvOpMatrixTimesVector = 139, + SpvOpMatrixTimesMatrix = 140, + SpvOpOuterProduct = 141, + SpvOpDot = 142, + SpvOpShiftRightLogical = 143, + SpvOpShiftRightArithmetic = 144, + SpvOpShiftLeftLogical = 145, + SpvOpLogicalOr = 146, + SpvOpLogicalXor = 147, + SpvOpLogicalAnd = 148, + SpvOpBitwiseOr = 149, + SpvOpBitwiseXor = 150, + SpvOpBitwiseAnd = 151, + SpvOpSelect = 152, + SpvOpIEqual = 153, + SpvOpFOrdEqual = 154, + SpvOpFUnordEqual = 155, + SpvOpINotEqual = 156, + SpvOpFOrdNotEqual = 157, + SpvOpFUnordNotEqual = 158, + SpvOpULessThan = 159, + SpvOpSLessThan = 160, + SpvOpFOrdLessThan = 161, + SpvOpFUnordLessThan = 162, + SpvOpUGreaterThan = 163, + SpvOpSGreaterThan = 164, + SpvOpFOrdGreaterThan = 165, + SpvOpFUnordGreaterThan = 166, + SpvOpULessThanEqual = 167, + SpvOpSLessThanEqual = 168, + SpvOpFOrdLessThanEqual = 169, + SpvOpFUnordLessThanEqual = 170, + SpvOpUGreaterThanEqual = 171, + SpvOpSGreaterThanEqual = 172, + SpvOpFOrdGreaterThanEqual = 173, + SpvOpFUnordGreaterThanEqual = 174, + SpvOpDPdx = 175, + SpvOpDPdy = 176, + SpvOpFwidth = 177, + SpvOpDPdxFine = 178, + SpvOpDPdyFine = 179, + SpvOpFwidthFine = 180, + SpvOpDPdxCoarse = 181, + SpvOpDPdyCoarse = 182, + SpvOpFwidthCoarse = 183, + SpvOpEmitVertex = 184, + SpvOpEndPrimitive = 185, + SpvOpEmitStreamVertex = 186, + SpvOpEndStreamPrimitive = 187, + SpvOpControlBarrier = 188, + SpvOpMemoryBarrier = 189, + SpvOpImagePointer = 190, + SpvOpAtomicInit = 191, + SpvOpAtomicLoad = 192, + SpvOpAtomicStore = 193, + SpvOpAtomicExchange = 194, + SpvOpAtomicCompareExchange = 195, + SpvOpAtomicCompareExchangeWeak = 196, + SpvOpAtomicIIncrement = 197, + SpvOpAtomicIDecrement = 198, + SpvOpAtomicIAdd = 199, + SpvOpAtomicISub = 200, + SpvOpAtomicUMin = 201, + SpvOpAtomicUMax = 202, + SpvOpAtomicAnd = 203, + SpvOpAtomicOr = 204, + SpvOpAtomicXor = 205, + SpvOpLoopMerge = 206, + SpvOpSelectionMerge = 207, + SpvOpLabel = 208, + SpvOpBranch = 209, + SpvOpBranchConditional = 210, + SpvOpSwitch = 211, + SpvOpKill = 212, + SpvOpReturn = 213, + SpvOpReturnValue = 214, + SpvOpUnreachable = 215, + SpvOpLifetimeStart = 216, + SpvOpLifetimeStop = 217, + SpvOpCompileFlag = 218, + SpvOpAsyncGroupCopy = 219, + SpvOpWaitGroupEvents = 220, + SpvOpGroupAll = 221, + SpvOpGroupAny = 222, + SpvOpGroupBroadcast = 223, + SpvOpGroupIAdd = 224, + SpvOpGroupFAdd = 225, + SpvOpGroupFMin = 226, + SpvOpGroupUMin = 227, + SpvOpGroupSMin = 228, + SpvOpGroupFMax = 229, + SpvOpGroupUMax = 230, + SpvOpGroupSMax = 231, + SpvOpGenericCastToPtrExplicit = 232, + SpvOpGenericPtrMemSemantics = 233, + SpvOpReadPipe = 234, + SpvOpWritePipe = 235, + SpvOpReservedReadPipe = 236, + SpvOpReservedWritePipe = 237, + SpvOpReserveReadPipePackets = 238, + SpvOpReserveWritePipePackets = 239, + SpvOpCommitReadPipe = 240, + SpvOpCommitWritePipe = 241, + SpvOpIsValidReserveId = 242, + SpvOpGetNumPipePackets = 243, + SpvOpGetMaxPipePackets = 244, + SpvOpGroupReserveReadPipePackets = 245, + SpvOpGroupReserveWritePipePackets = 246, + SpvOpGroupCommitReadPipe = 247, + SpvOpGroupCommitWritePipe = 248, + SpvOpEnqueueMarker = 249, + SpvOpEnqueueKernel = 250, + SpvOpGetKernelNDrangeSubGroupCount = 251, + SpvOpGetKernelNDrangeMaxSubGroupSize = 252, + SpvOpGetKernelWorkGroupSize = 253, + SpvOpGetKernelPreferredWorkGroupSizeMultiple = 254, + SpvOpRetainEvent = 255, + SpvOpReleaseEvent = 256, + SpvOpCreateUserEvent = 257, + SpvOpIsValidEvent = 258, + SpvOpSetUserEventStatus = 259, + SpvOpCaptureEventProfilingInfo = 260, + SpvOpGetDefaultQueue = 261, + SpvOpBuildNDRange = 262, + SpvOpSatConvertSToU = 263, + SpvOpSatConvertUToS = 264, + SpvOpAtomicIMin = 265, + SpvOpAtomicIMax = 266, +} SpvOp; + +#endif // #ifndef __cplusplus + +#endif // #ifndef spirv_H From b20d9f564335134c79c973fc4b6d85225b9d54b0 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Tue, 28 Apr 2015 17:43:16 -0700 Subject: [PATCH 02/55] nir: Add the start of a SPIR-V to NIR translator At the moment, it can handle the very basics of strings and can ignore debug instructions. It also has basic support for decorations. --- src/glsl/Makefile.sources | 2 + src/glsl/nir/nir_spirv.h | 39 ++++ src/glsl/nir/spirv_to_nir.c | 454 ++++++++++++++++++++++++++++++++++++ 3 files changed, 495 insertions(+) create mode 100644 src/glsl/nir/nir_spirv.h create mode 100644 src/glsl/nir/spirv_to_nir.c diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources index 05a12bc0721..c6a89362988 100644 --- a/src/glsl/Makefile.sources +++ b/src/glsl/Makefile.sources @@ -64,6 +64,7 @@ NIR_FILES = \ nir/nir_remove_dead_variables.c \ nir/nir_search.c \ nir/nir_search.h \ + nir/nir_spirv.h \ nir/nir_split_var_copies.c \ nir/nir_sweep.c \ nir/nir_to_ssa.c \ @@ -73,6 +74,7 @@ NIR_FILES = \ nir/nir_worklist.c \ nir/nir_worklist.h \ nir/nir_types.cpp \ + nir/spirv_to_nir.c \ $(NIR_GENERATED_FILES) # libglsl diff --git a/src/glsl/nir/nir_spirv.h b/src/glsl/nir/nir_spirv.h new file mode 100644 index 00000000000..5f4140db3d9 --- /dev/null +++ b/src/glsl/nir/nir_spirv.h @@ -0,0 +1,39 @@ +/* + * Copyright © 2015 Intel Corporation + * + * 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 (including the next + * paragraph) 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. + * + * Authors: + * Jason Ekstrand (jason@jlekstrand.net) + * + */ + +#pragma once + +#ifndef _NIR_SPIRV_H_ +#define _NIR_SPIRV_H_ + +#include "nir.h" + +nir_shader *spirv_to_nir(const uint32_t *words, size_t word_count, + gl_shader_stage stage, + const nir_shader_compiler_options *options); + +#endif /* _NIR_SPIRV_H_ */ diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c new file mode 100644 index 00000000000..3a49ad965ba --- /dev/null +++ b/src/glsl/nir/spirv_to_nir.c @@ -0,0 +1,454 @@ +/* + * Copyright © 2015 Intel Corporation + * + * 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 (including the next + * paragraph) 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. + * + * Authors: + * Jason Ekstrand (jason@jlekstrand.net) + * + */ + +#include "nir_spirv.h" +#include "spirv.h" + +struct vtn_decoration; + +enum vtn_value_type { + vtn_value_type_invalid = 0, + vtn_value_type_undef, + vtn_value_type_string, + vtn_value_type_decoration_group, + vtn_value_type_ssa, + vtn_value_type_deref, +}; + +struct vtn_value { + enum vtn_value_type value_type; + const char *name; + struct vtn_decoration *decoration; + union { + void *ptr; + char *str; + nir_ssa_def *ssa; + nir_deref_var *deref; + }; +}; + +struct vtn_decoration { + struct vtn_decoration *next; + const uint32_t *literals; + struct vtn_value *group; + SpvDecoration decoration; +}; + +struct vtn_builder { + nir_shader *shader; + nir_function_impl *impl; + + unsigned value_id_bound; + struct vtn_value *values; +}; + +static void +vtn_push_value(struct vtn_builder *b, uint32_t value_id, + enum vtn_value_type value_type, void *ptr) +{ + assert(value_id < b->value_id_bound); + assert(b->values[value_id].value_type == vtn_value_type_invalid); + + b->values[value_id].value_type = value_type; + b->values[value_id].ptr = ptr; +} + +static void +vtn_push_token(struct vtn_builder *b, uint32_t value_id, + enum vtn_value_type value_type) +{ + vtn_push_value(b, value_id, value_type, NULL); +} + +static char * +vtn_string_literal(struct vtn_builder *b, const uint32_t *words, + unsigned word_count) +{ + return ralloc_strndup(b, (char *)words, (word_count - 2) * sizeof(*words)); +} + +typedef void (*decoration_foreach_cb)(struct vtn_builder *, + struct vtn_value *, + const struct vtn_decoration *, + void *); + +static void +_foreach_decoration_helper(struct vtn_builder *b, + struct vtn_value *base_value, + struct vtn_value *value, + decoration_foreach_cb cb, void *data) +{ + for (struct vtn_decoration *dec = value->decoration; dec; dec = dec->next) { + if (dec->group) { + assert(dec->group->value_type == vtn_value_type_decoration_group); + _foreach_decoration_helper(b, base_value, dec->group, cb, data); + } else { + cb(b, base_value, dec, data); + } + } +} + +/** Iterates (recursively if needed) over all of the decorations on a value + * + * This function iterates over all of the decorations applied to a given + * value. If it encounters a decoration group, it recurses into the group + * and iterates over all of those decorations as well. + */ +static void +vtn_foreach_decoration(struct vtn_builder *b, struct vtn_value *value, + decoration_foreach_cb cb, void *data) +{ + _foreach_decoration_helper(b, value, value, cb, data); +} + +static void +vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) +{ + switch (opcode) { + case SpvOpDecorationGroup: + vtn_push_token(b, w[1], vtn_value_type_undef); + break; + + case SpvOpDecorate: { + struct vtn_value *val = &b->values[w[1]]; + + struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration); + dec->decoration = w[2]; + dec->literals = &w[3]; + + /* Link into the list */ + dec->next = val->decoration; + val->decoration = dec; + break; + } + + case SpvOpGroupDecorate: { + struct vtn_value *group = &b->values[w[1]]; + assert(group->value_type == vtn_value_type_decoration_group); + + for (unsigned i = 2; i < count; i++) { + struct vtn_value *val = &b->values[w[i]]; + struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration); + dec->group = group; + + /* Link into the list */ + dec->next = val->decoration; + val->decoration = dec; + } + break; + } + + case SpvOpGroupMemberDecorate: + assert(!"Bad instruction. Khronos Bug #13513"); + break; + + default: + unreachable("Unhandled opcode"); + } +} + +static void +vtn_handle_type(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) +{ + unreachable("Unhandled opcode"); +} + +static void +vtn_handle_constant(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) +{ + unreachable("Unhandled opcode"); +} + +static void +vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) +{ + unreachable("Unhandled opcode"); +} + +static void +vtn_handle_texture(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) +{ + unreachable("Unhandled opcode"); +} + +static void +vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) +{ + unreachable("Unhandled opcode"); +} + +static void +vtn_handle_instruction(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) +{ + switch (opcode) { + case SpvOpSource: + case SpvOpSourceExtension: + case SpvOpMemberName: + case SpvOpLine: + /* Unhandled, but these are for debug so that's ok. */ + break; + + case SpvOpName: + b->values[w[1]].name = vtn_string_literal(b, &w[2], count - 2); + break; + + case SpvOpString: + vtn_push_value(b, w[1], vtn_value_type_string, + vtn_string_literal(b, &w[2], count - 2)); + break; + + case SpvOpUndef: + vtn_push_token(b, w[2], vtn_value_type_undef); + break; + + case SpvOpTypeVoid: + case SpvOpTypeBool: + case SpvOpTypeInt: + case SpvOpTypeFloat: + case SpvOpTypeVector: + case SpvOpTypeMatrix: + case SpvOpTypeSampler: + case SpvOpTypeArray: + case SpvOpTypeRuntimeArray: + case SpvOpTypeStruct: + case SpvOpTypeOpaque: + case SpvOpTypePointer: + case SpvOpTypeFunction: + case SpvOpTypeEvent: + case SpvOpTypeDeviceEvent: + case SpvOpTypeReserveId: + case SpvOpTypeQueue: + case SpvOpTypePipe: + vtn_handle_type(b, opcode, w, count); + break; + + case SpvOpConstantTrue: + case SpvOpConstantFalse: + case SpvOpConstant: + case SpvOpConstantComposite: + case SpvOpConstantSampler: + case SpvOpConstantNullPointer: + case SpvOpConstantNullObject: + case SpvOpSpecConstantTrue: + case SpvOpSpecConstantFalse: + case SpvOpSpecConstant: + case SpvOpSpecConstantComposite: + vtn_handle_constant(b, opcode, w, count); + break; + + case SpvOpVariable: + case SpvOpVariableArray: + case SpvOpLoad: + case SpvOpStore: + case SpvOpCopyMemory: + case SpvOpCopyMemorySized: + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: + case SpvOpArrayLength: + case SpvOpImagePointer: + vtn_handle_variables(b, opcode, w, count); + break; + + case SpvOpDecorationGroup: + case SpvOpDecorate: + case SpvOpMemberDecorate: + case SpvOpGroupDecorate: + case SpvOpGroupMemberDecorate: + vtn_handle_decoration(b, opcode, w, count); + break; + + case SpvOpTextureSample: + case SpvOpTextureSampleDref: + case SpvOpTextureSampleLod: + case SpvOpTextureSampleProj: + case SpvOpTextureSampleGrad: + case SpvOpTextureSampleOffset: + case SpvOpTextureSampleProjLod: + case SpvOpTextureSampleProjGrad: + case SpvOpTextureSampleLodOffset: + case SpvOpTextureSampleProjOffset: + case SpvOpTextureSampleGradOffset: + case SpvOpTextureSampleProjLodOffset: + case SpvOpTextureSampleProjGradOffset: + case SpvOpTextureFetchTexelLod: + case SpvOpTextureFetchTexelOffset: + case SpvOpTextureFetchSample: + case SpvOpTextureFetchTexel: + case SpvOpTextureGather: + case SpvOpTextureGatherOffset: + case SpvOpTextureGatherOffsets: + case SpvOpTextureQuerySizeLod: + case SpvOpTextureQuerySize: + case SpvOpTextureQueryLod: + case SpvOpTextureQueryLevels: + case SpvOpTextureQuerySamples: + vtn_handle_texture(b, opcode, w, count); + break; + + case SpvOpSNegate: + case SpvOpFNegate: + case SpvOpNot: + case SpvOpAny: + case SpvOpAll: + case SpvOpConvertFToU: + case SpvOpConvertFToS: + case SpvOpConvertSToF: + case SpvOpConvertUToF: + case SpvOpUConvert: + case SpvOpSConvert: + case SpvOpFConvert: + case SpvOpConvertPtrToU: + case SpvOpConvertUToPtr: + case SpvOpPtrCastToGeneric: + case SpvOpGenericCastToPtr: + case SpvOpBitcast: + case SpvOpTranspose: + case SpvOpIsNan: + case SpvOpIsInf: + case SpvOpIsFinite: + case SpvOpIsNormal: + case SpvOpSignBitSet: + case SpvOpLessOrGreater: + case SpvOpOrdered: + case SpvOpUnordered: + case SpvOpIAdd: + case SpvOpFAdd: + case SpvOpISub: + case SpvOpFSub: + case SpvOpIMul: + case SpvOpFMul: + case SpvOpUDiv: + case SpvOpSDiv: + case SpvOpFDiv: + case SpvOpUMod: + case SpvOpSRem: + case SpvOpSMod: + case SpvOpFRem: + case SpvOpFMod: + case SpvOpVectorTimesScalar: + case SpvOpMatrixTimesScalar: + case SpvOpVectorTimesMatrix: + case SpvOpMatrixTimesVector: + case SpvOpMatrixTimesMatrix: + case SpvOpOuterProduct: + case SpvOpDot: + case SpvOpShiftRightLogical: + case SpvOpShiftRightArithmetic: + case SpvOpShiftLeftLogical: + case SpvOpLogicalOr: + case SpvOpLogicalXor: + case SpvOpLogicalAnd: + case SpvOpBitwiseOr: + case SpvOpBitwiseXor: + case SpvOpBitwiseAnd: + case SpvOpSelect: + case SpvOpIEqual: + case SpvOpFOrdEqual: + case SpvOpFUnordEqual: + case SpvOpINotEqual: + case SpvOpFOrdNotEqual: + case SpvOpFUnordNotEqual: + case SpvOpULessThan: + case SpvOpSLessThan: + case SpvOpFOrdLessThan: + case SpvOpFUnordLessThan: + case SpvOpUGreaterThan: + case SpvOpSGreaterThan: + case SpvOpFOrdGreaterThan: + case SpvOpFUnordGreaterThan: + case SpvOpULessThanEqual: + case SpvOpSLessThanEqual: + case SpvOpFOrdLessThanEqual: + case SpvOpFUnordLessThanEqual: + case SpvOpUGreaterThanEqual: + case SpvOpSGreaterThanEqual: + case SpvOpFOrdGreaterThanEqual: + case SpvOpFUnordGreaterThanEqual: + case SpvOpDPdx: + case SpvOpDPdy: + case SpvOpFwidth: + case SpvOpDPdxFine: + case SpvOpDPdyFine: + case SpvOpFwidthFine: + case SpvOpDPdxCoarse: + case SpvOpDPdyCoarse: + case SpvOpFwidthCoarse: + vtn_handle_alu(b, opcode, w, count); + break; + + default: + unreachable("Unhandled opcode"); + } +} + +nir_shader * +spirv_to_nir(const uint32_t *words, size_t word_count, + gl_shader_stage stage, + const nir_shader_compiler_options *options) +{ + /* Handle the SPIR-V header (first 4 dwords) */ + assert(word_count > 5); + + assert(words[0] == SpvMagicNumber); + assert(words[1] == 99); + /* words[2] == generator magic */ + unsigned value_id_bound = words[3]; + assert(words[4] == 0); + + words+= 5; + + nir_shader *shader = nir_shader_create(NULL, stage, options); + + /* Initialize the stn_builder object */ + struct vtn_builder *b = rzalloc(NULL, struct vtn_builder); + b->shader = shader; + b->value_id_bound = value_id_bound; + b->values = ralloc_array(b, struct vtn_value, value_id_bound); + + /* Start handling instructions */ + const uint32_t *word_end = words + word_count; + while (words < word_end) { + SpvOp opcode = words[0] & SpvOpCodeMask; + unsigned count = words[0] >> SpvWordCountShift; + assert(words + count <= word_end); + + vtn_handle_instruction(b, opcode, words, count); + + words += count; + } + + ralloc_free(b); + + return shader; +} From 2c585a722d61257c29eb9160e51b140afb27a928 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 29 Apr 2015 14:30:22 -0700 Subject: [PATCH 03/55] glsl/compiler: Move the error_no_memory stub to standalone_scaffolding.cpp --- src/glsl/standalone_scaffolding.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/glsl/standalone_scaffolding.cpp b/src/glsl/standalone_scaffolding.cpp index 6033364afc5..6ff9553d6fe 100644 --- a/src/glsl/standalone_scaffolding.cpp +++ b/src/glsl/standalone_scaffolding.cpp @@ -35,6 +35,12 @@ #include "util/ralloc.h" #include "util/strtod.h" +extern "C" void +_mesa_error_no_memory(const char *caller) +{ + fprintf(stderr, "Mesa error: out of memory in %s", caller); +} + void _mesa_warning(struct gl_context *ctx, const char *fmt, ...) { From 78eabc615323cf4728fb9ea72aa5bd9799828f04 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 29 Apr 2015 14:29:38 -0700 Subject: [PATCH 04/55] REVERT: Add a simple helper program for testing SPIR-V -> NIR translation --- src/glsl/Makefile.am | 12 ++++++++- src/glsl/nir/spirv2nir.c | 55 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 src/glsl/nir/spirv2nir.c diff --git a/src/glsl/Makefile.am b/src/glsl/Makefile.am index 98dcb37fc74..2ab40506e97 100644 --- a/src/glsl/Makefile.am +++ b/src/glsl/Makefile.am @@ -75,7 +75,7 @@ check_PROGRAMS = \ tests/sampler-types-test \ tests/uniform-initializer-test -noinst_PROGRAMS = glsl_compiler +noinst_PROGRAMS = glsl_compiler spirv2nir tests_blob_test_SOURCES = \ tests/blob_test.c @@ -156,6 +156,16 @@ glsl_compiler_LDADD = \ $(top_builddir)/src/libglsl_util.la \ $(PTHREAD_LIBS) +spirv2nir_SOURCES = \ + standalone_scaffolding.cpp \ + standalone_scaffolding.h \ + nir/spirv2nir.c + +spirv2nir_LDADD = \ + libglsl.la \ + $(top_builddir)/src/libglsl_util.la \ + $(PTHREAD_LIBS) + glsl_test_SOURCES = \ standalone_scaffolding.cpp \ test.cpp \ diff --git a/src/glsl/nir/spirv2nir.c b/src/glsl/nir/spirv2nir.c new file mode 100644 index 00000000000..e06e82595a2 --- /dev/null +++ b/src/glsl/nir/spirv2nir.c @@ -0,0 +1,55 @@ +/* + * Copyright © 2015 Intel Corporation + * + * 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 (including the next + * paragraph) 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. + * + * Authors: + * Jason Ekstrand (jason@jlekstrand.net) + * + */ + +/* + * A simple executable that opens a SPIR-V shader, converts it to NIR, and + * dumps out the result. This should be useful for testing the + * spirv_to_nir code. + */ + +#include "nir_spirv.h" + +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + int fd = open(argv[1], O_RDONLY); + off_t len = lseek(fd, 0, SEEK_END); + + assert(len % 4 == 0); + size_t word_count = len / 4; + + const void *map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); + assert(map != NULL); + + nir_shader *shader = spirv_to_nir(map, MESA_SHADER_FRAGMENT, + word_count, NULL); + nir_print_shader(shader, stderr); +} From ac60aba351c7c1076803b07c6f546ab5b70ac083 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 29 Apr 2015 14:32:55 -0700 Subject: [PATCH 05/55] nir/spirv: Add stub support for extension instructions --- src/glsl/nir/spirv_to_nir.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index 3a49ad965ba..bc7b98f2e0d 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -64,6 +64,9 @@ struct vtn_builder { unsigned value_id_bound; struct vtn_value *values; + + SpvExecutionModel execution_model; + struct vtn_value *entry_point; }; static void @@ -91,6 +94,21 @@ vtn_string_literal(struct vtn_builder *b, const uint32_t *words, return ralloc_strndup(b, (char *)words, (word_count - 2) * sizeof(*words)); } +static void +vtn_handle_extension(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) +{ + switch (opcode) { + case SpvOpExtInstImport: + /* Do nothing for the moment */ + break; + + case SpvOpExtInst: + default: + unreachable("Unhandled opcode"); + } +} + typedef void (*decoration_foreach_cb)(struct vtn_builder *, struct vtn_value *, const struct vtn_decoration *, @@ -216,6 +234,7 @@ vtn_handle_instruction(struct vtn_builder *b, SpvOp opcode, case SpvOpSourceExtension: case SpvOpMemberName: case SpvOpLine: + case SpvOpExtension: /* Unhandled, but these are for debug so that's ok. */ break; @@ -232,6 +251,22 @@ vtn_handle_instruction(struct vtn_builder *b, SpvOp opcode, vtn_push_token(b, w[2], vtn_value_type_undef); break; + case SpvOpMemoryModel: + assert(w[1] == SpvAddressingModelLogical); + assert(w[2] == SpvMemoryModelGLSL450); + break; + + case SpvOpEntryPoint: + assert(b->entry_point == NULL); + b->entry_point = &b->values[w[2]]; + b->execution_model = w[1]; + break; + + case SpvOpExtInstImport: + case SpvOpExtInst: + vtn_handle_extension(b, opcode, w, count); + break; + case SpvOpTypeVoid: case SpvOpTypeBool: case SpvOpTypeInt: From b79916dacc3d373d3d957a2e723a6e1d27932081 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 29 Apr 2015 14:34:06 -0700 Subject: [PATCH 06/55] nir/spirv: Rework the way values are added Instead of having functions to add values and set various things, we just have a function that does a few asserts and then returns the value. The caller is then responsible for setting the various fields. --- src/glsl/nir/spirv_to_nir.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index bc7b98f2e0d..05193531107 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -69,22 +69,16 @@ struct vtn_builder { struct vtn_value *entry_point; }; -static void +static struct vtn_value * vtn_push_value(struct vtn_builder *b, uint32_t value_id, - enum vtn_value_type value_type, void *ptr) + enum vtn_value_type value_type) { assert(value_id < b->value_id_bound); assert(b->values[value_id].value_type == vtn_value_type_invalid); b->values[value_id].value_type = value_type; - b->values[value_id].ptr = ptr; -} -static void -vtn_push_token(struct vtn_builder *b, uint32_t value_id, - enum vtn_value_type value_type) -{ - vtn_push_value(b, value_id, value_type, NULL); + return &b->values[value_id]; } static char * @@ -149,7 +143,7 @@ vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode, { switch (opcode) { case SpvOpDecorationGroup: - vtn_push_token(b, w[1], vtn_value_type_undef); + vtn_push_value(b, w[1], vtn_value_type_undef); break; case SpvOpDecorate: { @@ -243,12 +237,12 @@ vtn_handle_instruction(struct vtn_builder *b, SpvOp opcode, break; case SpvOpString: - vtn_push_value(b, w[1], vtn_value_type_string, - vtn_string_literal(b, &w[2], count - 2)); + vtn_push_value(b, w[1], vtn_value_type_string)->str = + vtn_string_literal(b, &w[2], count - 2); break; case SpvOpUndef: - vtn_push_token(b, w[2], vtn_value_type_undef); + vtn_push_value(b, w[2], vtn_value_type_undef); break; case SpvOpMemoryModel: From 1169fcdb0579b1cba1d43854397079ee54022e11 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Tue, 24 Feb 2015 16:27:32 -0800 Subject: [PATCH 07/55] glsl: Add GLSL_TYPE_FUNCTION to the base types enums --- src/glsl/ast_to_hir.cpp | 1 + src/glsl/glsl_types.cpp | 3 +++ src/glsl/glsl_types.h | 1 + src/glsl/ir_clone.cpp | 1 + src/glsl/link_uniform_initializers.cpp | 1 + src/mesa/drivers/dri/i965/brw_fs.cpp | 1 + src/mesa/drivers/dri/i965/brw_shader.cpp | 1 + src/mesa/drivers/dri/i965/brw_vec4_visitor.cpp | 1 + src/mesa/program/ir_to_mesa.cpp | 2 ++ 9 files changed, 12 insertions(+) diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index 517841c99f8..81b44bd6786 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -1019,6 +1019,7 @@ do_comparison(void *mem_ctx, int operation, ir_rvalue *op0, ir_rvalue *op1) case GLSL_TYPE_SAMPLER: case GLSL_TYPE_IMAGE: case GLSL_TYPE_INTERFACE: + case GLSL_TYPE_FUNCTION: case GLSL_TYPE_ATOMIC_UINT: case GLSL_TYPE_SUBROUTINE: /* I assume a comparison of a struct containing a sampler just diff --git a/src/glsl/glsl_types.cpp b/src/glsl/glsl_types.cpp index 755618ac28b..50409dd50de 100644 --- a/src/glsl/glsl_types.cpp +++ b/src/glsl/glsl_types.cpp @@ -1029,6 +1029,8 @@ glsl_type::component_slots() const return 1; case GLSL_TYPE_SUBROUTINE: return 1; + + case GLSL_TYPE_FUNCTION: case GLSL_TYPE_SAMPLER: case GLSL_TYPE_ATOMIC_UINT: case GLSL_TYPE_VOID: @@ -1402,6 +1404,7 @@ glsl_type::count_attribute_slots() const case GLSL_TYPE_ARRAY: return this->length * this->fields.array->count_attribute_slots(); + case GLSL_TYPE_FUNCTION: case GLSL_TYPE_SAMPLER: case GLSL_TYPE_IMAGE: case GLSL_TYPE_ATOMIC_UINT: diff --git a/src/glsl/glsl_types.h b/src/glsl/glsl_types.h index 02a398f6112..3c5345955fa 100644 --- a/src/glsl/glsl_types.h +++ b/src/glsl/glsl_types.h @@ -56,6 +56,7 @@ enum glsl_base_type { GLSL_TYPE_IMAGE, GLSL_TYPE_ATOMIC_UINT, GLSL_TYPE_STRUCT, + GLSL_TYPE_FUNCTION, GLSL_TYPE_INTERFACE, GLSL_TYPE_ARRAY, GLSL_TYPE_VOID, diff --git a/src/glsl/ir_clone.cpp b/src/glsl/ir_clone.cpp index a8fac183a8d..4edf70dba5d 100644 --- a/src/glsl/ir_clone.cpp +++ b/src/glsl/ir_clone.cpp @@ -363,6 +363,7 @@ ir_constant::clone(void *mem_ctx, struct hash_table *ht) const return c; } + case GLSL_TYPE_FUNCTION: case GLSL_TYPE_SAMPLER: case GLSL_TYPE_IMAGE: case GLSL_TYPE_ATOMIC_UINT: diff --git a/src/glsl/link_uniform_initializers.cpp b/src/glsl/link_uniform_initializers.cpp index 05000fc39ef..f238513f174 100644 --- a/src/glsl/link_uniform_initializers.cpp +++ b/src/glsl/link_uniform_initializers.cpp @@ -88,6 +88,7 @@ copy_constant_to_storage(union gl_constant_value *storage, case GLSL_TYPE_IMAGE: case GLSL_TYPE_ATOMIC_UINT: case GLSL_TYPE_INTERFACE: + case GLSL_TYPE_FUNCTION: case GLSL_TYPE_VOID: case GLSL_TYPE_SUBROUTINE: case GLSL_TYPE_ERROR: diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp index 269914d64a8..39c3eb2d4a1 100644 --- a/src/mesa/drivers/dri/i965/brw_fs.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs.cpp @@ -491,6 +491,7 @@ type_size_scalar(const struct glsl_type *type) case GLSL_TYPE_ERROR: case GLSL_TYPE_INTERFACE: case GLSL_TYPE_DOUBLE: + case GLSL_TYPE_FUNCTION: unreachable("not reached"); } diff --git a/src/mesa/drivers/dri/i965/brw_shader.cpp b/src/mesa/drivers/dri/i965/brw_shader.cpp index 445764d3d06..0007e5c07a5 100644 --- a/src/mesa/drivers/dri/i965/brw_shader.cpp +++ b/src/mesa/drivers/dri/i965/brw_shader.cpp @@ -459,6 +459,7 @@ brw_type_for_base_type(const struct glsl_type *type) case GLSL_TYPE_ERROR: case GLSL_TYPE_INTERFACE: case GLSL_TYPE_DOUBLE: + case GLSL_TYPE_FUNCTION: unreachable("not reached"); } diff --git a/src/mesa/drivers/dri/i965/brw_vec4_visitor.cpp b/src/mesa/drivers/dri/i965/brw_vec4_visitor.cpp index ca86e8b6d56..499f6288aee 100644 --- a/src/mesa/drivers/dri/i965/brw_vec4_visitor.cpp +++ b/src/mesa/drivers/dri/i965/brw_vec4_visitor.cpp @@ -643,6 +643,7 @@ type_size_vec4(const struct glsl_type *type) case GLSL_TYPE_DOUBLE: case GLSL_TYPE_ERROR: case GLSL_TYPE_INTERFACE: + case GLSL_TYPE_FUNCTION: unreachable("not reached"); } diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp index 8f58f3edf98..b8b082e2a59 100644 --- a/src/mesa/program/ir_to_mesa.cpp +++ b/src/mesa/program/ir_to_mesa.cpp @@ -543,6 +543,7 @@ type_size(const struct glsl_type *type) case GLSL_TYPE_VOID: case GLSL_TYPE_ERROR: case GLSL_TYPE_INTERFACE: + case GLSL_TYPE_FUNCTION: assert(!"Invalid type in type_size"); break; } @@ -2463,6 +2464,7 @@ _mesa_associate_uniform_storage(struct gl_context *ctx, case GLSL_TYPE_STRUCT: case GLSL_TYPE_ERROR: case GLSL_TYPE_INTERFACE: + case GLSL_TYPE_FUNCTION: assert(!"Should not get here."); break; } From 0db3e4dd7269c9eee48b165ce3560c042e73e8c0 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Tue, 24 Feb 2015 16:29:33 -0800 Subject: [PATCH 08/55] glsl/types: Add support for function types --- src/glsl/glsl_types.cpp | 102 ++++++++++++++++++++++++++++++++++++++++ src/glsl/glsl_types.h | 23 ++++++++- 2 files changed, 124 insertions(+), 1 deletion(-) diff --git a/src/glsl/glsl_types.cpp b/src/glsl/glsl_types.cpp index 50409dd50de..c737fb6e366 100644 --- a/src/glsl/glsl_types.cpp +++ b/src/glsl/glsl_types.cpp @@ -32,6 +32,7 @@ mtx_t glsl_type::mutex = _MTX_INITIALIZER_NP; hash_table *glsl_type::array_types = NULL; hash_table *glsl_type::record_types = NULL; hash_table *glsl_type::interface_types = NULL; +hash_table *glsl_type::function_types = NULL; hash_table *glsl_type::subroutine_types = NULL; void *glsl_type::mem_ctx = NULL; @@ -162,6 +163,39 @@ glsl_type::glsl_type(const glsl_struct_field *fields, unsigned num_fields, mtx_unlock(&glsl_type::mutex); } +glsl_type::glsl_type(const glsl_type *return_type, + const glsl_function_param *params, unsigned num_params) : + gl_type(0), + base_type(GLSL_TYPE_FUNCTION), + sampler_dimensionality(0), sampler_shadow(0), sampler_array(0), + sampler_type(0), interface_packing(0), + vector_elements(0), matrix_columns(0), + length(num_params) +{ + unsigned int i; + + mtx_lock(&glsl_type::mutex); + + init_ralloc_type_ctx(); + + this->fields.parameters = rzalloc_array(this->mem_ctx, + glsl_function_param, num_params + 1); + + /* We store the return type as the first parameter */ + this->fields.parameters[0].type = return_type; + this->fields.parameters[0].in = false; + this->fields.parameters[0].out = true; + + /* We store the i'th parameter in slot i+1 */ + for (i = 0; i < length; i++) { + this->fields.parameters[i + 1].type = params[i].type; + this->fields.parameters[i + 1].in = params[i].in; + this->fields.parameters[i + 1].out = params[i].out; + } + + mtx_unlock(&glsl_type::mutex); +} + glsl_type::glsl_type(const char *subroutine_name) : gl_type(0), base_type(GLSL_TYPE_SUBROUTINE), @@ -900,6 +934,74 @@ glsl_type::get_subroutine_instance(const char *subroutine_name) } +static bool +function_key_compare(const void *a, const void *b) +{ + const glsl_type *const key1 = (glsl_type *) a; + const glsl_type *const key2 = (glsl_type *) b; + + if (key1->length != key2->length) + return 1; + + return memcmp(key1->fields.parameters, key2->fields.parameters, + (key1->length + 1) * sizeof(*key1->fields.parameters)); +} + + +static uint32_t +function_key_hash(const void *a) +{ + const glsl_type *const key = (glsl_type *) a; + char hash_key[128]; + unsigned size = 0; + + size = snprintf(hash_key, sizeof(hash_key), "%08x", key->length); + + for (unsigned i = 0; i < key->length; i++) { + if (size >= sizeof(hash_key)) + break; + + size += snprintf(& hash_key[size], sizeof(hash_key) - size, + "%p", (void *) key->fields.structure[i].type); + } + + return _mesa_hash_string(hash_key); +} + +const glsl_type * +glsl_type::get_function_instance(const glsl_type *return_type, + const glsl_function_param *params, + unsigned num_params) +{ + const glsl_type key(return_type, params, num_params); + + mtx_lock(&glsl_type::mutex); + + if (function_types == NULL) { + function_types = _mesa_hash_table_create(NULL, function_key_hash, + function_key_compare); + } + + struct hash_entry *entry = _mesa_hash_table_search(function_types, &key); + if (entry == NULL) { + mtx_unlock(&glsl_type::mutex); + const glsl_type *t = new glsl_type(return_type, params, num_params); + mtx_lock(&glsl_type::mutex); + + entry = _mesa_hash_table_insert(function_types, t, (void *) t); + } + + const glsl_type *t = (const glsl_type *)entry->data; + + assert(t->base_type == GLSL_TYPE_FUNCTION); + assert(t->length == num_params); + + mtx_unlock(&glsl_type::mutex); + + return t; +} + + const glsl_type * glsl_type::get_mul_type(const glsl_type *type_a, const glsl_type *type_b) { diff --git a/src/glsl/glsl_types.h b/src/glsl/glsl_types.h index 3c5345955fa..daa809e3bae 100644 --- a/src/glsl/glsl_types.h +++ b/src/glsl/glsl_types.h @@ -180,7 +180,7 @@ struct glsl_type { */ union { const struct glsl_type *array; /**< Type of array elements. */ - const struct glsl_type *parameters; /**< Parameters to function. */ + struct glsl_function_param *parameters; /**< Parameters to function. */ struct glsl_struct_field *structure; /**< List of struct fields. */ } fields; @@ -270,6 +270,13 @@ struct glsl_type { */ static const glsl_type *get_subroutine_instance(const char *subroutine_name); + /** + * Get the instance of a function type + */ + static const glsl_type *get_function_instance(const struct glsl_type *return_type, + const glsl_function_param *parameters, + unsigned num_params); + /** * Get the type resulting from a multiplication of \p type_a * \p type_b */ @@ -690,6 +697,10 @@ private: glsl_type(const glsl_struct_field *fields, unsigned num_fields, enum glsl_interface_packing packing, const char *name); + /** Constructor for interface types */ + glsl_type(const glsl_type *return_type, + const glsl_function_param *params, unsigned num_params); + /** Constructor for array types */ glsl_type(const glsl_type *array, unsigned length); @@ -708,6 +719,9 @@ private: /** Hash table containing the known subroutine types. */ static struct hash_table *subroutine_types; + /** Hash table containing the known function types. */ + static struct hash_table *function_types; + static bool record_key_compare(const void *a, const void *b); static unsigned record_key_hash(const void *key); @@ -797,6 +811,13 @@ struct glsl_struct_field { } }; +struct glsl_function_param { + const struct glsl_type *type; + + bool in; + bool out; +}; + static inline unsigned int glsl_align(unsigned int a, unsigned int align) { From 53bff3e445b7c9697d7cfbbcd2207b21bbc6e08a Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 29 Apr 2015 14:48:12 -0700 Subject: [PATCH 09/55] glsl/types: Expose the function_param and struct_field structs to C Previously, they were hidden behind a #ifdef __cplusplus so C wouldn't find them. This commit simpliy moves the #ifdef and adds #ifdef's around constructors. --- src/glsl/glsl_types.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/glsl/glsl_types.h b/src/glsl/glsl_types.h index daa809e3bae..0a8a0b97dc9 100644 --- a/src/glsl/glsl_types.h +++ b/src/glsl/glsl_types.h @@ -749,6 +749,10 @@ private: /*@}*/ }; +#undef DECL_TYPE +#undef STRUCT_TYPE +#endif /* __cplusplus */ + struct glsl_struct_field { const struct glsl_type *type; const char *name; @@ -797,6 +801,7 @@ struct glsl_struct_field { */ int stream; +#ifdef __cplusplus glsl_struct_field(const struct glsl_type *_type, const char *_name) : type(_type), name(_name), location(-1), interpolation(0), centroid(0), sample(0), matrix_layout(GLSL_MATRIX_LAYOUT_INHERITED), patch(0), @@ -809,6 +814,7 @@ struct glsl_struct_field { { /* empty */ } +#endif }; struct glsl_function_param { @@ -824,8 +830,4 @@ glsl_align(unsigned int a, unsigned int align) return (a + align - 1) / align * align; } -#undef DECL_TYPE -#undef STRUCT_TYPE -#endif /* __cplusplus */ - #endif /* GLSL_TYPES_H */ From 5bb94c9b120cfd93ed362c9fa77ea274376b1d3b Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 29 Apr 2015 14:28:37 -0700 Subject: [PATCH 10/55] nir/types: Add more helpers for creating types --- src/glsl/nir/nir_types.cpp | 44 ++++++++++++++++++++++++++++++++++++-- src/glsl/nir/nir_types.h | 14 +++++++++++- 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/glsl/nir/nir_types.cpp b/src/glsl/nir/nir_types.cpp index 940c676005a..937a842d98e 100644 --- a/src/glsl/nir/nir_types.cpp +++ b/src/glsl/nir/nir_types.cpp @@ -149,9 +149,9 @@ glsl_float_type(void) } const glsl_type * -glsl_vec4_type(void) +glsl_int_type(void) { - return glsl_type::vec4_type; + return glsl_type::int_type; } const glsl_type * @@ -160,8 +160,48 @@ glsl_uint_type(void) return glsl_type::uint_type; } +const glsl_type * +glsl_bool_type(void) +{ + return glsl_type::bool_type; +} + +const glsl_type * +glsl_vec4_type(void) +{ + return glsl_type::vec4_type; +} + +const glsl_type * +glsl_vector_type(enum glsl_base_type base_type, unsigned components) +{ + assert(components > 1 && components <= 4); + return glsl_type::get_instance(base_type, components, 1); +} + +const glsl_type * +glsl_matrix_type(enum glsl_base_type base_type, unsigned rows, unsigned columns) +{ + assert(rows > 1 && rows <= 4 && columns > 1 && columns <= 4); + return glsl_type::get_instance(base_type, rows, columns); +} + const glsl_type * glsl_array_type(const glsl_type *base, unsigned elements) { return glsl_type::get_array_instance(base, elements); } + +const glsl_type * +glsl_struct_type(const glsl_struct_field *fields, + unsigned num_fields, const char *name) +{ + return glsl_type::get_record_instance(fields, num_fields, name); +} + +const glsl_type * +glsl_function_type(const glsl_type *return_type, + const glsl_function_param *params, unsigned num_params) +{ + return glsl_type::get_function_instance(return_type, params, num_params); +} diff --git a/src/glsl/nir/nir_types.h b/src/glsl/nir/nir_types.h index a8ff8f2c606..aad43f7a8c0 100644 --- a/src/glsl/nir/nir_types.h +++ b/src/glsl/nir/nir_types.h @@ -70,10 +70,22 @@ bool glsl_type_is_matrix(const struct glsl_type *type); const struct glsl_type *glsl_void_type(void); const struct glsl_type *glsl_float_type(void); -const struct glsl_type *glsl_vec4_type(void); +const struct glsl_type *glsl_int_type(void); const struct glsl_type *glsl_uint_type(void); +const struct glsl_type *glsl_bool_type(void); + +const struct glsl_type *glsl_vec4_type(void); +const struct glsl_type *glsl_vector_type(enum glsl_base_type base_type, + unsigned components); +const struct glsl_type *glsl_matrix_type(enum glsl_base_type base_type, + unsigned rows, unsigned columns); const struct glsl_type *glsl_array_type(const struct glsl_type *base, unsigned elements); +const struct glsl_type *glsl_struct_type(const struct glsl_struct_field *fields, + unsigned num_fields, const char *name); +const struct glsl_type * glsl_function_type(const struct glsl_type *return_type, + const struct glsl_function_param *params, + unsigned num_params); #ifdef __cplusplus } From 2a023f30a644821550e0d529078a05af12188fcb Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 29 Apr 2015 14:36:01 -0700 Subject: [PATCH 11/55] nir/spirv: Add basic support for types --- src/glsl/nir/spirv_to_nir.c | 89 +++++++++++++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 4 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index 05193531107..6c9b776922a 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -26,6 +26,7 @@ */ #include "nir_spirv.h" +#include "nir_vla.h" #include "spirv.h" struct vtn_decoration; @@ -35,6 +36,7 @@ enum vtn_value_type { vtn_value_type_undef, vtn_value_type_string, vtn_value_type_decoration_group, + vtn_value_type_type, vtn_value_type_ssa, vtn_value_type_deref, }; @@ -46,6 +48,7 @@ struct vtn_value { union { void *ptr; char *str; + const struct glsl_type *type; nir_ssa_def *ssa; nir_deref_var *deref; }; @@ -184,11 +187,88 @@ vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode, } } -static void +static const struct glsl_type * vtn_handle_type(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) + const uint32_t *args, unsigned count) { - unreachable("Unhandled opcode"); + switch (opcode) { + case SpvOpTypeVoid: + return glsl_void_type(); + case SpvOpTypeBool: + return glsl_bool_type(); + case SpvOpTypeInt: + return glsl_int_type(); + case SpvOpTypeFloat: + return glsl_float_type(); + + case SpvOpTypeVector: { + const struct glsl_type *base = b->values[args[0]].type; + unsigned elems = args[1]; + + assert(glsl_type_is_scalar(base)); + return glsl_vector_type(glsl_get_base_type(base), elems); + } + + case SpvOpTypeMatrix: { + const struct glsl_type *base = b->values[args[0]].type; + unsigned columns = args[1]; + + assert(glsl_type_is_vector(base)); + return glsl_matrix_type(glsl_get_base_type(base), + glsl_get_vector_elements(base), + columns); + } + + case SpvOpTypeArray: + return glsl_array_type(b->values[args[0]].type, args[1]); + + case SpvOpTypeStruct: { + NIR_VLA(struct glsl_struct_field, fields, count); + for (unsigned i = 0; i < count; i++) { + /* TODO: Handle decorators */ + fields[i].type = b->values[args[i]].type; + fields[i].name = ralloc_asprintf(b, "field%d", i); + fields[i].location = -1; + fields[i].interpolation = 0; + fields[i].centroid = 0; + fields[i].sample = 0; + fields[i].matrix_layout = 2; + fields[i].stream = -1; + } + return glsl_struct_type(fields, count, "struct"); + } + + case SpvOpTypeFunction: { + const struct glsl_type *return_type = b->values[args[0]].type; + NIR_VLA(struct glsl_function_param, params, count - 1); + for (unsigned i = 1; i < count; i++) { + params[i - 1].type = b->values[args[i]].type; + + /* FIXME: */ + params[i - 1].in = true; + params[i - 1].out = true; + } + return glsl_function_type(return_type, params, count - 1); + } + + case SpvOpTypePointer: + /* FIXME: For now, we'll just do the really lame thing and return + * the same type. The validator should ensure that the proper number + * of dereferences happen + */ + return b->values[args[0]].type; + + case SpvOpTypeSampler: + case SpvOpTypeRuntimeArray: + case SpvOpTypeOpaque: + case SpvOpTypeEvent: + case SpvOpTypeDeviceEvent: + case SpvOpTypeReserveId: + case SpvOpTypeQueue: + case SpvOpTypePipe: + default: + unreachable("Unhandled opcode"); + } } static void @@ -279,7 +359,8 @@ vtn_handle_instruction(struct vtn_builder *b, SpvOp opcode, case SpvOpTypeReserveId: case SpvOpTypeQueue: case SpvOpTypePipe: - vtn_handle_type(b, opcode, w, count); + vtn_push_value(b, w[1], vtn_value_type_type)->type = + vtn_handle_type(b, opcode, &w[2], count - 2); break; case SpvOpConstantTrue: From 24940556313ccb21c79fdbe6a0cdd061f49ba4c8 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 29 Apr 2015 18:14:11 -0700 Subject: [PATCH 12/55] nir/spirv: Add support for constants --- src/glsl/nir/spirv_to_nir.c | 68 ++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index 6c9b776922a..f22ec77b68e 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -37,6 +37,7 @@ enum vtn_value_type { vtn_value_type_string, vtn_value_type_decoration_group, vtn_value_type_type, + vtn_value_type_constant, vtn_value_type_ssa, vtn_value_type_deref, }; @@ -49,6 +50,7 @@ struct vtn_value { void *ptr; char *str; const struct glsl_type *type; + nir_constant *constant; nir_ssa_def *ssa; nir_deref_var *deref; }; @@ -84,6 +86,15 @@ vtn_push_value(struct vtn_builder *b, uint32_t value_id, return &b->values[value_id]; } +static struct vtn_value * +vtn_value(struct vtn_builder *b, uint32_t value_id, + enum vtn_value_type value_type) +{ + assert(value_id < b->value_id_bound); + assert(b->values[value_id].value_type == value_type); + return &b->values[value_id]; +} + static char * vtn_string_literal(struct vtn_builder *b, const uint32_t *words, unsigned word_count) @@ -275,7 +286,62 @@ static void vtn_handle_constant(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) { - unreachable("Unhandled opcode"); + const struct glsl_type *type = vtn_value(b, w[1], vtn_value_type_type)->type; + nir_constant *constant = ralloc(b, nir_constant); + switch (opcode) { + case SpvOpConstantTrue: + assert(type == glsl_bool_type()); + constant->value.u[0] = NIR_TRUE; + break; + case SpvOpConstantFalse: + assert(type == glsl_bool_type()); + constant->value.u[0] = NIR_FALSE; + break; + case SpvOpConstant: + assert(glsl_type_is_scalar(type)); + constant->value.u[0] = w[3]; + break; + case SpvOpConstantComposite: { + unsigned elem_count = count - 3; + nir_constant **elems = ralloc_array(b, nir_constant *, elem_count); + for (unsigned i = 0; i < elem_count; i++) + elems[i] = vtn_value(b, w[i + 3], vtn_value_type_constant)->constant; + + switch (glsl_get_base_type(type)) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_BOOL: + if (glsl_type_is_matrix(type)) { + unsigned rows = glsl_get_vector_elements(type); + assert(glsl_get_matrix_columns(type) == elem_count); + for (unsigned i = 0; i < elem_count; i++) + for (unsigned j = 0; j < rows; j++) + constant->value.u[rows * i + j] = elems[i]->value.u[j]; + } else { + assert(glsl_type_is_vector(type)); + assert(glsl_get_vector_elements(type) == elem_count); + for (unsigned i = 0; i < elem_count; i++) + constant->value.u[i] = elems[i]->value.u[0]; + } + ralloc_free(elems); + break; + + case GLSL_TYPE_STRUCT: + case GLSL_TYPE_ARRAY: + constant->elements = elems; + break; + + default: + unreachable("Unsupported type for constants"); + } + break; + } + + default: + unreachable("Unhandled opcode"); + } + vtn_push_value(b, w[2], vtn_value_type_constant)->constant = constant; } static void From 3a266a18ae5df27f78c442628a84ba2ab11dfb9d Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 29 Apr 2015 19:37:41 -0700 Subject: [PATCH 13/55] nir/spirv: Add support for declaring variables Deref chains and variable load/store operations are still missing. --- src/glsl/nir/spirv_to_nir.c | 152 +++++++++++++++++++++++++++++++++++- 1 file changed, 151 insertions(+), 1 deletion(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index f22ec77b68e..ab8b4465324 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -38,6 +38,7 @@ enum vtn_value_type { vtn_value_type_decoration_group, vtn_value_type_type, vtn_value_type_constant, + vtn_value_type_variable, vtn_value_type_ssa, vtn_value_type_deref, }; @@ -51,6 +52,7 @@ struct vtn_value { char *str; const struct glsl_type *type; nir_constant *constant; + nir_variable *var; nir_ssa_def *ssa; nir_deref_var *deref; }; @@ -344,11 +346,159 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode, vtn_push_value(b, w[2], vtn_value_type_constant)->constant = constant; } +static void +var_decoration_cb(struct vtn_builder *b, struct vtn_value *val, + const struct vtn_decoration *dec, void *unused) +{ + assert(val->value_type == vtn_value_type_variable); + nir_variable *var = val->var; + switch (dec->decoration) { + case SpvDecorationPrecisionLow: + case SpvDecorationPrecisionMedium: + case SpvDecorationPrecisionHigh: + break; /* FIXME: Do nothing with these for now. */ + case SpvDecorationSmooth: + var->data.interpolation = INTERP_QUALIFIER_SMOOTH; + break; + case SpvDecorationNoperspective: + var->data.interpolation = INTERP_QUALIFIER_NOPERSPECTIVE; + break; + case SpvDecorationFlat: + var->data.interpolation = INTERP_QUALIFIER_FLAT; + break; + case SpvDecorationCentroid: + var->data.centroid = true; + break; + case SpvDecorationSample: + var->data.sample = true; + break; + case SpvDecorationInvariant: + var->data.invariant = true; + break; + case SpvDecorationConstant: + assert(var->constant_initializer != NULL); + var->data.read_only = true; + break; + case SpvDecorationNonwritable: + var->data.read_only = true; + break; + case SpvDecorationLocation: + var->data.explicit_location = true; + var->data.location = dec->literals[0]; + break; + case SpvDecorationComponent: + var->data.location_frac = dec->literals[0]; + break; + case SpvDecorationIndex: + var->data.explicit_index = true; + var->data.index = dec->literals[0]; + break; + case SpvDecorationBinding: + var->data.explicit_binding = true; + var->data.binding = dec->literals[0]; + break; + case SpvDecorationBlock: + case SpvDecorationBufferBlock: + case SpvDecorationRowMajor: + case SpvDecorationColMajor: + case SpvDecorationGLSLShared: + case SpvDecorationGLSLStd140: + case SpvDecorationGLSLStd430: + case SpvDecorationGLSLPacked: + case SpvDecorationPatch: + case SpvDecorationRestrict: + case SpvDecorationAliased: + case SpvDecorationVolatile: + case SpvDecorationCoherent: + case SpvDecorationNonreadable: + case SpvDecorationUniform: + /* This is really nice but we have no use for it right now. */ + case SpvDecorationNoStaticUse: + case SpvDecorationCPacked: + case SpvDecorationSaturatedConversion: + case SpvDecorationStream: + case SpvDecorationDescriptorSet: + case SpvDecorationOffset: + case SpvDecorationAlignment: + case SpvDecorationXfbBuffer: + case SpvDecorationStride: + case SpvDecorationBuiltIn: + case SpvDecorationFuncParamAttr: + case SpvDecorationFPRoundingMode: + case SpvDecorationFPFastMathMode: + case SpvDecorationLinkageAttributes: + case SpvDecorationSpecId: + default: + unreachable("Unhandled variable decoration"); + } +} + static void vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) { - unreachable("Unhandled opcode"); + switch (opcode) { + case SpvOpVariable: { + const struct glsl_type *type = + vtn_value(b, w[1], vtn_value_type_type)->type; + struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_variable); + + nir_variable *var = ralloc(b->shader, nir_variable); + val->var = var; + + var->type = type; + var->name = ralloc_strdup(var, val->name); + + switch ((SpvStorageClass)w[3]) { + case SpvStorageClassUniformConstant: + var->data.mode = nir_var_uniform; + var->data.read_only = true; + break; + case SpvStorageClassInput: + var->data.mode = nir_var_shader_in; + var->data.read_only = true; + break; + case SpvStorageClassOutput: + var->data.mode = nir_var_shader_out; + break; + case SpvStorageClassPrivateGlobal: + var->data.mode = nir_var_global; + break; + case SpvStorageClassFunction: + var->data.mode = nir_var_local; + break; + case SpvStorageClassUniform: + case SpvStorageClassWorkgroupLocal: + case SpvStorageClassWorkgroupGlobal: + case SpvStorageClassGeneric: + case SpvStorageClassPrivate: + case SpvStorageClassAtomicCounter: + default: + unreachable("Unhandled variable storage class"); + } + + if (count > 4) { + assert(count == 5); + var->constant_initializer = + vtn_value(b, w[4], vtn_value_type_constant)->constant; + } + + vtn_foreach_decoration(b, val, var_decoration_cb, NULL); + break; + } + + case SpvOpVariableArray: + case SpvOpLoad: + case SpvOpStore: + case SpvOpCopyMemory: + case SpvOpCopyMemorySized: + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: + case SpvOpArrayLength: + case SpvOpImagePointer: + default: + unreachable("Unhandled opcode"); + } } static void From ac4d459aa2e018d8a4e1ff6b739dc6f93e5730f8 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 29 Apr 2015 20:09:36 -0700 Subject: [PATCH 14/55] nir/types: Add accessors for function parameter/return types --- src/glsl/nir/nir_types.cpp | 12 ++++++++++++ src/glsl/nir/nir_types.h | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/src/glsl/nir/nir_types.cpp b/src/glsl/nir/nir_types.cpp index 937a842d98e..f2894d40c78 100644 --- a/src/glsl/nir/nir_types.cpp +++ b/src/glsl/nir/nir_types.cpp @@ -70,6 +70,18 @@ glsl_get_struct_field(const glsl_type *type, unsigned index) return type->fields.structure[index].type; } +const glsl_type * +glsl_get_function_return_type(const glsl_type *type) +{ + return type->fields.parameters[0].type; +} + +const glsl_function_param * +glsl_get_function_param(const glsl_type *type, unsigned index) +{ + return &type->fields.parameters[index + 1]; +} + const struct glsl_type * glsl_get_column_type(const struct glsl_type *type) { diff --git a/src/glsl/nir/nir_types.h b/src/glsl/nir/nir_types.h index aad43f7a8c0..dd535770c9f 100644 --- a/src/glsl/nir/nir_types.h +++ b/src/glsl/nir/nir_types.h @@ -49,6 +49,12 @@ const struct glsl_type *glsl_get_array_element(const struct glsl_type *type); const struct glsl_type *glsl_get_column_type(const struct glsl_type *type); +const struct glsl_type * +glsl_get_function_return_type(const struct glsl_type *type); + +const struct glsl_function_param * +glsl_get_function_param(const struct glsl_type *type, unsigned index); + enum glsl_base_type glsl_get_base_type(const struct glsl_type *type); unsigned glsl_get_vector_elements(const struct glsl_type *type); From 399e962d2553814c947f25773c07a5b2944fdb9b Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 29 Apr 2015 20:10:20 -0700 Subject: [PATCH 15/55] nir/spirv: Add support for declaring functions --- src/glsl/nir/spirv_to_nir.c | 67 +++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index ab8b4465324..67db9a99e9e 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -39,6 +39,7 @@ enum vtn_value_type { vtn_value_type_type, vtn_value_type_constant, vtn_value_type_variable, + vtn_value_type_function, vtn_value_type_ssa, vtn_value_type_deref, }; @@ -53,6 +54,7 @@ struct vtn_value { const struct glsl_type *type; nir_constant *constant; nir_variable *var; + nir_function_impl *impl; nir_ssa_def *ssa; nir_deref_var *deref; }; @@ -68,6 +70,7 @@ struct vtn_decoration { struct vtn_builder { nir_shader *shader; nir_function_impl *impl; + struct exec_list *cf_list; unsigned value_id_bound; struct vtn_value *values; @@ -501,6 +504,63 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, } } +static void +vtn_handle_functions(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) +{ + switch (opcode) { + case SpvOpFunction: { + assert(b->impl == NULL); + + const struct glsl_type *result_type = + vtn_value(b, w[1], vtn_value_type_type)->type; + struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_function); + const struct glsl_type *func_type = + vtn_value(b, w[4], vtn_value_type_type)->type; + + assert(glsl_get_function_return_type(func_type) == result_type); + + nir_function *func = + nir_function_create(b->shader, ralloc_strdup(b->shader, val->name)); + + nir_function_overload *overload = nir_function_overload_create(func); + overload->num_params = glsl_get_length(func_type); + overload->params = ralloc_array(overload, nir_parameter, + overload->num_params); + for (unsigned i = 0; i < overload->num_params; i++) { + const struct glsl_function_param *param = + glsl_get_function_param(func_type, i); + overload->params[i].type = param->type; + if (param->in) { + if (param->out) { + overload->params[i].param_type = nir_parameter_inout; + } else { + overload->params[i].param_type = nir_parameter_in; + } + } else { + if (param->out) { + overload->params[i].param_type = nir_parameter_out; + } else { + assert(!"Parameter is neither in nor out"); + } + } + } + + val->impl = b->impl = nir_function_impl_create(overload); + b->cf_list = &b->impl->body; + + break; + } + case SpvOpFunctionEnd: + b->impl = NULL; + break; + case SpvOpFunctionParameter: + case SpvOpFunctionCall: + default: + unreachable("Unhandled opcode"); + } +} + static void vtn_handle_texture(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) @@ -614,6 +674,13 @@ vtn_handle_instruction(struct vtn_builder *b, SpvOp opcode, vtn_handle_decoration(b, opcode, w, count); break; + case SpvOpFunction: + case SpvOpFunctionEnd: + case SpvOpFunctionParameter: + case SpvOpFunctionCall: + vtn_handle_functions(b, opcode, w, count); + break; + case SpvOpTextureSample: case SpvOpTextureSampleDref: case SpvOpTextureSampleLod: From befecb3c553fd7418ff9bc8a85e685b84621cb58 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 29 Apr 2015 20:19:34 -0700 Subject: [PATCH 16/55] nir/spirv: Add support for OpLabel --- src/glsl/nir/spirv_to_nir.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index 67db9a99e9e..5b171ece8bf 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -40,6 +40,7 @@ enum vtn_value_type { vtn_value_type_constant, vtn_value_type_variable, vtn_value_type_function, + vtn_value_type_block, vtn_value_type_ssa, vtn_value_type_deref, }; @@ -55,6 +56,7 @@ struct vtn_value { nir_constant *constant; nir_variable *var; nir_function_impl *impl; + nir_block *block; nir_ssa_def *ssa; nir_deref_var *deref; }; @@ -612,6 +614,17 @@ vtn_handle_instruction(struct vtn_builder *b, SpvOp opcode, b->execution_model = w[1]; break; + case SpvOpLabel: { + struct exec_node *list_tail = exec_list_get_tail(b->cf_list); + nir_cf_node *tail_node = exec_node_data(nir_cf_node, list_tail, node); + assert(tail_node->type == nir_cf_node_block); + nir_block *block = nir_cf_node_as_block(tail_node); + + assert(exec_list_is_empty(&block->instr_list)); + vtn_push_value(b, w[1], vtn_value_type_block)->block = block; + break; + } + case SpvOpExtInstImport: case SpvOpExtInst: vtn_handle_extension(b, opcode, w, count); From 366366c7f7fe24d9bc2a7f3d7464c49ccdb73813 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 29 Apr 2015 20:56:17 -0700 Subject: [PATCH 17/55] nir/types: Add a scalar type constructor --- src/glsl/nir/nir_types.cpp | 6 ++++++ src/glsl/nir/nir_types.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/glsl/nir/nir_types.cpp b/src/glsl/nir/nir_types.cpp index f2894d40c78..f93a52b5fa5 100644 --- a/src/glsl/nir/nir_types.cpp +++ b/src/glsl/nir/nir_types.cpp @@ -184,6 +184,12 @@ glsl_vec4_type(void) return glsl_type::vec4_type; } +const glsl_type * +glsl_scalar_type(enum glsl_base_type base_type) +{ + return glsl_type::get_instance(base_type, 1, 1); +} + const glsl_type * glsl_vector_type(enum glsl_base_type base_type, unsigned components) { diff --git a/src/glsl/nir/nir_types.h b/src/glsl/nir/nir_types.h index dd535770c9f..40a80ec7130 100644 --- a/src/glsl/nir/nir_types.h +++ b/src/glsl/nir/nir_types.h @@ -81,6 +81,7 @@ const struct glsl_type *glsl_uint_type(void); const struct glsl_type *glsl_bool_type(void); const struct glsl_type *glsl_vec4_type(void); +const struct glsl_type *glsl_scalar_type(enum glsl_base_type base_type); const struct glsl_type *glsl_vector_type(enum glsl_base_type base_type, unsigned components); const struct glsl_type *glsl_matrix_type(enum glsl_base_type base_type, From 5e6c5e3c8e7a68452d8f2afc27472337a2457114 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 29 Apr 2015 20:56:36 -0700 Subject: [PATCH 18/55] nir/spirv: Add support for deref chains --- src/glsl/nir/spirv_to_nir.c | 86 +++++++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 12 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index 5b171ece8bf..a7ce17a77d5 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -38,11 +38,10 @@ enum vtn_value_type { vtn_value_type_decoration_group, vtn_value_type_type, vtn_value_type_constant, - vtn_value_type_variable, + vtn_value_type_deref, vtn_value_type_function, vtn_value_type_block, vtn_value_type_ssa, - vtn_value_type_deref, }; struct vtn_value { @@ -54,11 +53,10 @@ struct vtn_value { char *str; const struct glsl_type *type; nir_constant *constant; - nir_variable *var; + nir_deref_var *deref; nir_function_impl *impl; nir_block *block; nir_ssa_def *ssa; - nir_deref_var *deref; }; }; @@ -353,10 +351,13 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode, static void var_decoration_cb(struct vtn_builder *b, struct vtn_value *val, - const struct vtn_decoration *dec, void *unused) + const struct vtn_decoration *dec, void *void_var) { - assert(val->value_type == vtn_value_type_variable); - nir_variable *var = val->var; + assert(val->value_type == vtn_value_type_deref); + assert(val->deref->deref.child == NULL); + assert(val->deref->var == void_var); + + nir_variable *var = void_var; switch (dec->decoration) { case SpvDecorationPrecisionLow: case SpvDecorationPrecisionMedium: @@ -446,10 +447,9 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, case SpvOpVariable: { const struct glsl_type *type = vtn_value(b, w[1], vtn_value_type_type)->type; - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_variable); + struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_deref); nir_variable *var = ralloc(b->shader, nir_variable); - val->var = var; var->type = type; var->name = ralloc_strdup(var, val->name); @@ -488,7 +488,71 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, vtn_value(b, w[4], vtn_value_type_constant)->constant; } - vtn_foreach_decoration(b, val, var_decoration_cb, NULL); + val->deref = nir_deref_var_create(b->shader, var); + + vtn_foreach_decoration(b, val, var_decoration_cb, var); + break; + } + + case SpvOpAccessChain: + case SpvOpInBoundsAccessChain: { + struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_deref); + nir_deref_var *base = vtn_value(b, w[3], vtn_value_type_deref)->deref; + val->deref = nir_deref_as_var(nir_copy_deref(b, &base->deref)); + + nir_deref *tail = &val->deref->deref; + while (tail->child) + tail = tail->child; + + for (unsigned i = 0; i < count - 3; i++) { + assert(w[i + 3] < b->value_id_bound); + struct vtn_value *idx_val = &b->values[w[i + 3]]; + + enum glsl_base_type base_type = glsl_get_base_type(tail->type); + switch (base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_DOUBLE: + case GLSL_TYPE_BOOL: + case GLSL_TYPE_ARRAY: { + nir_deref_array *deref_arr = nir_deref_array_create(b); + if (base_type == GLSL_TYPE_ARRAY) { + deref_arr->deref.type = glsl_get_array_element(tail->type); + } else if (glsl_type_is_matrix(tail->type)) { + deref_arr->deref.type = glsl_get_column_type(tail->type); + } else { + assert(glsl_type_is_vector(tail->type)); + deref_arr->deref.type = glsl_scalar_type(base_type); + } + + if (idx_val->value_type == vtn_value_type_constant) { + unsigned idx = idx_val->constant->value.u[0]; + deref_arr->deref_array_type = nir_deref_array_type_direct; + deref_arr->base_offset = idx; + } else { + assert(idx_val->value_type == vtn_value_type_ssa); + deref_arr->deref_array_type = nir_deref_array_type_indirect; + /* TODO */ + unreachable("Indirect array accesses not implemented"); + } + tail->child = &deref_arr->deref; + break; + } + + case GLSL_TYPE_STRUCT: { + assert(idx_val->value_type == vtn_value_type_constant); + unsigned idx = idx_val->constant->value.u[0]; + nir_deref_struct *deref_struct = nir_deref_struct_create(b, idx); + deref_struct->deref.type = glsl_get_struct_field(tail->type, idx); + tail->child = &deref_struct->deref; + break; + } + default: + unreachable("Invalid type for deref"); + } + tail = tail->child; + } break; } @@ -497,8 +561,6 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, case SpvOpStore: case SpvOpCopyMemory: case SpvOpCopyMemorySized: - case SpvOpAccessChain: - case SpvOpInBoundsAccessChain: case SpvOpArrayLength: case SpvOpImagePointer: default: From 67af6c59f22cf5a223e539faa4215e7722bda75c Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Fri, 1 May 2015 11:26:40 -0700 Subject: [PATCH 19/55] nir/types: Add an is_vector_or_scalar helper --- src/glsl/nir/nir_types.cpp | 6 ++++++ src/glsl/nir/nir_types.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/glsl/nir/nir_types.cpp b/src/glsl/nir/nir_types.cpp index f93a52b5fa5..a6d35fe6179 100644 --- a/src/glsl/nir/nir_types.cpp +++ b/src/glsl/nir/nir_types.cpp @@ -142,6 +142,12 @@ glsl_type_is_scalar(const struct glsl_type *type) return type->is_scalar(); } +bool +glsl_type_is_vector_or_scalar(const struct glsl_type *type) +{ + return type->is_vector() || type->is_scalar(); +} + bool glsl_type_is_matrix(const struct glsl_type *type) { diff --git a/src/glsl/nir/nir_types.h b/src/glsl/nir/nir_types.h index 40a80ec7130..f19f0e5db5d 100644 --- a/src/glsl/nir/nir_types.h +++ b/src/glsl/nir/nir_types.h @@ -72,6 +72,7 @@ const char *glsl_get_struct_elem_name(const struct glsl_type *type, bool glsl_type_is_void(const struct glsl_type *type); bool glsl_type_is_vector(const struct glsl_type *type); bool glsl_type_is_scalar(const struct glsl_type *type); +bool glsl_type_is_vector_or_scalar(const struct glsl_type *type); bool glsl_type_is_matrix(const struct glsl_type *type); const struct glsl_type *glsl_void_type(void); From e709a4ebb8d3ebcdd101899223dd239b647a540b Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Fri, 1 May 2015 11:27:21 -0700 Subject: [PATCH 20/55] nir/spirv: Use vtn_value in the types code and fix a off-by-one error --- src/glsl/nir/spirv_to_nir.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index a7ce17a77d5..abcdd66a4f7 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -218,7 +218,8 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode, return glsl_float_type(); case SpvOpTypeVector: { - const struct glsl_type *base = b->values[args[0]].type; + const struct glsl_type *base = + vtn_value(b, args[0], vtn_value_type_type)->type; unsigned elems = args[1]; assert(glsl_type_is_scalar(base)); @@ -226,7 +227,8 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode, } case SpvOpTypeMatrix: { - const struct glsl_type *base = b->values[args[0]].type; + const struct glsl_type *base = + vtn_value(b, args[0], vtn_value_type_type)->type; unsigned columns = args[1]; assert(glsl_type_is_vector(base)); @@ -242,7 +244,7 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode, NIR_VLA(struct glsl_struct_field, fields, count); for (unsigned i = 0; i < count; i++) { /* TODO: Handle decorators */ - fields[i].type = b->values[args[i]].type; + fields[i].type = vtn_value(b, args[i], vtn_value_type_type)->type; fields[i].name = ralloc_asprintf(b, "field%d", i); fields[i].location = -1; fields[i].interpolation = 0; @@ -258,7 +260,7 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode, const struct glsl_type *return_type = b->values[args[0]].type; NIR_VLA(struct glsl_function_param, params, count - 1); for (unsigned i = 1; i < count; i++) { - params[i - 1].type = b->values[args[i]].type; + params[i - 1].type = vtn_value(b, args[i], vtn_value_type_type)->type; /* FIXME: */ params[i - 1].in = true; @@ -272,7 +274,7 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode, * the same type. The validator should ensure that the proper number * of dereferences happen */ - return b->values[args[0]].type; + return vtn_value(b, args[1], vtn_value_type_type)->type; case SpvOpTypeSampler: case SpvOpTypeRuntimeArray: From 4fa1366392ef3c9779ffe265bd6c39bd483249de Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Fri, 1 May 2015 11:27:44 -0700 Subject: [PATCH 21/55] nir/spirv: Add a vtn_untyped_value helper --- src/glsl/nir/spirv_to_nir.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index abcdd66a4f7..a71119fe524 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -91,13 +91,20 @@ vtn_push_value(struct vtn_builder *b, uint32_t value_id, return &b->values[value_id]; } +static struct vtn_value * +vtn_untyped_value(struct vtn_builder *b, uint32_t value_id) +{ + assert(value_id < b->value_id_bound); + return &b->values[value_id]; +} + static struct vtn_value * vtn_value(struct vtn_builder *b, uint32_t value_id, enum vtn_value_type value_type) { - assert(value_id < b->value_id_bound); - assert(b->values[value_id].value_type == value_type); - return &b->values[value_id]; + struct vtn_value *val = vtn_untyped_value(b, value_id); + assert(val->value_type == value_type); + return val; } static char * From 112c607216ae53ad19380970988309a96d5a1fd8 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Fri, 1 May 2015 11:28:01 -0700 Subject: [PATCH 22/55] nir/spirv: Actaully add variables to the funciton or shader --- src/glsl/nir/spirv_to_nir.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index a71119fe524..61514c1d469 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -497,6 +497,12 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, vtn_value(b, w[4], vtn_value_type_constant)->constant; } + if (var->data.mode == nir_var_local) { + exec_list_push_tail(&b->impl->locals, &var->node); + } else { + exec_list_push_tail(&b->shader->globals, &var->node); + } + val->deref = nir_deref_var_create(b->shader, var); vtn_foreach_decoration(b, val, var_decoration_cb, var); From 7d64741a5e68c238e49486730b2aa3a32fefa49f Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 4 May 2015 10:19:24 -0700 Subject: [PATCH 23/55] nir: Add a helper for getting the tail of a deref chain --- src/glsl/nir/nir.h | 9 +++++++++ src/glsl/nir/nir_lower_var_copies.c | 15 ++------------- src/glsl/nir/nir_split_var_copies.c | 12 ++---------- 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h index 9703372fcc0..fc8f27a7fe5 100644 --- a/src/glsl/nir/nir.h +++ b/src/glsl/nir/nir.h @@ -777,6 +777,15 @@ NIR_DEFINE_CAST(nir_deref_as_var, nir_deref, nir_deref_var, deref) NIR_DEFINE_CAST(nir_deref_as_array, nir_deref, nir_deref_array, deref) NIR_DEFINE_CAST(nir_deref_as_struct, nir_deref, nir_deref_struct, deref) +/** Returns the tail of a deref chain */ +static inline nir_deref * +nir_deref_tail(nir_deref *deref) +{ + while (deref->child) + deref = deref->child; + return deref; +} + typedef struct { nir_instr instr; diff --git a/src/glsl/nir/nir_lower_var_copies.c b/src/glsl/nir/nir_lower_var_copies.c index 21672901f04..98c107aa50e 100644 --- a/src/glsl/nir/nir_lower_var_copies.c +++ b/src/glsl/nir/nir_lower_var_copies.c @@ -53,17 +53,6 @@ deref_next_wildcard_parent(nir_deref *deref) return NULL; } -/* Returns the last deref in the chain. - */ -static nir_deref * -get_deref_tail(nir_deref *deref) -{ - while (deref->child) - deref = deref->child; - - return deref; -} - /* This function recursively walks the given deref chain and replaces the * given copy instruction with an equivalent sequence load/store * operations. @@ -121,8 +110,8 @@ emit_copy_load_store(nir_intrinsic_instr *copy_instr, } else { /* In this case, we have no wildcards anymore, so all we have to do * is just emit the load and store operations. */ - src_tail = get_deref_tail(src_tail); - dest_tail = get_deref_tail(dest_tail); + src_tail = nir_deref_tail(src_tail); + dest_tail = nir_deref_tail(dest_tail); assert(src_tail->type == dest_tail->type); diff --git a/src/glsl/nir/nir_split_var_copies.c b/src/glsl/nir/nir_split_var_copies.c index fc72c078c77..5c163b59819 100644 --- a/src/glsl/nir/nir_split_var_copies.c +++ b/src/glsl/nir/nir_split_var_copies.c @@ -66,14 +66,6 @@ struct split_var_copies_state { void *dead_ctx; }; -static nir_deref * -get_deref_tail(nir_deref *deref) -{ - while (deref->child != NULL) - deref = deref->child; - return deref; -} - /* Recursively constructs deref chains to split a copy instruction into * multiple (if needed) copy instructions with full-length deref chains. * External callers of this function should pass the tail and head of the @@ -225,8 +217,8 @@ split_var_copies_block(nir_block *block, void *void_state) nir_deref *dest_head = &intrinsic->variables[0]->deref; nir_deref *src_head = &intrinsic->variables[1]->deref; - nir_deref *dest_tail = get_deref_tail(dest_head); - nir_deref *src_tail = get_deref_tail(src_head); + nir_deref *dest_tail = nir_deref_tail(dest_head); + nir_deref *src_tail = nir_deref_tail(src_head); switch (glsl_get_base_type(src_tail->type)) { case GLSL_TYPE_ARRAY: From 7bf4b53f1ccb29c2beca24be19fcf76436cad0d1 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Fri, 1 May 2015 11:28:18 -0700 Subject: [PATCH 24/55] nir/spirv: Implement load/store instructiosn --- src/glsl/nir/spirv_to_nir.c | 72 +++++++++++++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 6 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index 61514c1d469..b9d35766019 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -519,9 +519,9 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, while (tail->child) tail = tail->child; - for (unsigned i = 0; i < count - 3; i++) { - assert(w[i + 3] < b->value_id_bound); - struct vtn_value *idx_val = &b->values[w[i + 3]]; + for (unsigned i = 0; i < count - 4; i++) { + assert(w[i + 4] < b->value_id_bound); + struct vtn_value *idx_val = &b->values[w[i + 4]]; enum glsl_base_type base_type = glsl_get_base_type(tail->type); switch (base_type) { @@ -571,10 +571,70 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, break; } + case SpvOpCopyMemory: { + nir_deref_var *dest = vtn_value(b, w[1], vtn_value_type_deref)->deref; + nir_deref_var *src = vtn_value(b, w[2], vtn_value_type_deref)->deref; + + nir_intrinsic_instr *copy = + nir_intrinsic_instr_create(b->shader, nir_intrinsic_copy_var); + copy->variables[0] = nir_deref_as_var(nir_copy_deref(copy, &dest->deref)); + copy->variables[1] = nir_deref_as_var(nir_copy_deref(copy, &src->deref)); + + nir_instr_insert_after_cf_list(b->cf_list, ©->instr); + break; + } + + case SpvOpLoad: { + struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); + nir_deref_var *src = vtn_value(b, w[3], vtn_value_type_deref)->deref; + const struct glsl_type *src_type = nir_deref_tail(&src->deref)->type; + assert(glsl_type_is_vector_or_scalar(src_type)); + + nir_intrinsic_instr *load = + nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_var); + load->variables[0] = nir_deref_as_var(nir_copy_deref(load, &src->deref)); + load->num_components = glsl_get_vector_elements(src_type); + nir_ssa_dest_init(&load->instr, &load->dest, load->num_components, + val->name); + + nir_instr_insert_after_cf_list(b->cf_list, &load->instr); + val->ssa = &load->dest.ssa; + break; + } + + case SpvOpStore: { + nir_deref_var *dest = vtn_value(b, w[1], vtn_value_type_deref)->deref; + const struct glsl_type *dest_type = nir_deref_tail(&dest->deref)->type; + struct vtn_value *src_val = vtn_untyped_value(b, w[2]); + if (src_val->value_type == vtn_value_type_ssa) { + assert(glsl_type_is_vector_or_scalar(dest_type)); + nir_intrinsic_instr *store = + nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_var); + store->src[0] = nir_src_for_ssa(src_val->ssa); + store->variables[0] = nir_deref_as_var(nir_copy_deref(store, &dest->deref)); + store->num_components = glsl_get_vector_elements(dest_type); + + nir_instr_insert_after_cf_list(b->cf_list, &store->instr); + } else { + assert(src_val->value_type == vtn_value_type_constant); + + nir_variable *const_tmp = rzalloc(b->shader, nir_variable); + const_tmp->type = dest_type; + const_tmp->data.mode = nir_var_local; + const_tmp->data.read_only = true; + exec_list_push_tail(&b->impl->locals, &const_tmp->node); + + nir_intrinsic_instr *copy = + nir_intrinsic_instr_create(b->shader, nir_intrinsic_copy_var); + copy->variables[0] = nir_deref_as_var(nir_copy_deref(copy, &dest->deref)); + copy->variables[1] = nir_deref_var_create(copy, const_tmp); + + nir_instr_insert_after_cf_list(b->cf_list, ©->instr); + } + break; + } + case SpvOpVariableArray: - case SpvOpLoad: - case SpvOpStore: - case SpvOpCopyMemory: case SpvOpCopyMemorySized: case SpvOpArrayLength: case SpvOpImagePointer: From f36fabb7367e6d154c4ddb010206d17447eb1a2a Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Fri, 1 May 2015 14:00:57 -0700 Subject: [PATCH 25/55] nir/spirv: Split instruction handling into preamble and body sections --- src/glsl/nir/spirv_to_nir.c | 140 ++++++++++++++++++++++++------------ 1 file changed, 94 insertions(+), 46 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index b9d35766019..ef42b14c41e 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -114,6 +114,28 @@ vtn_string_literal(struct vtn_builder *b, const uint32_t *words, return ralloc_strndup(b, (char *)words, (word_count - 2) * sizeof(*words)); } +typedef bool (*vtn_instruction_handler)(struct vtn_builder *, SpvOp, + const uint32_t *, unsigned); + +static const uint32_t * +vtn_foreach_instruction(struct vtn_builder *b, const uint32_t *start, + const uint32_t *end, vtn_instruction_handler handler) +{ + const uint32_t *w = start; + while (w < end) { + SpvOp opcode = w[0] & SpvOpCodeMask; + unsigned count = w[0] >> SpvWordCountShift; + assert(count >= 1 && w + count <= end); + + if (!handler(b, opcode, w, count)) + return w; + + w += count; + } + assert(w == end); + return w; +} + static void vtn_handle_extension(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) @@ -714,32 +736,19 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, unreachable("Unhandled opcode"); } -static void -vtn_handle_instruction(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) +static bool +vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) { switch (opcode) { case SpvOpSource: case SpvOpSourceExtension: - case SpvOpMemberName: - case SpvOpLine: + case SpvOpCompileFlag: case SpvOpExtension: + case SpvOpExtInstImport: /* Unhandled, but these are for debug so that's ok. */ break; - case SpvOpName: - b->values[w[1]].name = vtn_string_literal(b, &w[2], count - 2); - break; - - case SpvOpString: - vtn_push_value(b, w[1], vtn_value_type_string)->str = - vtn_string_literal(b, &w[2], count - 2); - break; - - case SpvOpUndef: - vtn_push_value(b, w[2], vtn_value_type_undef); - break; - case SpvOpMemoryModel: assert(w[1] == SpvAddressingModelLogical); assert(w[2] == SpvMemoryModelGLSL450); @@ -751,20 +760,32 @@ vtn_handle_instruction(struct vtn_builder *b, SpvOp opcode, b->execution_model = w[1]; break; - case SpvOpLabel: { - struct exec_node *list_tail = exec_list_get_tail(b->cf_list); - nir_cf_node *tail_node = exec_node_data(nir_cf_node, list_tail, node); - assert(tail_node->type == nir_cf_node_block); - nir_block *block = nir_cf_node_as_block(tail_node); - - assert(exec_list_is_empty(&block->instr_list)); - vtn_push_value(b, w[1], vtn_value_type_block)->block = block; + case SpvOpExecutionMode: + unreachable("Execution modes not yet implemented"); break; - } - case SpvOpExtInstImport: - case SpvOpExtInst: - vtn_handle_extension(b, opcode, w, count); + case SpvOpString: + vtn_push_value(b, w[1], vtn_value_type_string)->str = + vtn_string_literal(b, &w[2], count - 2); + break; + + case SpvOpName: + b->values[w[1]].name = vtn_string_literal(b, &w[2], count - 2); + break; + + case SpvOpMemberName: + /* TODO */ + break; + + case SpvOpLine: + break; /* Ignored for now */ + + case SpvOpDecorationGroup: + case SpvOpDecorate: + case SpvOpMemberDecorate: + case SpvOpGroupDecorate: + case SpvOpGroupMemberDecorate: + vtn_handle_decoration(b, opcode, w, count); break; case SpvOpTypeVoid: @@ -803,6 +824,41 @@ vtn_handle_instruction(struct vtn_builder *b, SpvOp opcode, vtn_handle_constant(b, opcode, w, count); break; + case SpvOpVariable: + vtn_handle_variables(b, opcode, w, count); + break; + + default: + return false; /* End of preamble */ + } + + return true; +} + +static bool +vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) +{ + switch (opcode) { + case SpvOpLabel: { + struct exec_node *list_tail = exec_list_get_tail(b->cf_list); + nir_cf_node *tail_node = exec_node_data(nir_cf_node, list_tail, node); + assert(tail_node->type == nir_cf_node_block); + nir_block *block = nir_cf_node_as_block(tail_node); + + assert(exec_list_is_empty(&block->instr_list)); + vtn_push_value(b, w[1], vtn_value_type_block)->block = block; + break; + } + + case SpvOpUndef: + vtn_push_value(b, w[2], vtn_value_type_undef); + break; + + case SpvOpExtInst: + vtn_handle_extension(b, opcode, w, count); + break; + case SpvOpVariable: case SpvOpVariableArray: case SpvOpLoad: @@ -816,14 +872,6 @@ vtn_handle_instruction(struct vtn_builder *b, SpvOp opcode, vtn_handle_variables(b, opcode, w, count); break; - case SpvOpDecorationGroup: - case SpvOpDecorate: - case SpvOpMemberDecorate: - case SpvOpGroupDecorate: - case SpvOpGroupMemberDecorate: - vtn_handle_decoration(b, opcode, w, count); - break; - case SpvOpFunction: case SpvOpFunctionEnd: case SpvOpFunctionParameter: @@ -953,6 +1001,8 @@ vtn_handle_instruction(struct vtn_builder *b, SpvOp opcode, default: unreachable("Unhandled opcode"); } + + return true; } nir_shader * @@ -979,17 +1029,15 @@ spirv_to_nir(const uint32_t *words, size_t word_count, b->value_id_bound = value_id_bound; b->values = ralloc_array(b, struct vtn_value, value_id_bound); - /* Start handling instructions */ const uint32_t *word_end = words + word_count; - while (words < word_end) { - SpvOp opcode = words[0] & SpvOpCodeMask; - unsigned count = words[0] >> SpvWordCountShift; - assert(words + count <= word_end); - vtn_handle_instruction(b, opcode, words, count); + /* Handle all the preamble instructions */ + words = vtn_foreach_instruction(b, words, word_end, + vtn_handle_preamble_instruction); - words += count; - } + words = vtn_foreach_instruction(b, words, word_end, + vtn_handle_body_instruction); + assert(words == word_end); ralloc_free(b); From d216dcee94d5adf72b8d7dee794ff7b3f1cd499f Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 4 May 2015 10:22:52 -0700 Subject: [PATCH 26/55] nir/spirv: Add a helper for getting a value as an SSA value --- src/glsl/nir/spirv_to_nir.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index ef42b14c41e..840b4c6fc65 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -107,6 +107,12 @@ vtn_value(struct vtn_builder *b, uint32_t value_id, return val; } +static nir_ssa_def * +vtn_ssa_value(struct vtn_builder *b, uint32_t value_id) +{ + return vtn_value(b, value_id, vtn_value_type_ssa)->ssa; +} + static char * vtn_string_literal(struct vtn_builder *b, const uint32_t *words, unsigned word_count) From b7904b828115ca2e00dfdd814c9e83f2fc3df3ea Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 4 May 2015 10:23:09 -0700 Subject: [PATCH 27/55] nir/spirv: Handle OpBranchConditional We do control-flow handling as a two-step process. The first step is to walk the instructions list and record various information about blocks and functions. This is where the acutal nir_function_overload objects get created. We also record the start/stop instruction for each block. Then a second pass walks over each of the functions and over the blocks in each function in a way that's NIR-friendly and actually parses the instructions. --- src/glsl/nir/spirv_to_nir.c | 257 ++++++++++++++++++++++++++---------- 1 file changed, 189 insertions(+), 68 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index 840b4c6fc65..0bbae8ee874 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -44,6 +44,19 @@ enum vtn_value_type { vtn_value_type_ssa, }; +struct vtn_block { + const uint32_t *label; + const uint32_t *branch; + nir_block *block; +}; + +struct vtn_function { + struct exec_node node; + + nir_function_overload *overload; + struct vtn_block *start_block; +}; + struct vtn_value { enum vtn_value_type value_type; const char *name; @@ -54,8 +67,8 @@ struct vtn_value { const struct glsl_type *type; nir_constant *constant; nir_deref_var *deref; - nir_function_impl *impl; - nir_block *block; + struct vtn_function *func; + struct vtn_block *block; nir_ssa_def *ssa; }; }; @@ -71,12 +84,17 @@ struct vtn_builder { nir_shader *shader; nir_function_impl *impl; struct exec_list *cf_list; + struct vtn_block *block; + struct vtn_block *merge_block; unsigned value_id_bound; struct vtn_value *values; SpvExecutionModel execution_model; struct vtn_value *entry_point; + + struct vtn_function *func; + struct exec_list functions; }; static struct vtn_value * @@ -672,60 +690,10 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, } static void -vtn_handle_functions(struct vtn_builder *b, SpvOp opcode, - const uint32_t *w, unsigned count) +vtn_handle_function_call(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) { - switch (opcode) { - case SpvOpFunction: { - assert(b->impl == NULL); - - const struct glsl_type *result_type = - vtn_value(b, w[1], vtn_value_type_type)->type; - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_function); - const struct glsl_type *func_type = - vtn_value(b, w[4], vtn_value_type_type)->type; - - assert(glsl_get_function_return_type(func_type) == result_type); - - nir_function *func = - nir_function_create(b->shader, ralloc_strdup(b->shader, val->name)); - - nir_function_overload *overload = nir_function_overload_create(func); - overload->num_params = glsl_get_length(func_type); - overload->params = ralloc_array(overload, nir_parameter, - overload->num_params); - for (unsigned i = 0; i < overload->num_params; i++) { - const struct glsl_function_param *param = - glsl_get_function_param(func_type, i); - overload->params[i].type = param->type; - if (param->in) { - if (param->out) { - overload->params[i].param_type = nir_parameter_inout; - } else { - overload->params[i].param_type = nir_parameter_in; - } - } else { - if (param->out) { - overload->params[i].param_type = nir_parameter_out; - } else { - assert(!"Parameter is neither in nor out"); - } - } - } - - val->impl = b->impl = nir_function_impl_create(overload); - b->cf_list = &b->impl->body; - - break; - } - case SpvOpFunctionEnd: - b->impl = NULL; - break; - case SpvOpFunctionParameter: - case SpvOpFunctionCall: - default: - unreachable("Unhandled opcode"); - } + unreachable("Unhandled opcode"); } static void @@ -841,22 +809,118 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode, return true; } +static bool +vtn_handle_first_cfg_pass_instruction(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) +{ + switch (opcode) { + case SpvOpFunction: { + assert(b->func == NULL); + b->func = rzalloc(b, struct vtn_function); + + const struct glsl_type *result_type = + vtn_value(b, w[1], vtn_value_type_type)->type; + struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_function); + const struct glsl_type *func_type = + vtn_value(b, w[4], vtn_value_type_type)->type; + + assert(glsl_get_function_return_type(func_type) == result_type); + + nir_function *func = + nir_function_create(b->shader, ralloc_strdup(b->shader, val->name)); + + nir_function_overload *overload = nir_function_overload_create(func); + overload->num_params = glsl_get_length(func_type); + overload->params = ralloc_array(overload, nir_parameter, + overload->num_params); + for (unsigned i = 0; i < overload->num_params; i++) { + const struct glsl_function_param *param = + glsl_get_function_param(func_type, i); + overload->params[i].type = param->type; + if (param->in) { + if (param->out) { + overload->params[i].param_type = nir_parameter_inout; + } else { + overload->params[i].param_type = nir_parameter_in; + } + } else { + if (param->out) { + overload->params[i].param_type = nir_parameter_out; + } else { + assert(!"Parameter is neither in nor out"); + } + } + } + b->func->overload = overload; + break; + } + + case SpvOpFunctionEnd: + b->func = NULL; + break; + + case SpvOpFunctionParameter: + break; /* Does nothing */ + + case SpvOpLabel: { + assert(b->block == NULL); + b->block = rzalloc(b, struct vtn_block); + b->block->label = w; + vtn_push_value(b, w[1], vtn_value_type_block)->block = b->block; + + if (b->func->start_block == NULL) { + /* This is the first block encountered for this function. In this + * case, we set the start block and add it to the list of + * implemented functions that we'll walk later. + */ + b->func->start_block = b->block; + exec_list_push_tail(&b->functions, &b->func->node); + } + break; + } + + case SpvOpBranch: + case SpvOpBranchConditional: + case SpvOpSwitch: + case SpvOpKill: + case SpvOpReturn: + case SpvOpReturnValue: + case SpvOpUnreachable: + assert(b->block); + b->block->branch = w; + b->block = NULL; + break; + + default: + /* Continue on as per normal */ + return true; + } + + return true; +} + static bool vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) { switch (opcode) { case SpvOpLabel: { + struct vtn_block *block = vtn_value(b, w[1], vtn_value_type_block)->block; struct exec_node *list_tail = exec_list_get_tail(b->cf_list); nir_cf_node *tail_node = exec_node_data(nir_cf_node, list_tail, node); assert(tail_node->type == nir_cf_node_block); - nir_block *block = nir_cf_node_as_block(tail_node); - - assert(exec_list_is_empty(&block->instr_list)); - vtn_push_value(b, w[1], vtn_value_type_block)->block = block; + block->block = nir_cf_node_as_block(tail_node); + assert(exec_list_is_empty(&block->block->instr_list)); break; } + case SpvOpLoopMerge: + case SpvOpSelectionMerge: + assert(b->merge_block == NULL); + /* TODO: Selection Control */ + b->merge_block = vtn_value(b, w[1], vtn_value_type_block)->block; + break; + case SpvOpUndef: vtn_push_value(b, w[2], vtn_value_type_undef); break; @@ -878,11 +942,8 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, vtn_handle_variables(b, opcode, w, count); break; - case SpvOpFunction: - case SpvOpFunctionEnd: - case SpvOpFunctionParameter: case SpvOpFunctionCall: - vtn_handle_functions(b, opcode, w, count); + vtn_handle_function_call(b, opcode, w, count); break; case SpvOpTextureSample: @@ -1011,11 +1072,66 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, return true; } +static void +vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start, + struct vtn_block *end) +{ + struct vtn_block *block = start; + while (block != end) { + vtn_foreach_instruction(b, block->label, block->branch, + vtn_handle_body_instruction); + + const uint32_t *w = block->branch; + SpvOp branch_op = w[0] & SpvOpCodeMask; + switch (branch_op) { + case SpvOpBranch: { + assert(vtn_value(b, w[1], vtn_value_type_block)->block == end); + return; + } + + case SpvOpBranchConditional: { + /* Gather up the branch blocks */ + struct vtn_block *then_block = + vtn_value(b, w[2], vtn_value_type_block)->block; + struct vtn_block *else_block = + vtn_value(b, w[3], vtn_value_type_block)->block; + struct vtn_block *merge_block = b->merge_block; + + nir_if *if_stmt = nir_if_create(b->shader); + if_stmt->condition = nir_src_for_ssa(vtn_ssa_value(b, w[1])); + nir_cf_node_insert_end(b->cf_list, &if_stmt->cf_node); + + struct exec_list *old_list = b->cf_list; + + b->cf_list = &if_stmt->then_list; + vtn_walk_blocks(b, then_block, merge_block); + + b->cf_list = &if_stmt->else_list; + vtn_walk_blocks(b, else_block, merge_block); + + b->cf_list = old_list; + block = merge_block; + continue; + } + + case SpvOpSwitch: + case SpvOpKill: + case SpvOpReturn: + case SpvOpReturnValue: + case SpvOpUnreachable: + default: + unreachable("Unhandled opcode"); + } + } +} + nir_shader * spirv_to_nir(const uint32_t *words, size_t word_count, gl_shader_stage stage, const nir_shader_compiler_options *options) { + const uint32_t *word_end = words + word_count; + /* Handle the SPIR-V header (first 4 dwords) */ assert(word_count > 5); @@ -1034,16 +1150,21 @@ spirv_to_nir(const uint32_t *words, size_t word_count, b->shader = shader; b->value_id_bound = value_id_bound; b->values = ralloc_array(b, struct vtn_value, value_id_bound); - - const uint32_t *word_end = words + word_count; + exec_list_make_empty(&b->functions); /* Handle all the preamble instructions */ words = vtn_foreach_instruction(b, words, word_end, vtn_handle_preamble_instruction); - words = vtn_foreach_instruction(b, words, word_end, - vtn_handle_body_instruction); - assert(words == word_end); + /* Do a very quick CFG analysis pass */ + vtn_foreach_instruction(b, words, word_end, + vtn_handle_first_cfg_pass_instruction); + + foreach_list_typed(struct vtn_function, func, node, &b->functions) { + b->impl = nir_function_impl_create(func->overload); + b->cf_list = &b->impl->body; + vtn_walk_blocks(b, func->start_block, NULL); + } ralloc_free(b); From 9197e3b9fcfe109c268f336fb260e3db6b11d21a Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 4 May 2015 12:02:24 -0700 Subject: [PATCH 28/55] nir/spirv: Explicitly type constants and SSA values --- src/glsl/nir/spirv_to_nir.c | 40 +++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index 0bbae8ee874..f36db8a3c27 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -61,10 +61,10 @@ struct vtn_value { enum vtn_value_type value_type; const char *name; struct vtn_decoration *decoration; + const struct glsl_type *type; union { void *ptr; char *str; - const struct glsl_type *type; nir_constant *constant; nir_deref_var *deref; struct vtn_function *func; @@ -346,20 +346,21 @@ static void vtn_handle_constant(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) { - const struct glsl_type *type = vtn_value(b, w[1], vtn_value_type_type)->type; - nir_constant *constant = ralloc(b, nir_constant); + struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_constant); + val->type = vtn_value(b, w[1], vtn_value_type_type)->type; + val->constant = ralloc(b, nir_constant); switch (opcode) { case SpvOpConstantTrue: - assert(type == glsl_bool_type()); - constant->value.u[0] = NIR_TRUE; + assert(val->type == glsl_bool_type()); + val->constant->value.u[0] = NIR_TRUE; break; case SpvOpConstantFalse: - assert(type == glsl_bool_type()); - constant->value.u[0] = NIR_FALSE; + assert(val->type == glsl_bool_type()); + val->constant->value.u[0] = NIR_FALSE; break; case SpvOpConstant: - assert(glsl_type_is_scalar(type)); - constant->value.u[0] = w[3]; + assert(glsl_type_is_scalar(val->type)); + val->constant->value.u[0] = w[3]; break; case SpvOpConstantComposite: { unsigned elem_count = count - 3; @@ -367,29 +368,30 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode, for (unsigned i = 0; i < elem_count; i++) elems[i] = vtn_value(b, w[i + 3], vtn_value_type_constant)->constant; - switch (glsl_get_base_type(type)) { + switch (glsl_get_base_type(val->type)) { case GLSL_TYPE_UINT: case GLSL_TYPE_INT: case GLSL_TYPE_FLOAT: case GLSL_TYPE_BOOL: - if (glsl_type_is_matrix(type)) { - unsigned rows = glsl_get_vector_elements(type); - assert(glsl_get_matrix_columns(type) == elem_count); + if (glsl_type_is_matrix(val->type)) { + unsigned rows = glsl_get_vector_elements(val->type); + assert(glsl_get_matrix_columns(val->type) == elem_count); for (unsigned i = 0; i < elem_count; i++) for (unsigned j = 0; j < rows; j++) - constant->value.u[rows * i + j] = elems[i]->value.u[j]; + val->constant->value.u[rows * i + j] = elems[i]->value.u[j]; } else { - assert(glsl_type_is_vector(type)); - assert(glsl_get_vector_elements(type) == elem_count); + assert(glsl_type_is_vector(val->type)); + assert(glsl_get_vector_elements(val->type) == elem_count); for (unsigned i = 0; i < elem_count; i++) - constant->value.u[i] = elems[i]->value.u[0]; + val->constant->value.u[i] = elems[i]->value.u[0]; } ralloc_free(elems); break; case GLSL_TYPE_STRUCT: case GLSL_TYPE_ARRAY: - constant->elements = elems; + ralloc_steal(val->constant, elems); + val->constant->elements = elems; break; default: @@ -401,7 +403,6 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode, default: unreachable("Unhandled opcode"); } - vtn_push_value(b, w[2], vtn_value_type_constant)->constant = constant; } static void @@ -644,6 +645,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, val->name); nir_instr_insert_after_cf_list(b->cf_list, &load->instr); + val->type = src_type; val->ssa = &load->dest.ssa; break; } From 91b3b46d8b5a1928bdea377acc51a3fcc85b498b Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 4 May 2015 12:02:57 -0700 Subject: [PATCH 29/55] nir/spirv: Add support for indirect array accesses --- src/glsl/nir/spirv_to_nir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index f36db8a3c27..9c056da897f 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -595,8 +595,8 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, } else { assert(idx_val->value_type == vtn_value_type_ssa); deref_arr->deref_array_type = nir_deref_array_type_indirect; - /* TODO */ - unreachable("Indirect array accesses not implemented"); + deref_arr->base_offset = 0; + deref_arr->indirect = nir_src_for_ssa(vtn_ssa_value(b, w[1])); } tail->child = &deref_arr->deref; break; From 9e03b6724cf75950181851196888f55725e537ad Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 4 May 2015 12:04:02 -0700 Subject: [PATCH 30/55] nir/spirv: Add support for a bunch of ALU operations --- src/glsl/nir/spirv_to_nir.c | 202 ++++++++++++++++++++++++++++++++++-- 1 file changed, 195 insertions(+), 7 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index 9c056da897f..a88fa4591bd 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -27,6 +27,7 @@ #include "nir_spirv.h" #include "nir_vla.h" +#include "nir_builder.h" #include "spirv.h" struct vtn_decoration; @@ -81,6 +82,8 @@ struct vtn_decoration { }; struct vtn_builder { + nir_builder nb; + nir_shader *shader; nir_function_impl *impl; struct exec_list *cf_list; @@ -705,11 +708,192 @@ vtn_handle_texture(struct vtn_builder *b, SpvOp opcode, unreachable("Unhandled opcode"); } +static void +vtn_handle_matrix_alu(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) +{ + unreachable("Matrix math not handled"); +} + static void vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) { - unreachable("Unhandled opcode"); + struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); + val->type = vtn_value(b, w[1], vtn_value_type_type)->type; + + /* Collect the various SSA sources */ + unsigned num_inputs = count - 3; + nir_ssa_def *src[4]; + for (unsigned i = 0; i < num_inputs; i++) + src[i] = vtn_ssa_value(b, w[i + 3]); + + /* We use the builder for some of the instructions. Go ahead and + * initialize it with the current cf_list. + */ + nir_builder_insert_after_cf_list(&b->nb, b->cf_list); + + /* Indicates that the first two arguments should be swapped. This is + * used for implementing greater-than and less-than-or-equal. + */ + bool swap = false; + + nir_op op; + switch (opcode) { + /* Basic ALU operations */ + case SpvOpSNegate: op = nir_op_ineg; break; + case SpvOpFNegate: op = nir_op_fneg; break; + case SpvOpNot: op = nir_op_inot; break; + + case SpvOpAny: + switch (src[0]->num_components) { + case 1: op = nir_op_imov; break; + case 2: op = nir_op_bany2; break; + case 3: op = nir_op_bany3; break; + case 4: op = nir_op_bany4; break; + } + break; + + case SpvOpAll: + switch (src[0]->num_components) { + case 1: op = nir_op_imov; break; + case 2: op = nir_op_ball2; break; + case 3: op = nir_op_ball3; break; + case 4: op = nir_op_ball4; break; + } + break; + + case SpvOpIAdd: op = nir_op_iadd; break; + case SpvOpFAdd: op = nir_op_fadd; break; + case SpvOpISub: op = nir_op_isub; break; + case SpvOpFSub: op = nir_op_fsub; break; + case SpvOpIMul: op = nir_op_imul; break; + case SpvOpFMul: op = nir_op_fmul; break; + case SpvOpUDiv: op = nir_op_udiv; break; + case SpvOpSDiv: op = nir_op_idiv; break; + case SpvOpFDiv: op = nir_op_fdiv; break; + case SpvOpUMod: op = nir_op_umod; break; + case SpvOpSMod: op = nir_op_umod; break; /* FIXME? */ + case SpvOpFMod: op = nir_op_fmod; break; + + case SpvOpDot: + assert(src[0]->num_components == src[1]->num_components); + switch (src[0]->num_components) { + case 1: op = nir_op_fmul; break; + case 2: op = nir_op_fdot2; break; + case 3: op = nir_op_fdot3; break; + case 4: op = nir_op_fdot4; break; + } + break; + + case SpvOpShiftRightLogical: op = nir_op_ushr; break; + case SpvOpShiftRightArithmetic: op = nir_op_ishr; break; + case SpvOpShiftLeftLogical: op = nir_op_ishl; break; + case SpvOpLogicalOr: op = nir_op_ior; break; + case SpvOpLogicalXor: op = nir_op_ixor; break; + case SpvOpLogicalAnd: op = nir_op_iand; break; + case SpvOpBitwiseOr: op = nir_op_ior; break; + case SpvOpBitwiseXor: op = nir_op_ixor; break; + case SpvOpBitwiseAnd: op = nir_op_iand; break; + case SpvOpSelect: op = nir_op_bcsel; break; + case SpvOpIEqual: op = nir_op_ieq; break; + + /* Comparisons: (TODO: How do we want to handled ordered/unordered?) */ + case SpvOpFOrdEqual: op = nir_op_feq; break; + case SpvOpFUnordEqual: op = nir_op_feq; break; + case SpvOpINotEqual: op = nir_op_ine; break; + case SpvOpFOrdNotEqual: op = nir_op_fne; break; + case SpvOpFUnordNotEqual: op = nir_op_fne; break; + case SpvOpULessThan: op = nir_op_ult; break; + case SpvOpSLessThan: op = nir_op_ilt; break; + case SpvOpFOrdLessThan: op = nir_op_flt; break; + case SpvOpFUnordLessThan: op = nir_op_flt; break; + case SpvOpUGreaterThan: op = nir_op_ult; swap = true; break; + case SpvOpSGreaterThan: op = nir_op_ilt; swap = true; break; + case SpvOpFOrdGreaterThan: op = nir_op_flt; swap = true; break; + case SpvOpFUnordGreaterThan: op = nir_op_flt; swap = true; break; + case SpvOpULessThanEqual: op = nir_op_uge; swap = true; break; + case SpvOpSLessThanEqual: op = nir_op_ige; swap = true; break; + case SpvOpFOrdLessThanEqual: op = nir_op_fge; swap = true; break; + case SpvOpFUnordLessThanEqual: op = nir_op_fge; swap = true; break; + case SpvOpUGreaterThanEqual: op = nir_op_uge; break; + case SpvOpSGreaterThanEqual: op = nir_op_ige; break; + case SpvOpFOrdGreaterThanEqual: op = nir_op_fge; break; + case SpvOpFUnordGreaterThanEqual:op = nir_op_fge; break; + + /* Conversions: */ + case SpvOpConvertFToU: op = nir_op_f2u; break; + case SpvOpConvertFToS: op = nir_op_f2i; break; + case SpvOpConvertSToF: op = nir_op_i2f; break; + case SpvOpConvertUToF: op = nir_op_u2f; break; + case SpvOpBitcast: op = nir_op_imov; break; + case SpvOpUConvert: + case SpvOpSConvert: + op = nir_op_imov; /* TODO: NIR is 32-bit only; these are no-ops. */ + break; + case SpvOpFConvert: + op = nir_op_fmov; + break; + + /* Derivatives: */ + case SpvOpDPdx: op = nir_op_fddx; break; + case SpvOpDPdy: op = nir_op_fddy; break; + case SpvOpDPdxFine: op = nir_op_fddx_fine; break; + case SpvOpDPdyFine: op = nir_op_fddy_fine; break; + case SpvOpDPdxCoarse: op = nir_op_fddx_coarse; break; + case SpvOpDPdyCoarse: op = nir_op_fddy_coarse; break; + case SpvOpFwidth: + val->ssa = nir_fadd(&b->nb, + nir_fabs(&b->nb, nir_fddx(&b->nb, src[0])), + nir_fabs(&b->nb, nir_fddx(&b->nb, src[1]))); + return; + case SpvOpFwidthFine: + val->ssa = nir_fadd(&b->nb, + nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[0])), + nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[1]))); + return; + case SpvOpFwidthCoarse: + val->ssa = nir_fadd(&b->nb, + nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[0])), + nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[1]))); + return; + + case SpvOpVectorTimesScalar: + /* The builder will take care of splatting for us. */ + val->ssa = nir_fmul(&b->nb, src[0], src[1]); + return; + + case SpvOpSRem: + case SpvOpFRem: + unreachable("No NIR equivalent"); + + case SpvOpIsNan: + case SpvOpIsInf: + case SpvOpIsFinite: + case SpvOpIsNormal: + case SpvOpSignBitSet: + case SpvOpLessOrGreater: + case SpvOpOrdered: + case SpvOpUnordered: + default: + unreachable("Unhandled opcode"); + } + + if (swap) { + nir_ssa_def *tmp = src[0]; + src[0] = src[1]; + src[1] = tmp; + } + + nir_alu_instr *instr = nir_alu_instr_create(b->shader, op); + nir_ssa_dest_init(&instr->instr, &instr->dest.dest, + glsl_get_vector_elements(val->type), val->name); + val->ssa = &instr->dest.dest.ssa; + + for (unsigned i = 0; i < nir_op_infos[op].num_inputs; i++) + instr->src[i].src = nir_src_for_ssa(src[i]); + + nir_instr_insert_after_cf_list(b->cf_list, &instr->instr); } static bool @@ -993,7 +1177,6 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, case SpvOpPtrCastToGeneric: case SpvOpGenericCastToPtr: case SpvOpBitcast: - case SpvOpTranspose: case SpvOpIsNan: case SpvOpIsInf: case SpvOpIsFinite: @@ -1017,11 +1200,6 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, case SpvOpFRem: case SpvOpFMod: case SpvOpVectorTimesScalar: - case SpvOpMatrixTimesScalar: - case SpvOpVectorTimesMatrix: - case SpvOpMatrixTimesVector: - case SpvOpMatrixTimesMatrix: - case SpvOpOuterProduct: case SpvOpDot: case SpvOpShiftRightLogical: case SpvOpShiftRightArithmetic: @@ -1067,6 +1245,15 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, vtn_handle_alu(b, opcode, w, count); break; + case SpvOpTranspose: + case SpvOpOuterProduct: + case SpvOpMatrixTimesScalar: + case SpvOpVectorTimesMatrix: + case SpvOpMatrixTimesVector: + case SpvOpMatrixTimesMatrix: + vtn_handle_matrix_alu(b, opcode, w, count); + break; + default: unreachable("Unhandled opcode"); } @@ -1164,6 +1351,7 @@ spirv_to_nir(const uint32_t *words, size_t word_count, foreach_list_typed(struct vtn_function, func, node, &b->functions) { b->impl = nir_function_impl_create(func->overload); + nir_builder_init(&b->nb, b->impl); b->cf_list = &b->impl->body; vtn_walk_blocks(b, func->start_block, NULL); } From 66fc7f252f7e4e5efe4891b2eed72a4f0c2f968e Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 4 May 2015 12:12:23 -0700 Subject: [PATCH 31/55] nir/spirv: Use the builder for all instructions We don't actually use it to create all the instructions but we do use it for insertion always. This should make things far more consistent for implementing extended instructions. --- src/glsl/nir/spirv_to_nir.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index a88fa4591bd..bd1052fc9c1 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -86,7 +86,6 @@ struct vtn_builder { nir_shader *shader; nir_function_impl *impl; - struct exec_list *cf_list; struct vtn_block *block; struct vtn_block *merge_block; @@ -630,7 +629,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, copy->variables[0] = nir_deref_as_var(nir_copy_deref(copy, &dest->deref)); copy->variables[1] = nir_deref_as_var(nir_copy_deref(copy, &src->deref)); - nir_instr_insert_after_cf_list(b->cf_list, ©->instr); + nir_builder_instr_insert(&b->nb, ©->instr); break; } @@ -647,7 +646,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, nir_ssa_dest_init(&load->instr, &load->dest, load->num_components, val->name); - nir_instr_insert_after_cf_list(b->cf_list, &load->instr); + nir_builder_instr_insert(&b->nb, &load->instr); val->type = src_type; val->ssa = &load->dest.ssa; break; @@ -665,7 +664,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, store->variables[0] = nir_deref_as_var(nir_copy_deref(store, &dest->deref)); store->num_components = glsl_get_vector_elements(dest_type); - nir_instr_insert_after_cf_list(b->cf_list, &store->instr); + nir_builder_instr_insert(&b->nb, &store->instr); } else { assert(src_val->value_type == vtn_value_type_constant); @@ -680,7 +679,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, copy->variables[0] = nir_deref_as_var(nir_copy_deref(copy, &dest->deref)); copy->variables[1] = nir_deref_var_create(copy, const_tmp); - nir_instr_insert_after_cf_list(b->cf_list, ©->instr); + nir_builder_instr_insert(&b->nb, ©->instr); } break; } @@ -728,11 +727,6 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, for (unsigned i = 0; i < num_inputs; i++) src[i] = vtn_ssa_value(b, w[i + 3]); - /* We use the builder for some of the instructions. Go ahead and - * initialize it with the current cf_list. - */ - nir_builder_insert_after_cf_list(&b->nb, b->cf_list); - /* Indicates that the first two arguments should be swapped. This is * used for implementing greater-than and less-than-or-equal. */ @@ -893,7 +887,7 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, for (unsigned i = 0; i < nir_op_infos[op].num_inputs; i++) instr->src[i].src = nir_src_for_ssa(src[i]); - nir_instr_insert_after_cf_list(b->cf_list, &instr->instr); + nir_builder_instr_insert(&b->nb, &instr->instr); } static bool @@ -1092,7 +1086,7 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, switch (opcode) { case SpvOpLabel: { struct vtn_block *block = vtn_value(b, w[1], vtn_value_type_block)->block; - struct exec_node *list_tail = exec_list_get_tail(b->cf_list); + struct exec_node *list_tail = exec_list_get_tail(b->nb.cf_node_list); nir_cf_node *tail_node = exec_node_data(nir_cf_node, list_tail, node); assert(tail_node->type == nir_cf_node_block); block->block = nir_cf_node_as_block(tail_node); @@ -1288,17 +1282,17 @@ vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start, nir_if *if_stmt = nir_if_create(b->shader); if_stmt->condition = nir_src_for_ssa(vtn_ssa_value(b, w[1])); - nir_cf_node_insert_end(b->cf_list, &if_stmt->cf_node); + nir_cf_node_insert_end(b->nb.cf_node_list, &if_stmt->cf_node); - struct exec_list *old_list = b->cf_list; + struct exec_list *old_list = b->nb.cf_node_list; - b->cf_list = &if_stmt->then_list; + nir_builder_insert_after_cf_list(&b->nb, &if_stmt->then_list); vtn_walk_blocks(b, then_block, merge_block); - b->cf_list = &if_stmt->else_list; + nir_builder_insert_after_cf_list(&b->nb, &if_stmt->else_list); vtn_walk_blocks(b, else_block, merge_block); - b->cf_list = old_list; + nir_builder_insert_after_cf_list(&b->nb, old_list); block = merge_block; continue; } @@ -1352,7 +1346,7 @@ spirv_to_nir(const uint32_t *words, size_t word_count, foreach_list_typed(struct vtn_function, func, node, &b->functions) { b->impl = nir_function_impl_create(func->overload); nir_builder_init(&b->nb, b->impl); - b->cf_list = &b->impl->body; + nir_builder_insert_after_cf_list(&b->nb, &b->impl->body); vtn_walk_blocks(b, func->start_block, NULL); } From 577c09fdadb789ee017ccf0b2bb397f3abec0bf7 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 4 May 2015 12:25:09 -0700 Subject: [PATCH 32/55] nir/spirv: Split the core datastructures into a header file --- src/glsl/nir/spirv_to_nir.c | 117 +---------------------- src/glsl/nir/spirv_to_nir_private.h | 141 ++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 112 deletions(-) create mode 100644 src/glsl/nir/spirv_to_nir_private.h diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index bd1052fc9c1..78bffda9e8c 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -25,109 +25,10 @@ * */ -#include "nir_spirv.h" +#include "spirv_to_nir_private.h" #include "nir_vla.h" -#include "nir_builder.h" -#include "spirv.h" -struct vtn_decoration; - -enum vtn_value_type { - vtn_value_type_invalid = 0, - vtn_value_type_undef, - vtn_value_type_string, - vtn_value_type_decoration_group, - vtn_value_type_type, - vtn_value_type_constant, - vtn_value_type_deref, - vtn_value_type_function, - vtn_value_type_block, - vtn_value_type_ssa, -}; - -struct vtn_block { - const uint32_t *label; - const uint32_t *branch; - nir_block *block; -}; - -struct vtn_function { - struct exec_node node; - - nir_function_overload *overload; - struct vtn_block *start_block; -}; - -struct vtn_value { - enum vtn_value_type value_type; - const char *name; - struct vtn_decoration *decoration; - const struct glsl_type *type; - union { - void *ptr; - char *str; - nir_constant *constant; - nir_deref_var *deref; - struct vtn_function *func; - struct vtn_block *block; - nir_ssa_def *ssa; - }; -}; - -struct vtn_decoration { - struct vtn_decoration *next; - const uint32_t *literals; - struct vtn_value *group; - SpvDecoration decoration; -}; - -struct vtn_builder { - nir_builder nb; - - nir_shader *shader; - nir_function_impl *impl; - struct vtn_block *block; - struct vtn_block *merge_block; - - unsigned value_id_bound; - struct vtn_value *values; - - SpvExecutionModel execution_model; - struct vtn_value *entry_point; - - struct vtn_function *func; - struct exec_list functions; -}; - -static struct vtn_value * -vtn_push_value(struct vtn_builder *b, uint32_t value_id, - enum vtn_value_type value_type) -{ - assert(value_id < b->value_id_bound); - assert(b->values[value_id].value_type == vtn_value_type_invalid); - - b->values[value_id].value_type = value_type; - - return &b->values[value_id]; -} - -static struct vtn_value * -vtn_untyped_value(struct vtn_builder *b, uint32_t value_id) -{ - assert(value_id < b->value_id_bound); - return &b->values[value_id]; -} - -static struct vtn_value * -vtn_value(struct vtn_builder *b, uint32_t value_id, - enum vtn_value_type value_type) -{ - struct vtn_value *val = vtn_untyped_value(b, value_id); - assert(val->value_type == value_type); - return val; -} - -static nir_ssa_def * +nir_ssa_def * vtn_ssa_value(struct vtn_builder *b, uint32_t value_id) { return vtn_value(b, value_id, vtn_value_type_ssa)->ssa; @@ -140,9 +41,6 @@ vtn_string_literal(struct vtn_builder *b, const uint32_t *words, return ralloc_strndup(b, (char *)words, (word_count - 2) * sizeof(*words)); } -typedef bool (*vtn_instruction_handler)(struct vtn_builder *, SpvOp, - const uint32_t *, unsigned); - static const uint32_t * vtn_foreach_instruction(struct vtn_builder *b, const uint32_t *start, const uint32_t *end, vtn_instruction_handler handler) @@ -177,16 +75,11 @@ vtn_handle_extension(struct vtn_builder *b, SpvOp opcode, } } -typedef void (*decoration_foreach_cb)(struct vtn_builder *, - struct vtn_value *, - const struct vtn_decoration *, - void *); - static void _foreach_decoration_helper(struct vtn_builder *b, struct vtn_value *base_value, struct vtn_value *value, - decoration_foreach_cb cb, void *data) + vtn_decoration_foreach_cb cb, void *data) { for (struct vtn_decoration *dec = value->decoration; dec; dec = dec->next) { if (dec->group) { @@ -204,9 +97,9 @@ _foreach_decoration_helper(struct vtn_builder *b, * value. If it encounters a decoration group, it recurses into the group * and iterates over all of those decorations as well. */ -static void +void vtn_foreach_decoration(struct vtn_builder *b, struct vtn_value *value, - decoration_foreach_cb cb, void *data) + vtn_decoration_foreach_cb cb, void *data) { _foreach_decoration_helper(b, value, value, cb, data); } diff --git a/src/glsl/nir/spirv_to_nir_private.h b/src/glsl/nir/spirv_to_nir_private.h new file mode 100644 index 00000000000..0a07b377e72 --- /dev/null +++ b/src/glsl/nir/spirv_to_nir_private.h @@ -0,0 +1,141 @@ +/* + * Copyright © 2015 Intel Corporation + * + * 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 (including the next + * paragraph) 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. + * + * Authors: + * Jason Ekstrand (jason@jlekstrand.net) + * + */ + +#include "nir_spirv.h" +#include "nir_builder.h" +#include "spirv.h" + +struct vtn_builder; +struct vtn_decoration; + +enum vtn_value_type { + vtn_value_type_invalid = 0, + vtn_value_type_undef, + vtn_value_type_string, + vtn_value_type_decoration_group, + vtn_value_type_type, + vtn_value_type_constant, + vtn_value_type_deref, + vtn_value_type_function, + vtn_value_type_block, + vtn_value_type_ssa, +}; + +struct vtn_block { + const uint32_t *label; + const uint32_t *branch; + nir_block *block; +}; + +struct vtn_function { + struct exec_node node; + + nir_function_overload *overload; + struct vtn_block *start_block; +}; + +typedef bool (*vtn_instruction_handler)(struct vtn_builder *, uint32_t, + const uint32_t *, unsigned); + +struct vtn_value { + enum vtn_value_type value_type; + const char *name; + struct vtn_decoration *decoration; + const struct glsl_type *type; + union { + void *ptr; + char *str; + nir_constant *constant; + nir_deref_var *deref; + struct vtn_function *func; + struct vtn_block *block; + nir_ssa_def *ssa; + }; +}; + +struct vtn_decoration { + struct vtn_decoration *next; + const uint32_t *literals; + struct vtn_value *group; + SpvDecoration decoration; +}; + +struct vtn_builder { + nir_builder nb; + + nir_shader *shader; + nir_function_impl *impl; + struct vtn_block *block; + struct vtn_block *merge_block; + + unsigned value_id_bound; + struct vtn_value *values; + + SpvExecutionModel execution_model; + struct vtn_value *entry_point; + + struct vtn_function *func; + struct exec_list functions; +}; + +static inline struct vtn_value * +vtn_push_value(struct vtn_builder *b, uint32_t value_id, + enum vtn_value_type value_type) +{ + assert(value_id < b->value_id_bound); + assert(b->values[value_id].value_type == vtn_value_type_invalid); + + b->values[value_id].value_type = value_type; + + return &b->values[value_id]; +} + +static inline struct vtn_value * +vtn_untyped_value(struct vtn_builder *b, uint32_t value_id) +{ + assert(value_id < b->value_id_bound); + return &b->values[value_id]; +} + +static inline struct vtn_value * +vtn_value(struct vtn_builder *b, uint32_t value_id, + enum vtn_value_type value_type) +{ + struct vtn_value *val = vtn_untyped_value(b, value_id); + assert(val->value_type == value_type); + return val; +} + +nir_ssa_def *vtn_ssa_value(struct vtn_builder *b, uint32_t value_id); + +typedef void (*vtn_decoration_foreach_cb)(struct vtn_builder *, + struct vtn_value *, + const struct vtn_decoration *, + void *); + +void vtn_foreach_decoration(struct vtn_builder *b, struct vtn_value *value, + vtn_decoration_foreach_cb cb, void *data); From 1feeee9cf476010f72cb973480f67de0764e6a90 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 4 May 2015 15:17:56 -0700 Subject: [PATCH 33/55] nir/spirv: Add initial support for GLSL 4.50 builtins --- src/glsl/Makefile.sources | 1 + src/glsl/nir/spirv_glsl450_to_nir.c | 284 ++++++++++++++++++++++++++++ src/glsl/nir/spirv_to_nir.c | 24 ++- src/glsl/nir/spirv_to_nir_private.h | 5 + 4 files changed, 310 insertions(+), 4 deletions(-) create mode 100644 src/glsl/nir/spirv_glsl450_to_nir.c diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources index c6a89362988..da38e3576bd 100644 --- a/src/glsl/Makefile.sources +++ b/src/glsl/Makefile.sources @@ -75,6 +75,7 @@ NIR_FILES = \ nir/nir_worklist.h \ nir/nir_types.cpp \ nir/spirv_to_nir.c \ + nir/spirv_glsl450_to_nir.c \ $(NIR_GENERATED_FILES) # libglsl diff --git a/src/glsl/nir/spirv_glsl450_to_nir.c b/src/glsl/nir/spirv_glsl450_to_nir.c new file mode 100644 index 00000000000..240ff012fe1 --- /dev/null +++ b/src/glsl/nir/spirv_glsl450_to_nir.c @@ -0,0 +1,284 @@ +/* + * Copyright © 2015 Intel Corporation + * + * 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 (including the next + * paragraph) 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. + * + * Authors: + * Jason Ekstrand (jason@jlekstrand.net) + * + */ + +#include "spirv_to_nir_private.h" + +enum GLSL450Entrypoint { + Round = 0, + RoundEven = 1, + Trunc = 2, + Abs = 3, + Sign = 4, + Floor = 5, + Ceil = 6, + Fract = 7, + + Radians = 8, + Degrees = 9, + Sin = 10, + Cos = 11, + Tan = 12, + Asin = 13, + Acos = 14, + Atan = 15, + Sinh = 16, + Cosh = 17, + Tanh = 18, + Asinh = 19, + Acosh = 20, + Atanh = 21, + Atan2 = 22, + + Pow = 23, + Exp = 24, + Log = 25, + Exp2 = 26, + Log2 = 27, + Sqrt = 28, + InverseSqrt = 29, + + Determinant = 30, + MatrixInverse = 31, + + Modf = 32, // second argument needs the OpVariable = , not an OpLoad + Min = 33, + Max = 34, + Clamp = 35, + Mix = 36, + Step = 37, + SmoothStep = 38, + + FloatBitsToInt = 39, + FloatBitsToUint = 40, + IntBitsToFloat = 41, + UintBitsToFloat = 42, + + Fma = 43, + Frexp = 44, + Ldexp = 45, + + PackSnorm4x8 = 46, + PackUnorm4x8 = 47, + PackSnorm2x16 = 48, + PackUnorm2x16 = 49, + PackHalf2x16 = 50, + PackDouble2x32 = 51, + UnpackSnorm2x16 = 52, + UnpackUnorm2x16 = 53, + UnpackHalf2x16 = 54, + UnpackSnorm4x8 = 55, + UnpackUnorm4x8 = 56, + UnpackDouble2x32 = 57, + + Length = 58, + Distance = 59, + Cross = 60, + Normalize = 61, + Ftransform = 62, + FaceForward = 63, + Reflect = 64, + Refract = 65, + + UaddCarry = 66, + UsubBorrow = 67, + UmulExtended = 68, + ImulExtended = 69, + BitfieldExtract = 70, + BitfieldInsert = 71, + BitfieldReverse = 72, + BitCount = 73, + FindLSB = 74, + FindMSB = 75, + + InterpolateAtCentroid = 76, + InterpolateAtSample = 77, + InterpolateAtOffset = 78, + + Count +}; + +static nir_ssa_def* +build_length(nir_builder *b, nir_ssa_def *vec) +{ + switch (vec->num_components) { + case 1: return nir_fsqrt(b, nir_fmul(b, vec, vec)); + case 2: return nir_fsqrt(b, nir_fdot2(b, vec, vec)); + case 3: return nir_fsqrt(b, nir_fdot3(b, vec, vec)); + case 4: return nir_fsqrt(b, nir_fdot4(b, vec, vec)); + default: + unreachable("Invalid number of components"); + } +} + +static void +handle_glsl450_alu(struct vtn_builder *b, enum GLSL450Entrypoint entrypoint, + const uint32_t *w, unsigned count) +{ + struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); + val->type = vtn_value(b, w[1], vtn_value_type_type)->type; + + /* Collect the various SSA sources */ + unsigned num_inputs = count - 5; + nir_ssa_def *src[3]; + for (unsigned i = 0; i < num_inputs; i++) + src[i] = vtn_ssa_value(b, w[i + 5]); + + nir_op op; + switch (entrypoint) { + case Round: op = nir_op_fround_even; break; /* TODO */ + case RoundEven: op = nir_op_fround_even; break; + case Trunc: op = nir_op_ftrunc; break; + case Abs: op = nir_op_fabs; break; + case Sign: op = nir_op_fsign; break; + case Floor: op = nir_op_ffloor; break; + case Ceil: op = nir_op_fceil; break; + case Fract: op = nir_op_ffract; break; + case Radians: + val->ssa = nir_fmul(&b->nb, src[0], nir_imm_float(&b->nb, 0.01745329251)); + return; + case Degrees: + val->ssa = nir_fmul(&b->nb, src[0], nir_imm_float(&b->nb, 57.2957795131)); + return; + case Sin: op = nir_op_fsin; break; + case Cos: op = nir_op_fcos; break; + case Tan: + val->ssa = nir_fdiv(&b->nb, nir_fsin(&b->nb, src[0]), + nir_fcos(&b->nb, src[0])); + return; + case Pow: op = nir_op_fpow; break; + case Exp: op = nir_op_fexp; break; + case Log: op = nir_op_flog; break; + case Exp2: op = nir_op_fexp2; break; + case Log2: op = nir_op_flog2; break; + case Sqrt: op = nir_op_fsqrt; break; + case InverseSqrt: op = nir_op_frsq; break; + + case Modf: op = nir_op_fmod; break; + case Min: op = nir_op_fmin; break; + case Max: op = nir_op_fmax; break; + case Mix: op = nir_op_flrp; break; + case Step: + val->ssa = nir_sge(&b->nb, src[1], src[0]); + return; + + case FloatBitsToInt: + case FloatBitsToUint: + case IntBitsToFloat: + case UintBitsToFloat: + /* Probably going to be removed from the final version of the spec. */ + val->ssa = src[0]; + return; + + case Fma: op = nir_op_ffma; break; + case Ldexp: op = nir_op_ldexp; break; + + /* Packing/Unpacking functions */ + case PackSnorm4x8: op = nir_op_pack_snorm_4x8; break; + case PackUnorm4x8: op = nir_op_pack_unorm_4x8; break; + case PackSnorm2x16: op = nir_op_pack_snorm_2x16; break; + case PackUnorm2x16: op = nir_op_pack_unorm_2x16; break; + case PackHalf2x16: op = nir_op_pack_half_2x16; break; + case UnpackSnorm4x8: op = nir_op_unpack_snorm_4x8; break; + case UnpackUnorm4x8: op = nir_op_unpack_unorm_4x8; break; + case UnpackSnorm2x16: op = nir_op_unpack_snorm_2x16; break; + case UnpackUnorm2x16: op = nir_op_unpack_unorm_2x16; break; + case UnpackHalf2x16: op = nir_op_unpack_half_2x16; break; + + case Length: + val->ssa = build_length(&b->nb, src[0]); + return; + case Distance: + val->ssa = build_length(&b->nb, nir_fsub(&b->nb, src[0], src[1])); + return; + case Normalize: + val->ssa = nir_fdiv(&b->nb, src[0], build_length(&b->nb, src[0])); + return; + + case UaddCarry: op = nir_op_uadd_carry; break; + case UsubBorrow: op = nir_op_usub_borrow; break; + case BitfieldExtract: op = nir_op_ubitfield_extract; break; /* TODO */ + case BitfieldInsert: op = nir_op_bitfield_insert; break; + case BitfieldReverse: op = nir_op_bitfield_reverse; break; + case BitCount: op = nir_op_bit_count; break; + case FindLSB: op = nir_op_find_lsb; break; + case FindMSB: op = nir_op_ufind_msb; break; /* TODO */ + + case Clamp: + case Asin: + case Acos: + case Atan: + case Atan2: + case Sinh: + case Cosh: + case Tanh: + case Asinh: + case Acosh: + case Atanh: + case SmoothStep: + case Frexp: + case PackDouble2x32: + case UnpackDouble2x32: + case Cross: + case Ftransform: + case FaceForward: + case Reflect: + case Refract: + case UmulExtended: + case ImulExtended: + default: + unreachable("Unhandled opcode"); + } + + nir_alu_instr *instr = nir_alu_instr_create(b->shader, op); + nir_ssa_dest_init(&instr->instr, &instr->dest.dest, + glsl_get_vector_elements(val->type), val->name); + val->ssa = &instr->dest.dest.ssa; + + for (unsigned i = 0; i < nir_op_infos[op].num_inputs; i++) + instr->src[i].src = nir_src_for_ssa(src[i]); + + nir_builder_instr_insert(&b->nb, &instr->instr); +} + +bool +vtn_handle_glsl450_instruction(struct vtn_builder *b, uint32_t ext_opcode, + const uint32_t *words, unsigned count) +{ + switch ((enum GLSL450Entrypoint)ext_opcode) { + case Determinant: + case MatrixInverse: + case InterpolateAtCentroid: + case InterpolateAtSample: + case InterpolateAtOffset: + unreachable("Unhandled opcode"); + + default: + handle_glsl450_alu(b, (enum GLSL450Entrypoint)ext_opcode, words, count); + } + + return true; +} diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index 78bffda9e8c..0177be04537 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -65,11 +65,24 @@ vtn_handle_extension(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) { switch (opcode) { - case SpvOpExtInstImport: - /* Do nothing for the moment */ + case SpvOpExtInstImport: { + struct vtn_value *val = vtn_push_value(b, w[1], vtn_value_type_extension); + if (strcmp((const char *)&w[2], "GLSL.std.450") == 0) { + val->ext_handler = vtn_handle_glsl450_instruction; + } else { + assert(!"Unsupported extension"); + } break; + } + + case SpvOpExtInst: { + struct vtn_value *val = vtn_value(b, w[3], vtn_value_type_extension); + bool handled = val->ext_handler(b, w[4], w, count); + (void)handled; + assert(handled); + break; + } - case SpvOpExtInst: default: unreachable("Unhandled opcode"); } @@ -792,10 +805,13 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode, case SpvOpSourceExtension: case SpvOpCompileFlag: case SpvOpExtension: - case SpvOpExtInstImport: /* Unhandled, but these are for debug so that's ok. */ break; + case SpvOpExtInstImport: + vtn_handle_extension(b, opcode, w, count); + break; + case SpvOpMemoryModel: assert(w[1] == SpvAddressingModelLogical); assert(w[2] == SpvMemoryModelGLSL450); diff --git a/src/glsl/nir/spirv_to_nir_private.h b/src/glsl/nir/spirv_to_nir_private.h index 0a07b377e72..fd80dd4e161 100644 --- a/src/glsl/nir/spirv_to_nir_private.h +++ b/src/glsl/nir/spirv_to_nir_private.h @@ -43,6 +43,7 @@ enum vtn_value_type { vtn_value_type_function, vtn_value_type_block, vtn_value_type_ssa, + vtn_value_type_extension, }; struct vtn_block { @@ -74,6 +75,7 @@ struct vtn_value { struct vtn_function *func; struct vtn_block *block; nir_ssa_def *ssa; + vtn_instruction_handler ext_handler; }; }; @@ -139,3 +141,6 @@ typedef void (*vtn_decoration_foreach_cb)(struct vtn_builder *, void vtn_foreach_decoration(struct vtn_builder *b, struct vtn_value *value, vtn_decoration_foreach_cb cb, void *data); + +bool vtn_handle_glsl450_instruction(struct vtn_builder *b, uint32_t ext_opcode, + const uint32_t *words, unsigned count); From 9da6d808bec836c413e308caa7b36d74429ecf8d Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 6 May 2015 12:35:30 -0700 Subject: [PATCH 34/55] nir/spirv: Make vtn_ssa_value handle constants as well as ssa values --- src/glsl/nir/spirv_to_nir.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index 0177be04537..03ef4c45dd1 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -31,7 +31,26 @@ nir_ssa_def * vtn_ssa_value(struct vtn_builder *b, uint32_t value_id) { - return vtn_value(b, value_id, vtn_value_type_ssa)->ssa; + struct vtn_value *val = vtn_untyped_value(b, value_id); + switch (val->value_type) { + case vtn_value_type_constant: { + assert(glsl_type_is_vector_or_scalar(val->type)); + unsigned num_components = glsl_get_vector_elements(val->type); + nir_load_const_instr *load = + nir_load_const_instr_create(b->shader, num_components); + + for (unsigned i = 0; i < num_components; i++) + load->value.u[0] = val->constant->value.u[0]; + + nir_builder_instr_insert(&b->nb, &load->instr); + return &load->def; + } + + case vtn_value_type_ssa: + return val->ssa; + default: + unreachable("Invalid type for an SSA value"); + } } static char * From 6fc7911d1565214c9921cfc9da3df37718839184 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 6 May 2015 12:36:09 -0700 Subject: [PATCH 35/55] nir/spirv: Use the correct length for copying string literals --- src/glsl/nir/spirv_to_nir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index 03ef4c45dd1..3d2a26c90b0 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -57,7 +57,7 @@ static char * vtn_string_literal(struct vtn_builder *b, const uint32_t *words, unsigned word_count) { - return ralloc_strndup(b, (char *)words, (word_count - 2) * sizeof(*words)); + return ralloc_strndup(b, (char *)words, word_count * sizeof(*words)); } static const uint32_t * From 4a63761e1d7970f34be19b02b98a0be1a6f1af2c Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 6 May 2015 12:36:31 -0700 Subject: [PATCH 36/55] nir/spirv: Set a name on temporary variables --- src/glsl/nir/spirv_to_nir.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index 3d2a26c90b0..b5130f339c4 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -595,6 +595,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, nir_variable *const_tmp = rzalloc(b->shader, nir_variable); const_tmp->type = dest_type; + const_tmp->name = "const_temp"; const_tmp->data.mode = nir_var_local; const_tmp->data.read_only = true; exec_list_push_tail(&b->impl->locals, &const_tmp->node); From b6562bbc300d75de71ef5ed03fd24bb6cbe8d51b Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 6 May 2015 12:37:10 -0700 Subject: [PATCH 37/55] nir/spirv: Handle control-flow with loops --- src/glsl/nir/spirv_to_nir.c | 168 ++++++++++++++++++++++++---- src/glsl/nir/spirv_to_nir_private.h | 4 +- 2 files changed, 151 insertions(+), 21 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index b5130f339c4..4a12b2930b2 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -1000,6 +1000,13 @@ vtn_handle_first_cfg_pass_instruction(struct vtn_builder *b, SpvOp opcode, b->block = NULL; break; + case SpvOpSelectionMerge: + case SpvOpLoopMerge: + assert(b->block && b->block->merge_op == SpvOpNop); + b->block->merge_op = opcode; + b->block->merge_block_id = w[1]; + break; + default: /* Continue on as per normal */ return true; @@ -1015,19 +1022,20 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, switch (opcode) { case SpvOpLabel: { struct vtn_block *block = vtn_value(b, w[1], vtn_value_type_block)->block; + assert(block->block == NULL); + struct exec_node *list_tail = exec_list_get_tail(b->nb.cf_node_list); nir_cf_node *tail_node = exec_node_data(nir_cf_node, list_tail, node); assert(tail_node->type == nir_cf_node_block); block->block = nir_cf_node_as_block(tail_node); + assert(exec_list_is_empty(&block->block->instr_list)); break; } case SpvOpLoopMerge: case SpvOpSelectionMerge: - assert(b->merge_block == NULL); - /* TODO: Selection Control */ - b->merge_block = vtn_value(b, w[1], vtn_value_type_block)->block; + /* This is handled by cfg pre-pass and walk_blocks */ break; case SpvOpUndef: @@ -1186,19 +1194,68 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, static void vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start, - struct vtn_block *end) + struct vtn_block *break_block, struct vtn_block *cont_block, + struct vtn_block *end_block) { struct vtn_block *block = start; - while (block != end) { + while (block != end_block) { + const uint32_t *w = block->branch; + SpvOp branch_op = w[0] & SpvOpCodeMask; + + if (block->block != NULL) { + /* We've already visited this block once before so this is a + * back-edge. Back-edges are only allowed to point to a loop + * merge. + */ + assert(block == cont_block); + return; + } + + b->block = block; vtn_foreach_instruction(b, block->label, block->branch, vtn_handle_body_instruction); - const uint32_t *w = block->branch; - SpvOp branch_op = w[0] & SpvOpCodeMask; switch (branch_op) { case SpvOpBranch: { - assert(vtn_value(b, w[1], vtn_value_type_block)->block == end); - return; + struct vtn_block *branch_block = + vtn_value(b, w[1], vtn_value_type_block)->block; + + if (branch_block == break_block) { + nir_jump_instr *jump = nir_jump_instr_create(b->shader, + nir_jump_break); + nir_builder_instr_insert(&b->nb, &jump->instr); + + return; + } else if (branch_block == cont_block) { + nir_jump_instr *jump = nir_jump_instr_create(b->shader, + nir_jump_continue); + nir_builder_instr_insert(&b->nb, &jump->instr); + + return; + } else if (branch_block == end_block) { + return; + } else if (branch_block->merge_op == SpvOpLoopMerge) { + /* This is the jump into a loop. */ + cont_block = branch_block; + break_block = vtn_value(b, branch_block->merge_block_id, + vtn_value_type_block)->block; + + nir_loop *loop = nir_loop_create(b->shader); + nir_cf_node_insert_end(b->nb.cf_node_list, &loop->cf_node); + + struct exec_list *old_list = b->nb.cf_node_list; + + nir_builder_insert_after_cf_list(&b->nb, &loop->body); + vtn_walk_blocks(b, branch_block, break_block, cont_block, NULL); + + nir_builder_insert_after_cf_list(&b->nb, old_list); + block = break_block; + continue; + } else { + /* TODO: Can this ever happen? */ + block = branch_block; + continue; + } } case SpvOpBranchConditional: { @@ -1207,28 +1264,99 @@ vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start, vtn_value(b, w[2], vtn_value_type_block)->block; struct vtn_block *else_block = vtn_value(b, w[3], vtn_value_type_block)->block; - struct vtn_block *merge_block = b->merge_block; nir_if *if_stmt = nir_if_create(b->shader); if_stmt->condition = nir_src_for_ssa(vtn_ssa_value(b, w[1])); nir_cf_node_insert_end(b->nb.cf_node_list, &if_stmt->cf_node); - struct exec_list *old_list = b->nb.cf_node_list; + if (then_block == break_block) { + nir_jump_instr *jump = nir_jump_instr_create(b->shader, + nir_jump_break); + nir_instr_insert_after_cf_list(&if_stmt->then_list, + &jump->instr); + block = else_block; + } else if (else_block == break_block) { + nir_jump_instr *jump = nir_jump_instr_create(b->shader, + nir_jump_break); + nir_instr_insert_after_cf_list(&if_stmt->else_list, + &jump->instr); + block = then_block; + } else if (then_block == cont_block) { + nir_jump_instr *jump = nir_jump_instr_create(b->shader, + nir_jump_continue); + nir_instr_insert_after_cf_list(&if_stmt->then_list, + &jump->instr); + block = else_block; + } else if (else_block == cont_block) { + nir_jump_instr *jump = nir_jump_instr_create(b->shader, + nir_jump_continue); + nir_instr_insert_after_cf_list(&if_stmt->else_list, + &jump->instr); + block = then_block; + } else { + /* Conventional if statement */ + assert(block->merge_op == SpvOpSelectionMerge); + struct vtn_block *merge_block = + vtn_value(b, block->merge_block_id, vtn_value_type_block)->block; - nir_builder_insert_after_cf_list(&b->nb, &if_stmt->then_list); - vtn_walk_blocks(b, then_block, merge_block); + struct exec_list *old_list = b->nb.cf_node_list; - nir_builder_insert_after_cf_list(&b->nb, &if_stmt->else_list); - vtn_walk_blocks(b, else_block, merge_block); + nir_builder_insert_after_cf_list(&b->nb, &if_stmt->then_list); + vtn_walk_blocks(b, then_block, break_block, cont_block, merge_block); - nir_builder_insert_after_cf_list(&b->nb, old_list); - block = merge_block; + nir_builder_insert_after_cf_list(&b->nb, &if_stmt->else_list); + vtn_walk_blocks(b, else_block, break_block, cont_block, merge_block); + + nir_builder_insert_after_cf_list(&b->nb, old_list); + block = merge_block; + continue; + } + + /* If we got here then we inserted a predicated break or continue + * above and we need to handle the other case. We already set + * `block` above to indicate what block to visit after the + * predicated break. + */ + + /* It's possible that the other branch is also a break/continue. + * If it is, we handle that here. + */ + if (block == break_block) { + nir_jump_instr *jump = nir_jump_instr_create(b->shader, + nir_jump_break); + nir_builder_instr_insert(&b->nb, &jump->instr); + + return; + } else if (block == cont_block) { + nir_jump_instr *jump = nir_jump_instr_create(b->shader, + nir_jump_continue); + nir_builder_instr_insert(&b->nb, &jump->instr); + + return; + } + + /* If we got here then there was a predicated break/continue but + * the other half of the if has stuff in it. `block` was already + * set above so there is nothing left for us to do. + */ continue; } + case SpvOpReturn: { + nir_jump_instr *jump = nir_jump_instr_create(b->shader, + nir_jump_return); + nir_builder_instr_insert(&b->nb, &jump->instr); + return; + } + + case SpvOpKill: { + nir_intrinsic_instr *discard = + nir_intrinsic_instr_create(b->shader, nir_intrinsic_discard); + nir_builder_instr_insert(&b->nb, &discard->instr); + return; + } + case SpvOpSwitch: - case SpvOpKill: - case SpvOpReturn: case SpvOpReturnValue: case SpvOpUnreachable: default: @@ -1276,7 +1404,7 @@ spirv_to_nir(const uint32_t *words, size_t word_count, b->impl = nir_function_impl_create(func->overload); nir_builder_init(&b->nb, b->impl); nir_builder_insert_after_cf_list(&b->nb, &b->impl->body); - vtn_walk_blocks(b, func->start_block, NULL); + vtn_walk_blocks(b, func->start_block, NULL, NULL, NULL); } ralloc_free(b); diff --git a/src/glsl/nir/spirv_to_nir_private.h b/src/glsl/nir/spirv_to_nir_private.h index fd80dd4e161..d2b364bdfeb 100644 --- a/src/glsl/nir/spirv_to_nir_private.h +++ b/src/glsl/nir/spirv_to_nir_private.h @@ -47,6 +47,9 @@ enum vtn_value_type { }; struct vtn_block { + /* Merge opcode if this block contains a merge; SpvOpNop otherwise. */ + SpvOp merge_op; + uint32_t merge_block_id; const uint32_t *label; const uint32_t *branch; nir_block *block; @@ -92,7 +95,6 @@ struct vtn_builder { nir_shader *shader; nir_function_impl *impl; struct vtn_block *block; - struct vtn_block *merge_block; unsigned value_id_bound; struct vtn_value *values; From ca51d926fd0a1080b114022b362cebb2107f2cbb Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 6 May 2015 12:54:02 -0700 Subject: [PATCH 38/55] nir/spirv: Handle boolean uniforms correctly --- src/glsl/nir/spirv_to_nir.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index 4a12b2930b2..d1205f5ae07 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -573,7 +573,16 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, nir_builder_instr_insert(&b->nb, &load->instr); val->type = src_type; - val->ssa = &load->dest.ssa; + + if (src->var->data.mode == nir_var_uniform && + glsl_get_base_type(src_type) == GLSL_TYPE_BOOL) { + /* Uniform boolean loads need to be fixed up since they're defined + * to be zero/nonzero rather than NIR_FALSE/NIR_TRUE. + */ + val->ssa = nir_ine(&b->nb, &load->dest.ssa, nir_imm_int(&b->nb, 0)); + } else { + val->ssa = &load->dest.ssa; + } break; } From 62b094a81c4f9ccd21622bea3aa18ccd1b9afb41 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 6 May 2015 15:33:21 -0700 Subject: [PATCH 39/55] nir/spirv: Handle jump-to-loop in a more general way --- src/glsl/nir/spirv_to_nir.c | 46 ++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index d1205f5ae07..bcb77faa551 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -1208,9 +1208,6 @@ vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start, { struct vtn_block *block = start; while (block != end_block) { - const uint32_t *w = block->branch; - SpvOp branch_op = w[0] & SpvOpCodeMask; - if (block->block != NULL) { /* We've already visited this block once before so this is a * back-edge. Back-edges are only allowed to point to a loop @@ -1220,6 +1217,31 @@ vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start, return; } + if (block->merge_op == SpvOpLoopMerge) { + /* This is the jump into a loop. */ + cont_block = block; + break_block = vtn_value(b, block->merge_block_id, + vtn_value_type_block)->block; + + nir_loop *loop = nir_loop_create(b->shader); + nir_cf_node_insert_end(b->nb.cf_node_list, &loop->cf_node); + + struct exec_list *old_list = b->nb.cf_node_list; + + /* Reset the merge_op to prerevent infinite recursion */ + block->merge_op = SpvOpNop; + + nir_builder_insert_after_cf_list(&b->nb, &loop->body); + vtn_walk_blocks(b, block, break_block, cont_block, NULL); + + nir_builder_insert_after_cf_list(&b->nb, old_list); + block = break_block; + continue; + } + + const uint32_t *w = block->branch; + SpvOp branch_op = w[0] & SpvOpCodeMask; + b->block = block; vtn_foreach_instruction(b, block->label, block->branch, vtn_handle_body_instruction); @@ -1243,25 +1265,7 @@ vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start, return; } else if (branch_block == end_block) { return; - } else if (branch_block->merge_op == SpvOpLoopMerge) { - /* This is the jump into a loop. */ - cont_block = branch_block; - break_block = vtn_value(b, branch_block->merge_block_id, - vtn_value_type_block)->block; - - nir_loop *loop = nir_loop_create(b->shader); - nir_cf_node_insert_end(b->nb.cf_node_list, &loop->cf_node); - - struct exec_list *old_list = b->nb.cf_node_list; - - nir_builder_insert_after_cf_list(&b->nb, &loop->body); - vtn_walk_blocks(b, branch_block, break_block, cont_block, NULL); - - nir_builder_insert_after_cf_list(&b->nb, old_list); - block = break_block; - continue; } else { - /* TODO: Can this ever happen? */ block = branch_block; continue; } From 2887e68f36e4782b2c255fd2fc11af328e2fe9fe Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Wed, 6 May 2015 15:36:54 -0700 Subject: [PATCH 40/55] nir/spirv: Make the global constants in spirv.h static I've been promissed in a bug that this will be fixed in a future version of the header. However, in the interest of my branch building, I'm adding these changes in myself for the moment. --- src/glsl/nir/spirv.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/glsl/nir/spirv.h b/src/glsl/nir/spirv.h index 93135c09596..da717ecd342 100644 --- a/src/glsl/nir/spirv.h +++ b/src/glsl/nir/spirv.h @@ -48,13 +48,13 @@ namespace spv { -const int MagicNumber = 0x07230203; -const int Version = 99; +static const int MagicNumber = 0x07230203; +static const int Version = 99; typedef unsigned int Id; -const unsigned int OpCodeMask = 0xFFFF; -const unsigned int WordCountShift = 16; +static const unsigned int OpCodeMask = 0xFFFF; +static const unsigned int WordCountShift = 16; enum SourceLanguage { SourceLanguageUnknown = 0, @@ -677,13 +677,13 @@ enum Op { #ifndef __cplusplus -const int SpvMagicNumber = 0x07230203; -const int SpvVersion = 99; +static const int SpvMagicNumber = 0x07230203; +static const int SpvVersion = 99; typedef unsigned int SpvId; -const unsigned int SpvOpCodeMask = 0xFFFF; -const unsigned int SpvWordCountShift = 16; +static const unsigned int SpvOpCodeMask = 0xFFFF; +static const unsigned int SpvWordCountShift = 16; typedef enum SpvSourceLanguage_ { SpvSourceLanguageUnknown = 0, From 45963c9c64bb18e8f8b4cde3ef2c5a93ed19d5fc Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Sat, 16 May 2015 12:32:58 -0700 Subject: [PATCH 41/55] nir/types: Add support for sampler types --- src/glsl/nir/nir_types.cpp | 41 ++++++++++++++++++++++++++++++++++++++ src/glsl/nir/nir_types.h | 8 ++++++++ 2 files changed, 49 insertions(+) diff --git a/src/glsl/nir/nir_types.cpp b/src/glsl/nir/nir_types.cpp index a6d35fe6179..35421506545 100644 --- a/src/glsl/nir/nir_types.cpp +++ b/src/glsl/nir/nir_types.cpp @@ -124,6 +124,20 @@ glsl_get_struct_elem_name(const struct glsl_type *type, unsigned index) return type->fields.structure[index].name; } +glsl_sampler_dim +glsl_get_sampler_dim(const struct glsl_type *type) +{ + assert(glsl_type_is_sampler(type)); + return (glsl_sampler_dim)type->sampler_dimensionality; +} + +glsl_base_type +glsl_get_sampler_result_type(const struct glsl_type *type) +{ + assert(glsl_type_is_sampler(type)); + return (glsl_base_type)type->sampler_type; +} + bool glsl_type_is_void(const glsl_type *type) { @@ -154,6 +168,26 @@ glsl_type_is_matrix(const struct glsl_type *type) return type->is_matrix(); } +bool +glsl_type_is_sampler(const struct glsl_type *type) +{ + return type->is_sampler(); +} + +bool +glsl_sampler_type_is_shadow(const struct glsl_type *type) +{ + assert(glsl_type_is_sampler(type)); + return type->sampler_shadow; +} + +bool +glsl_sampler_type_is_array(const struct glsl_type *type) +{ + assert(glsl_type_is_sampler(type)); + return type->sampler_array; +} + const glsl_type * glsl_void_type(void) { @@ -223,6 +257,13 @@ glsl_struct_type(const glsl_struct_field *fields, return glsl_type::get_record_instance(fields, num_fields, name); } +const struct glsl_type * +glsl_sampler_type(enum glsl_sampler_dim dim, bool is_shadow, bool is_array, + enum glsl_base_type base_type) +{ + return glsl_type::get_sampler_instance(dim, is_shadow, is_array, base_type); +} + const glsl_type * glsl_function_type(const glsl_type *return_type, const glsl_function_param *params, unsigned num_params) diff --git a/src/glsl/nir/nir_types.h b/src/glsl/nir/nir_types.h index f19f0e5db5d..ceb131c9f47 100644 --- a/src/glsl/nir/nir_types.h +++ b/src/glsl/nir/nir_types.h @@ -68,12 +68,17 @@ unsigned glsl_get_length(const struct glsl_type *type); const char *glsl_get_struct_elem_name(const struct glsl_type *type, unsigned index); +enum glsl_sampler_dim glsl_get_sampler_dim(const struct glsl_type *type); +enum glsl_base_type glsl_get_sampler_result_type(const struct glsl_type *type); bool glsl_type_is_void(const struct glsl_type *type); bool glsl_type_is_vector(const struct glsl_type *type); bool glsl_type_is_scalar(const struct glsl_type *type); bool glsl_type_is_vector_or_scalar(const struct glsl_type *type); bool glsl_type_is_matrix(const struct glsl_type *type); +bool glsl_type_is_sampler(const struct glsl_type *type); +bool glsl_sampler_type_is_shadow(const struct glsl_type *type); +bool glsl_sampler_type_is_array(const struct glsl_type *type); const struct glsl_type *glsl_void_type(void); const struct glsl_type *glsl_float_type(void); @@ -91,6 +96,9 @@ const struct glsl_type *glsl_array_type(const struct glsl_type *base, unsigned elements); const struct glsl_type *glsl_struct_type(const struct glsl_struct_field *fields, unsigned num_fields, const char *name); +const struct glsl_type *glsl_sampler_type(enum glsl_sampler_dim dim, + bool is_shadow, bool is_array, + enum glsl_base_type base_type); const struct glsl_type * glsl_function_type(const struct glsl_type *return_type, const struct glsl_function_param *params, unsigned num_params); From a992909aaef77c55162c4e92b16f009fe6b40fe2 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Sat, 16 May 2015 12:33:29 -0700 Subject: [PATCH 42/55] nir/spirv: Move Exp and Log to the list of currently unhandled ALU ops NIR doesn't have the native opcodes for them anymore --- src/glsl/nir/spirv_glsl450_to_nir.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/glsl/nir/spirv_glsl450_to_nir.c b/src/glsl/nir/spirv_glsl450_to_nir.c index 240ff012fe1..3b9d0940aad 100644 --- a/src/glsl/nir/spirv_glsl450_to_nir.c +++ b/src/glsl/nir/spirv_glsl450_to_nir.c @@ -170,8 +170,6 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSL450Entrypoint entrypoint, nir_fcos(&b->nb, src[0])); return; case Pow: op = nir_op_fpow; break; - case Exp: op = nir_op_fexp; break; - case Log: op = nir_op_flog; break; case Exp2: op = nir_op_fexp2; break; case Log2: op = nir_op_flog2; break; case Sqrt: op = nir_op_fsqrt; break; @@ -227,6 +225,8 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSL450Entrypoint entrypoint, case FindLSB: op = nir_op_find_lsb; break; case FindMSB: op = nir_op_ufind_msb; break; /* TODO */ + case Exp: + case Log: case Clamp: case Asin: case Acos: From fe220ebd371308c89f969a89bcff2b0c63ff070a Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Sat, 16 May 2015 12:34:15 -0700 Subject: [PATCH 43/55] nir/spirv: Add initial support for samplers --- src/glsl/nir/spirv_to_nir.c | 155 +++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 3 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index bcb77faa551..a0404dfd057 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -256,7 +256,36 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode, */ return vtn_value(b, args[1], vtn_value_type_type)->type; - case SpvOpTypeSampler: + case SpvOpTypeSampler: { + const struct glsl_type *sampled_type = + vtn_value(b, args[0], vtn_value_type_type)->type; + + assert(glsl_type_is_vector_or_scalar(sampled_type)); + + enum glsl_sampler_dim dim; + switch ((SpvDim)args[1]) { + case SpvDim1D: dim = GLSL_SAMPLER_DIM_1D; break; + case SpvDim2D: dim = GLSL_SAMPLER_DIM_2D; break; + case SpvDim3D: dim = GLSL_SAMPLER_DIM_3D; break; + case SpvDimCube: dim = GLSL_SAMPLER_DIM_CUBE; break; + case SpvDimRect: dim = GLSL_SAMPLER_DIM_RECT; break; + case SpvDimBuffer: dim = GLSL_SAMPLER_DIM_BUF; break; + default: + unreachable("Invalid SPIR-V Sampler dimension"); + } + + /* TODO: Handle the various texture image/filter options */ + (void)args[2]; + + bool is_array = args[3]; + bool is_shadow = args[4]; + + assert(args[5] == 0 && "FIXME: Handl multi-sampled textures"); + + return glsl_sampler_type(dim, is_shadow, is_array, + glsl_get_base_type(sampled_type)); + } + case SpvOpTypeRuntimeArray: case SpvOpTypeOpaque: case SpvOpTypeEvent: @@ -559,10 +588,16 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, } case SpvOpLoad: { - struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); nir_deref_var *src = vtn_value(b, w[3], vtn_value_type_deref)->deref; const struct glsl_type *src_type = nir_deref_tail(&src->deref)->type; + + if (glsl_get_base_type(src_type) == GLSL_TYPE_SAMPLER) { + vtn_push_value(b, w[2], vtn_value_type_deref)->deref = src; + return; + } + assert(glsl_type_is_vector_or_scalar(src_type)); + struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); nir_intrinsic_instr *load = nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_var); @@ -635,11 +670,125 @@ vtn_handle_function_call(struct vtn_builder *b, SpvOp opcode, unreachable("Unhandled opcode"); } +static nir_tex_src +vtn_tex_src(struct vtn_builder *b, unsigned index, nir_tex_src_type type) +{ + nir_tex_src src; + src.src = nir_src_for_ssa(vtn_value(b, index, vtn_value_type_ssa)->ssa); + src.src_type = type; + return src; +} + static void vtn_handle_texture(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) { - unreachable("Unhandled opcode"); + struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); + nir_deref_var *sampler = vtn_value(b, w[3], vtn_value_type_deref)->deref; + + nir_tex_src srcs[8]; /* 8 should be enough */ + nir_tex_src *p = srcs; + + unsigned coord_components = 0; + switch (opcode) { + case SpvOpTextureSample: + case SpvOpTextureSampleDref: + case SpvOpTextureSampleLod: + case SpvOpTextureSampleProj: + case SpvOpTextureSampleGrad: + case SpvOpTextureSampleOffset: + case SpvOpTextureSampleProjLod: + case SpvOpTextureSampleProjGrad: + case SpvOpTextureSampleLodOffset: + case SpvOpTextureSampleProjOffset: + case SpvOpTextureSampleGradOffset: + case SpvOpTextureSampleProjLodOffset: + case SpvOpTextureSampleProjGradOffset: + case SpvOpTextureFetchTexelLod: + case SpvOpTextureFetchTexelOffset: + case SpvOpTextureFetchSample: + case SpvOpTextureFetchTexel: + case SpvOpTextureGather: + case SpvOpTextureGatherOffset: + case SpvOpTextureGatherOffsets: + case SpvOpTextureQueryLod: { + /* All these types have the coordinate as their first real argument */ + struct vtn_value *coord = vtn_value(b, w[4], vtn_value_type_ssa); + coord_components = glsl_get_vector_elements(coord->type); + p->src = nir_src_for_ssa(coord->ssa); + p->src_type = nir_tex_src_coord; + p++; + break; + } + default: + break; + } + + nir_texop texop; + switch (opcode) { + case SpvOpTextureSample: + texop = nir_texop_tex; + + if (count == 6) { + texop = nir_texop_txb; + *p++ = vtn_tex_src(b, w[5], nir_tex_src_bias); + } + break; + + case SpvOpTextureSampleDref: + case SpvOpTextureSampleLod: + case SpvOpTextureSampleProj: + case SpvOpTextureSampleGrad: + case SpvOpTextureSampleOffset: + case SpvOpTextureSampleProjLod: + case SpvOpTextureSampleProjGrad: + case SpvOpTextureSampleLodOffset: + case SpvOpTextureSampleProjOffset: + case SpvOpTextureSampleGradOffset: + case SpvOpTextureSampleProjLodOffset: + case SpvOpTextureSampleProjGradOffset: + case SpvOpTextureFetchTexelLod: + case SpvOpTextureFetchTexelOffset: + case SpvOpTextureFetchSample: + case SpvOpTextureFetchTexel: + case SpvOpTextureGather: + case SpvOpTextureGatherOffset: + case SpvOpTextureGatherOffsets: + case SpvOpTextureQuerySizeLod: + case SpvOpTextureQuerySize: + case SpvOpTextureQueryLod: + case SpvOpTextureQueryLevels: + case SpvOpTextureQuerySamples: + default: + unreachable("Unhandled opcode"); + } + + nir_tex_instr *instr = nir_tex_instr_create(b->shader, p - srcs); + + const struct glsl_type *sampler_type = nir_deref_tail(&sampler->deref)->type; + instr->sampler_dim = glsl_get_sampler_dim(sampler_type); + + switch (glsl_get_sampler_result_type(sampler_type)) { + case GLSL_TYPE_FLOAT: instr->dest_type = nir_type_float; break; + case GLSL_TYPE_INT: instr->dest_type = nir_type_int; break; + case GLSL_TYPE_UINT: instr->dest_type = nir_type_unsigned; break; + case GLSL_TYPE_BOOL: instr->dest_type = nir_type_bool; break; + default: + unreachable("Invalid base type for sampler result"); + } + + instr->op = texop; + memcpy(instr->src, srcs, instr->num_srcs * sizeof(*instr->src)); + instr->coord_components = coord_components; + instr->is_array = glsl_sampler_type_is_array(sampler_type); + instr->is_shadow = glsl_sampler_type_is_shadow(sampler_type); + + instr->sampler = sampler; + + nir_ssa_dest_init(&instr->instr, &instr->dest, 4, NULL); + val->ssa = &instr->dest.ssa; + + nir_builder_instr_insert(&b->nb, &instr->instr); } static void From 756b00389c4034331989299d0dd3505da02dfa78 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Sat, 16 May 2015 12:34:32 -0700 Subject: [PATCH 44/55] nir/spirv: Don't assert that the current block is empty It's possible that someone will give us SPIR-V code in which someone needlessly branches to new blocks. We should handle that ok now. --- src/glsl/nir/spirv_to_nir.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index a0404dfd057..3f2ef15c74f 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -1186,8 +1186,6 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, nir_cf_node *tail_node = exec_node_data(nir_cf_node, list_tail, node); assert(tail_node->type == nir_cf_node_block); block->block = nir_cf_node_as_block(tail_node); - - assert(exec_list_is_empty(&block->block->instr_list)); break; } From a1e136711bc661f4471115396f6a477a5fe9f930 Mon Sep 17 00:00:00 2001 From: Connor Abbott Date: Thu, 18 Jun 2015 17:34:12 -0700 Subject: [PATCH 45/55] nir/types: add a helper to transpose a matrix type --- src/glsl/nir/nir_types.cpp | 7 +++++++ src/glsl/nir/nir_types.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/src/glsl/nir/nir_types.cpp b/src/glsl/nir/nir_types.cpp index 35421506545..d44d48095da 100644 --- a/src/glsl/nir/nir_types.cpp +++ b/src/glsl/nir/nir_types.cpp @@ -270,3 +270,10 @@ glsl_function_type(const glsl_type *return_type, { return glsl_type::get_function_instance(return_type, params, num_params); } + +const glsl_type * +glsl_transposed_type(const struct glsl_type *type) +{ + return glsl_type::get_instance(type->base_type, type->matrix_columns, + type->vector_elements); +} diff --git a/src/glsl/nir/nir_types.h b/src/glsl/nir/nir_types.h index ceb131c9f47..60e1d9d96fc 100644 --- a/src/glsl/nir/nir_types.h +++ b/src/glsl/nir/nir_types.h @@ -103,6 +103,8 @@ const struct glsl_type * glsl_function_type(const struct glsl_type *return_type, const struct glsl_function_param *params, unsigned num_params); +const struct glsl_type *glsl_transposed_type(const struct glsl_type *type); + #ifdef __cplusplus } #endif From c62be3828671706600f4b661e0b67fef78580cd2 Mon Sep 17 00:00:00 2001 From: Connor Abbott Date: Wed, 15 Jul 2015 21:58:32 -0700 Subject: [PATCH 46/55] nir/types: add more nir_type_is_xxx() wrappers --- src/glsl/nir/nir_types.cpp | 12 ++++++++++++ src/glsl/nir/nir_types.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/glsl/nir/nir_types.cpp b/src/glsl/nir/nir_types.cpp index d44d48095da..809a7cff79c 100644 --- a/src/glsl/nir/nir_types.cpp +++ b/src/glsl/nir/nir_types.cpp @@ -168,6 +168,18 @@ glsl_type_is_matrix(const struct glsl_type *type) return type->is_matrix(); } +bool +glsl_type_is_array(const struct glsl_type *type) +{ + return type->is_array(); +} + +bool +glsl_type_is_struct(const struct glsl_type *type) +{ + return type->is_record() || type->is_interface(); +} + bool glsl_type_is_sampler(const struct glsl_type *type) { diff --git a/src/glsl/nir/nir_types.h b/src/glsl/nir/nir_types.h index 60e1d9d96fc..a2fa7934e16 100644 --- a/src/glsl/nir/nir_types.h +++ b/src/glsl/nir/nir_types.h @@ -76,6 +76,8 @@ bool glsl_type_is_vector(const struct glsl_type *type); bool glsl_type_is_scalar(const struct glsl_type *type); bool glsl_type_is_vector_or_scalar(const struct glsl_type *type); bool glsl_type_is_matrix(const struct glsl_type *type); +bool glsl_type_is_array(const struct glsl_type *type); +bool glsl_type_is_struct(const struct glsl_type *type); bool glsl_type_is_sampler(const struct glsl_type *type); bool glsl_sampler_type_is_shadow(const struct glsl_type *type); bool glsl_sampler_type_is_array(const struct glsl_type *type); From 4956bbaa33858f2d67465421ac59dcfd66637c8b Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Fri, 28 Aug 2015 17:17:39 -0700 Subject: [PATCH 47/55] nir/cursor: Add a constructor for the end of a block but before the jump --- src/glsl/nir/nir.h | 11 +++++++++++ src/glsl/nir/nir_from_ssa.c | 7 +------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h index fc8f27a7fe5..0358f53737e 100644 --- a/src/glsl/nir/nir.h +++ b/src/glsl/nir/nir.h @@ -1616,6 +1616,17 @@ nir_after_instr(nir_instr *instr) return cursor; } +static inline nir_cursor +nir_after_block_before_jump(nir_block *block) +{ + nir_instr *last_instr = nir_block_last_instr(block); + if (last_instr && last_instr->type == nir_instr_type_jump) { + return nir_before_instr(last_instr); + } else { + return nir_after_block(block); + } +} + static inline nir_cursor nir_before_cf_node(nir_cf_node *node) { diff --git a/src/glsl/nir/nir_from_ssa.c b/src/glsl/nir/nir_from_ssa.c index 1fd8b24d33d..94002f18cd7 100644 --- a/src/glsl/nir/nir_from_ssa.c +++ b/src/glsl/nir/nir_from_ssa.c @@ -249,12 +249,7 @@ add_parallel_copy_to_end_of_block(nir_block *block, void *void_state) nir_parallel_copy_instr *pcopy = nir_parallel_copy_instr_create(state->dead_ctx); - nir_instr *last_instr = nir_block_last_instr(block); - if (last_instr && last_instr->type == nir_instr_type_jump) { - nir_instr_insert_before(last_instr, &pcopy->instr); - } else { - nir_instr_insert_after_block(block, &pcopy->instr); - } + nir_instr_insert(nir_after_block_before_jump(block), &pcopy->instr); } return true; From f6a0eff1ba3899276988cc115289d78363c25af0 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Fri, 28 Aug 2015 17:09:02 -0700 Subject: [PATCH 48/55] nir: Add a pass to lower outputs to temporary variables This pass can be used as a helper for NIR producers so they don't have to worry about creating the temporaries themselves. --- src/glsl/Makefile.sources | 1 + src/glsl/nir/nir.h | 2 + .../nir/nir_lower_outputs_to_temporaries.c | 93 +++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 src/glsl/nir/nir_lower_outputs_to_temporaries.c diff --git a/src/glsl/Makefile.sources b/src/glsl/Makefile.sources index da38e3576bd..acd13ef7745 100644 --- a/src/glsl/Makefile.sources +++ b/src/glsl/Makefile.sources @@ -40,6 +40,7 @@ NIR_FILES = \ nir/nir_lower_locals_to_regs.c \ nir/nir_lower_idiv.c \ nir/nir_lower_io.c \ + nir/nir_lower_outputs_to_temporaries.c \ nir/nir_lower_phis_to_scalar.c \ nir/nir_lower_samplers.cpp \ nir/nir_lower_system_values.c \ diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h index 0358f53737e..ac80af37bae 100644 --- a/src/glsl/nir/nir.h +++ b/src/glsl/nir/nir.h @@ -1791,6 +1791,8 @@ void nir_lower_global_vars_to_local(nir_shader *shader); void nir_lower_locals_to_regs(nir_shader *shader); +void nir_lower_outputs_to_temporaries(nir_shader *shader); + void nir_assign_var_locations(struct exec_list *var_list, unsigned *size, int (*type_size)(const struct glsl_type *)); diff --git a/src/glsl/nir/nir_lower_outputs_to_temporaries.c b/src/glsl/nir/nir_lower_outputs_to_temporaries.c new file mode 100644 index 00000000000..1a3e7721c31 --- /dev/null +++ b/src/glsl/nir/nir_lower_outputs_to_temporaries.c @@ -0,0 +1,93 @@ +/* + * Copyright © 2015 Intel Corporation + * + * 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 (including the next + * paragraph) 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. + * + * Authors: + * Jason Ekstrand (jason@jlekstrand.net) + * + */ + +/* + * Implements a pass that lowers output variables to a temporary plus an + * output variable with a single copy at each exit point of the shader. + * This way the output variable is only ever written. + * + * Because valid NIR requires that output variables are never read, this + * pass is more of a helper for NIR producers and must be run before the + * shader is ever validated. + */ + +#include "nir.h" + +static void +emit_output_copies(nir_shader *shader, nir_variable *temp, nir_variable *output) +{ + nir_foreach_overload(shader, overload) { + if (!overload->impl || strcmp(overload->function->name, "main")) + continue; + + struct set_entry *block_entry; + set_foreach(overload->impl->end_block->predecessors, block_entry) { + struct nir_block *block = (void *)block_entry->key; + + nir_intrinsic_instr *copy = + nir_intrinsic_instr_create(shader, nir_intrinsic_copy_var); + copy->variables[0] = nir_deref_var_create(copy, output); + copy->variables[1] = nir_deref_var_create(copy, temp); + + nir_instr_insert(nir_after_block_before_jump(block), ©->instr); + } + } +} + +void +nir_lower_outputs_to_temporaries(nir_shader *shader) +{ + struct exec_list old_outputs; + + exec_list_move_nodes_to(&shader->outputs, &old_outputs); + + /* Walk over all of the outputs turn each output into a temporary and + * make a new variable for the actual output. + */ + foreach_list_typed(nir_variable, var, node, &old_outputs) { + nir_variable *output = ralloc(shader, nir_variable); + memcpy(output, var, sizeof *output); + + /* The orignal is now the temporary */ + nir_variable *temp = var; + + /* Move the original name over to the new output */ + if (output->name) + ralloc_steal(output, output->name); + + /* Give the output a new name with @out-temp appended */ + temp->name = ralloc_asprintf(var, "%s@out-temp", output->name); + temp->data.mode = nir_var_global; + temp->constant_initializer = NULL; + + exec_list_push_tail(&shader->outputs, &output->node); + + emit_output_copies(shader, temp, output); + } + + exec_list_append(&shader->globals, &old_outputs); +} From 024c49e95e04dc6ec86c851450bfc954e46265d6 Mon Sep 17 00:00:00 2001 From: Connor Abbott Date: Thu, 18 Jun 2015 17:34:55 -0700 Subject: [PATCH 49/55] nir/builder: add a nir_fdot() convenience function --- src/glsl/nir/nir_builder.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/glsl/nir/nir_builder.h b/src/glsl/nir/nir_builder.h index 08b40f8ea7c..3aa0efded3c 100644 --- a/src/glsl/nir/nir_builder.h +++ b/src/glsl/nir/nir_builder.h @@ -217,6 +217,23 @@ nir_swizzle(nir_builder *build, nir_ssa_def *src, unsigned swiz[4], nir_imov_alu(build, alu_src, num_components); } +/* Selects the right fdot given the number of components in each source. */ +static inline nir_ssa_def * +nir_fdot(nir_builder *build, nir_ssa_def *src0, nir_ssa_def *src1) +{ + assert(src0->num_components == src1->num_components); + switch (src0->num_components) { + case 1: return nir_fmul(build, src0, src1); + case 2: return nir_fdot2(build, src0, src1); + case 3: return nir_fdot3(build, src0, src1); + case 4: return nir_fdot4(build, src0, src1); + default: + unreachable("bad component size"); + } + + return NULL; +} + /** * Turns a nir_src into a nir_ssa_def * so it can be passed to * nir_build_alu()-based builder calls. From de4f379a7092bb1710e205128447ff447b3868c5 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 31 Aug 2015 14:48:10 -0700 Subject: [PATCH 50/55] nir/cursor: Add a helper for getting the current block --- src/glsl/nir/nir.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h index ac80af37bae..2ad739523ba 100644 --- a/src/glsl/nir/nir.h +++ b/src/glsl/nir/nir.h @@ -1580,6 +1580,17 @@ typedef struct { }; } nir_cursor; +static inline nir_block * +nir_cursor_current_block(nir_cursor cursor) +{ + if (cursor.option == nir_cursor_before_instr || + cursor.option == nir_cursor_after_instr) { + return cursor.instr->block; + } else { + return cursor.block; + } +} + static inline nir_cursor nir_before_block(nir_block *block) { From 85cf2385c525caa576199d2020a2faab57ee041b Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 31 Aug 2015 14:55:49 -0700 Subject: [PATCH 51/55] mesa: Move gl_vert_attrib from mtypes.h to shader_enums.h It is a shader enum after all... --- src/glsl/shader_enums.h | 108 ++++++++++++++++++++++++++++++++++++++++ src/mesa/main/mtypes.h | 107 --------------------------------------- 2 files changed, 108 insertions(+), 107 deletions(-) diff --git a/src/glsl/shader_enums.h b/src/glsl/shader_enums.h index c6f4678f56f..9bb163f3bb0 100644 --- a/src/glsl/shader_enums.h +++ b/src/glsl/shader_enums.h @@ -45,6 +45,114 @@ typedef enum #define MESA_SHADER_STAGES (MESA_SHADER_COMPUTE + 1) + +/** + * Indexes for vertex program attributes. + * GL_NV_vertex_program aliases generic attributes over the conventional + * attributes. In GL_ARB_vertex_program shader the aliasing is optional. + * In GL_ARB_vertex_shader / OpenGL 2.0 the aliasing is disallowed (the + * generic attributes are distinct/separate). + */ +typedef enum +{ + VERT_ATTRIB_POS = 0, + VERT_ATTRIB_WEIGHT = 1, + VERT_ATTRIB_NORMAL = 2, + VERT_ATTRIB_COLOR0 = 3, + VERT_ATTRIB_COLOR1 = 4, + VERT_ATTRIB_FOG = 5, + VERT_ATTRIB_COLOR_INDEX = 6, + VERT_ATTRIB_EDGEFLAG = 7, + VERT_ATTRIB_TEX0 = 8, + VERT_ATTRIB_TEX1 = 9, + VERT_ATTRIB_TEX2 = 10, + VERT_ATTRIB_TEX3 = 11, + VERT_ATTRIB_TEX4 = 12, + VERT_ATTRIB_TEX5 = 13, + VERT_ATTRIB_TEX6 = 14, + VERT_ATTRIB_TEX7 = 15, + VERT_ATTRIB_POINT_SIZE = 16, + VERT_ATTRIB_GENERIC0 = 17, + VERT_ATTRIB_GENERIC1 = 18, + VERT_ATTRIB_GENERIC2 = 19, + VERT_ATTRIB_GENERIC3 = 20, + VERT_ATTRIB_GENERIC4 = 21, + VERT_ATTRIB_GENERIC5 = 22, + VERT_ATTRIB_GENERIC6 = 23, + VERT_ATTRIB_GENERIC7 = 24, + VERT_ATTRIB_GENERIC8 = 25, + VERT_ATTRIB_GENERIC9 = 26, + VERT_ATTRIB_GENERIC10 = 27, + VERT_ATTRIB_GENERIC11 = 28, + VERT_ATTRIB_GENERIC12 = 29, + VERT_ATTRIB_GENERIC13 = 30, + VERT_ATTRIB_GENERIC14 = 31, + VERT_ATTRIB_GENERIC15 = 32, + VERT_ATTRIB_MAX = 33 +} gl_vert_attrib; + +/** + * Symbolic constats to help iterating over + * specific blocks of vertex attributes. + * + * VERT_ATTRIB_FF + * includes all fixed function attributes as well as + * the aliased GL_NV_vertex_program shader attributes. + * VERT_ATTRIB_TEX + * include the classic texture coordinate attributes. + * Is a subset of VERT_ATTRIB_FF. + * VERT_ATTRIB_GENERIC + * include the OpenGL 2.0+ GLSL generic shader attributes. + * These alias the generic GL_ARB_vertex_shader attributes. + */ +#define VERT_ATTRIB_FF(i) (VERT_ATTRIB_POS + (i)) +#define VERT_ATTRIB_FF_MAX VERT_ATTRIB_GENERIC0 + +#define VERT_ATTRIB_TEX(i) (VERT_ATTRIB_TEX0 + (i)) +#define VERT_ATTRIB_TEX_MAX MAX_TEXTURE_COORD_UNITS + +#define VERT_ATTRIB_GENERIC(i) (VERT_ATTRIB_GENERIC0 + (i)) +#define VERT_ATTRIB_GENERIC_MAX MAX_VERTEX_GENERIC_ATTRIBS + +/** + * Bitflags for vertex attributes. + * These are used in bitfields in many places. + */ +/*@{*/ +#define VERT_BIT_POS BITFIELD64_BIT(VERT_ATTRIB_POS) +#define VERT_BIT_WEIGHT BITFIELD64_BIT(VERT_ATTRIB_WEIGHT) +#define VERT_BIT_NORMAL BITFIELD64_BIT(VERT_ATTRIB_NORMAL) +#define VERT_BIT_COLOR0 BITFIELD64_BIT(VERT_ATTRIB_COLOR0) +#define VERT_BIT_COLOR1 BITFIELD64_BIT(VERT_ATTRIB_COLOR1) +#define VERT_BIT_FOG BITFIELD64_BIT(VERT_ATTRIB_FOG) +#define VERT_BIT_COLOR_INDEX BITFIELD64_BIT(VERT_ATTRIB_COLOR_INDEX) +#define VERT_BIT_EDGEFLAG BITFIELD64_BIT(VERT_ATTRIB_EDGEFLAG) +#define VERT_BIT_TEX0 BITFIELD64_BIT(VERT_ATTRIB_TEX0) +#define VERT_BIT_TEX1 BITFIELD64_BIT(VERT_ATTRIB_TEX1) +#define VERT_BIT_TEX2 BITFIELD64_BIT(VERT_ATTRIB_TEX2) +#define VERT_BIT_TEX3 BITFIELD64_BIT(VERT_ATTRIB_TEX3) +#define VERT_BIT_TEX4 BITFIELD64_BIT(VERT_ATTRIB_TEX4) +#define VERT_BIT_TEX5 BITFIELD64_BIT(VERT_ATTRIB_TEX5) +#define VERT_BIT_TEX6 BITFIELD64_BIT(VERT_ATTRIB_TEX6) +#define VERT_BIT_TEX7 BITFIELD64_BIT(VERT_ATTRIB_TEX7) +#define VERT_BIT_POINT_SIZE BITFIELD64_BIT(VERT_ATTRIB_POINT_SIZE) +#define VERT_BIT_GENERIC0 BITFIELD64_BIT(VERT_ATTRIB_GENERIC0) + +#define VERT_BIT(i) BITFIELD64_BIT(i) +#define VERT_BIT_ALL BITFIELD64_RANGE(0, VERT_ATTRIB_MAX) + +#define VERT_BIT_FF(i) VERT_BIT(i) +#define VERT_BIT_FF_ALL BITFIELD64_RANGE(0, VERT_ATTRIB_FF_MAX) +#define VERT_BIT_TEX(i) VERT_BIT(VERT_ATTRIB_TEX(i)) +#define VERT_BIT_TEX_ALL \ + BITFIELD64_RANGE(VERT_ATTRIB_TEX(0), VERT_ATTRIB_TEX_MAX) + +#define VERT_BIT_GENERIC(i) VERT_BIT(VERT_ATTRIB_GENERIC(i)) +#define VERT_BIT_GENERIC_ALL \ + BITFIELD64_RANGE(VERT_ATTRIB_GENERIC(0), VERT_ATTRIB_GENERIC_MAX) +/*@}*/ + + /** * Indexes for vertex shader outputs, geometry shader inputs/outputs, and * fragment shader inputs. diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h index a172952c1fb..85a9f5dc5f1 100644 --- a/src/mesa/main/mtypes.h +++ b/src/mesa/main/mtypes.h @@ -94,113 +94,6 @@ struct vbo_context; #define PRIM_OUTSIDE_BEGIN_END (PRIM_MAX + 1) #define PRIM_UNKNOWN (PRIM_MAX + 2) -/** - * Indexes for vertex program attributes. - * GL_NV_vertex_program aliases generic attributes over the conventional - * attributes. In GL_ARB_vertex_program shader the aliasing is optional. - * In GL_ARB_vertex_shader / OpenGL 2.0 the aliasing is disallowed (the - * generic attributes are distinct/separate). - */ -typedef enum -{ - VERT_ATTRIB_POS = 0, - VERT_ATTRIB_WEIGHT = 1, - VERT_ATTRIB_NORMAL = 2, - VERT_ATTRIB_COLOR0 = 3, - VERT_ATTRIB_COLOR1 = 4, - VERT_ATTRIB_FOG = 5, - VERT_ATTRIB_COLOR_INDEX = 6, - VERT_ATTRIB_EDGEFLAG = 7, - VERT_ATTRIB_TEX0 = 8, - VERT_ATTRIB_TEX1 = 9, - VERT_ATTRIB_TEX2 = 10, - VERT_ATTRIB_TEX3 = 11, - VERT_ATTRIB_TEX4 = 12, - VERT_ATTRIB_TEX5 = 13, - VERT_ATTRIB_TEX6 = 14, - VERT_ATTRIB_TEX7 = 15, - VERT_ATTRIB_POINT_SIZE = 16, - VERT_ATTRIB_GENERIC0 = 17, - VERT_ATTRIB_GENERIC1 = 18, - VERT_ATTRIB_GENERIC2 = 19, - VERT_ATTRIB_GENERIC3 = 20, - VERT_ATTRIB_GENERIC4 = 21, - VERT_ATTRIB_GENERIC5 = 22, - VERT_ATTRIB_GENERIC6 = 23, - VERT_ATTRIB_GENERIC7 = 24, - VERT_ATTRIB_GENERIC8 = 25, - VERT_ATTRIB_GENERIC9 = 26, - VERT_ATTRIB_GENERIC10 = 27, - VERT_ATTRIB_GENERIC11 = 28, - VERT_ATTRIB_GENERIC12 = 29, - VERT_ATTRIB_GENERIC13 = 30, - VERT_ATTRIB_GENERIC14 = 31, - VERT_ATTRIB_GENERIC15 = 32, - VERT_ATTRIB_MAX = 33 -} gl_vert_attrib; - -/** - * Symbolic constats to help iterating over - * specific blocks of vertex attributes. - * - * VERT_ATTRIB_FF - * includes all fixed function attributes as well as - * the aliased GL_NV_vertex_program shader attributes. - * VERT_ATTRIB_TEX - * include the classic texture coordinate attributes. - * Is a subset of VERT_ATTRIB_FF. - * VERT_ATTRIB_GENERIC - * include the OpenGL 2.0+ GLSL generic shader attributes. - * These alias the generic GL_ARB_vertex_shader attributes. - */ -#define VERT_ATTRIB_FF(i) (VERT_ATTRIB_POS + (i)) -#define VERT_ATTRIB_FF_MAX VERT_ATTRIB_GENERIC0 - -#define VERT_ATTRIB_TEX(i) (VERT_ATTRIB_TEX0 + (i)) -#define VERT_ATTRIB_TEX_MAX MAX_TEXTURE_COORD_UNITS - -#define VERT_ATTRIB_GENERIC(i) (VERT_ATTRIB_GENERIC0 + (i)) -#define VERT_ATTRIB_GENERIC_MAX MAX_VERTEX_GENERIC_ATTRIBS - -/** - * Bitflags for vertex attributes. - * These are used in bitfields in many places. - */ -/*@{*/ -#define VERT_BIT_POS BITFIELD64_BIT(VERT_ATTRIB_POS) -#define VERT_BIT_WEIGHT BITFIELD64_BIT(VERT_ATTRIB_WEIGHT) -#define VERT_BIT_NORMAL BITFIELD64_BIT(VERT_ATTRIB_NORMAL) -#define VERT_BIT_COLOR0 BITFIELD64_BIT(VERT_ATTRIB_COLOR0) -#define VERT_BIT_COLOR1 BITFIELD64_BIT(VERT_ATTRIB_COLOR1) -#define VERT_BIT_FOG BITFIELD64_BIT(VERT_ATTRIB_FOG) -#define VERT_BIT_COLOR_INDEX BITFIELD64_BIT(VERT_ATTRIB_COLOR_INDEX) -#define VERT_BIT_EDGEFLAG BITFIELD64_BIT(VERT_ATTRIB_EDGEFLAG) -#define VERT_BIT_TEX0 BITFIELD64_BIT(VERT_ATTRIB_TEX0) -#define VERT_BIT_TEX1 BITFIELD64_BIT(VERT_ATTRIB_TEX1) -#define VERT_BIT_TEX2 BITFIELD64_BIT(VERT_ATTRIB_TEX2) -#define VERT_BIT_TEX3 BITFIELD64_BIT(VERT_ATTRIB_TEX3) -#define VERT_BIT_TEX4 BITFIELD64_BIT(VERT_ATTRIB_TEX4) -#define VERT_BIT_TEX5 BITFIELD64_BIT(VERT_ATTRIB_TEX5) -#define VERT_BIT_TEX6 BITFIELD64_BIT(VERT_ATTRIB_TEX6) -#define VERT_BIT_TEX7 BITFIELD64_BIT(VERT_ATTRIB_TEX7) -#define VERT_BIT_POINT_SIZE BITFIELD64_BIT(VERT_ATTRIB_POINT_SIZE) -#define VERT_BIT_GENERIC0 BITFIELD64_BIT(VERT_ATTRIB_GENERIC0) - -#define VERT_BIT(i) BITFIELD64_BIT(i) -#define VERT_BIT_ALL BITFIELD64_RANGE(0, VERT_ATTRIB_MAX) - -#define VERT_BIT_FF(i) VERT_BIT(i) -#define VERT_BIT_FF_ALL BITFIELD64_RANGE(0, VERT_ATTRIB_FF_MAX) -#define VERT_BIT_TEX(i) VERT_BIT(VERT_ATTRIB_TEX(i)) -#define VERT_BIT_TEX_ALL \ - BITFIELD64_RANGE(VERT_ATTRIB_TEX(0), VERT_ATTRIB_TEX_MAX) - -#define VERT_BIT_GENERIC(i) VERT_BIT(VERT_ATTRIB_GENERIC(i)) -#define VERT_BIT_GENERIC_ALL \ - BITFIELD64_RANGE(VERT_ATTRIB_GENERIC(0), VERT_ATTRIB_GENERIC_MAX) -/*@}*/ - - #define VARYING_SLOT_MAX (VARYING_SLOT_VAR0 + MAX_VARYING) #define VARYING_SLOT_PATCH0 (VARYING_SLOT_MAX) #define VARYING_SLOT_TESS_MAX (VARYING_SLOT_PATCH0 + MAX_VARYING) From f4608bc530e61b7dbc8ebe7eff6ddbc70ac20a9d Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 31 Aug 2015 15:34:56 -0700 Subject: [PATCH 52/55] nir/nir_variable: Add a descriptor set field We need this for SPIR-V --- src/glsl/nir/nir.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h index 2ad739523ba..4c60dbd645a 100644 --- a/src/glsl/nir/nir.h +++ b/src/glsl/nir/nir.h @@ -296,6 +296,11 @@ typedef struct { */ int index; + /** + * Descriptor set binding for sampler or UBO. + */ + int descriptor_set; + /** * Initial binding point for a sampler or UBO. * From 24b0c532319b9318e6e5794978c7e1c05e81d76e Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 31 Aug 2015 15:54:21 -0700 Subject: [PATCH 53/55] nir/intrinsics: Move to a two-dimensional binding model for UBO's --- src/glsl/nir/nir_intrinsics.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/glsl/nir/nir_intrinsics.h b/src/glsl/nir/nir_intrinsics.h index ed309b602c2..1f24f9f677d 100644 --- a/src/glsl/nir/nir_intrinsics.h +++ b/src/glsl/nir/nir_intrinsics.h @@ -145,8 +145,9 @@ SYSTEM_VALUE(invocation_id, 1) * the first index is the base address and the second index is an offset that * should be added to the base address. (This way you can determine in the * back-end which variable is being accessed even in an array.) For inputs, - * the one and only index corresponds to the attribute slot. UBO loads also - * have a single index which is the base address to load from. + * the one and only index corresponds to the attribute slot. UBO loads + * have two indices the first of which is the descriptor set and the second + * is the base address to load from. * * UBO loads have a (possibly constant) source which is the UBO buffer index. * For each type of load, the _indirect variant has one additional source @@ -165,7 +166,7 @@ SYSTEM_VALUE(invocation_id, 1) true, 0, 0, indices, flags) LOAD(uniform, 0, 2, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) -LOAD(ubo, 1, 1, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) +LOAD(ubo, 1, 2, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) LOAD(input, 0, 1, NIR_INTRINSIC_CAN_ELIMINATE | NIR_INTRINSIC_CAN_REORDER) /* LOAD(ssbo, 1, 0) */ From ce70cae7562c7651a7fb907b4bd2f6924a00b40c Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 31 Aug 2015 16:54:02 -0700 Subject: [PATCH 54/55] nir/builder: Use nir_after_instr to advance the cursor This *should* ensure that the cursor gets properly advanced in all cases. We had a problem before where, if the cursor was created using nir_after_cf_node on a non-block cf_node, that would call nir_before_block on the block following the cf node. Instructions would then get inserted in backwards order at the top of the block which is not at all what you would expect from nir_after_cf_node. By just resetting to after_instr, we avoid all these problems. --- src/glsl/nir/nir_builder.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/glsl/nir/nir_builder.h b/src/glsl/nir/nir_builder.h index 3aa0efded3c..295a209b4e6 100644 --- a/src/glsl/nir/nir_builder.h +++ b/src/glsl/nir/nir_builder.h @@ -49,8 +49,7 @@ nir_builder_instr_insert(nir_builder *build, nir_instr *instr) nir_instr_insert(build->cursor, instr); /* Move the cursor forward. */ - if (build->cursor.option == nir_cursor_after_instr) - build->cursor.instr = instr; + build->cursor = nir_after_instr(instr); } static inline void From 22fdb2f8551330fea308ce9cfe151ec00201e2b1 Mon Sep 17 00:00:00 2001 From: Jason Ekstrand Date: Mon, 31 Aug 2015 12:48:04 -0700 Subject: [PATCH 55/55] nir/spirv: Update to the latest revision --- src/glsl/nir/nir_spirv.h | 8 + src/glsl/nir/spirv.h | 1484 +++++++------------- src/glsl/nir/spirv_glsl450_to_nir.c | 27 +- src/glsl/nir/spirv_to_nir.c | 2018 ++++++++++++++++++++++----- src/glsl/nir/spirv_to_nir_private.h | 89 +- 5 files changed, 2313 insertions(+), 1313 deletions(-) diff --git a/src/glsl/nir/nir_spirv.h b/src/glsl/nir/nir_spirv.h index 5f4140db3d9..1f09174ad7f 100644 --- a/src/glsl/nir/nir_spirv.h +++ b/src/glsl/nir/nir_spirv.h @@ -32,8 +32,16 @@ #include "nir.h" +#ifdef __cplusplus +extern "C" { +#endif + nir_shader *spirv_to_nir(const uint32_t *words, size_t word_count, gl_shader_stage stage, const nir_shader_compiler_options *options); +#ifdef __cplusplus +} +#endif + #endif /* _NIR_SPIRV_H_ */ diff --git a/src/glsl/nir/spirv.h b/src/glsl/nir/spirv.h index da717ecd342..d289c687c76 100644 --- a/src/glsl/nir/spirv.h +++ b/src/glsl/nir/spirv.h @@ -1,5 +1,5 @@ /* -** Copyright (c) 2015 The Khronos Group Inc. +** Copyright (c) 2014-2015 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"), @@ -30,10 +30,15 @@ */ /* -** Specification revision 30. -** Enumeration tokens for SPIR-V, in three styles: C, C++, generic. -** - C++ will have the tokens in the "spv" name space, with no prefix. -** - C will have tokens with as "Spv" prefix. +** Specification revision 31. +** Enumeration tokens for SPIR-V, in various styles: +** C, C++, C++11, JSON, Lua, Python +** +** - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL +** - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL +** - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL +** - Lua will use tables, e.g.: spv.SourceLanguage.GLSL +** - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] ** ** Some tokens act like mask values, which can be OR'd together, ** while others are mutually exclusive. The mask-like ones have @@ -44,645 +49,12 @@ #ifndef spirv_H #define spirv_H -#ifdef __cplusplus - -namespace spv { - -static const int MagicNumber = 0x07230203; -static const int Version = 99; - -typedef unsigned int Id; - -static const unsigned int OpCodeMask = 0xFFFF; -static const unsigned int WordCountShift = 16; - -enum SourceLanguage { - SourceLanguageUnknown = 0, - SourceLanguageESSL = 1, - SourceLanguageGLSL = 2, - SourceLanguageOpenCL = 3, -}; - -enum ExecutionModel { - ExecutionModelVertex = 0, - ExecutionModelTessellationControl = 1, - ExecutionModelTessellationEvaluation = 2, - ExecutionModelGeometry = 3, - ExecutionModelFragment = 4, - ExecutionModelGLCompute = 5, - ExecutionModelKernel = 6, -}; - -enum AddressingModel { - AddressingModelLogical = 0, - AddressingModelPhysical32 = 1, - AddressingModelPhysical64 = 2, -}; - -enum MemoryModel { - MemoryModelSimple = 0, - MemoryModelGLSL450 = 1, - MemoryModelOpenCL12 = 2, - MemoryModelOpenCL20 = 3, - MemoryModelOpenCL21 = 4, -}; - -enum ExecutionMode { - ExecutionModeInvocations = 0, - ExecutionModeSpacingEqual = 1, - ExecutionModeSpacingFractionalEven = 2, - ExecutionModeSpacingFractionalOdd = 3, - ExecutionModeVertexOrderCw = 4, - ExecutionModeVertexOrderCcw = 5, - ExecutionModePixelCenterInteger = 6, - ExecutionModeOriginUpperLeft = 7, - ExecutionModeEarlyFragmentTests = 8, - ExecutionModePointMode = 9, - ExecutionModeXfb = 10, - ExecutionModeDepthReplacing = 11, - ExecutionModeDepthAny = 12, - ExecutionModeDepthGreater = 13, - ExecutionModeDepthLess = 14, - ExecutionModeDepthUnchanged = 15, - ExecutionModeLocalSize = 16, - ExecutionModeLocalSizeHint = 17, - ExecutionModeInputPoints = 18, - ExecutionModeInputLines = 19, - ExecutionModeInputLinesAdjacency = 20, - ExecutionModeInputTriangles = 21, - ExecutionModeInputTrianglesAdjacency = 22, - ExecutionModeInputQuads = 23, - ExecutionModeInputIsolines = 24, - ExecutionModeOutputVertices = 25, - ExecutionModeOutputPoints = 26, - ExecutionModeOutputLineStrip = 27, - ExecutionModeOutputTriangleStrip = 28, - ExecutionModeVecTypeHint = 29, - ExecutionModeContractionOff = 30, -}; - -enum StorageClass { - StorageClassUniformConstant = 0, - StorageClassInput = 1, - StorageClassUniform = 2, - StorageClassOutput = 3, - StorageClassWorkgroupLocal = 4, - StorageClassWorkgroupGlobal = 5, - StorageClassPrivateGlobal = 6, - StorageClassFunction = 7, - StorageClassGeneric = 8, - StorageClassPrivate = 9, - StorageClassAtomicCounter = 10, -}; - -enum Dim { - Dim1D = 0, - Dim2D = 1, - Dim3D = 2, - DimCube = 3, - DimRect = 4, - DimBuffer = 5, -}; - -enum SamplerAddressingMode { - SamplerAddressingModeNone = 0, - SamplerAddressingModeClampToEdge = 1, - SamplerAddressingModeClamp = 2, - SamplerAddressingModeRepeat = 3, - SamplerAddressingModeRepeatMirrored = 4, -}; - -enum SamplerFilterMode { - SamplerFilterModeNearest = 0, - SamplerFilterModeLinear = 1, -}; - -enum FPFastMathModeShift { - FPFastMathModeNotNaNShift = 0, - FPFastMathModeNotInfShift = 1, - FPFastMathModeNSZShift = 2, - FPFastMathModeAllowRecipShift = 3, - FPFastMathModeFastShift = 4, -}; - -enum FPFastMathModeMask { - FPFastMathModeMaskNone = 0, - FPFastMathModeNotNaNMask = 0x00000001, - FPFastMathModeNotInfMask = 0x00000002, - FPFastMathModeNSZMask = 0x00000004, - FPFastMathModeAllowRecipMask = 0x00000008, - FPFastMathModeFastMask = 0x00000010, -}; - -enum FPRoundingMode { - FPRoundingModeRTE = 0, - FPRoundingModeRTZ = 1, - FPRoundingModeRTP = 2, - FPRoundingModeRTN = 3, -}; - -enum LinkageType { - LinkageTypeExport = 0, - LinkageTypeImport = 1, -}; - -enum AccessQualifier { - AccessQualifierReadOnly = 0, - AccessQualifierWriteOnly = 1, - AccessQualifierReadWrite = 2, -}; - -enum FunctionParameterAttribute { - FunctionParameterAttributeZext = 0, - FunctionParameterAttributeSext = 1, - FunctionParameterAttributeByVal = 2, - FunctionParameterAttributeSret = 3, - FunctionParameterAttributeNoAlias = 4, - FunctionParameterAttributeNoCapture = 5, - FunctionParameterAttributeSVM = 6, - FunctionParameterAttributeNoWrite = 7, - FunctionParameterAttributeNoReadWrite = 8, -}; - -enum Decoration { - DecorationPrecisionLow = 0, - DecorationPrecisionMedium = 1, - DecorationPrecisionHigh = 2, - DecorationBlock = 3, - DecorationBufferBlock = 4, - DecorationRowMajor = 5, - DecorationColMajor = 6, - DecorationGLSLShared = 7, - DecorationGLSLStd140 = 8, - DecorationGLSLStd430 = 9, - DecorationGLSLPacked = 10, - DecorationSmooth = 11, - DecorationNoperspective = 12, - DecorationFlat = 13, - DecorationPatch = 14, - DecorationCentroid = 15, - DecorationSample = 16, - DecorationInvariant = 17, - DecorationRestrict = 18, - DecorationAliased = 19, - DecorationVolatile = 20, - DecorationConstant = 21, - DecorationCoherent = 22, - DecorationNonwritable = 23, - DecorationNonreadable = 24, - DecorationUniform = 25, - DecorationNoStaticUse = 26, - DecorationCPacked = 27, - DecorationSaturatedConversion = 28, - DecorationStream = 29, - DecorationLocation = 30, - DecorationComponent = 31, - DecorationIndex = 32, - DecorationBinding = 33, - DecorationDescriptorSet = 34, - DecorationOffset = 35, - DecorationAlignment = 36, - DecorationXfbBuffer = 37, - DecorationStride = 38, - DecorationBuiltIn = 39, - DecorationFuncParamAttr = 40, - DecorationFPRoundingMode = 41, - DecorationFPFastMathMode = 42, - DecorationLinkageAttributes = 43, - DecorationSpecId = 44, -}; - -enum BuiltIn { - BuiltInPosition = 0, - BuiltInPointSize = 1, - BuiltInClipVertex = 2, - BuiltInClipDistance = 3, - BuiltInCullDistance = 4, - BuiltInVertexId = 5, - BuiltInInstanceId = 6, - BuiltInPrimitiveId = 7, - BuiltInInvocationId = 8, - BuiltInLayer = 9, - BuiltInViewportIndex = 10, - BuiltInTessLevelOuter = 11, - BuiltInTessLevelInner = 12, - BuiltInTessCoord = 13, - BuiltInPatchVertices = 14, - BuiltInFragCoord = 15, - BuiltInPointCoord = 16, - BuiltInFrontFacing = 17, - BuiltInSampleId = 18, - BuiltInSamplePosition = 19, - BuiltInSampleMask = 20, - BuiltInFragColor = 21, - BuiltInFragDepth = 22, - BuiltInHelperInvocation = 23, - BuiltInNumWorkgroups = 24, - BuiltInWorkgroupSize = 25, - BuiltInWorkgroupId = 26, - BuiltInLocalInvocationId = 27, - BuiltInGlobalInvocationId = 28, - BuiltInLocalInvocationIndex = 29, - BuiltInWorkDim = 30, - BuiltInGlobalSize = 31, - BuiltInEnqueuedWorkgroupSize = 32, - BuiltInGlobalOffset = 33, - BuiltInGlobalLinearId = 34, - BuiltInWorkgroupLinearId = 35, - BuiltInSubgroupSize = 36, - BuiltInSubgroupMaxSize = 37, - BuiltInNumSubgroups = 38, - BuiltInNumEnqueuedSubgroups = 39, - BuiltInSubgroupId = 40, - BuiltInSubgroupLocalInvocationId = 41, -}; - -enum SelectionControlShift { - SelectionControlFlattenShift = 0, - SelectionControlDontFlattenShift = 1, -}; - -enum SelectionControlMask { - SelectionControlMaskNone = 0, - SelectionControlFlattenMask = 0x00000001, - SelectionControlDontFlattenMask = 0x00000002, -}; - -enum LoopControlShift { - LoopControlUnrollShift = 0, - LoopControlDontUnrollShift = 1, -}; - -enum LoopControlMask { - LoopControlMaskNone = 0, - LoopControlUnrollMask = 0x00000001, - LoopControlDontUnrollMask = 0x00000002, -}; - -enum FunctionControlShift { - FunctionControlInlineShift = 0, - FunctionControlDontInlineShift = 1, - FunctionControlPureShift = 2, - FunctionControlConstShift = 3, -}; - -enum FunctionControlMask { - FunctionControlMaskNone = 0, - FunctionControlInlineMask = 0x00000001, - FunctionControlDontInlineMask = 0x00000002, - FunctionControlPureMask = 0x00000004, - FunctionControlConstMask = 0x00000008, -}; - -enum MemorySemanticsShift { - MemorySemanticsRelaxedShift = 0, - MemorySemanticsSequentiallyConsistentShift = 1, - MemorySemanticsAcquireShift = 2, - MemorySemanticsReleaseShift = 3, - MemorySemanticsUniformMemoryShift = 4, - MemorySemanticsSubgroupMemoryShift = 5, - MemorySemanticsWorkgroupLocalMemoryShift = 6, - MemorySemanticsWorkgroupGlobalMemoryShift = 7, - MemorySemanticsAtomicCounterMemoryShift = 8, - MemorySemanticsImageMemoryShift = 9, -}; - -enum MemorySemanticsMask { - MemorySemanticsMaskNone = 0, - MemorySemanticsRelaxedMask = 0x00000001, - MemorySemanticsSequentiallyConsistentMask = 0x00000002, - MemorySemanticsAcquireMask = 0x00000004, - MemorySemanticsReleaseMask = 0x00000008, - MemorySemanticsUniformMemoryMask = 0x00000010, - MemorySemanticsSubgroupMemoryMask = 0x00000020, - MemorySemanticsWorkgroupLocalMemoryMask = 0x00000040, - MemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080, - MemorySemanticsAtomicCounterMemoryMask = 0x00000100, - MemorySemanticsImageMemoryMask = 0x00000200, -}; - -enum MemoryAccessShift { - MemoryAccessVolatileShift = 0, - MemoryAccessAlignedShift = 1, -}; - -enum MemoryAccessMask { - MemoryAccessMaskNone = 0, - MemoryAccessVolatileMask = 0x00000001, - MemoryAccessAlignedMask = 0x00000002, -}; - -enum ExecutionScope { - ExecutionScopeCrossDevice = 0, - ExecutionScopeDevice = 1, - ExecutionScopeWorkgroup = 2, - ExecutionScopeSubgroup = 3, -}; - -enum GroupOperation { - GroupOperationReduce = 0, - GroupOperationInclusiveScan = 1, - GroupOperationExclusiveScan = 2, -}; - -enum KernelEnqueueFlags { - KernelEnqueueFlagsNoWait = 0, - KernelEnqueueFlagsWaitKernel = 1, - KernelEnqueueFlagsWaitWorkGroup = 2, -}; - -enum KernelProfilingInfoShift { - KernelProfilingInfoCmdExecTimeShift = 0, -}; - -enum KernelProfilingInfoMask { - KernelProfilingInfoMaskNone = 0, - KernelProfilingInfoCmdExecTimeMask = 0x00000001, -}; - -enum Op { - OpNop = 0, - OpSource = 1, - OpSourceExtension = 2, - OpExtension = 3, - OpExtInstImport = 4, - OpMemoryModel = 5, - OpEntryPoint = 6, - OpExecutionMode = 7, - OpTypeVoid = 8, - OpTypeBool = 9, - OpTypeInt = 10, - OpTypeFloat = 11, - OpTypeVector = 12, - OpTypeMatrix = 13, - OpTypeSampler = 14, - OpTypeFilter = 15, - OpTypeArray = 16, - OpTypeRuntimeArray = 17, - OpTypeStruct = 18, - OpTypeOpaque = 19, - OpTypePointer = 20, - OpTypeFunction = 21, - OpTypeEvent = 22, - OpTypeDeviceEvent = 23, - OpTypeReserveId = 24, - OpTypeQueue = 25, - OpTypePipe = 26, - OpConstantTrue = 27, - OpConstantFalse = 28, - OpConstant = 29, - OpConstantComposite = 30, - OpConstantSampler = 31, - OpConstantNullPointer = 32, - OpConstantNullObject = 33, - OpSpecConstantTrue = 34, - OpSpecConstantFalse = 35, - OpSpecConstant = 36, - OpSpecConstantComposite = 37, - OpVariable = 38, - OpVariableArray = 39, - OpFunction = 40, - OpFunctionParameter = 41, - OpFunctionEnd = 42, - OpFunctionCall = 43, - OpExtInst = 44, - OpUndef = 45, - OpLoad = 46, - OpStore = 47, - OpPhi = 48, - OpDecorationGroup = 49, - OpDecorate = 50, - OpMemberDecorate = 51, - OpGroupDecorate = 52, - OpGroupMemberDecorate = 53, - OpName = 54, - OpMemberName = 55, - OpString = 56, - OpLine = 57, - OpVectorExtractDynamic = 58, - OpVectorInsertDynamic = 59, - OpVectorShuffle = 60, - OpCompositeConstruct = 61, - OpCompositeExtract = 62, - OpCompositeInsert = 63, - OpCopyObject = 64, - OpCopyMemory = 65, - OpCopyMemorySized = 66, - OpSampler = 67, - OpTextureSample = 68, - OpTextureSampleDref = 69, - OpTextureSampleLod = 70, - OpTextureSampleProj = 71, - OpTextureSampleGrad = 72, - OpTextureSampleOffset = 73, - OpTextureSampleProjLod = 74, - OpTextureSampleProjGrad = 75, - OpTextureSampleLodOffset = 76, - OpTextureSampleProjOffset = 77, - OpTextureSampleGradOffset = 78, - OpTextureSampleProjLodOffset = 79, - OpTextureSampleProjGradOffset = 80, - OpTextureFetchTexelLod = 81, - OpTextureFetchTexelOffset = 82, - OpTextureFetchSample = 83, - OpTextureFetchTexel = 84, - OpTextureGather = 85, - OpTextureGatherOffset = 86, - OpTextureGatherOffsets = 87, - OpTextureQuerySizeLod = 88, - OpTextureQuerySize = 89, - OpTextureQueryLod = 90, - OpTextureQueryLevels = 91, - OpTextureQuerySamples = 92, - OpAccessChain = 93, - OpInBoundsAccessChain = 94, - OpSNegate = 95, - OpFNegate = 96, - OpNot = 97, - OpAny = 98, - OpAll = 99, - OpConvertFToU = 100, - OpConvertFToS = 101, - OpConvertSToF = 102, - OpConvertUToF = 103, - OpUConvert = 104, - OpSConvert = 105, - OpFConvert = 106, - OpConvertPtrToU = 107, - OpConvertUToPtr = 108, - OpPtrCastToGeneric = 109, - OpGenericCastToPtr = 110, - OpBitcast = 111, - OpTranspose = 112, - OpIsNan = 113, - OpIsInf = 114, - OpIsFinite = 115, - OpIsNormal = 116, - OpSignBitSet = 117, - OpLessOrGreater = 118, - OpOrdered = 119, - OpUnordered = 120, - OpArrayLength = 121, - OpIAdd = 122, - OpFAdd = 123, - OpISub = 124, - OpFSub = 125, - OpIMul = 126, - OpFMul = 127, - OpUDiv = 128, - OpSDiv = 129, - OpFDiv = 130, - OpUMod = 131, - OpSRem = 132, - OpSMod = 133, - OpFRem = 134, - OpFMod = 135, - OpVectorTimesScalar = 136, - OpMatrixTimesScalar = 137, - OpVectorTimesMatrix = 138, - OpMatrixTimesVector = 139, - OpMatrixTimesMatrix = 140, - OpOuterProduct = 141, - OpDot = 142, - OpShiftRightLogical = 143, - OpShiftRightArithmetic = 144, - OpShiftLeftLogical = 145, - OpLogicalOr = 146, - OpLogicalXor = 147, - OpLogicalAnd = 148, - OpBitwiseOr = 149, - OpBitwiseXor = 150, - OpBitwiseAnd = 151, - OpSelect = 152, - OpIEqual = 153, - OpFOrdEqual = 154, - OpFUnordEqual = 155, - OpINotEqual = 156, - OpFOrdNotEqual = 157, - OpFUnordNotEqual = 158, - OpULessThan = 159, - OpSLessThan = 160, - OpFOrdLessThan = 161, - OpFUnordLessThan = 162, - OpUGreaterThan = 163, - OpSGreaterThan = 164, - OpFOrdGreaterThan = 165, - OpFUnordGreaterThan = 166, - OpULessThanEqual = 167, - OpSLessThanEqual = 168, - OpFOrdLessThanEqual = 169, - OpFUnordLessThanEqual = 170, - OpUGreaterThanEqual = 171, - OpSGreaterThanEqual = 172, - OpFOrdGreaterThanEqual = 173, - OpFUnordGreaterThanEqual = 174, - OpDPdx = 175, - OpDPdy = 176, - OpFwidth = 177, - OpDPdxFine = 178, - OpDPdyFine = 179, - OpFwidthFine = 180, - OpDPdxCoarse = 181, - OpDPdyCoarse = 182, - OpFwidthCoarse = 183, - OpEmitVertex = 184, - OpEndPrimitive = 185, - OpEmitStreamVertex = 186, - OpEndStreamPrimitive = 187, - OpControlBarrier = 188, - OpMemoryBarrier = 189, - OpImagePointer = 190, - OpAtomicInit = 191, - OpAtomicLoad = 192, - OpAtomicStore = 193, - OpAtomicExchange = 194, - OpAtomicCompareExchange = 195, - OpAtomicCompareExchangeWeak = 196, - OpAtomicIIncrement = 197, - OpAtomicIDecrement = 198, - OpAtomicIAdd = 199, - OpAtomicISub = 200, - OpAtomicUMin = 201, - OpAtomicUMax = 202, - OpAtomicAnd = 203, - OpAtomicOr = 204, - OpAtomicXor = 205, - OpLoopMerge = 206, - OpSelectionMerge = 207, - OpLabel = 208, - OpBranch = 209, - OpBranchConditional = 210, - OpSwitch = 211, - OpKill = 212, - OpReturn = 213, - OpReturnValue = 214, - OpUnreachable = 215, - OpLifetimeStart = 216, - OpLifetimeStop = 217, - OpCompileFlag = 218, - OpAsyncGroupCopy = 219, - OpWaitGroupEvents = 220, - OpGroupAll = 221, - OpGroupAny = 222, - OpGroupBroadcast = 223, - OpGroupIAdd = 224, - OpGroupFAdd = 225, - OpGroupFMin = 226, - OpGroupUMin = 227, - OpGroupSMin = 228, - OpGroupFMax = 229, - OpGroupUMax = 230, - OpGroupSMax = 231, - OpGenericCastToPtrExplicit = 232, - OpGenericPtrMemSemantics = 233, - OpReadPipe = 234, - OpWritePipe = 235, - OpReservedReadPipe = 236, - OpReservedWritePipe = 237, - OpReserveReadPipePackets = 238, - OpReserveWritePipePackets = 239, - OpCommitReadPipe = 240, - OpCommitWritePipe = 241, - OpIsValidReserveId = 242, - OpGetNumPipePackets = 243, - OpGetMaxPipePackets = 244, - OpGroupReserveReadPipePackets = 245, - OpGroupReserveWritePipePackets = 246, - OpGroupCommitReadPipe = 247, - OpGroupCommitWritePipe = 248, - OpEnqueueMarker = 249, - OpEnqueueKernel = 250, - OpGetKernelNDrangeSubGroupCount = 251, - OpGetKernelNDrangeMaxSubGroupSize = 252, - OpGetKernelWorkGroupSize = 253, - OpGetKernelPreferredWorkGroupSizeMultiple = 254, - OpRetainEvent = 255, - OpReleaseEvent = 256, - OpCreateUserEvent = 257, - OpIsValidEvent = 258, - OpSetUserEventStatus = 259, - OpCaptureEventProfilingInfo = 260, - OpGetDefaultQueue = 261, - OpBuildNDRange = 262, - OpSatConvertSToU = 263, - OpSatConvertUToS = 264, - OpAtomicIMin = 265, - OpAtomicIMax = 266, -}; - -}; // end namespace spv - -#endif // #ifdef __cplusplus - - -#ifndef __cplusplus - -static const int SpvMagicNumber = 0x07230203; -static const int SpvVersion = 99; - typedef unsigned int SpvId; -static const unsigned int SpvOpCodeMask = 0xFFFF; +static const unsigned int SpvMagicNumber = 0x07230203; +static const unsigned int SpvVersion = 99; +static const unsigned int SpvRevision = 31; +static const unsigned int SpvOpCodeMask = 0xffff; static const unsigned int SpvWordCountShift = 16; typedef enum SpvSourceLanguage_ { @@ -711,9 +83,7 @@ typedef enum SpvAddressingModel_ { typedef enum SpvMemoryModel_ { SpvMemoryModelSimple = 0, SpvMemoryModelGLSL450 = 1, - SpvMemoryModelOpenCL12 = 2, - SpvMemoryModelOpenCL20 = 3, - SpvMemoryModelOpenCL21 = 4, + SpvMemoryModelOpenCL = 2, } SpvMemoryModel; typedef enum SpvExecutionMode_ { @@ -725,29 +95,30 @@ typedef enum SpvExecutionMode_ { SpvExecutionModeVertexOrderCcw = 5, SpvExecutionModePixelCenterInteger = 6, SpvExecutionModeOriginUpperLeft = 7, - SpvExecutionModeEarlyFragmentTests = 8, - SpvExecutionModePointMode = 9, - SpvExecutionModeXfb = 10, - SpvExecutionModeDepthReplacing = 11, - SpvExecutionModeDepthAny = 12, - SpvExecutionModeDepthGreater = 13, - SpvExecutionModeDepthLess = 14, - SpvExecutionModeDepthUnchanged = 15, - SpvExecutionModeLocalSize = 16, - SpvExecutionModeLocalSizeHint = 17, - SpvExecutionModeInputPoints = 18, - SpvExecutionModeInputLines = 19, - SpvExecutionModeInputLinesAdjacency = 20, - SpvExecutionModeInputTriangles = 21, - SpvExecutionModeInputTrianglesAdjacency = 22, - SpvExecutionModeInputQuads = 23, - SpvExecutionModeInputIsolines = 24, - SpvExecutionModeOutputVertices = 25, - SpvExecutionModeOutputPoints = 26, - SpvExecutionModeOutputLineStrip = 27, - SpvExecutionModeOutputTriangleStrip = 28, - SpvExecutionModeVecTypeHint = 29, - SpvExecutionModeContractionOff = 30, + SpvExecutionModeOriginLowerLeft = 8, + SpvExecutionModeEarlyFragmentTests = 9, + SpvExecutionModePointMode = 10, + SpvExecutionModeXfb = 11, + SpvExecutionModeDepthReplacing = 12, + SpvExecutionModeDepthAny = 13, + SpvExecutionModeDepthGreater = 14, + SpvExecutionModeDepthLess = 15, + SpvExecutionModeDepthUnchanged = 16, + SpvExecutionModeLocalSize = 17, + SpvExecutionModeLocalSizeHint = 18, + SpvExecutionModeInputPoints = 19, + SpvExecutionModeInputLines = 20, + SpvExecutionModeInputLinesAdjacency = 21, + SpvExecutionModeInputTriangles = 22, + SpvExecutionModeInputTrianglesAdjacency = 23, + SpvExecutionModeInputQuads = 24, + SpvExecutionModeInputIsolines = 25, + SpvExecutionModeOutputVertices = 26, + SpvExecutionModeOutputPoints = 27, + SpvExecutionModeOutputLineStrip = 28, + SpvExecutionModeOutputTriangleStrip = 29, + SpvExecutionModeVecTypeHint = 30, + SpvExecutionModeContractionOff = 31, } SpvExecutionMode; typedef enum SpvStorageClass_ { @@ -760,8 +131,8 @@ typedef enum SpvStorageClass_ { SpvStorageClassPrivateGlobal = 6, SpvStorageClassFunction = 7, SpvStorageClassGeneric = 8, - SpvStorageClassPrivate = 9, SpvStorageClassAtomicCounter = 10, + SpvStorageClassImage = 11, } SpvStorageClass; typedef enum SpvDim_ { @@ -786,6 +157,111 @@ typedef enum SpvSamplerFilterMode_ { SpvSamplerFilterModeLinear = 1, } SpvSamplerFilterMode; +typedef enum SpvImageFormat_ { + SpvImageFormatUnknown = 0, + SpvImageFormatRgba32f = 1, + SpvImageFormatRgba16f = 2, + SpvImageFormatR32f = 3, + SpvImageFormatRgba8 = 4, + SpvImageFormatRgba8Snorm = 5, + SpvImageFormatRg32f = 6, + SpvImageFormatRg16f = 7, + SpvImageFormatR11fG11fB10f = 8, + SpvImageFormatR16f = 9, + SpvImageFormatRgba16 = 10, + SpvImageFormatRgb10A2 = 11, + SpvImageFormatRg16 = 12, + SpvImageFormatRg8 = 13, + SpvImageFormatR16 = 14, + SpvImageFormatR8 = 15, + SpvImageFormatRgba16Snorm = 16, + SpvImageFormatRg16Snorm = 17, + SpvImageFormatRg8Snorm = 18, + SpvImageFormatR16Snorm = 19, + SpvImageFormatR8Snorm = 20, + SpvImageFormatRgba32i = 21, + SpvImageFormatRgba16i = 22, + SpvImageFormatRgba8i = 23, + SpvImageFormatR32i = 24, + SpvImageFormatRg32i = 25, + SpvImageFormatRg16i = 26, + SpvImageFormatRg8i = 27, + SpvImageFormatR16i = 28, + SpvImageFormatR8i = 29, + SpvImageFormatRgba32ui = 30, + SpvImageFormatRgba16ui = 31, + SpvImageFormatRgba8ui = 32, + SpvImageFormatR32ui = 33, + SpvImageFormatRgb10a2ui = 34, + SpvImageFormatRg32ui = 35, + SpvImageFormatRg16ui = 36, + SpvImageFormatRg8ui = 37, + SpvImageFormatR16ui = 38, + SpvImageFormatR8ui = 39, +} SpvImageFormat; + +typedef enum SpvImageChannelOrder_ { + SpvImageChannelOrderR = 0, + SpvImageChannelOrderA = 1, + SpvImageChannelOrderRG = 2, + SpvImageChannelOrderRA = 3, + SpvImageChannelOrderRGB = 4, + SpvImageChannelOrderRGBA = 5, + SpvImageChannelOrderBGRA = 6, + SpvImageChannelOrderARGB = 7, + SpvImageChannelOrderIntensity = 8, + SpvImageChannelOrderLuminance = 9, + SpvImageChannelOrderRx = 10, + SpvImageChannelOrderRGx = 11, + SpvImageChannelOrderRGBx = 12, + SpvImageChannelOrderDepth = 13, + SpvImageChannelOrderDepthStencil = 14, + SpvImageChannelOrdersRGB = 15, + SpvImageChannelOrdersRGBx = 16, + SpvImageChannelOrdersRGBA = 17, + SpvImageChannelOrdersBGRA = 18, +} SpvImageChannelOrder; + +typedef enum SpvImageChannelDataType_ { + SpvImageChannelDataTypeSnormInt8 = 0, + SpvImageChannelDataTypeSnormInt16 = 1, + SpvImageChannelDataTypeUnormInt8 = 2, + SpvImageChannelDataTypeUnormInt16 = 3, + SpvImageChannelDataTypeUnormShort565 = 4, + SpvImageChannelDataTypeUnormShort555 = 5, + SpvImageChannelDataTypeUnormInt101010 = 6, + SpvImageChannelDataTypeSignedInt8 = 7, + SpvImageChannelDataTypeSignedInt16 = 8, + SpvImageChannelDataTypeSignedInt32 = 9, + SpvImageChannelDataTypeUnsignedInt8 = 10, + SpvImageChannelDataTypeUnsignedInt16 = 11, + SpvImageChannelDataTypeUnsignedInt32 = 12, + SpvImageChannelDataTypeHalfFloat = 13, + SpvImageChannelDataTypeFloat = 14, + SpvImageChannelDataTypeUnormInt24 = 15, +} SpvImageChannelDataType; + +typedef enum SpvImageOperandsShift_ { + SpvImageOperandsBiasShift = 0, + SpvImageOperandsLodShift = 1, + SpvImageOperandsGradShift = 2, + SpvImageOperandsConstOffsetShift = 3, + SpvImageOperandsOffsetShift = 4, + SpvImageOperandsConstOffsetsShift = 5, + SpvImageOperandsSampleShift = 6, +} SpvImageOperandsShift; + +typedef enum SpvImageOperandsMask_ { + SpvImageOperandsMaskNone = 0, + SpvImageOperandsBiasMask = 0x00000001, + SpvImageOperandsLodMask = 0x00000002, + SpvImageOperandsGradMask = 0x00000004, + SpvImageOperandsConstOffsetMask = 0x00000008, + SpvImageOperandsOffsetMask = 0x00000010, + SpvImageOperandsConstOffsetsMask = 0x00000020, + SpvImageOperandsSampleMask = 0x00000040, +} SpvImageOperandsMask; + typedef enum SpvFPFastMathModeShift_ { SpvFPFastMathModeNotNaNShift = 0, SpvFPFastMathModeNotInfShift = 1, @@ -828,40 +304,39 @@ typedef enum SpvFunctionParameterAttribute_ { SpvFunctionParameterAttributeSret = 3, SpvFunctionParameterAttributeNoAlias = 4, SpvFunctionParameterAttributeNoCapture = 5, - SpvFunctionParameterAttributeSVM = 6, - SpvFunctionParameterAttributeNoWrite = 7, - SpvFunctionParameterAttributeNoReadWrite = 8, + SpvFunctionParameterAttributeNoWrite = 6, + SpvFunctionParameterAttributeNoReadWrite = 7, } SpvFunctionParameterAttribute; typedef enum SpvDecoration_ { - SpvDecorationPrecisionLow = 0, - SpvDecorationPrecisionMedium = 1, - SpvDecorationPrecisionHigh = 2, - SpvDecorationBlock = 3, - SpvDecorationBufferBlock = 4, - SpvDecorationRowMajor = 5, - SpvDecorationColMajor = 6, - SpvDecorationGLSLShared = 7, - SpvDecorationGLSLStd140 = 8, - SpvDecorationGLSLStd430 = 9, - SpvDecorationGLSLPacked = 10, - SpvDecorationSmooth = 11, - SpvDecorationNoperspective = 12, - SpvDecorationFlat = 13, - SpvDecorationPatch = 14, - SpvDecorationCentroid = 15, - SpvDecorationSample = 16, - SpvDecorationInvariant = 17, - SpvDecorationRestrict = 18, - SpvDecorationAliased = 19, - SpvDecorationVolatile = 20, - SpvDecorationConstant = 21, - SpvDecorationCoherent = 22, - SpvDecorationNonwritable = 23, - SpvDecorationNonreadable = 24, - SpvDecorationUniform = 25, - SpvDecorationNoStaticUse = 26, - SpvDecorationCPacked = 27, + SpvDecorationRelaxedPrecision = 0, + SpvDecorationSpecId = 1, + SpvDecorationBlock = 2, + SpvDecorationBufferBlock = 3, + SpvDecorationRowMajor = 4, + SpvDecorationColMajor = 5, + SpvDecorationArrayStride = 6, + SpvDecorationMatrixStride = 7, + SpvDecorationGLSLShared = 8, + SpvDecorationGLSLPacked = 9, + SpvDecorationCPacked = 10, + SpvDecorationBuiltIn = 11, + SpvDecorationSmooth = 12, + SpvDecorationNoperspective = 13, + SpvDecorationFlat = 14, + SpvDecorationPatch = 15, + SpvDecorationCentroid = 16, + SpvDecorationSample = 17, + SpvDecorationInvariant = 18, + SpvDecorationRestrict = 19, + SpvDecorationAliased = 20, + SpvDecorationVolatile = 21, + SpvDecorationConstant = 22, + SpvDecorationCoherent = 23, + SpvDecorationNonwritable = 24, + SpvDecorationNonreadable = 25, + SpvDecorationUniform = 26, + SpvDecorationNoStaticUse = 27, SpvDecorationSaturatedConversion = 28, SpvDecorationStream = 29, SpvDecorationLocation = 30, @@ -870,21 +345,17 @@ typedef enum SpvDecoration_ { SpvDecorationBinding = 33, SpvDecorationDescriptorSet = 34, SpvDecorationOffset = 35, - SpvDecorationAlignment = 36, - SpvDecorationXfbBuffer = 37, - SpvDecorationStride = 38, - SpvDecorationBuiltIn = 39, - SpvDecorationFuncParamAttr = 40, - SpvDecorationFPRoundingMode = 41, - SpvDecorationFPFastMathMode = 42, - SpvDecorationLinkageAttributes = 43, - SpvDecorationSpecId = 44, + SpvDecorationXfbBuffer = 36, + SpvDecorationXfbStride = 37, + SpvDecorationFuncParamAttr = 38, + SpvDecorationFPRoundingMode = 39, + SpvDecorationFPFastMathMode = 40, + SpvDecorationLinkageAttributes = 41, } SpvDecoration; typedef enum SpvBuiltIn_ { SpvBuiltInPosition = 0, SpvBuiltInPointSize = 1, - SpvBuiltInClipVertex = 2, SpvBuiltInClipDistance = 3, SpvBuiltInCullDistance = 4, SpvBuiltInVertexId = 5, @@ -1001,12 +472,13 @@ typedef enum SpvMemoryAccessMask_ { SpvMemoryAccessAlignedMask = 0x00000002, } SpvMemoryAccessMask; -typedef enum SpvExecutionScope_ { - SpvExecutionScopeCrossDevice = 0, - SpvExecutionScopeDevice = 1, - SpvExecutionScopeWorkgroup = 2, - SpvExecutionScopeSubgroup = 3, -} SpvExecutionScope; +typedef enum SpvScope_ { + SpvScopeCrossDevice = 0, + SpvScopeDevice = 1, + SpvScopeWorkgroup = 2, + SpvScopeSubgroup = 3, + SpvScopeInvocation = 4, +} SpvScope; typedef enum SpvGroupOperation_ { SpvGroupOperationReduce = 0, @@ -1029,276 +501,320 @@ typedef enum SpvKernelProfilingInfoMask_ { SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001, } SpvKernelProfilingInfoMask; +typedef enum SpvCapability_ { + SpvCapabilityMatrix = 0, + SpvCapabilityShader = 1, + SpvCapabilityGeometry = 2, + SpvCapabilityTessellation = 3, + SpvCapabilityAddresses = 4, + SpvCapabilityLinkage = 5, + SpvCapabilityKernel = 6, + SpvCapabilityVector16 = 7, + SpvCapabilityFloat16Buffer = 8, + SpvCapabilityFloat16 = 9, + SpvCapabilityFloat64 = 10, + SpvCapabilityInt64 = 11, + SpvCapabilityInt64Atomics = 12, + SpvCapabilityImageBasic = 13, + SpvCapabilityImageReadWrite = 14, + SpvCapabilityImageMipmap = 15, + SpvCapabilityImageSRGBWrite = 16, + SpvCapabilityPipes = 17, + SpvCapabilityGroups = 18, + SpvCapabilityDeviceEnqueue = 19, + SpvCapabilityLiteralSampler = 20, + SpvCapabilityAtomicStorage = 21, + SpvCapabilityInt16 = 22, + SpvCapabilityTessellationPointSize = 23, + SpvCapabilityGeometryPointSize = 24, + SpvCapabilityImageGatherExtended = 25, + SpvCapabilityStorageImageExtendedFormats = 26, + SpvCapabilityStorageImageMultisample = 27, + SpvCapabilityUniformBufferArrayDynamicIndexing = 28, + SpvCapabilitySampledImageArrayDynamicIndexing = 29, + SpvCapabilityStorageBufferArrayDynamicIndexing = 30, + SpvCapabilityStorageImageArrayDynamicIndexing = 31, + SpvCapabilityClipDistance = 32, + SpvCapabilityCullDistance = 33, + SpvCapabilityImageCubeArray = 34, + SpvCapabilitySampleRateShading = 35, +} SpvCapability; + typedef enum SpvOp_ { SpvOpNop = 0, - SpvOpSource = 1, - SpvOpSourceExtension = 2, - SpvOpExtension = 3, - SpvOpExtInstImport = 4, - SpvOpMemoryModel = 5, - SpvOpEntryPoint = 6, - SpvOpExecutionMode = 7, - SpvOpTypeVoid = 8, - SpvOpTypeBool = 9, - SpvOpTypeInt = 10, - SpvOpTypeFloat = 11, - SpvOpTypeVector = 12, - SpvOpTypeMatrix = 13, - SpvOpTypeSampler = 14, - SpvOpTypeFilter = 15, - SpvOpTypeArray = 16, - SpvOpTypeRuntimeArray = 17, - SpvOpTypeStruct = 18, - SpvOpTypeOpaque = 19, - SpvOpTypePointer = 20, - SpvOpTypeFunction = 21, - SpvOpTypeEvent = 22, - SpvOpTypeDeviceEvent = 23, - SpvOpTypeReserveId = 24, - SpvOpTypeQueue = 25, - SpvOpTypePipe = 26, - SpvOpConstantTrue = 27, - SpvOpConstantFalse = 28, - SpvOpConstant = 29, - SpvOpConstantComposite = 30, - SpvOpConstantSampler = 31, - SpvOpConstantNullPointer = 32, - SpvOpConstantNullObject = 33, - SpvOpSpecConstantTrue = 34, - SpvOpSpecConstantFalse = 35, - SpvOpSpecConstant = 36, - SpvOpSpecConstantComposite = 37, - SpvOpVariable = 38, - SpvOpVariableArray = 39, - SpvOpFunction = 40, - SpvOpFunctionParameter = 41, - SpvOpFunctionEnd = 42, - SpvOpFunctionCall = 43, - SpvOpExtInst = 44, - SpvOpUndef = 45, - SpvOpLoad = 46, - SpvOpStore = 47, - SpvOpPhi = 48, - SpvOpDecorationGroup = 49, - SpvOpDecorate = 50, - SpvOpMemberDecorate = 51, - SpvOpGroupDecorate = 52, - SpvOpGroupMemberDecorate = 53, - SpvOpName = 54, - SpvOpMemberName = 55, - SpvOpString = 56, - SpvOpLine = 57, - SpvOpVectorExtractDynamic = 58, - SpvOpVectorInsertDynamic = 59, - SpvOpVectorShuffle = 60, - SpvOpCompositeConstruct = 61, - SpvOpCompositeExtract = 62, - SpvOpCompositeInsert = 63, - SpvOpCopyObject = 64, - SpvOpCopyMemory = 65, - SpvOpCopyMemorySized = 66, - SpvOpSampler = 67, - SpvOpTextureSample = 68, - SpvOpTextureSampleDref = 69, - SpvOpTextureSampleLod = 70, - SpvOpTextureSampleProj = 71, - SpvOpTextureSampleGrad = 72, - SpvOpTextureSampleOffset = 73, - SpvOpTextureSampleProjLod = 74, - SpvOpTextureSampleProjGrad = 75, - SpvOpTextureSampleLodOffset = 76, - SpvOpTextureSampleProjOffset = 77, - SpvOpTextureSampleGradOffset = 78, - SpvOpTextureSampleProjLodOffset = 79, - SpvOpTextureSampleProjGradOffset = 80, - SpvOpTextureFetchTexelLod = 81, - SpvOpTextureFetchTexelOffset = 82, - SpvOpTextureFetchSample = 83, - SpvOpTextureFetchTexel = 84, - SpvOpTextureGather = 85, - SpvOpTextureGatherOffset = 86, - SpvOpTextureGatherOffsets = 87, - SpvOpTextureQuerySizeLod = 88, - SpvOpTextureQuerySize = 89, - SpvOpTextureQueryLod = 90, - SpvOpTextureQueryLevels = 91, - SpvOpTextureQuerySamples = 92, - SpvOpAccessChain = 93, - SpvOpInBoundsAccessChain = 94, - SpvOpSNegate = 95, - SpvOpFNegate = 96, - SpvOpNot = 97, - SpvOpAny = 98, - SpvOpAll = 99, - SpvOpConvertFToU = 100, - SpvOpConvertFToS = 101, - SpvOpConvertSToF = 102, - SpvOpConvertUToF = 103, - SpvOpUConvert = 104, - SpvOpSConvert = 105, - SpvOpFConvert = 106, - SpvOpConvertPtrToU = 107, - SpvOpConvertUToPtr = 108, - SpvOpPtrCastToGeneric = 109, - SpvOpGenericCastToPtr = 110, - SpvOpBitcast = 111, - SpvOpTranspose = 112, - SpvOpIsNan = 113, - SpvOpIsInf = 114, - SpvOpIsFinite = 115, - SpvOpIsNormal = 116, - SpvOpSignBitSet = 117, - SpvOpLessOrGreater = 118, - SpvOpOrdered = 119, - SpvOpUnordered = 120, - SpvOpArrayLength = 121, - SpvOpIAdd = 122, - SpvOpFAdd = 123, - SpvOpISub = 124, - SpvOpFSub = 125, - SpvOpIMul = 126, - SpvOpFMul = 127, - SpvOpUDiv = 128, - SpvOpSDiv = 129, - SpvOpFDiv = 130, - SpvOpUMod = 131, - SpvOpSRem = 132, - SpvOpSMod = 133, - SpvOpFRem = 134, - SpvOpFMod = 135, - SpvOpVectorTimesScalar = 136, - SpvOpMatrixTimesScalar = 137, - SpvOpVectorTimesMatrix = 138, - SpvOpMatrixTimesVector = 139, - SpvOpMatrixTimesMatrix = 140, - SpvOpOuterProduct = 141, - SpvOpDot = 142, - SpvOpShiftRightLogical = 143, - SpvOpShiftRightArithmetic = 144, - SpvOpShiftLeftLogical = 145, - SpvOpLogicalOr = 146, - SpvOpLogicalXor = 147, - SpvOpLogicalAnd = 148, - SpvOpBitwiseOr = 149, - SpvOpBitwiseXor = 150, - SpvOpBitwiseAnd = 151, - SpvOpSelect = 152, - SpvOpIEqual = 153, - SpvOpFOrdEqual = 154, - SpvOpFUnordEqual = 155, - SpvOpINotEqual = 156, - SpvOpFOrdNotEqual = 157, - SpvOpFUnordNotEqual = 158, - SpvOpULessThan = 159, - SpvOpSLessThan = 160, - SpvOpFOrdLessThan = 161, - SpvOpFUnordLessThan = 162, - SpvOpUGreaterThan = 163, - SpvOpSGreaterThan = 164, - SpvOpFOrdGreaterThan = 165, - SpvOpFUnordGreaterThan = 166, - SpvOpULessThanEqual = 167, - SpvOpSLessThanEqual = 168, - SpvOpFOrdLessThanEqual = 169, - SpvOpFUnordLessThanEqual = 170, - SpvOpUGreaterThanEqual = 171, - SpvOpSGreaterThanEqual = 172, - SpvOpFOrdGreaterThanEqual = 173, - SpvOpFUnordGreaterThanEqual = 174, - SpvOpDPdx = 175, - SpvOpDPdy = 176, - SpvOpFwidth = 177, - SpvOpDPdxFine = 178, - SpvOpDPdyFine = 179, - SpvOpFwidthFine = 180, - SpvOpDPdxCoarse = 181, - SpvOpDPdyCoarse = 182, - SpvOpFwidthCoarse = 183, - SpvOpEmitVertex = 184, - SpvOpEndPrimitive = 185, - SpvOpEmitStreamVertex = 186, - SpvOpEndStreamPrimitive = 187, - SpvOpControlBarrier = 188, - SpvOpMemoryBarrier = 189, - SpvOpImagePointer = 190, - SpvOpAtomicInit = 191, - SpvOpAtomicLoad = 192, - SpvOpAtomicStore = 193, - SpvOpAtomicExchange = 194, - SpvOpAtomicCompareExchange = 195, - SpvOpAtomicCompareExchangeWeak = 196, - SpvOpAtomicIIncrement = 197, - SpvOpAtomicIDecrement = 198, - SpvOpAtomicIAdd = 199, - SpvOpAtomicISub = 200, - SpvOpAtomicUMin = 201, - SpvOpAtomicUMax = 202, - SpvOpAtomicAnd = 203, - SpvOpAtomicOr = 204, - SpvOpAtomicXor = 205, - SpvOpLoopMerge = 206, - SpvOpSelectionMerge = 207, - SpvOpLabel = 208, - SpvOpBranch = 209, - SpvOpBranchConditional = 210, - SpvOpSwitch = 211, - SpvOpKill = 212, - SpvOpReturn = 213, - SpvOpReturnValue = 214, - SpvOpUnreachable = 215, - SpvOpLifetimeStart = 216, - SpvOpLifetimeStop = 217, - SpvOpCompileFlag = 218, - SpvOpAsyncGroupCopy = 219, - SpvOpWaitGroupEvents = 220, - SpvOpGroupAll = 221, - SpvOpGroupAny = 222, - SpvOpGroupBroadcast = 223, - SpvOpGroupIAdd = 224, - SpvOpGroupFAdd = 225, - SpvOpGroupFMin = 226, - SpvOpGroupUMin = 227, - SpvOpGroupSMin = 228, - SpvOpGroupFMax = 229, - SpvOpGroupUMax = 230, - SpvOpGroupSMax = 231, - SpvOpGenericCastToPtrExplicit = 232, - SpvOpGenericPtrMemSemantics = 233, - SpvOpReadPipe = 234, - SpvOpWritePipe = 235, - SpvOpReservedReadPipe = 236, - SpvOpReservedWritePipe = 237, - SpvOpReserveReadPipePackets = 238, - SpvOpReserveWritePipePackets = 239, - SpvOpCommitReadPipe = 240, - SpvOpCommitWritePipe = 241, - SpvOpIsValidReserveId = 242, - SpvOpGetNumPipePackets = 243, - SpvOpGetMaxPipePackets = 244, - SpvOpGroupReserveReadPipePackets = 245, - SpvOpGroupReserveWritePipePackets = 246, - SpvOpGroupCommitReadPipe = 247, - SpvOpGroupCommitWritePipe = 248, - SpvOpEnqueueMarker = 249, - SpvOpEnqueueKernel = 250, - SpvOpGetKernelNDrangeSubGroupCount = 251, - SpvOpGetKernelNDrangeMaxSubGroupSize = 252, - SpvOpGetKernelWorkGroupSize = 253, - SpvOpGetKernelPreferredWorkGroupSizeMultiple = 254, - SpvOpRetainEvent = 255, - SpvOpReleaseEvent = 256, - SpvOpCreateUserEvent = 257, - SpvOpIsValidEvent = 258, - SpvOpSetUserEventStatus = 259, - SpvOpCaptureEventProfilingInfo = 260, - SpvOpGetDefaultQueue = 261, - SpvOpBuildNDRange = 262, - SpvOpSatConvertSToU = 263, - SpvOpSatConvertUToS = 264, - SpvOpAtomicIMin = 265, - SpvOpAtomicIMax = 266, + SpvOpUndef = 1, + SpvOpSource = 3, + SpvOpSourceExtension = 4, + SpvOpName = 5, + SpvOpMemberName = 6, + SpvOpString = 7, + SpvOpLine = 8, + SpvOpExtension = 10, + SpvOpExtInstImport = 11, + SpvOpExtInst = 12, + 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, + 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, + 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, + SpvOpImageQueryDim = 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, + SpvOpIMulExtended = 151, + 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, + SpvOpAsyncGroupCopy = 259, + SpvOpWaitGroupEvents = 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, } SpvOp; -#endif // #ifndef __cplusplus - #endif // #ifndef spirv_H diff --git a/src/glsl/nir/spirv_glsl450_to_nir.c b/src/glsl/nir/spirv_glsl450_to_nir.c index 3b9d0940aad..52b048820f3 100644 --- a/src/glsl/nir/spirv_glsl450_to_nir.c +++ b/src/glsl/nir/spirv_glsl450_to_nir.c @@ -139,13 +139,14 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSL450Entrypoint entrypoint, const uint32_t *w, unsigned count) { struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); - val->type = vtn_value(b, w[1], vtn_value_type_type)->type; + val->ssa = rzalloc(b, struct vtn_ssa_value); + val->ssa->type = vtn_value(b, w[1], vtn_value_type_type)->type->type; /* Collect the various SSA sources */ unsigned num_inputs = count - 5; nir_ssa_def *src[3]; for (unsigned i = 0; i < num_inputs; i++) - src[i] = vtn_ssa_value(b, w[i + 5]); + src[i] = vtn_ssa_value(b, w[i + 5])->def; nir_op op; switch (entrypoint) { @@ -158,16 +159,16 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSL450Entrypoint entrypoint, case Ceil: op = nir_op_fceil; break; case Fract: op = nir_op_ffract; break; case Radians: - val->ssa = nir_fmul(&b->nb, src[0], nir_imm_float(&b->nb, 0.01745329251)); + val->ssa->def = nir_fmul(&b->nb, src[0], nir_imm_float(&b->nb, 0.01745329251)); return; case Degrees: - val->ssa = nir_fmul(&b->nb, src[0], nir_imm_float(&b->nb, 57.2957795131)); + val->ssa->def = nir_fmul(&b->nb, src[0], nir_imm_float(&b->nb, 57.2957795131)); return; case Sin: op = nir_op_fsin; break; case Cos: op = nir_op_fcos; break; case Tan: - val->ssa = nir_fdiv(&b->nb, nir_fsin(&b->nb, src[0]), - nir_fcos(&b->nb, src[0])); + val->ssa->def = nir_fdiv(&b->nb, nir_fsin(&b->nb, src[0]), + nir_fcos(&b->nb, src[0])); return; case Pow: op = nir_op_fpow; break; case Exp2: op = nir_op_fexp2; break; @@ -180,7 +181,7 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSL450Entrypoint entrypoint, case Max: op = nir_op_fmax; break; case Mix: op = nir_op_flrp; break; case Step: - val->ssa = nir_sge(&b->nb, src[1], src[0]); + val->ssa->def = nir_sge(&b->nb, src[1], src[0]); return; case FloatBitsToInt: @@ -188,7 +189,7 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSL450Entrypoint entrypoint, case IntBitsToFloat: case UintBitsToFloat: /* Probably going to be removed from the final version of the spec. */ - val->ssa = src[0]; + val->ssa->def = src[0]; return; case Fma: op = nir_op_ffma; break; @@ -207,13 +208,13 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSL450Entrypoint entrypoint, case UnpackHalf2x16: op = nir_op_unpack_half_2x16; break; case Length: - val->ssa = build_length(&b->nb, src[0]); + val->ssa->def = build_length(&b->nb, src[0]); return; case Distance: - val->ssa = build_length(&b->nb, nir_fsub(&b->nb, src[0], src[1])); + val->ssa->def = build_length(&b->nb, nir_fsub(&b->nb, src[0], src[1])); return; case Normalize: - val->ssa = nir_fdiv(&b->nb, src[0], build_length(&b->nb, src[0])); + val->ssa->def = nir_fdiv(&b->nb, src[0], build_length(&b->nb, src[0])); return; case UaddCarry: op = nir_op_uadd_carry; break; @@ -255,8 +256,8 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSL450Entrypoint entrypoint, nir_alu_instr *instr = nir_alu_instr_create(b->shader, op); nir_ssa_dest_init(&instr->instr, &instr->dest.dest, - glsl_get_vector_elements(val->type), val->name); - val->ssa = &instr->dest.dest.ssa; + glsl_get_vector_elements(val->ssa->type), val->name); + val->ssa->def = &instr->dest.dest.ssa; for (unsigned i = 0; i < nir_op_infos[op].num_inputs; i++) instr->src[i].src = nir_src_for_ssa(src[i]); diff --git a/src/glsl/nir/spirv_to_nir.c b/src/glsl/nir/spirv_to_nir.c index 3f2ef15c74f..c3a16986fc1 100644 --- a/src/glsl/nir/spirv_to_nir.c +++ b/src/glsl/nir/spirv_to_nir.c @@ -27,24 +27,95 @@ #include "spirv_to_nir_private.h" #include "nir_vla.h" +#include "nir_control_flow.h" -nir_ssa_def * +static struct vtn_ssa_value * +vtn_const_ssa_value(struct vtn_builder *b, nir_constant *constant, + const struct glsl_type *type) +{ + struct hash_entry *entry = _mesa_hash_table_search(b->const_table, constant); + + if (entry) + return entry->data; + + struct vtn_ssa_value *val = rzalloc(b, struct vtn_ssa_value); + val->type = type; + + switch (glsl_get_base_type(type)) { + case GLSL_TYPE_INT: + case GLSL_TYPE_UINT: + case GLSL_TYPE_BOOL: + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_DOUBLE: + if (glsl_type_is_vector_or_scalar(type)) { + unsigned num_components = glsl_get_vector_elements(val->type); + nir_load_const_instr *load = + nir_load_const_instr_create(b->shader, num_components); + + for (unsigned i = 0; i < num_components; i++) + load->value.u[i] = constant->value.u[i]; + + nir_instr_insert_before_cf_list(&b->impl->body, &load->instr); + val->def = &load->def; + } else { + assert(glsl_type_is_matrix(type)); + unsigned rows = glsl_get_vector_elements(val->type); + unsigned columns = glsl_get_matrix_columns(val->type); + val->elems = ralloc_array(b, struct vtn_ssa_value *, columns); + + for (unsigned i = 0; i < columns; i++) { + struct vtn_ssa_value *col_val = rzalloc(b, struct vtn_ssa_value); + col_val->type = glsl_get_column_type(val->type); + nir_load_const_instr *load = + nir_load_const_instr_create(b->shader, rows); + + for (unsigned j = 0; j < rows; j++) + load->value.u[j] = constant->value.u[rows * i + j]; + + nir_instr_insert_before_cf_list(&b->impl->body, &load->instr); + col_val->def = &load->def; + + val->elems[i] = col_val; + } + } + break; + + case GLSL_TYPE_ARRAY: { + unsigned elems = glsl_get_length(val->type); + val->elems = ralloc_array(b, struct vtn_ssa_value *, elems); + const struct glsl_type *elem_type = glsl_get_array_element(val->type); + for (unsigned i = 0; i < elems; i++) + val->elems[i] = vtn_const_ssa_value(b, constant->elements[i], + elem_type); + break; + } + + case GLSL_TYPE_STRUCT: { + unsigned elems = glsl_get_length(val->type); + val->elems = ralloc_array(b, struct vtn_ssa_value *, elems); + for (unsigned i = 0; i < elems; i++) { + const struct glsl_type *elem_type = + glsl_get_struct_field(val->type, i); + val->elems[i] = vtn_const_ssa_value(b, constant->elements[i], + elem_type); + } + break; + } + + default: + unreachable("bad constant type"); + } + + return val; +} + +struct vtn_ssa_value * vtn_ssa_value(struct vtn_builder *b, uint32_t value_id) { struct vtn_value *val = vtn_untyped_value(b, value_id); switch (val->value_type) { - case vtn_value_type_constant: { - assert(glsl_type_is_vector_or_scalar(val->type)); - unsigned num_components = glsl_get_vector_elements(val->type); - nir_load_const_instr *load = - nir_load_const_instr_create(b->shader, num_components); - - for (unsigned i = 0; i < num_components; i++) - load->value.u[0] = val->constant->value.u[0]; - - nir_builder_instr_insert(&b->nb, &load->instr); - return &load->def; - } + case vtn_value_type_constant: + return vtn_const_ssa_value(b, val->constant, val->const_type); case vtn_value_type_ssa: return val->ssa; @@ -110,15 +181,24 @@ vtn_handle_extension(struct vtn_builder *b, SpvOp opcode, static void _foreach_decoration_helper(struct vtn_builder *b, struct vtn_value *base_value, + int member, struct vtn_value *value, vtn_decoration_foreach_cb cb, void *data) { + int new_member = member; + for (struct vtn_decoration *dec = value->decoration; dec; dec = dec->next) { + if (dec->member >= 0) { + assert(member == -1); + new_member = dec->member; + } + if (dec->group) { assert(dec->group->value_type == vtn_value_type_decoration_group); - _foreach_decoration_helper(b, base_value, dec->group, cb, data); + _foreach_decoration_helper(b, base_value, new_member, dec->group, + cb, data); } else { - cb(b, base_value, dec, data); + cb(b, base_value, new_member, dec, data); } } } @@ -133,24 +213,33 @@ void vtn_foreach_decoration(struct vtn_builder *b, struct vtn_value *value, vtn_decoration_foreach_cb cb, void *data) { - _foreach_decoration_helper(b, value, value, cb, data); + _foreach_decoration_helper(b, value, -1, value, cb, data); } static void vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) { + const uint32_t *w_end = w + count; + const uint32_t target = w[1]; + w += 2; + + int member = -1; switch (opcode) { case SpvOpDecorationGroup: - vtn_push_value(b, w[1], vtn_value_type_undef); + vtn_push_value(b, target, vtn_value_type_undef); break; + case SpvOpMemberDecorate: + member = *(w++); + /* fallthrough */ case SpvOpDecorate: { - struct vtn_value *val = &b->values[w[1]]; + struct vtn_value *val = &b->values[target]; struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration); - dec->decoration = w[2]; - dec->literals = &w[3]; + dec->member = member; + dec->decoration = *(w++); + dec->literals = w; /* Link into the list */ dec->next = val->decoration; @@ -158,13 +247,17 @@ vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode, break; } + case SpvOpGroupMemberDecorate: + member = *(w++); + /* fallthrough */ case SpvOpGroupDecorate: { - struct vtn_value *group = &b->values[w[1]]; + struct vtn_value *group = &b->values[target]; assert(group->value_type == vtn_value_type_decoration_group); - for (unsigned i = 2; i < count; i++) { - struct vtn_value *val = &b->values[w[i]]; + for (; w < w_end; w++) { + struct vtn_value *val = &b->values[*w]; struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration); + dec->member = member; dec->group = group; /* Link into the list */ @@ -174,57 +267,207 @@ vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode, break; } - case SpvOpGroupMemberDecorate: - assert(!"Bad instruction. Khronos Bug #13513"); - break; - default: unreachable("Unhandled opcode"); } } -static const struct glsl_type * -vtn_handle_type(struct vtn_builder *b, SpvOp opcode, - const uint32_t *args, unsigned count) +struct member_decoration_ctx { + struct glsl_struct_field *fields; + struct vtn_type *type; +}; + +/* does a shallow copy of a vtn_type */ + +static struct vtn_type * +vtn_type_copy(struct vtn_builder *b, struct vtn_type *src) { + struct vtn_type *dest = ralloc(b, struct vtn_type); + dest->type = src->type; + dest->is_builtin = src->is_builtin; + if (src->is_builtin) + dest->builtin = src->builtin; + + if (!glsl_type_is_vector_or_scalar(src->type)) { + switch (glsl_get_base_type(src->type)) { + case GLSL_TYPE_ARRAY: + dest->array_element = src->array_element; + dest->stride = src->stride; + break; + + case GLSL_TYPE_INT: + case GLSL_TYPE_UINT: + case GLSL_TYPE_BOOL: + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_DOUBLE: + /* matrices */ + dest->row_major = src->row_major; + dest->stride = src->stride; + break; + + case GLSL_TYPE_STRUCT: { + unsigned elems = glsl_get_length(src->type); + + dest->members = ralloc_array(b, struct vtn_type *, elems); + memcpy(dest->members, src->members, elems * sizeof(struct vtn_type *)); + + dest->offsets = ralloc_array(b, unsigned, elems); + memcpy(dest->offsets, src->offsets, elems * sizeof(unsigned)); + break; + } + + default: + unreachable("unhandled type"); + } + } + + return dest; +} + +static void +struct_member_decoration_cb(struct vtn_builder *b, + struct vtn_value *val, int member, + const struct vtn_decoration *dec, void *void_ctx) +{ + struct member_decoration_ctx *ctx = void_ctx; + + if (member < 0) + return; + + switch (dec->decoration) { + case SpvDecorationRelaxedPrecision: + break; /* FIXME: Do nothing with this for now. */ + case SpvDecorationSmooth: + ctx->fields[member].interpolation = INTERP_QUALIFIER_SMOOTH; + break; + case SpvDecorationNoperspective: + ctx->fields[member].interpolation = INTERP_QUALIFIER_NOPERSPECTIVE; + break; + case SpvDecorationFlat: + ctx->fields[member].interpolation = INTERP_QUALIFIER_FLAT; + break; + case SpvDecorationCentroid: + ctx->fields[member].centroid = true; + break; + case SpvDecorationSample: + ctx->fields[member].sample = true; + break; + case SpvDecorationLocation: + ctx->fields[member].location = dec->literals[0]; + break; + case SpvDecorationBuiltIn: + ctx->type->members[member] = vtn_type_copy(b, + ctx->type->members[member]); + ctx->type->members[member]->is_builtin = true; + ctx->type->members[member]->builtin = dec->literals[0]; + ctx->type->builtin_block = true; + break; + case SpvDecorationOffset: + ctx->type->offsets[member] = dec->literals[0]; + break; + default: + unreachable("Unhandled member decoration"); + } +} + +static void +type_decoration_cb(struct vtn_builder *b, + struct vtn_value *val, int member, + const struct vtn_decoration *dec, void *ctx) +{ + struct vtn_type *type = val->type; + + if (member != -1) + return; + + switch (dec->decoration) { + case SpvDecorationArrayStride: + type->stride = dec->literals[0]; + break; + case SpvDecorationBlock: + type->block = true; + break; + case SpvDecorationBufferBlock: + type->buffer_block = true; + break; + case SpvDecorationGLSLShared: + case SpvDecorationGLSLPacked: + /* Ignore these, since we get explicit offsets anyways */ + break; + + default: + unreachable("Unhandled type decoration"); + } +} + +static void +vtn_handle_type(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) +{ + struct vtn_value *val = vtn_push_value(b, w[1], vtn_value_type_type); + + val->type = rzalloc(b, struct vtn_type); + val->type->is_builtin = false; + switch (opcode) { case SpvOpTypeVoid: - return glsl_void_type(); + val->type->type = glsl_void_type(); + break; case SpvOpTypeBool: - return glsl_bool_type(); + val->type->type = glsl_bool_type(); + break; case SpvOpTypeInt: - return glsl_int_type(); + val->type->type = glsl_int_type(); + break; case SpvOpTypeFloat: - return glsl_float_type(); + val->type->type = glsl_float_type(); + break; case SpvOpTypeVector: { const struct glsl_type *base = - vtn_value(b, args[0], vtn_value_type_type)->type; - unsigned elems = args[1]; + vtn_value(b, w[2], vtn_value_type_type)->type->type; + unsigned elems = w[3]; assert(glsl_type_is_scalar(base)); - return glsl_vector_type(glsl_get_base_type(base), elems); + val->type->type = glsl_vector_type(glsl_get_base_type(base), elems); + break; } case SpvOpTypeMatrix: { - const struct glsl_type *base = - vtn_value(b, args[0], vtn_value_type_type)->type; - unsigned columns = args[1]; + struct vtn_type *base = + vtn_value(b, w[2], vtn_value_type_type)->type; + unsigned columns = w[3]; - assert(glsl_type_is_vector(base)); - return glsl_matrix_type(glsl_get_base_type(base), - glsl_get_vector_elements(base), - columns); + assert(glsl_type_is_vector(base->type)); + val->type->type = glsl_matrix_type(glsl_get_base_type(base->type), + glsl_get_vector_elements(base->type), + columns); + val->type->array_element = base; + val->type->row_major = false; + val->type->stride = 0; + break; } - case SpvOpTypeArray: - return glsl_array_type(b->values[args[0]].type, args[1]); + case SpvOpTypeArray: { + struct vtn_type *array_element = + vtn_value(b, w[2], vtn_value_type_type)->type; + val->type->type = glsl_array_type(array_element->type, w[3]); + val->type->array_element = array_element; + val->type->stride = 0; + break; + } case SpvOpTypeStruct: { + unsigned num_fields = count - 2; + val->type->members = ralloc_array(b, struct vtn_type *, num_fields); + val->type->offsets = ralloc_array(b, unsigned, num_fields); + NIR_VLA(struct glsl_struct_field, fields, count); - for (unsigned i = 0; i < count; i++) { + for (unsigned i = 0; i < num_fields; i++) { /* TODO: Handle decorators */ - fields[i].type = vtn_value(b, args[i], vtn_value_type_type)->type; + val->type->members[i] = + vtn_value(b, w[i + 2], vtn_value_type_type)->type; + fields[i].type = val->type->members[i]->type; fields[i].name = ralloc_asprintf(b, "field%d", i); fields[i].location = -1; fields[i].interpolation = 0; @@ -233,20 +476,33 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode, fields[i].matrix_layout = 2; fields[i].stream = -1; } - return glsl_struct_type(fields, count, "struct"); + + struct member_decoration_ctx ctx = { + .fields = fields, + .type = val->type + }; + + vtn_foreach_decoration(b, val, struct_member_decoration_cb, &ctx); + + const char *name = val->name ? val->name : "struct"; + + val->type->type = glsl_struct_type(fields, num_fields, name); + break; } case SpvOpTypeFunction: { - const struct glsl_type *return_type = b->values[args[0]].type; - NIR_VLA(struct glsl_function_param, params, count - 1); - for (unsigned i = 1; i < count; i++) { - params[i - 1].type = vtn_value(b, args[i], vtn_value_type_type)->type; + const struct glsl_type *return_type = + vtn_value(b, w[2], vtn_value_type_type)->type->type; + NIR_VLA(struct glsl_function_param, params, count - 3); + for (unsigned i = 0; i < count - 3; i++) { + params[i].type = vtn_value(b, w[i + 3], vtn_value_type_type)->type->type; /* FIXME: */ - params[i - 1].in = true; - params[i - 1].out = true; + params[i].in = true; + params[i].out = true; } - return glsl_function_type(return_type, params, count - 1); + val->type->type = glsl_function_type(return_type, params, count - 3); + break; } case SpvOpTypePointer: @@ -254,16 +510,17 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode, * the same type. The validator should ensure that the proper number * of dereferences happen */ - return vtn_value(b, args[1], vtn_value_type_type)->type; + val->type = vtn_value(b, w[3], vtn_value_type_type)->type; + break; - case SpvOpTypeSampler: { + case SpvOpTypeImage: { const struct glsl_type *sampled_type = - vtn_value(b, args[0], vtn_value_type_type)->type; + vtn_value(b, w[2], vtn_value_type_type)->type->type; assert(glsl_type_is_vector_or_scalar(sampled_type)); enum glsl_sampler_dim dim; - switch ((SpvDim)args[1]) { + switch ((SpvDim)w[3]) { case SpvDim1D: dim = GLSL_SAMPLER_DIM_1D; break; case SpvDim2D: dim = GLSL_SAMPLER_DIM_2D; break; case SpvDim3D: dim = GLSL_SAMPLER_DIM_3D; break; @@ -274,18 +531,21 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode, unreachable("Invalid SPIR-V Sampler dimension"); } - /* TODO: Handle the various texture image/filter options */ - (void)args[2]; + bool is_shadow = w[4]; + bool is_array = w[5]; - bool is_array = args[3]; - bool is_shadow = args[4]; + assert(w[6] == 0 && "FIXME: Handl multi-sampled textures"); + assert(w[7] == 1 && "FIXME: Add support for non-sampled images"); - assert(args[5] == 0 && "FIXME: Handl multi-sampled textures"); - - return glsl_sampler_type(dim, is_shadow, is_array, - glsl_get_base_type(sampled_type)); + val->type->type = glsl_sampler_type(dim, is_shadow, is_array, + glsl_get_base_type(sampled_type)); + break; } + case SpvOpTypeSampledImage: + val->type = vtn_value(b, w[2], vtn_value_type_type)->type; + break; + case SpvOpTypeRuntimeArray: case SpvOpTypeOpaque: case SpvOpTypeEvent: @@ -296,6 +556,8 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode, default: unreachable("Unhandled opcode"); } + + vtn_foreach_decoration(b, val, type_decoration_cb, NULL); } static void @@ -303,19 +565,19 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) { struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_constant); - val->type = vtn_value(b, w[1], vtn_value_type_type)->type; + val->const_type = vtn_value(b, w[1], vtn_value_type_type)->type->type; val->constant = ralloc(b, nir_constant); switch (opcode) { case SpvOpConstantTrue: - assert(val->type == glsl_bool_type()); + assert(val->const_type == glsl_bool_type()); val->constant->value.u[0] = NIR_TRUE; break; case SpvOpConstantFalse: - assert(val->type == glsl_bool_type()); + assert(val->const_type == glsl_bool_type()); val->constant->value.u[0] = NIR_FALSE; break; case SpvOpConstant: - assert(glsl_type_is_scalar(val->type)); + assert(glsl_type_is_scalar(val->const_type)); val->constant->value.u[0] = w[3]; break; case SpvOpConstantComposite: { @@ -324,20 +586,20 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode, for (unsigned i = 0; i < elem_count; i++) elems[i] = vtn_value(b, w[i + 3], vtn_value_type_constant)->constant; - switch (glsl_get_base_type(val->type)) { + switch (glsl_get_base_type(val->const_type)) { case GLSL_TYPE_UINT: case GLSL_TYPE_INT: case GLSL_TYPE_FLOAT: case GLSL_TYPE_BOOL: - if (glsl_type_is_matrix(val->type)) { - unsigned rows = glsl_get_vector_elements(val->type); - assert(glsl_get_matrix_columns(val->type) == elem_count); + if (glsl_type_is_matrix(val->const_type)) { + unsigned rows = glsl_get_vector_elements(val->const_type); + assert(glsl_get_matrix_columns(val->const_type) == elem_count); for (unsigned i = 0; i < elem_count; i++) for (unsigned j = 0; j < rows; j++) val->constant->value.u[rows * i + j] = elems[i]->value.u[j]; } else { - assert(glsl_type_is_vector(val->type)); - assert(glsl_get_vector_elements(val->type) == elem_count); + assert(glsl_type_is_vector(val->const_type)); + assert(glsl_get_vector_elements(val->const_type) == elem_count); for (unsigned i = 0; i < elem_count; i++) val->constant->value.u[i] = elems[i]->value.u[0]; } @@ -362,7 +624,101 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode, } static void -var_decoration_cb(struct vtn_builder *b, struct vtn_value *val, +vtn_get_builtin_location(SpvBuiltIn builtin, int *location, + nir_variable_mode *mode) +{ + switch (builtin) { + case SpvBuiltInPosition: + *location = VARYING_SLOT_POS; + *mode = nir_var_shader_out; + break; + case SpvBuiltInPointSize: + *location = VARYING_SLOT_PSIZ; + *mode = nir_var_shader_out; + break; + case SpvBuiltInClipDistance: + *location = VARYING_SLOT_CLIP_DIST0; /* XXX CLIP_DIST1? */ + *mode = nir_var_shader_in; + break; + case SpvBuiltInCullDistance: + /* XXX figure this out */ + unreachable("unhandled builtin"); + case SpvBuiltInVertexId: + *location = SYSTEM_VALUE_VERTEX_ID; + *mode = nir_var_system_value; + break; + case SpvBuiltInInstanceId: + *location = SYSTEM_VALUE_INSTANCE_ID; + *mode = nir_var_system_value; + break; + case SpvBuiltInPrimitiveId: + *location = VARYING_SLOT_PRIMITIVE_ID; + *mode = nir_var_shader_out; + break; + case SpvBuiltInInvocationId: + *location = SYSTEM_VALUE_INVOCATION_ID; + *mode = nir_var_system_value; + break; + case SpvBuiltInLayer: + *location = VARYING_SLOT_LAYER; + *mode = nir_var_shader_out; + break; + case SpvBuiltInTessLevelOuter: + case SpvBuiltInTessLevelInner: + case SpvBuiltInTessCoord: + case SpvBuiltInPatchVertices: + unreachable("no tessellation support"); + case SpvBuiltInFragCoord: + *location = VARYING_SLOT_POS; + *mode = nir_var_shader_in; + break; + case SpvBuiltInPointCoord: + *location = VARYING_SLOT_PNTC; + *mode = nir_var_shader_out; + break; + case SpvBuiltInFrontFacing: + *location = VARYING_SLOT_FACE; + *mode = nir_var_shader_out; + break; + case SpvBuiltInSampleId: + *location = SYSTEM_VALUE_SAMPLE_ID; + *mode = nir_var_shader_in; + break; + case SpvBuiltInSamplePosition: + *location = SYSTEM_VALUE_SAMPLE_POS; + *mode = nir_var_shader_in; + break; + case SpvBuiltInSampleMask: + *location = SYSTEM_VALUE_SAMPLE_MASK_IN; /* XXX out? */ + *mode = nir_var_shader_in; + break; + case SpvBuiltInFragColor: + *location = FRAG_RESULT_COLOR; + *mode = nir_var_shader_out; + break; + case SpvBuiltInFragDepth: + *location = FRAG_RESULT_DEPTH; + *mode = nir_var_shader_out; + break; + case SpvBuiltInHelperInvocation: + unreachable("unsupported builtin"); /* XXX */ + break; + case SpvBuiltInNumWorkgroups: + case SpvBuiltInWorkgroupSize: + /* these are constants, need to be handled specially */ + unreachable("unsupported builtin"); + case SpvBuiltInWorkgroupId: + case SpvBuiltInLocalInvocationId: + case SpvBuiltInGlobalInvocationId: + case SpvBuiltInLocalInvocationIndex: + unreachable("no compute shader support"); + default: + unreachable("unsupported builtin"); + } +} + +static void +var_decoration_cb(struct vtn_builder *b, struct vtn_value *val, int member, const struct vtn_decoration *dec, void *void_var) { assert(val->value_type == vtn_value_type_deref); @@ -371,10 +727,8 @@ var_decoration_cb(struct vtn_builder *b, struct vtn_value *val, nir_variable *var = void_var; switch (dec->decoration) { - case SpvDecorationPrecisionLow: - case SpvDecorationPrecisionMedium: - case SpvDecorationPrecisionHigh: - break; /* FIXME: Do nothing with these for now. */ + case SpvDecorationRelaxedPrecision: + break; /* FIXME: Do nothing with this for now. */ case SpvDecorationSmooth: var->data.interpolation = INTERP_QUALIFIER_SMOOTH; break; @@ -415,14 +769,25 @@ var_decoration_cb(struct vtn_builder *b, struct vtn_value *val, var->data.explicit_binding = true; var->data.binding = dec->literals[0]; break; - case SpvDecorationBlock: - case SpvDecorationBufferBlock: + case SpvDecorationDescriptorSet: + var->data.descriptor_set = dec->literals[0]; + break; + case SpvDecorationBuiltIn: { + nir_variable_mode mode; + vtn_get_builtin_location(dec->literals[0], &var->data.location, + &mode); + var->data.mode = mode; + if (mode == nir_var_shader_in || mode == nir_var_system_value) + var->data.read_only = true; + b->builtins[dec->literals[0]] = var; + break; + } + case SpvDecorationNoStaticUse: + /* This can safely be ignored */ + break; case SpvDecorationRowMajor: case SpvDecorationColMajor: case SpvDecorationGLSLShared: - case SpvDecorationGLSLStd140: - case SpvDecorationGLSLStd430: - case SpvDecorationGLSLPacked: case SpvDecorationPatch: case SpvDecorationRestrict: case SpvDecorationAliased: @@ -431,42 +796,453 @@ var_decoration_cb(struct vtn_builder *b, struct vtn_value *val, case SpvDecorationNonreadable: case SpvDecorationUniform: /* This is really nice but we have no use for it right now. */ - case SpvDecorationNoStaticUse: case SpvDecorationCPacked: case SpvDecorationSaturatedConversion: case SpvDecorationStream: - case SpvDecorationDescriptorSet: case SpvDecorationOffset: - case SpvDecorationAlignment: case SpvDecorationXfbBuffer: - case SpvDecorationStride: - case SpvDecorationBuiltIn: case SpvDecorationFuncParamAttr: case SpvDecorationFPRoundingMode: case SpvDecorationFPFastMathMode: case SpvDecorationLinkageAttributes: case SpvDecorationSpecId: + break; default: unreachable("Unhandled variable decoration"); } } +static nir_variable * +get_builtin_variable(struct vtn_builder *b, + const struct glsl_type *type, + SpvBuiltIn builtin) +{ + nir_variable *var = b->builtins[builtin]; + + if (!var) { + var = ralloc(b->shader, nir_variable); + var->type = type; + + nir_variable_mode mode; + vtn_get_builtin_location(builtin, &var->data.location, &mode); + var->data.mode = mode; + var->name = ralloc_strdup(var, "builtin"); + + switch (mode) { + case nir_var_shader_in: + exec_list_push_tail(&b->shader->inputs, &var->node); + break; + case nir_var_shader_out: + exec_list_push_tail(&b->shader->outputs, &var->node); + break; + case nir_var_system_value: + exec_list_push_tail(&b->shader->system_values, &var->node); + break; + default: + unreachable("bad builtin mode"); + } + + b->builtins[builtin] = var; + } + + return var; +} + +static void +vtn_builtin_load(struct vtn_builder *b, + struct vtn_ssa_value *val, + SpvBuiltIn builtin) +{ + assert(glsl_type_is_vector_or_scalar(val->type)); + + nir_variable *var = get_builtin_variable(b, val->type, builtin); + + nir_intrinsic_instr *load = + nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_var); + nir_ssa_dest_init(&load->instr, &load->dest, + glsl_get_vector_elements(val->type), NULL); + + load->variables[0] = nir_deref_var_create(load, var); + load->num_components = glsl_get_vector_elements(val->type); + nir_builder_instr_insert(&b->nb, &load->instr); + val->def = &load->dest.ssa; +} + +static void +vtn_builtin_store(struct vtn_builder *b, + struct vtn_ssa_value *val, + SpvBuiltIn builtin) +{ + assert(glsl_type_is_vector_or_scalar(val->type)); + + nir_variable *var = get_builtin_variable(b, val->type, builtin); + + nir_intrinsic_instr *store = + nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_var); + + store->variables[0] = nir_deref_var_create(store, var); + store->num_components = glsl_get_vector_elements(val->type); + store->src[0] = nir_src_for_ssa(val->def); + nir_builder_instr_insert(&b->nb, &store->instr); +} + +static struct vtn_ssa_value * +_vtn_variable_load(struct vtn_builder *b, + nir_deref_var *src_deref, struct vtn_type *src_type, + nir_deref *src_deref_tail) +{ + struct vtn_ssa_value *val = rzalloc(b, struct vtn_ssa_value); + val->type = src_deref_tail->type; + + if (src_type->is_builtin) { + vtn_builtin_load(b, val, src_type->builtin); + return val; + } + + /* The deref tail may contain a deref to select a component of a vector (in + * other words, it might not be an actual tail) so we have to save it away + * here since we overwrite it later. + */ + nir_deref *old_child = src_deref_tail->child; + + if (glsl_type_is_vector_or_scalar(val->type)) { + nir_intrinsic_instr *load = + nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_var); + load->variables[0] = + nir_deref_as_var(nir_copy_deref(load, &src_deref->deref)); + load->num_components = glsl_get_vector_elements(val->type); + nir_ssa_dest_init(&load->instr, &load->dest, load->num_components, NULL); + + nir_builder_instr_insert(&b->nb, &load->instr); + + if (src_deref->var->data.mode == nir_var_uniform && + glsl_get_base_type(val->type) == GLSL_TYPE_BOOL) { + /* Uniform boolean loads need to be fixed up since they're defined + * to be zero/nonzero rather than NIR_FALSE/NIR_TRUE. + */ + val->def = nir_ine(&b->nb, &load->dest.ssa, nir_imm_int(&b->nb, 0)); + } else { + val->def = &load->dest.ssa; + } + } else if (glsl_get_base_type(val->type) == GLSL_TYPE_ARRAY || + glsl_type_is_matrix(val->type)) { + unsigned elems = glsl_get_length(val->type); + val->elems = ralloc_array(b, struct vtn_ssa_value *, elems); + + nir_deref_array *deref = nir_deref_array_create(b); + deref->deref_array_type = nir_deref_array_type_direct; + deref->deref.type = glsl_get_array_element(val->type); + src_deref_tail->child = &deref->deref; + for (unsigned i = 0; i < elems; i++) { + deref->base_offset = i; + val->elems[i] = _vtn_variable_load(b, src_deref, + src_type->array_element, + &deref->deref); + } + } else { + assert(glsl_get_base_type(val->type) == GLSL_TYPE_STRUCT); + unsigned elems = glsl_get_length(val->type); + val->elems = ralloc_array(b, struct vtn_ssa_value *, elems); + + nir_deref_struct *deref = nir_deref_struct_create(b, 0); + src_deref_tail->child = &deref->deref; + for (unsigned i = 0; i < elems; i++) { + deref->index = i; + deref->deref.type = glsl_get_struct_field(val->type, i); + val->elems[i] = _vtn_variable_load(b, src_deref, + src_type->members[i], + &deref->deref); + } + } + + src_deref_tail->child = old_child; + + return val; +} + +static void +_vtn_variable_store(struct vtn_builder *b, struct vtn_type *dest_type, + nir_deref_var *dest_deref, nir_deref *dest_deref_tail, + struct vtn_ssa_value *src) +{ + if (dest_type->is_builtin) { + vtn_builtin_store(b, src, dest_type->builtin); + return; + } + + nir_deref *old_child = dest_deref_tail->child; + + if (glsl_type_is_vector_or_scalar(src->type)) { + nir_intrinsic_instr *store = + nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_var); + store->variables[0] = + nir_deref_as_var(nir_copy_deref(store, &dest_deref->deref)); + store->num_components = glsl_get_vector_elements(src->type); + store->src[0] = nir_src_for_ssa(src->def); + + nir_builder_instr_insert(&b->nb, &store->instr); + } else if (glsl_get_base_type(src->type) == GLSL_TYPE_ARRAY || + glsl_type_is_matrix(src->type)) { + unsigned elems = glsl_get_length(src->type); + + nir_deref_array *deref = nir_deref_array_create(b); + deref->deref_array_type = nir_deref_array_type_direct; + deref->deref.type = glsl_get_array_element(src->type); + dest_deref_tail->child = &deref->deref; + for (unsigned i = 0; i < elems; i++) { + deref->base_offset = i; + _vtn_variable_store(b, dest_type->array_element, dest_deref, + &deref->deref, src->elems[i]); + } + } else { + assert(glsl_get_base_type(src->type) == GLSL_TYPE_STRUCT); + unsigned elems = glsl_get_length(src->type); + + nir_deref_struct *deref = nir_deref_struct_create(b, 0); + dest_deref_tail->child = &deref->deref; + for (unsigned i = 0; i < elems; i++) { + deref->index = i; + deref->deref.type = glsl_get_struct_field(src->type, i); + _vtn_variable_store(b, dest_type->members[i], dest_deref, + &deref->deref, src->elems[i]); + } + } + + dest_deref_tail->child = old_child; +} + +static struct vtn_ssa_value * +_vtn_block_load(struct vtn_builder *b, nir_intrinsic_op op, + unsigned set, nir_ssa_def *binding, + unsigned offset, nir_ssa_def *indirect, + struct vtn_type *type) +{ + struct vtn_ssa_value *val = ralloc(b, struct vtn_ssa_value); + val->type = type->type; + val->transposed = NULL; + if (glsl_type_is_vector_or_scalar(type->type)) { + nir_intrinsic_instr *load = nir_intrinsic_instr_create(b->shader, op); + load->num_components = glsl_get_vector_elements(type->type); + load->const_index[0] = set; + load->src[0] = nir_src_for_ssa(binding); + load->const_index[1] = offset; + if (indirect) + load->src[1] = nir_src_for_ssa(indirect); + nir_ssa_dest_init(&load->instr, &load->dest, load->num_components, NULL); + nir_builder_instr_insert(&b->nb, &load->instr); + val->def = &load->dest.ssa; + } else { + unsigned elems = glsl_get_length(type->type); + val->elems = ralloc_array(b, struct vtn_ssa_value *, elems); + if (glsl_type_is_struct(type->type)) { + for (unsigned i = 0; i < elems; i++) { + val->elems[i] = _vtn_block_load(b, op, set, binding, + offset + type->offsets[i], + indirect, type->members[i]); + } + } else { + for (unsigned i = 0; i < elems; i++) { + val->elems[i] = _vtn_block_load(b, op, set, binding, + offset + i * type->stride, + indirect, type->array_element); + } + } + } + + return val; +} + +static struct vtn_ssa_value * +vtn_block_load(struct vtn_builder *b, nir_deref_var *src, + struct vtn_type *type, nir_deref *src_tail) +{ + unsigned set = src->var->data.descriptor_set; + + nir_ssa_def *binding = nir_imm_int(&b->nb, src->var->data.binding); + nir_deref *deref = &src->deref; + + /* The block variable may be an array, in which case the array index adds + * an offset to the binding. Figure out that index now. + */ + + if (deref->child->deref_type == nir_deref_type_array) { + deref = deref->child; + type = type->array_element; + nir_deref_array *deref_array = nir_deref_as_array(deref); + if (deref_array->deref_array_type == nir_deref_array_type_direct) { + binding = nir_imm_int(&b->nb, src->var->data.binding + + deref_array->base_offset); + } else { + binding = nir_iadd(&b->nb, binding, deref_array->indirect.ssa); + } + } + + unsigned offset = 0; + nir_ssa_def *indirect = NULL; + while (deref != src_tail) { + deref = deref->child; + switch (deref->deref_type) { + case nir_deref_type_array: { + nir_deref_array *deref_array = nir_deref_as_array(deref); + if (deref_array->deref_array_type == nir_deref_array_type_direct) { + offset += type->stride * deref_array->base_offset; + } else { + nir_ssa_def *offset = nir_imul(&b->nb, deref_array->indirect.ssa, + nir_imm_int(&b->nb, type->stride)); + indirect = indirect ? nir_iadd(&b->nb, indirect, offset) : offset; + } + type = type->array_element; + break; + } + + case nir_deref_type_struct: { + nir_deref_struct *deref_struct = nir_deref_as_struct(deref); + offset += type->offsets[deref_struct->index]; + type = type->members[deref_struct->index]; + break; + } + + default: + unreachable("unknown deref type"); + } + } + + /* TODO SSBO's */ + nir_intrinsic_op op = indirect ? nir_intrinsic_load_ubo_indirect + : nir_intrinsic_load_ubo; + + return _vtn_block_load(b, op, set, binding, offset, indirect, type); +} + +/* + * Gets the NIR-level deref tail, which may have as a child an array deref + * selecting which component due to OpAccessChain supporting per-component + * indexing in SPIR-V. + */ + +static nir_deref * +get_deref_tail(nir_deref_var *deref) +{ + nir_deref *cur = &deref->deref; + while (!glsl_type_is_vector_or_scalar(cur->type) && cur->child) + cur = cur->child; + + return cur; +} + +static nir_ssa_def *vtn_vector_extract(struct vtn_builder *b, + nir_ssa_def *src, unsigned index); + +static nir_ssa_def *vtn_vector_extract_dynamic(struct vtn_builder *b, + nir_ssa_def *src, + nir_ssa_def *index); + +static struct vtn_ssa_value * +vtn_variable_load(struct vtn_builder *b, nir_deref_var *src, + struct vtn_type *src_type) +{ + nir_deref *src_tail = get_deref_tail(src); + + struct vtn_ssa_value *val; + if (src->var->interface_type && src->var->data.mode == nir_var_uniform) + val = vtn_block_load(b, src, src_type, src_tail); + else + val = _vtn_variable_load(b, src, src_type, src_tail); + + if (src_tail->child) { + nir_deref_array *vec_deref = nir_deref_as_array(src_tail->child); + assert(vec_deref->deref.child == NULL); + val->type = vec_deref->deref.type; + if (vec_deref->deref_array_type == nir_deref_array_type_direct) + val->def = vtn_vector_extract(b, val->def, vec_deref->base_offset); + else + val->def = vtn_vector_extract_dynamic(b, val->def, + vec_deref->indirect.ssa); + } + + return val; +} + +static nir_ssa_def * vtn_vector_insert(struct vtn_builder *b, + nir_ssa_def *src, nir_ssa_def *insert, + unsigned index); + +static nir_ssa_def * vtn_vector_insert_dynamic(struct vtn_builder *b, + nir_ssa_def *src, + nir_ssa_def *insert, + nir_ssa_def *index); +static void +vtn_variable_store(struct vtn_builder *b, struct vtn_ssa_value *src, + nir_deref_var *dest, struct vtn_type *dest_type) +{ + nir_deref *dest_tail = get_deref_tail(dest); + if (dest_tail->child) { + struct vtn_ssa_value *val = _vtn_variable_load(b, dest, dest_type, + dest_tail); + nir_deref_array *deref = nir_deref_as_array(dest_tail->child); + assert(deref->deref.child == NULL); + if (deref->deref_array_type == nir_deref_array_type_direct) + val->def = vtn_vector_insert(b, val->def, src->def, + deref->base_offset); + else + val->def = vtn_vector_insert_dynamic(b, val->def, src->def, + deref->indirect.ssa); + _vtn_variable_store(b, dest_type, dest, dest_tail, val); + } else { + _vtn_variable_store(b, dest_type, dest, dest_tail, src); + } +} + +static void +vtn_variable_copy(struct vtn_builder *b, nir_deref_var *src, + nir_deref_var *dest, struct vtn_type *type) +{ + nir_deref *src_tail = get_deref_tail(src); + + if (src_tail->child || src->var->interface_type) { + assert(get_deref_tail(dest)->child); + struct vtn_ssa_value *val = vtn_variable_load(b, src, type); + vtn_variable_store(b, val, dest, type); + } else { + nir_intrinsic_instr *copy = + nir_intrinsic_instr_create(b->shader, nir_intrinsic_copy_var); + copy->variables[0] = nir_deref_as_var(nir_copy_deref(copy, &dest->deref)); + copy->variables[1] = nir_deref_as_var(nir_copy_deref(copy, &src->deref)); + + nir_builder_instr_insert(&b->nb, ©->instr); + } +} + static void vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) { switch (opcode) { case SpvOpVariable: { - const struct glsl_type *type = + struct vtn_type *type = vtn_value(b, w[1], vtn_value_type_type)->type; struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_deref); nir_variable *var = ralloc(b->shader, nir_variable); - var->type = type; + var->type = type->type; var->name = ralloc_strdup(var, val->name); + bool builtin_block = false; + if (type->block) { + var->interface_type = type->type; + builtin_block = type->builtin_block; + } else if (glsl_type_is_array(type->type) && + (type->array_element->block || + type->array_element->buffer_block)) { + var->interface_type = type->array_element->type; + builtin_block = type->array_element->builtin_block; + } else { + var->interface_type = NULL; + } + switch ((SpvStorageClass)w[3]) { + case SpvStorageClassUniform: case SpvStorageClassUniformConstant: var->data.mode = nir_var_uniform; var->data.read_only = true; @@ -484,11 +1260,9 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, case SpvStorageClassFunction: var->data.mode = nir_var_local; break; - case SpvStorageClassUniform: case SpvStorageClassWorkgroupLocal: case SpvStorageClassWorkgroupGlobal: case SpvStorageClassGeneric: - case SpvStorageClassPrivate: case SpvStorageClassAtomicCounter: default: unreachable("Unhandled variable storage class"); @@ -500,15 +1274,55 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, vtn_value(b, w[4], vtn_value_type_constant)->constant; } - if (var->data.mode == nir_var_local) { - exec_list_push_tail(&b->impl->locals, &var->node); - } else { - exec_list_push_tail(&b->shader->globals, &var->node); - } - - val->deref = nir_deref_var_create(b->shader, var); + val->deref = nir_deref_var_create(b, var); + val->deref_type = type; vtn_foreach_decoration(b, val, var_decoration_cb, var); + + if (b->execution_model == SpvExecutionModelFragment && + var->data.mode == nir_var_shader_out) { + var->data.location += FRAG_RESULT_DATA0; + } else if (b->execution_model == SpvExecutionModelVertex && + var->data.mode == nir_var_shader_in) { + var->data.location += VERT_ATTRIB_GENERIC0; + } else if (var->data.mode == nir_var_shader_in || + var->data.mode == nir_var_shader_out) { + var->data.location += VARYING_SLOT_VAR0; + } + + /* If this was a uniform block, then we're not going to actually use the + * variable (we're only going to use it to compute offsets), so don't + * declare it in the shader. + */ + if (var->data.mode == nir_var_uniform && var->interface_type) + break; + + /* Builtin blocks are lowered to individual variables during SPIR-V -> + * NIR, so don't declare them either. + */ + if (builtin_block) + break; + + switch (var->data.mode) { + case nir_var_shader_in: + exec_list_push_tail(&b->shader->inputs, &var->node); + break; + case nir_var_shader_out: + exec_list_push_tail(&b->shader->outputs, &var->node); + break; + case nir_var_global: + exec_list_push_tail(&b->shader->globals, &var->node); + break; + case nir_var_local: + exec_list_push_tail(&b->impl->locals, &var->node); + break; + case nir_var_uniform: + exec_list_push_tail(&b->shader->uniforms, &var->node); + break; + case nir_var_system_value: + exec_list_push_tail(&b->shader->system_values, &var->node); + break; + } break; } @@ -517,6 +1331,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_deref); nir_deref_var *base = vtn_value(b, w[3], vtn_value_type_deref)->deref; val->deref = nir_deref_as_var(nir_copy_deref(b, &base->deref)); + struct vtn_type *deref_type = vtn_value(b, w[3], vtn_value_type_deref)->deref_type; nir_deref *tail = &val->deref->deref; while (tail->child) @@ -535,15 +1350,17 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, case GLSL_TYPE_BOOL: case GLSL_TYPE_ARRAY: { nir_deref_array *deref_arr = nir_deref_array_create(b); - if (base_type == GLSL_TYPE_ARRAY) { - deref_arr->deref.type = glsl_get_array_element(tail->type); - } else if (glsl_type_is_matrix(tail->type)) { - deref_arr->deref.type = glsl_get_column_type(tail->type); + if (base_type == GLSL_TYPE_ARRAY || + glsl_type_is_matrix(tail->type)) { + deref_type = deref_type->array_element; } else { assert(glsl_type_is_vector(tail->type)); - deref_arr->deref.type = glsl_scalar_type(base_type); + deref_type = ralloc(b, struct vtn_type); + deref_type->type = glsl_scalar_type(base_type); } + deref_arr->deref.type = deref_type->type; + if (idx_val->value_type == vtn_value_type_constant) { unsigned idx = idx_val->constant->value.u[0]; deref_arr->deref_array_type = nir_deref_array_type_direct; @@ -552,7 +1369,8 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, assert(idx_val->value_type == vtn_value_type_ssa); deref_arr->deref_array_type = nir_deref_array_type_indirect; deref_arr->base_offset = 0; - deref_arr->indirect = nir_src_for_ssa(vtn_ssa_value(b, w[1])); + deref_arr->indirect = + nir_src_for_ssa(vtn_ssa_value(b, w[1])->def); } tail->child = &deref_arr->deref; break; @@ -561,8 +1379,9 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, case GLSL_TYPE_STRUCT: { assert(idx_val->value_type == vtn_value_type_constant); unsigned idx = idx_val->constant->value.u[0]; + deref_type = deref_type->members[idx]; nir_deref_struct *deref_struct = nir_deref_struct_create(b, idx); - deref_struct->deref.type = glsl_get_struct_field(tail->type, idx); + deref_struct->deref.type = deref_type->type; tail->child = &deref_struct->deref; break; } @@ -571,93 +1390,57 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode, } tail = tail->child; } + + /* For uniform blocks, we don't resolve the access chain until we + * actually access the variable, so we need to keep around the original + * type of the variable. + */ + if (base->var->interface_type && base->var->data.mode == nir_var_uniform) + val->deref_type = vtn_value(b, w[3], vtn_value_type_deref)->deref_type; + else + val->deref_type = deref_type; + + break; } case SpvOpCopyMemory: { nir_deref_var *dest = vtn_value(b, w[1], vtn_value_type_deref)->deref; nir_deref_var *src = vtn_value(b, w[2], vtn_value_type_deref)->deref; + struct vtn_type *type = + vtn_value(b, w[1], vtn_value_type_deref)->deref_type; - nir_intrinsic_instr *copy = - nir_intrinsic_instr_create(b->shader, nir_intrinsic_copy_var); - copy->variables[0] = nir_deref_as_var(nir_copy_deref(copy, &dest->deref)); - copy->variables[1] = nir_deref_as_var(nir_copy_deref(copy, &src->deref)); - - nir_builder_instr_insert(&b->nb, ©->instr); + vtn_variable_copy(b, src, dest, type); break; } case SpvOpLoad: { nir_deref_var *src = vtn_value(b, w[3], vtn_value_type_deref)->deref; - const struct glsl_type *src_type = nir_deref_tail(&src->deref)->type; + struct vtn_type *src_type = + vtn_value(b, w[3], vtn_value_type_deref)->deref_type; - if (glsl_get_base_type(src_type) == GLSL_TYPE_SAMPLER) { + if (glsl_get_base_type(src_type->type) == GLSL_TYPE_SAMPLER) { vtn_push_value(b, w[2], vtn_value_type_deref)->deref = src; return; } - assert(glsl_type_is_vector_or_scalar(src_type)); struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); - - nir_intrinsic_instr *load = - nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_var); - load->variables[0] = nir_deref_as_var(nir_copy_deref(load, &src->deref)); - load->num_components = glsl_get_vector_elements(src_type); - nir_ssa_dest_init(&load->instr, &load->dest, load->num_components, - val->name); - - nir_builder_instr_insert(&b->nb, &load->instr); - val->type = src_type; - - if (src->var->data.mode == nir_var_uniform && - glsl_get_base_type(src_type) == GLSL_TYPE_BOOL) { - /* Uniform boolean loads need to be fixed up since they're defined - * to be zero/nonzero rather than NIR_FALSE/NIR_TRUE. - */ - val->ssa = nir_ine(&b->nb, &load->dest.ssa, nir_imm_int(&b->nb, 0)); - } else { - val->ssa = &load->dest.ssa; - } + val->ssa = vtn_variable_load(b, src, src_type); break; } case SpvOpStore: { nir_deref_var *dest = vtn_value(b, w[1], vtn_value_type_deref)->deref; - const struct glsl_type *dest_type = nir_deref_tail(&dest->deref)->type; - struct vtn_value *src_val = vtn_untyped_value(b, w[2]); - if (src_val->value_type == vtn_value_type_ssa) { - assert(glsl_type_is_vector_or_scalar(dest_type)); - nir_intrinsic_instr *store = - nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_var); - store->src[0] = nir_src_for_ssa(src_val->ssa); - store->variables[0] = nir_deref_as_var(nir_copy_deref(store, &dest->deref)); - store->num_components = glsl_get_vector_elements(dest_type); - - nir_builder_instr_insert(&b->nb, &store->instr); - } else { - assert(src_val->value_type == vtn_value_type_constant); - - nir_variable *const_tmp = rzalloc(b->shader, nir_variable); - const_tmp->type = dest_type; - const_tmp->name = "const_temp"; - const_tmp->data.mode = nir_var_local; - const_tmp->data.read_only = true; - exec_list_push_tail(&b->impl->locals, &const_tmp->node); - - nir_intrinsic_instr *copy = - nir_intrinsic_instr_create(b->shader, nir_intrinsic_copy_var); - copy->variables[0] = nir_deref_as_var(nir_copy_deref(copy, &dest->deref)); - copy->variables[1] = nir_deref_var_create(copy, const_tmp); - - nir_builder_instr_insert(&b->nb, ©->instr); - } + struct vtn_type *dest_type = + vtn_value(b, w[1], vtn_value_type_deref)->deref_type; + struct vtn_ssa_value *src = vtn_ssa_value(b, w[2]); + vtn_variable_store(b, src, dest, dest_type); break; } - case SpvOpVariableArray: case SpvOpCopyMemorySized: case SpvOpArrayLength: - case SpvOpImagePointer: + case SpvOpImageTexelPointer: default: unreachable("Unhandled opcode"); } @@ -670,11 +1453,48 @@ vtn_handle_function_call(struct vtn_builder *b, SpvOp opcode, unreachable("Unhandled opcode"); } +static struct vtn_ssa_value * +vtn_create_ssa_value(struct vtn_builder *b, const struct glsl_type *type) +{ + struct vtn_ssa_value *val = rzalloc(b, struct vtn_ssa_value); + val->type = type; + + if (!glsl_type_is_vector_or_scalar(type)) { + unsigned elems = glsl_get_length(type); + val->elems = ralloc_array(b, struct vtn_ssa_value *, elems); + for (unsigned i = 0; i < elems; i++) { + const struct glsl_type *child_type; + + switch (glsl_get_base_type(type)) { + case GLSL_TYPE_INT: + case GLSL_TYPE_UINT: + case GLSL_TYPE_BOOL: + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_DOUBLE: + child_type = glsl_get_column_type(type); + break; + case GLSL_TYPE_ARRAY: + child_type = glsl_get_array_element(type); + break; + case GLSL_TYPE_STRUCT: + child_type = glsl_get_struct_field(type, i); + break; + default: + unreachable("unkown base type"); + } + + val->elems[i] = vtn_create_ssa_value(b, child_type); + } + } + + return val; +} + static nir_tex_src vtn_tex_src(struct vtn_builder *b, unsigned index, nir_tex_src_type type) { nir_tex_src src; - src.src = nir_src_for_ssa(vtn_value(b, index, vtn_value_type_ssa)->ssa); + src.src = nir_src_for_ssa(vtn_value(b, index, vtn_value_type_ssa)->ssa->def); src.src_type = type; return src; } @@ -689,80 +1509,67 @@ vtn_handle_texture(struct vtn_builder *b, SpvOp opcode, nir_tex_src srcs[8]; /* 8 should be enough */ nir_tex_src *p = srcs; + unsigned idx = 4; + unsigned coord_components = 0; switch (opcode) { - case SpvOpTextureSample: - case SpvOpTextureSampleDref: - case SpvOpTextureSampleLod: - case SpvOpTextureSampleProj: - case SpvOpTextureSampleGrad: - case SpvOpTextureSampleOffset: - case SpvOpTextureSampleProjLod: - case SpvOpTextureSampleProjGrad: - case SpvOpTextureSampleLodOffset: - case SpvOpTextureSampleProjOffset: - case SpvOpTextureSampleGradOffset: - case SpvOpTextureSampleProjLodOffset: - case SpvOpTextureSampleProjGradOffset: - case SpvOpTextureFetchTexelLod: - case SpvOpTextureFetchTexelOffset: - case SpvOpTextureFetchSample: - case SpvOpTextureFetchTexel: - case SpvOpTextureGather: - case SpvOpTextureGatherOffset: - case SpvOpTextureGatherOffsets: - case SpvOpTextureQueryLod: { + case SpvOpImageSampleImplicitLod: + case SpvOpImageSampleExplicitLod: + case SpvOpImageSampleDrefImplicitLod: + case SpvOpImageSampleDrefExplicitLod: + case SpvOpImageSampleProjImplicitLod: + case SpvOpImageSampleProjExplicitLod: + case SpvOpImageSampleProjDrefImplicitLod: + case SpvOpImageSampleProjDrefExplicitLod: + case SpvOpImageFetch: + case SpvOpImageGather: + case SpvOpImageDrefGather: + case SpvOpImageQueryLod: { /* All these types have the coordinate as their first real argument */ - struct vtn_value *coord = vtn_value(b, w[4], vtn_value_type_ssa); + struct vtn_ssa_value *coord = vtn_ssa_value(b, w[idx++]); coord_components = glsl_get_vector_elements(coord->type); - p->src = nir_src_for_ssa(coord->ssa); + p->src = nir_src_for_ssa(coord->def); p->src_type = nir_tex_src_coord; p++; break; } + default: break; } nir_texop texop; switch (opcode) { - case SpvOpTextureSample: + case SpvOpImageSampleImplicitLod: texop = nir_texop_tex; - - if (count == 6) { - texop = nir_texop_txb; - *p++ = vtn_tex_src(b, w[5], nir_tex_src_bias); - } break; - case SpvOpTextureSampleDref: - case SpvOpTextureSampleLod: - case SpvOpTextureSampleProj: - case SpvOpTextureSampleGrad: - case SpvOpTextureSampleOffset: - case SpvOpTextureSampleProjLod: - case SpvOpTextureSampleProjGrad: - case SpvOpTextureSampleLodOffset: - case SpvOpTextureSampleProjOffset: - case SpvOpTextureSampleGradOffset: - case SpvOpTextureSampleProjLodOffset: - case SpvOpTextureSampleProjGradOffset: - case SpvOpTextureFetchTexelLod: - case SpvOpTextureFetchTexelOffset: - case SpvOpTextureFetchSample: - case SpvOpTextureFetchTexel: - case SpvOpTextureGather: - case SpvOpTextureGatherOffset: - case SpvOpTextureGatherOffsets: - case SpvOpTextureQuerySizeLod: - case SpvOpTextureQuerySize: - case SpvOpTextureQueryLod: - case SpvOpTextureQueryLevels: - case SpvOpTextureQuerySamples: + case SpvOpImageSampleExplicitLod: + case SpvOpImageSampleDrefImplicitLod: + case SpvOpImageSampleDrefExplicitLod: + case SpvOpImageSampleProjImplicitLod: + case SpvOpImageSampleProjExplicitLod: + case SpvOpImageSampleProjDrefImplicitLod: + case SpvOpImageSampleProjDrefExplicitLod: + case SpvOpImageFetch: + case SpvOpImageGather: + case SpvOpImageDrefGather: + case SpvOpImageQuerySizeLod: + case SpvOpImageQuerySize: + case SpvOpImageQueryLod: + case SpvOpImageQueryLevels: + case SpvOpImageQuerySamples: default: unreachable("Unhandled opcode"); } + /* From now on, the remaining sources are "Optional Image Operands." */ + if (idx < count) { + /* XXX handle these (bias, lod, etc.) */ + assert(0); + } + + nir_tex_instr *instr = nir_tex_instr_create(b->shader, p - srcs); const struct glsl_type *sampler_type = nir_deref_tail(&sampler->deref)->type; @@ -783,19 +1590,237 @@ vtn_handle_texture(struct vtn_builder *b, SpvOp opcode, instr->is_array = glsl_sampler_type_is_array(sampler_type); instr->is_shadow = glsl_sampler_type_is_shadow(sampler_type); - instr->sampler = sampler; + instr->sampler = nir_deref_as_var(nir_copy_deref(instr, &sampler->deref)); nir_ssa_dest_init(&instr->instr, &instr->dest, 4, NULL); - val->ssa = &instr->dest.ssa; + val->ssa = vtn_create_ssa_value(b, glsl_vector_type(GLSL_TYPE_FLOAT, 4)); + val->ssa->def = &instr->dest.ssa; nir_builder_instr_insert(&b->nb, &instr->instr); } + +static nir_alu_instr * +create_vec(void *mem_ctx, unsigned num_components) +{ + nir_op op; + switch (num_components) { + case 1: op = nir_op_fmov; break; + case 2: op = nir_op_vec2; break; + case 3: op = nir_op_vec3; break; + case 4: op = nir_op_vec4; break; + default: unreachable("bad vector size"); + } + + nir_alu_instr *vec = nir_alu_instr_create(mem_ctx, op); + nir_ssa_dest_init(&vec->instr, &vec->dest.dest, num_components, NULL); + vec->dest.write_mask = (1 << num_components) - 1; + + return vec; +} + +static struct vtn_ssa_value * +vtn_transpose(struct vtn_builder *b, struct vtn_ssa_value *src) +{ + if (src->transposed) + return src->transposed; + + struct vtn_ssa_value *dest = + vtn_create_ssa_value(b, glsl_transposed_type(src->type)); + + for (unsigned i = 0; i < glsl_get_matrix_columns(dest->type); i++) { + nir_alu_instr *vec = create_vec(b, glsl_get_matrix_columns(src->type)); + if (glsl_type_is_vector_or_scalar(src->type)) { + vec->src[0].src = nir_src_for_ssa(src->def); + vec->src[0].swizzle[0] = i; + } else { + for (unsigned j = 0; j < glsl_get_matrix_columns(src->type); j++) { + vec->src[j].src = nir_src_for_ssa(src->elems[j]->def); + vec->src[j].swizzle[0] = i; + } + } + nir_builder_instr_insert(&b->nb, &vec->instr); + dest->elems[i]->def = &vec->dest.dest.ssa; + } + + dest->transposed = src; + + return dest; +} + +/* + * Normally, column vectors in SPIR-V correspond to a single NIR SSA + * definition. But for matrix multiplies, we want to do one routine for + * multiplying a matrix by a matrix and then pretend that vectors are matrices + * with one column. So we "wrap" these things, and unwrap the result before we + * send it off. + */ + +static struct vtn_ssa_value * +vtn_wrap_matrix(struct vtn_builder *b, struct vtn_ssa_value *val) +{ + if (val == NULL) + return NULL; + + if (glsl_type_is_matrix(val->type)) + return val; + + struct vtn_ssa_value *dest = rzalloc(b, struct vtn_ssa_value); + dest->type = val->type; + dest->elems = ralloc_array(b, struct vtn_ssa_value *, 1); + dest->elems[0] = val; + + return dest; +} + +static struct vtn_ssa_value * +vtn_unwrap_matrix(struct vtn_ssa_value *val) +{ + if (glsl_type_is_matrix(val->type)) + return val; + + return val->elems[0]; +} + +static struct vtn_ssa_value * +vtn_matrix_multiply(struct vtn_builder *b, + struct vtn_ssa_value *_src0, struct vtn_ssa_value *_src1) +{ + + struct vtn_ssa_value *src0 = vtn_wrap_matrix(b, _src0); + struct vtn_ssa_value *src1 = vtn_wrap_matrix(b, _src1); + struct vtn_ssa_value *src0_transpose = vtn_wrap_matrix(b, _src0->transposed); + struct vtn_ssa_value *src1_transpose = vtn_wrap_matrix(b, _src1->transposed); + + unsigned src0_rows = glsl_get_vector_elements(src0->type); + unsigned src0_columns = glsl_get_matrix_columns(src0->type); + unsigned src1_columns = glsl_get_matrix_columns(src1->type); + + struct vtn_ssa_value *dest = + vtn_create_ssa_value(b, glsl_matrix_type(glsl_get_base_type(src0->type), + src0_rows, src1_columns)); + + dest = vtn_wrap_matrix(b, dest); + + bool transpose_result = false; + if (src0_transpose && src1_transpose) { + /* transpose(A) * transpose(B) = transpose(B * A) */ + src1 = src0_transpose; + src0 = src1_transpose; + src0_transpose = NULL; + src1_transpose = NULL; + transpose_result = true; + } + + if (src0_transpose && !src1_transpose && + glsl_get_base_type(src0->type) == GLSL_TYPE_FLOAT) { + /* We already have the rows of src0 and the columns of src1 available, + * so we can just take the dot product of each row with each column to + * get the result. + */ + + for (unsigned i = 0; i < src1_columns; i++) { + nir_alu_instr *vec = create_vec(b, src0_rows); + for (unsigned j = 0; j < src0_rows; j++) { + vec->src[j].src = + nir_src_for_ssa(nir_fdot(&b->nb, src0_transpose->elems[j]->def, + src1->elems[i]->def)); + } + + nir_builder_instr_insert(&b->nb, &vec->instr); + dest->elems[i]->def = &vec->dest.dest.ssa; + } + } else { + /* We don't handle the case where src1 is transposed but not src0, since + * the general case only uses individual components of src1 so the + * optimizer should chew through the transpose we emitted for src1. + */ + + for (unsigned i = 0; i < src1_columns; i++) { + /* dest[i] = sum(src0[j] * src1[i][j] for all j) */ + dest->elems[i]->def = + nir_fmul(&b->nb, src0->elems[0]->def, + vtn_vector_extract(b, src1->elems[i]->def, 0)); + for (unsigned j = 1; j < src0_columns; j++) { + dest->elems[i]->def = + nir_fadd(&b->nb, dest->elems[i]->def, + nir_fmul(&b->nb, src0->elems[j]->def, + vtn_vector_extract(b, + src1->elems[i]->def, j))); + } + } + } + + dest = vtn_unwrap_matrix(dest); + + if (transpose_result) + dest = vtn_transpose(b, dest); + + return dest; +} + +static struct vtn_ssa_value * +vtn_mat_times_scalar(struct vtn_builder *b, + struct vtn_ssa_value *mat, + nir_ssa_def *scalar) +{ + struct vtn_ssa_value *dest = vtn_create_ssa_value(b, mat->type); + for (unsigned i = 0; i < glsl_get_matrix_columns(mat->type); i++) { + if (glsl_get_base_type(mat->type) == GLSL_TYPE_FLOAT) + dest->elems[i]->def = nir_fmul(&b->nb, mat->elems[i]->def, scalar); + else + dest->elems[i]->def = nir_imul(&b->nb, mat->elems[i]->def, scalar); + } + + return dest; +} + static void vtn_handle_matrix_alu(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) { - unreachable("Matrix math not handled"); + struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); + + switch (opcode) { + case SpvOpTranspose: { + struct vtn_ssa_value *src = vtn_ssa_value(b, w[3]); + val->ssa = vtn_transpose(b, src); + break; + } + + case SpvOpOuterProduct: { + struct vtn_ssa_value *src0 = vtn_ssa_value(b, w[3]); + struct vtn_ssa_value *src1 = vtn_ssa_value(b, w[4]); + + val->ssa = vtn_matrix_multiply(b, src0, vtn_transpose(b, src1)); + break; + } + + case SpvOpMatrixTimesScalar: { + struct vtn_ssa_value *mat = vtn_ssa_value(b, w[3]); + struct vtn_ssa_value *scalar = vtn_ssa_value(b, w[4]); + + if (mat->transposed) { + val->ssa = vtn_transpose(b, vtn_mat_times_scalar(b, mat->transposed, + scalar->def)); + } else { + val->ssa = vtn_mat_times_scalar(b, mat, scalar->def); + } + break; + } + + case SpvOpVectorTimesMatrix: + case SpvOpMatrixTimesVector: + case SpvOpMatrixTimesMatrix: { + struct vtn_ssa_value *src0 = vtn_ssa_value(b, w[3]); + struct vtn_ssa_value *src1 = vtn_ssa_value(b, w[4]); + + val->ssa = vtn_matrix_multiply(b, src0, src1); + break; + } + + default: unreachable("unknown matrix opcode"); + } } static void @@ -803,13 +1828,15 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) { struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); - val->type = vtn_value(b, w[1], vtn_value_type_type)->type; + const struct glsl_type *type = + vtn_value(b, w[1], vtn_value_type_type)->type->type; + val->ssa = vtn_create_ssa_value(b, type); /* Collect the various SSA sources */ unsigned num_inputs = count - 3; nir_ssa_def *src[4]; for (unsigned i = 0; i < num_inputs; i++) - src[i] = vtn_ssa_value(b, w[i + 3]); + src[i] = vtn_ssa_value(b, w[i + 3])->def; /* Indicates that the first two arguments should be swapped. This is * used for implementing greater-than and less-than-or-equal. @@ -868,7 +1895,8 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, case SpvOpShiftRightArithmetic: op = nir_op_ishr; break; case SpvOpShiftLeftLogical: op = nir_op_ishl; break; case SpvOpLogicalOr: op = nir_op_ior; break; - case SpvOpLogicalXor: op = nir_op_ixor; break; + case SpvOpLogicalEqual: op = nir_op_ieq; break; + case SpvOpLogicalNotEqual: op = nir_op_ine; break; case SpvOpLogicalAnd: op = nir_op_iand; break; case SpvOpBitwiseOr: op = nir_op_ior; break; case SpvOpBitwiseXor: op = nir_op_ixor; break; @@ -921,24 +1949,24 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, case SpvOpDPdxCoarse: op = nir_op_fddx_coarse; break; case SpvOpDPdyCoarse: op = nir_op_fddy_coarse; break; case SpvOpFwidth: - val->ssa = nir_fadd(&b->nb, - nir_fabs(&b->nb, nir_fddx(&b->nb, src[0])), - nir_fabs(&b->nb, nir_fddx(&b->nb, src[1]))); + val->ssa->def = nir_fadd(&b->nb, + nir_fabs(&b->nb, nir_fddx(&b->nb, src[0])), + nir_fabs(&b->nb, nir_fddx(&b->nb, src[1]))); return; case SpvOpFwidthFine: - val->ssa = nir_fadd(&b->nb, - nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[0])), - nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[1]))); + val->ssa->def = nir_fadd(&b->nb, + nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[0])), + nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[1]))); return; case SpvOpFwidthCoarse: - val->ssa = nir_fadd(&b->nb, - nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[0])), - nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[1]))); + val->ssa->def = nir_fadd(&b->nb, + nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[0])), + nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[1]))); return; case SpvOpVectorTimesScalar: /* The builder will take care of splatting for us. */ - val->ssa = nir_fmul(&b->nb, src[0], src[1]); + val->ssa->def = nir_fmul(&b->nb, src[0], src[1]); return; case SpvOpSRem: @@ -965,8 +1993,9 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, nir_alu_instr *instr = nir_alu_instr_create(b->shader, op); nir_ssa_dest_init(&instr->instr, &instr->dest.dest, - glsl_get_vector_elements(val->type), val->name); - val->ssa = &instr->dest.dest.ssa; + glsl_get_vector_elements(type), val->name); + instr->dest.write_mask = (1 << glsl_get_vector_elements(type)) - 1; + val->ssa->def = &instr->dest.dest.ssa; for (unsigned i = 0; i < nir_op_infos[op].num_inputs; i++) instr->src[i].src = nir_src_for_ssa(src[i]); @@ -974,6 +2003,350 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode, nir_builder_instr_insert(&b->nb, &instr->instr); } +static nir_ssa_def * +vtn_vector_extract(struct vtn_builder *b, nir_ssa_def *src, unsigned index) +{ + unsigned swiz[4] = { index }; + return nir_swizzle(&b->nb, src, swiz, 1, true); +} + + +static nir_ssa_def * +vtn_vector_insert(struct vtn_builder *b, nir_ssa_def *src, nir_ssa_def *insert, + unsigned index) +{ + nir_alu_instr *vec = create_vec(b->shader, src->num_components); + + for (unsigned i = 0; i < src->num_components; i++) { + if (i == index) { + vec->src[i].src = nir_src_for_ssa(insert); + } else { + vec->src[i].src = nir_src_for_ssa(src); + vec->src[i].swizzle[0] = i; + } + } + + nir_builder_instr_insert(&b->nb, &vec->instr); + + return &vec->dest.dest.ssa; +} + +static nir_ssa_def * +vtn_vector_extract_dynamic(struct vtn_builder *b, nir_ssa_def *src, + nir_ssa_def *index) +{ + nir_ssa_def *dest = vtn_vector_extract(b, src, 0); + for (unsigned i = 1; i < src->num_components; i++) + dest = nir_bcsel(&b->nb, nir_ieq(&b->nb, index, nir_imm_int(&b->nb, i)), + vtn_vector_extract(b, src, i), dest); + + return dest; +} + +static nir_ssa_def * +vtn_vector_insert_dynamic(struct vtn_builder *b, nir_ssa_def *src, + nir_ssa_def *insert, nir_ssa_def *index) +{ + nir_ssa_def *dest = vtn_vector_insert(b, src, insert, 0); + for (unsigned i = 1; i < src->num_components; i++) + dest = nir_bcsel(&b->nb, nir_ieq(&b->nb, index, nir_imm_int(&b->nb, i)), + vtn_vector_insert(b, src, insert, i), dest); + + return dest; +} + +static nir_ssa_def * +vtn_vector_shuffle(struct vtn_builder *b, unsigned num_components, + nir_ssa_def *src0, nir_ssa_def *src1, + const uint32_t *indices) +{ + nir_alu_instr *vec = create_vec(b->shader, num_components); + + nir_ssa_undef_instr *undef = nir_ssa_undef_instr_create(b->shader, 1); + nir_builder_instr_insert(&b->nb, &undef->instr); + + for (unsigned i = 0; i < num_components; i++) { + uint32_t index = indices[i]; + if (index == 0xffffffff) { + vec->src[i].src = nir_src_for_ssa(&undef->def); + } else if (index < src0->num_components) { + vec->src[i].src = nir_src_for_ssa(src0); + vec->src[i].swizzle[0] = index; + } else { + vec->src[i].src = nir_src_for_ssa(src1); + vec->src[i].swizzle[0] = index - src0->num_components; + } + } + + nir_builder_instr_insert(&b->nb, &vec->instr); + + return &vec->dest.dest.ssa; +} + +/* + * Concatentates a number of vectors/scalars together to produce a vector + */ +static nir_ssa_def * +vtn_vector_construct(struct vtn_builder *b, unsigned num_components, + unsigned num_srcs, nir_ssa_def **srcs) +{ + nir_alu_instr *vec = create_vec(b->shader, num_components); + + unsigned dest_idx = 0; + for (unsigned i = 0; i < num_srcs; i++) { + nir_ssa_def *src = srcs[i]; + for (unsigned j = 0; j < src->num_components; j++) { + vec->src[dest_idx].src = nir_src_for_ssa(src); + vec->src[dest_idx].swizzle[0] = j; + dest_idx++; + } + } + + nir_builder_instr_insert(&b->nb, &vec->instr); + + return &vec->dest.dest.ssa; +} + +static struct vtn_ssa_value * +vtn_composite_copy(void *mem_ctx, struct vtn_ssa_value *src) +{ + struct vtn_ssa_value *dest = rzalloc(mem_ctx, struct vtn_ssa_value); + dest->type = src->type; + + if (glsl_type_is_vector_or_scalar(src->type)) { + dest->def = src->def; + } else { + unsigned elems = glsl_get_length(src->type); + + dest->elems = ralloc_array(mem_ctx, struct vtn_ssa_value *, elems); + for (unsigned i = 0; i < elems; i++) + dest->elems[i] = vtn_composite_copy(mem_ctx, src->elems[i]); + } + + return dest; +} + +static struct vtn_ssa_value * +vtn_composite_insert(struct vtn_builder *b, struct vtn_ssa_value *src, + struct vtn_ssa_value *insert, const uint32_t *indices, + unsigned num_indices) +{ + struct vtn_ssa_value *dest = vtn_composite_copy(b, src); + + struct vtn_ssa_value *cur = dest; + unsigned i; + for (i = 0; i < num_indices - 1; i++) { + cur = cur->elems[indices[i]]; + } + + if (glsl_type_is_vector_or_scalar(cur->type)) { + /* According to the SPIR-V spec, OpCompositeInsert may work down to + * the component granularity. In that case, the last index will be + * the index to insert the scalar into the vector. + */ + + cur->def = vtn_vector_insert(b, cur->def, insert->def, indices[i]); + } else { + cur->elems[indices[i]] = insert; + } + + return dest; +} + +static struct vtn_ssa_value * +vtn_composite_extract(struct vtn_builder *b, struct vtn_ssa_value *src, + const uint32_t *indices, unsigned num_indices) +{ + struct vtn_ssa_value *cur = src; + for (unsigned i = 0; i < num_indices; i++) { + if (glsl_type_is_vector_or_scalar(cur->type)) { + assert(i == num_indices - 1); + /* According to the SPIR-V spec, OpCompositeExtract may work down to + * the component granularity. The last index will be the index of the + * vector to extract. + */ + + struct vtn_ssa_value *ret = rzalloc(b, struct vtn_ssa_value); + ret->type = glsl_scalar_type(glsl_get_base_type(cur->type)); + ret->def = vtn_vector_extract(b, cur->def, indices[i]); + return ret; + } + } + + return cur; +} + +static void +vtn_handle_composite(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) +{ + struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); + const struct glsl_type *type = + vtn_value(b, w[1], vtn_value_type_type)->type->type; + val->ssa = vtn_create_ssa_value(b, type); + + switch (opcode) { + case SpvOpVectorExtractDynamic: + val->ssa->def = vtn_vector_extract_dynamic(b, vtn_ssa_value(b, w[3])->def, + vtn_ssa_value(b, w[4])->def); + break; + + case SpvOpVectorInsertDynamic: + val->ssa->def = vtn_vector_insert_dynamic(b, vtn_ssa_value(b, w[3])->def, + vtn_ssa_value(b, w[4])->def, + vtn_ssa_value(b, w[5])->def); + break; + + case SpvOpVectorShuffle: + val->ssa->def = vtn_vector_shuffle(b, glsl_get_vector_elements(type), + vtn_ssa_value(b, w[3])->def, + vtn_ssa_value(b, w[4])->def, + w + 5); + break; + + case SpvOpCompositeConstruct: { + unsigned elems = count - 3; + if (glsl_type_is_vector_or_scalar(type)) { + nir_ssa_def *srcs[4]; + for (unsigned i = 0; i < elems; i++) + srcs[i] = vtn_ssa_value(b, w[3 + i])->def; + val->ssa->def = + vtn_vector_construct(b, glsl_get_vector_elements(type), + elems, srcs); + } else { + val->ssa->elems = ralloc_array(b, struct vtn_ssa_value *, elems); + for (unsigned i = 0; i < elems; i++) + val->ssa->elems[i] = vtn_ssa_value(b, w[3 + i]); + } + break; + } + case SpvOpCompositeExtract: + val->ssa = vtn_composite_extract(b, vtn_ssa_value(b, w[3]), + w + 4, count - 4); + break; + + case SpvOpCompositeInsert: + val->ssa = vtn_composite_insert(b, vtn_ssa_value(b, w[4]), + vtn_ssa_value(b, w[3]), + w + 5, count - 5); + break; + + case SpvOpCopyObject: + val->ssa = vtn_composite_copy(b, vtn_ssa_value(b, w[3])); + break; + + default: + unreachable("unknown composite operation"); + } +} + +static void +vtn_phi_node_init(struct vtn_builder *b, struct vtn_ssa_value *val) +{ + if (glsl_type_is_vector_or_scalar(val->type)) { + nir_phi_instr *phi = nir_phi_instr_create(b->shader); + nir_ssa_dest_init(&phi->instr, &phi->dest, + glsl_get_vector_elements(val->type), NULL); + exec_list_make_empty(&phi->srcs); + nir_builder_instr_insert(&b->nb, &phi->instr); + val->def = &phi->dest.ssa; + } else { + unsigned elems = glsl_get_length(val->type); + for (unsigned i = 0; i < elems; i++) + vtn_phi_node_init(b, val->elems[i]); + } +} + +static struct vtn_ssa_value * +vtn_phi_node_create(struct vtn_builder *b, const struct glsl_type *type) +{ + struct vtn_ssa_value *val = vtn_create_ssa_value(b, type); + vtn_phi_node_init(b, val); + return val; +} + +static void +vtn_handle_phi_first_pass(struct vtn_builder *b, const uint32_t *w) +{ + struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa); + const struct glsl_type *type = + vtn_value(b, w[1], vtn_value_type_type)->type->type; + val->ssa = vtn_phi_node_create(b, type); +} + +static void +vtn_phi_node_add_src(struct vtn_ssa_value *phi, const nir_block *pred, + struct vtn_ssa_value *val) +{ + assert(phi->type == val->type); + if (glsl_type_is_vector_or_scalar(phi->type)) { + nir_phi_instr *phi_instr = nir_instr_as_phi(phi->def->parent_instr); + nir_phi_src *src = ralloc(phi_instr, nir_phi_src); + src->pred = (nir_block *) pred; + src->src = nir_src_for_ssa(val->def); + exec_list_push_tail(&phi_instr->srcs, &src->node); + } else { + unsigned elems = glsl_get_length(phi->type); + for (unsigned i = 0; i < elems; i++) + vtn_phi_node_add_src(phi->elems[i], pred, val->elems[i]); + } +} + +static struct vtn_ssa_value * +vtn_get_phi_node_src(struct vtn_builder *b, nir_block *block, + const struct glsl_type *type, const uint32_t *w, + unsigned count) +{ + struct hash_entry *entry = _mesa_hash_table_search(b->block_table, block); + if (entry) { + struct vtn_block *spv_block = entry->data; + for (unsigned off = 4; off < count; off += 2) { + if (spv_block == vtn_value(b, w[off], vtn_value_type_block)->block) { + return vtn_ssa_value(b, w[off - 1]); + } + } + } + + b->nb.cursor = nir_before_block(block); + struct vtn_ssa_value *phi = vtn_phi_node_create(b, type); + + struct set_entry *entry2; + set_foreach(block->predecessors, entry2) { + nir_block *pred = (nir_block *) entry2->key; + struct vtn_ssa_value *val = vtn_get_phi_node_src(b, pred, type, w, + count); + vtn_phi_node_add_src(phi, pred, val); + } + + return phi; +} + +static bool +vtn_handle_phi_second_pass(struct vtn_builder *b, SpvOp opcode, + const uint32_t *w, unsigned count) +{ + if (opcode == SpvOpLabel) { + b->block = vtn_value(b, w[1], vtn_value_type_block)->block; + return true; + } + + if (opcode != SpvOpPhi) + return true; + + struct vtn_ssa_value *phi = vtn_value(b, w[2], vtn_value_type_ssa)->ssa; + + struct set_entry *entry; + set_foreach(b->block->block->predecessors, entry) { + nir_block *pred = (nir_block *) entry->key; + + struct vtn_ssa_value *val = vtn_get_phi_node_src(b, pred, phi->type, w, + count); + vtn_phi_node_add_src(phi, pred, val); + } + + return true; +} + static bool vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode, const uint32_t *w, unsigned count) @@ -981,11 +2354,19 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode, switch (opcode) { case SpvOpSource: case SpvOpSourceExtension: - case SpvOpCompileFlag: case SpvOpExtension: /* Unhandled, but these are for debug so that's ok. */ break; + case SpvOpCapability: + /* + * TODO properly handle these and give a real error if asking for too + * much. + */ + assert(w[1] == SpvCapabilityMatrix || + w[1] == SpvCapabilityShader); + break; + case SpvOpExtInstImport: vtn_handle_extension(b, opcode, w, count); break; @@ -1002,7 +2383,7 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode, break; case SpvOpExecutionMode: - unreachable("Execution modes not yet implemented"); + /* TODO */ break; case SpvOpString: @@ -1035,7 +2416,9 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode, case SpvOpTypeFloat: case SpvOpTypeVector: case SpvOpTypeMatrix: + case SpvOpTypeImage: case SpvOpTypeSampler: + case SpvOpTypeSampledImage: case SpvOpTypeArray: case SpvOpTypeRuntimeArray: case SpvOpTypeStruct: @@ -1047,8 +2430,7 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode, case SpvOpTypeReserveId: case SpvOpTypeQueue: case SpvOpTypePipe: - vtn_push_value(b, w[1], vtn_value_type_type)->type = - vtn_handle_type(b, opcode, &w[2], count - 2); + vtn_handle_type(b, opcode, w, count); break; case SpvOpConstantTrue: @@ -1056,8 +2438,6 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode, case SpvOpConstant: case SpvOpConstantComposite: case SpvOpConstantSampler: - case SpvOpConstantNullPointer: - case SpvOpConstantNullObject: case SpvOpSpecConstantTrue: case SpvOpSpecConstantFalse: case SpvOpSpecConstant: @@ -1086,10 +2466,10 @@ vtn_handle_first_cfg_pass_instruction(struct vtn_builder *b, SpvOp opcode, b->func = rzalloc(b, struct vtn_function); const struct glsl_type *result_type = - vtn_value(b, w[1], vtn_value_type_type)->type; + vtn_value(b, w[1], vtn_value_type_type)->type->type; struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_function); const struct glsl_type *func_type = - vtn_value(b, w[4], vtn_value_type_type)->type; + vtn_value(b, w[4], vtn_value_type_type)->type->type; assert(glsl_get_function_return_type(func_type) == result_type); @@ -1123,6 +2503,7 @@ vtn_handle_first_cfg_pass_instruction(struct vtn_builder *b, SpvOp opcode, } case SpvOpFunctionEnd: + b->func->end = w; b->func = NULL; break; @@ -1182,10 +2563,7 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, struct vtn_block *block = vtn_value(b, w[1], vtn_value_type_block)->block; assert(block->block == NULL); - struct exec_node *list_tail = exec_list_get_tail(b->nb.cf_node_list); - nir_cf_node *tail_node = exec_node_data(nir_cf_node, list_tail, node); - assert(tail_node->type == nir_cf_node_block); - block->block = nir_cf_node_as_block(tail_node); + block->block = nir_cursor_current_block(b->nb.cursor); break; } @@ -1203,7 +2581,6 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, break; case SpvOpVariable: - case SpvOpVariableArray: case SpvOpLoad: case SpvOpStore: case SpvOpCopyMemory: @@ -1211,7 +2588,7 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, case SpvOpAccessChain: case SpvOpInBoundsAccessChain: case SpvOpArrayLength: - case SpvOpImagePointer: + case SpvOpImageTexelPointer: vtn_handle_variables(b, opcode, w, count); break; @@ -1219,31 +2596,22 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, vtn_handle_function_call(b, opcode, w, count); break; - case SpvOpTextureSample: - case SpvOpTextureSampleDref: - case SpvOpTextureSampleLod: - case SpvOpTextureSampleProj: - case SpvOpTextureSampleGrad: - case SpvOpTextureSampleOffset: - case SpvOpTextureSampleProjLod: - case SpvOpTextureSampleProjGrad: - case SpvOpTextureSampleLodOffset: - case SpvOpTextureSampleProjOffset: - case SpvOpTextureSampleGradOffset: - case SpvOpTextureSampleProjLodOffset: - case SpvOpTextureSampleProjGradOffset: - case SpvOpTextureFetchTexelLod: - case SpvOpTextureFetchTexelOffset: - case SpvOpTextureFetchSample: - case SpvOpTextureFetchTexel: - case SpvOpTextureGather: - case SpvOpTextureGatherOffset: - case SpvOpTextureGatherOffsets: - case SpvOpTextureQuerySizeLod: - case SpvOpTextureQuerySize: - case SpvOpTextureQueryLod: - case SpvOpTextureQueryLevels: - case SpvOpTextureQuerySamples: + case SpvOpImageSampleImplicitLod: + case SpvOpImageSampleExplicitLod: + case SpvOpImageSampleDrefImplicitLod: + case SpvOpImageSampleDrefExplicitLod: + case SpvOpImageSampleProjImplicitLod: + case SpvOpImageSampleProjExplicitLod: + case SpvOpImageSampleProjDrefImplicitLod: + case SpvOpImageSampleProjDrefExplicitLod: + case SpvOpImageFetch: + case SpvOpImageGather: + case SpvOpImageDrefGather: + case SpvOpImageQuerySizeLod: + case SpvOpImageQuerySize: + case SpvOpImageQueryLod: + case SpvOpImageQueryLevels: + case SpvOpImageQuerySamples: vtn_handle_texture(b, opcode, w, count); break; @@ -1292,7 +2660,8 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, case SpvOpShiftRightArithmetic: case SpvOpShiftLeftLogical: case SpvOpLogicalOr: - case SpvOpLogicalXor: + case SpvOpLogicalEqual: + case SpvOpLogicalNotEqual: case SpvOpLogicalAnd: case SpvOpBitwiseOr: case SpvOpBitwiseXor: @@ -1341,6 +2710,20 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode, vtn_handle_matrix_alu(b, opcode, w, count); break; + case SpvOpVectorExtractDynamic: + case SpvOpVectorInsertDynamic: + case SpvOpVectorShuffle: + case SpvOpCompositeConstruct: + case SpvOpCompositeExtract: + case SpvOpCompositeInsert: + case SpvOpCopyObject: + vtn_handle_composite(b, opcode, w, count); + break; + + case SpvOpPhi: + vtn_handle_phi_first_pass(b, w); + break; + default: unreachable("Unhandled opcode"); } @@ -1355,34 +2738,23 @@ vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start, { struct vtn_block *block = start; while (block != end_block) { - if (block->block != NULL) { - /* We've already visited this block once before so this is a - * back-edge. Back-edges are only allowed to point to a loop - * merge. - */ - assert(block == cont_block); - return; - } - if (block->merge_op == SpvOpLoopMerge) { /* This is the jump into a loop. */ - cont_block = block; - break_block = vtn_value(b, block->merge_block_id, - vtn_value_type_block)->block; + struct vtn_block *new_cont_block = block; + struct vtn_block *new_break_block = + vtn_value(b, block->merge_block_id, vtn_value_type_block)->block; nir_loop *loop = nir_loop_create(b->shader); - nir_cf_node_insert_end(b->nb.cf_node_list, &loop->cf_node); - - struct exec_list *old_list = b->nb.cf_node_list; + nir_cf_node_insert(b->nb.cursor, &loop->cf_node); /* Reset the merge_op to prerevent infinite recursion */ block->merge_op = SpvOpNop; - nir_builder_insert_after_cf_list(&b->nb, &loop->body); - vtn_walk_blocks(b, block, break_block, cont_block, NULL); + b->nb.cursor = nir_after_cf_list(&loop->body); + vtn_walk_blocks(b, block, new_break_block, new_cont_block, NULL); - nir_builder_insert_after_cf_list(&b->nb, old_list); - block = break_block; + b->nb.cursor = nir_after_cf_node(&loop->cf_node); + block = new_break_block; continue; } @@ -1393,6 +2765,10 @@ vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start, vtn_foreach_instruction(b, block->label, block->branch, vtn_handle_body_instruction); + nir_block *cur_block = nir_cursor_current_block(b->nb.cursor); + assert(cur_block == block->block); + _mesa_hash_table_insert(b->block_table, cur_block, block); + switch (branch_op) { case SpvOpBranch: { struct vtn_block *branch_block = @@ -1411,8 +2787,16 @@ vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start, return; } else if (branch_block == end_block) { + /* We're branching to the merge block of an if, since for loops + * and functions end_block == NULL, so we're done here. + */ return; } else { + /* We're branching to another block, and according to the rules, + * we can only branch to another block with one predecessor (so + * we're the only one jumping to it) so we can just process it + * next. + */ block = branch_block; continue; } @@ -1426,8 +2810,8 @@ vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start, vtn_value(b, w[3], vtn_value_type_block)->block; nir_if *if_stmt = nir_if_create(b->shader); - if_stmt->condition = nir_src_for_ssa(vtn_ssa_value(b, w[1])); - nir_cf_node_insert_end(b->nb.cf_node_list, &if_stmt->cf_node); + if_stmt->condition = nir_src_for_ssa(vtn_ssa_value(b, w[1])->def); + nir_cf_node_insert(b->nb.cursor, &if_stmt->cf_node); if (then_block == break_block) { nir_jump_instr *jump = nir_jump_instr_create(b->shader, @@ -1454,20 +2838,21 @@ vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start, &jump->instr); block = then_block; } else { - /* Conventional if statement */ + /* According to the rules we're branching to two blocks that don't + * have any other predecessors, so we can handle this as a + * conventional if. + */ assert(block->merge_op == SpvOpSelectionMerge); struct vtn_block *merge_block = vtn_value(b, block->merge_block_id, vtn_value_type_block)->block; - struct exec_list *old_list = b->nb.cf_node_list; - - nir_builder_insert_after_cf_list(&b->nb, &if_stmt->then_list); + b->nb.cursor = nir_after_cf_list(&if_stmt->then_list); vtn_walk_blocks(b, then_block, break_block, cont_block, merge_block); - nir_builder_insert_after_cf_list(&b->nb, &if_stmt->else_list); + b->nb.cursor = nir_after_cf_list(&if_stmt->else_list); vtn_walk_blocks(b, else_block, break_block, cont_block, merge_block); - nir_builder_insert_after_cf_list(&b->nb, old_list); + b->nb.cursor = nir_after_cf_node(&if_stmt->cf_node); block = merge_block; continue; } @@ -1549,7 +2934,7 @@ spirv_to_nir(const uint32_t *words, size_t word_count, struct vtn_builder *b = rzalloc(NULL, struct vtn_builder); b->shader = shader; b->value_id_bound = value_id_bound; - b->values = ralloc_array(b, struct vtn_value, value_id_bound); + b->values = rzalloc_array(b, struct vtn_value, value_id_bound); exec_list_make_empty(&b->functions); /* Handle all the preamble instructions */ @@ -1562,11 +2947,22 @@ spirv_to_nir(const uint32_t *words, size_t word_count, foreach_list_typed(struct vtn_function, func, node, &b->functions) { b->impl = nir_function_impl_create(func->overload); + b->const_table = _mesa_hash_table_create(b, _mesa_hash_pointer, + _mesa_key_pointer_equal); + b->block_table = _mesa_hash_table_create(b, _mesa_hash_pointer, + _mesa_key_pointer_equal); nir_builder_init(&b->nb, b->impl); - nir_builder_insert_after_cf_list(&b->nb, &b->impl->body); + b->nb.cursor = nir_after_cf_list(&b->impl->body); vtn_walk_blocks(b, func->start_block, NULL, NULL, NULL); + vtn_foreach_instruction(b, func->start_block->label, func->end, + vtn_handle_phi_second_pass); } + /* Because we can still have output reads in NIR, we need to lower + * outputs to temporaries before we are truely finished. + */ + nir_lower_outputs_to_temporaries(shader); + ralloc_free(b); return shader; diff --git a/src/glsl/nir/spirv_to_nir_private.h b/src/glsl/nir/spirv_to_nir_private.h index d2b364bdfeb..decceff65a6 100644 --- a/src/glsl/nir/spirv_to_nir_private.h +++ b/src/glsl/nir/spirv_to_nir_private.h @@ -25,6 +25,7 @@ * */ +#include "nir.h" #include "nir_spirv.h" #include "nir_builder.h" #include "spirv.h" @@ -60,30 +61,88 @@ struct vtn_function { nir_function_overload *overload; struct vtn_block *start_block; + + const uint32_t *end; }; typedef bool (*vtn_instruction_handler)(struct vtn_builder *, uint32_t, const uint32_t *, unsigned); +struct vtn_ssa_value { + union { + nir_ssa_def *def; + struct vtn_ssa_value **elems; + }; + + /* For matrices, a transposed version of the value, or NULL if it hasn't + * been computed + */ + struct vtn_ssa_value *transposed; + + const struct glsl_type *type; +}; + +struct vtn_type { + const struct glsl_type *type; + + /* for matrices, whether the matrix is stored row-major */ + bool row_major; + + /* for structs, the offset of each member */ + unsigned *offsets; + + /* for structs, whether it was decorated as a "non-SSBO-like" block */ + bool block; + + /* for structs, whether it was decorated as an "SSBO-like" block */ + bool buffer_block; + + /* for structs with block == true, whether this is a builtin block (i.e. a + * block that contains only builtins). + */ + bool builtin_block; + + /* for arrays and matrices, the array stride */ + unsigned stride; + + /* for arrays, the vtn_type for the elements of the array */ + struct vtn_type *array_element; + + /* for structures, the vtn_type for each member */ + struct vtn_type **members; + + /* Whether this type, or a parent type, has been decorated as a builtin */ + bool is_builtin; + + SpvBuiltIn builtin; +}; + struct vtn_value { enum vtn_value_type value_type; const char *name; struct vtn_decoration *decoration; - const struct glsl_type *type; union { void *ptr; char *str; - nir_constant *constant; - nir_deref_var *deref; + struct vtn_type *type; + struct { + nir_constant *constant; + const struct glsl_type *const_type; + }; + struct { + nir_deref_var *deref; + struct vtn_type *deref_type; + }; struct vtn_function *func; struct vtn_block *block; - nir_ssa_def *ssa; + struct vtn_ssa_value *ssa; vtn_instruction_handler ext_handler; }; }; struct vtn_decoration { struct vtn_decoration *next; + int member; /* -1 if not a member decoration */ const uint32_t *literals; struct vtn_value *group; SpvDecoration decoration; @@ -96,6 +155,25 @@ struct vtn_builder { nir_function_impl *impl; struct vtn_block *block; + /* + * In SPIR-V, constants are global, whereas in NIR, the load_const + * instruction we use is per-function. So while we parse each function, we + * keep a hash table of constants we've resolved to nir_ssa_value's so + * far, and we lazily resolve them when we see them used in a function. + */ + struct hash_table *const_table; + + /* + * Map from nir_block to the vtn_block which ends with it -- used for + * handling phi nodes. + */ + struct hash_table *block_table; + + /* + * NIR variable for each SPIR-V builtin. + */ + nir_variable *builtins[42]; /* XXX need symbolic constant from SPIR-V header */ + unsigned value_id_bound; struct vtn_value *values; @@ -134,10 +212,11 @@ vtn_value(struct vtn_builder *b, uint32_t value_id, return val; } -nir_ssa_def *vtn_ssa_value(struct vtn_builder *b, uint32_t value_id); +struct vtn_ssa_value *vtn_ssa_value(struct vtn_builder *b, uint32_t value_id); typedef void (*vtn_decoration_foreach_cb)(struct vtn_builder *, struct vtn_value *, + int member, const struct vtn_decoration *, void *);