summaryrefslogtreecommitdiffstats
path: root/thirdparty/spirv-cross/include/spirv_cross
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/spirv-cross/include/spirv_cross')
-rw-r--r--thirdparty/spirv-cross/include/spirv_cross/barrier.hpp80
-rw-r--r--thirdparty/spirv-cross/include/spirv_cross/external_interface.h127
-rw-r--r--thirdparty/spirv-cross/include/spirv_cross/image.hpp63
-rw-r--r--thirdparty/spirv-cross/include/spirv_cross/internal_interface.hpp604
-rw-r--r--thirdparty/spirv-cross/include/spirv_cross/sampler.hpp106
-rw-r--r--thirdparty/spirv-cross/include/spirv_cross/thread_group.hpp114
6 files changed, 1094 insertions, 0 deletions
diff --git a/thirdparty/spirv-cross/include/spirv_cross/barrier.hpp b/thirdparty/spirv-cross/include/spirv_cross/barrier.hpp
new file mode 100644
index 0000000000..4ca7f4d77c
--- /dev/null
+++ b/thirdparty/spirv-cross/include/spirv_cross/barrier.hpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2015-2017 ARM Limited
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SPIRV_CROSS_BARRIER_HPP
+#define SPIRV_CROSS_BARRIER_HPP
+
+#include <atomic>
+#include <thread>
+
+namespace spirv_cross
+{
+class Barrier
+{
+public:
+ Barrier()
+ {
+ count.store(0);
+ iteration.store(0);
+ }
+
+ void set_release_divisor(unsigned divisor)
+ {
+ this->divisor = divisor;
+ }
+
+ static inline void memoryBarrier()
+ {
+ std::atomic_thread_fence(std::memory_order_seq_cst);
+ }
+
+ 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;
+
+ // 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();
+ }
+ }
+
+private:
+ unsigned divisor = 1;
+ std::atomic<unsigned> count;
+ std::atomic<unsigned> iteration;
+};
+}
+
+#endif
diff --git a/thirdparty/spirv-cross/include/spirv_cross/external_interface.h b/thirdparty/spirv-cross/include/spirv_cross/external_interface.h
new file mode 100644
index 0000000000..949654f5bf
--- /dev/null
+++ b/thirdparty/spirv-cross/include/spirv_cross/external_interface.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2015-2017 ARM Limited
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SPIRV_CROSS_EXTERNAL_INTERFACE_H
+#define SPIRV_CROSS_EXTERNAL_INTERFACE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h>
+
+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);
+};
+
+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_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_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);
+
+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;
+
+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
+#define SPIRV_CROSS_NUM_STAGE_INPUTS 16
+#define SPIRV_CROSS_NUM_STAGE_OUTPUTS 16
+#define SPIRV_CROSS_NUM_UNIFORM_CONSTANTS 32
+
+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_NUM_FORMATS
+};
+
+enum spirv_cross_wrap
+{
+ SPIRV_CROSS_WRAP_CLAMP_TO_EDGE = 0,
+ SPIRV_CROSS_WRAP_REPEAT = 1,
+
+ SPIRV_CROSS_NUM_WRAP
+};
+
+enum spirv_cross_filter
+{
+ SPIRV_CROSS_FILTER_NEAREST = 0,
+ SPIRV_CROSS_FILTER_LINEAR = 1,
+
+ 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_NUM_MIPFILTER
+};
+
+struct spirv_cross_miplevel
+{
+ 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;
+};
+
+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
+
+#endif
diff --git a/thirdparty/spirv-cross/include/spirv_cross/image.hpp b/thirdparty/spirv-cross/include/spirv_cross/image.hpp
new file mode 100644
index 0000000000..a41ccdfbb4
--- /dev/null
+++ b/thirdparty/spirv-cross/include/spirv_cross/image.hpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2015-2017 ARM Limited
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SPIRV_CROSS_IMAGE_HPP
+#define SPIRV_CROSS_IMAGE_HPP
+
+#ifndef GLM_SWIZZLE
+#define GLM_SWIZZLE
+#endif
+
+#ifndef GLM_FORCE_RADIANS
+#define GLM_FORCE_RADIANS
+#endif
+
+#include <glm/glm.hpp>
+
+namespace spirv_cross
+{
+template <typename T>
+struct image2DBase
+{
+ virtual ~image2DBase() = default;
+ inline virtual T load(glm::ivec2 coord) const
+ {
+ 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;
+
+template <typename T>
+inline T imageLoad(const image2DBase<T> &image, glm::ivec2 coord)
+{
+ return image.load(coord);
+}
+
+template <typename T>
+void imageStore(image2DBase<T> &image, glm::ivec2 coord, const T &value)
+{
+ image.store(coord, value);
+}
+}
+
+#endif
diff --git a/thirdparty/spirv-cross/include/spirv_cross/internal_interface.hpp b/thirdparty/spirv-cross/include/spirv_cross/internal_interface.hpp
new file mode 100644
index 0000000000..3ff7f8e258
--- /dev/null
+++ b/thirdparty/spirv-cross/include/spirv_cross/internal_interface.hpp
@@ -0,0 +1,604 @@
+/*
+ * Copyright 2015-2017 ARM Limited
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SPIRV_CROSS_INTERNAL_INTERFACE_HPP
+#define SPIRV_CROSS_INTERNAL_INTERFACE_HPP
+
+// This file must only be included by the shader generated by spirv-cross!
+
+#ifndef GLM_FORCE_SWIZZLE
+#define GLM_FORCE_SWIZZLE
+#endif
+
+#ifndef GLM_FORCE_RADIANS
+#define GLM_FORCE_RADIANS
+#endif
+
+#include <glm/glm.hpp>
+
+#include "barrier.hpp"
+#include "external_interface.h"
+#include "image.hpp"
+#include "sampler.hpp"
+#include "thread_group.hpp"
+#include <assert.h>
+#include <stdint.h>
+
+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>
+{
+};
+}
+
+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;
+ }
+};
+
+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);
+ }
+#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);
+ }
+#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__);
+ }
+#define gl_WorkGroupID __res->gl_WorkGroupID__.get()
+#define gl_NumWorkGroups __res->gl_NumWorkGroups__.get()
+
+ Barrier barrier__;
+#define barrier() __res->barrier__.wait()
+};
+
+struct ComputePrivateResources
+{
+ uint32_t gl_LocalInvocationIndex__;
+#define gl_LocalInvocationIndex __priv_res.gl_LocalInvocationIndex__
+ glm::uvec3 gl_LocalInvocationID__;
+#define gl_LocalInvocationID __priv_res.gl_LocalInvocationID__
+ 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);
+}
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+void spirv_cross_set_push_constant(spirv_cross_shader_t *shader, void *data, size_t 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)
+{
+ shader->set_builtin(builtin, data, size);
+}
+
+#endif
diff --git a/thirdparty/spirv-cross/include/spirv_cross/sampler.hpp b/thirdparty/spirv-cross/include/spirv_cross/sampler.hpp
new file mode 100644
index 0000000000..0208480951
--- /dev/null
+++ b/thirdparty/spirv-cross/include/spirv_cross/sampler.hpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2015-2017 ARM Limited
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SPIRV_CROSS_SAMPLER_HPP
+#define SPIRV_CROSS_SAMPLER_HPP
+
+#include <vector>
+
+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;
+ }
+
+ inline virtual T sample(glm::vec2 uv, float bias)
+ {
+ return sampleLod(uv, bias);
+ }
+
+ 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);
+
+ 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 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);
+ }
+
+ default:
+ return 0.0f;
+ }
+ }
+
+ std::vector<spirv_cross_miplevel> mips;
+ spirv_cross_format format;
+ spirv_cross_wrap wrap_s;
+ spirv_cross_wrap wrap_t;
+ spirv_cross_filter min_filter;
+ spirv_cross_filter mag_filter;
+ spirv_cross_mipfilter mip_filter;
+};
+
+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/thirdparty/spirv-cross/include/spirv_cross/thread_group.hpp b/thirdparty/spirv-cross/include/spirv_cross/thread_group.hpp
new file mode 100644
index 0000000000..b215581562
--- /dev/null
+++ b/thirdparty/spirv-cross/include/spirv_cross/thread_group.hpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2015-2017 ARM Limited
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SPIRV_CROSS_THREAD_GROUP_HPP
+#define SPIRV_CROSS_THREAD_GROUP_HPP
+
+#include <condition_variable>
+#include <mutex>
+#include <thread>
+
+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]);
+ }
+
+ void run()
+ {
+ for (auto &worker : workers)
+ worker.run();
+ }
+
+ void wait()
+ {
+ for (auto &worker : workers)
+ worker.wait();
+ }
+
+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;
+ }
+
+ impl->main();
+
+ 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 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];
+};
+}
+
+#endif