| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604 |
- /*
- * 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
|