mirror of
https://github.com/libretro/ppsspp.git
synced 2025-02-25 19:30:53 +00:00
Implement a trivial SPIR-V disassembler, just for fun
This commit is contained in:
parent
c64064024d
commit
eedd81988c
@ -239,6 +239,7 @@
|
||||
<ClInclude Include="ThreadSafeList.h" />
|
||||
<ClInclude Include="Thunk.h" />
|
||||
<ClInclude Include="Timer.h" />
|
||||
<ClInclude Include="Vulkan\SPIRVDisasm.h" />
|
||||
<ClInclude Include="x64Analyzer.h" />
|
||||
<ClInclude Include="x64Emitter.h" />
|
||||
</ItemGroup>
|
||||
@ -307,6 +308,7 @@
|
||||
<ClCompile Include="ThreadPools.cpp" />
|
||||
<ClCompile Include="Thunk.cpp" />
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
<ClCompile Include="Vulkan\SPIRVDisasm.cpp" />
|
||||
<ClCompile Include="x64Analyzer.cpp" />
|
||||
<ClCompile Include="x64Emitter.cpp" />
|
||||
</ItemGroup>
|
||||
|
@ -58,6 +58,9 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="GraphicsContext.h" />
|
||||
<ClInclude Include="DbgNew.h" />
|
||||
<ClInclude Include="Vulkan\SPIRVDisasm.h">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
@ -103,6 +106,9 @@
|
||||
<ClCompile Include="GL\GLInterface\GLInterface.cpp">
|
||||
<Filter>GL\GLInterface</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Vulkan\SPIRVDisasm.cpp">
|
||||
<Filter>Vulkan</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
@ -117,5 +123,8 @@
|
||||
<Filter Include="GL\GLInterface">
|
||||
<UniqueIdentifier>{2c723cf4-75b6-406a-90c0-ebb7a13ba476}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Vulkan">
|
||||
<UniqueIdentifier>{c14d66ef-5f7c-4565-975a-72774e7ccfb9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
616
Common/Vulkan/SPIRVDisasm.cpp
Normal file
616
Common/Vulkan/SPIRVDisasm.cpp
Normal file
@ -0,0 +1,616 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Common/Vulkan/SPIRVDisasm.h"
|
||||
#include "ext/vulkan/spirv.hpp"
|
||||
|
||||
#define WRITE p+=sprintf
|
||||
|
||||
struct SpirvID {
|
||||
std::string name;
|
||||
int opcode;
|
||||
};
|
||||
|
||||
struct OpInfo {
|
||||
const char *name;
|
||||
const char *extra;
|
||||
};
|
||||
|
||||
static const char *executionModelNames[] = {
|
||||
"Vertex", // 0,
|
||||
"TessellationControl", // 1,
|
||||
"TessellationEvaluation", // 2,
|
||||
"Geometry", // 3,
|
||||
"Fragment", // 4,
|
||||
"GLCompute", // 5,
|
||||
"Kernel", // 6,
|
||||
};
|
||||
|
||||
static const char *storageClassNames[] = {
|
||||
"UniformConstant",
|
||||
"Input",
|
||||
"Uniform",
|
||||
"Output",
|
||||
"Workgroup",
|
||||
"CrossWorkgroup",
|
||||
"Private",
|
||||
"Function",
|
||||
"Generic",
|
||||
"PushConstant",
|
||||
"AtomicCounter",
|
||||
"Image",
|
||||
};
|
||||
|
||||
static const char *decorationNames[] = {
|
||||
"RelaxedPrecision", // 0,
|
||||
"SpecId", // 1,
|
||||
"Block", // 2,
|
||||
"BufferBlock", // 3,
|
||||
"RowMajor", // 4,
|
||||
"ColMajor", // 5,
|
||||
"ArrayStride", // 6,
|
||||
"MatrixStride", // 7,
|
||||
"GLSLShared", // 8,
|
||||
"GLSLPacked", // 9,
|
||||
"CPacked", // 10,
|
||||
"BuiltIn", // 11,
|
||||
nullptr, // 12
|
||||
"NoPerspective", // 13,
|
||||
"Flat", // 14,
|
||||
"Patch", // 15,
|
||||
"Centroid", // 16,
|
||||
"Sample", // 17,
|
||||
"Invariant", // 18,
|
||||
"Restrict", // 19,
|
||||
"Aliased", // 20,
|
||||
"Volatile", // 21,
|
||||
"Constant", // 22,
|
||||
"Coherent", // 23,
|
||||
"NonWritable", // 24,
|
||||
"NonReadable", // 25,
|
||||
"Uniform", // 26,
|
||||
nullptr, // 27
|
||||
"SaturatedConversion", // 28,
|
||||
"Stream", // 29,
|
||||
"Location", // 30,
|
||||
"Component", // 31,
|
||||
"Index", // 32,
|
||||
"Binding", // 33,
|
||||
"DescriptorSet", // 34,
|
||||
"Offset", // 35,
|
||||
"XfbBuffer", // 36,
|
||||
"XfbStride", // 37,
|
||||
"FuncParamAttr", // 38,
|
||||
"FPRoundingMode", // 39,
|
||||
"FPFastMathMode", // 40,
|
||||
"LinkageAttributes", // 41,
|
||||
"NoContraction", // 42,
|
||||
"InputAttachmentIndex", // 43,
|
||||
"Alignment", // 44,
|
||||
};
|
||||
|
||||
static const OpInfo opInfo[] = {
|
||||
{"Nop"}, // 0,
|
||||
{"Undef"}, // 1,
|
||||
{"SourceContinued"}, // 2,
|
||||
{"Source"}, // 3,
|
||||
{"SourceExtension"}, // 4,
|
||||
{"Name"}, // 5,
|
||||
{"MemberName"}, // 6,
|
||||
{"String"}, // 7,
|
||||
{"Line"}, // 8,
|
||||
{nullptr}, // 9
|
||||
{"Extension"}, // 10,
|
||||
{"ExtInstImport"}, // 11,
|
||||
{"ExtInst"}, // 12,
|
||||
{nullptr}, // 13
|
||||
{"MemoryModel"}, // 14,
|
||||
{"EntryPoint"}, // 15,
|
||||
{"ExecutionMode"}, // 16,
|
||||
{"Capability"}, // 17,
|
||||
{nullptr}, // 18
|
||||
{"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,
|
||||
{nullptr}, // 40
|
||||
{"ConstantTrue"}, // 41,
|
||||
{"ConstantFalse"}, // 42,
|
||||
{"Constant"}, // 43,
|
||||
{"ConstantComposite"}, // 44,
|
||||
{"ConstantSampler"}, // 45,
|
||||
{"ConstantNull"}, // 46,
|
||||
{nullptr}, // 47
|
||||
{"SpecConstantTrue"}, // 48,
|
||||
{"SpecConstantFalse"}, // 49,
|
||||
{"SpecConstant"}, // 50,
|
||||
{"SpecConstantComposite"}, // 51,
|
||||
{"SpecConstantOp"}, // 52,
|
||||
{nullptr}, // 53
|
||||
{"Function"}, // 54,
|
||||
{"FunctionParameter"}, // 55,
|
||||
{"FunctionEnd"}, // 56,
|
||||
{"FunctionCall"}, // 57,
|
||||
{nullptr}, // 58
|
||||
{"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,
|
||||
{nullptr}, // 76
|
||||
{"VectorExtractDynamic"}, // 77,
|
||||
{"VectorInsertDynamic"}, // 78,
|
||||
{"VectorShuffle"}, // 79,
|
||||
{"CompositeConstruct"}, // 80,
|
||||
{"CompositeExtract"}, // 81,
|
||||
{"CompositeInsert"}, // 82,
|
||||
{"CopyObject"}, // 83,
|
||||
{"Transpose"}, // 84,
|
||||
{nullptr}, // 85
|
||||
{"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,
|
||||
{nullptr}, // 108
|
||||
{"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,
|
||||
{nullptr}, // 125
|
||||
{"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", " dot "}, // 148,
|
||||
{"IAddCarry"}, // 149,
|
||||
{"ISubBorrow"}, // 150,
|
||||
{"UMulExtended"}, // 151,
|
||||
{"SMulExtended"}, // 152,
|
||||
{nullptr}, // 153
|
||||
{"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,
|
||||
{ nullptr }, // 192
|
||||
{ nullptr }, // 193
|
||||
{"ShiftRightLogical"}, // 194,
|
||||
{"ShiftRightArithmetic"}, // 195,
|
||||
{"ShiftLeftLogical"}, // 196,
|
||||
{"BitwiseOr", "|"}, // 197,
|
||||
{"BitwiseXor", "^"}, // 198,
|
||||
{"BitwiseAnd", "&"}, // 199,
|
||||
{"Not", "~"}, // 200,
|
||||
{"BitFieldInsert"}, // 201,
|
||||
{"BitFieldSExtract"}, // 202,
|
||||
{"BitFieldUExtract"}, // 203,
|
||||
{"BitReverse"}, // 204,
|
||||
{"BitCount"}, // 205,
|
||||
{nullptr},
|
||||
{"DPdx"}, // 207,
|
||||
{"DPdy"}, // 208,
|
||||
{"Fwidth"}, // 209,
|
||||
{"DPdxFine"}, // 210,
|
||||
{"DPdyFine"}, // 211,
|
||||
{"FwidthFine"}, // 212,
|
||||
{"DPdxCoarse"}, // 213,
|
||||
{"DPdyCoarse"}, // 214,
|
||||
{"FwidthCoarse"}, // 215,
|
||||
{nullptr}, // 216
|
||||
{nullptr}, // 217
|
||||
{"EmitVertex"}, // 218,
|
||||
{"EndPrimitive"}, // 219,
|
||||
{"EmitStreamVertex"}, // 220,
|
||||
{"EndStreamPrimitive"}, // 221,
|
||||
{nullptr}, // 222
|
||||
{nullptr}, // 223
|
||||
{"ControlBarrier"}, // 224,
|
||||
{"MemoryBarrier"}, // 225,
|
||||
{nullptr}, // 226
|
||||
{"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,
|
||||
{ nullptr }, // 243,
|
||||
{ nullptr }, // 244,
|
||||
{"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,
|
||||
{ nullptr },
|
||||
{"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,
|
||||
{nullptr}, // 272
|
||||
{nullptr}, // 273
|
||||
{"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,
|
||||
{ nullptr }, // 289
|
||||
{ nullptr }, // 290
|
||||
{"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,
|
||||
};
|
||||
|
||||
static std::string ReadSpirvString(const std::vector<uint32_t> &spirv, int offset, int *outOffset = nullptr) {
|
||||
bool done = false;
|
||||
std::string temp;
|
||||
while (!done) {
|
||||
uint32_t data = spirv[offset++];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
char c = (char)(data & 0xff);
|
||||
if (!c) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
temp.push_back(data);
|
||||
data >>= 8;
|
||||
}
|
||||
if (offset == (int)spirv.size())
|
||||
break;
|
||||
}
|
||||
if (outOffset)
|
||||
*outOffset = offset;
|
||||
return temp;
|
||||
}
|
||||
|
||||
bool DisassembleSPIRV(std::vector<uint32_t> spirv, std::string *output) {
|
||||
if (spirv.size() < 10) {
|
||||
*output = "Too small";
|
||||
return false;
|
||||
}
|
||||
uint32_t magic = spirv[0];
|
||||
uint32_t version = spirv[1];
|
||||
uint32_t generator = spirv[2];
|
||||
|
||||
int bound = (int)spirv[3]; // Max ID used in file.
|
||||
// spirv[4] is reserved for schema.
|
||||
std::vector<SpirvID> ids;
|
||||
ids.resize(bound);
|
||||
for (int i = 0; i < bound; i++) {
|
||||
ids[i].name = StringFromFormat("%%%d", i);
|
||||
}
|
||||
|
||||
if (magic != 0x07230203) {
|
||||
*output = "Not SPIRV";
|
||||
return false;
|
||||
}
|
||||
|
||||
int indent = 0;
|
||||
|
||||
char *buffer = new char[1024 * 1024];
|
||||
char *p = buffer;
|
||||
|
||||
WRITE(p, "// ======= SPIR-V version %08x =======\n// Max ID: %d\n", version, bound); // GLSL ES
|
||||
|
||||
int i = 5;
|
||||
while (i < (int)spirv.size()) {
|
||||
uint32_t d = spirv[i];
|
||||
int wordCount = d >> 16;
|
||||
int opcode = d & 0xFFFF;
|
||||
const OpInfo &op = opInfo[opcode];
|
||||
int target = (i < (int)spirv.size() - 1) ? spirv[(i + 1)] : 0; // Not always, but used often enough that we get it here.
|
||||
int source, source2, resType;
|
||||
std::string name;
|
||||
switch (opcode) {
|
||||
case spv::OpTypeVoid:
|
||||
case spv::OpTypeBool:
|
||||
case spv::OpTypeInt:
|
||||
case spv::OpTypeFloat:
|
||||
case spv::OpTypeMatrix:
|
||||
case spv::OpTypeImage:
|
||||
case spv::OpTypeSampler:
|
||||
case spv::OpTypeSampledImage:
|
||||
case spv::OpTypeRuntimeArray:
|
||||
case spv::OpTypeOpaque:
|
||||
case spv::OpTypePointer:
|
||||
case spv::OpTypeFunction:
|
||||
case spv::OpTypeEvent:
|
||||
case spv::OpTypeDeviceEvent:
|
||||
case spv::OpTypeReserveId:
|
||||
case spv::OpTypeQueue:
|
||||
case spv::OpTypePipe:
|
||||
case spv::OpTypeForwardPointer:
|
||||
ids[target].name = op.name + 4; // Remove "Type"
|
||||
ids[target].opcode = opcode;
|
||||
break;
|
||||
case spv::OpTypeVector:
|
||||
source = spirv[i + 2];
|
||||
source2 = spirv[i + 3];
|
||||
ids[target].name = ids[source].name + StringFromFormat("%d", source2); break;
|
||||
break;
|
||||
case spv::OpTypeArray:
|
||||
source = spirv[i + 2];
|
||||
source2 = spirv[i + 3];
|
||||
ids[target].name = ids[source].name + "[" + ids[source2].name + "]"; break;
|
||||
break;
|
||||
case spv::OpTypeStruct:
|
||||
{
|
||||
ids[target].name = "struct" + ids[target].name;
|
||||
WRITE(p, "struct {\n");
|
||||
if (wordCount == 3) {
|
||||
source = spirv[i + 2];
|
||||
WRITE(p, " %s\n", ids[source].name.c_str());
|
||||
} else {
|
||||
int numMembers = (wordCount - 2) / 2;
|
||||
for (int m = 0; m < numMembers; m++) {
|
||||
int id = spirv[i + 2 + m];
|
||||
int type = spirv[i + 2 + m + numMembers];
|
||||
WRITE(p, " %s %s;\n", ids[type].name.c_str(), ids[id].name.c_str());
|
||||
}
|
||||
}
|
||||
WRITE(p, "};\n");
|
||||
}
|
||||
break;
|
||||
case spv::OpVariable:
|
||||
resType = spirv[i + 1];
|
||||
target = spirv[i + 2];
|
||||
source = spirv[i + 3];
|
||||
source2 = spirv[i + 4];
|
||||
ids[target].name = storageClassNames[source];
|
||||
break;
|
||||
case spv::OpDecorate:
|
||||
source = spirv[i + 2];
|
||||
ids[target].name += std::string("[") + decorationNames[source] + "]";
|
||||
break;
|
||||
case spv::OpName:
|
||||
ids[target].name = ReadSpirvString(spirv, i + 2);
|
||||
// WRITE(p, "Name %d: '%s'\n", target, ids[target].name.c_str());
|
||||
break;
|
||||
case spv::OpMemberName:
|
||||
break;
|
||||
case spv::OpStore:
|
||||
source = spirv[i + 2];
|
||||
WRITE(p, "Store(%s, %s)\n", ids[target].name.c_str(), ids[source].name.c_str());
|
||||
break;
|
||||
case spv::OpLoad:
|
||||
resType = spirv[i + 1];
|
||||
target = spirv[i + 2];
|
||||
source = spirv[i + 3];
|
||||
WRITE(p, "%s (%s) := Load(%s)\n", ids[target].name.c_str(), ids[resType].name.c_str(), ids[source].name.c_str());
|
||||
break;
|
||||
case spv::OpFAdd:
|
||||
case spv::OpFMul:
|
||||
case spv::OpFDiv:
|
||||
case spv::OpFSub:
|
||||
resType = spirv[i + 2];
|
||||
source = spirv[i + 3];
|
||||
source2 = spirv[i + 4];
|
||||
WRITE(p, "%s (%s) := %s %s %s\n", ids[target].name.c_str(), ids[resType].name.c_str(), ids[source].name.c_str(), op.extra, ids[source2].name.c_str());
|
||||
break;
|
||||
|
||||
case spv::OpCapability:
|
||||
case spv::OpMemoryModel:
|
||||
case spv::OpExtInstImport:
|
||||
case spv::OpExecutionMode:
|
||||
case spv::OpGroupAsyncCopy:
|
||||
case spv::OpSource:
|
||||
case spv::OpExtension:
|
||||
// hide these for now
|
||||
break;
|
||||
|
||||
case spv::OpEntryPoint:
|
||||
source = spirv[i + 1];
|
||||
source2 = spirv[i + 2];
|
||||
name = ReadSpirvString(spirv, i + 3);
|
||||
WRITE(p, "EntryPoint %s: '%s' %s : %s\n", executionModelNames[target], ids[source].name.c_str(), ids[source2].name.c_str(), name.c_str());
|
||||
break;
|
||||
|
||||
case spv::OpFunction:
|
||||
resType = spirv[i + 1];
|
||||
target = spirv[i + 2];
|
||||
source = spirv[i + 3];
|
||||
ids[target].name = ids[resType].name + "()";
|
||||
WRITE(p, "Function %s {\n", ids[target].name.c_str());
|
||||
break;
|
||||
|
||||
case spv::OpLabel:
|
||||
WRITE(p, "label %s:\n", ids[target].name.c_str());
|
||||
break;
|
||||
|
||||
case spv::OpReturnValue:
|
||||
WRITE(p, "return %s\n", ids[target].name.c_str());
|
||||
break;
|
||||
|
||||
case spv::OpReturn:
|
||||
WRITE(p, "return\n");
|
||||
break;
|
||||
|
||||
case spv::OpFunctionEnd:
|
||||
WRITE(p, "}\n");
|
||||
break;
|
||||
|
||||
case spv::OpSourceExtension:
|
||||
break;
|
||||
|
||||
default:
|
||||
WRITE(p, "%s (%d data words)\n", op.name, wordCount - 1);
|
||||
break;
|
||||
}
|
||||
i += wordCount;
|
||||
}
|
||||
|
||||
*output = buffer;
|
||||
delete[] buffer;
|
||||
return true;
|
||||
}
|
9
Common/Vulkan/SPIRVDisasm.h
Normal file
9
Common/Vulkan/SPIRVDisasm.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Mostly just a toy to understand SPIR-V better.
|
||||
|
||||
bool DisassembleSPIRV(std::vector<uint32_t> spirv, std::string *output);
|
@ -21,6 +21,8 @@
|
||||
#include <map>
|
||||
#include <assert.h>
|
||||
|
||||
#include "Common/Vulkan/SPIRVDisasm.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/display.h"
|
||||
#include "image/zim_load.h"
|
||||
@ -294,7 +296,16 @@ bool Thin3DVKShader::Compile(VkDevice device, const char *source) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CreateShaderModule(device, spirv, &module_)) {
|
||||
// Just for kicks, sanity check the SPIR-V. The disasm isn't perfect
|
||||
// but gives you some idea of what's going on.
|
||||
#if 0
|
||||
std::string disasm;
|
||||
if (DisassembleSPIRV(spirv, &disasm)) {
|
||||
OutputDebugStringA(disasm.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vulkan->CreateShaderModule(spirv, &module_)) {
|
||||
ok_ = true;
|
||||
} else {
|
||||
ok_ = false;
|
||||
@ -1381,4 +1392,4 @@ void Thin3DVKContext::Clear(int mask, uint32_t colorval, float depthVal, int ste
|
||||
|
||||
Thin3DContext *T3DCreateVulkanContext(VulkanContext *vulkan) {
|
||||
return new Thin3DVKContext(vulkan);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user