1 #pragma once 2 3 #include <mbgl/gl/types.hpp> 4 #include <mbgl/util/optional.hpp> 5 #include <mbgl/util/ignore.hpp> 6 #include <mbgl/util/indexed_tuple.hpp> 7 8 #include <array> 9 #include <vector> 10 #include <map> 11 #include <functional> 12 13 namespace mbgl { 14 namespace gl { 15 16 template <class T> 17 void bindUniform(UniformLocation, const T&); 18 19 template <class Tag, class T> 20 class UniformValue { 21 public: UniformValue(T t_)22 explicit UniformValue(T t_) : t(std::move(t_)) {} 23 T t; 24 }; 25 26 class ActiveUniform { 27 public: 28 std::size_t size; 29 UniformDataType type; 30 }; 31 32 #ifndef NDEBUG 33 34 template <class T> 35 bool verifyUniform(const ActiveUniform&); 36 37 using ActiveUniforms = std::map<std::string, ActiveUniform>; 38 ActiveUniforms activeUniforms(ProgramID); 39 40 #endif 41 42 template <class Tag, class T> 43 class Uniform { 44 public: 45 using Value = UniformValue<Tag, T>; 46 47 using Type = T; 48 49 class State { 50 public: State(UniformLocation location_)51 State(UniformLocation location_) : location(std::move(location_)) {} 52 operator =(const Value & value)53 void operator=(const Value& value) { 54 if (location >= 0 && (!current || *current != value.t)) { 55 current = value.t; 56 bindUniform(location, value.t); 57 } 58 } 59 60 UniformLocation location; 61 optional<T> current = {}; 62 }; 63 }; 64 65 template <class Tag, class T> 66 using UniformScalar = Uniform<Tag, T>; 67 68 template <class Tag, class T, size_t N> 69 using UniformVector = Uniform<Tag, std::array<T, N>>; 70 71 template <class Tag, class T, size_t N> 72 using UniformMatrix = Uniform<Tag, std::array<T, N*N>>; 73 74 #define MBGL_DEFINE_UNIFORM_SCALAR(type_, name_) \ 75 struct name_ : ::mbgl::gl::UniformScalar<name_, type_> { static auto name() { return #name_; } } 76 77 #define MBGL_DEFINE_UNIFORM_VECTOR(type_, n_, name_) \ 78 struct name_ : ::mbgl::gl::UniformVector<name_, type_, n_> { static auto name() { return #name_; } } 79 80 #define MBGL_DEFINE_UNIFORM_MATRIX(type_, n_, name_) \ 81 struct name_ : ::mbgl::gl::UniformMatrix<name_, type_, n_> { static auto name() { return #name_; } } 82 83 UniformLocation uniformLocation(ProgramID, const char * name); 84 85 template <class... Us> 86 class Uniforms { 87 public: 88 using Types = TypeList<Us...>; 89 using State = IndexedTuple<TypeList<Us...>, TypeList<typename Us::State...>>; 90 using Values = IndexedTuple<TypeList<Us...>, TypeList<typename Us::Value...>>; 91 using NamedLocations = std::vector<std::pair<const std::string, UniformLocation>>; 92 bindLocations(const ProgramID & id)93 static State bindLocations(const ProgramID& id) { 94 #ifndef NDEBUG 95 // Verify active uniform types match the enum 96 const auto active = activeUniforms(id); 97 98 util::ignore( 99 { // Some shader programs have uniforms declared, but not used, so they're not active. 100 // Therefore, we'll only verify them when they are indeed active. 101 (active.find(Us::name()) != active.end() 102 ? verifyUniform<typename Us::Type>(active.at(Us::name())) 103 : false)... }); 104 #endif 105 106 return State { { uniformLocation(id, Us::name()) }... }; 107 } 108 109 template <class Program> loadNamedLocations(const Program & program)110 static State loadNamedLocations(const Program& program) { 111 return State(typename Us::State(program.uniformLocation(Us::name()))...); 112 } 113 getNamedLocations(const State & state)114 static NamedLocations getNamedLocations(const State& state) { 115 return NamedLocations{ { Us::name(), state.template get<Us>().location }... }; 116 } 117 bind(State & state,const Values & values)118 static void bind(State& state, const Values& values) { 119 util::ignore({ (state.template get<Us>() = values.template get<Us>(), 0)... }); 120 } 121 }; 122 123 124 namespace detail { 125 126 template <class...> 127 struct ConcatenateUniforms; 128 129 template <class... As, class... Bs> 130 struct ConcatenateUniforms<TypeList<As...>, TypeList<Bs...>> { 131 using Type = Uniforms<As..., Bs...>; 132 }; 133 134 } // namespace detail 135 136 template <class A, class B> 137 using ConcatenateUniforms = typename detail::ConcatenateUniforms< 138 typename A::Types, 139 typename B::Types>::Type; 140 141 } // namespace gl 142 } // namespace mbgl 143