summaryrefslogtreecommitdiff
path: root/src/mbgl/gl/uniform.hpp
blob: 5a78068fc8bf0421f0c7dfd942179fe9eefed186 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#pragma once

#include <mbgl/gl/types.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/util/ignore.hpp>
#include <mbgl/util/indexed_tuple.hpp>

#include <array>
#include <vector>
#include <map>
#include <functional>

namespace mbgl {
namespace gl {

template <class T>
void bindUniform(UniformLocation, const T&);

template <class Tag, class T>
class UniformValue {
public:
    explicit UniformValue(T t_) : t(std::move(t_)) {}
    T t;
};

class ActiveUniform {
public:
    std::size_t size;
    UniformDataType type;
};

#ifndef NDEBUG

template <class T>
bool verifyUniform(const ActiveUniform&);

using ActiveUniforms = std::map<std::string, ActiveUniform>;
ActiveUniforms activeUniforms(ProgramID);

#endif

template <class Tag, class T>
class Uniform {
public:
    using Value = UniformValue<Tag, T>;

    using Type = T;

    class State {
    public:
        State(UniformLocation location_) : location(std::move(location_)) {}

        void operator=(const Value& value) {
            if (location >= 0 && (!current || *current != value.t)) {
                current = value.t;
                bindUniform(location, value.t);
            }
        }

        UniformLocation location;
        optional<T> current = {};
    };
};

template <class Tag, class T>
using UniformScalar = Uniform<Tag, T>;

template <class Tag, class T, size_t N>
using UniformVector = Uniform<Tag, std::array<T, N>>;

template <class Tag, class T, size_t N>
using UniformMatrix = Uniform<Tag, std::array<T, N*N>>;

#define MBGL_DEFINE_UNIFORM_SCALAR(type_, name_) \
    struct name_ : ::mbgl::gl::UniformScalar<name_, type_> { static auto name() { return #name_; } }

#define MBGL_DEFINE_UNIFORM_VECTOR(type_, n_, name_) \
    struct name_ : ::mbgl::gl::UniformVector<name_, type_, n_> { static auto name() { return #name_; } }

#define MBGL_DEFINE_UNIFORM_MATRIX(type_, n_, name_) \
    struct name_ : ::mbgl::gl::UniformMatrix<name_, type_, n_> { static auto name() { return #name_; } }

UniformLocation uniformLocation(ProgramID, const char * name);

template <class... Us>
class Uniforms {
public:
    using Types = TypeList<Us...>;
    using State = IndexedTuple<TypeList<Us...>, TypeList<typename Us::State...>>;
    using Values = IndexedTuple<TypeList<Us...>, TypeList<typename Us::Value...>>;
    using NamedLocations = std::vector<std::pair<const std::string, UniformLocation>>;

    static State bindLocations(const ProgramID& id) {
#ifndef NDEBUG
        // Verify active uniform types match the enum
        const auto active = activeUniforms(id);

        util::ignore(
            { // Some shader programs have uniforms declared, but not used, so they're not active.
              // Therefore, we'll only verify them when they are indeed active.
              (active.find(Us::name()) != active.end()
                   ? verifyUniform<typename Us::Type>(active.at(Us::name()))
                   : false)... });
#endif

        return State { { uniformLocation(id, Us::name()) }... };
    }

    template <class Program>
    static State loadNamedLocations(const Program& program) {
        return State(typename Us::State(program.uniformLocation(Us::name()))...);
    }

    static NamedLocations getNamedLocations(const State& state) {
        return NamedLocations{ { Us::name(), state.template get<Us>().location }... };
    }

    static void bind(State& state, const Values& values) {
        util::ignore({ (state.template get<Us>() = values.template get<Us>(), 0)... });
    }
};


namespace detail {

template <class...>
struct ConcatenateUniforms;

template <class... As, class... Bs>
struct ConcatenateUniforms<TypeList<As...>, TypeList<Bs...>> {
    using Type = Uniforms<As..., Bs...>;
};

} // namespace detail

template <class A, class B>
using ConcatenateUniforms = typename detail::ConcatenateUniforms<
    typename A::Types,
    typename B::Types>::Type;

} // namespace gl
} // namespace mbgl