#pragma once #include #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(location_) {} UniformState& operator=(const Value& value) { if (location >= 0 && (!current || *current != value)) { current = value; bindUniform(location, value); } return *this; } 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(concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value()) != active.end() ? verifyUniform(active.at(concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value())) : false)... }); #endif state = State{ gl::uniformLocation(id, concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value())... }; } NamedUniformLocations getNamedLocations() const { return NamedUniformLocations{ { concat_literals<&string_literal<'u', '_'>::value, &Us::name>::value(), state.template get().location }... }; } void bind(const gfx::UniformValues>& values) { util::ignore({ (state.template get() = values.template get(), 0)... }); } }; } // namespace gl } // namespace mbgl