summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/spirv_cross/barrier.hpp90
-rw-r--r--include/spirv_cross/external_interface.h94
-rw-r--r--include/spirv_cross/image.hpp25
-rw-r--r--include/spirv_cross/internal_interface.hpp964
-rw-r--r--include/spirv_cross/sampler.hpp136
-rw-r--r--include/spirv_cross/thread_group.hpp159
6 files changed, 773 insertions, 695 deletions
diff --git a/include/spirv_cross/barrier.hpp b/include/spirv_cross/barrier.hpp
index 5d882302..0d77b862 100644
--- a/include/spirv_cross/barrier.hpp
+++ b/include/spirv_cross/barrier.hpp
@@ -22,58 +22,58 @@
namespace spirv_cross
{
- class Barrier
- {
- public:
- Barrier()
- {
- count.store(0);
- iteration.store(0);
- }
+class Barrier
+{
+public:
+ Barrier()
+ {
+ count.store(0);
+ iteration.store(0);
+ }
- void set_release_divisor(unsigned divisor)
- {
- this->divisor = divisor;
- }
+ void set_release_divisor(unsigned divisor)
+ {
+ this->divisor = divisor;
+ }
- static inline void memoryBarrier()
- {
- std::atomic_thread_fence(std::memory_order_seq_cst);
- }
+ static inline void memoryBarrier()
+ {
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+ }
- void reset_counter()
- {
- count.store(0);
- iteration.store(0);
- }
+ void reset_counter()
+ {
+ count.store(0);
+ iteration.store(0);
+ }
- void wait()
- {
- unsigned target_iteration = iteration.load(std::memory_order_relaxed) + 1;
- // Overflows cleanly.
- unsigned target_count = divisor * target_iteration;
+ void wait()
+ {
+ unsigned target_iteration = iteration.load(std::memory_order_relaxed) + 1;
+ // Overflows cleanly.
+ unsigned target_count = divisor * target_iteration;
- // Barriers don't enforce memory ordering.
- // Be as relaxed about the barrier as we possibly can!
- unsigned c = count.fetch_add(1u, std::memory_order_relaxed);
+ // Barriers don't enforce memory ordering.
+ // Be as relaxed about the barrier as we possibly can!
+ unsigned c = count.fetch_add(1u, std::memory_order_relaxed);
- if (c + 1 == target_count)
- {
- iteration.store(target_iteration, std::memory_order_relaxed);
- }
- else
- {
- // If we have more threads than the CPU, don't hog the CPU for very long periods of time.
- while (iteration.load(std::memory_order_relaxed) != target_iteration)
- std::this_thread::yield();
- }
- }
+ if (c + 1 == target_count)
+ {
+ iteration.store(target_iteration, std::memory_order_relaxed);
+ }
+ else
+ {
+ // If we have more threads than the CPU, don't hog the CPU for very long periods of time.
+ while (iteration.load(std::memory_order_relaxed) != target_iteration)
+ std::this_thread::yield();
+ }
+ }
- private:
- unsigned divisor = 1;
- std::atomic<unsigned> count;
- std::atomic<unsigned> iteration;
- };
+private:
+ unsigned divisor = 1;
+ std::atomic<unsigned> count;
+ std::atomic<unsigned> iteration;
+};
}
#endif
diff --git a/include/spirv_cross/external_interface.h b/include/spirv_cross/external_interface.h
index 666aae78..a0067fc1 100644
--- a/include/spirv_cross/external_interface.h
+++ b/include/spirv_cross/external_interface.h
@@ -27,42 +27,33 @@ typedef struct spirv_cross_shader spirv_cross_shader_t;
struct spirv_cross_interface
{
- spirv_cross_shader_t* (*construct)(void);
- void (*destruct)(spirv_cross_shader_t *thiz);
- void (*invoke)(spirv_cross_shader_t *thiz);
+ spirv_cross_shader_t *(*construct)(void);
+ void (*destruct)(spirv_cross_shader_t *thiz);
+ void (*invoke)(spirv_cross_shader_t *thiz);
};
-void spirv_cross_set_stage_input(spirv_cross_shader_t *thiz,
- unsigned location, void *data, size_t size);
+void spirv_cross_set_stage_input(spirv_cross_shader_t *thiz, unsigned location, void *data, size_t size);
-void spirv_cross_set_stage_output(spirv_cross_shader_t *thiz,
- unsigned location, void *data, size_t size);
+void spirv_cross_set_stage_output(spirv_cross_shader_t *thiz, unsigned location, void *data, size_t size);
-void spirv_cross_set_push_constant(spirv_cross_shader_t *thiz,
- void *data, size_t size);
+void spirv_cross_set_push_constant(spirv_cross_shader_t *thiz, void *data, size_t size);
-void spirv_cross_set_uniform_constant(spirv_cross_shader_t *thiz,
- unsigned location,
- void *data, size_t size);
+void spirv_cross_set_uniform_constant(spirv_cross_shader_t *thiz, unsigned location, void *data, size_t size);
-void spirv_cross_set_resource(spirv_cross_shader_t *thiz,
- unsigned set, unsigned binding,
- void **data, size_t size);
+void spirv_cross_set_resource(spirv_cross_shader_t *thiz, unsigned set, unsigned binding, void **data, size_t size);
-const struct spirv_cross_interface* spirv_cross_get_interface(void);
+const struct spirv_cross_interface *spirv_cross_get_interface(void);
typedef enum spirv_cross_builtin
{
- SPIRV_CROSS_BUILTIN_POSITION = 0,
- SPIRV_CROSS_BUILTIN_FRAG_COORD = 1,
- SPIRV_CROSS_BUILTIN_WORK_GROUP_ID = 2,
- SPIRV_CROSS_BUILTIN_NUM_WORK_GROUPS = 3,
- SPIRV_CROSS_NUM_BUILTINS
+ SPIRV_CROSS_BUILTIN_POSITION = 0,
+ SPIRV_CROSS_BUILTIN_FRAG_COORD = 1,
+ SPIRV_CROSS_BUILTIN_WORK_GROUP_ID = 2,
+ SPIRV_CROSS_BUILTIN_NUM_WORK_GROUPS = 3,
+ SPIRV_CROSS_NUM_BUILTINS
} spirv_cross_builtin;
-void spirv_cross_set_builtin(spirv_cross_shader_t *thiz,
- spirv_cross_builtin builtin,
- void *data, size_t size);
+void spirv_cross_set_builtin(spirv_cross_shader_t *thiz, spirv_cross_builtin builtin, void *data, size_t size);
#define SPIRV_CROSS_NUM_DESCRIPTOR_SETS 4
#define SPIRV_CROSS_NUM_DESCRIPTOR_BINDINGS 16
@@ -72,64 +63,63 @@ void spirv_cross_set_builtin(spirv_cross_shader_t *thiz,
enum spirv_cross_format
{
- SPIRV_CROSS_FORMAT_R8_UNORM = 0,
- SPIRV_CROSS_FORMAT_R8G8_UNORM = 1,
- SPIRV_CROSS_FORMAT_R8G8B8_UNORM = 2,
- SPIRV_CROSS_FORMAT_R8G8B8A8_UNORM = 3,
+ SPIRV_CROSS_FORMAT_R8_UNORM = 0,
+ SPIRV_CROSS_FORMAT_R8G8_UNORM = 1,
+ SPIRV_CROSS_FORMAT_R8G8B8_UNORM = 2,
+ SPIRV_CROSS_FORMAT_R8G8B8A8_UNORM = 3,
- SPIRV_CROSS_NUM_FORMATS
+ SPIRV_CROSS_NUM_FORMATS
};
enum spirv_cross_wrap
{
- SPIRV_CROSS_WRAP_CLAMP_TO_EDGE = 0,
- SPIRV_CROSS_WRAP_REPEAT = 1,
+ SPIRV_CROSS_WRAP_CLAMP_TO_EDGE = 0,
+ SPIRV_CROSS_WRAP_REPEAT = 1,
- SPIRV_CROSS_NUM_WRAP
+ SPIRV_CROSS_NUM_WRAP
};
enum spirv_cross_filter
{
- SPIRV_CROSS_FILTER_NEAREST = 0,
- SPIRV_CROSS_FILTER_LINEAR = 1,
+ SPIRV_CROSS_FILTER_NEAREST = 0,
+ SPIRV_CROSS_FILTER_LINEAR = 1,
- SPIRV_CROSS_NUM_FILTER
+ SPIRV_CROSS_NUM_FILTER
};
enum spirv_cross_mipfilter
{
- SPIRV_CROSS_MIPFILTER_BASE = 0,
- SPIRV_CROSS_MIPFILTER_NEAREST = 1,
- SPIRV_CROSS_MIPFILTER_LINEAR = 2,
+ SPIRV_CROSS_MIPFILTER_BASE = 0,
+ SPIRV_CROSS_MIPFILTER_NEAREST = 1,
+ SPIRV_CROSS_MIPFILTER_LINEAR = 2,
- SPIRV_CROSS_NUM_MIPFILTER
+ SPIRV_CROSS_NUM_MIPFILTER
};
struct spirv_cross_miplevel
{
- const void *data;
- unsigned width, height;
- size_t stride;
+ const void *data;
+ unsigned width, height;
+ size_t stride;
};
struct spirv_cross_sampler_info
{
- const struct spirv_cross_miplevel *mipmaps;
- unsigned num_mipmaps;
-
- enum spirv_cross_format format;
- enum spirv_cross_wrap wrap_s;
- enum spirv_cross_wrap wrap_t;
- enum spirv_cross_filter min_filter;
- enum spirv_cross_filter mag_filter;
- enum spirv_cross_mipfilter mip_filter;
+ const struct spirv_cross_miplevel *mipmaps;
+ unsigned num_mipmaps;
+
+ enum spirv_cross_format format;
+ enum spirv_cross_wrap wrap_s;
+ enum spirv_cross_wrap wrap_t;
+ enum spirv_cross_filter min_filter;
+ enum spirv_cross_filter mag_filter;
+ enum spirv_cross_mipfilter mip_filter;
};
typedef struct spirv_cross_sampler_2d spirv_cross_sampler_2d_t;
spirv_cross_sampler_2d_t *spirv_cross_create_sampler_2d(const struct spirv_cross_sampler_info *info);
void spirv_cross_destroy_sampler_2d(spirv_cross_sampler_2d_t *samp);
-
#ifdef __cplusplus
}
#endif
diff --git a/include/spirv_cross/image.hpp b/include/spirv_cross/image.hpp
index 342faf31..1216f117 100644
--- a/include/spirv_cross/image.hpp
+++ b/include/spirv_cross/image.hpp
@@ -29,17 +29,22 @@
namespace spirv_cross
{
- template<typename T>
- struct image2DBase
- {
- virtual ~image2DBase() = default;
- inline virtual T load(glm::ivec2 coord) { return T(0, 0, 0, 1); }
- inline virtual void store(glm::ivec2 coord, const T &v) {}
- };
+template <typename T>
+struct image2DBase
+{
+ virtual ~image2DBase() = default;
+ inline virtual T load(glm::ivec2 coord)
+ {
+ return T(0, 0, 0, 1);
+ }
+ inline virtual void store(glm::ivec2 coord, const T &v)
+ {
+ }
+};
- typedef image2DBase<glm::vec4> image2D;
- typedef image2DBase<glm::ivec4> iimage2D;
- typedef image2DBase<glm::uvec4> uimage2D;
+typedef image2DBase<glm::vec4> image2D;
+typedef image2DBase<glm::ivec4> iimage2D;
+typedef image2DBase<glm::uvec4> uimage2D;
}
#endif
diff --git a/include/spirv_cross/internal_interface.hpp b/include/spirv_cross/internal_interface.hpp
index b47ee02b..c3cbdcd5 100644
--- a/include/spirv_cross/internal_interface.hpp
+++ b/include/spirv_cross/internal_interface.hpp
@@ -39,493 +39,565 @@
namespace internal
{
- // Adaptor helpers to adapt GLSL access chain syntax to C++.
- // Don't bother with arrays of arrays on uniforms ...
- // Would likely need horribly complex variadic template munging.
-
- template<typename T>
- struct Interface
- {
- enum { ArraySize = 1, Size = sizeof(T) };
-
- Interface() : ptr(0) {}
- T& get()
- {
- assert(ptr);
- return *ptr;
- }
-
- T *ptr;
- };
-
- // For array types, return a pointer instead.
- template<typename T, unsigned U>
- struct Interface<T[U]>
- {
- enum { ArraySize = U, Size = U * sizeof(T) };
-
- Interface() : ptr(0) {}
- T* get()
- {
- assert(ptr);
- return ptr;
- }
-
- T *ptr;
- };
-
- // For case when array size is 1, avoid double dereference.
- template<typename T>
- struct PointerInterface
- {
- enum { ArraySize = 1, Size = sizeof(T*) };
- enum { PreDereference = true };
-
- PointerInterface() : ptr(0) {}
-
- T& get()
- {
- assert(ptr);
- return *ptr;
- }
-
- T *ptr;
- };
-
- // Automatically converts a pointer down to reference to match GLSL syntax.
- template<typename T>
- struct DereferenceAdaptor
- {
- DereferenceAdaptor(T **ptr) : ptr(ptr) {}
- T& operator[](unsigned index) const { return *(ptr[index]); }
- T **ptr;
- };
-
- // We can't have a linear array of T* since T* can be an abstract type in case of samplers.
- // We also need a list of pointers since we can have run-time length SSBOs.
- template<typename T, unsigned U>
- struct PointerInterface<T[U]>
- {
- enum { ArraySize = U, Size = sizeof(T*) * U };
- enum { PreDereference = false };
- PointerInterface() : ptr(0) {}
-
- DereferenceAdaptor<T> get()
- {
- assert(ptr);
- return DereferenceAdaptor<T>(ptr);
- }
-
- T **ptr;
- };
-
- // Resources can be more abstract and be unsized,
- // so we need to have an array of pointers for those cases.
- template<typename T> struct Resource : PointerInterface<T> {};
-
- // POD with no unknown sizes, so we can express these as flat arrays.
- template<typename T> struct UniformConstant : Interface<T> {};
- template<typename T> struct StageInput : Interface<T> {};
- template<typename T> struct StageOutput : Interface<T> {};
- template<typename T> struct PushConstant : Interface<T> {};
+// Adaptor helpers to adapt GLSL access chain syntax to C++.
+// Don't bother with arrays of arrays on uniforms ...
+// Would likely need horribly complex variadic template munging.
+
+template <typename T>
+struct Interface
+{
+ enum
+ {
+ ArraySize = 1,
+ Size = sizeof(T)
+ };
+
+ Interface()
+ : ptr(0)
+ {
+ }
+ T &get()
+ {
+ assert(ptr);
+ return *ptr;
+ }
+
+ T *ptr;
+};
+
+// For array types, return a pointer instead.
+template <typename T, unsigned U>
+struct Interface<T[U]>
+{
+ enum
+ {
+ ArraySize = U,
+ Size = U * sizeof(T)
+ };
+
+ Interface()
+ : ptr(0)
+ {
+ }
+ T *get()
+ {
+ assert(ptr);
+ return ptr;
+ }
+
+ T *ptr;
+};
+
+// For case when array size is 1, avoid double dereference.
+template <typename T>
+struct PointerInterface
+{
+ enum
+ {
+ ArraySize = 1,
+ Size = sizeof(T *)
+ };
+ enum
+ {
+ PreDereference = true
+ };
+
+ PointerInterface()
+ : ptr(0)
+ {
+ }
+
+ T &get()
+ {
+ assert(ptr);
+ return *ptr;
+ }
+
+ T *ptr;
+};
+
+// Automatically converts a pointer down to reference to match GLSL syntax.
+template <typename T>
+struct DereferenceAdaptor
+{
+ DereferenceAdaptor(T **ptr)
+ : ptr(ptr)
+ {
+ }
+ T &operator[](unsigned index) const
+ {
+ return *(ptr[index]);
+ }
+ T **ptr;
+};
+
+// We can't have a linear array of T* since T* can be an abstract type in case of samplers.
+// We also need a list of pointers since we can have run-time length SSBOs.
+template <typename T, unsigned U>
+struct PointerInterface<T[U]>
+{
+ enum
+ {
+ ArraySize = U,
+ Size = sizeof(T *) * U
+ };
+ enum
+ {
+ PreDereference = false
+ };
+ PointerInterface()
+ : ptr(0)
+ {
+ }
+
+ DereferenceAdaptor<T> get()
+ {
+ assert(ptr);
+ return DereferenceAdaptor<T>(ptr);
+ }
+
+ T **ptr;
+};
+
+// Resources can be more abstract and be unsized,
+// so we need to have an array of pointers for those cases.
+template <typename T>
+struct Resource : PointerInterface<T>
+{
+};
+
+// POD with no unknown sizes, so we can express these as flat arrays.
+template <typename T>
+struct UniformConstant : Interface<T>
+{
+};
+template <typename T>
+struct StageInput : Interface<T>
+{
+};
+template <typename T>
+struct StageOutput : Interface<T>
+{
+};
+template <typename T>
+struct PushConstant : Interface<T>
+{
+};
}
struct spirv_cross_shader
{
- struct PPSize
- {
- PPSize() : ptr(0), size(0) {}
- void **ptr;
- size_t size;
- };
-
- struct PPSizeResource
- {
- PPSizeResource() : ptr(0), size(0), pre_dereference(false) {}
- void **ptr;
- size_t size;
- bool pre_dereference;
- };
-
- PPSizeResource resources[SPIRV_CROSS_NUM_DESCRIPTOR_SETS][SPIRV_CROSS_NUM_DESCRIPTOR_BINDINGS];
- PPSize stage_inputs[SPIRV_CROSS_NUM_STAGE_INPUTS];
- PPSize stage_outputs[SPIRV_CROSS_NUM_STAGE_OUTPUTS];
- PPSize uniform_constants[SPIRV_CROSS_NUM_UNIFORM_CONSTANTS];
- PPSize push_constant;
- PPSize builtins[SPIRV_CROSS_NUM_BUILTINS];
-
- template<typename U>
- void register_builtin(spirv_cross_builtin builtin, const U& value)
- {
- assert(!builtins[builtin].ptr);
-
- builtins[builtin].ptr = (void**)&value.ptr;
- builtins[builtin].size = sizeof(*value.ptr) * U::ArraySize;
- }
-
- void set_builtin(spirv_cross_builtin builtin, void *data, size_t size)
- {
- assert(builtins[builtin].ptr);
- assert(size >= builtins[builtin].size);
-
- *builtins[builtin].ptr = data;
- }
-
- template<typename U>
- void register_resource(const internal::Resource<U> &value, unsigned set, unsigned binding)
- {
- assert(set < SPIRV_CROSS_NUM_DESCRIPTOR_SETS);
- assert(binding < SPIRV_CROSS_NUM_DESCRIPTOR_BINDINGS);
- assert(!resources[set][binding].ptr);
-
- resources[set][binding].ptr = (void**)&value.ptr;
- resources[set][binding].size = internal::Resource<U>::Size;
- resources[set][binding].pre_dereference = internal::Resource<U>::PreDereference;
- }
-
- template<typename U>
- void register_stage_input(const internal::StageInput<U> &value, unsigned location)
- {
- assert(location < SPIRV_CROSS_NUM_STAGE_INPUTS);
- assert(!stage_inputs[location].ptr);
-
- stage_inputs[location].ptr = (void**)&value.ptr;
- stage_inputs[location].size = internal::StageInput<U>::Size;
- }
-
- template<typename U>
- void register_stage_output(const internal::StageOutput<U> &value, unsigned location)
- {
- assert(location < SPIRV_CROSS_NUM_STAGE_OUTPUTS);
- assert(!stage_outputs[location].ptr);
-
- stage_outputs[location].ptr = (void**)&value.ptr;
- stage_outputs[location].size = internal::StageOutput<U>::Size;
- }
-
- template<typename U>
- void register_uniform_constant(const internal::UniformConstant<U> &value, unsigned location)
- {
- assert(location < SPIRV_CROSS_NUM_UNIFORM_CONSTANTS);
- assert(!uniform_constants[location].ptr);
-
- uniform_constants[location].ptr = (void**)&value.ptr;
- uniform_constants[location].size = internal::UniformConstant<U>::Size;
- }
-
- template<typename U>
- void register_push_constant(const internal::PushConstant<U> &value)
- {
- assert(!push_constant.ptr);
-
- push_constant.ptr = (void**)&value.ptr;
- push_constant.size = internal::PushConstant<U>::Size;
- }
-
- void set_stage_input(unsigned location, void *data, size_t size)
- {
- assert(location < SPIRV_CROSS_NUM_STAGE_INPUTS);
- assert(stage_inputs[location].ptr);
- assert(size >= stage_inputs[location].size);
-
- *stage_inputs[location].ptr = data;
- }
-
- void set_stage_output(unsigned location, void *data, size_t size)
- {
- assert(location < SPIRV_CROSS_NUM_STAGE_OUTPUTS);
- assert(stage_outputs[location].ptr);
- assert(size >= stage_outputs[location].size);
-
- *stage_outputs[location].ptr = data;
- }
-
- void set_uniform_constant(unsigned location, void *data, size_t size)
- {
- assert(location < SPIRV_CROSS_NUM_UNIFORM_CONSTANTS);
- assert(uniform_constants[location].ptr);
- assert(size >= uniform_constants[location].size);
-
- *uniform_constants[location].ptr = data;
- }
-
- void set_push_constant(void *data, size_t size)
- {
- assert(push_constant.ptr);
- assert(size >= push_constant.size);
-
- *push_constant.ptr = data;
- }
-
- void set_resource(unsigned set, unsigned binding,
- void **data, size_t size)
- {
- assert(set < SPIRV_CROSS_NUM_DESCRIPTOR_SETS);
- assert(binding < SPIRV_CROSS_NUM_DESCRIPTOR_BINDINGS);
- assert(resources[set][binding].ptr);
- assert(size >= resources[set][binding].size);
-
- // We're using the regular PointerInterface, dereference ahead of time.
- if (resources[set][binding].pre_dereference)
- *resources[set][binding].ptr = *data;
- else
- *resources[set][binding].ptr = data;
- }
+ struct PPSize
+ {
+ PPSize()
+ : ptr(0)
+ , size(0)
+ {
+ }
+ void **ptr;
+ size_t size;
+ };
+
+ struct PPSizeResource
+ {
+ PPSizeResource()
+ : ptr(0)
+ , size(0)
+ , pre_dereference(false)
+ {
+ }
+ void **ptr;
+ size_t size;
+ bool pre_dereference;
+ };
+
+ PPSizeResource resources[SPIRV_CROSS_NUM_DESCRIPTOR_SETS][SPIRV_CROSS_NUM_DESCRIPTOR_BINDINGS];
+ PPSize stage_inputs[SPIRV_CROSS_NUM_STAGE_INPUTS];
+ PPSize stage_outputs[SPIRV_CROSS_NUM_STAGE_OUTPUTS];
+ PPSize uniform_constants[SPIRV_CROSS_NUM_UNIFORM_CONSTANTS];
+ PPSize push_constant;
+ PPSize builtins[SPIRV_CROSS_NUM_BUILTINS];
+
+ template <typename U>
+ void register_builtin(spirv_cross_builtin builtin, const U &value)
+ {
+ assert(!builtins[builtin].ptr);
+
+ builtins[builtin].ptr = (void **)&value.ptr;
+ builtins[builtin].size = sizeof(*value.ptr) * U::ArraySize;
+ }
+
+ void set_builtin(spirv_cross_builtin builtin, void *data, size_t size)
+ {
+ assert(builtins[builtin].ptr);
+ assert(size >= builtins[builtin].size);
+
+ *builtins[builtin].ptr = data;
+ }
+
+ template <typename U>
+ void register_resource(const internal::Resource<U> &value, unsigned set, unsigned binding)
+ {
+ assert(set < SPIRV_CROSS_NUM_DESCRIPTOR_SETS);
+ assert(binding < SPIRV_CROSS_NUM_DESCRIPTOR_BINDINGS);
+ assert(!resources[set][binding].ptr);
+
+ resources[set][binding].ptr = (void **)&value.ptr;
+ resources[set][binding].size = internal::Resource<U>::Size;
+ resources[set][binding].pre_dereference = internal::Resource<U>::PreDereference;
+ }
+
+ template <typename U>
+ void register_stage_input(const internal::StageInput<U> &value, unsigned location)
+ {
+ assert(location < SPIRV_CROSS_NUM_STAGE_INPUTS);
+ assert(!stage_inputs[location].ptr);
+
+ stage_inputs[location].ptr = (void **)&value.ptr;
+ stage_inputs[location].size = internal::StageInput<U>::Size;
+ }
+
+ template <typename U>
+ void register_stage_output(const internal::StageOutput<U> &value, unsigned location)
+ {
+ assert(location < SPIRV_CROSS_NUM_STAGE_OUTPUTS);
+ assert(!stage_outputs[location].ptr);
+
+ stage_outputs[location].ptr = (void **)&value.ptr;
+ stage_outputs[location].size = internal::StageOutput<U>::Size;
+ }
+
+ template <typename U>
+ void register_uniform_constant(const internal::UniformConstant<U> &value, unsigned location)
+ {
+ assert(location < SPIRV_CROSS_NUM_UNIFORM_CONSTANTS);
+ assert(!uniform_constants[location].ptr);
+
+ uniform_constants[location].ptr = (void **)&value.ptr;
+ uniform_constants[location].size = internal::UniformConstant<U>::Size;
+ }
+
+ template <typename U>
+ void register_push_constant(const internal::PushConstant<U> &value)
+ {
+ assert(!push_constant.ptr);
+
+ push_constant.ptr = (void **)&value.ptr;
+ push_constant.size = internal::PushConstant<U>::Size;
+ }
+
+ void set_stage_input(unsigned location, void *data, size_t size)
+ {
+ assert(location < SPIRV_CROSS_NUM_STAGE_INPUTS);
+ assert(stage_inputs[location].ptr);
+ assert(size >= stage_inputs[location].size);
+
+ *stage_inputs[location].ptr = data;
+ }
+
+ void set_stage_output(unsigned location, void *data, size_t size)
+ {
+ assert(location < SPIRV_CROSS_NUM_STAGE_OUTPUTS);
+ assert(stage_outputs[location].ptr);
+ assert(size >= stage_outputs[location].size);
+
+ *stage_outputs[location].ptr = data;
+ }
+
+ void set_uniform_constant(unsigned location, void *data, size_t size)
+ {
+ assert(location < SPIRV_CROSS_NUM_UNIFORM_CONSTANTS);
+ assert(uniform_constants[location].ptr);
+ assert(size >= uniform_constants[location].size);
+
+ *uniform_constants[location].ptr = data;
+ }
+
+ void set_push_constant(void *data, size_t size)
+ {
+ assert(push_constant.ptr);
+ assert(size >= push_constant.size);
+
+ *push_constant.ptr = data;
+ }
+
+ void set_resource(unsigned set, unsigned binding, void **data, size_t size)
+ {
+ assert(set < SPIRV_CROSS_NUM_DESCRIPTOR_SETS);
+ assert(binding < SPIRV_CROSS_NUM_DESCRIPTOR_BINDINGS);
+ assert(resources[set][binding].ptr);
+ assert(size >= resources[set][binding].size);
+
+ // We're using the regular PointerInterface, dereference ahead of time.
+ if (resources[set][binding].pre_dereference)
+ *resources[set][binding].ptr = *data;
+ else
+ *resources[set][binding].ptr = data;
+ }
};
namespace spirv_cross
{
- template<typename T>
- struct BaseShader : spirv_cross_shader
- {
- void invoke()
- {
- static_cast<T*>(this)->main();
- }
- };
-
- struct FragmentResources
- {
- internal::StageOutput<glm::vec4> gl_FragCoord;
- void init(spirv_cross_shader &s)
- {
- s.register_builtin(SPIRV_CROSS_BUILTIN_FRAG_COORD, gl_FragCoord);
- }
+template <typename T>
+struct BaseShader : spirv_cross_shader
+{
+ void invoke()
+ {
+ static_cast<T *>(this)->main();
+ }
+};
+
+struct FragmentResources
+{
+ internal::StageOutput<glm::vec4> gl_FragCoord;
+ void init(spirv_cross_shader &s)
+ {
+ s.register_builtin(SPIRV_CROSS_BUILTIN_FRAG_COORD, gl_FragCoord);
+ }
#define gl_FragCoord __res->gl_FragCoord.get()
- };
-
- template<typename T, typename Res>
- struct FragmentShader : BaseShader<FragmentShader<T, Res> >
- {
- inline void main()
- {
- impl.main();
- }
-
- FragmentShader()
- {
- resources.init(*this);
- impl.__res = &resources;
- }
-
- T impl;
- Res resources;
- };
-
- struct VertexResources
- {
- internal::StageOutput<glm::vec4> gl_Position;
- void init(spirv_cross_shader &s)
- {
- s.register_builtin(SPIRV_CROSS_BUILTIN_POSITION, gl_Position);
- }
+};
+
+template <typename T, typename Res>
+struct FragmentShader : BaseShader<FragmentShader<T, Res>>
+{
+ inline void main()
+ {
+ impl.main();
+ }
+
+ FragmentShader()
+ {
+ resources.init(*this);
+ impl.__res = &resources;
+ }
+
+ T impl;
+ Res resources;
+};
+
+struct VertexResources
+{
+ internal::StageOutput<glm::vec4> gl_Position;
+ void init(spirv_cross_shader &s)
+ {
+ s.register_builtin(SPIRV_CROSS_BUILTIN_POSITION, gl_Position);
+ }
#define gl_Position __res->gl_Position.get()
- };
-
- template<typename T, typename Res>
- struct VertexShader : BaseShader<VertexShader<T, Res> >
- {
- inline void main()
- {
- impl.main();
- }
-
- VertexShader()
- {
- resources.init(*this);
- impl.__res = &resources;
- }
-
- T impl;
- Res resources;
- };
-
- struct TessEvaluationResources
- {
- inline void init(spirv_cross_shader&) {}
- };
-
- template<typename T, typename Res>
- struct TessEvaluationShader : BaseShader<TessEvaluationShader<T, Res> >
- {
- inline void main()
- {
- impl.main();
- }
-
- TessEvaluationShader()
- {
- resources.init(*this);
- impl.__res = &resources;
- }
-
- T impl;
- Res resources;
- };
-
- struct TessControlResources
- {
- inline void init(spirv_cross_shader&) {}
- };
-
- template<typename T, typename Res>
- struct TessControlShader : BaseShader<TessControlShader<T, Res> >
- {
- inline void main()
- {
- impl.main();
- }
-
- TessControlShader()
- {
- resources.init(*this);
- impl.__res = &resources;
- }
-
- T impl;
- Res resources;
- };
-
- struct GeometryResources
- {
- inline void init(spirv_cross_shader&) {}
- };
-
- template<typename T, typename Res>
- struct GeometryShader : BaseShader<GeometryShader<T, Res> >
- {
- inline void main()
- {
- impl.main();
- }
-
- GeometryShader()
- {
- resources.init(*this);
- impl.__res = &resources;
- }
-
- T impl;
- Res resources;
- };
-
- struct ComputeResources
- {
- internal::StageInput<glm::uvec3> gl_WorkGroupID__;
- internal::StageInput<glm::uvec3> gl_NumWorkGroups__;
- void init(spirv_cross_shader &s)
- {
- s.register_builtin(SPIRV_CROSS_BUILTIN_WORK_GROUP_ID, gl_WorkGroupID__);
- s.register_builtin(SPIRV_CROSS_BUILTIN_NUM_WORK_GROUPS, gl_NumWorkGroups__);
- }
+};
+
+template <typename T, typename Res>
+struct VertexShader : BaseShader<VertexShader<T, Res>>
+{
+ inline void main()
+ {
+ impl.main();
+ }
+
+ VertexShader()
+ {
+ resources.init(*this);
+ impl.__res = &resources;
+ }
+
+ T impl;
+ Res resources;
+};
+
+struct TessEvaluationResources
+{
+ inline void init(spirv_cross_shader &)
+ {
+ }
+};
+
+template <typename T, typename Res>
+struct TessEvaluationShader : BaseShader<TessEvaluationShader<T, Res>>
+{
+ inline void main()
+ {
+ impl.main();
+ }
+
+ TessEvaluationShader()
+ {
+ resources.init(*this);
+ impl.__res = &resources;
+ }
+
+ T impl;
+ Res resources;
+};
+
+struct TessControlResources
+{
+ inline void init(spirv_cross_shader &)
+ {
+ }
+};
+
+template <typename T, typename Res>
+struct TessControlShader : BaseShader<TessControlShader<T, Res>>
+{
+ inline void main()
+ {
+ impl.main();
+ }
+
+ TessControlShader()
+ {
+ resources.init(*this);
+ impl.__res = &resources;
+ }
+
+ T impl;
+ Res resources;
+};
+
+struct GeometryResources
+{
+ inline void init(spirv_cross_shader &)
+ {
+ }
+};
+
+template <typename T, typename Res>
+struct GeometryShader : BaseShader<GeometryShader<T, Res>>
+{
+ inline void main()
+ {
+ impl.main();
+ }
+
+ GeometryShader()
+ {
+ resources.init(*this);
+ impl.__res = &resources;
+ }
+
+ T impl;
+ Res resources;
+};
+
+struct ComputeResources
+{
+ internal::StageInput<glm::uvec3> gl_WorkGroupID__;
+ internal::StageInput<glm::uvec3> gl_NumWorkGroups__;
+ void init(spirv_cross_shader &s)
+ {
+ s.register_builtin(SPIRV_CROSS_BUILTIN_WORK_GROUP_ID, gl_WorkGroupID__);
+ s.register_builtin(SPIRV_CROSS_BUILTIN_NUM_WORK_GROUPS, gl_NumWorkGroups__);
+ }
#define gl_WorkGroupID __res->gl_WorkGroupID__.get()
#define gl_NumWorkGroups __res->gl_NumWorkGroups.get()
- Barrier barrier__;
+ Barrier barrier__;
#define barrier() __res->barrier__.wait()
- };
+};
- struct ComputePrivateResources
- {
- uint32_t gl_LocalInvocationIndex__;
+struct ComputePrivateResources
+{
+ uint32_t gl_LocalInvocationIndex__;
#define gl_LocalInvocationIndex __priv_res.gl_LocalInvocationIndex__
- glm::uvec3 gl_LocalInvocationID__;
+ glm::uvec3 gl_LocalInvocationID__;
#define gl_LocalInvocationID __priv_res.gl_LocalInvocationID__
- glm::uvec3 gl_GlobalInvocationID__;
+ glm::uvec3 gl_GlobalInvocationID__;
#define gl_GlobalInvocationID __priv_res.gl_GlobalInvocationID__
- };
-
- template<typename T, typename Res, unsigned WorkGroupX, unsigned WorkGroupY, unsigned WorkGroupZ>
- struct ComputeShader : BaseShader<ComputeShader<T, Res, WorkGroupX, WorkGroupY, WorkGroupZ> >
- {
- inline void main()
- {
- resources.barrier__.reset_counter();
-
- for (unsigned z = 0; z < WorkGroupZ; z++)
- for (unsigned y = 0; y < WorkGroupY; y++)
- for (unsigned x = 0; x < WorkGroupX; x++)
- impl[z][y][x].__priv_res.gl_GlobalInvocationID__ =
- glm::uvec3(WorkGroupX, WorkGroupY, WorkGroupZ) * resources.gl_WorkGroupID__.get() +
- glm::uvec3(x, y, z);
-
- group.run();
- group.wait();
- }
-
- ComputeShader()
- : group(&impl[0][0][0])
- {
- resources.init(*this);
- resources.barrier__.set_release_divisor(WorkGroupX * WorkGroupY * WorkGroupZ);
-
- unsigned i = 0;
- for (unsigned z = 0; z < WorkGroupZ; z++)
- {
- for (unsigned y = 0; y < WorkGroupY; y++)
- {
- for (unsigned x = 0; x < WorkGroupX; x++)
- {
- impl[z][y][x].__priv_res.gl_LocalInvocationID__ =
- glm::uvec3(x, y, z);
- impl[z][y][x].__priv_res.gl_LocalInvocationIndex__ = i++;
- impl[z][y][x].__res = &resources;
- }
- }
- }
- }
-
- T impl[WorkGroupZ][WorkGroupY][WorkGroupX];
- ThreadGroup<T, WorkGroupX * WorkGroupY * WorkGroupZ> group;
- Res resources;
- };
-
- inline void memoryBarrierShared() { Barrier::memoryBarrier(); }
- inline void memoryBarrier() { Barrier::memoryBarrier(); }
- // TODO: Rest of the barriers.
-
- // Atomics
- template<typename T>
- inline T atomicAdd(T &v, T a)
- {
- static_assert(sizeof(std::atomic<T>) == sizeof(T), "Cannot cast properly to std::atomic<T>.");
-
- // We need explicit memory barriers in GLSL to enfore any ordering.
- // FIXME: Can we really cast this? There is no other way I think ...
- return std::atomic_fetch_add_explicit(reinterpret_cast<std::atomic<T>*>(&v),
- a, std::memory_order_relaxed);
- }
+};
+
+template <typename T, typename Res, unsigned WorkGroupX, unsigned WorkGroupY, unsigned WorkGroupZ>
+struct ComputeShader : BaseShader<ComputeShader<T, Res, WorkGroupX, WorkGroupY, WorkGroupZ>>
+{
+ inline void main()
+ {
+ resources.barrier__.reset_counter();
+
+ for (unsigned z = 0; z < WorkGroupZ; z++)
+ for (unsigned y = 0; y < WorkGroupY; y++)
+ for (unsigned x = 0; x < WorkGroupX; x++)
+ impl[z][y][x].__priv_res.gl_GlobalInvocationID__ =
+ glm::uvec3(WorkGroupX, WorkGroupY, WorkGroupZ) * resources.gl_WorkGroupID__.get() +
+ glm::uvec3(x, y, z);
+
+ group.run();
+ group.wait();
+ }
+
+ ComputeShader()
+ : group(&impl[0][0][0])
+ {
+ resources.init(*this);
+ resources.barrier__.set_release_divisor(WorkGroupX * WorkGroupY * WorkGroupZ);
+
+ unsigned i = 0;
+ for (unsigned z = 0; z < WorkGroupZ; z++)
+ {
+ for (unsigned y = 0; y < WorkGroupY; y++)
+ {
+ for (unsigned x = 0; x < WorkGroupX; x++)
+ {
+ impl[z][y][x].__priv_res.gl_LocalInvocationID__ = glm::uvec3(x, y, z);
+ impl[z][y][x].__priv_res.gl_LocalInvocationIndex__ = i++;
+ impl[z][y][x].__res = &resources;
+ }
+ }
+ }
+ }
+
+ T impl[WorkGroupZ][WorkGroupY][WorkGroupX];
+ ThreadGroup<T, WorkGroupX * WorkGroupY * WorkGroupZ> group;
+ Res resources;
+};
+
+inline void memoryBarrierShared()
+{
+ Barrier::memoryBarrier();
+}
+inline void memoryBarrier()
+{
+ Barrier::memoryBarrier();
+}
+// TODO: Rest of the barriers.
+
+// Atomics
+template <typename T>
+inline T atomicAdd(T &v, T a)
+{
+ static_assert(sizeof(std::atomic<T>) == sizeof(T), "Cannot cast properly to std::atomic<T>.");
+
+ // We need explicit memory barriers in GLSL to enfore any ordering.
+ // FIXME: Can we really cast this? There is no other way I think ...
+ return std::atomic_fetch_add_explicit(reinterpret_cast<std::atomic<T> *>(&v), a, std::memory_order_relaxed);
+}
}
void spirv_cross_set_stage_input(spirv_cross_shader_t *shader, unsigned location, void *data, size_t size)
{
- shader->set_stage_input(location, data, size);
+ shader->set_stage_input(location, data, size);
}
void spirv_cross_set_stage_output(spirv_cross_shader_t *shader, unsigned location, void *data, size_t size)
{
- shader->set_stage_output(location, data, size);
+ shader->set_stage_output(location, data, size);
}
void spirv_cross_set_uniform_constant(spirv_cross_shader_t *shader, unsigned location, void *data, size_t size)
{
- shader->set_uniform_constant(location, data, size);
+ shader->set_uniform_constant(location, data, size);
}
void spirv_cross_set_resource(spirv_cross_shader_t *shader, unsigned set, unsigned binding, void **data, size_t size)
{
- shader->set_resource(set, binding, data, size);
+ shader->set_resource(set, binding, data, size);
}
void spirv_cross_set_push_constant(spirv_cross_shader_t *shader, void *data, size_t size)
{
- shader->set_push_constant(data, size);
+ shader->set_push_constant(data, size);
}
-void spirv_cross_set_builtin(spirv_cross_shader_t *shader, spirv_cross_builtin builtin,
- void *data, size_t size)
+void spirv_cross_set_builtin(spirv_cross_shader_t *shader, spirv_cross_builtin builtin, void *data, size_t size)
{
- shader->set_builtin(builtin, data, size);
+ shader->set_builtin(builtin, data, size);
}
#endif
diff --git a/include/spirv_cross/sampler.hpp b/include/spirv_cross/sampler.hpp
index ca0aa9d1..e38e569a 100644
--- a/include/spirv_cross/sampler.hpp
+++ b/include/spirv_cross/sampler.hpp
@@ -21,81 +21,85 @@
namespace spirv_cross
{
- struct spirv_cross_sampler_2d
- {
- inline virtual ~spirv_cross_sampler_2d() {}
- };
-
- template<typename T>
- struct sampler2DBase : spirv_cross_sampler_2d
- {
- sampler2DBase(const spirv_cross_sampler_info *info)
- {
- mips.insert(mips.end(), info->mipmaps, info->mipmaps + info->num_mipmaps);
- format = info->format;
- wrap_s = info->wrap_s;
- wrap_t = info->wrap_t;
- min_filter = info->min_filter;
- mag_filter = info->mag_filter;
- mip_filter = info->mip_filter;
- }
+struct spirv_cross_sampler_2d
+{
+ inline virtual ~spirv_cross_sampler_2d()
+ {
+ }
+};
- inline virtual T sample(glm::vec2 uv, float bias)
- {
- return sampleLod(uv, bias);
- }
+template <typename T>
+struct sampler2DBase : spirv_cross_sampler_2d
+{
+ sampler2DBase(const spirv_cross_sampler_info *info)
+ {
+ mips.insert(mips.end(), info->mipmaps, info->mipmaps + info->num_mipmaps);
+ format = info->format;
+ wrap_s = info->wrap_s;
+ wrap_t = info->wrap_t;
+ min_filter = info->min_filter;
+ mag_filter = info->mag_filter;
+ mip_filter = info->mip_filter;
+ }
- inline virtual T sampleLod(glm::vec2 uv, float lod)
- {
- if (mag_filter == SPIRV_CROSS_FILTER_NEAREST)
- {
- uv.x = wrap(uv.x, wrap_s, mips[0].width);
- uv.y = wrap(uv.y, wrap_t, mips[0].height);
- glm::vec2 uv_full = uv * glm::vec2(mips[0].width, mips[0].height);
+ inline virtual T sample(glm::vec2 uv, float bias)
+ {
+ return sampleLod(uv, bias);
+ }
- int x = int(uv_full.x);
- int y = int(uv_full.y);
- return sample(x, y, 0);
- }
- else
- {
- return T(0, 0, 0, 1);
- }
- }
+ inline virtual T sampleLod(glm::vec2 uv, float lod)
+ {
+ if (mag_filter == SPIRV_CROSS_FILTER_NEAREST)
+ {
+ uv.x = wrap(uv.x, wrap_s, mips[0].width);
+ uv.y = wrap(uv.y, wrap_t, mips[0].height);
+ glm::vec2 uv_full = uv * glm::vec2(mips[0].width, mips[0].height);
- inline float wrap(float v, spirv_cross_wrap wrap, unsigned size)
- {
- switch (wrap)
- {
- case SPIRV_CROSS_WRAP_REPEAT:
- return v - glm::floor(v);
- case SPIRV_CROSS_WRAP_CLAMP_TO_EDGE:
- {
- float half = 0.5f / size;
- return glm::clamp(v, half, 1.0f - half);
- }
+ int x = int(uv_full.x);
+ int y = int(uv_full.y);
+ return sample(x, y, 0);
+ }
+ else
+ {
+ return T(0, 0, 0, 1);
+ }
+ }
- default:
- return 0.0f;
- }
- }
+ inline float wrap(float v, spirv_cross_wrap wrap, unsigned size)
+ {
+ switch (wrap)
+ {
+ case SPIRV_CROSS_WRAP_REPEAT:
+ return v - glm::floor(v);
+ case SPIRV_CROSS_WRAP_CLAMP_TO_EDGE:
+ {
+ float half = 0.5f / size;
+ return glm::clamp(v, half, 1.0f - half);
+ }
- std::vector<spirv_cross_miplevel> mips;
- spirv_cross_format format;
- spirv_cross_wrap wrap_s;
- spirv_cross_format wrap_t;
- spirv_cross_filter min_filter;
- spirv_cross_filter mag_filter;
- spirv_cross_mipfilter mip_filter;
- };
+ default:
+ return 0.0f;
+ }
+ }
- typedef sampler2DBase<glm::vec4> sampler2D;
- typedef sampler2DBase<glm::ivec4> isampler2D;
- typedef sampler2DBase<glm::uvec4> usampler2D;
+ std::vector<spirv_cross_miplevel> mips;
+ spirv_cross_format format;
+ spirv_cross_wrap wrap_s;
+ spirv_cross_format wrap_t;
+ spirv_cross_filter min_filter;
+ spirv_cross_filter mag_filter;
+ spirv_cross_mipfilter mip_filter;
+};
- template<typename T>
- inline T texture(const sampler2DBase<T> &samp, const glm::vec2 &uv, float bias = 0.0f) { return samp.sample(uv, bias); }
+typedef sampler2DBase<glm::vec4> sampler2D;
+typedef sampler2DBase<glm::ivec4> isampler2D;
+typedef sampler2DBase<glm::uvec4> usampler2D;
+template <typename T>
+inline T texture(const sampler2DBase<T> &samp, const glm::vec2 &uv, float bias = 0.0f)
+{
+ return samp.sample(uv, bias);
+}
}
#endif
diff --git a/include/spirv_cross/thread_group.hpp b/include/spirv_cross/thread_group.hpp
index 5877d243..81a9bf36 100644
--- a/include/spirv_cross/thread_group.hpp
+++ b/include/spirv_cross/thread_group.hpp
@@ -23,91 +23,98 @@
namespace spirv_cross
{
- template<typename T, unsigned Size>
- class ThreadGroup
- {
- public:
- ThreadGroup(T *impl)
- {
- for (unsigned i = 0; i < Size; i++)
- workers[i].start(&impl[i]);
- }
+template <typename T, unsigned Size>
+class ThreadGroup
+{
+public:
+ ThreadGroup(T *impl)
+ {
+ for (unsigned i = 0; i < Size; i++)
+ workers[i].start(&impl[i]);
+ }
- void run()
- {
- for (auto &worker : workers)
- worker.run();
- }
+ void run()
+ {
+ for (auto &worker : workers)
+ worker.run();
+ }
- void wait()
- {
- for (auto &worker : workers)
- worker.wait();
- }
+ void wait()
+ {
+ for (auto &worker : workers)
+ worker.wait();
+ }
- private:
- struct Thread
- {
- enum State
- {
- Idle,
- Running,
- Dying
- };
- State state = Idle;
+private:
+ struct Thread
+ {
+ enum State
+ {
+ Idle,
+ Running,
+ Dying
+ };
+ State state = Idle;
- void start(T *impl)
- {
- worker = std::thread([impl, this] {
- for (;;)
- {
- {
- std::unique_lock<std::mutex> l{lock};
- cond.wait(l, [this] { return state != Idle; });
- if (state == Dying)
- break;
- }
+ void start(T *impl)
+ {
+ worker = std::thread([impl, this]
+ {
+ for (;;)
+ {
+ {
+ std::unique_lock<std::mutex> l{ lock };
+ cond.wait(l, [this]
+ {
+ return state != Idle;
+ });
+ if (state == Dying)
+ break;
+ }
- impl->main();
+ impl->main();
- std::lock_guard<std::mutex> l{lock};
- state = Idle;
- cond.notify_one();
- }
- });
- }
+ std::lock_guard<std::mutex> l{ lock };
+ state = Idle;
+ cond.notify_one();
+ }
+ });
+ }
- void wait()
- {
- std::unique_lock<std::mutex> l{lock};
- cond.wait(l, [this] { return state == Idle; });
- }
+ void wait()
+ {
+ std::unique_lock<std::mutex> l{ lock };
+ cond.wait(l, [this]
+ {
+ return state == Idle;
+ });
+ }
- void run()
- {
- std::lock_guard<std::mutex> l{lock};
- state = Running;
- cond.notify_one();
- }
+ void run()
+ {
+ std::lock_guard<std::mutex> l{ lock };
+ state = Running;
+ cond.notify_one();
+ }
- ~Thread()
- {
- if (worker.joinable())
- {
- {
- std::lock_guard<std::mutex> l{lock};
- state = Dying;
- cond.notify_one();
- }
- worker.join();
- }
- }
- std::thread worker;
- std::condition_variable cond;
- std::mutex lock;
- };
- Thread workers[Size];
- };
+ ~Thread()
+ {
+ if (worker.joinable())
+ {
+ {
+ std::lock_guard<std::mutex> l{ lock };
+ state = Dying;
+ cond.notify_one();
+ }
+ worker.join();
+ }
+ }
+ std::thread worker;
+ std::condition_variable cond;
+ std::mutex lock;
+ };
+ Thread workers[Size];
+};
}
#endif