Reduce pressure on global allocation.

- Replace ostringstream with custom implementation.
  ~30% performance uplift on vector-shuffle-oom test.
  Allocations are measurably reduced in Valgrind.

- Replace std::vector with SmallVector.
  Classic malloc optimization, small vectors are backed by inline data.
  ~ 7-8% gain on vector-shuffle-oom on GCC 8 on Linux.

- Use an object pool for IVariant type.
  We generally allocate a lot of SPIR* objects. We can amortize these
  allocations neatly by pooling them.

- ~15% overall uplift on ./test_shaders.py --iterations 10000 shaders/.
This commit is contained in:
Hans-Kristian Arntzen 2019-04-02 11:19:03 +02:00
parent c60b9a1e96
commit a489ba7fd1
23 changed files with 923 additions and 283 deletions

View File

@ -186,7 +186,7 @@ struct CLIParser
bool ended_state = false;
};
static vector<uint32_t> read_spirv_file(const char *path)
static SmallVector<uint32_t> read_spirv_file(const char *path)
{
FILE *file = fopen(path, "rb");
if (!file)
@ -199,7 +199,7 @@ static vector<uint32_t> read_spirv_file(const char *path)
long len = ftell(file) / sizeof(uint32_t);
rewind(file);
vector<uint32_t> spirv(len);
SmallVector<uint32_t> spirv(len);
if (fread(spirv.data(), sizeof(uint32_t), len, file) != size_t(len))
spirv.clear();
@ -221,7 +221,7 @@ static bool write_string_to_file(const char *path, const char *string)
return true;
}
static void print_resources(const Compiler &compiler, const char *tag, const vector<Resource> &resources)
static void print_resources(const Compiler &compiler, const char *tag, const SmallVector<Resource> &resources)
{
fprintf(stderr, "%s\n", tag);
fprintf(stderr, "=============\n\n");
@ -411,7 +411,7 @@ static void print_resources(const Compiler &compiler, const ShaderResources &res
print_resources(compiler, "acceleration structures", res.acceleration_structures);
}
static void print_push_constant_resources(const Compiler &compiler, const vector<Resource> &res)
static void print_push_constant_resources(const Compiler &compiler, const SmallVector<Resource> &res)
{
for (auto &block : res)
{
@ -510,14 +510,14 @@ struct CLIArguments
bool msl_domain_lower_left = false;
bool msl_argument_buffers = false;
bool glsl_emit_push_constant_as_ubo = false;
vector<uint32_t> msl_discrete_descriptor_sets;
vector<PLSArg> pls_in;
vector<PLSArg> pls_out;
vector<Remap> remaps;
vector<string> extensions;
vector<VariableTypeRemap> variable_type_remaps;
vector<InterfaceVariableRename> interface_variable_renames;
vector<HLSLVertexAttributeRemap> hlsl_attr_remap;
SmallVector<uint32_t> msl_discrete_descriptor_sets;
SmallVector<PLSArg> pls_in;
SmallVector<PLSArg> pls_out;
SmallVector<Remap> remaps;
SmallVector<string> extensions;
SmallVector<VariableTypeRemap> variable_type_remaps;
SmallVector<InterfaceVariableRename> interface_variable_renames;
SmallVector<HLSLVertexAttributeRemap> hlsl_attr_remap;
string entry;
string entry_stage;
@ -527,7 +527,7 @@ struct CLIArguments
string new_name;
ExecutionModel execution_model;
};
vector<Rename> entry_point_rename;
SmallVector<Rename> entry_point_rename;
uint32_t iterations = 1;
bool cpp = false;
@ -595,7 +595,7 @@ static void print_help()
"\n");
}
static bool remap_generic(Compiler &compiler, const vector<Resource> &resources, const Remap &remap)
static bool remap_generic(Compiler &compiler, const SmallVector<Resource> &resources, const Remap &remap)
{
auto itr =
find_if(begin(resources), end(resources), [&remap](const Resource &res) { return res.name == remap.src_name; });
@ -611,10 +611,10 @@ static bool remap_generic(Compiler &compiler, const vector<Resource> &resources,
return false;
}
static vector<PlsRemap> remap_pls(const vector<PLSArg> &pls_variables, const vector<Resource> &resources,
const vector<Resource> *secondary_resources)
static SmallVector<PlsRemap> remap_pls(const SmallVector<PLSArg> &pls_variables, const SmallVector<Resource> &resources,
const SmallVector<Resource> *secondary_resources)
{
vector<PlsRemap> ret;
SmallVector<PlsRemap> ret;
for (auto &pls : pls_variables)
{
@ -697,7 +697,7 @@ static ExecutionModel stage_to_execution_model(const std::string &stage)
SPIRV_CROSS_THROW("Invalid stage.");
}
static string compile_iteration(const CLIArguments &args, vector<uint32_t> spirv_file)
static string compile_iteration(const CLIArguments &args, SmallVector<uint32_t> spirv_file)
{
Parser spirv_parser(move(spirv_file));
spirv_parser.parse();

View File

@ -143,7 +143,7 @@ void CFG::build_post_order_visit_order()
void CFG::add_branch(uint32_t from, uint32_t to)
{
const auto add_unique = [](vector<uint32_t> &l, uint32_t value) {
const auto add_unique = [](SmallVector<uint32_t> &l, uint32_t value) {
auto itr = find(begin(l), end(l), value);
if (itr == end(l))
l.push_back(value);
@ -223,4 +223,4 @@ void DominatorBuilder::lift_continue_block_dominator()
if (back_edge_dominator)
dominator = cfg.get_function().entry_block;
}
} // namespace spirv_cross
} // namespace SPIRV_CROSS_NAMESPACE

View File

@ -63,7 +63,7 @@ public:
uint32_t find_common_dominator(uint32_t a, uint32_t b) const;
const std::vector<uint32_t> &get_preceding_edges(uint32_t block) const
const SmallVector<uint32_t> &get_preceding_edges(uint32_t block) const
{
auto itr = preceding_edges.find(block);
if (itr != std::end(preceding_edges))
@ -72,7 +72,7 @@ public:
return empty_vector;
}
const std::vector<uint32_t> &get_succeeding_edges(uint32_t block) const
const SmallVector<uint32_t> &get_succeeding_edges(uint32_t block) const
{
auto itr = succeeding_edges.find(block);
if (itr != std::end(succeeding_edges))
@ -111,12 +111,12 @@ private:
Compiler &compiler;
const SPIRFunction &func;
std::unordered_map<uint32_t, std::vector<uint32_t>> preceding_edges;
std::unordered_map<uint32_t, std::vector<uint32_t>> succeeding_edges;
std::unordered_map<uint32_t, SmallVector<uint32_t>> preceding_edges;
std::unordered_map<uint32_t, SmallVector<uint32_t>> succeeding_edges;
std::unordered_map<uint32_t, uint32_t> immediate_dominators;
std::unordered_map<uint32_t, VisitOrder> visit_order;
std::vector<uint32_t> post_order;
std::vector<uint32_t> empty_vector;
SmallVector<uint32_t> post_order;
SmallVector<uint32_t> empty_vector;
void add_branch(uint32_t from, uint32_t to);
void build_post_order_visit_order();
@ -144,6 +144,6 @@ private:
const CFG &cfg;
uint32_t dominator = 0;
};
} // namespace spirv_cross
} // namespace SPIRV_CROSS_NAMESPACE
#endif

View File

@ -20,20 +20,19 @@
#include "spirv.hpp"
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <functional>
#include <memory>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
// A bit crude, but allows projects which embed SPIRV-Cross statically to
// effectively hide all the symbols from other projects.
@ -105,16 +104,543 @@ public:
#define SPIRV_CROSS_DEPRECATED(reason)
#endif
// std::aligned_storage does not support size == 0, so roll our own.
template <typename T, size_t N>
class AlignedBuffer
{
public:
T *data()
{
return reinterpret_cast<T *>(aligned_char);
}
private:
alignas(T) char aligned_char[sizeof(T) * N];
};
template <typename T>
class AlignedBuffer<T, 0>
{
public:
T *data()
{
return nullptr;
}
};
// An immutable version of SmallVector which erases type information about storage.
template <typename T>
class VectorView
{
public:
T &operator[](size_t i)
{
return ptr[i];
}
const T &operator[](size_t i) const
{
return ptr[i];
}
bool empty() const
{
return buffer_size == 0;
}
size_t size() const
{
return buffer_size;
}
T *data()
{
return ptr;
}
const T *data() const
{
return ptr;
}
T *begin()
{
return ptr;
}
T *end()
{
return ptr + buffer_size;
}
const T *begin() const
{
return ptr;
}
const T *end() const
{
return ptr + buffer_size;
}
T &front()
{
return ptr[0];
}
const T &front() const
{
return ptr[0];
}
T &back()
{
return ptr[buffer_size - 1];
}
const T &back() const
{
return ptr[buffer_size - 1];
}
// Avoid sliced copies. Base class should only be read as a reference.
VectorView(const VectorView &) = delete;
void operator=(const VectorView &) = delete;
protected:
VectorView() = default;
T *ptr = nullptr;
size_t buffer_size = 0;
};
// Simple vector which supports up to N elements inline, without malloc/free.
// We use a lot of throwaway vectors all over the place which triggers allocations.
// This class only implements the subset of std::vector we need in SPIRV-Cross.
// It is *NOT* a drop-in replacement.
template <typename T, size_t N = 8>
class SmallVector : public VectorView<T>
{
public:
SmallVector()
{
this->ptr = stack_storage.data();
buffer_capacity = N;
}
SmallVector(const T *arg_list_begin, const T *arg_list_end)
: SmallVector()
{
auto count = size_t(arg_list_end - arg_list_begin);
reserve(count);
for (size_t i = 0; i < count; i++, arg_list_begin++)
new (&this->ptr[i]) T(*arg_list_begin);
this->buffer_size = count;
}
SmallVector(SmallVector &&other) SPIRV_CROSS_NOEXCEPT : SmallVector()
{
*this = std::move(other);
}
SmallVector &operator=(SmallVector &&other) SPIRV_CROSS_NOEXCEPT
{
clear();
if (other.ptr != other.stack_storage.data())
{
// Pilfer allocated pointer.
if (this->ptr != stack_storage.data())
free(this->ptr);
this->ptr = other.ptr;
this->buffer_size = other.buffer_size;
buffer_capacity = other.buffer_capacity;
other.ptr = nullptr;
other.buffer_size = 0;
other.buffer_capacity = 0;
}
else
{
// Need to move the stack contents individually.
reserve(other.buffer_size);
for (size_t i = 0; i < other.buffer_size; i++)
{
new (&this->ptr[i]) T(std::move(other.ptr[i]));
other.ptr[i].~T();
}
this->buffer_size = other.buffer_size;
other.buffer_size = 0;
}
return *this;
}
SmallVector(const SmallVector &other)
: SmallVector()
{
*this = other;
}
SmallVector &operator=(const SmallVector &other)
{
clear();
reserve(other.buffer_size);
for (size_t i = 0; i < other.buffer_size; i++)
new (&this->ptr[i]) T(other.ptr[i]);
this->buffer_size = other.buffer_size;
return *this;
}
explicit SmallVector(size_t count)
: SmallVector()
{
resize(count);
}
~SmallVector()
{
clear();
if (this->ptr != stack_storage.data())
free(this->ptr);
}
void clear()
{
for (size_t i = 0; i < this->buffer_size; i++)
this->ptr[i].~T();
this->buffer_size = 0;
}
void push_back(const T &t)
{
reserve(this->buffer_size + 1);
new (&this->ptr[this->buffer_size]) T(t);
this->buffer_size++;
}
void push_back(T &&t)
{
reserve(this->buffer_size + 1);
new (&this->ptr[this->buffer_size]) T(std::move(t));
this->buffer_size++;
}
void pop_back()
{
resize(this->buffer_size - 1);
}
template <typename... Ts>
void emplace_back(Ts &&... ts)
{
reserve(this->buffer_size + 1);
new (&this->ptr[this->buffer_size]) T(std::forward<Ts>(ts)...);
this->buffer_size++;
}
void reserve(size_t count)
{
if (count > buffer_capacity)
{
size_t target_capacity = buffer_capacity;
if (target_capacity == 0)
target_capacity = 1;
if (target_capacity < N)
target_capacity = N;
while (target_capacity < count)
target_capacity <<= 1u;
T *new_buffer =
target_capacity > N ? static_cast<T *>(malloc(target_capacity * sizeof(T))) : stack_storage.data();
if (!new_buffer)
SPIRV_CROSS_THROW("Out of memory.");
// In case for some reason two allocations both come from same stack.
if (new_buffer != this->ptr)
{
// We don't deal with types which can throw in move constructor.
for (size_t i = 0; i < this->buffer_size; i++)
{
new (&new_buffer[i]) T(std::move(this->ptr[i]));
this->ptr[i].~T();
}
}
if (this->ptr != stack_storage.data())
free(this->ptr);
this->ptr = new_buffer;
buffer_capacity = target_capacity;
}
}
void insert(T *itr, const T *insert_begin, const T *insert_end)
{
if (itr == this->end())
{
auto count = size_t(insert_end - insert_begin);
reserve(this->buffer_size + count);
for (size_t i = 0; i < count; i++, insert_begin++)
new (&this->ptr[this->buffer_size + i]) T(*insert_begin);
this->buffer_size += count;
}
else
SPIRV_CROSS_THROW("Mid-insert not implemented.");
}
T *erase(T *itr)
{
std::move(itr + 1, this->end(), itr);
this->ptr[--this->buffer_size].~T();
return itr;
}
void erase(T *start_erase, T *end_erase)
{
if (end_erase != this->end())
SPIRV_CROSS_THROW("Mid-erase not implemented.");
resize(size_t(start_erase - this->begin()));
}
void resize(size_t new_size)
{
if (new_size < this->buffer_size)
{
for (size_t i = new_size; i < this->buffer_size; i++)
this->ptr[i].~T();
}
else if (new_size > this->buffer_size)
{
reserve(new_size);
for (size_t i = this->buffer_size; i < new_size; i++)
new (&this->ptr[i]) T();
}
this->buffer_size = new_size;
}
private:
size_t buffer_capacity = 0;
AlignedBuffer<T, N> stack_storage;
};
// A vector without stack storage.
// Could also be a typedef-ed to std::vector,
// but might as well use the one we have.
template <typename T>
using Vector = SmallVector<T, 0>;
// An object pool which we use for allocating IVariant-derived objects.
// We know we are going to allocate a bunch of objects of each type,
// so amortize the mallocs.
class ObjectPoolBase
{
public:
virtual ~ObjectPoolBase() = default;
virtual void free_opaque(void *ptr) = 0;
};
template <typename T>
class ObjectPool : public ObjectPoolBase
{
public:
explicit ObjectPool(unsigned start_object_count_ = 16)
: start_object_count(start_object_count_)
{
}
template <typename... P>
T *allocate(P &&... p)
{
if (vacants.empty())
{
unsigned num_objects = start_object_count << memory.size();
T *ptr = static_cast<T *>(malloc(num_objects * sizeof(T)));
if (!ptr)
return nullptr;
for (unsigned i = 0; i < num_objects; i++)
vacants.push_back(&ptr[i]);
memory.emplace_back(ptr);
}
T *ptr = vacants.back();
vacants.pop_back();
new (ptr) T(std::forward<P>(p)...);
return ptr;
}
void free(T *ptr)
{
ptr->~T();
vacants.push_back(ptr);
}
void free_opaque(void *ptr) override
{
free(static_cast<T *>(ptr));
}
void clear()
{
vacants.clear();
memory.clear();
}
protected:
Vector<T *> vacants;
struct MallocDeleter
{
void operator()(T *ptr)
{
::free(ptr);
}
};
SmallVector<std::unique_ptr<T, MallocDeleter>> memory;
unsigned start_object_count;
};
template <size_t StackSize = 4096, size_t BlockSize = 4096>
class StringStream
{
public:
StringStream()
{
reset();
}
~StringStream()
{
reset();
}
// Disable copies and moves. Makes it easier to implement, and we don't need it.
StringStream(const StringStream &) = delete;
void operator=(const StringStream &) = delete;
template <typename T, typename std::enable_if<!std::is_floating_point<T>::value, int>::type = 0>
StringStream &operator<<(const T &t)
{
auto s = std::to_string(t);
append(s.data(), s.size());
return *this;
}
// Only overload this to make float/double conversions ambiguous.
StringStream &operator<<(uint32_t v)
{
auto s = std::to_string(v);
append(s.data(), s.size());
return *this;
}
StringStream &operator<<(char c)
{
append(&c, 1);
return *this;
}
StringStream &operator<<(const std::string &str)
{
append(str.data(), str.size());
return *this;
}
StringStream &operator<<(const char *s)
{
append(s, strlen(s));
return *this;
}
template <size_t N>
StringStream &operator<<(const char (&s)[N])
{
append(s, strlen(s));
return *this;
}
std::string str() const
{
std::string ret;
size_t target_size = 0;
for (auto &saved : saved_buffers)
target_size += saved.offset;
target_size += current_buffer.offset;
ret.reserve(target_size);
for (auto &saved : saved_buffers)
ret.insert(ret.end(), saved.buffer, saved.buffer + saved.offset);
ret.insert(ret.end(), current_buffer.buffer, current_buffer.buffer + current_buffer.offset);
return ret;
}
void reset()
{
for (auto &saved : saved_buffers)
if (saved.buffer != stack_buffer)
free(saved.buffer);
if (current_buffer.buffer != stack_buffer)
free(current_buffer.buffer);
saved_buffers.clear();
current_buffer.buffer = stack_buffer;
current_buffer.offset = 0;
current_buffer.size = sizeof(stack_buffer);
}
private:
struct Buffer
{
char *buffer;
size_t offset;
size_t size;
};
Buffer current_buffer = {};
char stack_buffer[StackSize];
SmallVector<Buffer> saved_buffers;
void append(const char *str, size_t len)
{
size_t avail = current_buffer.size - current_buffer.offset;
if (avail < len)
{
if (avail > 0)
{
memcpy(current_buffer.buffer + current_buffer.offset, str, avail);
str += avail;
len -= avail;
current_buffer.offset += avail;
}
saved_buffers.push_back(current_buffer);
size_t target_size = len > BlockSize ? len : BlockSize;
current_buffer.buffer = static_cast<char *>(malloc(target_size));
if (!current_buffer.buffer)
SPIRV_CROSS_THROW("Out of memory.");
memcpy(current_buffer.buffer, str, len);
current_buffer.offset = len;
current_buffer.size = target_size;
}
else
{
memcpy(current_buffer.buffer + current_buffer.offset, str, len);
current_buffer.offset += len;
}
}
};
namespace inner
{
template <typename T>
void join_helper(std::ostringstream &stream, T &&t)
void join_helper(StringStream<> &stream, T &&t)
{
stream << std::forward<T>(t);
}
template <typename T, typename... Ts>
void join_helper(std::ostringstream &stream, T &&t, Ts &&... ts)
void join_helper(StringStream<> &stream, T &&t, Ts &&... ts)
{
stream << std::forward<T>(t);
join_helper(stream, std::forward<Ts>(ts)...);
@ -217,7 +743,7 @@ public:
// Need to enforce an order here for reproducible results,
// but hitting this path should happen extremely rarely, so having this slow path is fine.
std::vector<uint32_t> bits;
SmallVector<uint32_t> bits;
bits.reserve(higher.size());
for (auto &v : higher)
bits.push_back(v);
@ -244,21 +770,21 @@ private:
template <typename... Ts>
std::string join(Ts &&... ts)
{
std::ostringstream stream;
StringStream<> stream;
inner::join_helper(stream, std::forward<Ts>(ts)...);
return stream.str();
}
inline std::string merge(const std::vector<std::string> &list)
inline std::string merge(const SmallVector<std::string> &list)
{
std::string s;
StringStream<> stream;
for (auto &elem : list)
{
s += elem;
stream << elem;
if (&elem != &list.back())
s += ", ";
stream << ", ";
}
return s;
return stream.str();
}
// Make sure we don't accidentally call this with float or doubles with SFINAE.
@ -340,15 +866,14 @@ struct Instruction
struct IVariant
{
virtual ~IVariant() = default;
virtual std::unique_ptr<IVariant> clone() = 0;
virtual IVariant *clone(ObjectPoolBase *pool) = 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)); \
#define SPIRV_CROSS_DECLARE_CLONE(T) \
IVariant *clone(ObjectPoolBase *pool) override \
{ \
return static_cast<ObjectPool<T> *>(pool)->allocate(*this); \
}
enum Types
@ -421,7 +946,7 @@ struct SPIRConstantOp : IVariant
}
spv::Op opcode;
std::vector<uint32_t> arguments;
SmallVector<uint32_t> arguments;
uint32_t basetype;
SPIRV_CROSS_DECLARE_CLONE(SPIRConstantOp)
@ -469,14 +994,14 @@ struct SPIRType : IVariant
uint32_t columns = 1;
// Arrays, support array of arrays by having a vector of array sizes.
std::vector<uint32_t> array;
SmallVector<uint32_t> array;
// Array elements can be either specialization constants or specialization ops.
// This array determines how to interpret the array size.
// If an element is true, the element is a literal,
// otherwise, it's an expression, which must be resolved on demand.
// The actual size is not really known until runtime.
std::vector<bool> array_size_literal;
SmallVector<bool> array_size_literal;
// Pointers
// Keep track of how many pointer layers we have.
@ -485,7 +1010,7 @@ struct SPIRType : IVariant
spv::StorageClass storage = spv::StorageClassGeneric;
std::vector<uint32_t> member_types;
SmallVector<uint32_t> member_types;
struct ImageType
{
@ -556,7 +1081,7 @@ struct SPIREntryPoint
uint32_t self = 0;
std::string name;
std::string orig_name;
std::vector<uint32_t> interface_variables;
SmallVector<uint32_t> interface_variables;
Bitset flags;
struct
@ -610,11 +1135,11 @@ struct SPIRExpression : IVariant
bool access_chain = false;
// A list of expressions which this expression depends on.
std::vector<uint32_t> expression_dependencies;
SmallVector<uint32_t> expression_dependencies;
// By reading this expression, we implicitly read these expressions as well.
// Used by access chain Store and Load since we read multiple expressions in this case.
std::vector<uint32_t> implied_read_expressions;
SmallVector<uint32_t> implied_read_expressions;
SPIRV_CROSS_DECLARE_CLONE(SPIRExpression)
};
@ -632,7 +1157,7 @@ struct SPIRFunctionPrototype : IVariant
}
uint32_t return_type;
std::vector<uint32_t> parameter_types;
SmallVector<uint32_t> parameter_types;
SPIRV_CROSS_DECLARE_CLONE(SPIRFunctionPrototype)
};
@ -716,7 +1241,7 @@ struct SPIRBlock : IVariant
uint32_t false_block = 0;
uint32_t default_block = 0;
std::vector<Instruction> ops;
SmallVector<Instruction> ops;
struct Phi
{
@ -726,22 +1251,22 @@ struct SPIRBlock : IVariant
};
// Before entering this block flush out local variables to magical "phi" variables.
std::vector<Phi> phi_variables;
SmallVector<Phi> phi_variables;
// Declare these temporaries before beginning the block.
// Used for handling complex continue blocks which have side effects.
std::vector<std::pair<uint32_t, uint32_t>> declare_temporary;
SmallVector<std::pair<uint32_t, uint32_t>> declare_temporary;
// Declare these temporaries, but only conditionally if this block turns out to be
// a complex loop header.
std::vector<std::pair<uint32_t, uint32_t>> potential_declare_temporary;
SmallVector<std::pair<uint32_t, uint32_t>> potential_declare_temporary;
struct Case
{
uint32_t value;
uint32_t block;
};
std::vector<Case> cases;
SmallVector<Case> cases;
// If we have tried to optimize code for this block but failed,
// keep track of this.
@ -759,17 +1284,17 @@ struct SPIRBlock : IVariant
// All access to these variables are dominated by this block,
// so before branching anywhere we need to make sure that we declare these variables.
std::vector<uint32_t> dominated_variables;
SmallVector<uint32_t> dominated_variables;
// These are variables which should be declared in a for loop header, if we
// fail to use a classic for-loop,
// we remove these variables, and fall back to regular variables outside the loop.
std::vector<uint32_t> loop_variables;
SmallVector<uint32_t> loop_variables;
// Some expressions are control-flow dependent, i.e. any instruction which relies on derivatives or
// sub-group-like operations.
// Make sure that we only use these expressions in the original block.
std::vector<uint32_t> invalidate_expressions;
SmallVector<uint32_t> invalidate_expressions;
SPIRV_CROSS_DECLARE_CLONE(SPIRBlock)
};
@ -822,16 +1347,16 @@ struct SPIRFunction : IVariant
uint32_t return_type;
uint32_t function_type;
std::vector<Parameter> arguments;
SmallVector<Parameter> arguments;
// Can be used by backends to add magic arguments.
// Currently used by combined image/sampler implementation.
std::vector<Parameter> shadow_arguments;
std::vector<uint32_t> local_variables;
SmallVector<Parameter> shadow_arguments;
SmallVector<uint32_t> local_variables;
uint32_t entry_block = 0;
std::vector<uint32_t> blocks;
std::vector<CombinedImageSamplerParameter> combined_parameters;
SmallVector<uint32_t> blocks;
SmallVector<CombinedImageSamplerParameter> combined_parameters;
void add_local_variable(uint32_t id)
{
@ -847,17 +1372,19 @@ struct SPIRFunction : IVariant
// Hooks to be run when the function returns.
// Mostly used for lowering internal data structures onto flattened structures.
// Need to defer this, because they might rely on things which change during compilation.
std::vector<std::function<void()>> fixup_hooks_out;
// Intentionally not a small vector, this one is rare, and std::function can be large.
Vector<std::function<void()>> fixup_hooks_out;
// Hooks to be run when the function begins.
// Mostly used for populating internal data structures from flattened structures.
// Need to defer this, because they might rely on things which change during compilation.
std::vector<std::function<void()>> fixup_hooks_in;
// Intentionally not a small vector, this one is rare, and std::function can be large.
Vector<std::function<void()>> fixup_hooks_in;
// On function entry, make sure to copy a constant array into thread addr space to work around
// the case where we are passing a constant array by value to a function on backends which do not
// consider arrays value types.
std::vector<uint32_t> constant_arrays_needed_on_stack;
SmallVector<uint32_t> constant_arrays_needed_on_stack;
bool active = false;
bool flush_undeclared = true;
@ -901,7 +1428,7 @@ struct SPIRAccessChain : IVariant
// By reading this expression, we implicitly read these expressions as well.
// Used by access chain Store and Load since we read multiple expressions in this case.
std::vector<uint32_t> implied_read_expressions;
SmallVector<uint32_t> implied_read_expressions;
SPIRV_CROSS_DECLARE_CLONE(SPIRAccessChain)
};
@ -928,7 +1455,7 @@ struct SPIRVariable : IVariant
uint32_t initializer = 0;
uint32_t basevariable = 0;
std::vector<uint32_t> dereference_chain;
SmallVector<uint32_t> dereference_chain;
bool compat_builtin = false;
// If a variable is shadowed, we only statically assign to it
@ -939,7 +1466,7 @@ struct SPIRVariable : IVariant
uint32_t static_expression = 0;
// Temporaries which can remain forwarded as long as this variable is not modified.
std::vector<uint32_t> dependees;
SmallVector<uint32_t> dependees;
bool forwardable = true;
bool deferred_declaration = false;
@ -1178,7 +1705,7 @@ struct SPIRConstant : IVariant
: constant_type(constant_type_)
, specialization(specialized)
{
subconstants.insert(end(subconstants), elements, elements + num_elements);
subconstants.insert(std::end(subconstants), elements, elements + num_elements);
specialization = specialized;
}
@ -1247,7 +1774,7 @@ struct SPIRConstant : IVariant
bool is_used_as_lut = false;
// For composites which are constant arrays, etc.
std::vector<uint32_t> subconstants;
SmallVector<uint32_t> subconstants;
// Non-Vulkan GLSL, HLSL and sometimes MSL emits defines for each specialization constant,
// and uses them to initialize the constant. This allows the user
@ -1258,11 +1785,25 @@ struct SPIRConstant : IVariant
SPIRV_CROSS_DECLARE_CLONE(SPIRConstant)
};
// Variants have a very specific allocation scheme.
struct ObjectPoolGroup
{
std::unique_ptr<ObjectPoolBase> pools[TypeCount];
};
class Variant
{
public:
// MSVC 2013 workaround, we shouldn't need these constructors.
Variant() = default;
explicit Variant(ObjectPoolGroup *group_)
: group(group_)
{
}
~Variant()
{
if (holder)
group->pools[type]->free_opaque(holder);
}
// Marking custom move constructor as noexcept is important.
Variant(Variant &&other) SPIRV_CROSS_NOEXCEPT
@ -1270,19 +1811,23 @@ public:
*this = std::move(other);
}
Variant(const Variant &variant)
{
*this = variant;
}
// We cannot copy from other variant without our own pool group.
// Have to explicitly copy.
Variant(const Variant &variant) = delete;
// Marking custom move constructor as noexcept is important.
Variant &operator=(Variant &&other) SPIRV_CROSS_NOEXCEPT
{
if (this != &other)
{
holder = std::move(other.holder);
if (holder)
group->pools[type]->free_opaque(holder);
holder = other.holder;
group = other.group;
type = other.type;
allow_type_rewrite = other.allow_type_rewrite;
other.holder = nullptr;
other.type = TypeNone;
}
return *this;
@ -1298,24 +1843,37 @@ public:
#endif
if (this != &other)
{
holder.reset();
if (holder)
group->pools[type]->free_opaque(holder);
if (other.holder)
holder = other.holder->clone();
holder = other.holder->clone(group->pools[other.type].get());
type = other.type;
allow_type_rewrite = other.allow_type_rewrite;
}
return *this;
}
void set(std::unique_ptr<IVariant> val, Types new_type)
void set(IVariant *val, Types new_type)
{
holder = std::move(val);
if (holder)
group->pools[type]->free_opaque(holder);
holder = val;
if (!allow_type_rewrite && type != TypeNone && type != new_type)
SPIRV_CROSS_THROW("Overwriting a variant with new type.");
type = new_type;
allow_type_rewrite = false;
}
template <typename T, typename... Ts>
T *allocate_and_set(Types new_type, Ts &&... ts)
{
T *val = static_cast<ObjectPool<T> &>(*group->pools[new_type]).allocate(std::forward<Ts>(ts)...);
set(val, new_type);
return val;
}
template <typename T>
T &get()
{
@ -1323,7 +1881,7 @@ public:
SPIRV_CROSS_THROW("nullptr");
if (static_cast<Types>(T::type) != type)
SPIRV_CROSS_THROW("Bad cast");
return *static_cast<T *>(holder.get());
return *static_cast<T *>(holder);
}
template <typename T>
@ -1333,7 +1891,7 @@ public:
SPIRV_CROSS_THROW("nullptr");
if (static_cast<Types>(T::type) != type)
SPIRV_CROSS_THROW("Bad cast");
return *static_cast<const T *>(holder.get());
return *static_cast<const T *>(holder);
}
Types get_type() const
@ -1353,7 +1911,9 @@ public:
void reset()
{
holder.reset();
if (holder)
group->pools[type]->free_opaque(holder);
holder = nullptr;
type = TypeNone;
}
@ -1363,7 +1923,8 @@ public:
}
private:
std::unique_ptr<IVariant> holder;
ObjectPoolGroup *group = nullptr;
IVariant *holder = nullptr;
Types type = TypeNone;
bool allow_type_rewrite = false;
};
@ -1383,9 +1944,7 @@ const T &variant_get(const Variant &var)
template <typename T, typename... P>
T &variant_set(Variant &var, P &&... args)
{
auto uptr = std::unique_ptr<T>(new T(std::forward<P>(args)...));
auto ptr = uptr.get();
var.set(std::move(uptr), static_cast<Types>(T::type));
auto *ptr = var.allocate_and_set<T>(static_cast<Types>(T::type), std::forward<P>(args)...);
return *ptr;
}
@ -1430,7 +1989,9 @@ struct Meta
};
Decoration decoration;
std::vector<Decoration> members;
// Intentionally not a SmallVector. Decoration is large and somewhat rare.
Vector<Decoration> members;
std::unordered_map<uint32_t, uint32_t> decoration_word_offset;
@ -1529,6 +2090,6 @@ static inline bool opcode_is_sign_invariant(spv::Op opcode)
return false;
}
}
} // namespace spirv_cross
} // namespace SPIRV_CROSS_NAMESPACE
#endif

View File

@ -334,7 +334,7 @@ string CompilerCPP::compile()
reset();
// Move constructor for this type is broken on GCC 4.9 ...
buffer = unique_ptr<ostringstream>(new ostringstream());
buffer.reset();
emit_header();
emit_resources();
@ -355,7 +355,7 @@ string CompilerCPP::compile()
// Entry point in CPP is always main() for the time being.
get_entry_point().name = "main";
return buffer->str();
return buffer.str();
}
void CompilerCPP::emit_c_linkage()

View File

@ -19,15 +19,14 @@
#include "spirv_glsl.hpp"
#include <utility>
#include <vector>
namespace SPIRV_CROSS_NAMESPACE
{
class CompilerCPP : public CompilerGLSL
{
public:
explicit CompilerCPP(std::vector<uint32_t> spirv_)
: CompilerGLSL(move(spirv_))
explicit CompilerCPP(SmallVector<uint32_t> spirv_)
: CompilerGLSL(std::move(spirv_))
{
}
@ -75,13 +74,13 @@ private:
std::string argument_decl(const SPIRFunction::Parameter &arg);
std::vector<std::string> resource_registrations;
SmallVector<std::string> resource_registrations;
std::string impl_type;
std::string resource_type;
uint32_t shared_counter = 0;
std::string interface_name;
};
} // namespace spirv_cross
} // namespace SPIRV_CROSS_NAMESPACE
#endif

View File

@ -26,7 +26,7 @@ using namespace std;
using namespace spv;
using namespace SPIRV_CROSS_NAMESPACE;
Compiler::Compiler(vector<uint32_t> ir_)
Compiler::Compiler(SmallVector<uint32_t> ir_)
{
Parser parser(move(ir_));
parser.parse();
@ -1897,9 +1897,9 @@ bool Compiler::BufferAccessHandler::handle(Op opcode, const uint32_t *args, uint
return true;
}
std::vector<BufferRange> Compiler::get_active_buffer_ranges(uint32_t id) const
SmallVector<BufferRange> Compiler::get_active_buffer_ranges(uint32_t id) const
{
std::vector<BufferRange> ranges;
SmallVector<BufferRange> ranges;
BufferAccessHandler handler(*this, ranges, id);
traverse_all_reachable_opcodes(get<SPIRFunction>(ir.default_entry_point), handler);
return ranges;
@ -2126,9 +2126,9 @@ void Compiler::inherit_expression_dependencies(uint32_t dst, uint32_t source_exp
e_deps.erase(unique(begin(e_deps), end(e_deps)), end(e_deps));
}
vector<EntryPoint> Compiler::get_entry_points_and_stages() const
SmallVector<EntryPoint> Compiler::get_entry_points_and_stages() const
{
vector<EntryPoint> entries;
SmallVector<EntryPoint> entries;
for (auto &entry : ir.entry_points)
entries.push_back({ entry.second.orig_name, entry.second.model });
return entries;
@ -2715,9 +2715,9 @@ void Compiler::build_combined_image_samplers()
traverse_all_reachable_opcodes(get<SPIRFunction>(ir.default_entry_point), handler);
}
vector<SpecializationConstant> Compiler::get_specialization_constants() const
SmallVector<SpecializationConstant> Compiler::get_specialization_constants() const
{
vector<SpecializationConstant> spec_consts;
SmallVector<SpecializationConstant> spec_consts;
ir.for_each_typed_id<SPIRConstant>([&](uint32_t, const SPIRConstant &c) {
if (c.specialization && has_decoration(c.self, DecorationSpecId))
spec_consts.push_back({ c.self, get_decoration(c.self, DecorationSpecId) });
@ -3966,7 +3966,7 @@ void Compiler::make_constant_null(uint32_t id, uint32_t type)
if (!constant_type.array_size_literal.back())
SPIRV_CROSS_THROW("Array size of OpConstantNull must be a literal.");
vector<uint32_t> elements(constant_type.array.back());
SmallVector<uint32_t> elements(constant_type.array.back());
for (uint32_t i = 0; i < constant_type.array.back(); i++)
elements[i] = parent_id;
set<SPIRConstant>(id, type, elements.data(), uint32_t(elements.size()), false);
@ -3974,7 +3974,7 @@ void Compiler::make_constant_null(uint32_t id, uint32_t type)
else if (!constant_type.member_types.empty())
{
uint32_t member_ids = ir.increase_bound_by(uint32_t(constant_type.member_types.size()));
vector<uint32_t> elements(constant_type.member_types.size());
SmallVector<uint32_t> elements(constant_type.member_types.size());
for (uint32_t i = 0; i < constant_type.member_types.size(); i++)
{
make_constant_null(member_ids + i, constant_type.member_types[i]);
@ -3989,12 +3989,12 @@ void Compiler::make_constant_null(uint32_t id, uint32_t type)
}
}
const std::vector<spv::Capability> &Compiler::get_declared_capabilities() const
const SmallVector<spv::Capability> &Compiler::get_declared_capabilities() const
{
return ir.declared_capabilities;
}
const std::vector<std::string> &Compiler::get_declared_extensions() const
const SmallVector<std::string> &Compiler::get_declared_extensions() const
{
return ir.declared_extensions;
}

View File

@ -54,24 +54,24 @@ struct Resource
struct ShaderResources
{
std::vector<Resource> uniform_buffers;
std::vector<Resource> storage_buffers;
std::vector<Resource> stage_inputs;
std::vector<Resource> stage_outputs;
std::vector<Resource> subpass_inputs;
std::vector<Resource> storage_images;
std::vector<Resource> sampled_images;
std::vector<Resource> atomic_counters;
std::vector<Resource> acceleration_structures;
SmallVector<Resource> uniform_buffers;
SmallVector<Resource> storage_buffers;
SmallVector<Resource> stage_inputs;
SmallVector<Resource> stage_outputs;
SmallVector<Resource> subpass_inputs;
SmallVector<Resource> storage_images;
SmallVector<Resource> sampled_images;
SmallVector<Resource> atomic_counters;
SmallVector<Resource> acceleration_structures;
// There can only be one push constant block,
// but keep the vector in case this restriction is lifted in the future.
std::vector<Resource> push_constant_buffers;
SmallVector<Resource> push_constant_buffers;
// For Vulkan GLSL and HLSL source,
// these correspond to separate texture2D and samplers respectively.
std::vector<Resource> separate_images;
std::vector<Resource> separate_samplers;
SmallVector<Resource> separate_images;
SmallVector<Resource> separate_samplers;
};
struct CombinedImageSampler
@ -133,7 +133,7 @@ public:
// The constructor takes a buffer of SPIR-V words and parses it.
// 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);
explicit Compiler(SmallVector<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.
@ -235,7 +235,7 @@ public:
// SPIR-V shader. The granularity of this analysis is per-member of a struct.
// This can be used for Buffer (UBO), BufferBlock/StorageBuffer (SSBO) and PushConstant blocks.
// ID is the Resource::id obtained from get_shader_resources().
std::vector<BufferRange> get_active_buffer_ranges(uint32_t id) const;
SmallVector<BufferRange> get_active_buffer_ranges(uint32_t id) const;
// Returns the effective size of a buffer block.
size_t get_declared_struct_size(const SPIRType &struct_type) const;
@ -308,7 +308,7 @@ public:
// New variants of entry point query and reflection.
// Names for entry points in the SPIR-V module may alias if they belong to different execution models.
// To disambiguate, we must pass along with the entry point names the execution model.
std::vector<EntryPoint> get_entry_points_and_stages() const;
SmallVector<EntryPoint> get_entry_points_and_stages() const;
void set_entry_point(const std::string &entry, spv::ExecutionModel execution_model);
// Renames an entry point from old_name to new_name.
@ -392,7 +392,7 @@ public:
void build_combined_image_samplers();
// Gets a remapping for the combined image samplers.
const std::vector<CombinedImageSampler> &get_combined_image_samplers() const
const SmallVector<CombinedImageSampler> &get_combined_image_samplers() const
{
return combined_image_samplers;
}
@ -417,7 +417,7 @@ public:
// For composite types, the subconstants can be iterated over and modified.
// constant_type is the SPIRType for the specialization constant,
// which can be queried to determine which fields in the unions should be poked at.
std::vector<SpecializationConstant> get_specialization_constants() const;
SmallVector<SpecializationConstant> get_specialization_constants() const;
SPIRConstant &get_constant(uint32_t id);
const SPIRConstant &get_constant(uint32_t id) const;
@ -468,10 +468,10 @@ public:
bool buffer_get_hlsl_counter_buffer(uint32_t id, uint32_t &counter_id) const;
// Gets the list of all SPIR-V Capabilities which were declared in the SPIR-V module.
const std::vector<spv::Capability> &get_declared_capabilities() const;
const SmallVector<spv::Capability> &get_declared_capabilities() const;
// Gets the list of all SPIR-V extensions which were declared in the SPIR-V module.
const std::vector<std::string> &get_declared_extensions() const;
const SmallVector<std::string> &get_declared_extensions() const;
// When declaring buffer blocks in GLSL, the name declared in the GLSL source
// might not be the same as the name declared in the SPIR-V module due to naming conflicts.
@ -511,8 +511,8 @@ protected:
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;
SmallVector<uint32_t> global_variables;
SmallVector<uint32_t> aliased_variables;
SPIRFunction *current_function = nullptr;
SPIRBlock *current_block = nullptr;
@ -686,7 +686,7 @@ protected:
// variable is part of that entry points interface.
bool interface_variable_exists_in_entry_point(uint32_t id) const;
std::vector<CombinedImageSampler> combined_image_samplers;
SmallVector<CombinedImageSampler> combined_image_samplers;
void remap_variable_type_name(const SPIRType &type, const std::string &var_name, std::string &type_name) const
{
@ -729,7 +729,7 @@ protected:
struct BufferAccessHandler : OpcodeHandler
{
BufferAccessHandler(const Compiler &compiler_, std::vector<BufferRange> &ranges_, uint32_t id_)
BufferAccessHandler(const Compiler &compiler_, SmallVector<BufferRange> &ranges_, uint32_t id_)
: compiler(compiler_)
, ranges(ranges_)
, id(id_)
@ -739,7 +739,7 @@ protected:
bool handle(spv::Op opcode, const uint32_t *args, uint32_t length) override;
const Compiler &compiler;
std::vector<BufferRange> &ranges;
SmallVector<BufferRange> &ranges;
uint32_t id;
std::unordered_set<uint32_t> seen;
@ -810,7 +810,7 @@ protected:
bool traverse_all_reachable_opcodes(const SPIRBlock &block, OpcodeHandler &handler) const;
bool traverse_all_reachable_opcodes(const SPIRFunction &block, OpcodeHandler &handler) const;
// This must be an ordered data structure so we always pick the same type aliases.
std::vector<uint32_t> global_struct_cache;
SmallVector<uint32_t> global_struct_cache;
ShaderResources get_shader_resources(const std::unordered_set<uint32_t> *active_variables) const;
@ -967,6 +967,6 @@ private:
bool type_is_block_like(const SPIRType &type) const;
bool type_is_opaque_value(const SPIRType &type) const;
};
} // namespace spirv_cross
} // namespace SPIRV_CROSS_NAMESPACE
#endif

View File

@ -34,9 +34,9 @@
#include "spirv_reflect.hpp"
#endif
#include "spirv_parser.hpp"
#include <string.h>
#include <memory>
#include <new>
#include <string.h>
// clang-format off
@ -88,7 +88,7 @@ struct StringAllocation : ScratchMemoryAllocation
template <typename T>
struct TemporaryBuffer : ScratchMemoryAllocation
{
std::vector<T> buffer;
SmallVector<T> buffer;
};
template <typename T, typename... Ts>
@ -100,7 +100,7 @@ static inline std::unique_ptr<T> spvc_allocate(Ts &&... ts)
struct spvc_context_s
{
string last_error;
vector<unique_ptr<ScratchMemoryAllocation>> allocations;
SmallVector<unique_ptr<ScratchMemoryAllocation>> allocations;
const char *allocate_name(const std::string &name);
spvc_error_callback callback = nullptr;
@ -173,20 +173,20 @@ struct spvc_constant_s : SPIRConstant
struct spvc_resources_s : ScratchMemoryAllocation
{
spvc_context context = nullptr;
std::vector<spvc_reflected_resource> uniform_buffers;
std::vector<spvc_reflected_resource> storage_buffers;
std::vector<spvc_reflected_resource> stage_inputs;
std::vector<spvc_reflected_resource> stage_outputs;
std::vector<spvc_reflected_resource> subpass_inputs;
std::vector<spvc_reflected_resource> storage_images;
std::vector<spvc_reflected_resource> sampled_images;
std::vector<spvc_reflected_resource> atomic_counters;
std::vector<spvc_reflected_resource> push_constant_buffers;
std::vector<spvc_reflected_resource> separate_images;
std::vector<spvc_reflected_resource> separate_samplers;
std::vector<spvc_reflected_resource> acceleration_structures;
SmallVector<spvc_reflected_resource> uniform_buffers;
SmallVector<spvc_reflected_resource> storage_buffers;
SmallVector<spvc_reflected_resource> stage_inputs;
SmallVector<spvc_reflected_resource> stage_outputs;
SmallVector<spvc_reflected_resource> subpass_inputs;
SmallVector<spvc_reflected_resource> storage_images;
SmallVector<spvc_reflected_resource> sampled_images;
SmallVector<spvc_reflected_resource> atomic_counters;
SmallVector<spvc_reflected_resource> push_constant_buffers;
SmallVector<spvc_reflected_resource> separate_images;
SmallVector<spvc_reflected_resource> separate_samplers;
SmallVector<spvc_reflected_resource> acceleration_structures;
bool copy_resources(std::vector<spvc_reflected_resource> &outputs, const std::vector<Resource> &inputs);
bool copy_resources(SmallVector<spvc_reflected_resource> &outputs, const SmallVector<Resource> &inputs);
bool copy_resources(const ShaderResources &resources);
};
@ -634,7 +634,7 @@ spvc_result spvc_compiler_hlsl_set_root_constants_layout(spvc_compiler compiler,
}
auto &hlsl = *static_cast<CompilerHLSL *>(compiler->compiler.get());
std::vector<RootConstants> roots;
SmallVector<RootConstants> roots;
roots.reserve(count);
for (size_t i = 0; i < count; i++)
{
@ -980,8 +980,8 @@ spvc_result spvc_compiler_compile(spvc_compiler compiler, const char **source)
SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_UNSUPPORTED_SPIRV)
}
bool spvc_resources_s::copy_resources(std::vector<spvc_reflected_resource> &outputs,
const std::vector<Resource> &inputs)
bool spvc_resources_s::copy_resources(SmallVector<spvc_reflected_resource> &outputs,
const SmallVector<Resource> &inputs)
{
for (auto &i : inputs)
{
@ -1117,7 +1117,7 @@ spvc_result spvc_resources_get_resource_list_for_type(spvc_resources resources,
const spvc_reflected_resource **resource_list,
size_t *resource_size)
{
const std::vector<spvc_reflected_resource> *list = nullptr;
const SmallVector<spvc_reflected_resource> *list = nullptr;
switch (type)
{
case SPVC_RESOURCE_TYPE_UNIFORM_BUFFER:
@ -1275,7 +1275,7 @@ spvc_result spvc_compiler_get_entry_points(spvc_compiler compiler, const spvc_en
SPVC_BEGIN_SAFE_SCOPE
{
auto entries = compiler->compiler->get_entry_points_and_stages();
std::vector<spvc_entry_point> translated;
SmallVector<spvc_entry_point> translated;
translated.reserve(entries.size());
for (auto &entry : entries)
@ -1406,7 +1406,7 @@ unsigned spvc_type_get_bit_width(spvc_type type)
return type->width;
}
unsigned spvc_type_get_vector_size(spvc_type type)
unsigned spvc_type_get_SmallVector_size(spvc_type type)
{
return type->vecsize;
}
@ -1566,7 +1566,7 @@ spvc_result spvc_compiler_get_combined_image_samplers(spvc_compiler compiler,
SPVC_BEGIN_SAFE_SCOPE
{
auto combined = compiler->compiler->get_combined_image_samplers();
std::vector<spvc_combined_image_sampler> translated;
SmallVector<spvc_combined_image_sampler> translated;
translated.reserve(combined.size());
for (auto &c : combined)
{
@ -1591,7 +1591,7 @@ spvc_result spvc_compiler_get_specialization_constants(spvc_compiler compiler,
SPVC_BEGIN_SAFE_SCOPE
{
auto spec_constants = compiler->compiler->get_specialization_constants();
std::vector<spvc_specialization_constant> translated;
SmallVector<spvc_specialization_constant> translated;
translated.reserve(spec_constants.size());
for (auto &c : spec_constants)
{
@ -1743,7 +1743,7 @@ spvc_result spvc_compiler_get_declared_extensions(spvc_compiler compiler, const
SPVC_BEGIN_SAFE_SCOPE
{
auto &exts = compiler->compiler->get_declared_extensions();
std::vector<const char *> duped;
SmallVector<const char *> duped;
duped.reserve(exts.size());
for (auto &ext : exts)
duped.push_back(compiler->context->allocate_name(ext));

View File

@ -23,9 +23,70 @@ using namespace spv;
namespace SPIRV_CROSS_NAMESPACE
{
ParsedIR::ParsedIR()
{
// If we move ParsedIR, we need to make sure the pointer stays fixed since the child Variant objects consume a pointer to this group,
// so need an extra pointer here.
pool_group.reset(new ObjectPoolGroup);
pool_group->pools[TypeType].reset(new ObjectPool<SPIRType>);
pool_group->pools[TypeVariable].reset(new ObjectPool<SPIRVariable>);
pool_group->pools[TypeConstant].reset(new ObjectPool<SPIRConstant>);
pool_group->pools[TypeFunction].reset(new ObjectPool<SPIRFunction>);
pool_group->pools[TypeFunctionPrototype].reset(new ObjectPool<SPIRFunctionPrototype>);
pool_group->pools[TypeBlock].reset(new ObjectPool<SPIRBlock>);
pool_group->pools[TypeExtension].reset(new ObjectPool<SPIRExtension>);
pool_group->pools[TypeExpression].reset(new ObjectPool<SPIRExpression>);
pool_group->pools[TypeConstantOp].reset(new ObjectPool<SPIRConstantOp>);
pool_group->pools[TypeCombinedImageSampler].reset(new ObjectPool<SPIRCombinedImageSampler>);
pool_group->pools[TypeAccessChain].reset(new ObjectPool<SPIRAccessChain>);
pool_group->pools[TypeUndef].reset(new ObjectPool<SPIRUndef>);
}
ParsedIR::ParsedIR(const ParsedIR &other)
: ParsedIR()
{
*this = other;
}
ParsedIR &ParsedIR::operator=(const ParsedIR &other)
{
if (this != &other)
{
spirv = other.spirv;
meta = other.meta;
for (int i = 0; i < TypeCount; i++)
ids_for_type[i] = other.ids_for_type[i];
ids_for_constant_or_type = other.ids_for_constant_or_type;
ids_for_constant_or_variable = other.ids_for_constant_or_variable;
declared_capabilities = other.declared_capabilities;
declared_extensions = other.declared_extensions;
block_meta = other.block_meta;
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;
loop_iteration_depth = other.loop_iteration_depth;
// Very deliberate copying of IDs. There is no default copy constructor, nor a simple default constructor.
// Construct object first so we have the correct allocator set-up, then we can copy object into our new pool group.
ids.clear();
ids.reserve(other.ids.size());
for (size_t i = 0; i < other.ids.size(); i++)
{
ids.emplace_back(pool_group.get());
ids.back() = other.ids[i];
}
}
return *this;
}
void ParsedIR::set_id_bounds(uint32_t bounds)
{
ids.resize(bounds);
ids.reserve(bounds);
while (ids.size() < bounds)
ids.emplace_back(pool_group.get());
block_meta.resize(bounds);
}
@ -571,7 +632,11 @@ uint32_t ParsedIR::increase_bound_by(uint32_t incr_amount)
{
auto curr_bound = ids.size();
auto new_bound = curr_bound + incr_amount;
ids.resize(new_bound);
ids.reserve(ids.size() + incr_amount);
for (uint32_t i = 0; i < incr_amount; i++)
ids.emplace_back(pool_group.get());
block_meta.resize(new_bound);
return uint32_t(curr_bound);
}
@ -645,4 +710,4 @@ Meta *ParsedIR::find_meta(uint32_t id)
return nullptr;
}
} // namespace spirv_cross
} // namespace SPIRV_CROSS_NAMESPACE

View File

@ -20,7 +20,6 @@
#include "spirv_common.hpp"
#include <stdint.h>
#include <unordered_map>
#include <vector>
namespace SPIRV_CROSS_NAMESPACE
{
@ -32,15 +31,29 @@ namespace SPIRV_CROSS_NAMESPACE
class ParsedIR
{
private:
// This must be destroyed after the "ids" vector.
std::unique_ptr<ObjectPoolGroup> pool_group;
public:
ParsedIR();
// Due to custom allocations from object pools, we cannot use a default copy constructor.
ParsedIR(const ParsedIR &other);
ParsedIR &operator=(const ParsedIR &other);
// Moves are unproblematic.
ParsedIR(ParsedIR &&other) = default;
ParsedIR &operator=(ParsedIR &&other) = default;
// Resizes ids, meta and block_meta.
void set_id_bounds(uint32_t bounds);
// The raw SPIR-V, instructions and opcodes refer to this by offset + count.
std::vector<uint32_t> spirv;
SmallVector<uint32_t> spirv;
// Holds various data structures which inherit from IVariant.
std::vector<Variant> ids;
SmallVector<Variant> ids;
// Various meta data for IDs, decorations, names, etc.
std::unordered_map<uint32_t, Meta> meta;
@ -48,19 +61,19 @@ public:
// Holds all IDs which have a certain type.
// This is needed so we can iterate through a specific kind of resource quickly,
// and in-order of module declaration.
std::vector<uint32_t> ids_for_type[TypeCount];
SmallVector<uint32_t> ids_for_type[TypeCount];
// Special purpose lists which contain a union of types.
// This is needed so we can declare specialization constants and structs in an interleaved fashion,
// among other things.
// Constants can be of struct type, and struct array sizes can use specialization constants.
std::vector<uint32_t> ids_for_constant_or_type;
std::vector<uint32_t> ids_for_constant_or_variable;
SmallVector<uint32_t> ids_for_constant_or_type;
SmallVector<uint32_t> ids_for_constant_or_variable;
// Declared capabilities and extensions in the SPIR-V module.
// Not really used except for reflection at the moment.
std::vector<spv::Capability> declared_capabilities;
std::vector<std::string> declared_extensions;
SmallVector<spv::Capability> declared_capabilities;
SmallVector<std::string> declared_extensions;
// Meta data about blocks. The cross-compiler needs to query if a block is either of these types.
// It is a bitset as there can be more than one tag per block.
@ -73,7 +86,7 @@ public:
BLOCK_META_MULTISELECT_MERGE_BIT = 1 << 4
};
using BlockMetaFlags = uint8_t;
std::vector<BlockMetaFlags> block_meta;
SmallVector<BlockMetaFlags> block_meta;
std::unordered_map<uint32_t, uint32_t> continue_block_to_loop_header;
// Normally, we'd stick SPIREntryPoint in ids array, but it conflicts with SPIRFunction.
@ -181,6 +194,6 @@ private:
std::string empty_string;
Bitset cleared_bitset;
};
} // namespace spirv_cross
} // namespace SPIRV_CROSS_NAMESPACE
#endif

View File

@ -22,8 +22,8 @@ using namespace SPIRV_CROSS_NAMESPACE;
namespace spirv_cross_util
{
void rename_interface_variable(Compiler &compiler, const std::vector<Resource> &resources,
uint32_t location, const std::string &name)
void rename_interface_variable(Compiler &compiler, const SmallVector<Resource> &resources, uint32_t location,
const std::string &name)
{
for (auto &v : resources)
{

View File

@ -21,7 +21,8 @@
namespace spirv_cross_util
{
void rename_interface_variable(SPIRV_CROSS_NAMESPACE::Compiler &compiler, const std::vector<SPIRV_CROSS_NAMESPACE::Resource> &resources,
void rename_interface_variable(SPIRV_CROSS_NAMESPACE::Compiler &compiler,
const SPIRV_CROSS_NAMESPACE::SmallVector<SPIRV_CROSS_NAMESPACE::Resource> &resources,
uint32_t location, const std::string &name);
void inherit_combined_sampler_bindings(SPIRV_CROSS_NAMESPACE::Compiler &compiler);
} // namespace spirv_cross_util

View File

@ -454,8 +454,7 @@ string CompilerGLSL::compile()
reset();
// Move constructor for this type is broken on GCC 4.9 ...
buffer = unique_ptr<ostringstream>(new ostringstream());
buffer.reset();
emit_header();
emit_resources();
@ -468,15 +467,15 @@ string CompilerGLSL::compile()
// Entry point in GLSL is always main().
get_entry_point().name = "main";
return buffer->str();
return buffer.str();
}
std::string CompilerGLSL::get_partial_source()
{
return buffer ? buffer->str() : "No compiled source available yet.";
return buffer.str();
}
void CompilerGLSL::build_workgroup_size(vector<string> &arguments, const SpecializationConstant &wg_x,
void CompilerGLSL::build_workgroup_size(SmallVector<string> &arguments, const SpecializationConstant &wg_x,
const SpecializationConstant &wg_y, const SpecializationConstant &wg_z)
{
auto &execution = get_entry_point();
@ -573,8 +572,8 @@ void CompilerGLSL::emit_header()
for (auto &header : header_lines)
statement(header);
vector<string> inputs;
vector<string> outputs;
SmallVector<string> inputs;
SmallVector<string> outputs;
switch (execution.model)
{
@ -798,7 +797,7 @@ string CompilerGLSL::layout_for_member(const SPIRType &type, uint32_t index)
return "";
auto &dec = memb[index];
vector<string> attr;
SmallVector<string> attr;
// We can only apply layouts on members in block interfaces.
// This is a bit problematic because in SPIR-V decorations are applied on the struct types directly.
@ -1294,7 +1293,7 @@ string CompilerGLSL::layout_for_variable(const SPIRVariable &var)
if (is_legacy())
return "";
vector<string> attr;
SmallVector<string> attr;
auto &dec = ir.meta[var.self].decoration;
auto &type = get<SPIRType>(var.basetype);
@ -2325,7 +2324,7 @@ void CompilerGLSL::emit_resources()
if ((wg_x.id != 0) || (wg_y.id != 0) || (wg_z.id != 0))
{
vector<string> inputs;
SmallVector<string> inputs;
build_workgroup_size(inputs, wg_x, wg_y, wg_z);
statement("layout(", merge(inputs), ") in;");
statement("");
@ -3825,7 +3824,8 @@ void CompilerGLSL::emit_unary_func_op_cast(uint32_t result_type, uint32_t result
auto &out_type = get<SPIRType>(result_type);
auto expected_type = out_type;
expected_type.basetype = input_type;
string cast_op = expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_expression(op0);
string cast_op =
expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_expression(op0);
string expr;
if (out_type.basetype != expected_result_type)
@ -3845,17 +3845,18 @@ void CompilerGLSL::emit_unary_func_op_cast(uint32_t result_type, uint32_t result
inherit_expression_dependencies(result_id, op0);
}
void CompilerGLSL::emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id,
uint32_t op0, uint32_t op1, uint32_t op2,
const char *op,
SPIRType::BaseType input_type)
void CompilerGLSL::emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1,
uint32_t op2, const char *op, SPIRType::BaseType input_type)
{
auto &out_type = get<SPIRType>(result_type);
auto expected_type = out_type;
expected_type.basetype = input_type;
string cast_op0 = expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_expression(op0);
string cast_op1 = expression_type(op1).basetype != input_type ? bitcast_glsl(expected_type, op1) : to_expression(op1);
string cast_op2 = expression_type(op2).basetype != input_type ? bitcast_glsl(expected_type, op2) : to_expression(op2);
string cast_op0 =
expression_type(op0).basetype != input_type ? bitcast_glsl(expected_type, op0) : to_expression(op0);
string cast_op1 =
expression_type(op1).basetype != input_type ? bitcast_glsl(expected_type, op1) : to_expression(op1);
string cast_op2 =
expression_type(op2).basetype != input_type ? bitcast_glsl(expected_type, op2) : to_expression(op2);
string expr;
if (out_type.basetype != input_type)
@ -4311,7 +4312,7 @@ void CompilerGLSL::emit_texture_op(const Instruction &i)
auto op = static_cast<Op>(i.op);
uint32_t length = i.length;
vector<uint32_t> inherited_expressions;
SmallVector<uint32_t> inherited_expressions;
uint32_t result_type = ops[0];
uint32_t id = ops[1];
@ -5096,7 +5097,8 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop,
break;
case GLSLstd450FindUMsb:
emit_unary_func_op_cast(result_type, id, args[0], "findMSB", uint_type, int_type); // findMSB always returns int.
emit_unary_func_op_cast(result_type, id, args[0], "findMSB", uint_type,
int_type); // findMSB always returns int.
break;
// Multisampled varying
@ -7341,7 +7343,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
register_impure_function_call();
string funexpr;
vector<string> arglist;
SmallVector<string> arglist;
funexpr += to_name(func) + "(";
if (emit_return_value_as_argument)
@ -7704,7 +7706,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
trivial_forward = !expression_is_forwarded(vec0) && !expression_is_forwarded(vec1);
// Constructor style and shuffling from two different vectors.
vector<string> args;
SmallVector<string> args;
for (uint32_t i = 0; i < length; i++)
{
if (elems[i] == 0xffffffffu)
@ -9250,7 +9252,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction)
// access to shader input content from within a function (eg. Metal). Each additional
// function args uses the name of the global variable. Function nesting will modify the
// functions and function calls all the way up the nesting chain.
void CompilerGLSL::append_global_func_args(const SPIRFunction &func, uint32_t index, vector<string> &arglist)
void CompilerGLSL::append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector<string> &arglist)
{
auto &args = func.arguments;
uint32_t arg_cnt = uint32_t(args.size());
@ -10085,7 +10087,7 @@ void CompilerGLSL::emit_function_prototype(SPIRFunction &func, const Bitset &ret
decl += to_name(func.self);
decl += "(";
vector<string> arglist;
SmallVector<string> arglist;
for (auto &arg : func.arguments)
{
// Do not pass in separate images or samplers if we're remapping
@ -10543,7 +10545,7 @@ string CompilerGLSL::emit_continue_block(uint32_t continue_block, bool follow_tr
// if we have to emit temporaries.
current_continue_block = block;
vector<string> statements;
SmallVector<string> statements;
// Capture all statements into our list.
auto *old = redirect_statement;
@ -10866,7 +10868,7 @@ void CompilerGLSL::flush_undeclared_variables(SPIRBlock &block)
flush_variable_declaration(v);
}
void CompilerGLSL::emit_hoisted_temporaries(vector<pair<uint32_t, uint32_t>> &temporaries)
void CompilerGLSL::emit_hoisted_temporaries(SmallVector<pair<uint32_t, uint32_t>> &temporaries)
{
// If we need to force temporaries for certain IDs due to continue blocks, do it before starting loop header.
// Need to sort these to ensure that reference output is stable.
@ -11416,8 +11418,7 @@ void CompilerGLSL::unroll_array_from_complex_load(uint32_t target_id, uint32_t s
}
}
void CompilerGLSL::bitcast_from_builtin_load(uint32_t source_id, std::string &expr,
const SPIRType &expr_type)
void CompilerGLSL::bitcast_from_builtin_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type)
{
auto *var = maybe_get_backing_variable(source_id);
if (var)
@ -11464,8 +11465,7 @@ void CompilerGLSL::bitcast_from_builtin_load(uint32_t source_id, std::string &ex
expr = bitcast_expression(expr_type, expected_type, expr);
}
void CompilerGLSL::bitcast_to_builtin_store(uint32_t target_id, std::string &expr,
const SPIRType &expr_type)
void CompilerGLSL::bitcast_to_builtin_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type)
{
// Only interested in standalone builtin variables.
if (!has_decoration(target_id, DecorationBuiltIn))

View File

@ -17,9 +17,8 @@
#ifndef SPIRV_CROSS_GLSL_HPP
#define SPIRV_CROSS_GLSL_HPP
#include "spirv_cross.hpp"
#include "GLSL.std.450.h"
#include <sstream>
#include "spirv_cross.hpp"
#include <unordered_map>
#include <unordered_set>
#include <utility>
@ -134,15 +133,15 @@ public:
} fragment;
};
void remap_pixel_local_storage(std::vector<PlsRemap> inputs, std::vector<PlsRemap> outputs)
void remap_pixel_local_storage(SmallVector<PlsRemap> inputs, SmallVector<PlsRemap> outputs)
{
pls_inputs = std::move(inputs);
pls_outputs = std::move(outputs);
remap_pls_variables();
}
explicit CompilerGLSL(std::vector<uint32_t> spirv_)
: Compiler(move(spirv_))
explicit CompilerGLSL(SmallVector<uint32_t> spirv_)
: Compiler(std::move(spirv_))
{
init();
}
@ -230,7 +229,7 @@ protected:
virtual void emit_spv_amd_gcn_shader_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args,
uint32_t count);
virtual void emit_header();
void build_workgroup_size(std::vector<std::string> &arguments, const SpecializationConstant &x,
void build_workgroup_size(SmallVector<std::string> &arguments, const SpecializationConstant &x,
const SpecializationConstant &y, const SpecializationConstant &z);
virtual void emit_sampled_image_op(uint32_t result_type, uint32_t result_id, uint32_t image_id, uint32_t samp_id);
@ -260,19 +259,19 @@ protected:
virtual void emit_uniform(const SPIRVariable &var);
virtual std::string unpack_expression_type(std::string expr_str, const SPIRType &type, uint32_t packed_type_id);
std::unique_ptr<std::ostringstream> buffer;
StringStream<> buffer;
template <typename T>
inline void statement_inner(T &&t)
{
(*buffer) << std::forward<T>(t);
buffer << std::forward<T>(t);
statement_count++;
}
template <typename T, typename... Ts>
inline void statement_inner(T &&t, Ts &&... ts)
{
(*buffer) << std::forward<T>(t);
buffer << std::forward<T>(t);
statement_count++;
statement_inner(std::forward<Ts>(ts)...);
}
@ -296,9 +295,9 @@ protected:
else
{
for (uint32_t i = 0; i < indent; i++)
(*buffer) << " ";
buffer << " ";
statement_inner(std::forward<Ts>(ts)...);
(*buffer) << '\n';
buffer << '\n';
}
}
@ -314,7 +313,7 @@ protected:
// Used for implementing continue blocks where
// we want to obtain a list of statements we can merge
// on a single line separated by comma.
std::vector<std::string> *redirect_statement = nullptr;
SmallVector<std::string> *redirect_statement = nullptr;
const SPIRBlock *current_continue_block = nullptr;
void begin_scope();
@ -406,7 +405,7 @@ protected:
void emit_interface_block(const SPIRVariable &type);
void emit_flattened_io_block(const SPIRVariable &var, const char *qual);
void emit_block_chain(SPIRBlock &block);
void emit_hoisted_temporaries(std::vector<std::pair<uint32_t, uint32_t>> &temporaries);
void emit_hoisted_temporaries(SmallVector<std::pair<uint32_t, uint32_t>> &temporaries);
std::string constant_value_macro_name(uint32_t id);
void emit_constant(const SPIRConstant &constant);
void emit_specialization_constant_op(const SPIRConstantOp &constant);
@ -437,8 +436,8 @@ protected:
SPIRType::BaseType input_type, SPIRType::BaseType expected_result_type);
void emit_binary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op,
SPIRType::BaseType input_type, bool skip_cast_if_equal_type);
void emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2, const char *op,
SPIRType::BaseType input_type);
void emit_trinary_func_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2,
const char *op, SPIRType::BaseType input_type);
void emit_unary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op);
void emit_unrolled_unary_op(uint32_t result_type, uint32_t result_id, uint32_t operand, const char *op);
@ -486,7 +485,7 @@ protected:
std::string declare_temporary(uint32_t type, uint32_t id);
void emit_uninitialized_temporary(uint32_t type, uint32_t id);
SPIRExpression &emit_uninitialized_temporary_expression(uint32_t type, uint32_t id);
void append_global_func_args(const SPIRFunction &func, uint32_t index, std::vector<std::string> &arglist);
void append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector<std::string> &arglist);
std::string to_expression(uint32_t id, bool register_expression_read = true);
std::string to_enclosed_expression(uint32_t id, bool register_expression_read = true);
std::string to_unpacked_expression(uint32_t id, bool register_expression_read = true);
@ -562,8 +561,8 @@ protected:
std::unordered_map<uint32_t, uint32_t> expression_usage_counts;
void track_expression_read(uint32_t id);
std::vector<std::string> forced_extensions;
std::vector<std::string> header_lines;
SmallVector<std::string> forced_extensions;
SmallVector<std::string> header_lines;
// Used when expressions emit extra opcodes with their own unique IDs,
// and we need to reuse the IDs across recompilation loops.
@ -593,8 +592,8 @@ protected:
void register_control_dependent_expression(uint32_t expr);
// GL_EXT_shader_pixel_local_storage support.
std::vector<PlsRemap> pls_inputs;
std::vector<PlsRemap> pls_outputs;
SmallVector<PlsRemap> pls_inputs;
SmallVector<PlsRemap> pls_outputs;
std::string pls_decl(const PlsRemap &variable);
const char *to_pls_qualifiers_glsl(const SPIRVariable &variable);
void emit_pls();
@ -655,6 +654,6 @@ protected:
private:
void init();
};
} // namespace spirv_cross
} // namespace SPIRV_CROSS_NAMESPACE
#endif

View File

@ -1210,8 +1210,8 @@ void CompilerHLSL::emit_resources()
require_output = false;
unordered_set<uint32_t> active_inputs;
unordered_set<uint32_t> active_outputs;
vector<SPIRVariable *> input_variables;
vector<SPIRVariable *> output_variables;
SmallVector<SPIRVariable *> input_variables;
SmallVector<SPIRVariable *> output_variables;
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
auto &type = this->get<SPIRType>(var.basetype);
bool block = ir.meta[type.self].decoration.decoration_flags.get(DecorationBlock);
@ -2024,7 +2024,7 @@ void CompilerHLSL::emit_function_prototype(SPIRFunction &func, const Bitset &ret
decl += to_name(func.self);
decl += "(";
vector<string> arglist;
SmallVector<string> arglist;
if (!type.array.empty())
{
@ -2092,7 +2092,7 @@ void CompilerHLSL::emit_function_prototype(SPIRFunction &func, const Bitset &ret
void CompilerHLSL::emit_hlsl_entry_point()
{
vector<string> arguments;
SmallVector<string> arguments;
if (require_input)
arguments.push_back("SPIRV_Cross_Input stage_input");
@ -2425,7 +2425,7 @@ void CompilerHLSL::emit_texture_op(const Instruction &i)
auto op = static_cast<Op>(i.op);
uint32_t length = i.length;
vector<uint32_t> inherited_expressions;
SmallVector<uint32_t> inherited_expressions;
uint32_t result_type = ops[0];
uint32_t id = ops[1];
@ -4565,7 +4565,7 @@ void CompilerHLSL::require_texture_query_variant(const SPIRType &type)
}
}
void CompilerHLSL::set_root_constant_layouts(vector<RootConstants> layout)
void CompilerHLSL::set_root_constant_layouts(SmallVector<RootConstants> layout)
{
root_constants_layout = move(layout);
}
@ -4664,7 +4664,7 @@ string CompilerHLSL::compile()
reset();
// Move constructor for this type is broken on GCC 4.9 ...
buffer = unique_ptr<ostringstream>(new ostringstream());
buffer.reset();
emit_header();
emit_resources();
@ -4678,7 +4678,7 @@ string CompilerHLSL::compile()
// Entry point in HLSL is always main() for the time being.
get_entry_point().name = "main";
return buffer->str();
return buffer.str();
}
void CompilerHLSL::emit_block_hints(const SPIRBlock &block)

View File

@ -19,7 +19,6 @@
#include "spirv_glsl.hpp"
#include <utility>
#include <vector>
namespace SPIRV_CROSS_NAMESPACE
{
@ -62,8 +61,8 @@ public:
bool support_nonzero_base_vertex_base_instance = false;
};
explicit CompilerHLSL(std::vector<uint32_t> spirv_)
: CompilerGLSL(move(spirv_))
explicit CompilerHLSL(SmallVector<uint32_t> spirv_)
: CompilerGLSL(std::move(spirv_))
{
}
@ -96,7 +95,7 @@ public:
//
// Push constants ranges will be split up according to the
// layout specified.
void set_root_constant_layouts(std::vector<RootConstants> layout);
void set_root_constant_layouts(SmallVector<RootConstants> layout);
// Compiles and remaps vertex attributes at specific locations to a fixed semantic.
// The default is TEXCOORD# where # denotes location.
@ -209,7 +208,7 @@ private:
void emit_builtin_variables();
bool require_output = false;
bool require_input = false;
std::vector<HLSLVertexAttributeRemap> remap_vertex_attributes;
SmallVector<HLSLVertexAttributeRemap> remap_vertex_attributes;
uint32_t type_to_consumed_locations(const SPIRType &type) const;
@ -220,8 +219,8 @@ private:
// Custom root constant layout, which should be emitted
// when translating push constant ranges.
std::vector<RootConstants> root_constants_layout;
SmallVector<RootConstants> root_constants_layout;
};
} // namespace spirv_cross
} // namespace SPIRV_CROSS_NAMESPACE
#endif

View File

@ -30,7 +30,7 @@ static const uint32_t k_unknown_component = ~0u;
static const uint32_t k_aux_mbr_idx_swizzle_const = 0u;
CompilerMSL::CompilerMSL(vector<uint32_t> spirv_)
CompilerMSL::CompilerMSL(SmallVector<uint32_t> spirv_)
: CompilerGLSL(move(spirv_))
{
}
@ -423,7 +423,7 @@ void CompilerMSL::emit_entry_point_declarations()
if (type.basetype == SPIRType::Sampler)
add_resource_name(samp.first);
vector<string> args;
SmallVector<string> args;
auto &s = samp.second;
if (s.coord != MSL_SAMPLER_COORD_NORMALIZED)
@ -659,7 +659,7 @@ string CompilerMSL::compile()
next_metal_resource_index_sampler = 0;
// Move constructor for this type is broken on GCC 4.9 ...
buffer = unique_ptr<ostringstream>(new ostringstream());
buffer.reset();
emit_header();
emit_specialization_constants_and_structs();
@ -670,7 +670,7 @@ string CompilerMSL::compile()
pass_count++;
} while (is_forcing_recompilation());
return buffer->str();
return buffer.str();
}
// Register the need to output any custom functions.
@ -1822,7 +1822,7 @@ void CompilerMSL::fix_up_interface_member_indices(StorageClass storage, uint32_t
uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch)
{
// Accumulate the variables that should appear in the interface struct
vector<SPIRVariable *> vars;
SmallVector<SPIRVariable *> vars;
bool incl_builtins = (storage == StorageClassOutput || is_tessellation_shader());
ir.for_each_typed_id<SPIRVariable>([&](uint32_t var_id, SPIRVariable &var) {
@ -2954,8 +2954,8 @@ void CompilerMSL::emit_specialization_constants_and_structs()
// TODO: This can be expressed as a [[threads_per_threadgroup]] input semantic, but we need to know
// the work group size at compile time in SPIR-V, and [[threads_per_threadgroup]] would need to be passed around as a global.
// The work group size may be a specialization constant.
statement("constant uint3 ", builtin_to_glsl(BuiltInWorkgroupSize, StorageClassWorkgroup), " [[maybe_unused]] = ",
constant_expression(get<SPIRConstant>(workgroup_size_id)), ";");
statement("constant uint3 ", builtin_to_glsl(BuiltInWorkgroupSize, StorageClassWorkgroup),
" [[maybe_unused]] = ", constant_expression(get<SPIRConstant>(workgroup_size_id)), ";");
emitted = true;
}
else if (c.specialization)
@ -3082,7 +3082,7 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l
get_variable_data_type(*var).basetype == SPIRType::Struct))
{
AccessChainMeta meta;
std::vector<uint32_t> indices;
SmallVector<uint32_t> indices;
uint32_t next_id = ir.increase_bound_by(2);
indices.reserve(length - 3 + 1);
@ -5692,7 +5692,7 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args)
uint32_t index;
};
vector<Resource> resources;
SmallVector<Resource> resources;
ir.for_each_typed_id<SPIRVariable>([&](uint32_t, SPIRVariable &var) {
if ((var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant ||
@ -7408,7 +7408,7 @@ void CompilerMSL::MemberSorter::sort()
// Create a temporary array of consecutive member indices and sort it based on how
// the members should be reordered, based on builtin and sorting aspect meta info.
size_t mbr_cnt = type.member_types.size();
vector<uint32_t> mbr_idxs(mbr_cnt);
SmallVector<uint32_t> mbr_idxs(mbr_cnt);
iota(mbr_idxs.begin(), mbr_idxs.end(), 0); // Fill with consecutive indices
std::sort(mbr_idxs.begin(), mbr_idxs.end(), *this); // Sort member indices based on sorting aspect
@ -7602,7 +7602,7 @@ void CompilerMSL::analyze_argument_buffers()
SPIRType::BaseType basetype;
uint32_t index;
};
vector<Resource> resources_in_set[kMaxArgumentBuffers];
SmallVector<Resource> resources_in_set[kMaxArgumentBuffers];
ir.for_each_typed_id<SPIRVariable>([&](uint32_t self, SPIRVariable &var) {
if ((var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant ||

View File

@ -22,7 +22,6 @@
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <vector>
namespace SPIRV_CROSS_NAMESPACE
{
@ -268,7 +267,7 @@ public:
return capture_output_to_buffer && stage_in_var_id != 0;
}
explicit CompilerMSL(std::vector<uint32_t> spirv);
explicit CompilerMSL(SmallVector<uint32_t> spirv);
CompilerMSL(const uint32_t *ir, size_t word_count);
explicit CompilerMSL(const ParsedIR &ir);
explicit CompilerMSL(ParsedIR &&ir);
@ -495,9 +494,9 @@ protected:
std::unordered_map<MSLStructMemberKey, uint32_t> struct_member_padding;
std::set<std::string> pragma_lines;
std::set<std::string> typedef_lines;
std::vector<uint32_t> vars_needing_early_declaration;
SmallVector<uint32_t> vars_needing_early_declaration;
std::vector<std::pair<MSLResourceBinding, bool>> resource_bindings;
SmallVector<std::pair<MSLResourceBinding, bool>> resource_bindings;
uint32_t next_metal_resource_index_buffer = 0;
uint32_t next_metal_resource_index_texture = 0;
uint32_t next_metal_resource_index_sampler = 0;
@ -530,7 +529,7 @@ protected:
spv::Op previous_instruction_opcode = spv::OpNop;
std::unordered_map<uint32_t, MSLConstexprSampler> constexpr_samplers;
std::vector<uint32_t> buffer_arrays;
SmallVector<uint32_t> buffer_arrays;
uint32_t argument_buffer_ids[kMaxArgumentBuffers];
uint32_t argument_buffer_discrete_mask = 0;
@ -597,6 +596,6 @@ protected:
SortAspect sort_aspect;
};
};
} // namespace spirv_cross
} // namespace SPIRV_CROSS_NAMESPACE
#endif

View File

@ -22,14 +22,14 @@ using namespace spv;
namespace SPIRV_CROSS_NAMESPACE
{
Parser::Parser(std::vector<uint32_t> spirv)
Parser::Parser(SmallVector<uint32_t> spirv)
{
ir.spirv = move(spirv);
}
Parser::Parser(const uint32_t *spirv_data, size_t word_count)
{
ir.spirv = vector<uint32_t>(spirv_data, spirv_data + word_count);
ir.spirv = SmallVector<uint32_t>(spirv_data, spirv_data + word_count);
}
static bool decoration_is_string(Decoration decoration)
@ -88,7 +88,7 @@ void Parser::parse()
uint32_t offset = 5;
vector<Instruction> instructions;
SmallVector<Instruction> instructions;
while (offset < len)
{
Instruction instr = {};
@ -131,7 +131,7 @@ const uint32_t *Parser::stream(const Instruction &instr) const
return &ir.spirv[instr.offset];
}
static string extract_string(const vector<uint32_t> &spirv, uint32_t offset)
static string extract_string(const SmallVector<uint32_t> &spirv, uint32_t offset)
{
string ret;
for (uint32_t i = offset; i < spirv.size(); i++)
@ -1097,7 +1097,7 @@ void Parser::make_constant_null(uint32_t id, uint32_t type)
if (!constant_type.array_size_literal.back())
SPIRV_CROSS_THROW("Array size of OpConstantNull must be a literal.");
vector<uint32_t> elements(constant_type.array.back());
SmallVector<uint32_t> elements(constant_type.array.back());
for (uint32_t i = 0; i < constant_type.array.back(); i++)
elements[i] = parent_id;
set<SPIRConstant>(id, type, elements.data(), uint32_t(elements.size()), false);
@ -1105,7 +1105,7 @@ void Parser::make_constant_null(uint32_t id, uint32_t type)
else if (!constant_type.member_types.empty())
{
uint32_t member_ids = ir.increase_bound_by(uint32_t(constant_type.member_types.size()));
vector<uint32_t> elements(constant_type.member_types.size());
SmallVector<uint32_t> elements(constant_type.member_types.size());
for (uint32_t i = 0; i < constant_type.member_types.size(); i++)
{
make_constant_null(member_ids + i, constant_type.member_types[i]);
@ -1120,4 +1120,4 @@ void Parser::make_constant_null(uint32_t id, uint32_t type)
}
}
} // namespace spirv_cross
} // namespace SPIRV_CROSS_NAMESPACE

View File

@ -19,7 +19,6 @@
#include "spirv_cross_parsed_ir.hpp"
#include <stdint.h>
#include <vector>
namespace SPIRV_CROSS_NAMESPACE
{
@ -27,7 +26,7 @@ class Parser
{
public:
Parser(const uint32_t *spirv_data, size_t word_count);
Parser(std::vector<uint32_t> spirv);
Parser(SmallVector<uint32_t> spirv);
void parse();
@ -84,12 +83,12 @@ private:
}
// This must be an ordered data structure so we always pick the same type aliases.
std::vector<uint32_t> global_struct_cache;
SmallVector<uint32_t> global_struct_cache;
bool types_are_logically_equivalent(const SPIRType &a, const SPIRType &b) const;
bool variable_storage_is_aliased(const SPIRVariable &v) const;
void make_constant_null(uint32_t id, uint32_t type);
};
} // namespace spirv_cross
} // namespace SPIRV_CROSS_NAMESPACE
#endif

View File

@ -36,10 +36,16 @@ using Stack = std::stack<State>;
class Stream
{
Stack stack;
std::ostringstream buffer;
StringStream<> buffer;
uint32_t indent{ 0 };
char current_locale_radix_character = '.';
public:
void set_current_locale_radix_character(char c)
{
current_locale_radix_character = c;
}
void begin_json_object();
void end_json_object();
void emit_json_key(const std::string &key);
@ -212,7 +218,7 @@ void Stream::emit_json_key_value(const std::string &key, int32_t value)
void Stream::emit_json_key_value(const std::string &key, float value)
{
emit_json_key(key);
statement_inner(value);
statement_inner(convert_to_string(value, current_locale_radix_character));
}
void Stream::emit_json_key_value(const std::string &key, bool value)
@ -247,8 +253,8 @@ void CompilerReflection::set_format(const std::string &format)
string CompilerReflection::compile()
{
// Move constructor for this type is broken on GCC 4.9 ...
json_stream = std::make_shared<simple_json::Stream>();
json_stream->set_current_locale_radix_character(current_locale_radix_character);
json_stream->begin_json_object();
emit_entry_points();
emit_types();
@ -439,7 +445,7 @@ void CompilerReflection::emit_resources()
emit_resources("acceleration_structures", res.acceleration_structures);
}
void CompilerReflection::emit_resources(const char *tag, const vector<Resource> &resources)
void CompilerReflection::emit_resources(const char *tag, const SmallVector<Resource> &resources)
{
if (resources.empty())
{

View File

@ -19,7 +19,6 @@
#include "spirv_glsl.hpp"
#include <utility>
#include <vector>
namespace simple_json
{
@ -33,8 +32,8 @@ class CompilerReflection : public CompilerGLSL
using Parent = CompilerGLSL;
public:
explicit CompilerReflection(std::vector<uint32_t> spirv_)
: Parent(move(spirv_))
explicit CompilerReflection(SmallVector<uint32_t> spirv_)
: Parent(std::move(spirv_))
{
options.vulkan_semantics = true;
}
@ -72,13 +71,13 @@ private:
void emit_type_member(const SPIRType &type, uint32_t index);
void emit_type_member_qualifiers(const SPIRType &type, uint32_t index);
void emit_type_array(const SPIRType &type);
void emit_resources(const char *tag, const std::vector<Resource> &resources);
void emit_resources(const char *tag, const SmallVector<Resource> &resources);
std::string to_member_name(const SPIRType &type, uint32_t index) const;
std::shared_ptr<simple_json::Stream> json_stream;
};
} // namespace spirv_cross
} // namespace SPIRV_CROSS_NAMESPACE
#endif