diff options
54 files changed, 774 insertions, 520 deletions
diff --git a/benchmark/api/query.benchmark.cpp b/benchmark/api/query.benchmark.cpp index a9c4ade2da..5fa6a84db7 100644 --- a/benchmark/api/query.benchmark.cpp +++ b/benchmark/api/query.benchmark.cpp @@ -2,7 +2,7 @@ #include <mbgl/benchmark/util.hpp> #include <mbgl/map/map.hpp> -#include <mbgl/platform/default/headless_display.hpp> +#include <mbgl/platform/default/headless_backend.hpp> #include <mbgl/platform/default/headless_view.hpp> #include <mbgl/platform/default/thread_pool.hpp> #include <mbgl/sprite/sprite_image.hpp> @@ -35,11 +35,11 @@ public: } util::RunLoop loop; - std::shared_ptr<HeadlessDisplay> display{ std::make_shared<HeadlessDisplay>() }; - HeadlessView view{ display, 1 }; + HeadlessBackend backend; + HeadlessView view; DefaultFileSource fileSource{ "benchmark/fixtures/api/cache.db", "." }; ThreadPool threadPool{ 4 }; - Map map{ view, fileSource, threadPool, MapMode::Still }; + Map map{ backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still }; ScreenBox box{{ 0, 0 }, { 1000, 1000 }}; }; diff --git a/bin/glfw.cpp b/bin/glfw.cpp index c0d61820f8..44713d7532 100644 --- a/bin/glfw.cpp +++ b/bin/glfw.cpp @@ -16,7 +16,7 @@ namespace { -std::unique_ptr<GLFWView> view; +GLFWView* view = nullptr; } @@ -104,7 +104,8 @@ int main(int argc, char *argv[]) { mbgl::Log::Info(mbgl::Event::General, "BENCHMARK MODE: Some optimizations are disabled."); } - view = std::make_unique<GLFWView>(fullscreen, benchmark); + GLFWView backend(fullscreen, benchmark); + view = &backend; mbgl::DefaultFileSource fileSource("/tmp/mbgl-cache.db", "."); @@ -118,7 +119,7 @@ int main(int argc, char *argv[]) { mbgl::ThreadPool threadPool(4); - mbgl::Map map(*view, fileSource, threadPool); + mbgl::Map map(backend, backend, backend.getPixelRatio(), fileSource, threadPool); // Load settings mbgl::Settings_JSON settings; @@ -181,5 +182,6 @@ int main(int argc, char *argv[]) { "Exit location: --lat=\"%f\" --lon=\"%f\" --zoom=\"%f\" --bearing \"%f\"", settings.latitude, settings.longitude, settings.zoom, settings.bearing); + view = nullptr; return 0; } diff --git a/bin/render.cpp b/bin/render.cpp index e4d9951c05..f9574d0523 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -3,7 +3,7 @@ #include <mbgl/util/io.hpp> #include <mbgl/util/run_loop.hpp> -#include <mbgl/platform/default/headless_display.hpp> +#include <mbgl/platform/default/headless_backend.hpp> #include <mbgl/platform/default/headless_view.hpp> #include <mbgl/platform/default/thread_pool.hpp> #include <mbgl/storage/default_file_source.hpp> @@ -84,9 +84,10 @@ int main(int argc, char *argv[]) { fileSource.setAccessToken(std::string(token)); } + HeadlessBackend backend; HeadlessView view(pixelRatio, width, height); ThreadPool threadPool(4); - Map map(view, fileSource, threadPool, MapMode::Still); + Map map(backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still); map.setStyleJSON(style); map.setClasses(classes); diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index fac5490bb4..255d40fa50 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -54,6 +54,7 @@ set(MBGL_CORE_FILES # gl include/mbgl/gl/gl.hpp + include/mbgl/gl/implementation.hpp src/mbgl/gl/attribute.hpp src/mbgl/gl/context.cpp src/mbgl/gl/context.hpp @@ -92,11 +93,13 @@ set(MBGL_CORE_FILES src/mbgl/layout/symbol_layout.hpp # map + include/mbgl/map/backend.hpp include/mbgl/map/camera.hpp include/mbgl/map/map.hpp include/mbgl/map/mode.hpp include/mbgl/map/update.hpp include/mbgl/map/view.hpp + src/mbgl/map/backend.cpp src/mbgl/map/change.hpp src/mbgl/map/map.cpp src/mbgl/map/transform.cpp @@ -130,6 +133,7 @@ set(MBGL_CORE_FILES # platform/default include/mbgl/platform/default/glfw_view.hpp + include/mbgl/platform/default/headless_backend.hpp include/mbgl/platform/default/headless_display.hpp include/mbgl/platform/default/headless_view.hpp include/mbgl/platform/default/settings_json.hpp diff --git a/include/mbgl/gl/implementation.hpp b/include/mbgl/gl/implementation.hpp new file mode 100644 index 0000000000..4e3a3e51c7 --- /dev/null +++ b/include/mbgl/gl/implementation.hpp @@ -0,0 +1,14 @@ +#pragma once + +#if defined(__QT__) + #define MBGL_USE_QT 1 +#elif defined(__APPLE__) + #include <TargetConditionals.h> + #if TARGET_OS_IOS + #define MBGL_USE_EAGL 1 + #else + #define MBGL_USE_CGL 1 + #endif +#else + #define MBGL_USE_GLX 1 +#endif diff --git a/include/mbgl/map/backend.hpp b/include/mbgl/map/backend.hpp new file mode 100644 index 0000000000..e4a5634b88 --- /dev/null +++ b/include/mbgl/map/backend.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include <mbgl/map/change.hpp> + +namespace mbgl { + +class Map; + +class Backend { +public: + virtual ~Backend() = default; + + // Called when the backend's GL context needs to be made active or inactive. These are called, + // as a matched pair, in four situations: + // + // 1. When releasing GL resources during Map destruction + // 2. When calling a CustomLayerInitializeFunction, during Map::addLayer + // 3. When calling a CustomLayerDeinitializeFunction, during Map::removeLayer + // 4. When rendering for Map::renderStill + // + // They are *not* called for Map::render; it is assumed that the correct context is already + // activated prior to calling Map::render. + virtual void activate() = 0; + virtual void deactivate() = 0; + + // Called when the map needs to be rendered; the backend should call Map::render() at some point + // in the near future. (Not called for Map::renderStill() mode.) + virtual void invalidate() = 0; + + // Notifies a watcher of map x/y/scale/rotation changes. + virtual void notifyMapChange(MapChange change); +}; + +} // namespace mbgl diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 2831206d54..4f6207fc6f 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -19,6 +19,7 @@ namespace mbgl { +class Backend; class View; class FileSource; class Scheduler; @@ -33,7 +34,11 @@ class Layer; class Map : private util::noncopyable { public: - explicit Map(View&, FileSource&, Scheduler&, + explicit Map(Backend&, + View&, + float pixelRatio, + FileSource&, + Scheduler&, MapMode mapMode = MapMode::Continuous, GLContextMode contextMode = GLContextMode::Unique, ConstrainMode constrainMode = ConstrainMode::HeightOnly, diff --git a/include/mbgl/map/view.hpp b/include/mbgl/map/view.hpp index 590eef7237..0dff4b3602 100644 --- a/include/mbgl/map/view.hpp +++ b/include/mbgl/map/view.hpp @@ -1,24 +1,23 @@ #pragma once -#include <mbgl/map/change.hpp> -#include <mbgl/util/chrono.hpp> #include <mbgl/util/image.hpp> #include <array> -#include <functional> -#include <memory> namespace mbgl { class Map; -class View { +class View : private util::noncopyable { public: virtual ~View() = default; - // Called directly after initialization. Must always return the same value, i.e. it may - // not change over time. - virtual float getPixelRatio() const = 0; + // Called when this View is associated with a Map object. + virtual void initialize(Map*); + + // Called when this View is used for rendering. Implementations should ensure that a renderable + // object is bound and glClear/glDraw* calls can be done. + virtual void bind() = 0; // Called when the View signaled a dimension change. Must return the logical dimension // of this map in pixels. @@ -30,34 +29,12 @@ public: // different from that rule. virtual std::array<uint16_t, 2> getFramebufferSize() const = 0; - // Called when this View is associated with a Map object. - virtual void initialize(Map*); - - // Called when the view's GL context needs to be made active or inactive. These are called, - // as a matched pair, in four situations: - // - // 1. When releasing GL resources during Map destruction - // 2. When calling a CustomLayerInitializeFunction, during Map::addLayer - // 3. When calling a CustomLayerDeinitializeFunction, during Map::removeLayer - // 4. When rendering for Map::renderStill - // - // They are *not* called for Map::render; it is assumed that the correct context is already - // activated prior to calling Map::render. - virtual void activate() = 0; - virtual void deactivate() = 0; - - // Called when the map needs to be rendered; the view should call Map::render() at some point - // in the near future. (Not called for Map::renderStill() mode.) - virtual void invalidate() = 0; - // Reads the pixel data from the current framebuffer. If your View implementation // doesn't support reading from the framebuffer, return a null pointer. virtual PremultipliedImage readStillImage(std::array<uint16_t, 2> size = {{ 0, 0 }}); - // Notifies a watcher of map x/y/scale/rotation changes. - virtual void notifyMapChange(MapChange change); - protected: mbgl::Map *map = nullptr; }; + } // namespace mbgl diff --git a/include/mbgl/platform/default/glfw_view.hpp b/include/mbgl/platform/default/glfw_view.hpp index 8662a90bf3..a115d03d7f 100644 --- a/include/mbgl/platform/default/glfw_view.hpp +++ b/include/mbgl/platform/default/glfw_view.hpp @@ -1,6 +1,7 @@ #pragma once #include <mbgl/mbgl.hpp> +#include <mbgl/map/backend.hpp> #include <mbgl/util/run_loop.hpp> #include <mbgl/util/timer.hpp> #include <mbgl/util/geometry.hpp> @@ -11,20 +12,36 @@ #define GL_GLEXT_PROTOTYPES #include <GLFW/glfw3.h> -class GLFWView : public mbgl::View { +class GLFWView : public mbgl::View, public mbgl::Backend { public: GLFWView(bool fullscreen = false, bool benchmark = false); ~GLFWView() override; - float getPixelRatio() const override; + float getPixelRatio() const; + + // Callback called when the user presses the key mapped to style change. + // The expected action is to set a new style, different to the current one. + void setChangeStyleCallback(std::function<void()> callback); + + void setShouldClose(); + + void setWindowTitle(const std::string&); + + void run(); + +private: + // mbgl::View implementation + void initialize(mbgl::Map*) override; + void bind() override; std::array<uint16_t, 2> getSize() const override; std::array<uint16_t, 2> getFramebufferSize() const override; - void initialize(mbgl::Map*) override; + // mbgl::Backend implementation void activate() override; void deactivate() override; void invalidate() override; + // Window callbacks static void onKey(GLFWwindow *window, int key, int scancode, int action, int mods); static void onScroll(GLFWwindow *window, double xoffset, double yoffset); static void onWindowResize(GLFWwindow *window, int width, int height); @@ -32,21 +49,12 @@ public: static void onMouseClick(GLFWwindow *window, int button, int action, int modifiers); static void onMouseMove(GLFWwindow *window, double x, double y); - // Callback called when the user presses the key mapped to style change. - // The expected action is to set a new style, different to the current one. - void setChangeStyleCallback(std::function<void()> callback); - - void setShouldClose(); - - void setWindowTitle(const std::string&); - - void run(); + // Internal void report(float duration); void setMapChangeCallback(std::function<void(mbgl::MapChange)> callback); void notifyMapChange(mbgl::MapChange change) override; -private: mbgl::Color makeRandomColor() const; mbgl::Point<double> makeRandomPoint() const; static std::shared_ptr<const mbgl::SpriteImage> diff --git a/include/mbgl/platform/default/headless_backend.hpp b/include/mbgl/platform/default/headless_backend.hpp new file mode 100644 index 0000000000..2f4886a365 --- /dev/null +++ b/include/mbgl/platform/default/headless_backend.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include <mbgl/gl/implementation.hpp> + +#if MBGL_USE_QT +class QGLWidget; +#elif MBGL_USE_CGL +#include <OpenGL/OpenGL.h> +#elif MBGL_USE_GLX +typedef struct _XDisplay Display; +typedef struct __GLXcontextRec* GLXContext; +typedef struct __GLXFBConfigRec* GLXFBConfig; +typedef long unsigned int XID; +typedef XID GLXPbuffer; +#endif + +#include <mbgl/map/backend.hpp> +#include <mbgl/gl/extension.hpp> + +#include <memory> +#include <functional> + +namespace mbgl { + +class HeadlessDisplay; + +class HeadlessBackend : public Backend { +public: + HeadlessBackend(); + HeadlessBackend(std::shared_ptr<HeadlessDisplay>); + ~HeadlessBackend() override; + + void invalidate() override; + void activate() override; + void deactivate() override; + void notifyMapChange(MapChange) override; + + void setMapChangeCallback(std::function<void(MapChange)>&& cb) { mapChangeCallback = std::move(cb); } + +private: + void activateContext(); + void deactivateContext(); + +private: + // Implementation specific functions + static gl::glProc initializeExtension(const char*); + void createContext(); + void destroyContext(); + + std::shared_ptr<HeadlessDisplay> display; + + bool extensionsLoaded = false; + bool active = false; + +#if MBGL_USE_QT + QGLWidget* glContext = nullptr; +#endif + +#if MBGL_USE_CGL + CGLContextObj glContext = nullptr; +#endif + +#if MBGL_USE_EAGL + void *glContext = nullptr; +#endif + +#if MBGL_USE_GLX + Display *xDisplay = nullptr; + GLXFBConfig *fbConfigs = nullptr; + GLXContext glContext = nullptr; + GLXPbuffer glxPbuffer = 0; +#endif + + std::function<void(MapChange)> mapChangeCallback; + +}; + +} // namespace mbgl diff --git a/include/mbgl/platform/default/headless_display.hpp b/include/mbgl/platform/default/headless_display.hpp index edcc905221..f43e61340f 100644 --- a/include/mbgl/platform/default/headless_display.hpp +++ b/include/mbgl/platform/default/headless_display.hpp @@ -1,6 +1,13 @@ #pragma once -#include <mbgl/platform/default/headless_view.hpp> +#include <mbgl/gl/implementation.hpp> + +#if MBGL_USE_CGL +#include <OpenGL/OpenGL.h> +#elif MBGL_USE_GLX +typedef struct _XDisplay Display; +typedef struct __GLXFBConfigRec* GLXFBConfig; +#endif namespace mbgl { diff --git a/include/mbgl/platform/default/headless_view.hpp b/include/mbgl/platform/default/headless_view.hpp index 23f1e8251a..27af4fc9d9 100644 --- a/include/mbgl/platform/default/headless_view.hpp +++ b/include/mbgl/platform/default/headless_view.hpp @@ -1,95 +1,37 @@ #pragma once -#if defined(__QT__) -#define MBGL_USE_QT 1 -class QGLWidget; -#elif defined(__APPLE__) -#include <TargetConditionals.h> -#if TARGET_OS_IOS -#define MBGL_USE_EAGL 1 -#else -#define MBGL_USE_CGL 1 -#endif -#else -#define GL_GLEXT_PROTOTYPES -#define MBGL_USE_GLX 1 -typedef struct _XDisplay Display; -typedef struct __GLXcontextRec* GLXContext; -typedef struct __GLXFBConfigRec* GLXFBConfig; -typedef long unsigned int XID; -typedef XID GLXPbuffer; -#endif - -#include <mbgl/mbgl.hpp> -#include <mbgl/gl/gl.hpp> +#include <mbgl/map/view.hpp> #include <mbgl/gl/types.hpp> -#include <mbgl/gl/extension.hpp> - -#include <memory> -#include <thread> namespace mbgl { -class HeadlessDisplay; - class HeadlessView : public View { public: - HeadlessView(float pixelRatio, uint16_t width = 256, uint16_t height = 256); - HeadlessView(std::shared_ptr<HeadlessDisplay> display, float pixelRatio, uint16_t width = 256, uint16_t height = 256); + HeadlessView(float pixelRatio = 1, uint16_t width = 256, uint16_t height = 256); ~HeadlessView() override; - float getPixelRatio() const override; + void bind() override; + std::array<uint16_t, 2> getSize() const override; std::array<uint16_t, 2> getFramebufferSize() const override; - void invalidate() override; - void activate() override; - void deactivate() override; - void notifyMapChange(MapChange) override; PremultipliedImage readStillImage(std::array<uint16_t, 2> size = {{ 0, 0 }}) override; + float getPixelRatio() const; + void resize(uint16_t width, uint16_t height); - void setMapChangeCallback(std::function<void(MapChange)>&& cb) { mapChangeCallback = std::move(cb); } private: - // Implementation specific functions - static gl::glProc initializeExtension(const char*); - void createContext(); - void destroyContext(); void clearBuffers(); void resizeFramebuffer(); - void activateContext(); - void deactivateContext(); + void bindFramebuffer(); - std::shared_ptr<HeadlessDisplay> display; +private: const float pixelRatio; std::array<uint16_t, 2> dimensions; bool needsResize = false; - bool extensionsLoaded = false; - bool active = false; - -#if MBGL_USE_QT - QGLWidget* glContext = nullptr; -#endif - -#if MBGL_USE_CGL - CGLContextObj glContext = nullptr; -#endif - -#if MBGL_USE_EAGL - void *glContext = nullptr; -#endif - -#if MBGL_USE_GLX - Display *xDisplay = nullptr; - GLXFBConfig *fbConfigs = nullptr; - GLXContext glContext = nullptr; - GLXPbuffer glxPbuffer = 0; -#endif - - std::function<void(MapChange)> mapChangeCallback; gl::FramebufferID fbo = 0; gl::RenderbufferID fboDepthStencil = 0; diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 5bd2694932..fe201ac069 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -55,10 +55,8 @@ void log_gl_string(GLenum name, const char *label) { } } -NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float pixelRatio_, int availableProcessors_, size_t totalMemory_) - : mbgl::View(*this), - env(env_), - pixelRatio(pixelRatio_), +NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float pixelRatio, int availableProcessors_, size_t totalMemory_) + : env(env_), availableProcessors(availableProcessors_), totalMemory(totalMemory_), threadPool(4) { @@ -82,7 +80,7 @@ NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float pixelRatio_, int mbgl::android::cachePath + "/mbgl-offline.db", mbgl::android::apkPath); - map = std::make_unique<mbgl::Map>(*this, *fileSource, threadPool, MapMode::Continuous); + map = std::make_unique<mbgl::Map>(*this, *this, pixelRatio, *fileSource, threadPool, MapMode::Continuous); float zoomFactor = map->getMaxZoom() - map->getMinZoom() + 1; float cpuFactor = availableProcessors; @@ -114,8 +112,8 @@ NativeMapView::~NativeMapView() { vm = nullptr; } -float NativeMapView::getPixelRatio() const { - return pixelRatio; +void NativeMapView::bind() { + MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); } std::array<uint16_t, 2> NativeMapView::getSize() const { diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index d42890dae2..42a9a10ad4 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -2,6 +2,7 @@ #include <mbgl/map/map.hpp> #include <mbgl/map/view.hpp> +#include <mbgl/map/backend.hpp> #include <mbgl/util/noncopyable.hpp> #include <mbgl/platform/default/thread_pool.hpp> #include <mbgl/storage/default_file_source.hpp> @@ -14,12 +15,13 @@ namespace mbgl { namespace android { -class NativeMapView : public mbgl::View, private mbgl::util::noncopyable { +class NativeMapView : public mbgl::View, public mbgl::Backend { public: NativeMapView(JNIEnv *env, jobject obj, float pixelRatio, int availableProcessors, size_t totalMemory); virtual ~NativeMapView(); - float getPixelRatio() const override; + void bind() override; + std::array<uint16_t, 2> getSize() const override; std::array<uint16_t, 2> getFramebufferSize() const override; void activate() override; @@ -89,7 +91,6 @@ private: int height = 0; int fbWidth = 0; int fbHeight = 0; - const float pixelRatio; int availableProcessors = 0; size_t totalMemory = 0; diff --git a/platform/darwin/src/headless_backend_cgl.cpp b/platform/darwin/src/headless_backend_cgl.cpp new file mode 100644 index 0000000000..4ca567f55c --- /dev/null +++ b/platform/darwin/src/headless_backend_cgl.cpp @@ -0,0 +1,58 @@ +#include <mbgl/platform/default/headless_backend.hpp> +#include <mbgl/platform/default/headless_display.hpp> + +#include <CoreFoundation/CoreFoundation.h> + +#include <string> +#include <stdexcept> + +namespace mbgl { + +gl::glProc HeadlessBackend::initializeExtension(const char* name) { + static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); + if (!framework) { + throw std::runtime_error("Failed to load OpenGL framework."); + } + + CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); + void* symbol = CFBundleGetFunctionPointerForName(framework, str); + CFRelease(str); + + return reinterpret_cast<gl::glProc>(symbol); +} + +void HeadlessBackend::createContext() { + CGLError error = CGLCreateContext(display->pixelFormat, nullptr, &glContext); + if (error != kCGLNoError) { + throw std::runtime_error(std::string("Error creating GL context object:") + + CGLErrorString(error) + "\n"); + } + + error = CGLEnable(glContext, kCGLCEMPEngine); + if (error != kCGLNoError) { + throw std::runtime_error(std::string("Error enabling OpenGL multithreading:") + + CGLErrorString(error) + "\n"); + } +} + +void HeadlessBackend::destroyContext() { + CGLDestroyContext(glContext); +} + +void HeadlessBackend::activateContext() { + CGLError error = CGLSetCurrentContext(glContext); + if (error != kCGLNoError) { + throw std::runtime_error(std::string("Switching OpenGL context failed:") + + CGLErrorString(error) + "\n"); + } +} + +void HeadlessBackend::deactivateContext() { + CGLError error = CGLSetCurrentContext(nullptr); + if (error != kCGLNoError) { + throw std::runtime_error(std::string("Removing OpenGL context failed:") + + CGLErrorString(error) + "\n"); + } +} + +} // namespace mbgl diff --git a/platform/darwin/src/headless_backend_eagl.mm b/platform/darwin/src/headless_backend_eagl.mm new file mode 100644 index 0000000000..0a1ae706b8 --- /dev/null +++ b/platform/darwin/src/headless_backend_eagl.mm @@ -0,0 +1,46 @@ +#include <mbgl/platform/default/headless_backend.hpp> + +#include <mbgl/gl/extension.hpp> + +#include <OpenGLES/EAGL.h> + +#include <stdexcept> + +namespace mbgl { + +gl::glProc HeadlessBackend::initializeExtension(const char* name) { + static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles")); + if (!framework) { + throw std::runtime_error("Failed to load OpenGL framework."); + } + + CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); + void* symbol = CFBundleGetFunctionPointerForName(framework, str); + CFRelease(str); + + return reinterpret_cast<gl::glProc>(symbol); +} + +void HeadlessBackend::createContext() { + glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + if (glContext == nil) { + throw std::runtime_error("Error creating GL context object"); + } + [reinterpret_cast<EAGLContext*>(glContext) retain]; + reinterpret_cast<EAGLContext*>(glContext).multiThreaded = YES; +} + +void HeadlessBackend::destroyContext() { + [reinterpret_cast<EAGLContext*>(glContext) release]; + glContext = nil; +} + +void HeadlessBackend::activateContext() { + [EAGLContext setCurrentContext:reinterpret_cast<EAGLContext*>(glContext)]; +} + +void HeadlessBackend::deactivateContext() { + [EAGLContext setCurrentContext:nil]; +} + +} // namespace mbgl diff --git a/platform/darwin/src/headless_view_cgl.cpp b/platform/darwin/src/headless_view_cgl.cpp index dc58463b5d..08f0da8751 100644 --- a/platform/darwin/src/headless_view_cgl.cpp +++ b/platform/darwin/src/headless_view_cgl.cpp @@ -1,37 +1,14 @@ #include <mbgl/platform/default/headless_view.hpp> -#include <mbgl/platform/default/headless_display.hpp> -#include <CoreFoundation/CoreFoundation.h> +#include <mbgl/gl/gl.hpp> -namespace mbgl { - -gl::glProc HeadlessView::initializeExtension(const char* name) { - static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl")); - if (!framework) { - throw std::runtime_error("Failed to load OpenGL framework."); - } - - CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); - void* symbol = CFBundleGetFunctionPointerForName(framework, str); - CFRelease(str); - - return reinterpret_cast<gl::glProc>(symbol); -} - -void HeadlessView::createContext() { - CGLError error = CGLCreateContext(display->pixelFormat, nullptr, &glContext); - if (error != kCGLNoError) { - throw std::runtime_error(std::string("Error creating GL context object:") + CGLErrorString(error) + "\n"); - } +#include <cassert> - error = CGLEnable(glContext, kCGLCEMPEngine); - if (error != kCGLNoError) { - throw std::runtime_error(std::string("Error enabling OpenGL multithreading:") + CGLErrorString(error) + "\n"); - } -} +namespace mbgl { -void HeadlessView::destroyContext() { - CGLDestroyContext(glContext); +void HeadlessView::bindFramebuffer() { + assert(fbo); + MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo)); } void HeadlessView::resizeFramebuffer() { @@ -76,8 +53,6 @@ void HeadlessView::resizeFramebuffer() { } void HeadlessView::clearBuffers() { - assert(active); - MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); if (fbo) { @@ -96,18 +71,4 @@ void HeadlessView::clearBuffers() { } } -void HeadlessView::activateContext() { - CGLError error = CGLSetCurrentContext(glContext); - if (error != kCGLNoError) { - throw std::runtime_error(std::string("Switching OpenGL context failed:") + CGLErrorString(error) + "\n"); - } -} - -void HeadlessView::deactivateContext() { - CGLError error = CGLSetCurrentContext(nullptr); - if (error != kCGLNoError) { - throw std::runtime_error(std::string("Removing OpenGL context failed:") + CGLErrorString(error) + "\n"); - } -} - } // namespace mbgl diff --git a/platform/darwin/src/headless_view_eagl.mm b/platform/darwin/src/headless_view_eagl.cpp index a1f335fc6e..cc378912f9 100644 --- a/platform/darwin/src/headless_view_eagl.mm +++ b/platform/darwin/src/headless_view_eagl.cpp @@ -1,35 +1,14 @@ #include <mbgl/platform/default/headless_view.hpp> -#include <mbgl/platform/default/headless_display.hpp> -#include <OpenGLES/EAGL.h> +#include <mbgl/gl/gl.hpp> -namespace mbgl { - -gl::glProc HeadlessView::initializeExtension(const char* name) { - static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles")); - if (!framework) { - throw std::runtime_error("Failed to load OpenGL framework."); - } - - CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII); - void* symbol = CFBundleGetFunctionPointerForName(framework, str); - CFRelease(str); +#include <cassert> - return reinterpret_cast<gl::glProc>(symbol); -} - -void HeadlessView::createContext() { - glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - if (glContext == nil) { - throw std::runtime_error("Error creating GL context object"); - } - [reinterpret_cast<EAGLContext*>(glContext) retain]; - reinterpret_cast<EAGLContext*>(glContext).multiThreaded = YES; -} +namespace mbgl { -void HeadlessView::destroyContext() { - [reinterpret_cast<EAGLContext*>(glContext) release]; - glContext = nil; +void HeadlessView::bindFramebuffer() { + assert(fbo); + MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, fbo)); } void HeadlessView::resizeFramebuffer() { @@ -72,8 +51,6 @@ void HeadlessView::resizeFramebuffer() { } void HeadlessView::clearBuffers() { - assert(active); - MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); if (fbo) { @@ -92,12 +69,4 @@ void HeadlessView::clearBuffers() { } } -void HeadlessView::activateContext() { - [EAGLContext setCurrentContext:reinterpret_cast<EAGLContext*>(glContext)]; -} - -void HeadlessView::deactivateContext() { - [EAGLContext setCurrentContext:nil]; -} - } // namespace mbgl diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp index 9c54fc4ebf..044181e8c8 100644 --- a/platform/default/glfw_view.cpp +++ b/platform/default/glfw_view.cpp @@ -129,6 +129,10 @@ void GLFWView::initialize(mbgl::Map *map_) { map->addAnnotationIcon("default_marker", makeSpriteImage(22, 22, 1)); } +void GLFWView::bind() { + MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); +} + void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action, int mods) { GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window)); diff --git a/platform/default/headless_backend.cpp b/platform/default/headless_backend.cpp new file mode 100644 index 0000000000..279a7973c9 --- /dev/null +++ b/platform/default/headless_backend.cpp @@ -0,0 +1,56 @@ +#include <mbgl/platform/default/headless_backend.hpp> +#include <mbgl/platform/default/headless_display.hpp> + +#include <cassert> +#include <stdexcept> + +namespace mbgl { + +HeadlessBackend::HeadlessBackend() : display(std::make_shared<HeadlessDisplay>()) { + activate(); +} + +HeadlessBackend::HeadlessBackend(std::shared_ptr<HeadlessDisplay> display_) + : display(std::move(display_)) { + activate(); +} + +HeadlessBackend::~HeadlessBackend() { + deactivate(); + destroyContext(); +} + +void HeadlessBackend::activate() { + active = true; + + if (!glContext) { + if (!display) { + throw std::runtime_error("Display is not set"); + } + createContext(); + } + + activateContext(); + + if (!extensionsLoaded) { + gl::InitializeExtensions(initializeExtension); + extensionsLoaded = true; + } +} + +void HeadlessBackend::deactivate() { + deactivateContext(); + active = false; +} + +void HeadlessBackend::invalidate() { + assert(false); +} + +void HeadlessBackend::notifyMapChange(MapChange change) { + if (mapChangeCallback) { + mapChangeCallback(change); + } +} + +} // namespace mbgl diff --git a/platform/default/headless_backend_glx.cpp b/platform/default/headless_backend_glx.cpp new file mode 100644 index 0000000000..bbfd19345b --- /dev/null +++ b/platform/default/headless_backend_glx.cpp @@ -0,0 +1,67 @@ +#include <mbgl/platform/default/headless_backend.hpp> +#include <mbgl/platform/default/headless_display.hpp> + +#include <mbgl/platform/log.hpp> + +// #include <cassert> + +#include <GL/glx.h> + +namespace mbgl { + +gl::glProc HeadlessBackend::initializeExtension(const char* name) { + return glXGetProcAddress(reinterpret_cast<const GLubyte*>(name)); +} + +void HeadlessBackend::createContext() { + xDisplay = display->xDisplay; + fbConfigs = display->fbConfigs; + + if (!glContext) { + // Try to create a legacy context + glContext = glXCreateNewContext(xDisplay, fbConfigs[0], GLX_RGBA_TYPE, None, True); + if (glContext) { + if (!glXIsDirect(xDisplay, glContext)) { + Log::Error(Event::OpenGL, "failed to create direct OpenGL Legacy context"); + glXDestroyContext(xDisplay, glContext); + glContext = nullptr; + } + } + } + + if (glContext == nullptr) { + throw std::runtime_error("Error creating GL context object."); + } + + // Create a dummy pbuffer. We will render to framebuffers anyway, but we need a pbuffer to + // activate the context. + int pbufferAttributes[] = { + GLX_PBUFFER_WIDTH, 8, + GLX_PBUFFER_HEIGHT, 8, + None + }; + glxPbuffer = glXCreatePbuffer(xDisplay, fbConfigs[0], pbufferAttributes); +} + +void HeadlessBackend::destroyContext() { + if (glxPbuffer) { + glXDestroyPbuffer(xDisplay, glxPbuffer); + glxPbuffer = 0; + } + + glXDestroyContext(xDisplay, glContext); +} + +void HeadlessBackend::activateContext() { + if (!glXMakeContextCurrent(xDisplay, glxPbuffer, glxPbuffer, glContext)) { + throw std::runtime_error("Switching OpenGL context failed.\n"); + } +} + +void HeadlessBackend::deactivateContext() { + if (!glXMakeContextCurrent(xDisplay, 0, 0, nullptr)) { + throw std::runtime_error("Removing OpenGL context failed.\n"); + } +} + +} // namespace mbgl diff --git a/platform/default/headless_display.cpp b/platform/default/headless_display.cpp index 8b9f3fe04b..b98aef7903 100644 --- a/platform/default/headless_display.cpp +++ b/platform/default/headless_display.cpp @@ -1,12 +1,13 @@ #include <mbgl/platform/default/headless_display.hpp> -#include <cstring> -#include <stdexcept> - #if MBGL_USE_GLX #include <GL/glx.h> #endif +#include <cstring> +#include <stdexcept> +#include <string> + namespace mbgl { HeadlessDisplay::HeadlessDisplay() { diff --git a/platform/default/headless_view.cpp b/platform/default/headless_view.cpp index 95b196b746..f96b0a7f6d 100644 --- a/platform/default/headless_view.cpp +++ b/platform/default/headless_view.cpp @@ -1,34 +1,27 @@ #include <mbgl/platform/default/headless_view.hpp> -#include <mbgl/platform/default/headless_display.hpp> -#include <cassert> +#include <mbgl/gl/gl.hpp> + #include <cstring> namespace mbgl { HeadlessView::HeadlessView(float pixelRatio_, uint16_t width, uint16_t height) - : display(std::make_shared<HeadlessDisplay>()) - , pixelRatio(pixelRatio_) - , dimensions({{ width, height }}) - , needsResize(true) { -} - -HeadlessView::HeadlessView(std::shared_ptr<HeadlessDisplay> display_, - float pixelRatio_, - uint16_t width, - uint16_t height) - : display(std::move(display_)) - , pixelRatio(pixelRatio_) - , dimensions({{ width, height }}) - , needsResize(true) { + : pixelRatio(pixelRatio_), dimensions({ { width, height } }), needsResize(true) { } HeadlessView::~HeadlessView() { - activate(); clearBuffers(); - deactivate(); +} - destroyContext(); +void HeadlessView::bind() { + if (needsResize) { + clearBuffers(); + resizeFramebuffer(); + needsResize = false; + } else { + bindFramebuffer(); + } } void HeadlessView::resize(const uint16_t width, const uint16_t height) { @@ -41,8 +34,6 @@ void HeadlessView::resize(const uint16_t width, const uint16_t height) { } PremultipliedImage HeadlessView::readStillImage(std::array<uint16_t, 2> size) { - assert(active); - if (!size[0] || !size[1]) { size[0] = dimensions[0] * pixelRatio; size[1] = dimensions[1] * pixelRatio; @@ -76,43 +67,4 @@ std::array<uint16_t, 2> HeadlessView::getFramebufferSize() const { static_cast<uint16_t>(dimensions[1] * pixelRatio) }}; } -void HeadlessView::activate() { - active = true; - - if (!glContext) { - if (!display) { - throw std::runtime_error("Display is not set"); - } - createContext(); - } - - activateContext(); - - if (!extensionsLoaded) { - gl::InitializeExtensions(initializeExtension); - extensionsLoaded = true; - } - - if (needsResize) { - clearBuffers(); - resizeFramebuffer(); - needsResize = false; - } -} - -void HeadlessView::deactivate() { - deactivateContext(); - active = false; -} - -void HeadlessView::invalidate() { - assert(false); -} - -void HeadlessView::notifyMapChange(MapChange change) { - if (mapChangeCallback) { - mapChangeCallback(change); - } -} - } // namespace mbgl diff --git a/platform/default/headless_view_glx.cpp b/platform/default/headless_view_glx.cpp index 55d9313f99..08f0da8751 100644 --- a/platform/default/headless_view_glx.cpp +++ b/platform/default/headless_view_glx.cpp @@ -1,54 +1,14 @@ #include <mbgl/platform/default/headless_view.hpp> -#include <mbgl/platform/default/headless_display.hpp> -#include <mbgl/platform/log.hpp> -#include <cassert> +#include <mbgl/gl/gl.hpp> -#include <GL/glx.h> +#include <cassert> namespace mbgl { -gl::glProc HeadlessView::initializeExtension(const char* name) { - return glXGetProcAddress(reinterpret_cast<const GLubyte*>(name)); -} - -void HeadlessView::createContext() { - xDisplay = display->xDisplay; - fbConfigs = display->fbConfigs; - - if (!glContext) { - // Try to create a legacy context - glContext = glXCreateNewContext(xDisplay, fbConfigs[0], GLX_RGBA_TYPE, None, True); - if (glContext) { - if (!glXIsDirect(xDisplay, glContext)) { - Log::Error(Event::OpenGL, "failed to create direct OpenGL Legacy context"); - glXDestroyContext(xDisplay, glContext); - glContext = nullptr; - } - } - } - - if (glContext == nullptr) { - throw std::runtime_error("Error creating GL context object."); - } - - // Create a dummy pbuffer. We will render to framebuffers anyway, but we need a pbuffer to - // activate the context. - int pbufferAttributes[] = { - GLX_PBUFFER_WIDTH, 8, - GLX_PBUFFER_HEIGHT, 8, - None - }; - glxPbuffer = glXCreatePbuffer(xDisplay, fbConfigs[0], pbufferAttributes); -} - -void HeadlessView::destroyContext() { - if (glxPbuffer) { - glXDestroyPbuffer(xDisplay, glxPbuffer); - glxPbuffer = 0; - } - - glXDestroyContext(xDisplay, glContext); +void HeadlessView::bindFramebuffer() { + assert(fbo); + MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo)); } void HeadlessView::resizeFramebuffer() { @@ -93,8 +53,6 @@ void HeadlessView::resizeFramebuffer() { } void HeadlessView::clearBuffers() { - assert(active); - MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); if (fbo) { @@ -113,16 +71,4 @@ void HeadlessView::clearBuffers() { } } -void HeadlessView::activateContext() { - if (!glXMakeContextCurrent(xDisplay, glxPbuffer, glxPbuffer, glContext)) { - throw std::runtime_error("Switching OpenGL context failed.\n"); - } -} - -void HeadlessView::deactivateContext() { - if (!glXMakeContextCurrent(xDisplay, 0, 0, nullptr)) { - throw std::runtime_error("Removing OpenGL context failed.\n"); - } -} - } // namespace mbgl diff --git a/platform/ios/config.cmake b/platform/ios/config.cmake index e5480e37df..db75d7a4de 100644 --- a/platform/ios/config.cmake +++ b/platform/ios/config.cmake @@ -37,7 +37,9 @@ macro(mbgl_platform_core) PRIVATE platform/darwin/src/image.mm # Headless view - PRIVATE platform/darwin/src/headless_view_eagl.mm + PRIVATE platform/darwin/src/headless_backend_eagl.mm + PRIVATE platform/darwin/src/headless_view_eagl.cpp + PRIVATE platform/default/headless_backend.cpp PRIVATE platform/default/headless_display.cpp PRIVATE platform/default/headless_view.cpp @@ -53,7 +55,7 @@ macro(mbgl_platform_core) # TODO: Remove this by converting to ARC set_source_files_properties( - platform/darwin/src/headless_view_eagl.mm + platform/darwin/src/headless_backend_eagl.mm PROPERTIES COMPILE_FLAGS -fno-objc-arc ) diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 194f1a88d4..3d93dc8fc9 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -18,6 +18,7 @@ #include <mbgl/storage/network_status.hpp> #include <mbgl/style/transition_options.hpp> #include <mbgl/style/layers/custom_layer.hpp> +#include <mbgl/map/backend.hpp> #include <mbgl/math/wrap.hpp> #include <mbgl/util/geo.hpp> #include <mbgl/util/constants.hpp> @@ -389,8 +390,7 @@ public: self.clipsToBounds = YES; // setup mbgl view - const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; - _mbglView = new MBGLView(self, scaleFactor); + _mbglView = new MBGLView(self); // Delete the pre-offline ambient cache at ~/Library/Caches/cache.db. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); @@ -398,9 +398,10 @@ public: [[NSFileManager defaultManager] removeItemAtPath:fileCachePath error:NULL]; // setup mbgl map + const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; _mbglThreadPool = new mbgl::ThreadPool(4); - _mbglMap = new mbgl::Map(*_mbglView, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); + _mbglMap = new mbgl::Map(*_mbglView, *_mbglView, scaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); [self validateTileCacheSize]; // start paused if in IB @@ -4938,15 +4939,11 @@ public: return _annotationViewReuseQueueByIdentifier[identifier]; } -class MBGLView : public mbgl::View +class MBGLView : public mbgl::View, public mbgl::Backend { public: - MBGLView(MGLMapView* nativeView_, const float scaleFactor_) - : nativeView(nativeView_), scaleFactor(scaleFactor_) { - } - - float getPixelRatio() const override { - return scaleFactor; + MBGLView(MGLMapView* nativeView_) + : nativeView(nativeView_) { } std::array<uint16_t, 2> getSize() const override { @@ -4959,6 +4956,10 @@ public: static_cast<uint16_t>([[nativeView glView] drawableHeight]) }}; } + void bind() override { + [nativeView.glView bindDrawable]; + } + void notifyMapChange(mbgl::MapChange change) override { [nativeView notifyMapChange:change]; @@ -4981,7 +4982,6 @@ public: private: __weak MGLMapView *nativeView = nullptr; - const float scaleFactor; }; @end diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake index 86e8697f8c..d033f9df21 100644 --- a/platform/linux/config.cmake +++ b/platform/linux/config.cmake @@ -41,9 +41,11 @@ macro(mbgl_platform_core) PRIVATE platform/default/webp_reader.cpp # Headless view + PRIVATE platform/default/headless_backend_glx.cpp + PRIVATE platform/default/headless_view_glx.cpp + PRIVATE platform/default/headless_backend.cpp PRIVATE platform/default/headless_display.cpp PRIVATE platform/default/headless_view.cpp - PRIVATE platform/default/headless_view_glx.cpp # Thread pool PRIVATE platform/default/thread_pool.cpp diff --git a/platform/macos/config.cmake b/platform/macos/config.cmake index 645feb90c3..198dfc7083 100644 --- a/platform/macos/config.cmake +++ b/platform/macos/config.cmake @@ -35,7 +35,9 @@ macro(mbgl_platform_core) PRIVATE platform/darwin/src/image.mm # Headless view + PRIVATE platform/darwin/src/headless_backend_cgl.cpp PRIVATE platform/darwin/src/headless_view_cgl.cpp + PRIVATE platform/default/headless_backend.cpp PRIVATE platform/default/headless_display.cpp PRIVATE platform/default/headless_view.cpp diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 46766b573b..475ca2d259 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -25,6 +25,7 @@ #import <mbgl/platform/default/thread_pool.hpp> #import <mbgl/gl/extension.hpp> #import <mbgl/gl/gl.hpp> +#import <mbgl/map/backend.hpp> #import <mbgl/sprite/sprite_image.hpp> #import <mbgl/storage/default_file_source.hpp> #import <mbgl/storage/network_status.hpp> @@ -248,7 +249,7 @@ public: _isTargetingInterfaceBuilder = NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent; // Set up cross-platform controllers and resources. - _mbglView = new MGLMapViewImpl(self, [NSScreen mainScreen].backingScaleFactor); + _mbglView = new MGLMapViewImpl(self); // Delete the pre-offline ambient cache at // ~/Library/Caches/com.mapbox.sdk.ios/cache.db. @@ -264,7 +265,7 @@ public: mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; _mbglThreadPool = new mbgl::ThreadPool(4); - _mbglMap = new mbgl::Map(*_mbglView, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); + _mbglMap = new mbgl::Map(*_mbglView, *_mbglView, [NSScreen mainScreen].backingScaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); [self validateTileCacheSize]; // Install the OpenGL layer. Interface Builder’s synchronous drawing means @@ -745,6 +746,8 @@ public: return reinterpret_cast<mbgl::gl::glProc>(symbol); }); + _mbglView->updateFramebufferBinding(); + _mbglMap->render(); if (_isPrinting) { @@ -2531,14 +2534,10 @@ public: } /// Adapter responsible for bridging calls from mbgl to MGLMapView and Cocoa. -class MGLMapViewImpl : public mbgl::View { +class MGLMapViewImpl : public mbgl::View, public mbgl::Backend { public: - MGLMapViewImpl(MGLMapView *nativeView_, const float scaleFactor_) - : nativeView(nativeView_), scaleFactor(scaleFactor_) {} - - float getPixelRatio() const override { - return scaleFactor; - } + MGLMapViewImpl(MGLMapView *nativeView_) + : nativeView(nativeView_) {} std::array<uint16_t, 2> getSize() const override { return {{ static_cast<uint16_t>(nativeView.bounds.size.width), @@ -2568,6 +2567,14 @@ public: [NSOpenGLContext clearCurrentContext]; } + void updateFramebufferBinding() { + MBGL_CHECK_ERROR(glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo)); + } + + void bind() override { + MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, fbo)); + } + mbgl::PremultipliedImage readStillImage(std::array<uint16_t, 2> size = {{ 0, 0 }}) override { if (!size[0] || !size[1]) { size = getFramebufferSize(); @@ -2592,8 +2599,8 @@ private: /// Cocoa map view that this adapter bridges to. __weak MGLMapView *nativeView = nullptr; - /// Backing scale factor of the view. - const float scaleFactor; + /// The current framebuffer of the NSOpenGLLayer we are painting to. + GLint fbo = 0; }; @end diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp index a13adbc417..ebdf8d62c3 100644 --- a/platform/node/src/node_map.cpp +++ b/platform/node/src/node_map.cpp @@ -773,15 +773,16 @@ void NodeMap::QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>& } NodeMap::NodeMap(v8::Local<v8::Object> options) : - view(sharedDisplay(), [&] { + backend(sharedDisplay()), + view([&] { Nan::HandleScope scope; return Nan::Has(options, Nan::New("ratio").ToLocalChecked()).FromJust() ? Nan::Get(options, Nan::New("ratio").ToLocalChecked()).ToLocalChecked()->NumberValue() : 1.0; }()), threadpool(), - map(std::make_unique<mbgl::Map>(view, *this, threadpool, mbgl::MapMode::Still)), + map(std::make_unique<mbgl::Map>(backend, view, view.getPixelRatio(), *this, threadpool, mbgl::MapMode::Still)), async(new uv_async_t) { - view.setMapChangeCallback([&](mbgl::MapChange change) { + backend.setMapChangeCallback([&](mbgl::MapChange change) { if (change == mbgl::MapChangeDidFailLoadingMap) { throw std::runtime_error("Requires a map style to be a valid style JSON"); } diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp index 588ece2c74..48ff2caab1 100644 --- a/platform/node/src/node_map.hpp +++ b/platform/node/src/node_map.hpp @@ -4,6 +4,7 @@ #include <mbgl/map/map.hpp> #include <mbgl/storage/file_source.hpp> +#include <mbgl/platform/default/headless_backend.hpp> #include <mbgl/platform/default/headless_view.hpp> #pragma GCC diagnostic push @@ -53,6 +54,7 @@ public: std::unique_ptr<mbgl::AsyncRequest> request(const mbgl::Resource&, mbgl::FileSource::Callback); + mbgl::HeadlessBackend backend; mbgl::HeadlessView view; NodeThreadPool threadpool; std::unique_ptr<mbgl::Map> map; diff --git a/platform/qt/config.cmake b/platform/qt/config.cmake index d8ede6b450..6df311f885 100644 --- a/platform/qt/config.cmake +++ b/platform/qt/config.cmake @@ -43,8 +43,10 @@ endmacro() macro(mbgl_platform_test) target_sources(mbgl-test PRIVATE test/src/main.cpp + PRIVATE platform/qt/test/headless_backend_qt.cpp PRIVATE platform/qt/test/headless_view_qt.cpp PRIVATE platform/qt/test/qmapboxgl.cpp + PRIVATE platform/default/headless_backend.cpp PRIVATE platform/default/headless_display.cpp PRIVATE platform/default/headless_view.cpp ) diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index d0a05301f8..73a1771908 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -813,7 +813,7 @@ QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settin settings.cacheDatabaseMaximumSize())) , threadPool(4) , mapObj(std::make_unique<mbgl::Map>( - *this, *fileSourceObj, threadPool, + *this, *this, getPixelRatio(), *fileSourceObj, threadPool, static_cast<mbgl::MapMode>(settings.mapMode()), static_cast<mbgl::GLContextMode>(settings.contextMode()), static_cast<mbgl::ConstrainMode>(settings.constrainMode()), @@ -845,6 +845,11 @@ float QMapboxGLPrivate::getPixelRatio() const return pixelRatio; } +void QMapboxGLPrivate::bind() +{ + MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); +} + std::array<uint16_t, 2> QMapboxGLPrivate::getSize() const { return {{ static_cast<uint16_t>(size.width()), static_cast<uint16_t>(size.height()) }}; diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp index c35ac4e7ba..5a228896dc 100644 --- a/platform/qt/src/qmapboxgl_p.hpp +++ b/platform/qt/src/qmapboxgl_p.hpp @@ -3,6 +3,7 @@ #include "qmapboxgl.hpp" #include <mbgl/map/map.hpp> +#include <mbgl/map/backend.hpp> #include <mbgl/map/view.hpp> #include <mbgl/platform/default/thread_pool.hpp> #include <mbgl/storage/default_file_source.hpp> @@ -11,7 +12,7 @@ #include <QObject> #include <QSize> -class QMapboxGLPrivate : public QObject, public mbgl::View +class QMapboxGLPrivate : public QObject, public mbgl::View, public mbgl::Backend { Q_OBJECT @@ -20,7 +21,8 @@ public: virtual ~QMapboxGLPrivate(); // mbgl::View implementation. - float getPixelRatio() const final; + float getPixelRatio() const; + void bind() final; std::array<uint16_t, 2> getSize() const final; std::array<uint16_t, 2> getFramebufferSize() const final; diff --git a/platform/qt/test/headless_backend_qt.cpp b/platform/qt/test/headless_backend_qt.cpp new file mode 100644 index 0000000000..3f287ae578 --- /dev/null +++ b/platform/qt/test/headless_backend_qt.cpp @@ -0,0 +1,46 @@ +#include <mbgl/platform/default/headless_backend.hpp> +#include <mbgl/platform/default/headless_display.hpp> + +#include <QApplication> +#include <QGLContext> +#include <QGLWidget> + +#if QT_VERSION >= 0x050000 +#include <QOpenGLContext> +#endif + +namespace mbgl { + +gl::glProc HeadlessBackend::initializeExtension(const char* name) { +#if QT_VERSION >= 0x050000 + QOpenGLContext* thisContext = QOpenGLContext::currentContext(); + return thisContext->getProcAddress(name); +#else + const QGLContext* thisContext = QGLContext::currentContext(); + return reinterpret_cast<mbgl::gl::glProc>(thisContext->getProcAddress(name)); +#endif +} + +void HeadlessBackend::createContext() { + static const char* argv[] = { "mbgl" }; + static int argc = 1; + static auto* app = new QApplication(argc, const_cast<char**>(argv)); + + Q_UNUSED(app); + + glContext = new QGLWidget; +} + +void HeadlessBackend::destroyContext() { + delete glContext; +} + +void HeadlessBackend::activateContext() { + glContext->makeCurrent(); +} + +void HeadlessBackend::deactivateContext() { + glContext->doneCurrent(); +} + +} // namespace mbgl diff --git a/platform/qt/test/headless_view_qt.cpp b/platform/qt/test/headless_view_qt.cpp index 03ecb741ab..133b4a2371 100644 --- a/platform/qt/test/headless_view_qt.cpp +++ b/platform/qt/test/headless_view_qt.cpp @@ -1,6 +1,7 @@ -#include <mbgl/platform/default/headless_display.hpp> #include <mbgl/platform/default/headless_view.hpp> +#include <mbgl/gl/gl.hpp> + #include <QApplication> #include <QGLContext> #include <QGLWidget> @@ -9,30 +10,13 @@ #include <QOpenGLContext> #endif -namespace mbgl { - -gl::glProc HeadlessView::initializeExtension(const char* name) { -#if QT_VERSION >= 0x050000 - QOpenGLContext* thisContext = QOpenGLContext::currentContext(); - return thisContext->getProcAddress(name); -#else - const QGLContext* thisContext = QGLContext::currentContext(); - return reinterpret_cast<mbgl::gl::glProc>(thisContext->getProcAddress(name)); -#endif -} - -void HeadlessView::createContext() { - static const char* argv[] = { "mbgl" }; - static int argc = 1; - static auto* app = new QApplication(argc, const_cast<char**>(argv)); - - Q_UNUSED(app); +#include <cassert> - glContext = new QGLWidget; -} +namespace mbgl { -void HeadlessView::destroyContext() { - delete glContext; +void HeadlessView::bindFramebuffer() { + assert(fbo); + MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo)); } void HeadlessView::resizeFramebuffer() { @@ -95,12 +79,4 @@ void HeadlessView::clearBuffers() { } } -void HeadlessView::activateContext() { - glContext->makeCurrent(); -} - -void HeadlessView::deactivateContext() { - glContext->doneCurrent(); -} - } // namespace mbgl diff --git a/src/mbgl/map/backend.cpp b/src/mbgl/map/backend.cpp new file mode 100644 index 0000000000..fea4b70ce9 --- /dev/null +++ b/src/mbgl/map/backend.cpp @@ -0,0 +1,12 @@ +#include <mbgl/map/backend.hpp> + +#include <cassert> + +namespace mbgl { + +void Backend::notifyMapChange(MapChange) { + // no-op +} + + +} // namespace mbgl diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index d948225d8a..ab85187c98 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -1,6 +1,7 @@ #include <mbgl/map/map.hpp> #include <mbgl/map/camera.hpp> #include <mbgl/map/view.hpp> +#include <mbgl/map/backend.hpp> #include <mbgl/map/transform.hpp> #include <mbgl/map/transform_state.hpp> #include <mbgl/annotation/annotation_manager.hpp> @@ -36,7 +37,15 @@ enum class RenderState : uint8_t { class Map::Impl : public style::Observer { public: - Impl(View&, FileSource&, Scheduler&, MapMode, GLContextMode, ConstrainMode, ViewportMode); + Impl(Backend&, + View&, + float pixelRatio, + FileSource&, + Scheduler&, + MapMode, + GLContextMode, + ConstrainMode, + ViewportMode); void onSourceAttributionChanged(style::Source&, const std::string&) override; void onUpdate(Update) override; @@ -49,6 +58,7 @@ public: void loadStyleJSON(const std::string&); + Backend& backend; View& view; FileSource& fileSource; Scheduler& scheduler; @@ -81,34 +91,53 @@ public: bool loading = false; }; -Map::Map(View& view, FileSource& fileSource, Scheduler& scheduler, MapMode mapMode, GLContextMode contextMode, ConstrainMode constrainMode, ViewportMode viewportMode) - : impl(std::make_unique<Impl>(view, fileSource, scheduler, mapMode, contextMode, constrainMode, viewportMode)) { +Map::Map(Backend& backend, + View& view, + const float pixelRatio, + FileSource& fileSource, + Scheduler& scheduler, + MapMode mapMode, + GLContextMode contextMode, + ConstrainMode constrainMode, + ViewportMode viewportMode) + : impl(std::make_unique<Impl>(backend, + view, + pixelRatio, + fileSource, + scheduler, + mapMode, + contextMode, + constrainMode, + viewportMode)) { view.initialize(this); update(Update::Dimensions); } -Map::Impl::Impl(View& view_, +Map::Impl::Impl(Backend& backend_, + View& view_, + float pixelRatio_, FileSource& fileSource_, Scheduler& scheduler_, MapMode mode_, GLContextMode contextMode_, ConstrainMode constrainMode_, ViewportMode viewportMode_) - : view(view_), + : backend(backend_), + view(view_), fileSource(fileSource_), scheduler(scheduler_), - transform([this](MapChange change) { view.notifyMapChange(change); }, + transform([this](MapChange change) { backend.notifyMapChange(change); }, constrainMode_, viewportMode_), mode(mode_), contextMode(contextMode_), - pixelRatio(view.getPixelRatio()), + pixelRatio(pixelRatio_), asyncUpdate([this] { update(); }), annotationManager(std::make_unique<AnnotationManager>(pixelRatio)) { } Map::~Map() { - impl->view.activate(); + impl->backend.activate(); impl->styleRequest = nullptr; @@ -118,7 +147,7 @@ Map::~Map() { impl->annotationManager.reset(); impl->painter.reset(); - impl->view.deactivate(); + impl->backend.deactivate(); } void Map::renderStill(StillImageCallback callback) { @@ -162,16 +191,16 @@ void Map::render() { } if (impl->renderState == RenderState::Never) { - impl->view.notifyMapChange(MapChangeWillStartRenderingMap); + impl->backend.notifyMapChange(MapChangeWillStartRenderingMap); } - impl->view.notifyMapChange(MapChangeWillStartRenderingFrame); + impl->backend.notifyMapChange(MapChangeWillStartRenderingFrame); const Update flags = impl->transform.updateTransitions(Clock::now()); impl->render(); - impl->view.notifyMapChange(isFullyLoaded() ? + impl->backend.notifyMapChange(isFullyLoaded() ? MapChangeDidFinishRenderingFrameFullyRendered : MapChangeDidFinishRenderingFrame); @@ -179,10 +208,10 @@ void Map::render() { impl->renderState = RenderState::Partial; } else if (impl->renderState != RenderState::Fully) { impl->renderState = RenderState::Fully; - impl->view.notifyMapChange(MapChangeDidFinishRenderingMapFullyRendered); + impl->backend.notifyMapChange(MapChangeDidFinishRenderingMapFullyRendered); if (impl->loading) { impl->loading = false; - impl->view.notifyMapChange(MapChangeDidFinishLoadingMap); + impl->backend.notifyMapChange(MapChangeDidFinishLoadingMap); } } @@ -240,11 +269,11 @@ void Map::Impl::update() { style->updateTiles(parameters); if (mode == MapMode::Continuous) { - view.invalidate(); + backend.invalidate(); } else if (callback && style->isLoaded()) { - view.activate(); + backend.activate(); render(); - view.deactivate(); + backend.deactivate(); } updateFlags = Update::Nothing; @@ -255,8 +284,7 @@ void Map::Impl::render() { painter = std::make_unique<Painter>(transform.getState()); } - FrameData frameData { view.getFramebufferSize(), - timePoint, + FrameData frameData { timePoint, pixelRatio, mode, contextMode, @@ -264,6 +292,7 @@ void Map::Impl::render() { painter->render(*style, frameData, + view, annotationManager->getSpriteAtlas()); if (mode == MapMode::Still) { @@ -291,7 +320,7 @@ void Map::setStyleURL(const std::string& url) { impl->loading = true; - impl->view.notifyMapChange(MapChangeWillStartLoadingMap); + impl->backend.notifyMapChange(MapChangeWillStartLoadingMap); impl->styleRequest = nullptr; impl->styleURL = url; @@ -335,7 +364,7 @@ void Map::setStyleJSON(const std::string& json) { impl->loading = true; - impl->view.notifyMapChange(MapChangeWillStartLoadingMap); + impl->backend.notifyMapChange(MapChangeWillStartLoadingMap); impl->styleURL.clear(); impl->styleJSON.clear(); @@ -801,12 +830,12 @@ void Map::addLayer(std::unique_ptr<Layer> layer, const optional<std::string>& be } impl->styleMutated = true; - impl->view.activate(); + impl->backend.activate(); impl->style->addLayer(std::move(layer), before); update(Update::Classes); - impl->view.deactivate(); + impl->backend.deactivate(); } void Map::removeLayer(const std::string& id) { @@ -815,12 +844,12 @@ void Map::removeLayer(const std::string& id) { } impl->styleMutated = true; - impl->view.activate(); + impl->backend.activate(); impl->style->removeLayer(id); update(Update::Classes); - impl->view.deactivate(); + impl->backend.deactivate(); } void Map::addImage(const std::string& name, std::unique_ptr<const SpriteImage> image) { @@ -971,7 +1000,7 @@ void Map::setSourceTileCacheSize(size_t size) { impl->sourceCacheSize = size; if (!impl->style) return; impl->style->setSourceTileCacheSize(size); - impl->view.invalidate(); + impl->backend.invalidate(); } } @@ -981,12 +1010,12 @@ void Map::onLowMemory() { } if (impl->style) { impl->style->onLowMemory(); - impl->view.invalidate(); + impl->backend.invalidate(); } } void Map::Impl::onSourceAttributionChanged(style::Source&, const std::string&) { - view.notifyMapChange(MapChangeSourceDidChange); + backend.notifyMapChange(MapChangeSourceDidChange); } void Map::Impl::onUpdate(Update flags) { @@ -999,11 +1028,11 @@ void Map::Impl::onUpdate(Update flags) { } void Map::Impl::onStyleLoaded() { - view.notifyMapChange(MapChangeDidFinishLoadingStyle); + backend.notifyMapChange(MapChangeDidFinishLoadingStyle); } void Map::Impl::onStyleError() { - view.notifyMapChange(MapChangeDidFailLoadingMap); + backend.notifyMapChange(MapChangeDidFailLoadingMap); } void Map::Impl::onResourceError(std::exception_ptr error) { diff --git a/src/mbgl/map/view.cpp b/src/mbgl/map/view.cpp index 8541753c7a..23ce70a3cf 100644 --- a/src/mbgl/map/view.cpp +++ b/src/mbgl/map/view.cpp @@ -5,18 +5,13 @@ namespace mbgl { -void View::initialize(Map *map_) { - assert(map_); - map = map_; -} - PremultipliedImage View::readStillImage(std::array<uint16_t, 2>) { return {}; } -void View::notifyMapChange(MapChange) { - // no-op +void View::initialize(Map *map_) { + assert(map_); + map = map_; } - } // namespace mbgl diff --git a/src/mbgl/renderer/paint_parameters.hpp b/src/mbgl/renderer/paint_parameters.hpp index 13bf21080d..bd67dc9cfd 100644 --- a/src/mbgl/renderer/paint_parameters.hpp +++ b/src/mbgl/renderer/paint_parameters.hpp @@ -3,10 +3,12 @@ namespace mbgl { class Shaders; +class View; class PaintParameters { public: Shaders& shaders; + View& view; }; } // namespace mbgl diff --git a/src/mbgl/renderer/painter.cpp b/src/mbgl/renderer/painter.cpp index ad0e75cd92..ee7ef6d212 100644 --- a/src/mbgl/renderer/painter.cpp +++ b/src/mbgl/renderer/painter.cpp @@ -5,6 +5,8 @@ #include <mbgl/style/source.hpp> #include <mbgl/style/source_impl.hpp> +#include <mbgl/map/view.hpp> + #include <mbgl/platform/log.hpp> #include <mbgl/gl/gl.hpp> #include <mbgl/gl/debugging.hpp> @@ -90,19 +92,18 @@ void Painter::cleanup() { context.performCleanup(); } -void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& annotationSpriteAtlas) { - if (frame.framebufferSize != frame_.framebufferSize) { - context.viewport.setDefaultValue( - { 0, 0, frame_.framebufferSize[0], frame_.framebufferSize[1] }); - } +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_; PaintParameters parameters { #ifndef NDEBUG - paintMode() == PaintMode::Overdraw ? *overdrawShaders : *shaders + paintMode() == PaintMode::Overdraw ? *overdrawShaders : *shaders, #else - *shaders + *shaders, #endif + view }; glyphAtlas = style.glyphAtlas.get(); @@ -148,7 +149,8 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a // tiles whatsoever. { MBGL_DEBUG_GROUP("clear"); - context.bindFramebuffer.reset(); + context.bindFramebuffer.setDirty(); + view.bind(); context.viewport.reset(); context.stencilFunc.reset(); context.stencilTest = true; @@ -188,7 +190,7 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a #if not MBGL_USE_GLES2 and not defined(NDEBUG) if (frame.debugOptions & MapDebugOptions::StencilClip) { - renderClipMasks(); + renderClipMasks(parameters); return; } #endif @@ -231,7 +233,7 @@ void Painter::render(const Style& style, const FrameData& frame_, SpriteAtlas& a #if not MBGL_USE_GLES2 and not defined(NDEBUG) if (frame.debugOptions & MapDebugOptions::DepthBuffer) { - renderDepthBuffer(); + renderDepthBuffer(parameters); } #endif @@ -302,7 +304,8 @@ void Painter::renderPass(PaintParameters& parameters, setDepthSublayer(0); layer.as<CustomLayer>()->impl->render(state); context.setDirtyState(); - context.bindFramebuffer.reset(); + context.bindFramebuffer.setDirty(); + parameters.view.bind(); context.viewport.reset(); } else { MBGL_DEBUG_GROUP(layer.baseImpl->id + " - " + util::toString(item.tile->id)); diff --git a/src/mbgl/renderer/painter.hpp b/src/mbgl/renderer/painter.hpp index 28aa5aab44..d2c89c04a9 100644 --- a/src/mbgl/renderer/painter.hpp +++ b/src/mbgl/renderer/painter.hpp @@ -28,6 +28,7 @@ namespace mbgl { class RenderTile; class SpriteAtlas; +class View; class GlyphAtlas; class LineAtlas; struct FrameData; @@ -58,7 +59,6 @@ class BackgroundLayer; } // namespace style struct FrameData { - std::array<uint16_t, 2> framebufferSize = {{ 0, 0 }}; TimePoint timePoint; float pixelRatio; MapMode mapMode; @@ -73,6 +73,7 @@ public: void render(const style::Style&, const FrameData&, + View&, SpriteAtlas& annotationSpriteAtlas); void cleanup(); @@ -85,9 +86,9 @@ public: #ifndef NDEBUG // Renders tile clip boundaries, using stencil buffer to calculate fill color. - void renderClipMasks(); + void renderClipMasks(PaintParameters&); // Renders the depth buffer. - void renderDepthBuffer(); + void renderDepthBuffer(PaintParameters&); #endif void renderDebugText(Tile&, const mat4&); diff --git a/src/mbgl/renderer/painter_debug.cpp b/src/mbgl/renderer/painter_debug.cpp index 23a2a8e571..ca961f84e7 100644 --- a/src/mbgl/renderer/painter_debug.cpp +++ b/src/mbgl/renderer/painter_debug.cpp @@ -1,6 +1,8 @@ #include <mbgl/renderer/painter.hpp> #include <mbgl/renderer/debug_bucket.hpp> #include <mbgl/renderer/render_tile.hpp> +#include <mbgl/renderer/paint_parameters.hpp> +#include <mbgl/map/view.hpp> #include <mbgl/tile/tile.hpp> #include <mbgl/shader/shaders.hpp> #include <mbgl/util/string.hpp> @@ -87,7 +89,7 @@ void Painter::renderDebugFrame(const mat4 &matrix) { } #ifndef NDEBUG -void Painter::renderClipMasks() { +void Painter::renderClipMasks(PaintParameters& parameters) { context.stencilTest = false; context.depthTest = false; context.program = 0; @@ -98,7 +100,7 @@ void Painter::renderClipMasks() { context.rasterPos = { -1, -1, 0, 0 }; // Read the stencil buffer - const auto& fbSize = frame.framebufferSize; + const auto& fbSize = parameters.view.getFramebufferSize(); auto pixels = std::make_unique<uint8_t[]>(fbSize[0] * fbSize[1]); MBGL_CHECK_ERROR(glReadPixels( 0, // GLint x @@ -120,12 +122,14 @@ void Painter::renderClipMasks() { MBGL_CHECK_ERROR(glWindowPos2i(0, 0)); MBGL_CHECK_ERROR(glDrawPixels(fbSize[0], fbSize[1], GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels.get())); +#else + (void)parameters; #endif // MBGL_USE_GLES2 } #endif // NDEBUG #ifndef NDEBUG -void Painter::renderDepthBuffer() { +void Painter::renderDepthBuffer(PaintParameters& parameters) { context.stencilTest = false; context.depthTest = false; context.program = 0; @@ -136,7 +140,7 @@ void Painter::renderDepthBuffer() { context.rasterPos = { -1, -1, 0, 0 }; // Read the stencil buffer - const auto& fbSize = frame.framebufferSize; + const auto& fbSize = parameters.view.getFramebufferSize(); auto pixels = std::make_unique<GLubyte[]>(fbSize[0] * fbSize[1]); const double base = 1.0 / (1.0 - depthRangeSize); @@ -155,6 +159,8 @@ void Painter::renderDepthBuffer() { MBGL_CHECK_ERROR(glWindowPos2i(0, 0)); MBGL_CHECK_ERROR(glDrawPixels(fbSize[0], fbSize[1], GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels.get())); +#else + (void)parameters; #endif // MBGL_USE_GLES2 } #endif // NDEBUG diff --git a/src/mbgl/renderer/painter_fill.cpp b/src/mbgl/renderer/painter_fill.cpp index 50ead900f6..1fc5f11079 100644 --- a/src/mbgl/renderer/painter_fill.cpp +++ b/src/mbgl/renderer/painter_fill.cpp @@ -1,6 +1,7 @@ #include <mbgl/renderer/painter.hpp> #include <mbgl/renderer/paint_parameters.hpp> #include <mbgl/gl/gl.hpp> +#include <mbgl/map/view.hpp> #include <mbgl/renderer/fill_bucket.hpp> #include <mbgl/renderer/render_tile.hpp> @@ -29,7 +30,7 @@ void Painter::renderFill(PaintParameters& parameters, const bool isOutlineColorDefined = !properties.fillOutlineColor.isUndefined(); Color strokeColor = isOutlineColorDefined? properties.fillOutlineColor : fillColor; - auto worldSize = util::convert<GLfloat>(frame.framebufferSize); + auto worldSize = util::convert<GLfloat>(parameters.view.getFramebufferSize()); bool pattern = !properties.fillPattern.value.from.empty(); bool outline = properties.fillAntialias && !pattern && isOutlineColorDefined; diff --git a/test/api/annotations.test.cpp b/test/api/annotations.test.cpp index c1716a5228..53c0182ee9 100644 --- a/test/api/annotations.test.cpp +++ b/test/api/annotations.test.cpp @@ -5,7 +5,7 @@ #include <mbgl/annotation/annotation.hpp> #include <mbgl/sprite/sprite_image.hpp> #include <mbgl/map/map.hpp> -#include <mbgl/platform/default/headless_display.hpp> +#include <mbgl/platform/default/headless_backend.hpp> #include <mbgl/platform/default/headless_view.hpp> #include <mbgl/util/io.hpp> #include <mbgl/util/run_loop.hpp> @@ -23,11 +23,11 @@ std::shared_ptr<SpriteImage> namedMarker(const std::string &name) { class AnnotationTest { public: util::RunLoop loop; - std::shared_ptr<HeadlessDisplay> display { std::make_shared<HeadlessDisplay>() }; - HeadlessView view { display, 1 }; + HeadlessBackend backend; + HeadlessView view; StubFileSource fileSource; ThreadPool threadPool { 4 }; - Map map { view, fileSource, threadPool, MapMode::Still }; + Map map { backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still }; void checkRendering(const char * name) { test::checkImage(std::string("test/fixtures/annotations/") + name, diff --git a/test/api/api_misuse.test.cpp b/test/api/api_misuse.test.cpp index 2016e278da..f11363fa3c 100644 --- a/test/api/api_misuse.test.cpp +++ b/test/api/api_misuse.test.cpp @@ -3,7 +3,8 @@ #include <mbgl/test/fixture_log_observer.hpp> #include <mbgl/map/map.hpp> -#include <mbgl/platform/default/headless_display.hpp> +#include <mbgl/platform/default/headless_backend.hpp> +#include <mbgl/platform/default/headless_view.hpp> #include <mbgl/storage/online_file_source.hpp> #include <mbgl/platform/default/thread_pool.hpp> #include <mbgl/util/exception.hpp> @@ -19,13 +20,14 @@ TEST(API, RenderWithoutCallback) { util::RunLoop loop; - auto display = std::make_shared<mbgl::HeadlessDisplay>(); - HeadlessView view(display, 1); + HeadlessBackend backend; + HeadlessView view; view.resize(128, 512); StubFileSource fileSource; ThreadPool threadPool(4); - std::unique_ptr<Map> map = std::make_unique<Map>(view, fileSource, threadPool, MapMode::Still); + std::unique_ptr<Map> map = std::make_unique<Map>(backend, view, view.getPixelRatio(), + fileSource, threadPool, MapMode::Still); map->renderStill(nullptr); // Force Map thread to join. @@ -44,13 +46,13 @@ TEST(API, RenderWithoutCallback) { TEST(API, RenderWithoutStyle) { util::RunLoop loop; - auto display = std::make_shared<mbgl::HeadlessDisplay>(); - HeadlessView view(display, 1); + HeadlessBackend backend; + HeadlessView view; view.resize(128, 512); StubFileSource fileSource; ThreadPool threadPool(4); - Map map(view, fileSource, threadPool, MapMode::Still); + Map map(backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still); std::exception_ptr error; map.renderStill([&](std::exception_ptr error_, PremultipliedImage&&) { diff --git a/test/api/custom_layer.test.cpp b/test/api/custom_layer.test.cpp index 1342dfa50c..84ae780174 100644 --- a/test/api/custom_layer.test.cpp +++ b/test/api/custom_layer.test.cpp @@ -2,7 +2,7 @@ #include <mbgl/gl/gl.hpp> #include <mbgl/map/map.hpp> -#include <mbgl/platform/default/headless_display.hpp> +#include <mbgl/platform/default/headless_backend.hpp> #include <mbgl/platform/default/headless_view.hpp> #include <mbgl/platform/default/thread_pool.hpp> #include <mbgl/storage/default_file_source.hpp> @@ -85,8 +85,8 @@ public: TEST(CustomLayer, Basic) { util::RunLoop loop; - auto display = std::make_shared<mbgl::HeadlessDisplay>(); - HeadlessView view(display, 1); + HeadlessBackend backend; + HeadlessView view; #ifdef MBGL_ASSET_ZIP // Regenerate with `cd test/fixtures/api/ && zip -r assets.zip assets/` @@ -97,7 +97,7 @@ TEST(CustomLayer, Basic) { ThreadPool threadPool(4); - Map map(view, fileSource, threadPool, MapMode::Still); + Map map(backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still); map.setStyleJSON(util::read_file("test/fixtures/api/water.json")); map.setLatLngZoom({ 37.8, -122.5 }, 10); map.addLayer(std::make_unique<CustomLayer>( diff --git a/test/api/query.test.cpp b/test/api/query.test.cpp index da38dd0cb2..d989d222c5 100644 --- a/test/api/query.test.cpp +++ b/test/api/query.test.cpp @@ -1,5 +1,5 @@ #include <mbgl/map/map.hpp> -#include <mbgl/platform/default/headless_display.hpp> +#include <mbgl/platform/default/headless_backend.hpp> #include <mbgl/platform/default/headless_view.hpp> #include <mbgl/platform/default/thread_pool.hpp> #include <mbgl/sprite/sprite_image.hpp> @@ -26,11 +26,11 @@ public: } util::RunLoop loop; - std::shared_ptr<HeadlessDisplay> display { std::make_shared<HeadlessDisplay>() }; - HeadlessView view { display, 1 }; + HeadlessBackend backend; + HeadlessView view; StubFileSource fileSource; ThreadPool threadPool { 4 }; - Map map { view, fileSource, threadPool, MapMode::Still }; + Map map { backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still }; }; } // end namespace diff --git a/test/api/render_missing.test.cpp b/test/api/render_missing.test.cpp index d57a5a98bd..8123070282 100644 --- a/test/api/render_missing.test.cpp +++ b/test/api/render_missing.test.cpp @@ -2,7 +2,7 @@ #include <mbgl/test/fixture_log_observer.hpp> #include <mbgl/map/map.hpp> -#include <mbgl/platform/default/headless_display.hpp> +#include <mbgl/platform/default/headless_backend.hpp> #include <mbgl/platform/default/headless_view.hpp> #include <mbgl/platform/default/thread_pool.hpp> #include <mbgl/storage/default_file_source.hpp> @@ -25,8 +25,8 @@ TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) { const auto style = util::read_file("test/fixtures/api/water_missing_tiles.json"); - auto display = std::make_shared<mbgl::HeadlessDisplay>(); - HeadlessView view(display, 1, 256, 512); + HeadlessBackend backend; + HeadlessView view(1, 256, 512); #ifdef MBGL_ASSET_ZIP // Regenerate with `cd test/fixtures/api/ && zip -r assets.zip assets/` DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets.zip"); @@ -38,7 +38,7 @@ TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) { Log::setObserver(std::make_unique<FixtureLogObserver>()); - Map map(view, fileSource, threadPool, MapMode::Still); + Map map(backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still); std::string message; diff --git a/test/api/repeated_render.test.cpp b/test/api/repeated_render.test.cpp index 4229f9d7ad..5bc57198bd 100644 --- a/test/api/repeated_render.test.cpp +++ b/test/api/repeated_render.test.cpp @@ -2,7 +2,7 @@ #include <mbgl/test/fixture_log_observer.hpp> #include <mbgl/map/map.hpp> -#include <mbgl/platform/default/headless_display.hpp> +#include <mbgl/platform/default/headless_backend.hpp> #include <mbgl/platform/default/headless_view.hpp> #include <mbgl/platform/default/thread_pool.hpp> #include <mbgl/storage/default_file_source.hpp> @@ -19,9 +19,8 @@ TEST(API, RepeatedRender) { const auto style = util::read_file("test/fixtures/api/water.json"); - auto display = std::make_shared<mbgl::HeadlessDisplay>(); - HeadlessView view(display, 1, 256, 512); - + HeadlessBackend backend; + HeadlessView view(1, 256, 512); #ifdef MBGL_ASSET_ZIP // Regenerate with `cd test/fixtures/api/ && zip -r assets.zip assets/` DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets.zip"); @@ -33,7 +32,7 @@ TEST(API, RepeatedRender) { Log::setObserver(std::make_unique<FixtureLogObserver>()); - Map map(view, fileSource, threadPool, MapMode::Still); + Map map(backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still); { map.setStyleJSON(style); diff --git a/test/gl/object.test.cpp b/test/gl/object.test.cpp index 1a90cec83b..1f9d48cff7 100644 --- a/test/gl/object.test.cpp +++ b/test/gl/object.test.cpp @@ -1,6 +1,6 @@ #include <mbgl/test/util.hpp> -#include <mbgl/platform/default/headless_display.hpp> +#include <mbgl/platform/default/headless_backend.hpp> #include <mbgl/platform/default/headless_view.hpp> #include <mbgl/gl/gl.hpp> @@ -67,8 +67,8 @@ TEST(GLObject, Value) { } TEST(GLObject, Store) { - mbgl::HeadlessView view(std::make_shared<mbgl::HeadlessDisplay>(), 1); - view.activate(); + mbgl::HeadlessBackend backend; + mbgl::HeadlessView view; mbgl::gl::Context context; EXPECT_TRUE(context.empty()); @@ -106,5 +106,5 @@ TEST(GLObject, Store) { context.reset(); EXPECT_TRUE(context.empty()); - view.deactivate(); + backend.deactivate(); } diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index c03a038dc0..a5d634e77a 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -4,7 +4,7 @@ #include <mbgl/test/fixture_log_observer.hpp> #include <mbgl/map/map.hpp> -#include <mbgl/platform/default/headless_display.hpp> +#include <mbgl/platform/default/headless_backend.hpp> #include <mbgl/platform/default/headless_view.hpp> #include <mbgl/platform/default/thread_pool.hpp> #include <mbgl/sprite/sprite_image.hpp> @@ -22,15 +22,16 @@ using namespace std::literals::string_literals; struct MapTest { util::RunLoop runLoop; - std::shared_ptr<HeadlessDisplay> display { std::make_shared<mbgl::HeadlessDisplay>() }; - HeadlessView view { display, 1 }; + HeadlessBackend backend; + HeadlessView view; StubFileSource fileSource; ThreadPool threadPool { 4 }; }; TEST(Map, LatLngBehavior) { MapTest test; - Map map(test.view, test.fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool, + MapMode::Still); map.setStyleJSON(util::read_file("test/fixtures/api/empty.json")); @@ -64,7 +65,8 @@ TEST(Map, Offline) { fileSource.put(Resource::glyphs(prefix + "{fontstack}/{range}.pbf", {{"Helvetica"}}, {0, 255}), expiredItem("glyph.pbf")); NetworkStatus::Set(NetworkStatus::Status::Offline); - Map map(test.view, fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), fileSource, test.threadPool, + MapMode::Still); map.setStyleURL(prefix + "style.json"); test::checkImage("test/fixtures/map/offline", @@ -81,14 +83,15 @@ TEST(Map, SetStyleInvalidJSON) { Log::setObserver(std::make_unique<FixtureLogObserver>()); bool fail = false; - test.view.setMapChangeCallback([&](MapChange change) { + test.backend.setMapChangeCallback([&](MapChange change) { if (change == mbgl::MapChangeDidFailLoadingMap) { fail = true; } }); { - Map map(test.view, test.fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, + test.threadPool, MapMode::Still); map.setStyleJSON("invalid"); } @@ -113,13 +116,14 @@ TEST(Map, SetStyleInvalidURL) { return response; }; - test.view.setMapChangeCallback([&](MapChange change) { + test.backend.setMapChangeCallback([&](MapChange change) { if (change == mbgl::MapChangeDidFailLoadingMap) { test.runLoop.stop(); } }); - Map map(test.view, test.fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool, + MapMode::Still); map.setStyleURL("mapbox://bar"); test.runLoop.run(); @@ -128,7 +132,8 @@ TEST(Map, SetStyleInvalidURL) { TEST(Map, DoubleStyleLoad) { MapTest test; - Map map(test.view, test.fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool, + MapMode::Still); map.setStyleJSON(""); map.setStyleJSON(""); } @@ -139,7 +144,8 @@ TEST(Map, StyleFresh) { MapTest test; FakeFileSource fileSource; - Map map(test.view, fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), fileSource, test.threadPool, + MapMode::Still); map.setStyleURL("mapbox://styles/test"); EXPECT_EQ(1u, fileSource.requests.size()); @@ -159,7 +165,8 @@ TEST(Map, StyleExpired) { MapTest test; FakeFileSource fileSource; - Map map(test.view, fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), fileSource, test.threadPool, + MapMode::Still); map.setStyleURL("mapbox://styles/test"); EXPECT_EQ(1u, fileSource.requests.size()); @@ -186,7 +193,8 @@ TEST(Map, StyleExpiredWithAnnotations) { MapTest test; FakeFileSource fileSource; - Map map(test.view, fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), fileSource, test.threadPool, + MapMode::Still); map.setStyleURL("mapbox://styles/test"); EXPECT_EQ(1u, fileSource.requests.size()); @@ -210,7 +218,8 @@ TEST(Map, StyleEarlyMutation) { MapTest test; FakeFileSource fileSource; - Map map(test.view, fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), fileSource, test.threadPool, + MapMode::Still); map.setStyleURL("mapbox://styles/test"); map.addLayer(std::make_unique<style::BackgroundLayer>("bg")); @@ -224,11 +233,12 @@ TEST(Map, StyleEarlyMutation) { TEST(Map, StyleLoadedSignal) { MapTest test; - Map map(test.view, test.fileSource, test.threadPool, MapMode::Still); - + Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool, + MapMode::Still); + // The map should emit a signal on style loaded bool emitted = false; - test.view.setMapChangeCallback([&](MapChange change) { + test.backend.setMapChangeCallback([&](MapChange change) { if (change == mbgl::MapChangeDidFinishLoadingStyle) { emitted = true; } @@ -245,7 +255,8 @@ TEST(Map, StyleLoadedSignal) { TEST(Map, AddLayer) { MapTest test; - Map map(test.view, test.fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool, + MapMode::Still); map.setStyleJSON(util::read_file("test/fixtures/api/empty.json")); auto layer = std::make_unique<BackgroundLayer>("background"); @@ -258,7 +269,8 @@ TEST(Map, AddLayer) { TEST(Map, RemoveLayer) { MapTest test; - Map map(test.view, test.fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool, + MapMode::Still); map.setStyleJSON(util::read_file("test/fixtures/api/empty.json")); auto layer = std::make_unique<BackgroundLayer>("background"); @@ -283,7 +295,8 @@ TEST(Map, DisabledSources) { return {}; }; - Map map(test.view, test.fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool, + MapMode::Still); map.setZoom(1); // This stylesheet has two raster layers, one that starts at zoom 1, the other at zoom 0. @@ -333,7 +346,8 @@ TEST(Map, DisabledSources) { TEST(Map, Classes) { MapTest test; - Map map(test.view, test.fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool, + MapMode::Still); map.setStyleJSON(util::read_file("test/fixtures/api/empty.json")); EXPECT_FALSE(map.getTransitionOptions().duration); @@ -367,7 +381,8 @@ TEST(Map, Classes) { TEST(Map, AddImage) { MapTest test; - Map map(test.view, test.fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool, + MapMode::Still); auto decoded1 = decodeImage(util::read_file("test/fixtures/sprites/default_marker.png")); auto decoded2 = decodeImage(util::read_file("test/fixtures/sprites/default_marker.png")); auto image1 = std::make_unique<SpriteImage>(std::move(decoded1), 1.0); @@ -384,7 +399,8 @@ TEST(Map, AddImage) { TEST(Map, RemoveImage) { MapTest test; - Map map(test.view, test.fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool, + MapMode::Still); auto decoded = decodeImage(util::read_file("test/fixtures/sprites/default_marker.png")); auto image = std::make_unique<SpriteImage>(std::move(decoded), 1.0); diff --git a/test/util/memory.test.cpp b/test/util/memory.test.cpp index e2ace99c41..2ab3a03799 100644 --- a/test/util/memory.test.cpp +++ b/test/util/memory.test.cpp @@ -2,7 +2,7 @@ #include <mbgl/test/util.hpp> #include <mbgl/map/map.hpp> -#include <mbgl/platform/default/headless_display.hpp> +#include <mbgl/platform/default/headless_backend.hpp> #include <mbgl/platform/default/headless_view.hpp> #include <mbgl/platform/default/thread_pool.hpp> #include <mbgl/util/io.hpp> @@ -56,8 +56,8 @@ public: } util::RunLoop runLoop; - std::shared_ptr<HeadlessDisplay> display { std::make_shared<mbgl::HeadlessDisplay>() }; - HeadlessView view { display, 2 }; + HeadlessBackend backend; + HeadlessView view{ 2 }; StubFileSource fileSource; ThreadPool threadPool { 4 }; @@ -93,7 +93,8 @@ private: TEST(Memory, Vector) { MemoryTest test; - Map map(test.view, test.fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool, + MapMode::Still); map.setZoom(16); // more map features map.setStyleURL("mapbox://streets"); @@ -103,7 +104,8 @@ TEST(Memory, Vector) { TEST(Memory, Raster) { MemoryTest test; - Map map(test.view, test.fileSource, test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool, + MapMode::Still); map.setStyleURL("mapbox://satellite"); test::render(map); @@ -130,7 +132,8 @@ TEST(Memory, Footprint) { // Warm up buffers and cache. for (unsigned i = 0; i < 10; ++i) { - Map map(test.view, test.fileSource,test.threadPool, MapMode::Still); + Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, + test.threadPool, MapMode::Still); renderMap(&map, "mapbox://streets"); renderMap(&map, "mapbox://satellite"); }; @@ -144,7 +147,8 @@ TEST(Memory, Footprint) { long vectorInitialRSS = getRSS(); for (unsigned i = 0; i < runs; ++i) { - auto vector = std::make_unique<Map>(test.view, test.fileSource, test.threadPool, MapMode::Still); + auto vector = std::make_unique<Map>(test.backend, test.view, test.view.getPixelRatio(), + test.fileSource, test.threadPool, MapMode::Still); renderMap(vector.get(), "mapbox://streets"); maps.push_back(std::move(vector)); }; @@ -153,7 +157,8 @@ TEST(Memory, Footprint) { long rasterInitialRSS = getRSS(); for (unsigned i = 0; i < runs; ++i) { - auto raster = std::make_unique<Map>(test.view, test.fileSource, test.threadPool, MapMode::Still); + auto raster = std::make_unique<Map>(test.backend, test.view, test.view.getPixelRatio(), + test.fileSource, test.threadPool, MapMode::Still); renderMap(raster.get(), "mapbox://satellite"); maps.push_back(std::move(raster)); }; diff --git a/test/util/offscreen_texture.test.cpp b/test/util/offscreen_texture.test.cpp index 301fc2c250..e281a3d65b 100644 --- a/test/util/offscreen_texture.test.cpp +++ b/test/util/offscreen_texture.test.cpp @@ -1,15 +1,18 @@ #include <mbgl/test/util.hpp> #include <mbgl/gl/context.hpp> +#include <mbgl/platform/default/headless_backend.hpp> #include <mbgl/platform/default/headless_view.hpp> +#include <mbgl/gl/gl.hpp> #include <mbgl/util/offscreen_texture.hpp> using namespace mbgl; TEST(OffscreenTexture, EmptyRed) { + HeadlessBackend backend; HeadlessView view(1.0f, 512, 256); - view.activate(); + view.bind(); MBGL_CHECK_ERROR(glClearColor(1.0f, 0.0f, 0.0f, 1.0f)); MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT)); @@ -64,11 +67,11 @@ struct Buffer { TEST(OffscreenTexture, RenderToTexture) { + HeadlessBackend backend; HeadlessView view(1.0f, 512, 256); - view.activate(); + view.bind(); gl::Context context; context.viewport.setDefaultValue(gl::value::Viewport::Get()); - context.bindFramebuffer.setDefaultValue(gl::value::BindFramebuffer::Get()); MBGL_CHECK_ERROR(glEnable(GL_BLEND)); MBGL_CHECK_ERROR(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); @@ -130,6 +133,8 @@ void main() { // Now reset the FBO back to normal and retrieve the original (restored) framebuffer. context.resetState(); + context.bindFramebuffer.setDirty(); + view.bind(); image = view.readStillImage(); test::checkImage("test/fixtures/offscreen_texture/render-to-fbo", image, 0, 0); |