#pragma once #include #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); using NamedUniformLocations = std::vector>; template class UniformStates; template class UniformStates> final { private: using State = IndexedTuple, TypeList...>>; State state; public: void queryLocations(const ProgramID& id) { #ifndef NDEBUG // Verify active uniform types match the enum const auto active = gl::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 state = State{ gl::uniformLocation(id, Us::name())... }; } template void loadNamedLocations(const BinaryProgram& program) { state = State{ UniformState(program.uniformLocation(Us::name()))... }; } NamedUniformLocations getNamedLocations() const { return NamedUniformLocations{ { Us::name(), state.template get().location }... }; } void bind(const gfx::UniformValues>& values) { util::ignore({ (state.template get() = values.template get(), 0)... }); } }; } // namespace gl } // namespace mbgl