diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mbgl/gl/context.cpp | 183 | ||||
-rw-r--r-- | src/mbgl/gl/context.hpp | 27 | ||||
-rw-r--r-- | src/mbgl/gl/framebuffer.hpp | 17 | ||||
-rw-r--r-- | src/mbgl/gl/gl.cpp | 1 | ||||
-rw-r--r-- | src/mbgl/gl/object.cpp | 5 | ||||
-rw-r--r-- | src/mbgl/gl/object.hpp | 6 | ||||
-rw-r--r-- | src/mbgl/gl/renderbuffer.hpp | 19 | ||||
-rw-r--r-- | src/mbgl/gl/state.hpp | 36 | ||||
-rw-r--r-- | src/mbgl/gl/types.hpp | 5 | ||||
-rw-r--r-- | src/mbgl/gl/value.cpp | 16 | ||||
-rw-r--r-- | src/mbgl/gl/value.hpp | 9 | ||||
-rw-r--r-- | src/mbgl/map/backend.cpp | 10 | ||||
-rw-r--r-- | src/mbgl/map/map.cpp | 147 | ||||
-rw-r--r-- | src/mbgl/map/update.hpp | 30 | ||||
-rw-r--r-- | src/mbgl/map/view.cpp | 17 | ||||
-rw-r--r-- | src/mbgl/renderer/painter.cpp | 35 | ||||
-rw-r--r-- | src/mbgl/renderer/painter.hpp | 7 | ||||
-rw-r--r-- | src/mbgl/renderer/painter_debug.cpp | 44 | ||||
-rw-r--r-- | src/mbgl/renderer/painter_fill.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/util/offscreen_texture.cpp | 70 | ||||
-rw-r--r-- | src/mbgl/util/offscreen_texture.hpp | 17 |
21 files changed, 449 insertions, 256 deletions
diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index 2a04fcc18e..23b28a15df 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -1,3 +1,4 @@ +#include <mbgl/map/view.hpp> #include <mbgl/gl/context.hpp> #include <mbgl/gl/gl.hpp> #include <mbgl/gl/vertex_array.hpp> @@ -142,6 +143,113 @@ UniqueFramebuffer Context::createFramebuffer() { return UniqueFramebuffer{ std::move(id), { this } }; } +UniqueRenderbuffer Context::createRenderbuffer(const RenderbufferType type, + const uint16_t width, + const uint16_t height) { + RenderbufferID id = 0; + MBGL_CHECK_ERROR(glGenRenderbuffers(1, &id)); + UniqueRenderbuffer renderbuffer{ std::move(id), { this } }; + + bindRenderbuffer = renderbuffer; + MBGL_CHECK_ERROR( + glRenderbufferStorage(GL_RENDERBUFFER, static_cast<GLenum>(type), width, height)); + return renderbuffer; +} + +namespace { + +void checkFramebuffer() { + GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatus(GL_FRAMEBUFFER)); + if (status != GL_FRAMEBUFFER_COMPLETE) { + switch (status) { + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + throw std::runtime_error("Couldn't create framebuffer: incomplete attachment"); + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + throw std::runtime_error("Couldn't create framebuffer: incomplete missing attachment"); +#ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER + case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: + throw std::runtime_error("Couldn't create framebuffer: incomplete draw buffer"); +#endif +#ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER + case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: + throw std::runtime_error("Couldn't create framebuffer: incomplete read buffer"); +#endif +#ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + throw std::runtime_error("Couldn't create framebuffer: incomplete dimensions"); +#endif + + case GL_FRAMEBUFFER_UNSUPPORTED: + throw std::runtime_error("Couldn't create framebuffer: unsupported"); + default: + throw std::runtime_error("Couldn't create framebuffer: other"); + } + } +} + +void bindDepthStencilRenderbuffer( + const Renderbuffer<RenderbufferType::DepthStencil>& depthStencil) { +#ifdef GL_DEPTH_STENCIL_ATTACHMENT + MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, depthStencil.renderbuffer)); +#else + MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, + depthStencil.renderbuffer)); + MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, depthStencil.renderbuffer)); +#endif +} + +} // namespace + +Framebuffer +Context::createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>& color, + const Renderbuffer<RenderbufferType::DepthStencil>& depthStencil) { + if (color.size != depthStencil.size) { + throw new std::runtime_error("Renderbuffer size mismatch"); + } + auto fbo = createFramebuffer(); + bindFramebuffer = fbo; + MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, color.renderbuffer)); + bindDepthStencilRenderbuffer(depthStencil); + checkFramebuffer(); + return { color.size, std::move(fbo) }; +} + +Framebuffer Context::createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>& color) { + auto fbo = createFramebuffer(); + bindFramebuffer = fbo; + MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, color.renderbuffer)); + checkFramebuffer(); + return { color.size, std::move(fbo) }; +} + +Framebuffer +Context::createFramebuffer(const Texture& color, + const Renderbuffer<RenderbufferType::DepthStencil>& depthStencil) { + if (color.size != depthStencil.size) { + throw new std::runtime_error("Renderbuffer size mismatch"); + } + auto fbo = createFramebuffer(); + bindFramebuffer = fbo; + MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + color.texture, 0)); + bindDepthStencilRenderbuffer(depthStencil); + checkFramebuffer(); + return { color.size, std::move(fbo) }; +} + +Framebuffer Context::createFramebuffer(const Texture& color) { + auto fbo = createFramebuffer(); + bindFramebuffer = fbo; + MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + color.texture, 0)); + checkFramebuffer(); + return { color.size, std::move(fbo) }; +} + UniqueTexture Context::createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit unit) { auto obj = createTexture(); @@ -186,50 +294,37 @@ void Context::reset() { performCleanup(); } -namespace { - -template <typename Fn> -void applyStateFunction(Context& context, Fn&& fn) { - fn(context.stencilFunc); - fn(context.stencilMask); - fn(context.stencilTest); - fn(context.stencilOp); - fn(context.depthRange); - fn(context.depthMask); - fn(context.depthTest); - fn(context.depthFunc); - fn(context.blend); - fn(context.blendFunc); - fn(context.blendColor); - fn(context.colorMask); - fn(context.clearDepth); - fn(context.clearColor); - fn(context.clearStencil); - fn(context.program); - fn(context.lineWidth); - fn(context.activeTexture); - fn(context.bindFramebuffer); - fn(context.viewport); +void Context::setDirtyState() { + // Note: does not set viewport/bindFramebuffer to dirty since they are handled separately in + // the view object. + stencilFunc.setDirty(); + stencilMask.setDirty(); + stencilTest.setDirty(); + stencilOp.setDirty(); + depthRange.setDirty(); + depthMask.setDirty(); + depthTest.setDirty(); + depthFunc.setDirty(); + blend.setDirty(); + blendFunc.setDirty(); + blendColor.setDirty(); + colorMask.setDirty(); + clearDepth.setDirty(); + clearColor.setDirty(); + clearStencil.setDirty(); + program.setDirty(); + lineWidth.setDirty(); + activeTexture.setDirty(); #if not MBGL_USE_GLES2 - fn(context.pixelZoom); - fn(context.rasterPos); + pixelZoom.setDirty(); + rasterPos.setDirty(); #endif // MBGL_USE_GLES2 - for (auto& tex : context.texture) { - fn(tex); + for (auto& tex : texture) { + tex.setDirty(); } - fn(context.vertexBuffer); - fn(context.elementBuffer); - fn(context.vertexArrayObject); -} - -} // namespace - -void Context::resetState() { - applyStateFunction(*this, [](auto& state) { state.reset(); }); -} - -void Context::setDirtyState() { - applyStateFunction(*this, [](auto& state) { state.setDirty(); }); + vertexBuffer.setDirty(); + elementBuffer.setDirty(); + vertexArrayObject.setDirty(); } void Context::performCleanup() { @@ -289,6 +384,12 @@ void Context::performCleanup() { glDeleteFramebuffers(int(abandonedFramebuffers.size()), abandonedFramebuffers.data())); abandonedFramebuffers.clear(); } + + if (!abandonedRenderbuffers.empty()) { + MBGL_CHECK_ERROR(glDeleteRenderbuffers(int(abandonedRenderbuffers.size()), + abandonedRenderbuffers.data())); + abandonedRenderbuffers.clear(); + } } } // namespace gl diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 6a5d44793a..cf8bb2658b 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -4,6 +4,8 @@ #include <mbgl/gl/state.hpp> #include <mbgl/gl/value.hpp> #include <mbgl/gl/texture.hpp> +#include <mbgl/gl/renderbuffer.hpp> +#include <mbgl/gl/framebuffer.hpp> #include <mbgl/gl/vertex_buffer.hpp> #include <mbgl/gl/index_buffer.hpp> #include <mbgl/gl/attribute.hpp> @@ -14,6 +16,9 @@ #include <array> namespace mbgl { + +class View; + namespace gl { constexpr size_t TextureMax = 64; @@ -27,7 +32,6 @@ public: UniqueShader createFragmentShader(); UniqueTexture createTexture(); UniqueVertexArray createVertexArray(); - UniqueFramebuffer createFramebuffer(); template <class V> VertexBuffer<V> createVertexBuffer(std::vector<V>&& v) { @@ -44,6 +48,20 @@ public: }; } + template <RenderbufferType type> + Renderbuffer<type> createRenderbuffer(const std::array<uint16_t, 2>& size) { + static_assert(type == RenderbufferType::RGBA || type == RenderbufferType::DepthStencil, + "invalid renderbuffer type"); + return { size, createRenderbuffer(type, size[0], size[1]) }; + } + + Framebuffer createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>&, + const Renderbuffer<RenderbufferType::DepthStencil>&); + Framebuffer createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>&); + Framebuffer createFramebuffer(const Texture&, + const Renderbuffer<RenderbufferType::DepthStencil>&); + Framebuffer createFramebuffer(const Texture&); + // Create a texture from an image with data. template <typename Image> Texture createTexture(const Image& image, TextureUnit unit = 0) { @@ -87,8 +105,6 @@ public: && abandonedFramebuffers.empty(); } - void resetState(); - void setDirtyState(); State<value::StencilFunc> stencilFunc; @@ -111,6 +127,7 @@ public: State<value::ActiveTexture> activeTexture; State<value::BindFramebuffer> bindFramebuffer; State<value::Viewport> viewport; + State<value::BindRenderbuffer> bindRenderbuffer; #if not MBGL_USE_GLES2 State<value::PixelZoom> pixelZoom; State<value::RasterPos> rasterPos; @@ -124,6 +141,8 @@ private: UniqueBuffer createVertexBuffer(const void* data, std::size_t size); UniqueBuffer createIndexBuffer(const void* data, std::size_t size); UniqueTexture createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit); + UniqueFramebuffer createFramebuffer(); + UniqueRenderbuffer createRenderbuffer(RenderbufferType, uint16_t width, uint16_t height); void bindAttribute(const AttributeBinding&, std::size_t stride, const int8_t* offset); friend detail::ProgramDeleter; @@ -132,6 +151,7 @@ private: friend detail::TextureDeleter; friend detail::VertexArrayDeleter; friend detail::FramebufferDeleter; + friend detail::RenderbufferDeleter; std::vector<TextureID> pooledTextures; @@ -141,6 +161,7 @@ private: std::vector<TextureID> abandonedTextures; std::vector<VertexArrayID> abandonedVertexArrays; std::vector<FramebufferID> abandonedFramebuffers; + std::vector<RenderbufferID> abandonedRenderbuffers; }; } // namespace gl diff --git a/src/mbgl/gl/framebuffer.hpp b/src/mbgl/gl/framebuffer.hpp new file mode 100644 index 0000000000..880fed159e --- /dev/null +++ b/src/mbgl/gl/framebuffer.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include <mbgl/gl/object.hpp> + +#include <array> + +namespace mbgl { +namespace gl { + +class Framebuffer { +public: + std::array<uint16_t, 2> size; + gl::UniqueFramebuffer framebuffer; +}; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/gl.cpp b/src/mbgl/gl/gl.cpp index 5cef254160..8999468dbd 100644 --- a/src/mbgl/gl/gl.cpp +++ b/src/mbgl/gl/gl.cpp @@ -51,6 +51,7 @@ constexpr const char* stringFromError(GLenum err) { } // namespace void checkError(const char* cmd, const char* file, int line) { +// fprintf(stderr, "cmd: %s\n", cmd); GLenum err = GL_NO_ERROR; if ((err = glGetError()) != GL_NO_ERROR) { std::string message = std::string(cmd) + ": Error " + stringFromError(err); diff --git a/src/mbgl/gl/object.cpp b/src/mbgl/gl/object.cpp index aee87f8836..e2d476e0c0 100644 --- a/src/mbgl/gl/object.cpp +++ b/src/mbgl/gl/object.cpp @@ -41,6 +41,11 @@ void FramebufferDeleter::operator()(FramebufferID id) const { context->abandonedFramebuffers.push_back(id); } +void RenderbufferDeleter::operator()(RenderbufferID id) const { + assert(context); + context->abandonedRenderbuffers.push_back(id); +} + } // namespace detail } // namespace gl } // namespace mbgl diff --git a/src/mbgl/gl/object.hpp b/src/mbgl/gl/object.hpp index 1cc1f04a97..1408add65a 100644 --- a/src/mbgl/gl/object.hpp +++ b/src/mbgl/gl/object.hpp @@ -41,6 +41,11 @@ struct FramebufferDeleter { void operator()(FramebufferID) const; }; +struct RenderbufferDeleter { + Context* context; + void operator()(RenderbufferID) const; +}; + } // namespace detail using UniqueProgram = std_experimental::unique_resource<ProgramID, detail::ProgramDeleter>; @@ -49,6 +54,7 @@ using UniqueBuffer = std_experimental::unique_resource<BufferID, detail::BufferD using UniqueTexture = std_experimental::unique_resource<TextureID, detail::TextureDeleter>; using UniqueVertexArray = std_experimental::unique_resource<VertexArrayID, detail::VertexArrayDeleter>; using UniqueFramebuffer = std_experimental::unique_resource<FramebufferID, detail::FramebufferDeleter>; +using UniqueRenderbuffer = std_experimental::unique_resource<RenderbufferID, detail::RenderbufferDeleter>; } // namespace gl } // namespace mbgl diff --git a/src/mbgl/gl/renderbuffer.hpp b/src/mbgl/gl/renderbuffer.hpp new file mode 100644 index 0000000000..9e8993bb77 --- /dev/null +++ b/src/mbgl/gl/renderbuffer.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include <mbgl/gl/object.hpp> + +#include <array> + +namespace mbgl { +namespace gl { + +template <RenderbufferType renderbufferType> +class Renderbuffer { +public: + using type = std::integral_constant<RenderbufferType, renderbufferType>; + std::array<uint16_t, 2> size; + gl::UniqueRenderbuffer renderbuffer; +}; + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/gl/state.hpp b/src/mbgl/gl/state.hpp index dbb005e77d..efe869e5b9 100644 --- a/src/mbgl/gl/state.hpp +++ b/src/mbgl/gl/state.hpp @@ -3,20 +3,6 @@ namespace mbgl { namespace gl { -// Helper struct that allows obtaining the default value of a Value class -template <typename T, typename = void> -struct DefaultValue { - static typename T::Type Get() { - return T::Get(); - } -}; -template <typename T> -struct DefaultValue<T, decltype((void)T::Default, void())> { - static typename T::Type Get() { - return T::Default; - } -}; - // Wraps a piece of OpenGL state and remember its value to avoid redundant state calls. // Wrapped types need to implement to the Value class interface: // @@ -26,17 +12,12 @@ struct DefaultValue<T, decltype((void)T::Default, void())> { // static void Set(const Type& value); // static Type Get(); // }; -// -// The Get() function is optional, but if it is omitted, you must provide a Default. -// Default is also optional, but if it is omitted, you must provide a Get() function. -// If both are present, DefaultValue<T>::Get() will use the Default member. template <typename T> class State { public: void operator=(const typename T::Type& value) { if (*this != value) { - dirty = false; - currentValue = value; + setCurrentValue(value); T::Set(currentValue); } } @@ -49,9 +30,9 @@ public: return dirty || currentValue != value; } - // Explicitly resets the piece of OpenGL state to its default value. - void reset() { - *this = defaultValue; + void setCurrentValue(const typename T::Type& value) { + dirty = false; + currentValue = value; } // Mark the state as dirty. This means that the next time we are assigning a value to this @@ -68,14 +49,9 @@ public: return dirty; } - void setDefaultValue(const typename T::Type& value) { - defaultValue = value; - } - private: - typename T::Type defaultValue = DefaultValue<T>::Get(); - typename T::Type currentValue = defaultValue; - bool dirty = false; + typename T::Type currentValue = T::Default; + bool dirty = true; }; // Helper struct that stores the current state and restores it upon destruction. You should not use diff --git a/src/mbgl/gl/types.hpp b/src/mbgl/gl/types.hpp index f24674457a..dccc61b03a 100644 --- a/src/mbgl/gl/types.hpp +++ b/src/mbgl/gl/types.hpp @@ -48,6 +48,11 @@ enum class BufferType : uint32_t { Element = 0x8893 }; +enum class RenderbufferType : uint32_t { + RGBA = 0x8058, + DepthStencil = 0x88F0, +}; + enum class TextureMipMap : bool { No = false, Yes = true }; enum class TextureFilter : bool { Nearest = false, Linear = true }; diff --git a/src/mbgl/gl/value.cpp b/src/mbgl/gl/value.cpp index e78b97ef2e..14cd03efc4 100644 --- a/src/mbgl/gl/value.cpp +++ b/src/mbgl/gl/value.cpp @@ -241,6 +241,8 @@ ActiveTexture::Type ActiveTexture::Get() { return static_cast<Type>(activeTexture - GL_TEXTURE0); } +const constexpr Viewport::Type Viewport::Default; + void Viewport::Set(const Type& value) { MBGL_CHECK_ERROR(glViewport(value.x, value.y, value.width, value.height)); } @@ -252,6 +254,8 @@ Viewport::Type Viewport::Get() { static_cast<uint16_t>(viewport[2]), static_cast<uint16_t>(viewport[3]) }; } +const constexpr BindFramebuffer::Type BindFramebuffer::Default; + void BindFramebuffer::Set(const Type& value) { MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, value)); } @@ -262,6 +266,18 @@ BindFramebuffer::Type BindFramebuffer::Get() { return binding; } +const constexpr BindRenderbuffer::Type BindRenderbuffer::Default; + +void BindRenderbuffer::Set(const Type& value) { + MBGL_CHECK_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, value)); +} + +BindRenderbuffer::Type BindRenderbuffer::Get() { + GLint binding; + MBGL_CHECK_ERROR(glGetIntegerv(GL_RENDERBUFFER_BINDING, &binding)); + return binding; +} + const constexpr BindTexture::Type BindTexture::Default; void BindTexture::Set(const Type& value) { diff --git a/src/mbgl/gl/value.hpp b/src/mbgl/gl/value.hpp index 9110b33a16..866ce389a4 100644 --- a/src/mbgl/gl/value.hpp +++ b/src/mbgl/gl/value.hpp @@ -180,6 +180,7 @@ struct Viewport { uint16_t width; uint16_t height; }; + static const constexpr Type Default = { 0, 0, 0, 0 }; static void Set(const Type&); static Type Get(); }; @@ -190,6 +191,14 @@ constexpr bool operator!=(const Viewport::Type& a, const Viewport::Type& b) { struct BindFramebuffer { using Type = FramebufferID; + static const constexpr Type Default = 0; + static void Set(const Type&); + static Type Get(); +}; + +struct BindRenderbuffer { + using Type = RenderbufferID; + static const constexpr Type Default = 0; static void Set(const Type&); static Type Get(); }; diff --git a/src/mbgl/map/backend.cpp b/src/mbgl/map/backend.cpp index fea4b70ce9..8a06fe2d91 100644 --- a/src/mbgl/map/backend.cpp +++ b/src/mbgl/map/backend.cpp @@ -1,9 +1,19 @@ #include <mbgl/map/backend.hpp> +#include <mbgl/gl/context.hpp> #include <cassert> namespace mbgl { +Backend::Backend() : context(std::make_unique<gl::Context>()) { +} + +gl::Context& Backend::getContext() { + return *context; +} + +Backend::~Backend() = default; + void Backend::notifyMapChange(MapChange) { // no-op } diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index ab85187c98..7b58026386 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -35,10 +35,18 @@ enum class RenderState : uint8_t { Fully, }; +struct StillImageRequest { + StillImageRequest(View& view_, Map::StillImageCallback&& callback_) + : view(view_), callback(std::move(callback_)) { + } + + View& view; + Map::StillImageCallback callback; +}; + class Map::Impl : public style::Observer { public: Impl(Backend&, - View&, float pixelRatio, FileSource&, Scheduler&, @@ -54,12 +62,11 @@ public: void onResourceError(std::exception_ptr) override; void update(); - void render(); + void render(View&); void loadStyleJSON(const std::string&); Backend& backend; - View& view; FileSource& fileSource; Scheduler& scheduler; @@ -85,14 +92,14 @@ public: std::unique_ptr<AsyncRequest> styleRequest; - Map::StillImageCallback callback; + std::unique_ptr<StillImageRequest> stillImageRequest; size_t sourceCacheSize; TimePoint timePoint; bool loading = false; }; Map::Map(Backend& backend, - View& view, + const std::array<uint16_t, 2> size, const float pixelRatio, FileSource& fileSource, Scheduler& scheduler, @@ -101,7 +108,6 @@ Map::Map(Backend& backend, ConstrainMode constrainMode, ViewportMode viewportMode) : impl(std::make_unique<Impl>(backend, - view, pixelRatio, fileSource, scheduler, @@ -109,12 +115,10 @@ Map::Map(Backend& backend, contextMode, constrainMode, viewportMode)) { - view.initialize(this); - update(Update::Dimensions); + impl->transform.resize(size); } Map::Impl::Impl(Backend& backend_, - View& view_, float pixelRatio_, FileSource& fileSource_, Scheduler& scheduler_, @@ -123,7 +127,6 @@ Map::Impl::Impl(Backend& backend_, ConstrainMode constrainMode_, ViewportMode viewportMode_) : backend(backend_), - view(view_), fileSource(fileSource_), scheduler(scheduler_), transform([this](MapChange change) { backend.notifyMapChange(change); }, @@ -150,42 +153,38 @@ Map::~Map() { impl->backend.deactivate(); } -void Map::renderStill(StillImageCallback callback) { +void Map::renderStill(View& view, StillImageCallback callback) { if (!callback) { Log::Error(Event::General, "StillImageCallback not set"); return; } if (impl->mode != MapMode::Still) { - callback(std::make_exception_ptr(util::MisuseException("Map is not in still image render mode")), {}); + callback(std::make_exception_ptr(util::MisuseException("Map is not in still image render mode"))); return; } - if (impl->callback) { - callback(std::make_exception_ptr(util::MisuseException("Map is currently rendering an image")), {}); + if (impl->stillImageRequest) { + callback(std::make_exception_ptr(util::MisuseException("Map is currently rendering an image"))); return; } if (!impl->style) { - callback(std::make_exception_ptr(util::MisuseException("Map doesn't have a style")), {}); + callback(std::make_exception_ptr(util::MisuseException("Map doesn't have a style"))); return; } if (impl->style->getLastError()) { - callback(impl->style->getLastError(), {}); + callback(impl->style->getLastError()); return; } - impl->callback = callback; + impl->stillImageRequest = std::make_unique<StillImageRequest>(view, std::move(callback)); impl->updateFlags |= Update::RenderStill; impl->asyncUpdate.send(); } -void Map::update(Update flags) { - impl->onUpdate(flags); -} - -void Map::render() { +void Map::render(View& view) { if (!impl->style) { return; } @@ -198,7 +197,7 @@ void Map::render() { const Update flags = impl->transform.updateTransitions(Clock::now()); - impl->render(); + impl->render(view); impl->backend.notifyMapChange(isFullyLoaded() ? MapChangeDidFinishRenderingFrameFullyRendered : @@ -218,16 +217,20 @@ void Map::render() { // Triggers an asynchronous update, that eventually triggers a view // invalidation, causing renderSync to be called again if in transition. if (flags != Update::Nothing) { - update(flags); + impl->onUpdate(flags); } } +void Map::triggerRepaint() { + impl->backend.invalidate(); +} + void Map::Impl::update() { if (!style) { updateFlags = Update::Nothing; } - if (updateFlags == Update::Nothing || (mode == MapMode::Still && !callback)) { + if (updateFlags == Update::Nothing || (mode == MapMode::Still && !stillImageRequest)) { return; } @@ -270,18 +273,19 @@ void Map::Impl::update() { if (mode == MapMode::Continuous) { backend.invalidate(); - } else if (callback && style->isLoaded()) { + } else if (stillImageRequest && style->isLoaded()) { + // TODO: determine whether we need activate/deactivate backend.activate(); - render(); + render(stillImageRequest->view); backend.deactivate(); } updateFlags = Update::Nothing; } -void Map::Impl::render() { +void Map::Impl::render(View& view) { if (!painter) { - painter = std::make_unique<Painter>(transform.getState()); + painter = std::make_unique<Painter>(backend.getContext(), transform.getState()); } FrameData frameData { timePoint, @@ -296,8 +300,8 @@ void Map::Impl::render() { annotationManager->getSpriteAtlas()); if (mode == MapMode::Still) { - callback(nullptr, view.readStillImage()); - callback = nullptr; + auto request = std::move(stillImageRequest); + request->callback(nullptr); } painter->cleanup(); @@ -399,12 +403,12 @@ std::string Map::getStyleJSON() const { void Map::cancelTransitions() { impl->transform.cancelTransitions(); - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } void Map::setGestureInProgress(bool inProgress) { impl->transform.setGestureInProgress(inProgress); - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } bool Map::isGestureInProgress() const { @@ -431,24 +435,24 @@ CameraOptions Map::getCameraOptions(optional<EdgeInsets> padding) const { void Map::jumpTo(const CameraOptions& camera) { impl->transform.jumpTo(camera); - update(camera.zoom ? Update::RecalculateStyle : Update::Repaint); + impl->onUpdate(camera.zoom ? Update::RecalculateStyle : Update::Repaint); } void Map::easeTo(const CameraOptions& camera, const AnimationOptions& animation) { impl->transform.easeTo(camera, animation); - update(camera.zoom ? Update::RecalculateStyle : Update::Repaint); + impl->onUpdate(camera.zoom ? Update::RecalculateStyle : Update::Repaint); } void Map::flyTo(const CameraOptions& camera, const AnimationOptions& animation) { impl->transform.flyTo(camera, animation); - update(Update::RecalculateStyle); + impl->onUpdate(Update::RecalculateStyle); } #pragma mark - Position void Map::moveBy(const ScreenCoordinate& point, const Duration& duration) { impl->transform.moveBy(point, duration); - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } void Map::setLatLng(const LatLng& latLng, const Duration& duration) { @@ -457,12 +461,12 @@ void Map::setLatLng(const LatLng& latLng, const Duration& duration) { void Map::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const Duration& duration) { impl->transform.setLatLng(latLng, padding, duration); - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } void Map::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const Duration& duration) { impl->transform.setLatLng(latLng, anchor, duration); - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } LatLng Map::getLatLng(optional<EdgeInsets> padding) const { @@ -477,7 +481,7 @@ void Map::resetPosition(optional<EdgeInsets> padding) { camera.padding = padding; camera.zoom = 0; impl->transform.jumpTo(camera); - update(Update::RecalculateStyle); + impl->onUpdate(Update::RecalculateStyle); } @@ -485,12 +489,12 @@ void Map::resetPosition(optional<EdgeInsets> padding) { void Map::scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& duration) { impl->transform.scaleBy(ds, anchor, duration); - update(Update::RecalculateStyle); + impl->onUpdate(Update::RecalculateStyle); } void Map::setScale(double scale, optional<ScreenCoordinate> anchor, const Duration& duration) { impl->transform.setScale(scale, anchor, duration); - update(Update::RecalculateStyle); + impl->onUpdate(Update::RecalculateStyle); } double Map::getScale() const { @@ -503,7 +507,7 @@ void Map::setZoom(double zoom, const Duration& duration) { void Map::setZoom(double zoom, optional<EdgeInsets> padding, const Duration& duration) { impl->transform.setZoom(zoom, padding, duration); - update(Update::RecalculateStyle); + impl->onUpdate(Update::RecalculateStyle); } double Map::getZoom() const { @@ -516,7 +520,7 @@ void Map::setLatLngZoom(const LatLng& latLng, double zoom, const Duration& durat void Map::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const Duration& duration) { impl->transform.setLatLngZoom(latLng, zoom, padding, duration); - update(Update::RecalculateStyle); + impl->onUpdate(Update::RecalculateStyle); } CameraOptions Map::cameraForLatLngBounds(const LatLngBounds& bounds, optional<EdgeInsets> padding) const { @@ -613,6 +617,11 @@ double Map::getMaxZoom() const { #pragma mark - Size +void Map::setSize(const std::array<uint16_t, 2>& size) { + impl->transform.resize(size); + impl->onUpdate(Update::Repaint); +} + uint16_t Map::getWidth() const { return impl->transform.getState().getWidth(); } @@ -625,7 +634,7 @@ uint16_t Map::getHeight() const { void Map::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const Duration& duration) { impl->transform.rotateBy(first, second, duration); - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } void Map::setBearing(double degrees, const Duration& duration) { @@ -634,12 +643,12 @@ void Map::setBearing(double degrees, const Duration& duration) { void Map::setBearing(double degrees, optional<ScreenCoordinate> anchor, const Duration& duration) { impl->transform.setAngle(-degrees * util::DEG2RAD, anchor, duration); - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } void Map::setBearing(double degrees, optional<EdgeInsets> padding, const Duration& duration) { impl->transform.setAngle(-degrees * util::DEG2RAD, padding, duration); - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } double Map::getBearing() const { @@ -648,7 +657,7 @@ double Map::getBearing() const { void Map::resetNorth(const Duration& duration) { impl->transform.setAngle(0, duration); - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } #pragma mark - Pitch @@ -659,7 +668,7 @@ void Map::setPitch(double pitch, const Duration& duration) { void Map::setPitch(double pitch, optional<ScreenCoordinate> anchor, const Duration& duration) { impl->transform.setPitch(pitch * util::DEG2RAD, anchor, duration); - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } double Map::getPitch() const { @@ -670,7 +679,7 @@ double Map::getPitch() const { void Map::setNorthOrientation(NorthOrientation orientation) { impl->transform.setNorthOrientation(orientation); - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } NorthOrientation Map::getNorthOrientation() const { @@ -681,7 +690,7 @@ NorthOrientation Map::getNorthOrientation() const { void Map::setConstrainMode(mbgl::ConstrainMode mode) { impl->transform.setConstrainMode(mode); - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } ConstrainMode Map::getConstrainMode() const { @@ -692,7 +701,7 @@ ConstrainMode Map::getConstrainMode() const { void Map::setViewportMode(mbgl::ViewportMode mode) { impl->transform.setViewportMode(mode); - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } ViewportMode Map::getViewportMode() const { @@ -737,17 +746,17 @@ double Map::getTopOffsetPixelsForAnnotationIcon(const std::string& name) { AnnotationID Map::addAnnotation(const Annotation& annotation) { auto result = impl->annotationManager->addAnnotation(annotation, getMaxZoom()); - update(Update::AnnotationStyle | Update::AnnotationData); + impl->onUpdate(Update::AnnotationStyle | Update::AnnotationData); return result; } void Map::updateAnnotation(AnnotationID id, const Annotation& annotation) { - update(impl->annotationManager->updateAnnotation(id, annotation, getMaxZoom())); + impl->onUpdate(impl->annotationManager->updateAnnotation(id, annotation, getMaxZoom())); } void Map::removeAnnotation(AnnotationID annotation) { impl->annotationManager->removeAnnotation(annotation); - update(Update::AnnotationStyle | Update::AnnotationData); + impl->onUpdate(Update::AnnotationStyle | Update::AnnotationData); } #pragma mark - Feature query api @@ -833,7 +842,7 @@ void Map::addLayer(std::unique_ptr<Layer> layer, const optional<std::string>& be impl->backend.activate(); impl->style->addLayer(std::move(layer), before); - update(Update::Classes); + impl->onUpdate(Update::Classes); impl->backend.deactivate(); } @@ -847,7 +856,7 @@ void Map::removeLayer(const std::string& id) { impl->backend.activate(); impl->style->removeLayer(id); - update(Update::Classes); + impl->onUpdate(Update::Classes); impl->backend.deactivate(); } @@ -861,7 +870,7 @@ void Map::addImage(const std::string& name, std::unique_ptr<const SpriteImage> i impl->style->spriteAtlas->setSprite(name, std::move(image)); impl->style->spriteAtlas->updateDirty(); - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } void Map::removeImage(const std::string& name) { @@ -873,7 +882,7 @@ void Map::removeImage(const std::string& name) { impl->style->spriteAtlas->removeSprite(name); impl->style->spriteAtlas->updateDirty(); - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } #pragma mark - Defaults @@ -917,7 +926,7 @@ double Map::getDefaultPitch() const { void Map::setDebug(MapDebugOptions debugOptions) { impl->debugOptions = debugOptions; - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } void Map::cycleDebugOptions() { @@ -941,7 +950,7 @@ void Map::cycleDebugOptions() { else impl->debugOptions = MapDebugOptions::TileBorders; - update(Update::Repaint); + impl->onUpdate(Update::Repaint); } MapDebugOptions Map::getDebug() const { @@ -954,20 +963,20 @@ bool Map::isFullyLoaded() const { void Map::addClass(const std::string& className) { if (impl->style && impl->style->addClass(className)) { - update(Update::Classes); + impl->onUpdate(Update::Classes); } } void Map::removeClass(const std::string& className) { if (impl->style && impl->style->removeClass(className)) { - update(Update::Classes); + impl->onUpdate(Update::Classes); } } void Map::setClasses(const std::vector<std::string>& classNames) { if (impl->style) { impl->style->setClasses(classNames); - update(Update::Classes); + impl->onUpdate(Update::Classes); } } @@ -1019,10 +1028,6 @@ void Map::Impl::onSourceAttributionChanged(style::Source&, const std::string&) { } void Map::Impl::onUpdate(Update flags) { - if (flags & Update::Dimensions) { - transform.resize(view.getSize()); - } - updateFlags |= flags; asyncUpdate.send(); } @@ -1036,9 +1041,9 @@ void Map::Impl::onStyleError() { } void Map::Impl::onResourceError(std::exception_ptr error) { - if (mode == MapMode::Still && callback) { - callback(error, {}); - callback = nullptr; + if (mode == MapMode::Still && stillImageRequest) { + auto request = std::move(stillImageRequest); + request->callback(error); } } diff --git a/src/mbgl/map/update.hpp b/src/mbgl/map/update.hpp new file mode 100644 index 0000000000..dc383b819e --- /dev/null +++ b/src/mbgl/map/update.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include <mbgl/util/traits.hpp> + +namespace mbgl { + +enum class Update { + Nothing = 0, + Classes = 1 << 2, + RecalculateStyle = 1 << 3, + RenderStill = 1 << 4, + Repaint = 1 << 5, + AnnotationStyle = 1 << 6, + AnnotationData = 1 << 7, + Layout = 1 << 8 +}; + +constexpr Update operator|(Update lhs, Update rhs) { + return Update(mbgl::underlying_type(lhs) | mbgl::underlying_type(rhs)); +} + +constexpr Update& operator|=(Update& lhs, const Update& rhs) { + return (lhs = lhs | rhs); +} + +constexpr bool operator& (Update lhs, Update rhs) { + return mbgl::underlying_type(lhs) & mbgl::underlying_type(rhs); +} + +} // namespace mbgl diff --git a/src/mbgl/map/view.cpp b/src/mbgl/map/view.cpp deleted file mode 100644 index 23ce70a3cf..0000000000 --- a/src/mbgl/map/view.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include <mbgl/map/view.hpp> -#include <mbgl/map/map.hpp> - -#include <cassert> - -namespace mbgl { - -PremultipliedImage View::readStillImage(std::array<uint16_t, 2>) { - return {}; -} - -void View::initialize(Map *map_) { - assert(map_); - map = map_; -} - -} // namespace mbgl diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index ee7ef6d212..fc61d6e0a0 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -31,6 +31,8 @@ #include <mbgl/util/mat3.hpp> #include <mbgl/util/string.hpp> +#include <mbgl/util/offscreen_texture.hpp> + #include <cassert> #include <algorithm> #include <iostream> @@ -40,8 +42,9 @@ namespace mbgl { using namespace style; -Painter::Painter(const TransformState& state_) - : state(state_), +Painter::Painter(gl::Context& context_, const TransformState& state_) + : context(context_), + state(state_), tileTriangleVertexBuffer(context.createVertexBuffer(std::vector<FillVertex> {{ { 0, 0 }, { util::EXTENT, 0 }, @@ -71,9 +74,6 @@ Painter::Painter(const TransformState& state_) #ifndef NDEBUG overdrawShaders = std::make_unique<Shaders>(context, gl::Shader::Overdraw); #endif - - // Reset GL values - context.setDirtyState(); } Painter::~Painter() = default; @@ -93,9 +93,10 @@ void Painter::cleanup() { } void Painter::render(const Style& style, const FrameData& frame_, View& view, SpriteAtlas& annotationSpriteAtlas) { - context.viewport.setDefaultValue( - { 0, 0, view.getFramebufferSize()[0], view.getFramebufferSize()[1] }); frame = frame_; + if (frame.contextMode == GLContextMode::Shared) { + context.setDirtyState(); + } PaintParameters parameters { #ifndef NDEBUG @@ -126,12 +127,14 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp frameHistory.record(frame.timePoint, state.getZoom(), frame.mapMode == MapMode::Continuous ? util::DEFAULT_FADE_DURATION : Milliseconds(0)); + // - UPLOAD PASS ------------------------------------------------------------------------------- // Uploads all required buffers and images before we do any actual rendering. { MBGL_DEBUG_GROUP("upload"); spriteAtlas->upload(context, 0); + lineAtlas->upload(context, 0); glyphAtlas->upload(context, 0); frameHistory.upload(context, 0); @@ -149,10 +152,8 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp // tiles whatsoever. { MBGL_DEBUG_GROUP("clear"); - context.bindFramebuffer.setDirty(); view.bind(); - context.viewport.reset(); - context.stencilFunc.reset(); + context.stencilFunc = { gl::StencilTestFunction::Always, 0, ~0u }; context.stencilTest = true; context.stencilMask = 0xFF; context.depthTest = false; @@ -249,10 +250,6 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp context.vertexArrayObject = 0; } - - if (frame.contextMode == GLContextMode::Shared) { - context.setDirtyState(); - } } template <class Iterator> @@ -296,17 +293,21 @@ void Painter::renderPass(PaintParameters& parameters, renderBackground(parameters, *layer.as<BackgroundLayer>()); } else if (layer.is<CustomLayer>()) { MBGL_DEBUG_GROUP(layer.baseImpl->id + " - custom"); + + // Reset GL state to a known state so the CustomLayer always has a clean slate. context.vertexArrayObject = 0; context.depthFunc = gl::DepthTestFunction::LessEqual; context.depthTest = true; context.depthMask = false; context.stencilTest = false; setDepthSublayer(0); + layer.as<CustomLayer>()->impl->render(state); - context.setDirtyState(); - context.bindFramebuffer.setDirty(); + + // Reset the view back to our original one, just in case the CustomLayer changed + // the viewport or Framebuffer. parameters.view.bind(); - context.viewport.reset(); + context.setDirtyState(); } else { MBGL_DEBUG_GROUP(layer.baseImpl->id + " - " + util::toString(item.tile->id)); if (item.bucket->needsClipping()) { diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index d2c89c04a9..f339ed1aed 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -68,7 +68,7 @@ struct FrameData { class Painter : private util::noncopyable { public: - Painter(const TransformState&); + Painter(gl::Context&, const TransformState&); ~Painter(); void render(const style::Style&, @@ -153,6 +153,9 @@ private: } #endif +private: + gl::Context& context; + mat4 projMatrix; std::array<float, 2> pixelsToGLUnits; @@ -169,8 +172,6 @@ private: int indent = 0; - gl::Context context; - RenderPass pass = RenderPass::Opaque; int numSublayers = 3; diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painter_debug.cpp index ca961f84e7..e57bb2205e 100644 --- a/src/mbgl/renderer/painter_debug.cpp +++ b/src/mbgl/renderer/painter_debug.cpp @@ -89,7 +89,7 @@ void Painter::renderDebugFrame(const mat4 &matrix) { } #ifndef NDEBUG -void Painter::renderClipMasks(PaintParameters& parameters) { +void Painter::renderClipMasks(PaintParameters&) { context.stencilTest = false; context.depthTest = false; context.program = 0; @@ -100,13 +100,13 @@ void Painter::renderClipMasks(PaintParameters& parameters) { context.rasterPos = { -1, -1, 0, 0 }; // Read the stencil buffer - const auto& fbSize = parameters.view.getFramebufferSize(); - auto pixels = std::make_unique<uint8_t[]>(fbSize[0] * fbSize[1]); + const auto viewport = context.viewport.getCurrentValue(); + auto pixels = std::make_unique<uint8_t[]>(viewport.width * viewport.height); MBGL_CHECK_ERROR(glReadPixels( - 0, // GLint x - 0, // GLint y - fbSize[0], // GLsizei width - fbSize[1], // GLsizei height + viewport.x, // GLint x + viewport.y, // GLint y + viewport.width, // GLsizei width + viewport.height, // GLsizei height GL_STENCIL_INDEX, // GLenum format GL_UNSIGNED_BYTE, // GLenum type pixels.get() // GLvoid * data @@ -114,22 +114,21 @@ void Painter::renderClipMasks(PaintParameters& parameters) { // Scale the Stencil buffer to cover the entire color space. auto it = pixels.get(); - auto end = it + fbSize[0] * fbSize[1]; + auto end = it + viewport.width * viewport.height; const auto factor = 255.0f / *std::max_element(it, end); for (; it != end; ++it) { *it *= factor; } - MBGL_CHECK_ERROR(glWindowPos2i(0, 0)); - MBGL_CHECK_ERROR(glDrawPixels(fbSize[0], fbSize[1], GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels.get())); -#else - (void)parameters; + MBGL_CHECK_ERROR(glWindowPos2i(viewport.x, viewport.y)); + MBGL_CHECK_ERROR(glDrawPixels(viewport.width, viewport.height, GL_LUMINANCE, GL_UNSIGNED_BYTE, + pixels.get())); #endif // MBGL_USE_GLES2 } #endif // NDEBUG #ifndef NDEBUG -void Painter::renderDepthBuffer(PaintParameters& parameters) { +void Painter::renderDepthBuffer(PaintParameters&) { context.stencilTest = false; context.depthTest = false; context.program = 0; @@ -140,27 +139,26 @@ void Painter::renderDepthBuffer(PaintParameters& parameters) { context.rasterPos = { -1, -1, 0, 0 }; // Read the stencil buffer - const auto& fbSize = parameters.view.getFramebufferSize(); - auto pixels = std::make_unique<GLubyte[]>(fbSize[0] * fbSize[1]); + const auto viewport = context.viewport.getCurrentValue(); + auto pixels = std::make_unique<uint8_t[]>(viewport.width * viewport.height); const double base = 1.0 / (1.0 - depthRangeSize); glPixelTransferf(GL_DEPTH_SCALE, base); glPixelTransferf(GL_DEPTH_BIAS, 1.0 - base); MBGL_CHECK_ERROR(glReadPixels( - 0, // GLint x - 0, // GLint y - fbSize[0], // GLsizei width - fbSize[1], // GLsizei height + viewport.x, // GLint x + viewport.y, // GLint y + viewport.width, // GLsizei width + viewport.height, // GLsizei height GL_DEPTH_COMPONENT, // GLenum format GL_UNSIGNED_BYTE, // GLenum type pixels.get() // GLvoid * data )); - MBGL_CHECK_ERROR(glWindowPos2i(0, 0)); - MBGL_CHECK_ERROR(glDrawPixels(fbSize[0], fbSize[1], GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels.get())); -#else - (void)parameters; + MBGL_CHECK_ERROR(glWindowPos2i(viewport.x, viewport.y)); + MBGL_CHECK_ERROR(glDrawPixels(viewport.width, viewport.height, GL_LUMINANCE, GL_UNSIGNED_BYTE, + pixels.get())); #endif // MBGL_USE_GLES2 } #endif // NDEBUG diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp index 1fc5f11079..b6606ca40b 100644 --- a/src/mbgl/renderer/painter_fill.cpp +++ b/src/mbgl/renderer/painter_fill.cpp @@ -30,7 +30,9 @@ void Painter::renderFill(PaintParameters& parameters, const bool isOutlineColorDefined = !properties.fillOutlineColor.isUndefined(); Color strokeColor = isOutlineColorDefined? properties.fillOutlineColor : fillColor; - auto worldSize = util::convert<GLfloat>(parameters.view.getFramebufferSize()); + const auto viewport = context.viewport.getCurrentValue(); + const std::array<GLfloat, 2> worldSize{ { static_cast<GLfloat>(viewport.width), + static_cast<GLfloat>(viewport.height) } }; bool pattern = !properties.fillPattern.value.from.empty(); bool outline = properties.fillAntialias && !pattern && isOutlineColorDefined; diff --git a/src/mbgl/util/offscreen_texture.cpp b/src/mbgl/util/offscreen_texture.cpp index 51049f8282..40bb70b70e 100644 --- a/src/mbgl/util/offscreen_texture.cpp +++ b/src/mbgl/util/offscreen_texture.cpp @@ -1,70 +1,48 @@ +#include <mbgl/util/offscreen_texture.hpp> #include <mbgl/gl/context.hpp> #include <mbgl/gl/gl.hpp> -#include <mbgl/util/offscreen_texture.hpp> +#include <cstring> #include <cassert> namespace mbgl { -void OffscreenTexture::bind(gl::Context& context, - std::array<uint16_t, 2> size) { +OffscreenTexture::OffscreenTexture(gl::Context& context_, std::array<uint16_t, 2> size_) + : context(context_), size(std::move(size_)) { assert(size[0] > 0 && size[1] > 0); +} - if (!texture || texture->size != size) { - texture = context.createTexture(size); - } - +void OffscreenTexture::bind() { if (!framebuffer) { - framebuffer = context.createFramebuffer(); - context.bindFramebuffer = *framebuffer; - MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - texture->texture, 0)); - - GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatus(GL_FRAMEBUFFER)); - if (status != GL_FRAMEBUFFER_COMPLETE) { - switch (status) { - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - throw std::runtime_error("Couldn't create framebuffer: incomplete attachment"); - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - throw std::runtime_error( - "Couldn't create framebuffer: incomplete missing attachment"); -#ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: - throw std::runtime_error("Couldn't create framebuffer: incomplete draw buffer"); -#endif -#ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: - throw std::runtime_error("Couldn't create framebuffer: incomplete read buffer"); -#endif -#ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: - throw std::runtime_error("Couldn't create framebuffer: incomplete dimensions"); -#endif - - case GL_FRAMEBUFFER_UNSUPPORTED: - throw std::runtime_error("Couldn't create framebuffer: unsupported"); - default: - throw std::runtime_error("Couldn't create framebuffer: other"); - } - } + texture = context.createTexture(size); + framebuffer = context.createFramebuffer(*texture); } else { - context.bindFramebuffer = *framebuffer; + context.bindFramebuffer = framebuffer->framebuffer; } context.viewport = { 0, 0, size[0], size[1] }; } gl::Texture& OffscreenTexture::getTexture() { + assert(texture); return *texture; } -std::array<uint16_t, 2> OffscreenTexture::getSize() const { - if (texture) { - // Use explicit dereference instead of -> due to clang 3.5 bug - return (*texture).size; - } else { - return {{ 0, 0 }}; +PremultipliedImage OffscreenTexture::readStillImage() { + PremultipliedImage image { size[0], size[1] }; + MBGL_CHECK_ERROR(glReadPixels(0, 0, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE, image.data.get())); + + const auto stride = image.stride(); + auto tmp = std::make_unique<uint8_t[]>(stride); + uint8_t* rgba = image.data.get(); + for (int i = 0, j = size[1] - 1; i < j; i++, j--) { + std::memcpy(tmp.get(), rgba + i * stride, stride); + std::memcpy(rgba + i * stride, rgba + j * stride, stride); + std::memcpy(rgba + j * stride, tmp.get(), stride); } + + return image; } + } // namespace mbgl diff --git a/src/mbgl/util/offscreen_texture.hpp b/src/mbgl/util/offscreen_texture.hpp index c71c0e51d9..8928bc2434 100644 --- a/src/mbgl/util/offscreen_texture.hpp +++ b/src/mbgl/util/offscreen_texture.hpp @@ -1,6 +1,10 @@ #pragma once +#include <mbgl/map/view.hpp> +#include <mbgl/gl/framebuffer.hpp> #include <mbgl/gl/texture.hpp> +#include <mbgl/util/optional.hpp> +#include <mbgl/util/image.hpp> namespace mbgl { @@ -8,15 +12,20 @@ namespace gl { class Context; } // namespace gl -class OffscreenTexture { +class OffscreenTexture : public View { public: - void bind(gl::Context&, std::array<uint16_t, 2> size); + OffscreenTexture(gl::Context&, std::array<uint16_t, 2> size = {{ 256, 256 }}); + + void bind() override; + + PremultipliedImage readStillImage(); gl::Texture& getTexture(); - std::array<uint16_t, 2> getSize() const; private: - optional<gl::UniqueFramebuffer> framebuffer; + gl::Context& context; + std::array<uint16_t, 2> size; + optional<gl::Framebuffer> framebuffer; optional<gl::Texture> texture; }; |