diff --git a/main.cpp b/main.cpp index a8021417..ee2559af 100644 --- a/main.cpp +++ b/main.cpp @@ -205,11 +205,16 @@ static void print_resources(const Compiler &compiler, const char *tag, const vec { fprintf(stderr, "%s\n", tag); fprintf(stderr, "=============\n\n"); + bool print_ssbo = !strcmp(tag, "ssbos"); + for (auto &res : resources) { auto &type = compiler.get_type(res.type_id); auto mask = compiler.get_decoration_mask(res.id); + if (print_ssbo && compiler.buffer_is_hlsl_counter_buffer(res.id)) + continue; + // If we don't have a name, use the fallback for the type instead of the variable // for SSBOs and UBOs since those are the only meaningful names to use externally. // Push constant blocks are still accessed by name and not block name, even though they are technically Blocks. @@ -245,6 +250,10 @@ static void print_resources(const Compiler &compiler, const char *tag, const vec fprintf(stderr, " readonly"); if (is_sized_block) fprintf(stderr, " (BlockSize : %u bytes)", block_size); + + uint32_t counter_id = 0; + if (print_ssbo && compiler.buffer_get_hlsl_counter_buffer(res.id, counter_id)) + fprintf(stderr, " (HLSL counter buffer ID: %u)", counter_id); fprintf(stderr, "\n"); } fprintf(stderr, "=============\n\n"); diff --git a/spirv.hpp b/spirv.hpp index 987f3c1d..91cb59eb 100644 --- a/spirv.hpp +++ b/spirv.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2016 The Khronos Group Inc. +// Copyright (c) 2014-2017 The Khronos Group Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and/or associated documentation files (the "Materials"), @@ -47,11 +47,11 @@ namespace spv { typedef unsigned int Id; #define SPV_VERSION 0x10000 -#define SPV_REVISION 5 +#define SPV_REVISION 10 static const unsigned int MagicNumber = 0x07230203; static const unsigned int Version = 0x00010000; -static const unsigned int Revision = 5; +static const unsigned int Revision = 10; static const unsigned int OpCodeMask = 0xffff; static const unsigned int WordCountShift = 16; @@ -61,6 +61,8 @@ enum SourceLanguage { SourceLanguageGLSL = 2, SourceLanguageOpenCL_C = 3, SourceLanguageOpenCL_CPP = 4, + SourceLanguageHLSL = 5, + SourceLanguageMax = 0x7fffffff, }; enum ExecutionModel { @@ -71,18 +73,21 @@ enum ExecutionModel { ExecutionModelFragment = 4, ExecutionModelGLCompute = 5, ExecutionModelKernel = 6, + ExecutionModelMax = 0x7fffffff, }; enum AddressingModel { AddressingModelLogical = 0, AddressingModelPhysical32 = 1, AddressingModelPhysical64 = 2, + AddressingModelMax = 0x7fffffff, }; enum MemoryModel { MemoryModelSimple = 0, MemoryModelGLSL450 = 1, MemoryModelOpenCL = 2, + MemoryModelMax = 0x7fffffff, }; enum ExecutionMode { @@ -117,6 +122,7 @@ enum ExecutionMode { ExecutionModeOutputTriangleStrip = 29, ExecutionModeVecTypeHint = 30, ExecutionModeContractionOff = 31, + ExecutionModeMax = 0x7fffffff, }; enum StorageClass { @@ -132,6 +138,8 @@ enum StorageClass { StorageClassPushConstant = 9, StorageClassAtomicCounter = 10, StorageClassImage = 11, + StorageClassStorageBuffer = 12, + StorageClassMax = 0x7fffffff, }; enum Dim { @@ -142,6 +150,7 @@ enum Dim { DimRect = 4, DimBuffer = 5, DimSubpassData = 6, + DimMax = 0x7fffffff, }; enum SamplerAddressingMode { @@ -150,11 +159,13 @@ enum SamplerAddressingMode { SamplerAddressingModeClamp = 2, SamplerAddressingModeRepeat = 3, SamplerAddressingModeRepeatMirrored = 4, + SamplerAddressingModeMax = 0x7fffffff, }; enum SamplerFilterMode { SamplerFilterModeNearest = 0, SamplerFilterModeLinear = 1, + SamplerFilterModeMax = 0x7fffffff, }; enum ImageFormat { @@ -198,6 +209,7 @@ enum ImageFormat { ImageFormatRg8ui = 37, ImageFormatR16ui = 38, ImageFormatR8ui = 39, + ImageFormatMax = 0x7fffffff, }; enum ImageChannelOrder { @@ -221,6 +233,7 @@ enum ImageChannelOrder { ImageChannelOrdersRGBA = 17, ImageChannelOrdersBGRA = 18, ImageChannelOrderABGR = 19, + ImageChannelOrderMax = 0x7fffffff, }; enum ImageChannelDataType { @@ -241,6 +254,7 @@ enum ImageChannelDataType { ImageChannelDataTypeFloat = 14, ImageChannelDataTypeUnormInt24 = 15, ImageChannelDataTypeUnormInt101010_2 = 16, + ImageChannelDataTypeMax = 0x7fffffff, }; enum ImageOperandsShift { @@ -252,6 +266,7 @@ enum ImageOperandsShift { ImageOperandsConstOffsetsShift = 5, ImageOperandsSampleShift = 6, ImageOperandsMinLodShift = 7, + ImageOperandsMax = 0x7fffffff, }; enum ImageOperandsMask { @@ -272,6 +287,7 @@ enum FPFastMathModeShift { FPFastMathModeNSZShift = 2, FPFastMathModeAllowRecipShift = 3, FPFastMathModeFastShift = 4, + FPFastMathModeMax = 0x7fffffff, }; enum FPFastMathModeMask { @@ -288,17 +304,20 @@ enum FPRoundingMode { FPRoundingModeRTZ = 1, FPRoundingModeRTP = 2, FPRoundingModeRTN = 3, + FPRoundingModeMax = 0x7fffffff, }; enum LinkageType { LinkageTypeExport = 0, LinkageTypeImport = 1, + LinkageTypeMax = 0x7fffffff, }; enum AccessQualifier { AccessQualifierReadOnly = 0, AccessQualifierWriteOnly = 1, AccessQualifierReadWrite = 2, + AccessQualifierMax = 0x7fffffff, }; enum FunctionParameterAttribute { @@ -310,6 +329,7 @@ enum FunctionParameterAttribute { FunctionParameterAttributeNoCapture = 5, FunctionParameterAttributeNoWrite = 6, FunctionParameterAttributeNoReadWrite = 7, + FunctionParameterAttributeMax = 0x7fffffff, }; enum Decoration { @@ -356,6 +376,11 @@ enum Decoration { DecorationNoContraction = 42, DecorationInputAttachmentIndex = 43, DecorationAlignment = 44, + DecorationOverrideCoverageNV = 5248, + DecorationPassthroughNV = 5250, + DecorationViewportRelativeNV = 5252, + DecorationSecondaryViewportRelativeNV = 5256, + DecorationMax = 0x7fffffff, }; enum BuiltIn { @@ -400,11 +425,28 @@ enum BuiltIn { BuiltInSubgroupLocalInvocationId = 41, BuiltInVertexIndex = 42, BuiltInInstanceIndex = 43, + BuiltInSubgroupEqMaskKHR = 4416, + BuiltInSubgroupGeMaskKHR = 4417, + BuiltInSubgroupGtMaskKHR = 4418, + BuiltInSubgroupLeMaskKHR = 4419, + BuiltInSubgroupLtMaskKHR = 4420, + BuiltInBaseVertex = 4424, + BuiltInBaseInstance = 4425, + BuiltInDrawIndex = 4426, + BuiltInDeviceIndex = 4438, + BuiltInViewIndex = 4440, + BuiltInViewportMaskNV = 5253, + BuiltInSecondaryPositionNV = 5257, + BuiltInSecondaryViewportMaskNV = 5258, + BuiltInPositionPerViewNV = 5261, + BuiltInViewportMaskPerViewNV = 5262, + BuiltInMax = 0x7fffffff, }; enum SelectionControlShift { SelectionControlFlattenShift = 0, SelectionControlDontFlattenShift = 1, + SelectionControlMax = 0x7fffffff, }; enum SelectionControlMask { @@ -416,6 +458,7 @@ enum SelectionControlMask { enum LoopControlShift { LoopControlUnrollShift = 0, LoopControlDontUnrollShift = 1, + LoopControlMax = 0x7fffffff, }; enum LoopControlMask { @@ -429,6 +472,7 @@ enum FunctionControlShift { FunctionControlDontInlineShift = 1, FunctionControlPureShift = 2, FunctionControlConstShift = 3, + FunctionControlMax = 0x7fffffff, }; enum FunctionControlMask { @@ -450,6 +494,7 @@ enum MemorySemanticsShift { MemorySemanticsCrossWorkgroupMemoryShift = 9, MemorySemanticsAtomicCounterMemoryShift = 10, MemorySemanticsImageMemoryShift = 11, + MemorySemanticsMax = 0x7fffffff, }; enum MemorySemanticsMask { @@ -470,6 +515,7 @@ enum MemoryAccessShift { MemoryAccessVolatileShift = 0, MemoryAccessAlignedShift = 1, MemoryAccessNontemporalShift = 2, + MemoryAccessMax = 0x7fffffff, }; enum MemoryAccessMask { @@ -485,22 +531,26 @@ enum Scope { ScopeWorkgroup = 2, ScopeSubgroup = 3, ScopeInvocation = 4, + ScopeMax = 0x7fffffff, }; enum GroupOperation { GroupOperationReduce = 0, GroupOperationInclusiveScan = 1, GroupOperationExclusiveScan = 2, + GroupOperationMax = 0x7fffffff, }; enum KernelEnqueueFlags { KernelEnqueueFlagsNoWait = 0, KernelEnqueueFlagsWaitKernel = 1, KernelEnqueueFlagsWaitWorkGroup = 2, + KernelEnqueueFlagsMax = 0x7fffffff, }; enum KernelProfilingInfoShift { KernelProfilingInfoCmdExecTimeShift = 0, + KernelProfilingInfoMax = 0x7fffffff, }; enum KernelProfilingInfoMask { @@ -565,6 +615,26 @@ enum Capability { CapabilityStorageImageReadWithoutFormat = 55, CapabilityStorageImageWriteWithoutFormat = 56, CapabilityMultiViewport = 57, + CapabilitySubgroupBallotKHR = 4423, + CapabilityDrawParameters = 4427, + CapabilitySubgroupVoteKHR = 4431, + CapabilityStorageBuffer16BitAccess = 4433, + CapabilityStorageUniformBufferBlock16 = 4433, + CapabilityStorageUniform16 = 4434, + CapabilityUniformAndStorageBuffer16BitAccess = 4434, + CapabilityStoragePushConstant16 = 4435, + CapabilityStorageInputOutput16 = 4436, + CapabilityDeviceGroup = 4437, + CapabilityMultiView = 4439, + CapabilityVariablePointersStorageBuffer = 4441, + CapabilityVariablePointers = 4442, + CapabilitySampleMaskOverrideCoverageNV = 5249, + CapabilityGeometryShaderPassthroughNV = 5251, + CapabilityShaderViewportIndexLayerNV = 5254, + CapabilityShaderViewportMaskNV = 5255, + CapabilityShaderStereoViewNV = 5259, + CapabilityPerViewAttributesNV = 5260, + CapabilityMax = 0x7fffffff, }; enum Op { @@ -862,6 +932,13 @@ enum Op { OpAtomicFlagTestAndSet = 318, OpAtomicFlagClear = 319, OpImageSparseRead = 320, + OpSubgroupBallotKHR = 4421, + OpSubgroupFirstInvocationKHR = 4422, + OpSubgroupAllKHR = 4428, + OpSubgroupAnyKHR = 4429, + OpSubgroupAllEqualKHR = 4430, + OpSubgroupReadInvocationKHR = 4432, + OpMax = 0x7fffffff, }; // Overload operator| for mask bit combining diff --git a/spirv_common.hpp b/spirv_common.hpp index a970fc8b..5949a289 100644 --- a/spirv_common.hpp +++ b/spirv_common.hpp @@ -969,6 +969,14 @@ struct Meta uint32_t sampler = 0; std::unordered_map decoration_word_offset; + + // Used when the parser has detected a candidate identifier which matches + // known "magic" counter buffers as emitted by HLSL frontends. + // We will need to match the identifiers by name later when reflecting resources. + // We could use the regular alias later, but the alias will be mangled when parsing SPIR-V because the identifier + // is not a valid identifier in any high-level language. + std::string hlsl_magic_counter_buffer_name; + bool hlsl_magic_counter_buffer_candidate = false; }; // A user callback that remaps the type of any variable. diff --git a/spirv_cross.cpp b/spirv_cross.cpp index 0f8548b4..fda87c2e 100644 --- a/spirv_cross.cpp +++ b/spirv_cross.cpp @@ -820,6 +820,21 @@ void Compiler::set_name(uint32_t id, const std::string &name) if (name.empty()) return; + + // glslang uses identifiers to pass along meaningful information + // about HLSL reflection. + auto &m = meta.at(id); + if (source.hlsl && name.find("@count") == name.size() - 6) + { + m.hlsl_magic_counter_buffer_candidate = true; + m.hlsl_magic_counter_buffer_name = name.substr(0, name.find("@count")); + } + else + { + m.hlsl_magic_counter_buffer_candidate = false; + m.hlsl_magic_counter_buffer_name.clear(); + } + // Reserved for temporaries. if (name[0] == '_' && name.size() >= 2 && isdigit(name[1])) return; @@ -1156,14 +1171,23 @@ void Compiler::parse(const Instruction &instruction) source.es = true; source.version = ops[1]; source.known = true; + source.hlsl = false; break; case SourceLanguageGLSL: source.es = false; source.version = ops[1]; source.known = true; + source.hlsl = false; break; + case SourceLanguageHLSL: + // For purposes of cross-compiling, this is GLSL 450. + source.es = false; + source.version = 450; + source.known = true; + source.hlsl = true; + default: source.known = false; break; @@ -3424,3 +3448,35 @@ bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_ return true; } + +bool Compiler::buffer_is_hlsl_counter_buffer(uint32_t id) const +{ + if (meta.at(id).hlsl_magic_counter_buffer_candidate) + { + auto *var = maybe_get(id); + // Ensure that this actually a buffer object. + return var && has_decoration(get(var->basetype).self, DecorationBufferBlock); + } + else + return false; +} + +bool Compiler::buffer_get_hlsl_counter_buffer(uint32_t id, uint32_t &counter_id) const +{ + auto &name = get_name(id); + uint32_t id_bound = get_current_id_bound(); + for (uint32_t i = 0; i < id_bound; i++) + { + if (meta[i].hlsl_magic_counter_buffer_candidate && meta[i].hlsl_magic_counter_buffer_name == name) + { + auto *var = maybe_get(i); + // Ensure that this actually a buffer object. + if (var && has_decoration(get(var->basetype).self, DecorationBufferBlock)) + { + counter_id = i; + return true; + } + } + } + return false; +} diff --git a/spirv_cross.hpp b/spirv_cross.hpp index e47463c5..3c168022 100644 --- a/spirv_cross.hpp +++ b/spirv_cross.hpp @@ -335,6 +335,25 @@ public: // If the decoration does not have any value attached to it (e.g. DecorationRelaxedPrecision), this function will also return false. bool get_binary_offset_for_decoration(uint32_t id, spv::Decoration decoration, uint32_t &word_offset) const; + // HLSL counter buffer reflection interface. + // Append/Consume/Increment/Decrement in HLSL is implemented as two "neighbor" buffer objects where + // one buffer implements the storage, and a single buffer containing just a lone "int" implements the counter. + // To SPIR-V these will be exposed as two separate buffers, but glslang HLSL frontend emits a special indentifier + // which lets us link the two buffers together. + + // Queries if a variable ID is a counter buffer which "belongs" to a regular buffer object. + // NOTE: This query is purely based on OpName identifiers as found in the SPIR-V module, and will + // only return true if OpSource was reported HLSL. + // To rely on this functionality, ensure that the SPIR-V module is not stripped. + bool buffer_is_hlsl_counter_buffer(uint32_t id) const; + + // Queries if a buffer object has a neighbor "counter" buffer. + // If so, the ID of that counter buffer will be returned in counter_id. + // NOTE: This query is purely based on OpName identifiers as found in the SPIR-V module, and will + // only return true if OpSource was reported HLSL. + // To rely on this functionality, ensure that the SPIR-V module is not stripped. + bool buffer_get_hlsl_counter_buffer(uint32_t id, uint32_t &counter_id) const; + protected: const uint32_t *stream(const Instruction &instr) const { @@ -413,6 +432,7 @@ protected: uint32_t version = 0; bool es = false; bool known = false; + bool hlsl = false; Source() = default; } source;