[core] Bind only active attributes in order to avoid exceeding attribute limits (#9373)
Introducing two new attributes to enable property functions for line-width (#9250) pushed the attribute count over GL_MAX_VERTEX_ATTRIBS on some devices. Now we selectively bind only attributes that are used, making it unlikely to surpass GL_MAX_VERTEX_ATTRIBS.
This commit is contained in:
committed by
John Firebaugh
parent
e8272ebdbb
commit
eed89fcf9d
@@ -2,14 +2,55 @@
|
||||
#include <mbgl/gl/context.hpp>
|
||||
#include <mbgl/gl/gl.hpp>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace mbgl {
|
||||
namespace gl {
|
||||
|
||||
AttributeLocation bindAttributeLocation(ProgramID id, AttributeLocation location, const char* name) {
|
||||
assert(location < 8);
|
||||
MBGL_CHECK_ERROR(glBindAttribLocation(id, location, name));
|
||||
return location;
|
||||
}
|
||||
|
||||
int32_t getActiveAttributeCount(ProgramID id) {
|
||||
GLint numAttributes;
|
||||
MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_ATTRIBUTES, &numAttributes));
|
||||
return numAttributes;
|
||||
}
|
||||
|
||||
int32_t getMaxAttributeNameLength(ProgramID id) {
|
||||
GLint nameLength;
|
||||
MBGL_CHECK_ERROR(glGetProgramiv(id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &nameLength));
|
||||
return nameLength;
|
||||
}
|
||||
|
||||
std::string getAttributeName(ProgramID id, int32_t maxLength, AttributeLocation location) {
|
||||
std::string attributeName;
|
||||
attributeName.resize(maxLength);
|
||||
GLsizei actualLength;
|
||||
GLint size;
|
||||
GLenum type;
|
||||
MBGL_CHECK_ERROR(glGetActiveAttrib(id, static_cast<GLuint>(location),
|
||||
static_cast<GLsizei>(maxLength), &actualLength, &size, &type,
|
||||
const_cast<char*>(attributeName.data())));
|
||||
attributeName.resize(actualLength);
|
||||
return attributeName;
|
||||
}
|
||||
|
||||
std::set<std::string> getActiveAttributes(ProgramID id) {
|
||||
std::set<std::string> activeAttributes;
|
||||
|
||||
GLint attributeCount = getActiveAttributeCount(id);
|
||||
GLint maxAttributeLength = getMaxAttributeNameLength(id);
|
||||
|
||||
for (int32_t i = 0; i < attributeCount; i++) {
|
||||
activeAttributes.emplace(getAttributeName(id, maxAttributeLength, i));
|
||||
}
|
||||
|
||||
return activeAttributes;
|
||||
}
|
||||
|
||||
void DisabledAttribute::bind(Context&, AttributeLocation location, std::size_t) const {
|
||||
MBGL_CHECK_ERROR(glDisableVertexAttribArray(location));
|
||||
}
|
||||
@@ -25,6 +66,11 @@ template <> DataType DataTypeOf<float> = DataType::Float;
|
||||
|
||||
template <class T, std::size_t N>
|
||||
void AttributeBinding<T, N>::bind(Context& context, AttributeLocation location, std::size_t vertexOffset) const {
|
||||
// FillProgram will attempt to bind at location -1 because it includes
|
||||
// a fill-outline-color paint property but does not use it or have an
|
||||
// a_outline_color shader attribute - in this case, we have nothing to bind.
|
||||
if (location == -1) return;
|
||||
|
||||
context.vertexBuffer = vertexBuffer;
|
||||
MBGL_CHECK_ERROR(glEnableVertexAttribArray(location));
|
||||
MBGL_CHECK_ERROR(glVertexAttribPointer(
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <functional>
|
||||
|
||||
namespace mbgl {
|
||||
@@ -223,6 +224,7 @@ const std::size_t Vertex<A1, A2, A3, A4, A5>::attributeOffsets[5] = {
|
||||
} // namespace detail
|
||||
|
||||
AttributeLocation bindAttributeLocation(ProgramID, AttributeLocation, const char * name);
|
||||
std::set<std::string> getActiveAttributes(ProgramID);
|
||||
|
||||
template <class... As>
|
||||
class Attributes {
|
||||
@@ -242,7 +244,15 @@ public:
|
||||
static constexpr std::size_t Index = TypeIndex<A, As...>::value;
|
||||
|
||||
static Locations bindLocations(const ProgramID& id) {
|
||||
return Locations { bindAttributeLocation(id, Index<As>, As::name())... };
|
||||
std::set<std::string> activeAttributes = getActiveAttributes(id);
|
||||
|
||||
AttributeLocation location = -1;
|
||||
auto bindAndIncrement = [&](const char* name) {
|
||||
location++;
|
||||
return bindAttributeLocation(id, location, name);
|
||||
};
|
||||
return Locations{ (activeAttributes.count(As::name()) ? bindAndIncrement(As::name())
|
||||
: -1)... };
|
||||
}
|
||||
|
||||
template <class Program>
|
||||
|
||||
@@ -33,15 +33,17 @@ public:
|
||||
: program(
|
||||
context.createProgram(context.createShader(ShaderType::Vertex, vertexSource),
|
||||
context.createShader(ShaderType::Fragment, fragmentSource))),
|
||||
attributeLocations(Attributes::bindLocations(program)),
|
||||
uniformsState((context.linkProgram(program), Uniforms::bindLocations(program))) {
|
||||
uniformsState((context.linkProgram(program), Uniforms::bindLocations(program))),
|
||||
attributeLocations(Attributes::bindLocations(program)) {
|
||||
// Re-link program after manually binding only active attributes in Attributes::bindLocations
|
||||
context.linkProgram(program);
|
||||
}
|
||||
|
||||
template <class BinaryProgram>
|
||||
Program(Context& context, const BinaryProgram& binaryProgram)
|
||||
: program(context.createProgram(binaryProgram.format(), binaryProgram.code())),
|
||||
attributeLocations(Attributes::loadNamedLocations(binaryProgram)),
|
||||
uniformsState(Uniforms::loadNamedLocations(binaryProgram)) {
|
||||
uniformsState(Uniforms::loadNamedLocations(binaryProgram)),
|
||||
attributeLocations(Attributes::loadNamedLocations(binaryProgram)) {
|
||||
}
|
||||
|
||||
static Program createProgram(gl::Context& context,
|
||||
@@ -144,8 +146,8 @@ public:
|
||||
private:
|
||||
UniqueProgram program;
|
||||
|
||||
typename Attributes::Locations attributeLocations;
|
||||
typename Uniforms::State uniformsState;
|
||||
typename Attributes::Locations attributeLocations;
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
|
||||
Reference in New Issue
Block a user