Merge pull request #162 from KhronosGroup/hlsl-counter-buffer
Add interface for reflecting "magic" HLSL counter buffers.
This commit is contained in:
commit
a0d0a0ec9e
9
main.cpp
9
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");
|
||||
|
83
spirv.hpp
83
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
|
||||
|
@ -969,6 +969,14 @@ struct Meta
|
||||
uint32_t sampler = 0;
|
||||
|
||||
std::unordered_map<uint32_t, uint32_t> 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.
|
||||
|
@ -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.size() >= 6 && 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,12 +1171,22 @@ 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;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -3424,3 +3449,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<SPIRVariable>(id);
|
||||
// Ensure that this is actually a buffer object.
|
||||
return var && has_decoration(get<SPIRType>(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<SPIRVariable>(i);
|
||||
// Ensure that this is actually a buffer object.
|
||||
if (var && has_decoration(get<SPIRType>(var->basetype).self, DecorationBufferBlock))
|
||||
{
|
||||
counter_id = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -69,6 +69,8 @@ string CompilerHLSL::image_type_hlsl_modern(const SPIRType &type)
|
||||
case DimSubpassData:
|
||||
// This should be implemented same way as desktop GL. Fetch on a 2D texture based on int2(SV_Position).
|
||||
SPIRV_CROSS_THROW("Subpass data support is not yet implemented for HLSL"); // TODO
|
||||
default:
|
||||
SPIRV_CROSS_THROW("Invalid dimension.");
|
||||
}
|
||||
uint32_t components = 4;
|
||||
const char *arrayed = type.image.arrayed ? "Array" : "";
|
||||
@ -1375,6 +1377,8 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
|
||||
case DimBuffer:
|
||||
case DimSubpassData:
|
||||
SPIRV_CROSS_THROW("Buffer texture support is not yet implemented for HLSL"); // TODO
|
||||
default:
|
||||
SPIRV_CROSS_THROW("Invalid dimension.");
|
||||
}
|
||||
|
||||
if (gather)
|
||||
|
Loading…
Reference in New Issue
Block a user