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