Updated spirv-cross.

This commit is contained in:
Бранимир Караџић
2026-01-30 16:26:12 -08:00
committed by Branimir Karadžić
parent e17b97c0fe
commit 87c821cf65
10 changed files with 501 additions and 59 deletions

View File

@@ -0,0 +1,171 @@
// Copyright (c) 2018-2024 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"),
// to deal in the Materials without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Materials, and to permit persons to whom the
// Materials are furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Materials.
//
// MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS KHRONOS
// STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS SPECIFICATIONS AND
// HEADER INFORMATION ARE LOCATED AT https://www.khronos.org/registry/
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM,OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE USE OR OTHER DEALINGS
// IN THE MATERIALS.
#ifndef SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_
#define SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_
#ifdef __cplusplus
extern "C" {
#endif
enum {
NonSemanticShaderDebugInfo100Version = 100,
NonSemanticShaderDebugInfo100Version_BitWidthPadding = 0x7fffffff
};
enum {
NonSemanticShaderDebugInfo100Revision = 6,
NonSemanticShaderDebugInfo100Revision_BitWidthPadding = 0x7fffffff
};
enum NonSemanticShaderDebugInfo100Instructions {
NonSemanticShaderDebugInfo100DebugInfoNone = 0,
NonSemanticShaderDebugInfo100DebugCompilationUnit = 1,
NonSemanticShaderDebugInfo100DebugTypeBasic = 2,
NonSemanticShaderDebugInfo100DebugTypePointer = 3,
NonSemanticShaderDebugInfo100DebugTypeQualifier = 4,
NonSemanticShaderDebugInfo100DebugTypeArray = 5,
NonSemanticShaderDebugInfo100DebugTypeVector = 6,
NonSemanticShaderDebugInfo100DebugTypedef = 7,
NonSemanticShaderDebugInfo100DebugTypeFunction = 8,
NonSemanticShaderDebugInfo100DebugTypeEnum = 9,
NonSemanticShaderDebugInfo100DebugTypeComposite = 10,
NonSemanticShaderDebugInfo100DebugTypeMember = 11,
NonSemanticShaderDebugInfo100DebugTypeInheritance = 12,
NonSemanticShaderDebugInfo100DebugTypePtrToMember = 13,
NonSemanticShaderDebugInfo100DebugTypeTemplate = 14,
NonSemanticShaderDebugInfo100DebugTypeTemplateParameter = 15,
NonSemanticShaderDebugInfo100DebugTypeTemplateTemplateParameter = 16,
NonSemanticShaderDebugInfo100DebugTypeTemplateParameterPack = 17,
NonSemanticShaderDebugInfo100DebugGlobalVariable = 18,
NonSemanticShaderDebugInfo100DebugFunctionDeclaration = 19,
NonSemanticShaderDebugInfo100DebugFunction = 20,
NonSemanticShaderDebugInfo100DebugLexicalBlock = 21,
NonSemanticShaderDebugInfo100DebugLexicalBlockDiscriminator = 22,
NonSemanticShaderDebugInfo100DebugScope = 23,
NonSemanticShaderDebugInfo100DebugNoScope = 24,
NonSemanticShaderDebugInfo100DebugInlinedAt = 25,
NonSemanticShaderDebugInfo100DebugLocalVariable = 26,
NonSemanticShaderDebugInfo100DebugInlinedVariable = 27,
NonSemanticShaderDebugInfo100DebugDeclare = 28,
NonSemanticShaderDebugInfo100DebugValue = 29,
NonSemanticShaderDebugInfo100DebugOperation = 30,
NonSemanticShaderDebugInfo100DebugExpression = 31,
NonSemanticShaderDebugInfo100DebugMacroDef = 32,
NonSemanticShaderDebugInfo100DebugMacroUndef = 33,
NonSemanticShaderDebugInfo100DebugImportedEntity = 34,
NonSemanticShaderDebugInfo100DebugSource = 35,
NonSemanticShaderDebugInfo100DebugFunctionDefinition = 101,
NonSemanticShaderDebugInfo100DebugSourceContinued = 102,
NonSemanticShaderDebugInfo100DebugLine = 103,
NonSemanticShaderDebugInfo100DebugNoLine = 104,
NonSemanticShaderDebugInfo100DebugBuildIdentifier = 105,
NonSemanticShaderDebugInfo100DebugStoragePath = 106,
NonSemanticShaderDebugInfo100DebugEntryPoint = 107,
NonSemanticShaderDebugInfo100DebugTypeMatrix = 108,
NonSemanticShaderDebugInfo100InstructionsMax = 0x7fffffff
};
enum NonSemanticShaderDebugInfo100DebugInfoFlags {
NonSemanticShaderDebugInfo100None = 0x0000,
NonSemanticShaderDebugInfo100FlagIsProtected = 0x01,
NonSemanticShaderDebugInfo100FlagIsPrivate = 0x02,
NonSemanticShaderDebugInfo100FlagIsPublic = 0x03,
NonSemanticShaderDebugInfo100FlagIsLocal = 0x04,
NonSemanticShaderDebugInfo100FlagIsDefinition = 0x08,
NonSemanticShaderDebugInfo100FlagFwdDecl = 0x10,
NonSemanticShaderDebugInfo100FlagArtificial = 0x20,
NonSemanticShaderDebugInfo100FlagExplicit = 0x40,
NonSemanticShaderDebugInfo100FlagPrototyped = 0x80,
NonSemanticShaderDebugInfo100FlagObjectPointer = 0x100,
NonSemanticShaderDebugInfo100FlagStaticMember = 0x200,
NonSemanticShaderDebugInfo100FlagIndirectVariable = 0x400,
NonSemanticShaderDebugInfo100FlagLValueReference = 0x800,
NonSemanticShaderDebugInfo100FlagRValueReference = 0x1000,
NonSemanticShaderDebugInfo100FlagIsOptimized = 0x2000,
NonSemanticShaderDebugInfo100FlagIsEnumClass = 0x4000,
NonSemanticShaderDebugInfo100FlagTypePassByValue = 0x8000,
NonSemanticShaderDebugInfo100FlagTypePassByReference = 0x10000,
NonSemanticShaderDebugInfo100FlagUnknownPhysicalLayout = 0x20000,
NonSemanticShaderDebugInfo100DebugInfoFlagsMax = 0x7fffffff
};
enum NonSemanticShaderDebugInfo100BuildIdentifierFlags {
NonSemanticShaderDebugInfo100IdentifierPossibleDuplicates = 0x01,
NonSemanticShaderDebugInfo100BuildIdentifierFlagsMax = 0x7fffffff
};
enum NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncoding {
NonSemanticShaderDebugInfo100Unspecified = 0,
NonSemanticShaderDebugInfo100Address = 1,
NonSemanticShaderDebugInfo100Boolean = 2,
NonSemanticShaderDebugInfo100Float = 3,
NonSemanticShaderDebugInfo100Signed = 4,
NonSemanticShaderDebugInfo100SignedChar = 5,
NonSemanticShaderDebugInfo100Unsigned = 6,
NonSemanticShaderDebugInfo100UnsignedChar = 7,
NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncodingMax = 0x7fffffff
};
enum NonSemanticShaderDebugInfo100DebugCompositeType {
NonSemanticShaderDebugInfo100Class = 0,
NonSemanticShaderDebugInfo100Structure = 1,
NonSemanticShaderDebugInfo100Union = 2,
NonSemanticShaderDebugInfo100DebugCompositeTypeMax = 0x7fffffff
};
enum NonSemanticShaderDebugInfo100DebugTypeQualifier {
NonSemanticShaderDebugInfo100ConstType = 0,
NonSemanticShaderDebugInfo100VolatileType = 1,
NonSemanticShaderDebugInfo100RestrictType = 2,
NonSemanticShaderDebugInfo100AtomicType = 3,
NonSemanticShaderDebugInfo100DebugTypeQualifierMax = 0x7fffffff
};
enum NonSemanticShaderDebugInfo100DebugOperation {
NonSemanticShaderDebugInfo100Deref = 0,
NonSemanticShaderDebugInfo100Plus = 1,
NonSemanticShaderDebugInfo100Minus = 2,
NonSemanticShaderDebugInfo100PlusUconst = 3,
NonSemanticShaderDebugInfo100BitPiece = 4,
NonSemanticShaderDebugInfo100Swap = 5,
NonSemanticShaderDebugInfo100Xderef = 6,
NonSemanticShaderDebugInfo100StackValue = 7,
NonSemanticShaderDebugInfo100Constu = 8,
NonSemanticShaderDebugInfo100Fragment = 9,
NonSemanticShaderDebugInfo100DebugOperationMax = 0x7fffffff
};
enum NonSemanticShaderDebugInfo100DebugImportedEntity {
NonSemanticShaderDebugInfo100ImportedModule = 0,
NonSemanticShaderDebugInfo100ImportedDeclaration = 1,
NonSemanticShaderDebugInfo100DebugImportedEntityMax = 0x7fffffff
};
#ifdef __cplusplus
}
#endif
#endif // SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_

View File

@@ -377,6 +377,7 @@ enum Types
TypeAccessChain,
TypeUndef,
TypeString,
TypeDebugLocalVariable,
TypeCount
};
@@ -506,6 +507,18 @@ struct SPIRString : IVariant
SPIRV_CROSS_DECLARE_CLONE(SPIRString)
};
struct SPIRDebugLocalVariable : IVariant
{
enum
{
type = TypeDebugLocalVariable
};
uint32_t name_id;
SPIRV_CROSS_DECLARE_CLONE(SPIRDebugLocalVariable)
};
// This type is only used by backends which need to access the combined image and sampler IDs separately after
// the OpSampledImage opcode.
struct SPIRCombinedImageSampler : IVariant
@@ -1163,6 +1176,9 @@ struct SPIRVariable : IVariant
// Temporaries which can remain forwarded as long as this variable is not modified.
SmallVector<ID> dependees;
// ShaderDebugInfo local variables attached to this variable via DebugDeclare
SmallVector<ID> debug_local_variables;
bool deferred_declaration = false;
bool phi_variable = false;

View File

@@ -3611,7 +3611,7 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(Op op, const uint32_t *
case OpCopyObject:
{
// OpCopyObject copies the underlying non-pointer type,
// OpCopyObject copies the underlying non-pointer type,
// so any temp variable should be declared using the underlying type.
// If the type is a pointer, get its base type and overwrite the result type mapping.
auto &type = compiler.get<SPIRType>(result_type);
@@ -5078,12 +5078,12 @@ std::string Compiler::get_remapped_declared_block_name(uint32_t id, bool fallbac
bool Compiler::reflection_ssbo_instance_name_is_significant() const
{
if (ir.source.known)
if (!ir.sources.empty() && ir.sources[0].known)
{
// UAVs from HLSL source tend to be declared in a way where the type is reused
// but the instance name is significant, and that's the name we should report.
// For GLSL, SSBOs each have their own block type as that's how GLSL is written.
return ir.source.hlsl;
return ir.sources[0].hlsl;
}
unordered_set<uint32_t> ssbo_type_ids;

View File

@@ -549,6 +549,9 @@ public:
return position_invariant;
}
const ParsedIR &get_ir() const { return ir; }
uint32_t evaluate_constant_u32(uint32_t id) const;
protected:
const uint32_t *stream(const Instruction &instr) const
{
@@ -1197,7 +1200,6 @@ protected:
bool flush_phi_required(BlockID from, BlockID to) const;
uint32_t evaluate_spec_constant_u32(const SPIRConstantOp &spec) const;
uint32_t evaluate_constant_u32(uint32_t id) const;
bool is_vertex_like_shader() const;

View File

@@ -49,6 +49,7 @@ ParsedIR::ParsedIR()
pool_group->pools[TypeAccessChain].reset(new ObjectPool<SPIRAccessChain>);
pool_group->pools[TypeUndef].reset(new ObjectPool<SPIRUndef>);
pool_group->pools[TypeString].reset(new ObjectPool<SPIRString>);
pool_group->pools[TypeDebugLocalVariable].reset(new ObjectPool<SPIRDebugLocalVariable>);
}
// Should have been default-implemented, but need this on MSVC 2013.
@@ -78,7 +79,7 @@ ParsedIR &ParsedIR::operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT
memory_model = other.memory_model;
default_entry_point = other.default_entry_point;
source = other.source;
sources = std::move(other.sources);
loop_iteration_depth_hard = other.loop_iteration_depth_hard;
loop_iteration_depth_soft = other.loop_iteration_depth_soft;
@@ -110,7 +111,7 @@ ParsedIR &ParsedIR::operator=(const ParsedIR &other)
continue_block_to_loop_header = other.continue_block_to_loop_header;
entry_points = other.entry_points;
default_entry_point = other.default_entry_point;
source = other.source;
sources = other.sources;
loop_iteration_depth_hard = other.loop_iteration_depth_hard;
loop_iteration_depth_soft = other.loop_iteration_depth_soft;
addressing_model = other.addressing_model;

View File

@@ -118,10 +118,25 @@ public:
bool known = false;
bool hlsl = false;
ID file_id = 0; // string
ID define_id = 0; // only non-zero for DebugSource
std::string source;
struct Marker
{
ID line; // in source
ID col; // in source
ID offset; // in spirv stream
ID function_id;
ID block_id;
};
SmallVector<Marker> line_markers; // sorted by line
Source() = default;
};
Source source;
std::vector<Source> sources;
AddressingModel addressing_model = AddressingModelMax;
MemoryModel memory_model = MemoryModelMax;
@@ -233,7 +248,6 @@ public:
uint32_t get_spirv_version() const;
private:
template <typename T>
T &get(uint32_t id)
{
@@ -246,6 +260,7 @@ private:
return variant_get<T>(ids[id]);
}
private:
mutable uint32_t loop_iteration_depth_hard = 0;
mutable uint32_t loop_iteration_depth_soft = 0;
std::string empty_string;

View File

@@ -206,10 +206,10 @@ static BufferPackingStandard packing_to_substruct_packing(BufferPackingStandard
void CompilerGLSL::init()
{
if (ir.source.known)
if (!ir.sources.empty() && ir.sources.front().known)
{
options.es = ir.source.es;
options.version = ir.source.version;
options.es = ir.sources.front().es;
options.version = ir.sources.front().version;
}
// Query the locale to see what the decimal point is.
@@ -1755,10 +1755,32 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f
{
uint32_t packed_size = to_array_size_literal(type) * type_to_packed_array_stride(type, flags, packing);
// For arrays of vectors and matrices in HLSL, the last element has a size which depends on its vector size,
// so that it is possible to pack other vectors into the last element.
if (packing_is_hlsl(packing) && type.basetype != SPIRType::Struct)
packed_size -= (4 - type.vecsize) * (type.width / 8);
if (packing_is_hlsl(packing))
{
// For arrays of vectors and matrices in HLSL, the last element has a size which depends on its vector size,
// so that it is possible to pack other vectors into the last element.
if (type.basetype != SPIRType::Struct)
{
if (flags.get(DecorationRowMajor) && type.columns > 1)
packed_size -= (4 - type.columns) * (type.width / 8);
else
packed_size -= (4 - type.vecsize) * (type.width / 8);
}
else
{
const auto *base_type = &type;
while (is_array(*base_type))
{
auto &new_type = get<SPIRType>(base_type->parent_type);
if (!is_array(new_type))
break;
base_type = &new_type;
}
packed_size -= type_to_packed_array_stride(*base_type, flags, packing);
packed_size += type_to_packed_size(get<SPIRType>(base_type->parent_type), flags, packing);
}
}
return packed_size;
}
@@ -1777,15 +1799,27 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f
uint32_t packed_alignment = type_to_packed_alignment(member_type, member_flags, packing);
uint32_t alignment = max(packed_alignment, pad_alignment);
// The next member following a struct member is aligned to the base alignment of the struct that came before.
// GL 4.5 spec, 7.6.2.2.
if (member_type.basetype == SPIRType::Struct)
pad_alignment = packed_alignment;
uint32_t element_size = type_to_packed_size(member_type, member_flags, packing);
pad_alignment = 1;
if (packing_is_hlsl(packing))
{
// HLSL is primarily a "cannot-straddle-vec4" language.
uint32_t begin_word = size / 16;
uint32_t end_word = (size + element_size - 1) / 16;
if (begin_word != end_word)
alignment = max<uint32_t>(alignment, 16u);
}
else
pad_alignment = 1;
{
// The next member following a struct member is aligned to the base alignment of the struct that came before.
// GL 4.5 spec, 7.6.2.2.
if (member_type.basetype == SPIRType::Struct)
pad_alignment = packed_alignment;
}
size = (size + alignment - 1) & ~(alignment - 1);
size += type_to_packed_size(member_type, member_flags, packing);
size += element_size;
}
}
else
@@ -1803,9 +1837,7 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f
if (flags.get(DecorationColMajor) && type.columns > 1)
{
if (packing_is_vec4_padded(packing))
size = type.columns * 4 * base_alignment;
else if (type.vecsize == 3)
if (packing_is_vec4_padded(packing) || type.vecsize == 3)
size = type.columns * 4 * base_alignment;
else
size = type.columns * type.vecsize * base_alignment;
@@ -1813,9 +1845,7 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f
if (flags.get(DecorationRowMajor) && type.vecsize > 1)
{
if (packing_is_vec4_padded(packing))
size = type.vecsize * 4 * base_alignment;
else if (type.columns == 3)
if (packing_is_vec4_padded(packing) || type.columns == 3)
size = type.vecsize * 4 * base_alignment;
else
size = type.vecsize * type.columns * base_alignment;
@@ -1824,7 +1854,12 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f
// For matrices in HLSL, the last element has a size which depends on its vector size,
// so that it is possible to pack other vectors into the last element.
if (packing_is_hlsl(packing) && type.columns > 1)
size -= (4 - type.vecsize) * (type.width / 8);
{
if (flags.get(DecorationRowMajor))
size -= (4 - type.columns) * (type.width / 8);
else
size -= (4 - type.vecsize) * (type.width / 8);
}
}
}
@@ -1915,7 +1950,7 @@ bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackin
// The next member following a struct member is aligned to the base alignment of the struct that came before.
// GL 4.5 spec, 7.6.2.2.
if (memb_type.basetype == SPIRType::Struct && !memb_type.pointer)
if (!packing_is_hlsl(packing) && memb_type.basetype == SPIRType::Struct && !memb_type.pointer)
pad_alignment = packed_alignment;
else
pad_alignment = 1;
@@ -1943,13 +1978,16 @@ bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackin
}
// Verify array stride rules.
if (is_array(memb_type) &&
type_to_packed_array_stride(memb_type, member_flags, packing) !=
type_struct_member_array_stride(type, i))
if (is_array(memb_type))
{
if (failed_validation_index)
*failed_validation_index = i;
return false;
auto packed_array_stride = type_to_packed_array_stride(memb_type, member_flags, packing);
auto member_array_stride = type_struct_member_array_stride(type, i);
if (packed_array_stride != member_array_stride)
{
if (failed_validation_index)
*failed_validation_index = i;
return false;
}
}
// Verify that sub-structs also follow packing rules.

View File

@@ -6170,14 +6170,31 @@ void CompilerMSL::emit_custom_functions()
"device", "device", "device", "device", "thread", "threadgroup",
};
static const bool src_is_physical_with_mismatch[] = {
true, true, false,
false, false, false,
false, false, false,
false, true, true,
};
static const bool dst_is_physical_with_mismatch[] = {
false, false, false,
false, false, false,
false, false, true,
true, false, false,
};
for (uint32_t variant = 0; variant < 12; variant++)
{
assert(!src_is_physical_with_mismatch[variant] || !dst_is_physical_with_mismatch[variant]);
bool is_multidim = spv_func == SPVFuncImplArrayCopyMultidim;
const char* dim = is_multidim ? "[N][M]" : "[N]";
const char *dim = is_multidim ? "[N][M]" : "[N]";
// Simple base case.
statement("template<typename T, uint N", is_multidim ? ", uint M>" : ">");
statement("inline void spvArrayCopy", function_name_tags[variant], "(",
dst_address_space[variant], " T (&dst)", dim, ", ",
src_address_space[variant], " T (&src)", dim, ")");
dst_address_space[variant], " T (&dst)", dim, ", ",
src_address_space[variant], " T (&src)", dim, ")");
begin_scope();
statement("for (uint i = 0; i < N; i++)");
begin_scope();
@@ -6187,6 +6204,81 @@ void CompilerMSL::emit_custom_functions()
statement("dst[i] = src[i];");
end_scope();
end_scope();
if (spv_function_implementations.count(SPVFuncImplArrayCopyExtendedSrc) &&
src_is_physical_with_mismatch[variant])
{
// 1st overload, src can be magic vector where dst is a scalar.
// Need reinterpret casts to be memory model correct. LLVM vectors are broken otherwise.
statement("template<typename T, uint V, uint N", is_multidim ? ", uint M>" : ">");
statement("inline void spvArrayCopy", function_name_tags[variant], "(",
dst_address_space[variant], " T (&dst)", dim, ", ",
src_address_space[variant], " vec<T, V> (&src)", dim, ")");
begin_scope();
statement("for (uint i = 0; i < N; i++)");
begin_scope();
if (is_multidim)
statement("spvArrayCopy", function_name_tags[variant], "(dst[i], src[i]);");
else
statement("dst[i] = reinterpret_cast<", src_address_space[variant], " T &>(src[i]);");
end_scope();
end_scope();
statement("");
// 2nd overload, both are vectors, but need SFINAE magic to avoid ambiguous case.
statement("template<typename T, uint Vdst, uint Vsrc, uint N", is_multidim ? ", uint M>" : ">");
statement("inline enable_if_t<Vdst != Vsrc> spvArrayCopy", function_name_tags[variant], "(",
dst_address_space[variant], " vec<T, Vdst> (&dst)", dim, ", ",
src_address_space[variant], " vec<T, Vsrc> (&src)", dim, ")");
begin_scope();
statement("for (uint i = 0; i < N; i++)");
begin_scope();
if (is_multidim)
statement("spvArrayCopy", function_name_tags[variant], "(dst[i], src[i]);");
else
statement("dst[i] = reinterpret_cast<", src_address_space[variant], " vec<T, Vdst> &>(src[i]);");
end_scope();
end_scope();
}
if (spv_function_implementations.count(SPVFuncImplArrayCopyExtendedDst) &&
dst_is_physical_with_mismatch[variant])
{
// 1st overload, src can be magic vector where dst is a scalar.
// Need reinterpret casts to be memory model correct. LLVM vectors are broken otherwise.
statement("template<typename T, uint V, uint N", is_multidim ? ", uint M>" : ">");
statement("inline void spvArrayCopy", function_name_tags[variant], "(",
dst_address_space[variant], " vec<T, V> (&dst)", dim, ", ",
src_address_space[variant], " T (&src)", dim, ")");
begin_scope();
statement("for (uint i = 0; i < N; i++)");
begin_scope();
if (is_multidim)
statement("spvArrayCopy", function_name_tags[variant], "(dst[i], src[i]);");
else
statement("reinterpret_cast<", dst_address_space[variant], " T &>(dst[i]) = src[i];");
end_scope();
end_scope();
statement("");
// 2nd overload, both are vectors, but need SFINAE magic to avoid ambiguous case.
statement("template<typename T, uint Vdst, uint Vsrc, uint N", is_multidim ? ", uint M>" : ">");
statement("inline enable_if_t<Vdst != Vsrc> spvArrayCopy", function_name_tags[variant], "(",
dst_address_space[variant], " vec<T, Vdst> (&dst)", dim, ", ",
src_address_space[variant], " vec<T, Vsrc> (&src)", dim, ")");
begin_scope();
statement("for (uint i = 0; i < N; i++)");
begin_scope();
if (is_multidim)
statement("spvArrayCopy", function_name_tags[variant], "(dst[i], src[i]);");
else
statement("reinterpret_cast<", dst_address_space[variant], " vec<T, Vsrc> &>(dst[i]) = src[i];");
end_scope();
end_scope();
}
statement("");
}
break;
@@ -10905,6 +10997,12 @@ bool CompilerMSL::emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rh
else
SPIRV_CROSS_THROW("Unknown storage class used for copying arrays.");
// Should be very rare, but mark if we need extra magic template overloads.
if (has_extended_decoration(lhs_id, SPIRVCrossDecorationPhysicalTypeID))
add_spv_func_and_recompile(SPVFuncImplArrayCopyExtendedDst);
if (has_extended_decoration(rhs_id, SPIRVCrossDecorationPhysicalTypeID))
add_spv_func_and_recompile(SPVFuncImplArrayCopyExtendedSrc);
// Pass internal array of spvUnsafeArray<> into wrapper functions
if (lhs_is_array_template && rhs_is_array_template && !msl_options.force_native_arrays)
statement("spvArrayCopy", tag, "(", lhs, ".elements, ", to_expression(rhs_id), ".elements);");
@@ -14172,6 +14270,10 @@ string CompilerMSL::get_type_address_space(const SPIRType &type, uint32_t id, bo
addr_space = "threadgroup";
}
// BlockIO is passed as thread and lowered on return from main.
if (get_execution_model() == ExecutionModelVertex && has_decoration(type.self, DecorationBlock))
addr_space = "thread";
if (!addr_space)
addr_space = "device";
}

View File

@@ -796,6 +796,8 @@ protected:
SPVFuncImplSSign,
SPVFuncImplArrayCopy,
SPVFuncImplArrayCopyMultidim,
SPVFuncImplArrayCopyExtendedSrc,
SPVFuncImplArrayCopyExtendedDst,
SPVFuncImplTexelBufferCoords,
SPVFuncImplImage2DAtomicCoords, // Emulate texture2D atomic operations
SPVFuncImplGradientCube,

View File

@@ -22,6 +22,7 @@
*/
#include "spirv_parser.hpp"
#include "NonSemanticShaderDebugInfo100.h"
#include <assert.h>
using namespace std;
@@ -137,6 +138,15 @@ void Parser::parse()
}
forward_pointer_fixups.clear();
for (auto &source : ir.sources)
{
auto cmp = [](const ParsedIR::Source::Marker &a, const ParsedIR::Source::Marker &b) {
return a.line < b.line;
};
std::sort(source.line_markers.begin(), source.line_markers.end(), cmp);
}
if (current_function)
SPIRV_CROSS_THROW("Function was not terminated.");
if (current_block)
@@ -194,7 +204,6 @@ void Parser::parse(const Instruction &instruction)
switch (op)
{
case OpSourceContinued:
case OpSourceExtension:
case OpNop:
case OpModuleProcessed:
@@ -213,38 +222,53 @@ void Parser::parse(const Instruction &instruction)
case OpSource:
{
ir.source.lang = static_cast<SourceLanguage>(ops[0]);
switch (ir.source.lang)
ir.sources.emplace_back();
auto &source = ir.sources.back();
source.lang = static_cast<SourceLanguage>(ops[0]);
switch (source.lang)
{
case SourceLanguageESSL:
ir.source.es = true;
ir.source.version = ops[1];
ir.source.known = true;
ir.source.hlsl = false;
source.es = true;
source.version = ops[1];
source.known = true;
source.hlsl = false;
break;
case SourceLanguageGLSL:
ir.source.es = false;
ir.source.version = ops[1];
ir.source.known = true;
ir.source.hlsl = false;
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.
ir.source.es = false;
ir.source.version = 450;
ir.source.known = true;
ir.source.hlsl = true;
source.es = false;
source.version = 450;
source.known = true;
source.hlsl = true;
break;
default:
ir.source.known = false;
source.known = false;
break;
}
if (length >= 3)
source.file_id = ops[2];
if (length >= 4)
source.source = extract_string(ir.spirv, instruction.offset + 3);
break;
}
case OpSourceContinued:
if (!ir.sources.empty())
ir.sources.back().source += extract_string(ir.spirv, instruction.offset);
break;
case OpUndef:
{
uint32_t result_type = ops[0];
@@ -318,17 +342,70 @@ void Parser::parse(const Instruction &instruction)
ir.load_type_width.insert({ ops[1], type->width });
}
}
else if (op == OpExtInst)
if (op == OpExtInst && length > 4)
{
// Don't want to deal with ForwardRefs here.
auto &ext = get<SPIRExtension>(ops[2]);
if (ext.ext == SPIRExtension::NonSemanticShaderDebugInfo)
{
// Parse global ShaderDebugInfo we care about.
// Just forward the string information.
if (ops[3] == SPIRExtension::DebugSource)
const auto instr = ops[3];
if (instr == NonSemanticShaderDebugInfo100DebugSource)
{
set<SPIRString>(ops[1], get<SPIRString>(ops[4]).str);
ir.sources.emplace_back();
auto &source = ir.sources.back();
source.file_id = ops[4];
source.define_id = ops[1];
if (length >= 6)
source.source = ir.get<SPIRString>(ops[5]).str;
}
else if (instr == NonSemanticShaderDebugInfo100DebugSourceContinued)
{
if (length < 5)
SPIRV_CROSS_THROW("Invalid arguments for ShaderDebugInfo100DebugSourceContinued");
if (!ir.sources.empty())
ir.sources.back().source += ir.get<SPIRString>(ops[4]).str;
}
else if (instr == NonSemanticShaderDebugInfo100DebugLine)
{
if (length < 9)
SPIRV_CROSS_THROW("Invalid arguments for ShaderDebugInfo100DebugLine");
auto source_id = ops[4];
auto line_start = ir.get<SPIRConstant>(ops[5]).scalar_i32();
auto col_start = ir.get<SPIRConstant>(ops[7]).scalar_i32();
for (auto &source : ir.sources)
{
if (source.define_id != source_id)
continue;
source.line_markers.emplace_back();
auto &marker = source.line_markers.back();
marker.line = line_start;
marker.col = col_start;
marker.offset = instruction.offset - 1;
marker.function_id = current_function ? current_function->self : ID(0);
marker.block_id = current_block ? current_block->self : ID(0);
break;
}
}
else if (instr == NonSemanticShaderDebugInfo100DebugLocalVariable)
{
if (length < 11)
SPIRV_CROSS_THROW("Invalid arguments for ShaderDebugInfo100DebugLocalVariable");
auto &lvar = set<SPIRDebugLocalVariable>(ops[1]);
lvar.name_id = ops[4];
}
else if (instr == NonSemanticShaderDebugInfo100DebugDeclare)
{
if (length < 7)
SPIRV_CROSS_THROW("Invalid arguments for ShaderDebugInfo100DebugDeclare");
auto &lvar = get<SPIRDebugLocalVariable>(ops[4]);
auto &var = get<SPIRVariable>(ops[5]);
var.debug_local_variables.push_back(lvar.self);
}
}
}
break;
@@ -1378,6 +1455,24 @@ void Parser::parse(const Instruction &instruction)
current_function->entry_line.line_literal = ops[1];
}
}
uint32_t file = ops[0];
uint32_t line = ops[1];
for (auto &source : ir.sources)
{
if (source.file_id == file)
{
source.line_markers.emplace_back();
auto &marker = source.line_markers.back();
marker.line = line;
marker.offset = instruction.offset - 1;
marker.function_id = current_function ? current_function->self : ID(0);
marker.block_id = current_block ? current_block->self : ID(0);
break;
}
}
break;
}