implemented SPIR-V shader export

This commit is contained in:
Perfare
2020-08-12 22:11:26 +08:00
parent 0ec29f62ca
commit 729a8a8263
17 changed files with 6720 additions and 5 deletions

View File

@ -0,0 +1,365 @@
namespace Smolv
{
public struct OpData
{
public OpData(byte hasResult, byte hasType, sbyte deltaFromResult, byte varrest)
{
this.hasResult = hasResult;
this.hasType = hasType;
this.deltaFromResult = deltaFromResult;
this.varrest = varrest;
}
/// <summary>
/// Does it have result ID?
/// </summary>
public byte hasResult;
/// <summary>
/// Does it have type ID?
/// </summary>
public byte hasType;
/// <summary>
/// How many words after (optional) type+result to write out as deltas from result?
/// </summary>
public sbyte deltaFromResult;
/// <summary>
/// Should the rest of words be written in varint encoding?
/// </summary>
public byte varrest;
public static readonly OpData[] SpirvOpData =
{
new OpData(0, 0, 0, 0), // Nop
new OpData(1, 1, 0, 0), // Undef
new OpData(0, 0, 0, 0), // SourceContinued
new OpData(0, 0, 0, 1), // Source
new OpData(0, 0, 0, 0), // SourceExtension
new OpData(0, 0, 0, 0), // Name
new OpData(0, 0, 0, 0), // MemberName
new OpData(0, 0, 0, 0), // String
new OpData(0, 0, 0, 1), // Line
new OpData(1, 1, 0, 0), // #9
new OpData(0, 0, 0, 0), // Extension
new OpData(1, 0, 0, 0), // ExtInstImport
new OpData(1, 1, 0, 1), // ExtInst
new OpData(1, 1, 2, 1), // VectorShuffleCompact - new in SMOLV
new OpData(0, 0, 0, 1), // MemoryModel
new OpData(0, 0, 0, 1), // EntryPoint
new OpData(0, 0, 0, 1), // ExecutionMode
new OpData(0, 0, 0, 1), // Capability
new OpData(1, 1, 0, 0), // #18
new OpData(1, 0, 0, 1), // TypeVoid
new OpData(1, 0, 0, 1), // TypeBool
new OpData(1, 0, 0, 1), // TypeInt
new OpData(1, 0, 0, 1), // TypeFloat
new OpData(1, 0, 0, 1), // TypeVector
new OpData(1, 0, 0, 1), // TypeMatrix
new OpData(1, 0, 0, 1), // TypeImage
new OpData(1, 0, 0, 1), // TypeSampler
new OpData(1, 0, 0, 1), // TypeSampledImage
new OpData(1, 0, 0, 1), // TypeArray
new OpData(1, 0, 0, 1), // TypeRuntimeArray
new OpData(1, 0, 0, 1), // TypeStruct
new OpData(1, 0, 0, 1), // TypeOpaque
new OpData(1, 0, 0, 1), // TypePointer
new OpData(1, 0, 0, 1), // TypeFunction
new OpData(1, 0, 0, 1), // TypeEvent
new OpData(1, 0, 0, 1), // TypeDeviceEvent
new OpData(1, 0, 0, 1), // TypeReserveId
new OpData(1, 0, 0, 1), // TypeQueue
new OpData(1, 0, 0, 1), // TypePipe
new OpData(0, 0, 0, 1), // TypeForwardPointer
new OpData(1, 1, 0, 0), // #40
new OpData(1, 1, 0, 0), // ConstantTrue
new OpData(1, 1, 0, 0), // ConstantFalse
new OpData(1, 1, 0, 0), // Constant
new OpData(1, 1, 9, 0), // ConstantComposite
new OpData(1, 1, 0, 1), // ConstantSampler
new OpData(1, 1, 0, 0), // ConstantNull
new OpData(1, 1, 0, 0), // #47
new OpData(1, 1, 0, 0), // SpecConstantTrue
new OpData(1, 1, 0, 0), // SpecConstantFalse
new OpData(1, 1, 0, 0), // SpecConstant
new OpData(1, 1, 9, 0), // SpecConstantComposite
new OpData(1, 1, 0, 0), // SpecConstantOp
new OpData(1, 1, 0, 0), // #53
new OpData(1, 1, 0, 1), // Function
new OpData(1, 1, 0, 0), // FunctionParameter
new OpData(0, 0, 0, 0), // FunctionEnd
new OpData(1, 1, 9, 0), // FunctionCall
new OpData(1, 1, 0, 0), // #58
new OpData(1, 1, 0, 1), // Variable
new OpData(1, 1, 0, 0), // ImageTexelPointer
new OpData(1, 1, 1, 1), // Load
new OpData(0, 0, 2, 1), // Store
new OpData(0, 0, 0, 0), // CopyMemory
new OpData(0, 0, 0, 0), // CopyMemorySized
new OpData(1, 1, 0, 1), // AccessChain
new OpData(1, 1, 0, 0), // InBoundsAccessChain
new OpData(1, 1, 0, 0), // PtrAccessChain
new OpData(1, 1, 0, 0), // ArrayLength
new OpData(1, 1, 0, 0), // GenericPtrMemSemantics
new OpData(1, 1, 0, 0), // InBoundsPtrAccessChain
new OpData(0, 0, 0, 1), // Decorate
new OpData(0, 0, 0, 1), // MemberDecorate
new OpData(1, 0, 0, 0), // DecorationGroup
new OpData(0, 0, 0, 0), // GroupDecorate
new OpData(0, 0, 0, 0), // GroupMemberDecorate
new OpData(1, 1, 0, 0), // #76
new OpData(1, 1, 1, 1), // VectorExtractDynamic
new OpData(1, 1, 2, 1), // VectorInsertDynamic
new OpData(1, 1, 2, 1), // VectorShuffle
new OpData(1, 1, 9, 0), // CompositeConstruct
new OpData(1, 1, 1, 1), // CompositeExtract
new OpData(1, 1, 2, 1), // CompositeInsert
new OpData(1, 1, 1, 0), // CopyObject
new OpData(1, 1, 0, 0), // Transpose
new OpData(1, 1, 0, 0), // #85
new OpData(1, 1, 0, 0), // SampledImage
new OpData(1, 1, 2, 1), // ImageSampleImplicitLod
new OpData(1, 1, 2, 1), // ImageSampleExplicitLod
new OpData(1, 1, 3, 1), // ImageSampleDrefImplicitLod
new OpData(1, 1, 3, 1), // ImageSampleDrefExplicitLod
new OpData(1, 1, 2, 1), // ImageSampleProjImplicitLod
new OpData(1, 1, 2, 1), // ImageSampleProjExplicitLod
new OpData(1, 1, 3, 1), // ImageSampleProjDrefImplicitLod
new OpData(1, 1, 3, 1), // ImageSampleProjDrefExplicitLod
new OpData(1, 1, 2, 1), // ImageFetch
new OpData(1, 1, 3, 1), // ImageGather
new OpData(1, 1, 3, 1), // ImageDrefGather
new OpData(1, 1, 2, 1), // ImageRead
new OpData(0, 0, 3, 1), // ImageWrite
new OpData(1, 1, 1, 0), // Image
new OpData(1, 1, 1, 0), // ImageQueryFormat
new OpData(1, 1, 1, 0), // ImageQueryOrder
new OpData(1, 1, 2, 0), // ImageQuerySizeLod
new OpData(1, 1, 1, 0), // ImageQuerySize
new OpData(1, 1, 2, 0), // ImageQueryLod
new OpData(1, 1, 1, 0), // ImageQueryLevels
new OpData(1, 1, 1, 0), // ImageQuerySamples
new OpData(1, 1, 0, 0), // #108
new OpData(1, 1, 1, 0), // ConvertFToU
new OpData(1, 1, 1, 0), // ConvertFToS
new OpData(1, 1, 1, 0), // ConvertSToF
new OpData(1, 1, 1, 0), // ConvertUToF
new OpData(1, 1, 1, 0), // UConvert
new OpData(1, 1, 1, 0), // SConvert
new OpData(1, 1, 1, 0), // FConvert
new OpData(1, 1, 1, 0), // QuantizeToF16
new OpData(1, 1, 1, 0), // ConvertPtrToU
new OpData(1, 1, 1, 0), // SatConvertSToU
new OpData(1, 1, 1, 0), // SatConvertUToS
new OpData(1, 1, 1, 0), // ConvertUToPtr
new OpData(1, 1, 1, 0), // PtrCastToGeneric
new OpData(1, 1, 1, 0), // GenericCastToPtr
new OpData(1, 1, 1, 1), // GenericCastToPtrExplicit
new OpData(1, 1, 1, 0), // Bitcast
new OpData(1, 1, 0, 0), // #125
new OpData(1, 1, 1, 0), // SNegate
new OpData(1, 1, 1, 0), // FNegate
new OpData(1, 1, 2, 0), // IAdd
new OpData(1, 1, 2, 0), // FAdd
new OpData(1, 1, 2, 0), // ISub
new OpData(1, 1, 2, 0), // FSub
new OpData(1, 1, 2, 0), // IMul
new OpData(1, 1, 2, 0), // FMul
new OpData(1, 1, 2, 0), // UDiv
new OpData(1, 1, 2, 0), // SDiv
new OpData(1, 1, 2, 0), // FDiv
new OpData(1, 1, 2, 0), // UMod
new OpData(1, 1, 2, 0), // SRem
new OpData(1, 1, 2, 0), // SMod
new OpData(1, 1, 2, 0), // FRem
new OpData(1, 1, 2, 0), // FMod
new OpData(1, 1, 2, 0), // VectorTimesScalar
new OpData(1, 1, 2, 0), // MatrixTimesScalar
new OpData(1, 1, 2, 0), // VectorTimesMatrix
new OpData(1, 1, 2, 0), // MatrixTimesVector
new OpData(1, 1, 2, 0), // MatrixTimesMatrix
new OpData(1, 1, 2, 0), // OuterProduct
new OpData(1, 1, 2, 0), // Dot
new OpData(1, 1, 2, 0), // IAddCarry
new OpData(1, 1, 2, 0), // ISubBorrow
new OpData(1, 1, 2, 0), // UMulExtended
new OpData(1, 1, 2, 0), // SMulExtended
new OpData(1, 1, 0, 0), // #153
new OpData(1, 1, 1, 0), // Any
new OpData(1, 1, 1, 0), // All
new OpData(1, 1, 1, 0), // IsNan
new OpData(1, 1, 1, 0), // IsInf
new OpData(1, 1, 1, 0), // IsFinite
new OpData(1, 1, 1, 0), // IsNormal
new OpData(1, 1, 1, 0), // SignBitSet
new OpData(1, 1, 2, 0), // LessOrGreater
new OpData(1, 1, 2, 0), // Ordered
new OpData(1, 1, 2, 0), // Unordered
new OpData(1, 1, 2, 0), // LogicalEqual
new OpData(1, 1, 2, 0), // LogicalNotEqual
new OpData(1, 1, 2, 0), // LogicalOr
new OpData(1, 1, 2, 0), // LogicalAnd
new OpData(1, 1, 1, 0), // LogicalNot
new OpData(1, 1, 3, 0), // Select
new OpData(1, 1, 2, 0), // IEqual
new OpData(1, 1, 2, 0), // INotEqual
new OpData(1, 1, 2, 0), // UGreaterThan
new OpData(1, 1, 2, 0), // SGreaterThan
new OpData(1, 1, 2, 0), // UGreaterThanEqual
new OpData(1, 1, 2, 0), // SGreaterThanEqual
new OpData(1, 1, 2, 0), // ULessThan
new OpData(1, 1, 2, 0), // SLessThan
new OpData(1, 1, 2, 0), // ULessThanEqual
new OpData(1, 1, 2, 0), // SLessThanEqual
new OpData(1, 1, 2, 0), // FOrdEqual
new OpData(1, 1, 2, 0), // FUnordEqual
new OpData(1, 1, 2, 0), // FOrdNotEqual
new OpData(1, 1, 2, 0), // FUnordNotEqual
new OpData(1, 1, 2, 0), // FOrdLessThan
new OpData(1, 1, 2, 0), // FUnordLessThan
new OpData(1, 1, 2, 0), // FOrdGreaterThan
new OpData(1, 1, 2, 0), // FUnordGreaterThan
new OpData(1, 1, 2, 0), // FOrdLessThanEqual
new OpData(1, 1, 2, 0), // FUnordLessThanEqual
new OpData(1, 1, 2, 0), // FOrdGreaterThanEqual
new OpData(1, 1, 2, 0), // FUnordGreaterThanEqual
new OpData(1, 1, 0, 0), // #192
new OpData(1, 1, 0, 0), // #193
new OpData(1, 1, 2, 0), // ShiftRightLogical
new OpData(1, 1, 2, 0), // ShiftRightArithmetic
new OpData(1, 1, 2, 0), // ShiftLeftLogical
new OpData(1, 1, 2, 0), // BitwiseOr
new OpData(1, 1, 2, 0), // BitwiseXor
new OpData(1, 1, 2, 0), // BitwiseAnd
new OpData(1, 1, 1, 0), // Not
new OpData(1, 1, 4, 0), // BitFieldInsert
new OpData(1, 1, 3, 0), // BitFieldSExtract
new OpData(1, 1, 3, 0), // BitFieldUExtract
new OpData(1, 1, 1, 0), // BitReverse
new OpData(1, 1, 1, 0), // BitCount
new OpData(1, 1, 0, 0), // #206
new OpData(1, 1, 0, 0), // DPdx
new OpData(1, 1, 0, 0), // DPdy
new OpData(1, 1, 0, 0), // Fwidth
new OpData(1, 1, 0, 0), // DPdxFine
new OpData(1, 1, 0, 0), // DPdyFine
new OpData(1, 1, 0, 0), // FwidthFine
new OpData(1, 1, 0, 0), // DPdxCoarse
new OpData(1, 1, 0, 0), // DPdyCoarse
new OpData(1, 1, 0, 0), // FwidthCoarse
new OpData(1, 1, 0, 0), // #216
new OpData(1, 1, 0, 0), // #217
new OpData(0, 0, 0, 0), // EmitVertex
new OpData(0, 0, 0, 0), // EndPrimitive
new OpData(0, 0, 0, 0), // EmitStreamVertex
new OpData(0, 0, 0, 0), // EndStreamPrimitive
new OpData(1, 1, 0, 0), // #222
new OpData(1, 1, 0, 0), // #223
new OpData(0, 0, -3, 0), // ControlBarrier
new OpData(0, 0, -2, 0), // MemoryBarrier
new OpData(1, 1, 0, 0), // #226
new OpData(1, 1, 0, 0), // AtomicLoad
new OpData(0, 0, 0, 0), // AtomicStore
new OpData(1, 1, 0, 0), // AtomicExchange
new OpData(1, 1, 0, 0), // AtomicCompareExchange
new OpData(1, 1, 0, 0), // AtomicCompareExchangeWeak
new OpData(1, 1, 0, 0), // AtomicIIncrement
new OpData(1, 1, 0, 0), // AtomicIDecrement
new OpData(1, 1, 0, 0), // AtomicIAdd
new OpData(1, 1, 0, 0), // AtomicISub
new OpData(1, 1, 0, 0), // AtomicSMin
new OpData(1, 1, 0, 0), // AtomicUMin
new OpData(1, 1, 0, 0), // AtomicSMax
new OpData(1, 1, 0, 0), // AtomicUMax
new OpData(1, 1, 0, 0), // AtomicAnd
new OpData(1, 1, 0, 0), // AtomicOr
new OpData(1, 1, 0, 0), // AtomicXor
new OpData(1, 1, 0, 0), // #243
new OpData(1, 1, 0, 0), // #244
new OpData(1, 1, 0, 0), // Phi
new OpData(0, 0, -2, 1), // LoopMerge
new OpData(0, 0, -1, 1), // SelectionMerge
new OpData(1, 0, 0, 0), // Label
new OpData(0, 0, -1, 0), // Branch
new OpData(0, 0, -3, 1), // BranchConditional
new OpData(0, 0, 0, 0), // Switch
new OpData(0, 0, 0, 0), // Kill
new OpData(0, 0, 0, 0), // Return
new OpData(0, 0, 0, 0), // ReturnValue
new OpData(0, 0, 0, 0), // Unreachable
new OpData(0, 0, 0, 0), // LifetimeStart
new OpData(0, 0, 0, 0), // LifetimeStop
new OpData(1, 1, 0, 0), // #258
new OpData(1, 1, 0, 0), // GroupAsyncCopy
new OpData(0, 0, 0, 0), // GroupWaitEvents
new OpData(1, 1, 0, 0), // GroupAll
new OpData(1, 1, 0, 0), // GroupAny
new OpData(1, 1, 0, 0), // GroupBroadcast
new OpData(1, 1, 0, 0), // GroupIAdd
new OpData(1, 1, 0, 0), // GroupFAdd
new OpData(1, 1, 0, 0), // GroupFMin
new OpData(1, 1, 0, 0), // GroupUMin
new OpData(1, 1, 0, 0), // GroupSMin
new OpData(1, 1, 0, 0), // GroupFMax
new OpData(1, 1, 0, 0), // GroupUMax
new OpData(1, 1, 0, 0), // GroupSMax
new OpData(1, 1, 0, 0), // #272
new OpData(1, 1, 0, 0), // #273
new OpData(1, 1, 0, 0), // ReadPipe
new OpData(1, 1, 0, 0), // WritePipe
new OpData(1, 1, 0, 0), // ReservedReadPipe
new OpData(1, 1, 0, 0), // ReservedWritePipe
new OpData(1, 1, 0, 0), // ReserveReadPipePackets
new OpData(1, 1, 0, 0), // ReserveWritePipePackets
new OpData(0, 0, 0, 0), // CommitReadPipe
new OpData(0, 0, 0, 0), // CommitWritePipe
new OpData(1, 1, 0, 0), // IsValidReserveId
new OpData(1, 1, 0, 0), // GetNumPipePackets
new OpData(1, 1, 0, 0), // GetMaxPipePackets
new OpData(1, 1, 0, 0), // GroupReserveReadPipePackets
new OpData(1, 1, 0, 0), // GroupReserveWritePipePackets
new OpData(0, 0, 0, 0), // GroupCommitReadPipe
new OpData(0, 0, 0, 0), // GroupCommitWritePipe
new OpData(1, 1, 0, 0), // #289
new OpData(1, 1, 0, 0), // #290
new OpData(1, 1, 0, 0), // EnqueueMarker
new OpData(1, 1, 0, 0), // EnqueueKernel
new OpData(1, 1, 0, 0), // GetKernelNDrangeSubGroupCount
new OpData(1, 1, 0, 0), // GetKernelNDrangeMaxSubGroupSize
new OpData(1, 1, 0, 0), // GetKernelWorkGroupSize
new OpData(1, 1, 0, 0), // GetKernelPreferredWorkGroupSizeMultiple
new OpData(0, 0, 0, 0), // RetainEvent
new OpData(0, 0, 0, 0), // ReleaseEvent
new OpData(1, 1, 0, 0), // CreateUserEvent
new OpData(1, 1, 0, 0), // IsValidEvent
new OpData(0, 0, 0, 0), // SetUserEventStatus
new OpData(0, 0, 0, 0), // CaptureEventProfilingInfo
new OpData(1, 1, 0, 0), // GetDefaultQueue
new OpData(1, 1, 0, 0), // BuildNDRange
new OpData(1, 1, 2, 1), // ImageSparseSampleImplicitLod
new OpData(1, 1, 2, 1), // ImageSparseSampleExplicitLod
new OpData(1, 1, 3, 1), // ImageSparseSampleDrefImplicitLod
new OpData(1, 1, 3, 1), // ImageSparseSampleDrefExplicitLod
new OpData(1, 1, 2, 1), // ImageSparseSampleProjImplicitLod
new OpData(1, 1, 2, 1), // ImageSparseSampleProjExplicitLod
new OpData(1, 1, 3, 1), // ImageSparseSampleProjDrefImplicitLod
new OpData(1, 1, 3, 1), // ImageSparseSampleProjDrefExplicitLod
new OpData(1, 1, 2, 1), // ImageSparseFetch
new OpData(1, 1, 3, 1), // ImageSparseGather
new OpData(1, 1, 3, 1), // ImageSparseDrefGather
new OpData(1, 1, 1, 0), // ImageSparseTexelsResident
new OpData(0, 0, 0, 0), // NoLine
new OpData(1, 1, 0, 0), // AtomicFlagTestAndSet
new OpData(0, 0, 0, 0), // AtomicFlagClear
new OpData(1, 1, 0, 0), // ImageSparseRead
new OpData(1, 1, 0, 0), // SizeOf
new OpData(1, 1, 0, 0), // TypePipeStorage
new OpData(1, 1, 0, 0), // ConstantPipeStorage
new OpData(1, 1, 0, 0), // CreatePipeFromPipeStorage
new OpData(1, 1, 0, 0), // GetKernelLocalSizeForSubgroupCount
new OpData(1, 1, 0, 0), // GetKernelMaxNumSubgroups
new OpData(1, 1, 0, 0), // TypeNamedBarrier
new OpData(1, 1, 0, 1), // NamedBarrierInitialize
new OpData(0, 0, -2, 1), // MemoryNamedBarrier
new OpData(1, 1, 0, 0), // ModuleProcessed
};
};
}

View File

@ -0,0 +1,479 @@
using System;
using System.IO;
using System.Text;
namespace Smolv
{
public static class SmolvDecoder
{
public static int GetDecodedBufferSize(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
if (!CheckSmolHeader(data))
{
return 0;
}
int size = BitConverter.ToInt32(data, 5 * sizeof(uint));
return size;
}
public static int GetDecodedBufferSize(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException(nameof(stream));
}
if (!stream.CanSeek)
{
throw new ArgumentException(nameof(stream));
}
if (stream.Position + HeaderSize > stream.Length)
{
return 0;
}
long initPosition = stream.Position;
stream.Position += HeaderSize - sizeof(uint);
int size = stream.ReadByte() | stream.ReadByte() << 8 | stream.ReadByte() << 16 | stream.ReadByte() << 24;
stream.Position = initPosition;
return size;
}
public static byte[] Decode(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
int bufferSize = GetDecodedBufferSize(data);
if (bufferSize == 0)
{
// invalid SMOL-V
return null;
}
byte[] output = new byte[bufferSize];
if (Decode(data, output))
{
return output;
}
return null;
}
public static bool Decode(byte[] data, byte[] output)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
if (output == null)
{
throw new ArgumentNullException(nameof(output));
}
int bufferSize = GetDecodedBufferSize(data);
if (bufferSize > output.Length)
{
return false;
}
using (MemoryStream outputStream = new MemoryStream(output))
{
return Decode(data, outputStream);
}
}
public static bool Decode(byte[] data, Stream outputStream)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
using (MemoryStream inputStream = new MemoryStream(data))
{
return Decode(inputStream, data.Length, outputStream);
}
}
public static bool Decode(Stream inputStream, int inputSize, Stream outputStream)
{
if (inputStream == null)
{
throw new ArgumentNullException(nameof(inputStream));
}
if (outputStream == null)
{
throw new ArgumentNullException(nameof(outputStream));
}
if (inputStream.Length < HeaderSize)
{
return false;
}
using (BinaryReader input = new BinaryReader(inputStream, Encoding.UTF8, true))
{
using (BinaryWriter output = new BinaryWriter(outputStream, Encoding.UTF8, true))
{
long inputEndPosition = input.BaseStream.Position + inputSize;
long outputStartPosition = output.BaseStream.Position;
// Header
output.Write(SpirVHeaderMagic);
input.BaseStream.Position += sizeof(uint);
uint version = input.ReadUInt32();
output.Write(version);
uint generator = input.ReadUInt32();
output.Write(generator);
int bound = input.ReadInt32();
output.Write(bound);
uint schema = input.ReadUInt32();
output.Write(schema);
int decodedSize = input.ReadInt32();
// Body
int prevResult = 0;
int prevDecorate = 0;
while (input.BaseStream.Position < inputEndPosition)
{
// read length + opcode
if (!ReadLengthOp(input, out uint instrLen, out SpvOp op))
{
return false;
}
bool wasSwizzle = op == SpvOp.VectorShuffleCompact;
if (wasSwizzle)
{
op = SpvOp.VectorShuffle;
}
output.Write((instrLen << 16) | (uint)op);
uint ioffs = 1;
// read type as varint, if we have it
if (op.OpHasType())
{
if (!ReadVarint(input, out uint value))
{
return false;
}
output.Write(value);
ioffs++;
}
// read result as delta+varint, if we have it
if (op.OpHasResult())
{
if (!ReadVarint(input, out uint value))
{
return false;
}
int zds = prevResult + ZigDecode(value);
output.Write(zds);
prevResult = zds;
ioffs++;
}
// Decorate: IDs relative to previous decorate
if (op == SpvOp.Decorate || op == SpvOp.MemberDecorate)
{
if (!ReadVarint(input, out uint value))
{
return false;
}
int zds = prevDecorate + unchecked((int)value);
output.Write(zds);
prevDecorate = zds;
ioffs++;
}
// Read this many IDs, that are relative to result ID
int relativeCount = op.OpDeltaFromResult();
bool inverted = false;
if (relativeCount < 0)
{
inverted = true;
relativeCount = -relativeCount;
}
for (int i = 0; i < relativeCount && ioffs < instrLen; ++i, ++ioffs)
{
if (!ReadVarint(input, out uint value))
{
return false;
}
int zd = inverted ? ZigDecode(value) : unchecked((int)value);
output.Write(prevResult - zd);
}
if (wasSwizzle && instrLen <= 9)
{
uint swizzle = input.ReadByte();
if (instrLen > 5) output.Write(swizzle >> 6);
if (instrLen > 6) output.Write((swizzle >> 4) & 3);
if (instrLen > 7) output.Write((swizzle >> 2) & 3);
if (instrLen > 8) output.Write(swizzle & 3);
}
else if (op.OpVarRest())
{
// read rest of words with variable encoding
for (; ioffs < instrLen; ++ioffs)
{
if (!ReadVarint(input, out uint value))
{
return false;
}
output.Write(value);
}
}
else
{
// read rest of words without any encoding
for (; ioffs < instrLen; ++ioffs)
{
if (input.BaseStream.Position + 4 > input.BaseStream.Length)
{
return false;
}
uint val = input.ReadUInt32();
output.Write(val);
}
}
}
if (output.BaseStream.Position != outputStartPosition + decodedSize)
{
// something went wrong during decoding? we should have decoded to exact output size
return false;
}
return true;
}
}
}
private static bool CheckSmolHeader(byte[] data)
{
if (!CheckGenericHeader(data, SmolHeaderMagic))
{
return false;
}
return true;
}
private static bool CheckGenericHeader(byte[] data, uint expectedMagic)
{
if (data == null)
{
return false;
}
if (data.Length < HeaderSize)
{
return false;
}
uint headerMagic = BitConverter.ToUInt32(data, 0 * sizeof(uint));
if (headerMagic != expectedMagic)
{
return false;
}
uint headerVersion = BitConverter.ToUInt32(data, 1 * sizeof(uint));
if (headerVersion < 0x00010000 || headerVersion > 0x00010300)
{
// only support 1.0 through 1.3
return false;
}
return true;
}
private static bool ReadVarint(BinaryReader input, out uint value)
{
uint v = 0;
int shift = 0;
while (input.BaseStream.Position < input.BaseStream.Length)
{
byte b = input.ReadByte();
v |= unchecked((uint)(b & 127) << shift);
shift += 7;
if ((b & 128) == 0)
{
break;
}
}
value = v;
// @TODO: report failures
return true;
}
private static bool ReadLengthOp(BinaryReader input, out uint len, out SpvOp op)
{
len = default;
op = default;
if (!ReadVarint(input, out uint value))
{
return false;
}
len = ((value >> 20) << 4) | ((value >> 4) & 0xF);
op = (SpvOp) (((value >> 4) & 0xFFF0) | (value & 0xF));
op = RemapOp(op);
len = DecodeLen(op, len);
return true;
}
/// <summary>
/// Remap most common Op codes (Load, Store, Decorate, VectorShuffle etc.) to be in &lt; 16 range, for
/// more compact varint encoding. This basically swaps rarely used op values that are &lt; 16 with the
/// ones that are common.
/// </summary>
private static SpvOp RemapOp(SpvOp op)
{
switch (op)
{
// 0: 24%
case SpvOp.Decorate:
return SpvOp.Nop;
case SpvOp.Nop:
return SpvOp.Decorate;
// 1: 17%
case SpvOp.Load:
return SpvOp.Undef;
case SpvOp.Undef:
return SpvOp.Load;
// 2: 9%
case SpvOp.Store:
return SpvOp.SourceContinued;
case SpvOp.SourceContinued:
return SpvOp.Store;
// 3: 7.2%
case SpvOp.AccessChain:
return SpvOp.Source;
case SpvOp.Source:
return SpvOp.AccessChain;
// 4: 5.0%
// Name - already small enum value - 5: 4.4%
// MemberName - already small enum value - 6: 2.9%
case SpvOp.VectorShuffle:
return SpvOp.SourceExtension;
case SpvOp.SourceExtension:
return SpvOp.VectorShuffle;
// 7: 4.0%
case SpvOp.MemberDecorate:
return SpvOp.String;
case SpvOp.String:
return SpvOp.MemberDecorate;
// 8: 0.9%
case SpvOp.Label:
return SpvOp.Line;
case SpvOp.Line:
return SpvOp.Label;
// 9: 3.9%
case SpvOp.Variable:
return (SpvOp)9;
case (SpvOp)9:
return SpvOp.Variable;
// 10: 3.9%
case SpvOp.FMul:
return SpvOp.Extension;
case SpvOp.Extension:
return SpvOp.FMul;
// 11: 2.5%
// ExtInst - already small enum value - 12: 1.2%
// VectorShuffleCompact - already small enum value - used for compact shuffle encoding
case SpvOp.FAdd:
return SpvOp.ExtInstImport;
case SpvOp.ExtInstImport:
return SpvOp.FAdd;
// 14: 2.2%
case SpvOp.TypePointer:
return SpvOp.MemoryModel;
case SpvOp.MemoryModel:
return SpvOp.TypePointer;
// 15: 1.1%
case SpvOp.FNegate:
return SpvOp.EntryPoint;
case SpvOp.EntryPoint:
return SpvOp.FNegate;
}
return op;
}
private static uint DecodeLen(SpvOp op, uint len)
{
len++;
switch (op)
{
case SpvOp.VectorShuffle:
len += 4;
break;
case SpvOp.VectorShuffleCompact:
len += 4;
break;
case SpvOp.Decorate:
len += 2;
break;
case SpvOp.Load:
len += 3;
break;
case SpvOp.AccessChain:
len += 3;
break;
}
return len;
}
private static int DecorationExtraOps(int dec)
{
// RelaxedPrecision, Block..ColMajor
if (dec == 0 || (dec >= 2 && dec <= 5))
{
return 0;
}
// Stream..XfbStride
if (dec >= 29 && dec <= 37)
{
return 1;
}
// unknown, encode length
return -1;
}
private static int ZigDecode(uint u)
{
return (u & 1) != 0 ? unchecked((int)(~(u >> 1))) : unchecked((int)(u >> 1));
}
public const uint SpirVHeaderMagic = 0x07230203;
/// <summary>
/// 'SMOL' ascii
/// </summary>
public const uint SmolHeaderMagic = 0x534D4F4C;
private const int HeaderSize = 6 * sizeof(uint);
}
}

View File

@ -0,0 +1,369 @@
namespace Smolv
{
public enum SpvOp
{
Nop = 0,
Undef = 1,
SourceContinued = 2,
Source = 3,
SourceExtension = 4,
Name = 5,
MemberName = 6,
String = 7,
Line = 8,
Extension = 10,
ExtInstImport = 11,
ExtInst = 12,
/// <summary>
/// Not in SPIR-V, added for SMOL-V!
/// </summary>
VectorShuffleCompact = 13,
MemoryModel = 14,
EntryPoint = 15,
ExecutionMode = 16,
Capability = 17,
TypeVoid = 19,
TypeBool = 20,
TypeInt = 21,
TypeFloat = 22,
TypeVector = 23,
TypeMatrix = 24,
TypeImage = 25,
TypeSampler = 26,
TypeSampledImage = 27,
TypeArray = 28,
TypeRuntimeArray = 29,
TypeStruct = 30,
TypeOpaque = 31,
TypePointer = 32,
TypeFunction = 33,
TypeEvent = 34,
TypeDeviceEvent = 35,
TypeReserveId = 36,
TypeQueue = 37,
TypePipe = 38,
TypeForwardPointer = 39,
ConstantTrue = 41,
ConstantFalse = 42,
Constant = 43,
ConstantComposite = 44,
ConstantSampler = 45,
ConstantNull = 46,
SpecConstantTrue = 48,
SpecConstantFalse = 49,
SpecConstant = 50,
SpecConstantComposite = 51,
SpecConstantOp = 52,
Function = 54,
FunctionParameter = 55,
FunctionEnd = 56,
FunctionCall = 57,
Variable = 59,
ImageTexelPointer = 60,
Load = 61,
Store = 62,
CopyMemory = 63,
CopyMemorySized = 64,
AccessChain = 65,
InBoundsAccessChain = 66,
PtrAccessChain = 67,
ArrayLength = 68,
GenericPtrMemSemantics = 69,
InBoundsPtrAccessChain = 70,
Decorate = 71,
MemberDecorate = 72,
DecorationGroup = 73,
GroupDecorate = 74,
GroupMemberDecorate = 75,
VectorExtractDynamic = 77,
VectorInsertDynamic = 78,
VectorShuffle = 79,
CompositeConstruct = 80,
CompositeExtract = 81,
CompositeInsert = 82,
CopyObject = 83,
Transpose = 84,
SampledImage = 86,
ImageSampleImplicitLod = 87,
ImageSampleExplicitLod = 88,
ImageSampleDrefImplicitLod = 89,
ImageSampleDrefExplicitLod = 90,
ImageSampleProjImplicitLod = 91,
ImageSampleProjExplicitLod = 92,
ImageSampleProjDrefImplicitLod = 93,
ImageSampleProjDrefExplicitLod = 94,
ImageFetch = 95,
ImageGather = 96,
ImageDrefGather = 97,
ImageRead = 98,
ImageWrite = 99,
Image = 100,
ImageQueryFormat = 101,
ImageQueryOrder = 102,
ImageQuerySizeLod = 103,
ImageQuerySize = 104,
ImageQueryLod = 105,
ImageQueryLevels = 106,
ImageQuerySamples = 107,
ConvertFToU = 109,
ConvertFToS = 110,
ConvertSToF = 111,
ConvertUToF = 112,
UConvert = 113,
SConvert = 114,
FConvert = 115,
QuantizeToF16 = 116,
ConvertPtrToU = 117,
SatConvertSToU = 118,
SatConvertUToS = 119,
ConvertUToPtr = 120,
PtrCastToGeneric = 121,
GenericCastToPtr = 122,
GenericCastToPtrExplicit = 123,
Bitcast = 124,
SNegate = 126,
FNegate = 127,
IAdd = 128,
FAdd = 129,
ISub = 130,
FSub = 131,
IMul = 132,
FMul = 133,
UDiv = 134,
SDiv = 135,
FDiv = 136,
UMod = 137,
SRem = 138,
SMod = 139,
FRem = 140,
FMod = 141,
VectorTimesScalar = 142,
MatrixTimesScalar = 143,
VectorTimesMatrix = 144,
MatrixTimesVector = 145,
MatrixTimesMatrix = 146,
OuterProduct = 147,
Dot = 148,
IAddCarry = 149,
ISubBorrow = 150,
UMulExtended = 151,
SMulExtended = 152,
Any = 154,
All = 155,
IsNan = 156,
IsInf = 157,
IsFinite = 158,
IsNormal = 159,
SignBitSet = 160,
LessOrGreater = 161,
Ordered = 162,
Unordered = 163,
LogicalEqual = 164,
LogicalNotEqual = 165,
LogicalOr = 166,
LogicalAnd = 167,
LogicalNot = 168,
Select = 169,
IEqual = 170,
INotEqual = 171,
UGreaterThan = 172,
SGreaterThan = 173,
UGreaterThanEqual = 174,
SGreaterThanEqual = 175,
ULessThan = 176,
SLessThan = 177,
ULessThanEqual = 178,
SLessThanEqual = 179,
FOrdEqual = 180,
FUnordEqual = 181,
FOrdNotEqual = 182,
FUnordNotEqual = 183,
FOrdLessThan = 184,
FUnordLessThan = 185,
FOrdGreaterThan = 186,
FUnordGreaterThan = 187,
FOrdLessThanEqual = 188,
FUnordLessThanEqual = 189,
FOrdGreaterThanEqual = 190,
FUnordGreaterThanEqual = 191,
ShiftRightLogical = 194,
ShiftRightArithmetic = 195,
ShiftLeftLogical = 196,
BitwiseOr = 197,
BitwiseXor = 198,
BitwiseAnd = 199,
Not = 200,
BitFieldInsert = 201,
BitFieldSExtract = 202,
BitFieldUExtract = 203,
BitReverse = 204,
BitCount = 205,
DPdx = 207,
DPdy = 208,
Fwidth = 209,
DPdxFine = 210,
DPdyFine = 211,
FwidthFine = 212,
DPdxCoarse = 213,
DPdyCoarse = 214,
FwidthCoarse = 215,
EmitVertex = 218,
EndPrimitive = 219,
EmitStreamVertex = 220,
EndStreamPrimitive = 221,
ControlBarrier = 224,
MemoryBarrier = 225,
AtomicLoad = 227,
AtomicStore = 228,
AtomicExchange = 229,
AtomicCompareExchange = 230,
AtomicCompareExchangeWeak = 231,
AtomicIIncrement = 232,
AtomicIDecrement = 233,
AtomicIAdd = 234,
AtomicISub = 235,
AtomicSMin = 236,
AtomicUMin = 237,
AtomicSMax = 238,
AtomicUMax = 239,
AtomicAnd = 240,
AtomicOr = 241,
AtomicXor = 242,
Phi = 245,
LoopMerge = 246,
SelectionMerge = 247,
Label = 248,
Branch = 249,
BranchConditional = 250,
Switch = 251,
Kill = 252,
Return = 253,
ReturnValue = 254,
Unreachable = 255,
LifetimeStart = 256,
LifetimeStop = 257,
GroupAsyncCopy = 259,
GroupWaitEvents = 260,
GroupAll = 261,
GroupAny = 262,
GroupBroadcast = 263,
GroupIAdd = 264,
GroupFAdd = 265,
GroupFMin = 266,
GroupUMin = 267,
GroupSMin = 268,
GroupFMax = 269,
GroupUMax = 270,
GroupSMax = 271,
ReadPipe = 274,
WritePipe = 275,
ReservedReadPipe = 276,
ReservedWritePipe = 277,
ReserveReadPipePackets = 278,
ReserveWritePipePackets = 279,
CommitReadPipe = 280,
CommitWritePipe = 281,
IsValidReserveId = 282,
GetNumPipePackets = 283,
GetMaxPipePackets = 284,
GroupReserveReadPipePackets = 285,
GroupReserveWritePipePackets = 286,
GroupCommitReadPipe = 287,
GroupCommitWritePipe = 288,
EnqueueMarker = 291,
EnqueueKernel = 292,
GetKernelNDrangeSubGroupCount = 293,
GetKernelNDrangeMaxSubGroupSize = 294,
GetKernelWorkGroupSize = 295,
GetKernelPreferredWorkGroupSizeMultiple = 296,
RetainEvent = 297,
ReleaseEvent = 298,
CreateUserEvent = 299,
IsValidEvent = 300,
SetUserEventStatus = 301,
CaptureEventProfilingInfo = 302,
GetDefaultQueue = 303,
BuildNDRange = 304,
ImageSparseSampleImplicitLod = 305,
ImageSparseSampleExplicitLod = 306,
ImageSparseSampleDrefImplicitLod = 307,
ImageSparseSampleDrefExplicitLod = 308,
ImageSparseSampleProjImplicitLod = 309,
ImageSparseSampleProjExplicitLod = 310,
ImageSparseSampleProjDrefImplicitLod = 311,
ImageSparseSampleProjDrefExplicitLod = 312,
ImageSparseFetch = 313,
ImageSparseGather = 314,
ImageSparseDrefGather = 315,
ImageSparseTexelsResident = 316,
NoLine = 317,
AtomicFlagTestAndSet = 318,
AtomicFlagClear = 319,
ImageSparseRead = 320,
SizeOf = 321,
TypePipeStorage = 322,
ConstantPipeStorage = 323,
CreatePipeFromPipeStorage = 324,
GetKernelLocalSizeForSubgroupCount = 325,
GetKernelMaxNumSubgroups = 326,
TypeNamedBarrier = 327,
NamedBarrierInitialize = 328,
MemoryNamedBarrier = 329,
ModuleProcessed = 330,
KnownOpsCount,
}
public static class SpvOpExtensions
{
public static bool OpHasResult(this SpvOp _this)
{
if (_this < 0 || _this >= SpvOp.KnownOpsCount)
{
return false;
}
return OpData.SpirvOpData[(int)_this].hasResult != 0;
}
public static bool OpHasType(this SpvOp _this)
{
if (_this < 0 || _this >= SpvOp.KnownOpsCount)
{
return false;
}
return OpData.SpirvOpData[(int)_this].hasType != 0;
}
public static int OpDeltaFromResult(this SpvOp _this)
{
if (_this < 0 || _this >= SpvOp.KnownOpsCount)
{
return 0;
}
return OpData.SpirvOpData[(int)_this].deltaFromResult;
}
public static bool OpVarRest(this SpvOp _this)
{
if (_this < 0 || _this >= SpvOp.KnownOpsCount)
{
return false;
}
return OpData.SpirvOpData[(int)_this].varrest != 0;
}
public static bool OpDebugInfo(this SpvOp _this)
{
return
_this == SpvOp.SourceContinued ||
_this == SpvOp.Source ||
_this == SpvOp.SourceExtension ||
_this == SpvOp.Name ||
_this == SpvOp.MemberName ||
_this == SpvOp.String ||
_this == SpvOp.Line ||
_this == SpvOp.NoLine ||
_this == SpvOp.ModuleProcessed;
}
}
}