diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2018-05-04 01:31:43 +0200 |
---|---|---|
committer | Lauren Budorick <lauren@mapbox.com> | 2018-05-03 16:31:43 -0700 |
commit | c3346f473ac7e3d49219c8dbc381d92f8fe3f017 (patch) | |
tree | 7e7d1c1569c849192209b0c5f5a58ef7736896a1 /src/mbgl/gl | |
parent | f6da3ba9be27ff9b279730603c517c4cb5e57007 (diff) | |
download | qtlocation-mapboxgl-c3346f473ac7e3d49219c8dbc381d92f8fe3f017.tar.gz |
[core] Don't crash when attribute count is exceeded
Diffstat (limited to 'src/mbgl/gl')
-rw-r--r-- | src/mbgl/gl/attribute.cpp | 14 | ||||
-rw-r--r-- | src/mbgl/gl/attribute.hpp | 18 | ||||
-rw-r--r-- | src/mbgl/gl/context.cpp | 10 | ||||
-rw-r--r-- | src/mbgl/gl/context.hpp | 4 | ||||
-rw-r--r-- | src/mbgl/gl/program.hpp | 2 | ||||
-rw-r--r-- | src/mbgl/gl/vertex_array.cpp | 6 | ||||
-rw-r--r-- | src/mbgl/gl/vertex_array.hpp | 13 |
7 files changed, 42 insertions, 25 deletions
diff --git a/src/mbgl/gl/attribute.cpp b/src/mbgl/gl/attribute.cpp index bb5b2ddc34..b2d05fe665 100644 --- a/src/mbgl/gl/attribute.cpp +++ b/src/mbgl/gl/attribute.cpp @@ -1,14 +1,20 @@ #include <mbgl/gl/attribute.hpp> +#include <mbgl/gl/context.hpp> #include <mbgl/gl/gl.hpp> namespace mbgl { namespace gl { -void bindAttributeLocation(ProgramID id, AttributeLocation location, const char* name) { - if (location >= MAX_ATTRIBUTES) { - throw gl::Error("too many vertex attributes"); +void bindAttributeLocation(Context& context, ProgramID id, AttributeLocation location, const char* name) { + // We're using sequentially numberered attribute locations starting with 0. Therefore we can use + // the location as a proxy for the number of attributes. + if (location >= context.maximumVertexBindingCount) { + // Don't bind the location on this hardware since it exceeds the limit (otherwise we'd get + // an OpenGL error). This means we'll see rendering errors, and possibly slow rendering due + // to unbound attributes. + } else { + MBGL_CHECK_ERROR(glBindAttribLocation(id, location, name)); } - MBGL_CHECK_ERROR(glBindAttribLocation(id, location, name)); } std::set<std::string> getActiveAttributes(ProgramID id) { diff --git a/src/mbgl/gl/attribute.hpp b/src/mbgl/gl/attribute.hpp index fa6c2ddeab..3763f0a583 100644 --- a/src/mbgl/gl/attribute.hpp +++ b/src/mbgl/gl/attribute.hpp @@ -17,8 +17,6 @@ namespace mbgl { namespace gl { -static constexpr std::size_t MAX_ATTRIBUTES = 8; - template <class> struct DataTypeOf; template <> struct DataTypeOf< int8_t> : std::integral_constant<DataType, DataType::Byte> {}; template <> struct DataTypeOf<uint8_t> : std::integral_constant<DataType, DataType::UnsignedByte> {}; @@ -45,7 +43,7 @@ public: } }; -using AttributeBindingArray = std::array<optional<AttributeBinding>, MAX_ATTRIBUTES>; +using AttributeBindingArray = std::vector<optional<AttributeBinding>>; /* gl::Attribute<T,N> manages the binding of a vertex buffer to a GL program attribute. @@ -214,7 +212,8 @@ const std::size_t Vertex<A1, A2, A3, A4, A5>::attributeOffsets[5] = { } // namespace detail -void bindAttributeLocation(ProgramID, AttributeLocation, const char * name); +class Context; +void bindAttributeLocation(Context&, ProgramID, AttributeLocation, const char * name); std::set<std::string> getActiveAttributes(ProgramID); template <class... As> @@ -231,13 +230,13 @@ public: using Vertex = detail::Vertex<typename As::Type...>; - static Locations bindLocations(const ProgramID& id) { + static Locations bindLocations(Context& context, const ProgramID& id) { std::set<std::string> activeAttributes = getActiveAttributes(id); AttributeLocation location = 0; auto maybeBindLocation = [&](const char* name) -> optional<AttributeLocation> { if (activeAttributes.count(name)) { - bindAttributeLocation(id, location, name); + bindAttributeLocation(context, id, location, name); return location++; } else { return {}; @@ -277,6 +276,7 @@ public: static AttributeBindingArray toBindingArray(const Locations& locations, const Bindings& bindings) { AttributeBindingArray result; + result.resize(sizeof...(As)); auto maybeAddBinding = [&] (const optional<AttributeLocation>& location, const optional<AttributeBinding>& binding) { @@ -289,6 +289,12 @@ public: return result; } + + static uint32_t activeBindingCount(const Bindings& bindings) { + uint32_t result = 0; + util::ignore({ ((result += bool(bindings.template get<As>())), 0)... }); + return result; + } }; namespace detail { diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index ba44adb42b..c6352d3e84 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -94,7 +94,13 @@ static_assert(underlying_type(BufferUsage::DynamicDraw) == GL_DYNAMIC_DRAW, "Ope static_assert(std::is_same<BinaryProgramFormat, GLenum>::value, "OpenGL type mismatch"); -Context::Context() = default; +Context::Context() + : maximumVertexBindingCount([] { + GLint value; + MBGL_CHECK_ERROR(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &value)); + return value; + }()) { +} Context::~Context() { if (cleanupOnDestruction) { @@ -351,7 +357,7 @@ VertexArray Context::createVertexArray() { VertexArrayID id = 0; MBGL_CHECK_ERROR(vertexArray->genVertexArrays(1, &id)); UniqueVertexArray vao(std::move(id), { this }); - return { UniqueVertexArrayState(new VertexArrayState(std::move(vao), *this), VertexArrayStateDeleter { true })}; + return { UniqueVertexArrayState(new VertexArrayState(std::move(vao)), VertexArrayStateDeleter { true })}; } else { // On GL implementations which do not support vertex arrays, attribute bindings are global state. // So return a VertexArray which shares our global state tracking and whose deleter is a no-op. diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 67624288e2..d95311115e 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -226,7 +226,7 @@ public: State<value::BindVertexBuffer> vertexBuffer; State<value::BindVertexArray, const Context&> bindVertexArray { *this }; - VertexArrayState globalVertexArrayState { UniqueVertexArray(0, { this }), *this }; + VertexArrayState globalVertexArrayState { UniqueVertexArray(0, { this }) }; State<value::PixelStorePack> pixelStorePack; State<value::PixelStoreUnpack> pixelStoreUnpack; @@ -239,6 +239,8 @@ public: #endif // MBGL_USE_GLES2 bool supportsHalfFloatTextures = false; + const uint32_t maximumVertexBindingCount; + static constexpr const uint32_t minimumRequiredVertexBindingCount = 8; private: State<value::StencilFunc> stencilFunc; diff --git a/src/mbgl/gl/program.hpp b/src/mbgl/gl/program.hpp index af02ad3d54..f33501cd11 100644 --- a/src/mbgl/gl/program.hpp +++ b/src/mbgl/gl/program.hpp @@ -35,7 +35,7 @@ public: context.createProgram(context.createShader(ShaderType::Vertex, vertexSource), context.createShader(ShaderType::Fragment, fragmentSource))), uniformsState((context.linkProgram(program), Uniforms::bindLocations(program))), - attributeLocations(Attributes::bindLocations(program)) { + attributeLocations(Attributes::bindLocations(context, program)) { // Re-link program after manually binding only active attributes in Attributes::bindLocations context.linkProgram(program); diff --git a/src/mbgl/gl/vertex_array.cpp b/src/mbgl/gl/vertex_array.cpp index 68a500ac45..d552a8292e 100644 --- a/src/mbgl/gl/vertex_array.cpp +++ b/src/mbgl/gl/vertex_array.cpp @@ -9,7 +9,11 @@ void VertexArray::bind(Context& context, BufferID indexBuffer, const AttributeBi context.bindVertexArray = state->vertexArray; state->indexBuffer = indexBuffer; - for (AttributeLocation location = 0; location < MAX_ATTRIBUTES; ++location) { + state->bindings.reserve(bindings.size()); + for (AttributeLocation location = 0; location < bindings.size(); ++location) { + if (state->bindings.size() <= location) { + state->bindings.emplace_back(context, AttributeLocation(location)); + } state->bindings[location] = bindings[location]; } } diff --git a/src/mbgl/gl/vertex_array.hpp b/src/mbgl/gl/vertex_array.hpp index 46c67017bb..604754f672 100644 --- a/src/mbgl/gl/vertex_array.hpp +++ b/src/mbgl/gl/vertex_array.hpp @@ -15,9 +15,8 @@ class Context; class VertexArrayState { public: - VertexArrayState(UniqueVertexArray vertexArray_, Context& context) - : vertexArray(std::move(vertexArray_)), - bindings(makeBindings(context, std::make_index_sequence<MAX_ATTRIBUTES>())) { + VertexArrayState(UniqueVertexArray vertexArray_) + : vertexArray(std::move(vertexArray_)) { } void setDirty() { @@ -31,13 +30,7 @@ public: State<value::BindElementBuffer> indexBuffer; using AttributeState = State<value::VertexAttribute, Context&, AttributeLocation>; - std::array<AttributeState, MAX_ATTRIBUTES> bindings; - -private: - template <std::size_t... I> - std::array<AttributeState, MAX_ATTRIBUTES> makeBindings(Context& context, std::index_sequence<I...>) { - return {{ AttributeState { context, I }... }}; - } + std::vector<AttributeState> bindings; }; class VertexArrayStateDeleter { |