summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mbgl/gl/context.cpp183
-rw-r--r--src/mbgl/gl/context.hpp27
-rw-r--r--src/mbgl/gl/framebuffer.hpp17
-rw-r--r--src/mbgl/gl/gl.cpp1
-rw-r--r--src/mbgl/gl/object.cpp5
-rw-r--r--src/mbgl/gl/object.hpp6
-rw-r--r--src/mbgl/gl/renderbuffer.hpp19
-rw-r--r--src/mbgl/gl/state.hpp36
-rw-r--r--src/mbgl/gl/types.hpp5
-rw-r--r--src/mbgl/gl/value.cpp16
-rw-r--r--src/mbgl/gl/value.hpp9
-rw-r--r--src/mbgl/map/backend.cpp10
-rw-r--r--src/mbgl/map/map.cpp147
-rw-r--r--src/mbgl/map/update.hpp30
-rw-r--r--src/mbgl/map/view.cpp17
-rw-r--r--src/mbgl/renderer/painter.cpp35
-rw-r--r--src/mbgl/renderer/painter.hpp7
-rw-r--r--src/mbgl/renderer/painter_debug.cpp44
-rw-r--r--src/mbgl/renderer/painter_fill.cpp4
-rw-r--r--src/mbgl/util/offscreen_texture.cpp70
-rw-r--r--src/mbgl/util/offscreen_texture.hpp17
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;
};