mirror of
https://github.com/aelurum/AssetStudio.git
synced 2025-05-25 05:40:21 -04:00
implemented SPIR-V shader export
This commit is contained in:
parent
0ec29f62ca
commit
729a8a8263
@ -49,6 +49,16 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="AudioClipConverter.cs" />
|
<Compile Include="AudioClipConverter.cs" />
|
||||||
|
<Compile Include="CSspv\Disassembler.cs" />
|
||||||
|
<Compile Include="CSspv\EnumValuesExtensions.cs" />
|
||||||
|
<Compile Include="CSspv\Instruction.cs" />
|
||||||
|
<Compile Include="CSspv\Module.cs" />
|
||||||
|
<Compile Include="CSspv\OperandType.cs" />
|
||||||
|
<Compile Include="CSspv\ParsedInstruction.cs" />
|
||||||
|
<Compile Include="CSspv\Reader.cs" />
|
||||||
|
<Compile Include="CSspv\SpirV.Core.Grammar.cs" />
|
||||||
|
<Compile Include="CSspv\SpirV.Meta.cs" />
|
||||||
|
<Compile Include="CSspv\Types.cs" />
|
||||||
<Compile Include="FMOD Studio API\fmod.cs" />
|
<Compile Include="FMOD Studio API\fmod.cs" />
|
||||||
<Compile Include="FMOD Studio API\fmod_dsp.cs" />
|
<Compile Include="FMOD Studio API\fmod_dsp.cs" />
|
||||||
<Compile Include="FMOD Studio API\fmod_errors.cs" />
|
<Compile Include="FMOD Studio API\fmod_errors.cs" />
|
||||||
@ -57,6 +67,10 @@
|
|||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="ScriptDumper.cs" />
|
<Compile Include="ScriptDumper.cs" />
|
||||||
<Compile Include="ShaderConverter.cs" />
|
<Compile Include="ShaderConverter.cs" />
|
||||||
|
<Compile Include="Smolv\OpData.cs" />
|
||||||
|
<Compile Include="Smolv\SmolvDecoder.cs" />
|
||||||
|
<Compile Include="Smolv\SpvOp.cs" />
|
||||||
|
<Compile Include="SpirVShaderConverter.cs" />
|
||||||
<Compile Include="SpriteHelper.cs" />
|
<Compile Include="SpriteHelper.cs" />
|
||||||
<Compile Include="Texture2DConverter.cs" />
|
<Compile Include="Texture2DConverter.cs" />
|
||||||
<Compile Include="Texture2DExtensions.cs" />
|
<Compile Include="Texture2DExtensions.cs" />
|
||||||
|
221
AssetStudioUtility/CSspv/Disassembler.cs
Normal file
221
AssetStudioUtility/CSspv/Disassembler.cs
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace SpirV
|
||||||
|
{
|
||||||
|
public struct ModuleHeader
|
||||||
|
{
|
||||||
|
public Version Version { get; set; }
|
||||||
|
public string GeneratorVendor { get; set; }
|
||||||
|
public string GeneratorName { get; set; }
|
||||||
|
public int GeneratorVersion { get; set; }
|
||||||
|
public uint Bound { get; set; }
|
||||||
|
public uint Reserved { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum DisassemblyOptions
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
ShowTypes,
|
||||||
|
ShowNames,
|
||||||
|
Default = ShowTypes | ShowNames
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Disassembler
|
||||||
|
{
|
||||||
|
public string Disassemble (Module module)
|
||||||
|
{
|
||||||
|
return Disassemble(module, DisassemblyOptions.Default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Disassemble(Module module, DisassemblyOptions options)
|
||||||
|
{
|
||||||
|
m_sb.AppendLine("; SPIR-V");
|
||||||
|
m_sb.Append("; Version: ").Append(module.Header.Version).AppendLine();
|
||||||
|
if (module.Header.GeneratorName == null)
|
||||||
|
{
|
||||||
|
m_sb.Append("; Generator: unknown; ").Append(module.Header.GeneratorVersion).AppendLine();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_sb.Append("; Generator: ").Append(module.Header.GeneratorVendor).Append(' ').
|
||||||
|
Append(module.Header.GeneratorName).Append("; ").Append(module.Header.GeneratorVersion).AppendLine();
|
||||||
|
}
|
||||||
|
m_sb.Append("; Bound: ").Append(module.Header.Bound).AppendLine();
|
||||||
|
m_sb.Append("; Schema: ").Append(module.Header.Reserved).AppendLine();
|
||||||
|
|
||||||
|
string[] lines = new string[module.Instructions.Count + 1];
|
||||||
|
lines[0] = m_sb.ToString();
|
||||||
|
m_sb.Clear();
|
||||||
|
|
||||||
|
for (int i = 0; i < module.Instructions.Count; i++)
|
||||||
|
{
|
||||||
|
ParsedInstruction instruction = module.Instructions[i];
|
||||||
|
PrintInstruction(m_sb, instruction, options);
|
||||||
|
lines[i + 1] = m_sb.ToString();
|
||||||
|
m_sb.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int longestPrefix = 0;
|
||||||
|
for (int i = 0; i < lines.Length; i++)
|
||||||
|
{
|
||||||
|
string line = lines[i];
|
||||||
|
longestPrefix = Math.Max(longestPrefix, line.IndexOf('='));
|
||||||
|
if (longestPrefix > 50)
|
||||||
|
{
|
||||||
|
longestPrefix = 50;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_sb.Append(lines[0]);
|
||||||
|
for (int i = 1; i < lines.Length; i++)
|
||||||
|
{
|
||||||
|
string line = lines[i];
|
||||||
|
int index = line.IndexOf('=');
|
||||||
|
if (index == -1)
|
||||||
|
{
|
||||||
|
m_sb.Append(' ', longestPrefix + 4);
|
||||||
|
m_sb.Append(line);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int pad = Math.Max(0, longestPrefix - index);
|
||||||
|
m_sb.Append(' ', pad);
|
||||||
|
m_sb.Append(line, 0, index);
|
||||||
|
m_sb.Append('=');
|
||||||
|
m_sb.Append(line, index + 1, line.Length - index - 1);
|
||||||
|
}
|
||||||
|
m_sb.AppendLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
string result = m_sb.ToString();
|
||||||
|
m_sb.Clear();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PrintInstruction(StringBuilder sb, ParsedInstruction instruction, DisassemblyOptions options)
|
||||||
|
{
|
||||||
|
if (instruction.Operands.Count == 0)
|
||||||
|
{
|
||||||
|
sb.Append(instruction.Instruction.Name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int currentOperand = 0;
|
||||||
|
if (instruction.Instruction.Operands[currentOperand].Type is IdResultType)
|
||||||
|
{
|
||||||
|
if (options.HasFlag(DisassemblyOptions.ShowTypes))
|
||||||
|
{
|
||||||
|
instruction.ResultType.ToString(sb).Append(' ');
|
||||||
|
}
|
||||||
|
++currentOperand;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentOperand < instruction.Operands.Count && instruction.Instruction.Operands[currentOperand].Type is IdResult)
|
||||||
|
{
|
||||||
|
if (!options.HasFlag(DisassemblyOptions.ShowNames) || string.IsNullOrWhiteSpace(instruction.Name))
|
||||||
|
{
|
||||||
|
PrintOperandValue(sb, instruction.Operands[currentOperand].Value, options);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(instruction.Name);
|
||||||
|
}
|
||||||
|
sb.Append(" = ");
|
||||||
|
|
||||||
|
++currentOperand;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append(instruction.Instruction.Name);
|
||||||
|
sb.Append(' ');
|
||||||
|
|
||||||
|
for (; currentOperand < instruction.Operands.Count; ++currentOperand)
|
||||||
|
{
|
||||||
|
PrintOperandValue(sb, instruction.Operands[currentOperand].Value, options);
|
||||||
|
sb.Append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PrintOperandValue(StringBuilder sb, object value, DisassemblyOptions options)
|
||||||
|
{
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case System.Type t:
|
||||||
|
sb.Append(t.Name);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case string s:
|
||||||
|
{
|
||||||
|
sb.Append('"');
|
||||||
|
sb.Append(s);
|
||||||
|
sb.Append('"');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ObjectReference or:
|
||||||
|
{
|
||||||
|
if (options.HasFlag(DisassemblyOptions.ShowNames) && or.Reference != null && !string.IsNullOrWhiteSpace(or.Reference.Name))
|
||||||
|
{
|
||||||
|
sb.Append(or.Reference.Name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
or.ToString(sb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IBitEnumOperandValue beov:
|
||||||
|
PrintBitEnumValue(sb, beov, options);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IValueEnumOperandValue veov:
|
||||||
|
PrintValueEnumValue(sb, veov, options);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VaryingOperandValue varOpVal:
|
||||||
|
varOpVal.ToString(sb);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
sb.Append(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PrintBitEnumValue(StringBuilder sb, IBitEnumOperandValue enumOperandValue, DisassemblyOptions options)
|
||||||
|
{
|
||||||
|
foreach (uint key in enumOperandValue.Values.Keys)
|
||||||
|
{
|
||||||
|
sb.Append(enumOperandValue.EnumerationType.GetEnumName(key));
|
||||||
|
IReadOnlyList<object> value = enumOperandValue.Values[key];
|
||||||
|
if (value.Count != 0)
|
||||||
|
{
|
||||||
|
sb.Append(' ');
|
||||||
|
foreach (object v in value)
|
||||||
|
{
|
||||||
|
PrintOperandValue(sb, v, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PrintValueEnumValue(StringBuilder sb, IValueEnumOperandValue valueOperandValue, DisassemblyOptions options)
|
||||||
|
{
|
||||||
|
sb.Append(valueOperandValue.Key);
|
||||||
|
if (valueOperandValue.Value is IList<object> valueList && valueList.Count > 0)
|
||||||
|
{
|
||||||
|
sb.Append(' ');
|
||||||
|
foreach (object v in valueList)
|
||||||
|
{
|
||||||
|
PrintOperandValue(sb, v, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly StringBuilder m_sb = new StringBuilder();
|
||||||
|
}
|
||||||
|
}
|
42
AssetStudioUtility/CSspv/EnumValuesExtensions.cs
Normal file
42
AssetStudioUtility/CSspv/EnumValuesExtensions.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#if NETSTANDARD1_0 || NETSTANDARD1_1 || NETSTANDARD1_2 || NETSTANDARD1_3 || NETSTANDARD1_4 || NETSTANDARD1_5 || NETSTANDARD1_6
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace SpirV
|
||||||
|
{
|
||||||
|
public static class EnumValuesExtensions
|
||||||
|
{
|
||||||
|
public static Array GetEnumValues(this System.Type _this)
|
||||||
|
{
|
||||||
|
TypeInfo typeInfo = _this.GetTypeInfo ();
|
||||||
|
if (!typeInfo.IsEnum) {
|
||||||
|
throw new ArgumentException ("GetEnumValues: Type '" + _this.Name + "' is not an enum");
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
(
|
||||||
|
from field in typeInfo.DeclaredFields
|
||||||
|
where field.IsLiteral
|
||||||
|
select field.GetValue (null)
|
||||||
|
)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetEnumName(this System.Type _this, object value)
|
||||||
|
{
|
||||||
|
TypeInfo typeInfo = _this.GetTypeInfo ();
|
||||||
|
if (!typeInfo.IsEnum) {
|
||||||
|
throw new ArgumentException ("GetEnumName: Type '" + _this.Name + "' is not an enum");
|
||||||
|
}
|
||||||
|
return
|
||||||
|
(
|
||||||
|
from field in typeInfo.DeclaredFields
|
||||||
|
where field.IsLiteral && (uint)field.GetValue(null) == (uint)value
|
||||||
|
select field.Name
|
||||||
|
)
|
||||||
|
.First();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
51
AssetStudioUtility/CSspv/Instruction.cs
Normal file
51
AssetStudioUtility/CSspv/Instruction.cs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace SpirV
|
||||||
|
{
|
||||||
|
public enum OperandQuantifier
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 1
|
||||||
|
/// </summary>
|
||||||
|
Default,
|
||||||
|
/// <summary>
|
||||||
|
/// 0 or 1
|
||||||
|
/// </summary>
|
||||||
|
Optional,
|
||||||
|
/// <summary>
|
||||||
|
/// 0+
|
||||||
|
/// </summary>
|
||||||
|
Varying
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Operand
|
||||||
|
{
|
||||||
|
public Operand(OperandType kind, string name, OperandQuantifier quantifier)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Type = kind;
|
||||||
|
Quantifier = quantifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
public OperandType Type { get; }
|
||||||
|
public OperandQuantifier Quantifier { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Instruction
|
||||||
|
{
|
||||||
|
public Instruction (string name)
|
||||||
|
: this (name, new List<Operand> ())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instruction (string name, IReadOnlyList<Operand> operands)
|
||||||
|
{
|
||||||
|
Operands = operands;
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
public IReadOnlyList<Operand> Operands { get; }
|
||||||
|
}
|
||||||
|
}
|
25
AssetStudioUtility/CSspv/LICENSE
Normal file
25
AssetStudioUtility/CSspv/LICENSE
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
BSD 2-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2017, Matthäus G. Chajdas
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
426
AssetStudioUtility/CSspv/Module.cs
Normal file
426
AssetStudioUtility/CSspv/Module.cs
Normal file
@ -0,0 +1,426 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace SpirV
|
||||||
|
{
|
||||||
|
public class Module
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
private struct FloatUIntUnion
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public uint Int;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public float Float;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
private struct DoubleULongUnion
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public ulong Long;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public double Double;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Module(ModuleHeader header, IReadOnlyList<ParsedInstruction> instructions)
|
||||||
|
{
|
||||||
|
Header = header;
|
||||||
|
Instructions = instructions;
|
||||||
|
|
||||||
|
Read(Instructions, objects_);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsDebugInstruction(ParsedInstruction instruction)
|
||||||
|
{
|
||||||
|
return debugInstructions_.Contains(instruction.Instruction.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Read(IReadOnlyList<ParsedInstruction> instructions, Dictionary<uint, ParsedInstruction> objects)
|
||||||
|
{
|
||||||
|
// Debug instructions can be only processed after everything
|
||||||
|
// else has been parsed, as they may reference types which haven't
|
||||||
|
// been seen in the file yet
|
||||||
|
List<ParsedInstruction> debugInstructions = new List<ParsedInstruction>();
|
||||||
|
// Entry points contain forward references
|
||||||
|
// Those need to be resolved afterwards
|
||||||
|
List<ParsedInstruction> entryPoints = new List<ParsedInstruction>();
|
||||||
|
|
||||||
|
foreach (var instruction in instructions)
|
||||||
|
{
|
||||||
|
if (IsDebugInstruction(instruction))
|
||||||
|
{
|
||||||
|
debugInstructions.Add(instruction);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (instruction.Instruction is OpEntryPoint)
|
||||||
|
{
|
||||||
|
entryPoints.Add(instruction);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instruction.Instruction.Name.StartsWith("OpType", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
ProcessTypeInstruction(instruction, objects);
|
||||||
|
}
|
||||||
|
|
||||||
|
instruction.ResolveResultType(objects);
|
||||||
|
if (instruction.HasResult)
|
||||||
|
{
|
||||||
|
objects[instruction.ResultId] = instruction;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (instruction.Instruction)
|
||||||
|
{
|
||||||
|
// Constants require that the result type has been resolved
|
||||||
|
case OpSpecConstant sc:
|
||||||
|
case OpConstant oc:
|
||||||
|
{
|
||||||
|
Type t = instruction.ResultType;
|
||||||
|
Debug.Assert (t != null);
|
||||||
|
Debug.Assert (t is ScalarType);
|
||||||
|
|
||||||
|
object constant = ConvertConstant(instruction.ResultType as ScalarType, instruction.Words, 3);
|
||||||
|
instruction.Operands[2].Value = constant;
|
||||||
|
instruction.Value = constant;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ParsedInstruction instruction in debugInstructions)
|
||||||
|
{
|
||||||
|
switch (instruction.Instruction)
|
||||||
|
{
|
||||||
|
case OpMemberName mn:
|
||||||
|
{
|
||||||
|
StructType t = (StructType)objects[instruction.Words[1]].ResultType;
|
||||||
|
t.SetMemberName((uint)instruction.Operands[1].Value, (string)instruction.Operands[2].Value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpName n:
|
||||||
|
{
|
||||||
|
// We skip naming objects we don't know about
|
||||||
|
ParsedInstruction t = objects[instruction.Words[1]];
|
||||||
|
t.Name = (string)instruction.Operands[1].Value;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ParsedInstruction instruction in instructions)
|
||||||
|
{
|
||||||
|
instruction.ResolveReferences(objects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Module ReadFrom(Stream stream)
|
||||||
|
{
|
||||||
|
BinaryReader br = new BinaryReader(stream);
|
||||||
|
Reader reader = new Reader(br);
|
||||||
|
|
||||||
|
uint versionNumber = reader.ReadDWord();
|
||||||
|
int majorVersion = (int)(versionNumber >> 16);
|
||||||
|
int minorVersion = (int)((versionNumber >> 8) & 0xFF);
|
||||||
|
Version version = new Version(majorVersion, minorVersion);
|
||||||
|
|
||||||
|
uint generatorMagicNumber = reader.ReadDWord();
|
||||||
|
int generatorToolId = (int)(generatorMagicNumber >> 16);
|
||||||
|
string generatorVendor = "unknown";
|
||||||
|
string generatorName = null;
|
||||||
|
|
||||||
|
if (Meta.Tools.ContainsKey(generatorToolId))
|
||||||
|
{
|
||||||
|
Meta.ToolInfo toolInfo = Meta.Tools[generatorToolId];
|
||||||
|
generatorVendor = toolInfo.Vendor;
|
||||||
|
if (toolInfo.Name != null)
|
||||||
|
{
|
||||||
|
generatorName = toolInfo.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read header
|
||||||
|
ModuleHeader header = new ModuleHeader();
|
||||||
|
header.Version = version;
|
||||||
|
header.GeneratorName = generatorName;
|
||||||
|
header.GeneratorVendor = generatorVendor;
|
||||||
|
header.GeneratorVersion = (int)(generatorMagicNumber & 0xFFFF);
|
||||||
|
header.Bound = reader.ReadDWord();
|
||||||
|
header.Reserved = reader.ReadDWord();
|
||||||
|
|
||||||
|
List<ParsedInstruction> instructions = new List<ParsedInstruction>();
|
||||||
|
while (!reader.EndOfStream)
|
||||||
|
{
|
||||||
|
uint instructionStart = reader.ReadDWord ();
|
||||||
|
ushort wordCount = (ushort)(instructionStart >> 16);
|
||||||
|
int opCode = (int)(instructionStart & 0xFFFF);
|
||||||
|
|
||||||
|
uint[] words = new uint[wordCount];
|
||||||
|
words[0] = instructionStart;
|
||||||
|
for (ushort i = 1; i < wordCount; ++i)
|
||||||
|
{
|
||||||
|
words[i] = reader.ReadDWord();
|
||||||
|
}
|
||||||
|
|
||||||
|
ParsedInstruction instruction = new ParsedInstruction(opCode, words);
|
||||||
|
instructions.Add(instruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Module(header, instructions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collect types from OpType* instructions
|
||||||
|
/// </summary>
|
||||||
|
private static void ProcessTypeInstruction(ParsedInstruction i, IReadOnlyDictionary<uint, ParsedInstruction> objects)
|
||||||
|
{
|
||||||
|
switch (i.Instruction)
|
||||||
|
{
|
||||||
|
case OpTypeInt t:
|
||||||
|
{
|
||||||
|
i.ResultType = new IntegerType((int)i.Words[2], i.Words[3] == 1u);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpTypeFloat t:
|
||||||
|
{
|
||||||
|
i.ResultType = new FloatingPointType((int)i.Words[2]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpTypeVector t:
|
||||||
|
{
|
||||||
|
i.ResultType = new VectorType((ScalarType)objects[i.Words[2]].ResultType, (int)i.Words[3]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpTypeMatrix t:
|
||||||
|
{
|
||||||
|
i.ResultType = new MatrixType((VectorType)objects[i.Words[2]].ResultType, (int)i.Words[3]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpTypeArray t:
|
||||||
|
{
|
||||||
|
object constant = objects[i.Words[3]].Value;
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
switch (constant)
|
||||||
|
{
|
||||||
|
case ushort u16:
|
||||||
|
size = u16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case uint u32:
|
||||||
|
size = (int)u32;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ulong u64:
|
||||||
|
size = (int)u64;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case short i16:
|
||||||
|
size = i16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case int i32:
|
||||||
|
size = i32;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case long i64:
|
||||||
|
size = (int)i64;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
i.ResultType = new ArrayType(objects[i.Words[2]].ResultType, size);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpTypeRuntimeArray t:
|
||||||
|
{
|
||||||
|
i.ResultType = new RuntimeArrayType((Type)objects[i.Words[2]].ResultType);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpTypeBool t:
|
||||||
|
{
|
||||||
|
i.ResultType = new BoolType();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpTypeOpaque t:
|
||||||
|
{
|
||||||
|
i.ResultType = new OpaqueType();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpTypeVoid t:
|
||||||
|
{
|
||||||
|
i.ResultType = new VoidType();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpTypeImage t:
|
||||||
|
{
|
||||||
|
Type sampledType = objects[i.Operands[1].GetId ()].ResultType;
|
||||||
|
Dim dim = i.Operands[2].GetSingleEnumValue<Dim>();
|
||||||
|
uint depth = (uint)i.Operands[3].Value;
|
||||||
|
bool isArray = (uint)i.Operands[4].Value != 0;
|
||||||
|
bool isMultiSampled = (uint)i.Operands[5].Value != 0;
|
||||||
|
uint sampled = (uint)i.Operands[6].Value;
|
||||||
|
ImageFormat imageFormat = i.Operands[7].GetSingleEnumValue<ImageFormat>();
|
||||||
|
|
||||||
|
i.ResultType = new ImageType(sampledType,
|
||||||
|
dim,
|
||||||
|
(int)depth, isArray, isMultiSampled,
|
||||||
|
(int)sampled, imageFormat,
|
||||||
|
i.Operands.Count > 8 ? i.Operands[8].GetSingleEnumValue<AccessQualifier>() : AccessQualifier.ReadOnly);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpTypeSampler st:
|
||||||
|
{
|
||||||
|
i.ResultType = new SamplerType();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case OpTypeSampledImage t:
|
||||||
|
{
|
||||||
|
i.ResultType = new SampledImageType((ImageType)objects[i.Words[2]].ResultType);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpTypeFunction t:
|
||||||
|
{
|
||||||
|
List<Type> parameterTypes = new List<Type>();
|
||||||
|
for (int j = 3; j < i.Words.Count; ++j)
|
||||||
|
{
|
||||||
|
parameterTypes.Add(objects[i.Words[j]].ResultType);
|
||||||
|
}
|
||||||
|
i.ResultType = new FunctionType(objects[i.Words[2]].ResultType, parameterTypes);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpTypeForwardPointer t:
|
||||||
|
{
|
||||||
|
// We create a normal pointer, but with unspecified type
|
||||||
|
// This will get resolved later on
|
||||||
|
i.ResultType = new PointerType((StorageClass)i.Words[2]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpTypePointer t:
|
||||||
|
{
|
||||||
|
if (objects.ContainsKey(i.Words[1]))
|
||||||
|
{
|
||||||
|
// If there is something present, it must have been
|
||||||
|
// a forward reference. The storage type must
|
||||||
|
// match
|
||||||
|
PointerType pt = (PointerType)i.ResultType;
|
||||||
|
Debug.Assert (pt != null);
|
||||||
|
Debug.Assert (pt.StorageClass == (StorageClass)i.Words[2]);
|
||||||
|
pt.ResolveForwardReference (objects[i.Words[3]].ResultType);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i.ResultType = new PointerType((StorageClass)i.Words[2], objects[i.Words[3]].ResultType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpTypeStruct t:
|
||||||
|
{
|
||||||
|
List<Type> memberTypes = new List<Type>();
|
||||||
|
for (int j = 2; j < i.Words.Count; ++j)
|
||||||
|
{
|
||||||
|
memberTypes.Add(objects[i.Words[j]].ResultType);
|
||||||
|
}
|
||||||
|
i.ResultType = new StructType(memberTypes);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static object ConvertConstant(ScalarType type, IReadOnlyList<uint> words, int index)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case IntegerType i:
|
||||||
|
{
|
||||||
|
if (i.Signed)
|
||||||
|
{
|
||||||
|
if (i.Width == 16)
|
||||||
|
{
|
||||||
|
return unchecked((short)(words[index]));
|
||||||
|
}
|
||||||
|
else if (i.Width == 32)
|
||||||
|
{
|
||||||
|
return unchecked((int)(words[index]));
|
||||||
|
}
|
||||||
|
else if (i.Width == 64)
|
||||||
|
{
|
||||||
|
return unchecked((long)(words[index] | (ulong)(words[index + 1]) << 32));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (i.Width == 16)
|
||||||
|
{
|
||||||
|
return unchecked((ushort)(words[index]));
|
||||||
|
}
|
||||||
|
else if (i.Width == 32)
|
||||||
|
{
|
||||||
|
return words[index];
|
||||||
|
}
|
||||||
|
else if (i.Width == 64)
|
||||||
|
{
|
||||||
|
return words[index] | (ulong)(words[index + 1]) << 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception ("Cannot construct integer literal.");
|
||||||
|
}
|
||||||
|
|
||||||
|
case FloatingPointType f:
|
||||||
|
{
|
||||||
|
if (f.Width == 32)
|
||||||
|
{
|
||||||
|
return new FloatUIntUnion { Int = words[0] }.Float;
|
||||||
|
}
|
||||||
|
else if (f.Width == 64)
|
||||||
|
{
|
||||||
|
return new DoubleULongUnion { Long = (words[index] | (ulong)(words[index + 1]) << 32) }.Double;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Cannot construct floating point literal.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ModuleHeader Header { get; }
|
||||||
|
public IReadOnlyList<ParsedInstruction> Instructions { get; }
|
||||||
|
|
||||||
|
private static HashSet<string> debugInstructions_ = new HashSet<string>
|
||||||
|
{
|
||||||
|
"OpSourceContinued",
|
||||||
|
"OpSource",
|
||||||
|
"OpSourceExtension",
|
||||||
|
"OpName",
|
||||||
|
"OpMemberName",
|
||||||
|
"OpString",
|
||||||
|
"OpLine",
|
||||||
|
"OpNoLine",
|
||||||
|
"OpModuleProcessed"
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly Dictionary<uint, ParsedInstruction> objects_ = new Dictionary<uint, ParsedInstruction>();
|
||||||
|
}
|
||||||
|
}
|
302
AssetStudioUtility/CSspv/OperandType.cs
Normal file
302
AssetStudioUtility/CSspv/OperandType.cs
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace SpirV
|
||||||
|
{
|
||||||
|
public class OperandType
|
||||||
|
{
|
||||||
|
public virtual bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||||
|
{
|
||||||
|
// This returns the dynamic type
|
||||||
|
value = GetType();
|
||||||
|
wordsUsed = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Literal : OperandType
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LiteralNumber : Literal
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// The SPIR-V JSON file uses only literal integers
|
||||||
|
public class LiteralInteger : LiteralNumber
|
||||||
|
{
|
||||||
|
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||||
|
{
|
||||||
|
value = words[index];
|
||||||
|
wordsUsed = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LiteralString : Literal
|
||||||
|
{
|
||||||
|
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||||
|
{
|
||||||
|
// This is just a fail-safe -- the loop below must terminate
|
||||||
|
wordsUsed = 1;
|
||||||
|
int bytesUsed = 0;
|
||||||
|
byte[] bytes = new byte[(words.Count - index) * 4];
|
||||||
|
for (int i = index; i < words.Count; ++i)
|
||||||
|
{
|
||||||
|
uint word = words[i];
|
||||||
|
byte b0 = (byte)(word & 0xFF);
|
||||||
|
if (b0 == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bytes[bytesUsed++] = b0;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte b1 = (byte)((word >> 8) & 0xFF);
|
||||||
|
if (b1 == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bytes[bytesUsed++] = b1;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte b2 = (byte)((word >> 16) & 0xFF);
|
||||||
|
if (b2 == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bytes[bytesUsed++] = b2;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte b3 = (byte)(word >> 24);
|
||||||
|
if (b3 == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bytes[bytesUsed++] = b3;
|
||||||
|
}
|
||||||
|
wordsUsed++;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = Encoding.UTF8.GetString(bytes, 0, bytesUsed);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LiteralContextDependentNumber : Literal
|
||||||
|
{
|
||||||
|
// This is handled during parsing by ConvertConstant
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LiteralExtInstInteger : Literal
|
||||||
|
{
|
||||||
|
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||||
|
{
|
||||||
|
value = words[index];
|
||||||
|
wordsUsed = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LiteralSpecConstantOpInteger : Literal
|
||||||
|
{
|
||||||
|
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||||
|
{
|
||||||
|
List<ObjectReference> result = new List<ObjectReference>();
|
||||||
|
for (int i = index; i < words.Count; i++)
|
||||||
|
{
|
||||||
|
ObjectReference objRef = new ObjectReference(words[i]);
|
||||||
|
result.Add(objRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
value = result;
|
||||||
|
wordsUsed = words.Count - index;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Parameter
|
||||||
|
{
|
||||||
|
public virtual IReadOnlyList<OperandType> OperandTypes { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ParameterFactory
|
||||||
|
{
|
||||||
|
public virtual Parameter CreateParameter(object value)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EnumType<T> : EnumType<T, ParameterFactory>
|
||||||
|
where T : Enum
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
public class EnumType<T, U> : OperandType
|
||||||
|
where T : Enum
|
||||||
|
where U : ParameterFactory, new ()
|
||||||
|
{
|
||||||
|
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||||
|
{
|
||||||
|
int wordsUsedForParameters = 0;
|
||||||
|
if (typeof(T).GetTypeInfo().GetCustomAttributes<FlagsAttribute>().Any())
|
||||||
|
{
|
||||||
|
Dictionary<uint, IReadOnlyList<object>> result = new Dictionary<uint, IReadOnlyList<object>>();
|
||||||
|
foreach (object enumValue in EnumerationType.GetEnumValues())
|
||||||
|
{
|
||||||
|
uint bit = (uint)enumValue;
|
||||||
|
// bit == 0 and words[0] == 0 handles the 0x0 = None cases
|
||||||
|
if ((words[index] & bit) != 0 || (bit == 0 && words[index] == 0))
|
||||||
|
{
|
||||||
|
Parameter p = parameterFactory_.CreateParameter(bit);
|
||||||
|
if (p == null)
|
||||||
|
{
|
||||||
|
result.Add(bit, Array.Empty<object>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
object[] resultItems = new object[p.OperandTypes.Count];
|
||||||
|
for (int j = 0; j < p.OperandTypes.Count; ++j)
|
||||||
|
{
|
||||||
|
p.OperandTypes[j].ReadValue(words, 1 + wordsUsedForParameters, out object pValue, out int pWordsUsed);
|
||||||
|
wordsUsedForParameters += pWordsUsed;
|
||||||
|
resultItems[j] = pValue;
|
||||||
|
}
|
||||||
|
result.Add(bit, resultItems);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value = new BitEnumOperandValue<T>(result);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
object[] resultItems;
|
||||||
|
Parameter p = parameterFactory_.CreateParameter(words[index]);
|
||||||
|
if (p == null)
|
||||||
|
{
|
||||||
|
resultItems = Array.Empty<object>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resultItems = new object[p.OperandTypes.Count];
|
||||||
|
for (int j = 0; j < p.OperandTypes.Count; ++j)
|
||||||
|
{
|
||||||
|
p.OperandTypes[j].ReadValue(words, 1 + wordsUsedForParameters, out object pValue, out int pWordsUsed);
|
||||||
|
wordsUsedForParameters += pWordsUsed;
|
||||||
|
resultItems[j] = pValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
value = new ValueEnumOperandValue<T>((T)(object)words[index], resultItems);
|
||||||
|
}
|
||||||
|
|
||||||
|
wordsUsed = wordsUsedForParameters + 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public System.Type EnumerationType => typeof(T);
|
||||||
|
|
||||||
|
private U parameterFactory_ = new U();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IdScope : OperandType
|
||||||
|
{
|
||||||
|
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||||
|
{
|
||||||
|
value = (Scope)words[index];
|
||||||
|
wordsUsed = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IdMemorySemantics : OperandType
|
||||||
|
{
|
||||||
|
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||||
|
{
|
||||||
|
value = (MemorySemantics)words[index];
|
||||||
|
wordsUsed = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IdType : OperandType
|
||||||
|
{
|
||||||
|
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||||
|
{
|
||||||
|
value = words[index];
|
||||||
|
wordsUsed = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IdResult : IdType
|
||||||
|
{
|
||||||
|
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||||
|
{
|
||||||
|
value = new ObjectReference(words[index]);
|
||||||
|
wordsUsed = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IdResultType : IdType
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IdRef : IdType
|
||||||
|
{
|
||||||
|
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||||
|
{
|
||||||
|
value = new ObjectReference(words[index]);
|
||||||
|
wordsUsed = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PairIdRefIdRef : OperandType
|
||||||
|
{
|
||||||
|
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||||
|
{
|
||||||
|
ObjectReference variable = new ObjectReference(words[index]);
|
||||||
|
ObjectReference parent = new ObjectReference(words[index + 1]);
|
||||||
|
value = new { Variable = variable, Parent = parent };
|
||||||
|
wordsUsed = 2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PairIdRefLiteralInteger : OperandType
|
||||||
|
{
|
||||||
|
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||||
|
{
|
||||||
|
ObjectReference type = new ObjectReference(words[index]);
|
||||||
|
uint word = words[index + 1];
|
||||||
|
value = new { Type = type, Member = word };
|
||||||
|
wordsUsed = 2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PairLiteralIntegerIdRef : OperandType
|
||||||
|
{
|
||||||
|
public override bool ReadValue(IReadOnlyList<uint> words, int index, out object value, out int wordsUsed)
|
||||||
|
{
|
||||||
|
uint selector = words[index];
|
||||||
|
ObjectReference label = new ObjectReference(words[index + 1]);
|
||||||
|
value = new { Selector = selector, Label = label };
|
||||||
|
wordsUsed = 2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
265
AssetStudioUtility/CSspv/ParsedInstruction.cs
Normal file
265
AssetStudioUtility/CSspv/ParsedInstruction.cs
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace SpirV
|
||||||
|
{
|
||||||
|
public class ParsedOperand
|
||||||
|
{
|
||||||
|
public ParsedOperand(IReadOnlyList<uint> words, int index, int count, object value, Operand operand)
|
||||||
|
{
|
||||||
|
uint[] array = new uint[count];
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
array[i] = words[index + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
Words = array;
|
||||||
|
Value = value;
|
||||||
|
Operand = operand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T GetSingleEnumValue<T>()
|
||||||
|
where T : Enum
|
||||||
|
{
|
||||||
|
IValueEnumOperandValue v = (IValueEnumOperandValue)Value;
|
||||||
|
if (v.Value.Count == 0)
|
||||||
|
{
|
||||||
|
// If there's no value at all, the enum is probably something like ImageFormat.
|
||||||
|
// In which case we just return the enum value
|
||||||
|
return (T)v.Key;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// This means the enum has a value attached to it, so we return the attached value
|
||||||
|
return (T)((IValueEnumOperandValue)Value).Value[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint GetId()
|
||||||
|
{
|
||||||
|
return ((ObjectReference)Value).Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T GetBitEnumValue<T>()
|
||||||
|
where T : Enum
|
||||||
|
{
|
||||||
|
var v = Value as IBitEnumOperandValue;
|
||||||
|
|
||||||
|
uint result = 0;
|
||||||
|
foreach (var k in v.Values.Keys)
|
||||||
|
{
|
||||||
|
result |= k;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T)(object)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<uint> Words { get; }
|
||||||
|
public object Value { get; set; }
|
||||||
|
public Operand Operand { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VaryingOperandValue
|
||||||
|
{
|
||||||
|
public VaryingOperandValue(IReadOnlyList<object> values)
|
||||||
|
{
|
||||||
|
Values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
ToString(sb);
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringBuilder ToString(StringBuilder sb)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Values.Count; ++i)
|
||||||
|
{
|
||||||
|
if (Values[i] is ObjectReference objRef)
|
||||||
|
{
|
||||||
|
objRef.ToString(sb);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(Values[i]);
|
||||||
|
}
|
||||||
|
if (i < (Values.Count - 1))
|
||||||
|
{
|
||||||
|
sb.Append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<object> Values { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IEnumOperandValue
|
||||||
|
{
|
||||||
|
System.Type EnumerationType { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IBitEnumOperandValue : IEnumOperandValue
|
||||||
|
{
|
||||||
|
IReadOnlyDictionary<uint, IReadOnlyList<object>> Values { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IValueEnumOperandValue : IEnumOperandValue
|
||||||
|
{
|
||||||
|
object Key { get; }
|
||||||
|
IReadOnlyList<object> Value { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ValueEnumOperandValue<T> : IValueEnumOperandValue
|
||||||
|
where T : Enum
|
||||||
|
{
|
||||||
|
public ValueEnumOperandValue(T key, IReadOnlyList<object> value)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public System.Type EnumerationType => typeof(T);
|
||||||
|
public object Key { get; }
|
||||||
|
public IReadOnlyList<object> Value { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BitEnumOperandValue<T> : IBitEnumOperandValue
|
||||||
|
where T : Enum
|
||||||
|
{
|
||||||
|
public BitEnumOperandValue(Dictionary<uint, IReadOnlyList<object>> values)
|
||||||
|
{
|
||||||
|
Values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyDictionary<uint, IReadOnlyList<object>> Values { get; }
|
||||||
|
public System.Type EnumerationType => typeof(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ObjectReference
|
||||||
|
{
|
||||||
|
public ObjectReference(uint id)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resolve(IReadOnlyDictionary<uint, ParsedInstruction> objects)
|
||||||
|
{
|
||||||
|
Reference = objects[Id];
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"%{Id}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public StringBuilder ToString(StringBuilder sb)
|
||||||
|
{
|
||||||
|
return sb.Append('%').Append(Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint Id { get; }
|
||||||
|
public ParsedInstruction Reference { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ParsedInstruction
|
||||||
|
{
|
||||||
|
public ParsedInstruction(int opCode, IReadOnlyList<uint> words)
|
||||||
|
{
|
||||||
|
Words = words;
|
||||||
|
Instruction = Instructions.OpcodeToInstruction[opCode];
|
||||||
|
ParseOperands();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseOperands()
|
||||||
|
{
|
||||||
|
if (Instruction.Operands.Count == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Word 0 describes this instruction so we can ignore it
|
||||||
|
int currentWord = 1;
|
||||||
|
int currentOperand = 0;
|
||||||
|
List<object> varyingOperandValues = new List<object>();
|
||||||
|
int varyingWordStart = 0;
|
||||||
|
Operand varyingOperand = null;
|
||||||
|
|
||||||
|
while (currentWord < Words.Count)
|
||||||
|
{
|
||||||
|
Operand operand = Instruction.Operands[currentOperand];
|
||||||
|
operand.Type.ReadValue(Words, currentWord, out object value, out int wordsUsed);
|
||||||
|
if (operand.Quantifier == OperandQuantifier.Varying)
|
||||||
|
{
|
||||||
|
varyingOperandValues.Add(value);
|
||||||
|
varyingWordStart = currentWord;
|
||||||
|
varyingOperand = operand;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int wordCount = Math.Min(Words.Count - currentWord, wordsUsed);
|
||||||
|
ParsedOperand parsedOperand = new ParsedOperand(Words, currentWord, wordCount, value, operand);
|
||||||
|
Operands.Add(parsedOperand);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentWord += wordsUsed;
|
||||||
|
if (operand.Quantifier != OperandQuantifier.Varying)
|
||||||
|
{
|
||||||
|
++currentOperand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (varyingOperand != null)
|
||||||
|
{
|
||||||
|
VaryingOperandValue varOperantValue = new VaryingOperandValue(varyingOperandValues);
|
||||||
|
ParsedOperand parsedOperand = new ParsedOperand(Words, currentWord, Words.Count - currentWord, varOperantValue, varyingOperand);
|
||||||
|
Operands.Add(parsedOperand);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResolveResultType(IReadOnlyDictionary<uint, ParsedInstruction> objects)
|
||||||
|
{
|
||||||
|
if (Instruction.Operands.Count > 0 && Instruction.Operands[0].Type is IdResultType)
|
||||||
|
{
|
||||||
|
ResultType = objects[(uint)Operands[0].Value].ResultType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResolveReferences (IReadOnlyDictionary<uint, ParsedInstruction> objects)
|
||||||
|
{
|
||||||
|
foreach (var operand in Operands)
|
||||||
|
{
|
||||||
|
if (operand.Value is ObjectReference objectReference)
|
||||||
|
{
|
||||||
|
objectReference.Resolve (objects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type ResultType { get; set; }
|
||||||
|
public uint ResultId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Instruction.Operands.Count; ++i)
|
||||||
|
{
|
||||||
|
if (Instruction.Operands[i].Type is IdResult)
|
||||||
|
{
|
||||||
|
return Operands[i].GetId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool HasResult => ResultId != 0;
|
||||||
|
|
||||||
|
public IReadOnlyList<uint> Words { get; }
|
||||||
|
public Instruction Instruction { get; }
|
||||||
|
public IList<ParsedOperand> Operands { get; } = new List<ParsedOperand>();
|
||||||
|
public string Name { get; set; }
|
||||||
|
public object Value { get; set; }
|
||||||
|
}
|
||||||
|
}
|
50
AssetStudioUtility/CSspv/Reader.cs
Normal file
50
AssetStudioUtility/CSspv/Reader.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace SpirV
|
||||||
|
{
|
||||||
|
internal sealed class Reader
|
||||||
|
{
|
||||||
|
public Reader(BinaryReader reader)
|
||||||
|
{
|
||||||
|
reader_ = reader;
|
||||||
|
uint magicNumber = reader_.ReadUInt32();
|
||||||
|
if (magicNumber == Meta.MagicNumber)
|
||||||
|
{
|
||||||
|
littleEndian_ = true;
|
||||||
|
}
|
||||||
|
else if (Reverse(magicNumber) == Meta.MagicNumber)
|
||||||
|
{
|
||||||
|
littleEndian_ = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Invalid magic number");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint ReadDWord()
|
||||||
|
{
|
||||||
|
if (littleEndian_)
|
||||||
|
{
|
||||||
|
return reader_.ReadUInt32 ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Reverse(reader_.ReadUInt32());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static uint Reverse(uint u)
|
||||||
|
{
|
||||||
|
return (u << 24) | (u & 0xFF00U) << 8 | (u >> 8) & 0xFF00U | (u >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EndOfStream => reader_.BaseStream.Position == reader_.BaseStream.Length;
|
||||||
|
|
||||||
|
private readonly BinaryReader reader_;
|
||||||
|
private readonly bool littleEndian_;
|
||||||
|
}
|
||||||
|
}
|
3543
AssetStudioUtility/CSspv/SpirV.Core.Grammar.cs
Normal file
3543
AssetStudioUtility/CSspv/SpirV.Core.Grammar.cs
Normal file
File diff suppressed because one or more lines are too long
54
AssetStudioUtility/CSspv/SpirV.Meta.cs
Normal file
54
AssetStudioUtility/CSspv/SpirV.Meta.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace SpirV
|
||||||
|
{
|
||||||
|
internal class Meta
|
||||||
|
{
|
||||||
|
public class ToolInfo
|
||||||
|
{
|
||||||
|
public ToolInfo(string vendor)
|
||||||
|
{
|
||||||
|
Vendor = vendor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ToolInfo(string vendor, string name)
|
||||||
|
{
|
||||||
|
Vendor = vendor;
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
public string Vendor { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint MagicNumber => 119734787U;
|
||||||
|
public static uint Version => 66048U;
|
||||||
|
public static uint Revision => 2U;
|
||||||
|
public static uint OpCodeMask => 65535U;
|
||||||
|
public static uint WordCountShift => 16U;
|
||||||
|
|
||||||
|
public static IReadOnlyDictionary<int, ToolInfo> Tools => toolInfos_;
|
||||||
|
|
||||||
|
private readonly static Dictionary<int, ToolInfo> toolInfos_ = new Dictionary<int, ToolInfo>
|
||||||
|
{
|
||||||
|
{ 0, new ToolInfo("Khronos") },
|
||||||
|
{ 1, new ToolInfo("LunarG") },
|
||||||
|
{ 2, new ToolInfo("Valve") },
|
||||||
|
{ 3, new ToolInfo("Codeplay") },
|
||||||
|
{ 4, new ToolInfo("NVIDIA") },
|
||||||
|
{ 5, new ToolInfo("ARM") },
|
||||||
|
{ 6, new ToolInfo("Khronos", "LLVM/SPIR-V Translator") },
|
||||||
|
{ 7, new ToolInfo("Khronos", "SPIR-V Tools Assembler") },
|
||||||
|
{ 8, new ToolInfo("Khronos", "Glslang Reference Front End") },
|
||||||
|
{ 9, new ToolInfo("Qualcomm") },
|
||||||
|
{ 10, new ToolInfo("AMD") },
|
||||||
|
{ 11, new ToolInfo("Intel") },
|
||||||
|
{ 12, new ToolInfo("Imagination") },
|
||||||
|
{ 13, new ToolInfo("Google", "Shaderc over Glslang") },
|
||||||
|
{ 14, new ToolInfo("Google", "spiregg") },
|
||||||
|
{ 15, new ToolInfo("Google", "rspirv") },
|
||||||
|
{ 16, new ToolInfo("X-LEGEND", "Mesa-IR/SPIR-V Translator") },
|
||||||
|
{ 17, new ToolInfo("Khronos", "SPIR-V Tools Linker") },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
428
AssetStudioUtility/CSspv/Types.cs
Normal file
428
AssetStudioUtility/CSspv/Types.cs
Normal file
@ -0,0 +1,428 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace SpirV
|
||||||
|
{
|
||||||
|
public class Type
|
||||||
|
{
|
||||||
|
public virtual StringBuilder ToString(StringBuilder sb)
|
||||||
|
{
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VoidType : Type
|
||||||
|
{
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "void";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override StringBuilder ToString(StringBuilder sb)
|
||||||
|
{
|
||||||
|
return sb.Append("void");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ScalarType : Type
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BoolType : ScalarType
|
||||||
|
{
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "bool";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override StringBuilder ToString(StringBuilder sb)
|
||||||
|
{
|
||||||
|
return sb.Append("bool");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IntegerType : ScalarType
|
||||||
|
{
|
||||||
|
public IntegerType (int width, bool signed)
|
||||||
|
{
|
||||||
|
Width = width;
|
||||||
|
Signed = signed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
if (Signed)
|
||||||
|
{
|
||||||
|
return $"i{Width}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $"u{Width}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override StringBuilder ToString(StringBuilder sb)
|
||||||
|
{
|
||||||
|
if (Signed)
|
||||||
|
{
|
||||||
|
sb.Append('i').Append(Width);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append('u').Append(Width);
|
||||||
|
}
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Width { get; }
|
||||||
|
public bool Signed { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FloatingPointType : ScalarType
|
||||||
|
{
|
||||||
|
public FloatingPointType (int width)
|
||||||
|
{
|
||||||
|
Width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"f{Width}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override StringBuilder ToString(StringBuilder sb)
|
||||||
|
{
|
||||||
|
return sb.Append('f').Append(Width);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Width { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VectorType : Type
|
||||||
|
{
|
||||||
|
public VectorType (ScalarType scalarType, int componentCount)
|
||||||
|
{
|
||||||
|
ComponentType = scalarType;
|
||||||
|
ComponentCount = componentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{ComponentType}_{ComponentCount}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override StringBuilder ToString(StringBuilder sb)
|
||||||
|
{
|
||||||
|
return ComponentType.ToString(sb).Append('_').Append(ComponentCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScalarType ComponentType { get; }
|
||||||
|
public int ComponentCount { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MatrixType : Type
|
||||||
|
{
|
||||||
|
public MatrixType (VectorType vectorType, int columnCount)
|
||||||
|
{
|
||||||
|
ColumnType = vectorType;
|
||||||
|
ColumnCount = columnCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString ()
|
||||||
|
{
|
||||||
|
return $"{ColumnType}x{ColumnCount}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override StringBuilder ToString(StringBuilder sb)
|
||||||
|
{
|
||||||
|
return sb.Append(ColumnType).Append('x').Append(ColumnCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VectorType ColumnType { get; }
|
||||||
|
public int ColumnCount { get; }
|
||||||
|
public int RowCount => ColumnType.ComponentCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ImageType : Type
|
||||||
|
{
|
||||||
|
public ImageType (Type sampledType, Dim dim, int depth, bool isArray, bool isMultisampled, int sampleCount,
|
||||||
|
ImageFormat imageFormat, AccessQualifier accessQualifier)
|
||||||
|
{
|
||||||
|
SampledType = sampledType;
|
||||||
|
Dim = dim;
|
||||||
|
Depth = depth;
|
||||||
|
IsArray = isArray;
|
||||||
|
IsMultisampled = isMultisampled;
|
||||||
|
SampleCount = sampleCount;
|
||||||
|
Format = imageFormat;
|
||||||
|
AccessQualifier = accessQualifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString ()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder ();
|
||||||
|
ToString(sb);
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override StringBuilder ToString(StringBuilder sb)
|
||||||
|
{
|
||||||
|
switch (AccessQualifier)
|
||||||
|
{
|
||||||
|
case AccessQualifier.ReadWrite:
|
||||||
|
sb.Append("read_write ");
|
||||||
|
break;
|
||||||
|
case AccessQualifier.WriteOnly:
|
||||||
|
sb.Append("write_only ");
|
||||||
|
break;
|
||||||
|
case AccessQualifier.ReadOnly:
|
||||||
|
sb.Append("read_only ");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append("Texture");
|
||||||
|
switch (Dim)
|
||||||
|
{
|
||||||
|
case Dim.Dim1D:
|
||||||
|
sb.Append("1D");
|
||||||
|
break;
|
||||||
|
case Dim.Dim2D:
|
||||||
|
sb.Append("2D");
|
||||||
|
break;
|
||||||
|
case Dim.Dim3D:
|
||||||
|
sb.Append("3D");
|
||||||
|
break;
|
||||||
|
case Dim.Cube:
|
||||||
|
sb.Append("Cube");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsMultisampled)
|
||||||
|
{
|
||||||
|
sb.Append("MS");
|
||||||
|
}
|
||||||
|
if (IsArray)
|
||||||
|
{
|
||||||
|
sb.Append("Array");
|
||||||
|
}
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type SampledType { get; }
|
||||||
|
public Dim Dim { get; }
|
||||||
|
public int Depth { get; }
|
||||||
|
public bool IsArray { get; }
|
||||||
|
public bool IsMultisampled { get; }
|
||||||
|
public int SampleCount { get; }
|
||||||
|
public ImageFormat Format { get; }
|
||||||
|
public AccessQualifier AccessQualifier { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SamplerType : Type
|
||||||
|
{
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "sampler";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override StringBuilder ToString(StringBuilder sb)
|
||||||
|
{
|
||||||
|
return sb.Append("sampler");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class SampledImageType : Type
|
||||||
|
{
|
||||||
|
public SampledImageType (ImageType imageType)
|
||||||
|
{
|
||||||
|
ImageType = imageType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{ImageType}Sampled";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override StringBuilder ToString(StringBuilder sb)
|
||||||
|
{
|
||||||
|
return ImageType.ToString(sb).Append("Sampled");
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageType ImageType { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ArrayType : Type
|
||||||
|
{
|
||||||
|
public ArrayType (Type elementType, int elementCount)
|
||||||
|
{
|
||||||
|
ElementType = elementType;
|
||||||
|
ElementCount = elementCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{ElementType}[{ElementCount}]";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override StringBuilder ToString(StringBuilder sb)
|
||||||
|
{
|
||||||
|
return ElementType.ToString(sb).Append('[').Append(ElementCount).Append(']');
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ElementCount { get; }
|
||||||
|
public Type ElementType { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RuntimeArrayType : Type
|
||||||
|
{
|
||||||
|
public RuntimeArrayType(Type elementType)
|
||||||
|
{
|
||||||
|
ElementType = elementType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type ElementType { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StructType : Type
|
||||||
|
{
|
||||||
|
public StructType(IReadOnlyList<Type> memberTypes)
|
||||||
|
{
|
||||||
|
MemberTypes = memberTypes;
|
||||||
|
memberNames_ = new List<string>();
|
||||||
|
|
||||||
|
for (int i = 0; i < memberTypes.Count; ++i)
|
||||||
|
{
|
||||||
|
memberNames_.Add(string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetMemberName(uint member, string name)
|
||||||
|
{
|
||||||
|
memberNames_[(int)member] = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
ToString(sb);
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override StringBuilder ToString(StringBuilder sb)
|
||||||
|
{
|
||||||
|
sb.Append("struct {");
|
||||||
|
for (int i = 0; i < MemberTypes.Count; ++i)
|
||||||
|
{
|
||||||
|
Type memberType = MemberTypes[i];
|
||||||
|
memberType.ToString(sb);
|
||||||
|
if (!string.IsNullOrEmpty(memberNames_[i]))
|
||||||
|
{
|
||||||
|
sb.Append(' ');
|
||||||
|
sb.Append(MemberNames[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.Append(';');
|
||||||
|
if (i < (MemberTypes.Count - 1))
|
||||||
|
{
|
||||||
|
sb.Append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.Append('}');
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<Type> MemberTypes { get; }
|
||||||
|
public IReadOnlyList<string> MemberNames => memberNames_;
|
||||||
|
|
||||||
|
private List<string> memberNames_;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OpaqueType : Type
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PointerType : Type
|
||||||
|
{
|
||||||
|
public PointerType(StorageClass storageClass, Type type)
|
||||||
|
{
|
||||||
|
StorageClass = storageClass;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PointerType(StorageClass storageClass)
|
||||||
|
{
|
||||||
|
StorageClass = storageClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResolveForwardReference(Type t)
|
||||||
|
{
|
||||||
|
Type = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
if (Type == null)
|
||||||
|
{
|
||||||
|
return $"{StorageClass} *";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return $"{StorageClass} {Type}*";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override StringBuilder ToString(StringBuilder sb)
|
||||||
|
{
|
||||||
|
sb.Append(StorageClass.ToString()).Append(' ');
|
||||||
|
if (Type != null)
|
||||||
|
{
|
||||||
|
Type.ToString(sb);
|
||||||
|
}
|
||||||
|
sb.Append('*');
|
||||||
|
return sb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StorageClass StorageClass { get; }
|
||||||
|
public Type Type { get; private set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class FunctionType : Type
|
||||||
|
{
|
||||||
|
public FunctionType(Type returnType, IReadOnlyList<Type> parameterTypes)
|
||||||
|
{
|
||||||
|
ReturnType = returnType;
|
||||||
|
ParameterTypes = parameterTypes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type ReturnType { get; }
|
||||||
|
public IReadOnlyList<Type> ParameterTypes { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventType : Type
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DeviceEventType : Type
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ReserveIdType : Type
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class QueueType : Type
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PipeType : Type
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PipeStorage : Type
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class NamedBarrier : Type
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
@ -21,13 +21,13 @@ namespace AssetStudio
|
|||||||
using (var blobReader = new BinaryReader(new MemoryStream(decompressedBytes)))
|
using (var blobReader = new BinaryReader(new MemoryStream(decompressedBytes)))
|
||||||
{
|
{
|
||||||
var program = new ShaderProgram(blobReader, shader.version);
|
var program = new ShaderProgram(blobReader, shader.version);
|
||||||
return program.Export(Encoding.UTF8.GetString(shader.m_Script));
|
return header + program.Export(Encoding.UTF8.GetString(shader.m_Script));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shader.compressedBlob != null) //5.5 and up
|
if (shader.compressedBlob != null) //5.5 and up
|
||||||
{
|
{
|
||||||
return ConvertSerializedShader(shader);
|
return header + ConvertSerializedShader(shader);
|
||||||
}
|
}
|
||||||
|
|
||||||
return header + Encoding.UTF8.GetString(shader.m_Script);
|
return header + Encoding.UTF8.GetString(shader.m_Script);
|
||||||
@ -727,14 +727,14 @@ namespace AssetStudio
|
|||||||
case ShaderGpuProgramType.kShaderGpuProgramDX11HullSM50:
|
case ShaderGpuProgramType.kShaderGpuProgramDX11HullSM50:
|
||||||
case ShaderGpuProgramType.kShaderGpuProgramDX11DomainSM50:
|
case ShaderGpuProgramType.kShaderGpuProgramDX11DomainSM50:
|
||||||
{
|
{
|
||||||
int start = 6;
|
/*int start = 6;
|
||||||
if (m_Version == 201509030) // 5.3
|
if (m_Version == 201509030) // 5.3
|
||||||
{
|
{
|
||||||
start = 5;
|
start = 5;
|
||||||
}
|
}
|
||||||
var buff = new byte[m_ProgramCode.Length - start];
|
var buff = new byte[m_ProgramCode.Length - start];
|
||||||
Buffer.BlockCopy(m_ProgramCode, start, buff, 0, buff.Length);
|
Buffer.BlockCopy(m_ProgramCode, start, buff, 0, buff.Length);
|
||||||
/*var shaderBytecode = new ShaderBytecode(buff);
|
var shaderBytecode = new ShaderBytecode(buff);
|
||||||
sb.Append(shaderBytecode.Disassemble());*/
|
sb.Append(shaderBytecode.Disassemble());*/
|
||||||
sb.Append("// shader disassembly not supported on DXBC");
|
sb.Append("// shader disassembly not supported on DXBC");
|
||||||
break;
|
break;
|
||||||
@ -755,7 +755,14 @@ namespace AssetStudio
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ShaderGpuProgramType.kShaderGpuProgramSPIRV:
|
case ShaderGpuProgramType.kShaderGpuProgramSPIRV:
|
||||||
sb.Append("// shader disassembly not supported on SPIR-V\n");
|
try
|
||||||
|
{
|
||||||
|
sb.Append(SpirVShaderConverter.Convert(m_ProgramCode));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
sb.Append($"// disassembly error {e.Message}\n");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ShaderGpuProgramType.kShaderGpuProgramConsoleVS:
|
case ShaderGpuProgramType.kShaderGpuProgramConsoleVS:
|
||||||
case ShaderGpuProgramType.kShaderGpuProgramConsoleFS:
|
case ShaderGpuProgramType.kShaderGpuProgramConsoleFS:
|
||||||
|
365
AssetStudioUtility/Smolv/OpData.cs
Normal file
365
AssetStudioUtility/Smolv/OpData.cs
Normal 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
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
479
AssetStudioUtility/Smolv/SmolvDecoder.cs
Normal file
479
AssetStudioUtility/Smolv/SmolvDecoder.cs
Normal 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 < 16 range, for
|
||||||
|
/// more compact varint encoding. This basically swaps rarely used op values that are < 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);
|
||||||
|
}
|
||||||
|
}
|
369
AssetStudioUtility/Smolv/SpvOp.cs
Normal file
369
AssetStudioUtility/Smolv/SpvOp.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
74
AssetStudioUtility/SpirVShaderConverter.cs
Normal file
74
AssetStudioUtility/SpirVShaderConverter.cs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
using Smolv;
|
||||||
|
using SpirV;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace AssetStudio
|
||||||
|
{
|
||||||
|
public static class SpirVShaderConverter
|
||||||
|
{
|
||||||
|
public static string Convert(byte[] m_ProgramCode)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
using (var ms = new MemoryStream(m_ProgramCode))
|
||||||
|
{
|
||||||
|
using (var reader = new BinaryReader(ms))
|
||||||
|
{
|
||||||
|
int requirements = reader.ReadInt32();
|
||||||
|
int minOffset = m_ProgramCode.Length;
|
||||||
|
int snippetCount = 5;
|
||||||
|
/*if (version[0] > 2019 || (version[0] == 2019 && version[1] >= 3)) //2019.3 and up
|
||||||
|
{
|
||||||
|
snippetCount = 6;
|
||||||
|
}*/
|
||||||
|
for (int i = 0; i < snippetCount; i++)
|
||||||
|
{
|
||||||
|
if (reader.BaseStream.Position >= minOffset)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int offset = reader.ReadInt32();
|
||||||
|
int size = reader.ReadInt32();
|
||||||
|
if (size > 0)
|
||||||
|
{
|
||||||
|
if (offset < minOffset)
|
||||||
|
{
|
||||||
|
minOffset = offset;
|
||||||
|
}
|
||||||
|
var pos = ms.Position;
|
||||||
|
sb.Append(ExportSnippet(ms, offset, size));
|
||||||
|
ms.Position = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ExportSnippet(Stream stream, int offset, int size)
|
||||||
|
{
|
||||||
|
stream.Position = offset;
|
||||||
|
int decodedSize = SmolvDecoder.GetDecodedBufferSize(stream);
|
||||||
|
if (decodedSize == 0)
|
||||||
|
{
|
||||||
|
throw new Exception("Invalid SMOL-V shader header");
|
||||||
|
}
|
||||||
|
using (var decodedStream = new MemoryStream(new byte[decodedSize]))
|
||||||
|
{
|
||||||
|
if (SmolvDecoder.Decode(stream, size, decodedStream))
|
||||||
|
{
|
||||||
|
decodedStream.Position = 0;
|
||||||
|
var module = Module.ReadFrom(decodedStream);
|
||||||
|
var disassembler = new Disassembler();
|
||||||
|
return disassembler.Disassemble(module, DisassemblyOptions.Default).Replace("\r\n", "\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Unable to decode SMOL-V shader");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user