#pragma once #include #include #include #include #include #include #include #include namespace mbgl { namespace gl { template void bindUniform(UniformLocation, const T&); class ActiveUniform { public: std::size_t size; UniformDataType type; }; #ifndef NDEBUG template bool verifyUniform(const ActiveUniform&); using ActiveUniforms = std::map; ActiveUniforms activeUniforms(ProgramID); #endif template class UniformState { public: UniformState(UniformLocation location_ = -1) : location(std::move(location_)) { } void operator=(const Value& value) { if (location >= 0 && (!current || *current != value)) { current = value; bindUniform(location, value); } } UniformLocation location; optional current = {}; }; UniformLocation uniformLocation(ProgramID, const char * name); template class Uniforms; template class Uniforms> final { public: using Types = TypeList; using State = IndexedTuple, TypeList...>>; using Values = IndexedTuple, TypeList>; using NamedLocations = std::vector>; 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(active.at(Us::name())) : false)... }); #endif return State(uniformLocation(id, Us::name())...); } template static State loadNamedLocations(const Program& program) { return State(UniformState(program.uniformLocation(Us::name()))...); } static NamedLocations getNamedLocations(const State& state) { return NamedLocations{ { Us::name(), state.template get().location }... }; } static void bind(State& state, const Values& values) { util::ignore({ (state.template get() = values.template get(), 0)... }); } }; } // namespace gl } // namespace mbgl