Commit 0d1f7dcd authored by Laszlo Agocs's avatar Laszlo Agocs

Upgrade 3rdparty deps

parent 23a70462
......@@ -7,7 +7,7 @@
"QtUsage": "Shader code generation",
"Homepage": "https://github.com/KhronosGroup/SPIRV-Cross",
"Version": "",
"Version": "bfeb388edfb63c9a927e517b634abaaa5bfb1caf",
"License": "Apache License 2.0",
"LicenseId": "Apache-2.0",
"LicenseFile": "LICENSE",
......
......@@ -42,8 +42,8 @@ namespace spirv_cross
#ifndef _MSC_VER
[[noreturn]]
#endif
inline void
report_and_abort(const std::string &msg)
inline void
report_and_abort(const std::string &msg)
{
#ifdef NDEBUG
(void)msg;
......@@ -68,6 +68,17 @@ public:
#define SPIRV_CROSS_THROW(x) throw CompilerError(x)
#endif
//#define SPIRV_CROSS_COPY_CONSTRUCTOR_SANITIZE
// MSVC 2013 does not have noexcept. We need this for Variant to get move constructor to work correctly
// instead of copy constructor.
// MSVC 2013 ignores that move constructors cannot throw in std::vector, so just don't define it.
#if defined(_MSC_VER) && _MSC_VER < 1900
#define SPIRV_CROSS_NOEXCEPT
#else
#define SPIRV_CROSS_NOEXCEPT noexcept
#endif
#if __cplusplus >= 201402l
#define SPIRV_CROSS_DEPRECATED(reason) [[deprecated(reason)]]
#elif defined(__GNUC__)
......@@ -282,21 +293,27 @@ inline std::string convert_to_string(double t)
struct Instruction
{
Instruction(const std::vector<uint32_t> &spirv, uint32_t &index);
uint16_t op;
uint16_t count;
uint32_t offset;
uint32_t length;
uint16_t op = 0;
uint16_t count = 0;
uint32_t offset = 0;
uint32_t length = 0;
};
// Helper for Variant interface.
struct IVariant
{
virtual ~IVariant() = default;
virtual std::unique_ptr<IVariant> clone() = 0;
uint32_t self = 0;
};
#define SPIRV_CROSS_DECLARE_CLONE(T) \
std::unique_ptr<IVariant> clone() override \
{ \
return std::unique_ptr<IVariant>(new T(*this)); \
}
enum Types
{
TypeNone,
......@@ -326,6 +343,8 @@ struct SPIRUndef : IVariant
{
}
uint32_t basetype;
SPIRV_CROSS_DECLARE_CLONE(SPIRUndef)
};
// This type is only used by backends which need to access the combined image and sampler IDs separately after
......@@ -345,6 +364,8 @@ struct SPIRCombinedImageSampler : IVariant
uint32_t combined_type;
uint32_t image;
uint32_t sampler;
SPIRV_CROSS_DECLARE_CLONE(SPIRCombinedImageSampler)
};
struct SPIRConstantOp : IVariant
......@@ -364,6 +385,8 @@ struct SPIRConstantOp : IVariant
spv::Op opcode;
std::vector<uint32_t> arguments;
uint32_t basetype;
SPIRV_CROSS_DECLARE_CLONE(SPIRConstantOp)
};
struct SPIRType : IVariant
......@@ -438,6 +461,8 @@ struct SPIRType : IVariant
// Used in backends to avoid emitting members with conflicting names.
std::unordered_set<std::string> member_name_cache;
SPIRV_CROSS_DECLARE_CLONE(SPIRType)
};
struct SPIRExtension : IVariant
......@@ -463,6 +488,7 @@ struct SPIRExtension : IVariant
}
Extension ext;
SPIRV_CROSS_DECLARE_CLONE(SPIRExtension)
};
// SPIREntryPoint is not a variant since its IDs are used to decorate OpFunction,
......@@ -533,6 +559,8 @@ struct SPIRExpression : IVariant
// A list of expressions which this expression depends on.
std::vector<uint32_t> expression_dependencies;
SPIRV_CROSS_DECLARE_CLONE(SPIRExpression)
};
struct SPIRFunctionPrototype : IVariant
......@@ -549,6 +577,8 @@ struct SPIRFunctionPrototype : IVariant
uint32_t return_type;
std::vector<uint32_t> parameter_types;
SPIRV_CROSS_DECLARE_CLONE(SPIRFunctionPrototype)
};
struct SPIRBlock : IVariant
......@@ -664,6 +694,9 @@ struct SPIRBlock : IVariant
// If the continue block is complex, fallback to "dumb" for loops.
bool complex_continue = false;
// Do we need a ladder variable to defer breaking out of a loop construct after a switch block?
bool need_ladder_break = false;
// The dominating block which this block might be within.
// Used in continue; blocks to determine if we really need to write continue.
uint32_t loop_dominator = 0;
......@@ -681,6 +714,8 @@ struct SPIRBlock : IVariant
// sub-group-like operations.
// Make sure that we only use these expressions in the original block.
std::vector<uint32_t> invalidate_expressions;
SPIRV_CROSS_DECLARE_CLONE(SPIRBlock)
};
struct SPIRFunction : IVariant
......@@ -753,17 +788,21 @@ struct SPIRFunction : IVariant
arguments.push_back({ parameter_type, id, 0u, 0u, alias_global_variable });
}
// Statements to be emitted when the function returns.
// Hooks to be run when the function returns.
// Mostly used for lowering internal data structures onto flattened structures.
std::vector<std::string> fixup_statements_out;
// Need to defer this, because they might rely on things which change during compilation.
std::vector<std::function<void()>> fixup_hooks_out;
// Statements to be emitted when the function begins.
// Hooks to be run when the function begins.
// Mostly used for populating internal data structures from flattened structures.
std::vector<std::string> fixup_statements_in;
// Need to defer this, because they might rely on things which change during compilation.
std::vector<std::function<void()>> fixup_hooks_in;
bool active = false;
bool flush_undeclared = true;
bool do_combined_parameters = true;
SPIRV_CROSS_DECLARE_CLONE(SPIRFunction)
};
struct SPIRAccessChain : IVariant
......@@ -798,6 +837,8 @@ struct SPIRAccessChain : IVariant
uint32_t matrix_stride = 0;
bool row_major_matrix = false;
bool immutable = false;
SPIRV_CROSS_DECLARE_CLONE(SPIRAccessChain)
};
struct SPIRVariable : IVariant
......@@ -851,6 +892,8 @@ struct SPIRVariable : IVariant
bool loop_variable_enable = false;
SPIRFunction::Parameter *parameter = nullptr;
SPIRV_CROSS_DECLARE_CLONE(SPIRVariable)
};
struct SPIRConstant : IVariant
......@@ -1106,6 +1149,8 @@ struct SPIRConstant : IVariant
// For composites which are constant arrays, etc.
std::vector<uint32_t> subconstants;
SPIRV_CROSS_DECLARE_CLONE(SPIRConstant)
};
class Variant
......@@ -1113,21 +1158,50 @@ class Variant
public:
// MSVC 2013 workaround, we shouldn't need these constructors.
Variant() = default;
Variant(Variant &&other)
// Marking custom move constructor as noexcept is important.
Variant(Variant &&other) SPIRV_CROSS_NOEXCEPT
{
*this = std::move(other);
}
Variant &operator=(Variant &&other)
Variant(const Variant &variant)
{
*this = variant;
}
// Marking custom move constructor as noexcept is important.
Variant &operator=(Variant &&other) SPIRV_CROSS_NOEXCEPT
{
if (this != &other)
{
holder = move(other.holder);
holder = std::move(other.holder);
type = other.type;
allow_type_rewrite = other.allow_type_rewrite;
other.type = TypeNone;
}
return *this;
}
// This copy/clone should only be called in the Compiler constructor.
// If this is called inside ::compile(), we invalidate any references we took higher in the stack.
// This should never happen.
Variant &operator=(const Variant &other)
{
#ifdef SPIRV_CROSS_COPY_CONSTRUCTOR_SANITIZE
abort();
#endif
if (this != &other)
{
holder.reset();
if (other.holder)
holder = other.holder->clone();
type = other.type;
allow_type_rewrite = other.allow_type_rewrite;
}
return *this;
}
void set(std::unique_ptr<IVariant> val, uint32_t new_type)
{
holder = std::move(val);
......@@ -1161,14 +1235,17 @@ public:
{
return type;
}
uint32_t get_id() const
{
return holder ? holder->self : 0;
}
bool empty() const
{
return !holder;
}
void reset()
{
holder.reset();
......@@ -1217,6 +1294,7 @@ struct Meta
Bitset decoration_flags;
spv::BuiltIn builtin_type;
uint32_t location = 0;
uint32_t component = 0;
uint32_t set = 0;
uint32_t binding = 0;
uint32_t offset = 0;
......@@ -1230,7 +1308,6 @@ struct Meta
Decoration decoration;
std::vector<Decoration> members;
uint32_t sampler = 0;
std::unordered_map<uint32_t, uint32_t> decoration_word_offset;
......@@ -1291,6 +1368,12 @@ static inline bool type_is_floating_point(const SPIRType &type)
{
return type.basetype == SPIRType::Half || type.basetype == SPIRType::Float || type.basetype == SPIRType::Double;
}
static inline bool type_is_integral(const SPIRType &type)
{
return type.basetype == SPIRType::Int || type.basetype == SPIRType::UInt || type.basetype == SPIRType::Int64 ||
type.basetype == SPIRType::UInt64;
}
} // namespace spirv_cross
#endif
......@@ -27,8 +27,8 @@ void CompilerCPP::emit_buffer_block(const SPIRVariable &var)
auto &type = get<SPIRType>(var.basetype);
auto instance_name = to_name(var.self);
uint32_t descriptor_set = meta[var.self].decoration.set;
uint32_t binding = meta[var.self].decoration.binding;
uint32_t descriptor_set = ir.meta[var.self].decoration.set;
uint32_t binding = ir.meta[var.self].decoration.binding;
emit_block_struct(type);
auto buffer_name = to_name(type.self);
......@@ -49,10 +49,10 @@ void CompilerCPP::emit_interface_block(const SPIRVariable &var)
const char *qual = var.storage == StorageClassInput ? "StageInput" : "StageOutput";
const char *lowerqual = var.storage == StorageClassInput ? "stage_input" : "stage_output";
auto instance_name = to_name(var.self);
uint32_t location = meta[var.self].decoration.location;
uint32_t location = ir.meta[var.self].decoration.location;
string buffer_name;
auto flags = meta[type.self].decoration.decoration_flags;
auto flags = ir.meta[type.self].decoration.decoration_flags;
if (flags.get(DecorationBlock))
{
emit_block_struct(type);
......@@ -83,9 +83,9 @@ void CompilerCPP::emit_uniform(const SPIRVariable &var)
auto &type = get<SPIRType>(var.basetype);
auto instance_name = to_name(var.self);
uint32_t descriptor_set = meta[var.self].decoration.set;
uint32_t binding = meta[var.self].decoration.binding;
uint32_t location = meta[var.self].decoration.location;
uint32_t descriptor_set = ir.meta[var.self].decoration.set;
uint32_t binding = ir.meta[var.self].decoration.binding;
uint32_t location = ir.meta[var.self].decoration.location;
string type_name = type_to_glsl(type);
remap_variable_type_name(type, instance_name, type_name);
......@@ -114,7 +114,7 @@ void CompilerCPP::emit_push_constant_block(const SPIRVariable &var)
add_resource_name(var.self);
auto &type = get<SPIRType>(var.basetype);
auto &flags = meta[var.self].decoration.decoration_flags;
auto &flags = ir.meta[var.self].decoration.decoration_flags;
if (flags.get(DecorationBinding) || flags.get(DecorationDescriptorSet))
SPIRV_CROSS_THROW("Push constant blocks cannot be compiled to GLSL with Binding or Set syntax. "
"Remap to location with reflection API first or disable these decorations.");
......@@ -145,14 +145,14 @@ void CompilerCPP::emit_resources()
{
// Output all basic struct types which are not Block or BufferBlock as these are declared inplace
// when such variables are instantiated.
for (auto &id : ids)
for (auto &id : ir.ids)
{
if (id.get_type() == TypeType)
{
auto &type = id.get<SPIRType>();
if (type.basetype == SPIRType::Struct && type.array.empty() && !type.pointer &&
(!meta[type.self].decoration.decoration_flags.get(DecorationBlock) &&
!meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock)))
(!ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) &&
!ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock)))
{
emit_struct(type);
}
......@@ -163,7 +163,7 @@ void CompilerCPP::emit_resources()
begin_scope();
// Output UBOs and SSBOs
for (auto &id : ids)
for (auto &id : ir.ids)
{
if (id.get_type() == TypeVariable)
{
......@@ -172,8 +172,8 @@ void CompilerCPP::emit_resources()
if (var.storage != StorageClassFunction && type.pointer && type.storage == StorageClassUniform &&
!is_hidden_variable(var) &&
(meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock)))
(ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock) ||
ir.meta[type.self].decoration.decoration_flags.get(DecorationBufferBlock)))
{
emit_buffer_block(var);
}
......@@ -181,7 +181,7 @@ void CompilerCPP::emit_resources()
}
// Output push constant blocks
for (auto &id : ids)
for (auto &id : ir.ids)
{
if (id.get_type() == TypeVariable)
{
......@@ -196,7 +196,7 @@ void CompilerCPP::emit_resources()
}
// Output in/out interfaces.
for (auto &id : ids)
for (auto &id : ir.ids)
{
if (id.get_type() == TypeVariable)
{
......@@ -213,7 +213,7 @@ void CompilerCPP::emit_resources()
}
// Output Uniform Constants (values, samplers, images, etc).
for (auto &id : ids)
for (auto &id : ir.ids)
{
if (id.get_type() == TypeVariable)
{
......@@ -318,7 +318,7 @@ string CompilerCPP::compile()
emit_header();
emit_resources();
emit_function(get<SPIRFunction>(entry_point), Bitset());
emit_function(get<SPIRFunction>(ir.default_entry_point), Bitset());
pass_count++;
} while (force_recompile);
......@@ -376,7 +376,7 @@ void CompilerCPP::emit_c_linkage()
void CompilerCPP::emit_function_prototype(SPIRFunction &func, const Bitset &)
{
if (func.self != entry_point)
if (func.self != ir.default_entry_point)
add_function_overload(func);
local_variable_names = resource_names;
......@@ -387,7 +387,7 @@ void CompilerCPP::emit_function_prototype(SPIRFunction &func, const Bitset &)
decl += type_to_glsl(type);
decl += " ";
if (func.self == entry_point)
if (func.self == ir.default_entry_point)
{
decl += "main";
processing_entry_point = true;
......
......@@ -26,13 +26,23 @@ namespace spirv_cross
class CompilerCPP : public CompilerGLSL
{
public:
CompilerCPP(std::vector<uint32_t> spirv_)
explicit CompilerCPP(std::vector<uint32_t> spirv_)
: CompilerGLSL(move(spirv_))
{
}
CompilerCPP(const uint32_t *ir, size_t word_count)
: CompilerGLSL(ir, word_count)
CompilerCPP(const uint32_t *ir_, size_t word_count)
: CompilerGLSL(ir_, word_count)
{
}
explicit CompilerCPP(const ParsedIR &ir_)
: CompilerGLSL(ir_)
{
}
explicit CompilerCPP(ParsedIR &&ir_)
: CompilerGLSL(std::move(ir_))
{
}
......
This diff is collapsed.
......@@ -19,7 +19,7 @@
#include "spirv.hpp"
#include "spirv_cfg.hpp"
#include "spirv_common.hpp"
#include "spirv_cross_parsed_ir.hpp"
namespace spirv_cross
{
......@@ -121,9 +121,16 @@ public:
friend class DominatorBuilder;
// The constructor takes a buffer of SPIR-V words and parses it.
Compiler(std::vector<uint32_t> ir);
// It will create its own parser, parse the SPIR-V and move the parsed IR
// as if you had called the constructors taking ParsedIR directly.
explicit Compiler(std::vector<uint32_t> ir);
Compiler(const uint32_t *ir, size_t word_count);
// This is more modular. We can also consume a ParsedIR structure directly, either as a move, or copy.
// With copy, we can reuse the same parsed IR for multiple Compiler instances.
explicit Compiler(const ParsedIR &ir);
explicit Compiler(ParsedIR &&ir);
virtual ~Compiler() = default;
// After parsing, API users can modify the SPIR-V via reflection and call this
......@@ -160,7 +167,7 @@ public:
uint32_t get_decoration(uint32_t id, spv::Decoration decoration) const;
const std::string &get_decoration_string(uint32_t id, spv::Decoration decoration) const;
// Removes the decoration for a an ID.
// Removes the decoration for an ID.
void unset_decoration(uint32_t id, spv::Decoration decoration);
// Gets the SPIR-V type associated with ID.
......@@ -179,6 +186,9 @@ public:
// Gets the SPIR-V type underlying the given type_id, which might be a pointer.
const SPIRType &get_non_pointer_type(uint32_t type_id) const;
// Returns if the given type refers to a sampled image.
bool is_sampled_image_type(const SPIRType &type);
// Gets the underlying storage class for an OpVariable.
spv::StorageClass get_storage_class(uint32_t id) const;
......@@ -239,6 +249,18 @@ public:
// Returns the effective size of a buffer block.
size_t get_declared_struct_size(const SPIRType &struct_type) const;
// Returns the effective size of a buffer block, with a given array size
// for a runtime array.
// SSBOs are typically declared as runtime arrays. get_declared_struct_size() will return 0 for the size.
// This is not very helpful for applications which might need to know the array stride of its last member.
// This can be done through the API, but it is not very intuitive how to accomplish this, so here we provide a helper function
// to query the size of the buffer, assuming that the last member has a certain size.
// If the buffer does not contain a runtime array, array_size is ignored, and the function will behave as
// get_declared_struct_size().
// To get the array stride of the last member, something like:
// get_declared_struct_size_runtime_array(type, 1) - get_declared_struct_size_runtime_array(type, 0) will work.
size_t get_declared_struct_size_runtime_array(const SPIRType &struct_type, size_t array_size) const;
// Returns the effective size of a buffer block struct member.
virtual size_t get_declared_struct_member_size(const SPIRType &struct_type, uint32_t index) const;
......@@ -429,7 +451,7 @@ public:
uint32_t get_current_id_bound() const
{
return uint32_t(ids.size());
return uint32_t(ir.ids.size());
}
// API for querying buffer objects.
......@@ -490,6 +512,8 @@ public:
// For other names like remapped names for variables, etc, it's generally enough to query the name of the variables
// after compiling, block names are an exception to this rule.
// ID is the name of a variable as returned by Resource::id, and must be a variable with a Block-like type.
//
// This also applies to HLSL cbuffers.
std::string get_remapped_declared_block_name(uint32_t id) const;
// For buffer block variables, get the decorations for that variable.
......@@ -507,20 +531,19 @@ protected:
if (!instr.length)
return nullptr;
if (instr.offset + instr.length > spirv.size())
if (instr.offset + instr.length > ir.spirv.size())
SPIRV_CROSS_THROW("Compiler::stream() out of range.");
return &spirv[instr.offset];
return &ir.spirv[instr.offset];
}
std::vector<uint32_t> spirv;
std::vector<Instruction> inst;
std::vector<Variant> ids;
std::vector<Meta> meta;
ParsedIR ir;
// Marks variables which have global scope and variables which can alias with other variables
// (SSBO, image load store, etc)
std::vector<uint32_t> global_variables;
std::vector<uint32_t> aliased_variables;
SPIRFunction *current_function = nullptr;
SPIRBlock *current_block = nullptr;
std::vector<uint32_t> global_variables;
std::vector<uint32_t> aliased_variables;
std::unordered_set<uint32_t> active_interface_variables;
bool check_active_interface_variables = false;
......@@ -529,7 +552,7 @@ protected:
template <typename T, typename... P>
T &set(uint32_t id, P &&... args)
{
auto &var = variant_set<T>(ids.at(id), std::forward<P>(args)...);
auto &var = variant_set<T>(ir.ids.at(id), std::forward<P>(args)...);
var.self = id;
return var;
}
......@@ -537,13 +560,13 @@ protected:
template <typename T>
T &get(uint32_t id)
{
return variant_get<T>(ids.at(id));
return variant_get<T>(ir.ids.at(id));
}
template <typename T>
T *maybe_get(uint32_t id)
{
if (ids.at(id).get_type() == T::type)
if (ir.ids.at(id).get_type() == T::type)
return &get<T>(id);
else
return nullptr;
......@@ -552,44 +575,24 @@ protected:
template <typename T>
const T &get(uint32_t id) const
{
return variant_get<T>(ids.at(id));
return variant_get<T>(ir.ids.at(id));
}
template <typename T>
const T *maybe_get(uint32_t id) const
{
if (ids.at(id).get_type() == T::type)
if (ir.ids.at(id).get_type() == T::type)
return &get<T>(id);
else
return nullptr;
}
uint32_t entry_point = 0;
// Normally, we'd stick SPIREntryPoint in ids array, but it conflicts with SPIRFunction.
// Entry points can therefore be seen as some sort of meta structure.
std::unordered_map<uint32_t, SPIREntryPoint> entry_points;
const SPIREntryPoint &get_entry_point() const;
SPIREntryPoint &get_entry_point();
struct Source
{
uint32_t version = 0;
bool es = false;
bool known = false;
bool hlsl = false;
Source() = default;
} source;
std::unordered_set<uint32_t> loop_blocks;