diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2016-07-07 19:13:16 +0200 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2016-07-08 13:11:25 +0200 |
commit | 4f26c8122a57cd5fe35a10dc2e125500179a75a5 (patch) | |
tree | 02381c3db2adedcc6afa721137a6fb318ec915dd | |
parent | aaa30c8a19bd608baf4c190f794258919365c36d (diff) | |
download | qtlocation-mapboxgl-4f26c8122a57cd5fe35a10dc2e125500179a75a5.tar.gz |
[core] track texture state to avoid redundand binds
29 files changed, 159 insertions, 99 deletions
diff --git a/include/mbgl/gl/gl_values.hpp b/include/mbgl/gl/gl_values.hpp index b15ef18f48..29a5281cca 100644 --- a/include/mbgl/gl/gl_values.hpp +++ b/include/mbgl/gl/gl_values.hpp @@ -3,6 +3,7 @@ #include <cstdint> #include <tuple> #include <array> +#include <cassert> #include <mbgl/gl/gl.hpp> #include <mbgl/util/color.hpp> @@ -258,15 +259,15 @@ struct LineWidth { }; struct ActiveTexture { - using Type = GLint; + using Type = uint8_t; static const Type Default; static void Set(const Type& value) { - MBGL_CHECK_ERROR(glActiveTexture(value)); + MBGL_CHECK_ERROR(glActiveTexture(GL_TEXTURE0 + value)); } static Type Get() { - Type activeTexture; + GLint activeTexture; MBGL_CHECK_ERROR(glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture)); - return activeTexture; + return activeTexture - GL_TEXTURE0; } }; @@ -305,5 +306,18 @@ struct RasterPos { #endif // GL_ES_VERSION_2_0 +struct BindTexture { + using Type = GLuint; + static const Type Default; + static void Set(const Type& value) { + MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, value)); + } + static Type Get() { + GLint texture; + MBGL_CHECK_ERROR(glGetIntegerv(GL_TEXTURE_BINDING_2D, &texture)); + return texture; + } +}; + } // namespace gl } // namespace mbgl diff --git a/src/mbgl/geometry/glyph_atlas.cpp b/src/mbgl/geometry/glyph_atlas.cpp index c45a93d24e..cfc5962eb3 100644 --- a/src/mbgl/geometry/glyph_atlas.cpp +++ b/src/mbgl/geometry/glyph_atlas.cpp @@ -2,6 +2,7 @@ #include <mbgl/gl/gl.hpp> #include <mbgl/gl/object_store.hpp> +#include <mbgl/gl/gl_config.hpp> #include <mbgl/platform/log.hpp> #include <mbgl/platform/platform.hpp> @@ -141,13 +142,14 @@ void GlyphAtlas::removeGlyphs(uintptr_t tileUID) { } } -void GlyphAtlas::upload(gl::ObjectStore& store) { +void GlyphAtlas::upload(gl::ObjectStore& store, gl::Config& config, uint32_t unit) { if (dirty) { const bool first = !texture; - bind(store); + bind(store, config, unit); std::lock_guard<std::mutex> lock(mtx); + config.activeTexture = unit; if (first) { MBGL_CHECK_ERROR(glTexImage2D( GL_TEXTURE_2D, // GLenum target @@ -182,10 +184,11 @@ void GlyphAtlas::upload(gl::ObjectStore& store) { } } -void GlyphAtlas::bind(gl::ObjectStore& store) { +void GlyphAtlas::bind(gl::ObjectStore& store, gl::Config& config, uint32_t unit) { if (!texture) { texture = store.createTexture(); - MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture)); + config.activeTexture = unit; + config.texture[unit] = *texture; #ifndef GL_ES_VERSION_2_0 MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); #endif @@ -193,8 +196,9 @@ void GlyphAtlas::bind(gl::ObjectStore& store) { MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); - } else { - MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture)); + } else if (config.texture[unit] != *texture) { + config.activeTexture = unit; + config.texture[unit] = *texture; } } diff --git a/src/mbgl/geometry/glyph_atlas.hpp b/src/mbgl/geometry/glyph_atlas.hpp index b1fc9d5747..5252963f51 100644 --- a/src/mbgl/geometry/glyph_atlas.hpp +++ b/src/mbgl/geometry/glyph_atlas.hpp @@ -15,6 +15,10 @@ namespace mbgl { +namespace gl { +class Config; +} // namespace gl + class GlyphAtlas : public util::noncopyable { public: GlyphAtlas(uint16_t width, uint16_t height); @@ -28,11 +32,11 @@ public: void removeGlyphs(uintptr_t tileUID); // Binds the atlas texture to the GPU, and uploads data if it is out of date. - void bind(gl::ObjectStore&); + void bind(gl::ObjectStore&, gl::Config&, uint32_t unit); // Uploads the texture to the GPU to be available when we need it. This is a lazy operation; // the texture is only bound when the data is out of date (=dirty). - void upload(gl::ObjectStore&); + void upload(gl::ObjectStore&, gl::Config&, uint32_t unit); const GLsizei width; const GLsizei height; diff --git a/src/mbgl/geometry/line_atlas.cpp b/src/mbgl/geometry/line_atlas.cpp index d7ae5b4a60..f08ea1e5fc 100644 --- a/src/mbgl/geometry/line_atlas.cpp +++ b/src/mbgl/geometry/line_atlas.cpp @@ -1,6 +1,7 @@ #include <mbgl/geometry/line_atlas.hpp> #include <mbgl/gl/gl.hpp> #include <mbgl/gl/object_store.hpp> +#include <mbgl/gl/gl_config.hpp> #include <mbgl/platform/log.hpp> #include <mbgl/platform/platform.hpp> @@ -20,7 +21,7 @@ LineAtlas::LineAtlas(GLsizei w, GLsizei h) LineAtlas::~LineAtlas() = default; -LinePatternPos LineAtlas::getDashPosition(const std::vector<float> &dasharray, bool round, gl::ObjectStore& store) { +LinePatternPos LineAtlas::getDashPosition(const std::vector<float>& dasharray, bool round) { size_t key = round ? std::numeric_limits<size_t>::min() : std::numeric_limits<size_t>::max(); for (const float part : dasharray) { boost::hash_combine<float>(key, part); @@ -29,7 +30,7 @@ LinePatternPos LineAtlas::getDashPosition(const std::vector<float> &dasharray, b // Note: We're not handling hash collisions here. const auto it = positions.find(key); if (it == positions.end()) { - auto inserted = positions.emplace(key, addDash(dasharray, round, store)); + auto inserted = positions.emplace(key, addDash(dasharray, round)); assert(inserted.second); return inserted.first->second; } else { @@ -37,8 +38,7 @@ LinePatternPos LineAtlas::getDashPosition(const std::vector<float> &dasharray, b } } -LinePatternPos LineAtlas::addDash(const std::vector<float> &dasharray, bool round, gl::ObjectStore& store) { - +LinePatternPos LineAtlas::addDash(const std::vector<float>& dasharray, bool round) { int n = round ? 7 : 0; int dashheight = 2 * n + 1; const uint8_t offset = 128; @@ -115,32 +115,34 @@ LinePatternPos LineAtlas::addDash(const std::vector<float> &dasharray, bool roun nextRow += dashheight; dirty = true; - bind(store); return position; } -void LineAtlas::upload(gl::ObjectStore& store) { +void LineAtlas::upload(gl::ObjectStore& store, gl::Config& config, uint32_t unit) { if (dirty) { - bind(store); + bind(store, config, unit); } } -void LineAtlas::bind(gl::ObjectStore& store) { +void LineAtlas::bind(gl::ObjectStore& store, gl::Config& config, uint32_t unit) { bool first = false; if (!texture) { texture = store.createTexture(); - MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture)); + config.activeTexture = unit; + config.texture[unit] = *texture; MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); first = true; - } else { - MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture)); + } else if (config.texture[unit] != *texture) { + config.activeTexture = unit; + config.texture[unit] = *texture; } if (dirty) { + config.activeTexture = unit; if (first) { MBGL_CHECK_ERROR(glTexImage2D( GL_TEXTURE_2D, // GLenum target diff --git a/src/mbgl/geometry/line_atlas.hpp b/src/mbgl/geometry/line_atlas.hpp index 0ca5e95a23..1e6c0ac84e 100644 --- a/src/mbgl/geometry/line_atlas.hpp +++ b/src/mbgl/geometry/line_atlas.hpp @@ -9,6 +9,10 @@ namespace mbgl { +namespace gl { +class Config; +} // namespace gl + typedef struct { float width; float height; @@ -21,14 +25,14 @@ public: ~LineAtlas(); // Binds the atlas texture to the GPU, and uploads data if it is out of date. - void bind(gl::ObjectStore&); + void bind(gl::ObjectStore&, gl::Config&, uint32_t unit); // Uploads the texture to the GPU to be available when we need it. This is a lazy operation; // the texture is only bound when the data is out of date (=dirty). - void upload(gl::ObjectStore&); + void upload(gl::ObjectStore&, gl::Config&, uint32_t unit); - LinePatternPos getDashPosition(const std::vector<float>&, bool, gl::ObjectStore&); - LinePatternPos addDash(const std::vector<float> &dasharray, bool round, gl::ObjectStore&); + LinePatternPos getDashPosition(const std::vector<float>&, bool); + LinePatternPos addDash(const std::vector<float>& dasharray, bool round); const GLsizei width; const GLsizei height; diff --git a/src/mbgl/gl/gl_config.cpp b/src/mbgl/gl/gl_config.cpp index 97d2f26f6c..9031c3d34f 100644 --- a/src/mbgl/gl/gl_config.cpp +++ b/src/mbgl/gl/gl_config.cpp @@ -20,7 +20,8 @@ const ClearColor::Type ClearColor::Default = { 0, 0, 0, 0 }; const ClearStencil::Type ClearStencil::Default = 0; const Program::Type Program::Default = 0; const LineWidth::Type LineWidth::Default = 1; -const ActiveTexture::Type ActiveTexture::Default = GL_TEXTURE0; +const ActiveTexture::Type ActiveTexture::Default = 0; +const BindTexture::Type BindTexture::Default = 0; #ifndef GL_ES_VERSION_2_0 const PixelZoom::Type PixelZoom::Default = { 1, 1 }; diff --git a/src/mbgl/gl/gl_config.hpp b/src/mbgl/gl/gl_config.hpp index 9d7dfb3b6c..41bee8fab7 100644 --- a/src/mbgl/gl/gl_config.hpp +++ b/src/mbgl/gl/gl_config.hpp @@ -13,13 +13,17 @@ template <typename T> class Value { public: void operator=(const typename T::Type& value) { - if (dirty || current != value) { + if (*this != value) { dirty = false; current = value; T::Set(current); } } + bool operator!=(const typename T::Type& value) const { + return dirty || current != value; + } + void reset() { *this = T::Default; } @@ -28,11 +32,11 @@ public: dirty = true; } - typename T::Type getCurrent() { + typename T::Type getCurrent() const { return current; } - bool getDirty() { + bool getDirty() const { return dirty; } @@ -115,6 +119,7 @@ public: Value<PixelZoom> pixelZoom; Value<RasterPos> rasterPos; #endif // GL_ES_VERSION_2_0 + std::array<Value<BindTexture>, 2> texture; }; } // namespace gl diff --git a/src/mbgl/renderer/bucket.hpp b/src/mbgl/renderer/bucket.hpp index 6792c162a5..4fcfb7b24e 100644 --- a/src/mbgl/renderer/bucket.hpp +++ b/src/mbgl/renderer/bucket.hpp @@ -17,6 +17,7 @@ class CollisionTile; namespace gl { class ObjectStore; +class Config; } // namespace gl namespace style { @@ -29,7 +30,7 @@ public: // As long as this bucket has a Prepare render pass, this function is getting called. Typically, // this only happens once when the bucket is being rendered for the first time. - virtual void upload(gl::ObjectStore&) = 0; + virtual void upload(gl::ObjectStore&, gl::Config&) = 0; // Every time this bucket is getting rendered, this function is called. This happens either // once or twice (for Opaque and Transparent render passes). diff --git a/src/mbgl/renderer/circle_bucket.cpp b/src/mbgl/renderer/circle_bucket.cpp index d86fbda489..3a6181b003 100644 --- a/src/mbgl/renderer/circle_bucket.cpp +++ b/src/mbgl/renderer/circle_bucket.cpp @@ -16,7 +16,7 @@ CircleBucket::~CircleBucket() { // Do not remove. header file only contains forward definitions to unique pointers. } -void CircleBucket::upload(gl::ObjectStore& store) { +void CircleBucket::upload(gl::ObjectStore& store, gl::Config&) { vertexBuffer_.upload(store); elementsBuffer_.upload(store); uploaded = true; diff --git a/src/mbgl/renderer/circle_bucket.hpp b/src/mbgl/renderer/circle_bucket.hpp index 041207a6ca..695abe53b6 100644 --- a/src/mbgl/renderer/circle_bucket.hpp +++ b/src/mbgl/renderer/circle_bucket.hpp @@ -18,7 +18,7 @@ public: CircleBucket(const MapMode); ~CircleBucket() override; - void upload(gl::ObjectStore&) override; + void upload(gl::ObjectStore&, gl::Config&) override; void render(Painter&, const style::Layer&, const UnwrappedTileID&, const mat4&) override; bool hasData() const override; diff --git a/src/mbgl/renderer/fill_bucket.cpp b/src/mbgl/renderer/fill_bucket.cpp index c927071850..e79dfd316b 100644 --- a/src/mbgl/renderer/fill_bucket.cpp +++ b/src/mbgl/renderer/fill_bucket.cpp @@ -95,7 +95,7 @@ void FillBucket::addGeometry(const GeometryCollection& geometry) { } } -void FillBucket::upload(gl::ObjectStore& store) { +void FillBucket::upload(gl::ObjectStore& store, gl::Config&) { vertexBuffer.upload(store); triangleElementsBuffer.upload(store); lineElementsBuffer.upload(store); diff --git a/src/mbgl/renderer/fill_bucket.hpp b/src/mbgl/renderer/fill_bucket.hpp index 7508445579..69d4331486 100644 --- a/src/mbgl/renderer/fill_bucket.hpp +++ b/src/mbgl/renderer/fill_bucket.hpp @@ -20,7 +20,7 @@ public: FillBucket(); ~FillBucket() override; - void upload(gl::ObjectStore&) override; + void upload(gl::ObjectStore&, gl::Config&) override; void render(Painter&, const style::Layer&, const UnwrappedTileID&, const mat4&) override; bool hasData() const override; bool needsClipping() const override; diff --git a/src/mbgl/renderer/frame_history.cpp b/src/mbgl/renderer/frame_history.cpp index 68b6bf863e..fc9d9b6616 100644 --- a/src/mbgl/renderer/frame_history.cpp +++ b/src/mbgl/renderer/frame_history.cpp @@ -1,5 +1,6 @@ #include <mbgl/renderer/frame_history.hpp> #include <mbgl/math/minmax.hpp> +#include <mbgl/gl/gl_config.hpp> namespace mbgl { @@ -57,11 +58,11 @@ bool FrameHistory::needsAnimation(const Duration& duration) const { return (time - previousTime) < duration; } -void FrameHistory::upload(gl::ObjectStore& store) { +void FrameHistory::upload(gl::ObjectStore& store, gl::Config& config, uint32_t unit) { if (changed) { const bool first = !texture; - bind(store); + bind(store, config, unit); if (first) { MBGL_CHECK_ERROR(glTexImage2D( @@ -94,10 +95,11 @@ void FrameHistory::upload(gl::ObjectStore& store) { } } -void FrameHistory::bind(gl::ObjectStore& store) { +void FrameHistory::bind(gl::ObjectStore& store, gl::Config& config, uint32_t unit) { if (!texture) { texture = store.createTexture(); - MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture)); + config.activeTexture = unit; + config.texture[unit] = *texture; #ifndef GL_ES_VERSION_2_0 MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); #endif @@ -105,10 +107,10 @@ void FrameHistory::bind(gl::ObjectStore& store) { MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); - } else { - MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture)); + } else if (config.texture[unit] != *texture) { + config.activeTexture = unit; + config.texture[unit] = *texture; } - } } // namespace mbgl diff --git a/src/mbgl/renderer/frame_history.hpp b/src/mbgl/renderer/frame_history.hpp index 04ebe23276..ec43e2beb5 100644 --- a/src/mbgl/renderer/frame_history.hpp +++ b/src/mbgl/renderer/frame_history.hpp @@ -9,14 +9,18 @@ namespace mbgl { +namespace gl { +class Config; +} // namespace gl + class FrameHistory { public: FrameHistory(); void record(const TimePoint&, float zoom, const Duration&); bool needsAnimation(const Duration&) const; - void bind(gl::ObjectStore&); - void upload(gl::ObjectStore&); + void bind(gl::ObjectStore&, gl::Config&, uint32_t); + void upload(gl::ObjectStore&, gl::Config&, uint32_t); private: const int width = 256; diff --git a/src/mbgl/renderer/line_bucket.cpp b/src/mbgl/renderer/line_bucket.cpp index e9a8e78618..381356b801 100644 --- a/src/mbgl/renderer/line_bucket.cpp +++ b/src/mbgl/renderer/line_bucket.cpp @@ -437,7 +437,7 @@ void LineBucket::addPieSliceVertex(const GeometryCoordinate& currentVertex, } } -void LineBucket::upload(gl::ObjectStore& store) { +void LineBucket::upload(gl::ObjectStore& store, gl::Config&) { vertexBuffer.upload(store); triangleElementsBuffer.upload(store); diff --git a/src/mbgl/renderer/line_bucket.hpp b/src/mbgl/renderer/line_bucket.hpp index 5ece05b03b..f09341e7a5 100644 --- a/src/mbgl/renderer/line_bucket.hpp +++ b/src/mbgl/renderer/line_bucket.hpp @@ -24,7 +24,7 @@ public: LineBucket(uint32_t overscaling); ~LineBucket() override; - void upload(gl::ObjectStore&) override; + void upload(gl::ObjectStore&, gl::Config&) override; void render(Painter&, const style::Layer&, const UnwrappedTileID&, const mat4&) override; bool hasData() const override; bool needsClipping() const override; diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index d6f14708aa..46207fbcfe 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -135,15 +135,15 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a tileStencilBuffer.upload(store); rasterBoundsBuffer.upload(store); tileBorderBuffer.upload(store); - spriteAtlas->upload(store); - lineAtlas->upload(store); - glyphAtlas->upload(store); - frameHistory.upload(store); - annotationSpriteAtlas.upload(store); + spriteAtlas->upload(store, config, 0); + lineAtlas->upload(store, config, 0); + glyphAtlas->upload(store, config, 0); + frameHistory.upload(store, config, 0); + annotationSpriteAtlas.upload(store, config, 0); for (const auto& item : order) { if (item.bucket && item.bucket->needsUpload()) { - item.bucket->upload(store); + item.bucket->upload(store, config); } } } @@ -232,7 +232,11 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a { MBGL_DEBUG_GROUP("cleanup"); - MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, 0)); + config.activeTexture = 1; + config.texture[1] = 0; + config.activeTexture = 0; + config.texture[0] = 0; + MBGL_CHECK_ERROR(VertexArrayObject::Unbind()); } diff --git a/src/mbgl/renderer/painter_background.cpp b/src/mbgl/renderer/painter_background.cpp index 6c47bb08fb..68463f3154 100644 --- a/src/mbgl/renderer/painter_background.cpp +++ b/src/mbgl/renderer/painter_background.cpp @@ -43,7 +43,7 @@ void Painter::renderBackground(const BackgroundLayer& layer) { patternShader.u_mix = properties.backgroundPattern.value.t; patternShader.u_opacity = properties.backgroundOpacity; - spriteAtlas->bind(true, store); + spriteAtlas->bind(true, store, config, 0); arrayBackgroundPattern.bind(patternShader, tileStencilBuffer, BUFFER_OFFSET(0), store); } else { diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp index 2b90f6d351..1a7b758000 100644 --- a/src/mbgl/renderer/painter_fill.cpp +++ b/src/mbgl/renderer/painter_fill.cpp @@ -103,8 +103,7 @@ void Painter::renderFill(FillBucket& bucket, patternShader.u_pixel_coord_upper = {{ float(pixelX >> 16), float(pixelY >> 16) }}; patternShader.u_pixel_coord_lower = {{ float(pixelX & 0xFFFF), float(pixelY & 0xFFFF) }}; - config.activeTexture = GL_TEXTURE0; - spriteAtlas->bind(true, store); + spriteAtlas->bind(true, store, config, 0); // Draw the actual triangles into the color & stencil buffer. setDepthSublayer(0); @@ -132,8 +131,7 @@ void Painter::renderFill(FillBucket& bucket, // Draw the entire line outlinePatternShader.u_world = worldSize; - config.activeTexture = GL_TEXTURE0; - spriteAtlas->bind(true, store); + spriteAtlas->bind(true, store, config, 0); setDepthSublayer(2); bucket.drawVertices(outlinePatternShader, store, overdraw); diff --git a/src/mbgl/renderer/painter_line.cpp b/src/mbgl/renderer/painter_line.cpp index ab552d7ef9..ce1c6758fc 100644 --- a/src/mbgl/renderer/painter_line.cpp +++ b/src/mbgl/renderer/painter_line.cpp @@ -72,8 +72,8 @@ void Painter::renderLine(LineBucket& bucket, linesdfShader.u_color = color; linesdfShader.u_opacity = opacity; - LinePatternPos posA = lineAtlas->getDashPosition(properties.lineDasharray.value.from, layout.lineCap == LineCapType::Round, store); - LinePatternPos posB = lineAtlas->getDashPosition(properties.lineDasharray.value.to, layout.lineCap == LineCapType::Round, store); + LinePatternPos posA = lineAtlas->getDashPosition(properties.lineDasharray.value.from, layout.lineCap == LineCapType::Round); + LinePatternPos posB = lineAtlas->getDashPosition(properties.lineDasharray.value.to, layout.lineCap == LineCapType::Round); const float widthA = posA.width * properties.lineDasharray.value.fromScale * layer.impl->dashLineWidth; const float widthB = posB.width * properties.lineDasharray.value.toScale * layer.impl->dashLineWidth; @@ -94,8 +94,7 @@ void Painter::renderLine(LineBucket& bucket, linesdfShader.u_antialiasingmatrix = antialiasingMatrix; linesdfShader.u_image = 0; - config.activeTexture = GL_TEXTURE0; - lineAtlas->bind(store); + lineAtlas->bind(store, config, 0); bucket.drawLineSDF(linesdfShader, store, overdraw); @@ -136,8 +135,7 @@ void Painter::renderLine(LineBucket& bucket, linepatternShader.u_antialiasingmatrix = antialiasingMatrix; linepatternShader.u_image = 0; - config.activeTexture = GL_TEXTURE0; - spriteAtlas->bind(true, store); + spriteAtlas->bind(true, store, config, 0); bucket.drawLinePatterns(linepatternShader, store, overdraw); diff --git a/src/mbgl/renderer/painter_symbol.cpp b/src/mbgl/renderer/painter_symbol.cpp index 8b4138819c..df29d16b9d 100644 --- a/src/mbgl/renderer/painter_symbol.cpp +++ b/src/mbgl/renderer/painter_symbol.cpp @@ -77,8 +77,7 @@ void Painter::renderSDF(SymbolBucket &bucket, sdfShader.u_zoom = (state.getZoom() - zoomAdjust) * 10; // current zoom level - config.activeTexture = GL_TEXTURE1; - frameHistory.bind(store); + frameHistory.bind(store, config, 1); sdfShader.u_fadetexture = 1; // The default gamma value has to be adjust for the current pixelratio so that we're not @@ -164,8 +163,7 @@ void Painter::renderSymbol(SymbolBucket& bucket, SpriteAtlas* activeSpriteAtlas = layer.impl->spriteAtlas; const bool iconScaled = fontScale != 1 || frame.pixelRatio != activeSpriteAtlas->getPixelRatio() || bucket.iconsNeedLinear; const bool iconTransformed = layout.iconRotationAlignment == AlignmentType::Map || angleOffset != 0 || state.getPitch() != 0; - config.activeTexture = GL_TEXTURE0; - activeSpriteAtlas->bind(sdf || state.isChanging() || iconScaled || iconTransformed, store); + activeSpriteAtlas->bind(sdf || state.isChanging() || iconScaled || iconTransformed, store, config, 0); if (sdf) { renderSDF(bucket, @@ -219,8 +217,7 @@ void Painter::renderSymbol(SymbolBucket& bucket, iconShader.u_zoom = (state.getZoom() - zoomAdjust) * 10; // current zoom level iconShader.u_opacity = paint.iconOpacity; - config.activeTexture = GL_TEXTURE1; - frameHistory.bind(store); + frameHistory.bind(store, config, 1); iconShader.u_fadetexture = 1; setDepthSublayer(0); @@ -236,8 +233,7 @@ void Painter::renderSymbol(SymbolBucket& bucket, config.depthTest = GL_FALSE; } - config.activeTexture = GL_TEXTURE0; - glyphAtlas->bind(store); + glyphAtlas->bind(store, config, 0); renderSDF(bucket, tileID, @@ -276,8 +272,6 @@ void Painter::renderSymbol(SymbolBucket& bucket, bucket.drawCollisionBoxes(collisionBoxShader, store); } - - config.activeTexture = GL_TEXTURE0; } } // namespace mbgl diff --git a/src/mbgl/renderer/raster_bucket.cpp b/src/mbgl/renderer/raster_bucket.cpp index 1cf6f2c413..c4e11198d3 100644 --- a/src/mbgl/renderer/raster_bucket.cpp +++ b/src/mbgl/renderer/raster_bucket.cpp @@ -7,9 +7,9 @@ namespace mbgl { using namespace style; -void RasterBucket::upload(gl::ObjectStore& store) { +void RasterBucket::upload(gl::ObjectStore& store, gl::Config& config) { if (hasData()) { - raster.upload(store); + raster.upload(store, config, 0); uploaded = true; } } @@ -30,10 +30,8 @@ void RasterBucket::drawRaster(RasterShader& shader, VertexArrayObject& array, gl::Config& config, gl::ObjectStore& store) { - config.activeTexture = GL_TEXTURE0; - raster.bind(store, Raster::Scaling::Linear); - config.activeTexture = GL_TEXTURE1; - raster.bind(store, Raster::Scaling::Linear); + raster.bind(store, config, 0, Raster::Scaling::Linear); + raster.bind(store, config, 1, Raster::Scaling::Linear); array.bind(shader, vertices, BUFFER_OFFSET_0, store); MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, (GLsizei)vertices.index())); } diff --git a/src/mbgl/renderer/raster_bucket.hpp b/src/mbgl/renderer/raster_bucket.hpp index 35b1bc2b51..ec24cff400 100644 --- a/src/mbgl/renderer/raster_bucket.hpp +++ b/src/mbgl/renderer/raster_bucket.hpp @@ -12,7 +12,7 @@ class VertexArrayObject; class RasterBucket : public Bucket { public: - void upload(gl::ObjectStore&) override; + void upload(gl::ObjectStore&, gl::Config&) override; void render(Painter&, const style::Layer&, const UnwrappedTileID&, const mat4&) override; bool hasData() const override; bool needsClipping() const override; diff --git a/src/mbgl/renderer/symbol_bucket.cpp b/src/mbgl/renderer/symbol_bucket.cpp index 66d2f04700..78b90dea19 100644 --- a/src/mbgl/renderer/symbol_bucket.cpp +++ b/src/mbgl/renderer/symbol_bucket.cpp @@ -73,7 +73,7 @@ SymbolBucket::~SymbolBucket() { // Do not remove. header file only contains forward definitions to unique pointers. } -void SymbolBucket::upload(gl::ObjectStore& store) { +void SymbolBucket::upload(gl::ObjectStore& store, gl::Config&) { if (hasTextData()) { renderData->text.vertices.upload(store); renderData->text.triangles.upload(store); diff --git a/src/mbgl/renderer/symbol_bucket.hpp b/src/mbgl/renderer/symbol_bucket.hpp index b899d52767..9a023a6010 100644 --- a/src/mbgl/renderer/symbol_bucket.hpp +++ b/src/mbgl/renderer/symbol_bucket.hpp @@ -69,7 +69,7 @@ public: SymbolBucket(uint32_t overscaling, float zoom, const MapMode, std::string bucketName_, std::string sourceLayerName_); ~SymbolBucket() override; - void upload(gl::ObjectStore&) override; + void upload(gl::ObjectStore&, gl::Config&) override; void render(Painter&, const style::Layer&, const UnwrappedTileID&, const mat4&) override; bool hasData() const override; bool hasTextData() const; diff --git a/src/mbgl/sprite/sprite_atlas.cpp b/src/mbgl/sprite/sprite_atlas.cpp index 581bc01ed8..05b713f454 100644 --- a/src/mbgl/sprite/sprite_atlas.cpp +++ b/src/mbgl/sprite/sprite_atlas.cpp @@ -1,6 +1,7 @@ #include <mbgl/sprite/sprite_atlas.hpp> #include <mbgl/sprite/sprite_store.hpp> #include <mbgl/gl/gl.hpp> +#include <mbgl/gl/gl_config.hpp> #include <mbgl/platform/log.hpp> #include <mbgl/platform/platform.hpp> #include <mbgl/util/math.hpp> @@ -142,9 +143,9 @@ void SpriteAtlas::copy(const Holder& holder, const bool wrap) { dirty = true; } -void SpriteAtlas::upload(gl::ObjectStore& objectStore) { +void SpriteAtlas::upload(gl::ObjectStore& objectStore, gl::Config& config, uint32_t unit) { if (dirty) { - bind(false, objectStore); + bind(false, objectStore, config, unit); } } @@ -179,14 +180,15 @@ void SpriteAtlas::updateDirty() { } } -void SpriteAtlas::bind(bool linear, gl::ObjectStore& objectStore) { +void SpriteAtlas::bind(bool linear, gl::ObjectStore& objectStore, gl::Config& config, uint32_t unit) { if (!data) { return; // Empty atlas } if (!texture) { texture = objectStore.createTexture(); - MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture)); + config.activeTexture = unit; + config.texture[unit] = *texture; #ifndef GL_ES_VERSION_2_0 MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0)); #endif @@ -195,12 +197,14 @@ void SpriteAtlas::bind(bool linear, gl::ObjectStore& objectStore) { MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); fullUploadRequired = true; - } else { - MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture)); + } else if (config.texture[unit] != *texture) { + config.activeTexture = unit; + config.texture[unit] = *texture; } GLuint filter_val = linear ? GL_LINEAR : GL_NEAREST; if (filter_val != filter) { + config.activeTexture = unit; MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter_val)); MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter_val)); filter = filter_val; @@ -209,6 +213,7 @@ void SpriteAtlas::bind(bool linear, gl::ObjectStore& objectStore) { if (dirty) { std::lock_guard<std::recursive_mutex> lock(mtx); + config.activeTexture = unit; if (fullUploadRequired) { MBGL_CHECK_ERROR(glTexImage2D( GL_TEXTURE_2D, // GLenum target diff --git a/src/mbgl/sprite/sprite_atlas.hpp b/src/mbgl/sprite/sprite_atlas.hpp index 4d1ee1c38c..4f44eb9ac9 100644 --- a/src/mbgl/sprite/sprite_atlas.hpp +++ b/src/mbgl/sprite/sprite_atlas.hpp @@ -16,6 +16,10 @@ namespace mbgl { +namespace gl { +class Config; +} // namespace gl + class SpriteStore; class SpriteImage; class SpritePosition; @@ -47,14 +51,14 @@ public: optional<SpriteAtlasPosition> getPosition(const std::string& name, bool repeating = false); // Binds the atlas texture to the GPU, and uploads data if it is out of date. - void bind(bool linear, gl::ObjectStore&); + void bind(bool linear, gl::ObjectStore&, gl::Config&, uint32_t unit); // Updates sprites in the atlas texture that may have changed in the source SpriteStore object. void updateDirty(); // Uploads the texture to the GPU to be available when we need it. This is a lazy operation; // the texture is only bound when the data is out of date (=dirty). - void upload(gl::ObjectStore&); + void upload(gl::ObjectStore&, gl::Config&, uint32_t unit); dimension getWidth() const { return width; } dimension getHeight() const { return height; } diff --git a/src/mbgl/util/raster.cpp b/src/mbgl/util/raster.cpp index 7417c8bcd5..3f9cb467b9 100644 --- a/src/mbgl/util/raster.cpp +++ b/src/mbgl/util/raster.cpp @@ -1,5 +1,6 @@ #include <mbgl/platform/platform.hpp> #include <mbgl/gl/gl.hpp> +#include <mbgl/gl/gl_config.hpp> #include <mbgl/platform/log.hpp> #include <mbgl/util/raster.hpp> @@ -24,7 +25,11 @@ void Raster::load(PremultipliedImage image, uint32_t mipmapLevel) { loaded = true; } -void Raster::bind(gl::ObjectStore& store, Scaling newFilter, MipMap newMipMap) { +void Raster::bind(gl::ObjectStore& store, + gl::Config& config, + uint32_t unit, + Scaling newFilter, + MipMap newMipMap) { bool updateFilter = false; if (!texture) { @@ -32,17 +37,21 @@ void Raster::bind(gl::ObjectStore& store, Scaling newFilter, MipMap newMipMap) { Log::Error(Event::OpenGL, "trying to bind texture without images"); return; } else { - upload(store); + upload(store, config, unit); updateFilter = true; } } else { - MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture)); + if (config.texture[unit] != *texture) { + config.activeTexture = unit; + config.texture[unit] = *texture; + } updateFilter = (filter != newFilter || mipmap != newMipMap); } if (updateFilter) { filter = newFilter; mipmap = newMipMap; + config.activeTexture = unit; MBGL_CHECK_ERROR(glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter == Scaling::Linear @@ -53,10 +62,11 @@ void Raster::bind(gl::ObjectStore& store, Scaling newFilter, MipMap newMipMap) { } } -void Raster::upload(gl::ObjectStore& store) { +void Raster::upload(gl::ObjectStore& store, gl::Config& config, uint32_t unit) { if (!images.empty() && !texture) { texture = store.createTexture(); - MBGL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, *texture)); + config.activeTexture = unit; + config.texture[unit] = *texture; #ifndef GL_ES_VERSION_2_0 MBGL_CHECK_ERROR(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, images.size())); #endif diff --git a/src/mbgl/util/raster.hpp b/src/mbgl/util/raster.hpp index 6223440bd6..a30c086323 100644 --- a/src/mbgl/util/raster.hpp +++ b/src/mbgl/util/raster.hpp @@ -7,6 +7,10 @@ namespace mbgl { +namespace gl { +class Config; +} // namespace gl + class Raster { public: enum class MipMap : bool { No = false, Yes = true }; @@ -16,10 +20,14 @@ public: void load(PremultipliedImage, uint32_t mipmapLevel = 0); // bind current texture - void bind(gl::ObjectStore&, Scaling = Scaling::Nearest, MipMap = MipMap::No); + void bind(gl::ObjectStore&, + gl::Config&, + uint32_t unit, + Scaling = Scaling::Nearest, + MipMap = MipMap::No); // uploads the texture if it hasn't been uploaded yet. - void upload(gl::ObjectStore&); + void upload(gl::ObjectStore&, gl::Config&, uint32_t unit); // loaded status bool isLoaded() const; |