diff --git a/include/mln/gfx/renderable.hpp b/include/mln/gfx/renderable.hpp index 06ec94793..c64111b51 100644 --- a/include/mln/gfx/renderable.hpp +++ b/include/mln/gfx/renderable.hpp @@ -34,6 +34,7 @@ protected: virtual ~Renderable() = default; public: + /// Returns the renderable dimensions in physical pixels. Size getSize() const { return size; } template @@ -50,8 +51,12 @@ public: bool operator!=(const Renderable& other) const { return resource.get() != other.resource.get(); } -protected: +private: Size size; + +protected: + void setRenderableSize(const Size& size_) noexcept { size = size_; } + std::unique_ptr resource; }; diff --git a/include/mln/vulkan/renderable_resource.hpp b/include/mln/vulkan/renderable_resource.hpp index 39b80ea30..01efce018 100644 --- a/include/mln/vulkan/renderable_resource.hpp +++ b/include/mln/vulkan/renderable_resource.hpp @@ -116,7 +116,7 @@ protected: ~Renderable() override = default; public: - void setSize(const Size& size_) { size = size_; } + void setSize(const Size& size_) { setRenderableSize(size_); } }; } // namespace vulkan diff --git a/platform/android/MapLibreAndroid/src/cpp/android_gl_renderer_backend.cpp b/platform/android/MapLibreAndroid/src/cpp/android_gl_renderer_backend.cpp index d1b242d11..8326f9ff3 100644 --- a/platform/android/MapLibreAndroid/src/cpp/android_gl_renderer_backend.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/android_gl_renderer_backend.cpp @@ -46,21 +46,21 @@ gl::ProcAddress AndroidGLRendererBackend::getExtensionFunctionPointer(const char void AndroidGLRendererBackend::updateViewPort() { assert(gfx::BackendScope::exists()); - setViewport(0, 0, size); + setViewport(0, 0, getSize()); } void AndroidGLRendererBackend::resizeFramebuffer(int width, int height) { - size = {static_cast(width), static_cast(height)}; + setRenderableSize({static_cast(width), static_cast(height)}); } PremultipliedImage AndroidGLRendererBackend::readFramebuffer() { assert(gfx::BackendScope::exists()); - return gl::RendererBackend::readFramebuffer(size); + return gl::RendererBackend::readFramebuffer(getSize()); } void AndroidGLRendererBackend::updateAssumedState() { assumeFramebufferBinding(0); - assumeViewport(0, 0, size); + assumeViewport(0, 0, getSize()); } void AndroidGLRendererBackend::markContextLost() { diff --git a/platform/android/MapLibreAndroid/src/cpp/android_webgpu_renderer_backend.cpp b/platform/android/MapLibreAndroid/src/cpp/android_webgpu_renderer_backend.cpp index 8fd36777e..d008f8488 100644 --- a/platform/android/MapLibreAndroid/src/cpp/android_webgpu_renderer_backend.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/android_webgpu_renderer_backend.cpp @@ -160,8 +160,6 @@ public: WGPUTexture currentTexture = nullptr; WGPUTextureView currentTextureView = nullptr; bool needsPresent = false; - - Size framebufferSize; }; AndroidWebGPURendererBackend::AndroidWebGPURendererBackend(ANativeWindow* window_) @@ -303,9 +301,8 @@ AndroidWebGPURendererBackend::AndroidWebGPURendererBackend(ANativeWindow* window const int w = ANativeWindow_getWidth(window); const int h = ANativeWindow_getHeight(window); if (w > 0 && h > 0) { - impl->framebufferSize = {static_cast(w), static_cast(h)}; - size = impl->framebufferSize; - configureSurface(impl->framebufferSize.width, impl->framebufferSize.height); + setRenderableSize({static_cast(w), static_cast(h)}); + configureSurface(static_cast(w), static_cast(h)); } } @@ -508,8 +505,7 @@ void AndroidWebGPURendererBackend::createDepthStencilTexture(uint32_t width, uin void AndroidWebGPURendererBackend::resizeFramebuffer(int width, int height) { if (width <= 0 || height <= 0) return; - impl->framebufferSize = {static_cast(width), static_cast(height)}; - size = impl->framebufferSize; + setRenderableSize({static_cast(width), static_cast(height)}); if (impl->currentTextureView) { wgpuTextureViewRelease(impl->currentTextureView); @@ -520,16 +516,16 @@ void AndroidWebGPURendererBackend::resizeFramebuffer(int width, int height) { impl->currentTexture = nullptr; } - configureSurface(impl->framebufferSize.width, impl->framebufferSize.height); + configureSurface(static_cast(width), static_cast(height)); } PremultipliedImage AndroidWebGPURendererBackend::readFramebuffer() { - if (!impl->currentTexture || !impl->device || !impl->queue || impl->framebufferSize.width == 0 || - impl->framebufferSize.height == 0) { - return PremultipliedImage(impl->framebufferSize.isEmpty() ? Size(2, 2) : impl->framebufferSize); + const auto framebufferSize = getSize(); + if (!impl->currentTexture || !impl->device || !impl->queue || framebufferSize.isEmpty()) { + return PremultipliedImage(framebufferSize.isEmpty() ? Size(2, 2) : framebufferSize); } - const auto& fbSize = impl->framebufferSize; + const auto& fbSize = framebufferSize; constexpr uint32_t bytesPerPixel = 4; constexpr uint32_t bytesPerRowAlignment = 256u; const uint32_t rowStride = fbSize.width * bytesPerPixel; @@ -683,7 +679,8 @@ void* AndroidWebGPURendererBackend::getCurrentTextureView() { auto status = static_cast(surfaceTexture.status); if (status == WGPUSurfaceGetCurrentTextureStatus_Outdated || status == WGPUSurfaceGetCurrentTextureStatus_Lost) { wgpuTextureRelease(surfaceTexture.texture); - configureSurface(impl->framebufferSize.width, impl->framebufferSize.height); + const auto framebufferSize = getSize(); + configureSurface(framebufferSize.width, framebufferSize.height); return nullptr; } @@ -698,10 +695,9 @@ void* AndroidWebGPURendererBackend::getCurrentTextureView() { // Actual texture size may differ from configured size (Vulkan currentExtent clamping) const uint32_t texW = wgpuTextureGetWidth(surfaceTexture.texture); const uint32_t texH = wgpuTextureGetHeight(surfaceTexture.texture); - if (texW != size.width || texH != size.height) { + if (const auto framebufferSize = getSize(); texW != framebufferSize.width || texH != framebufferSize.height) { if (texW > 0 && texH > 0) { - size = {texW, texH}; - impl->framebufferSize = size; + setRenderableSize({texW, texH}); createDepthStencilTexture(texW, texH); } } @@ -759,7 +755,7 @@ void* AndroidWebGPURendererBackend::getDepthStencilView() { } mln::Size AndroidWebGPURendererBackend::getFramebufferSize() const { - return impl->framebufferSize; + return getSize(); } } // namespace android diff --git a/platform/default/src/mln/gfx/headless_backend.cpp b/platform/default/src/mln/gfx/headless_backend.cpp index bbb891702..29e445ce2 100644 --- a/platform/default/src/mln/gfx/headless_backend.cpp +++ b/platform/default/src/mln/gfx/headless_backend.cpp @@ -9,7 +9,7 @@ HeadlessBackend::HeadlessBackend(Size size_) : mln::gfx::Renderable(size_, nullptr) {} void HeadlessBackend::setSize(Size size_) { - size = size_; + setRenderableSize(size_); resource.reset(); } diff --git a/platform/default/src/mln/gl/headless_backend.cpp b/platform/default/src/mln/gl/headless_backend.cpp index 865869ef3..2d5884276 100644 --- a/platform/default/src/mln/gl/headless_backend.cpp +++ b/platform/default/src/mln/gl/headless_backend.cpp @@ -97,7 +97,8 @@ gfx::Renderable& HeadlessBackend::getDefaultRenderable() { MLN_TRACE_FUNC(); if (!resource) { - resource = std::make_unique(*this, static_cast(getContext()), size); + resource = std::make_unique( + *this, static_cast(getContext()), getSize()); } return *this; } @@ -115,7 +116,7 @@ void HeadlessBackend::updateAssumedState() { PremultipliedImage HeadlessBackend::readStillImage() { MLN_TRACE_FUNC(); - return static_cast(getContext()).readFramebuffer(size); + return static_cast(getContext()).readFramebuffer(getSize()); } RendererBackend* HeadlessBackend::getRendererBackend() { diff --git a/platform/default/src/mln/mtl/headless_backend.cpp b/platform/default/src/mln/mtl/headless_backend.cpp index 5e8c0e002..9a16dbd32 100644 --- a/platform/default/src/mln/mtl/headless_backend.cpp +++ b/platform/default/src/mln/mtl/headless_backend.cpp @@ -83,7 +83,8 @@ gfx::Renderable& HeadlessBackend::getDefaultRenderable() { void HeadlessBackend::ensureResource() { if (!resource) { - resource = std::make_unique(*this, static_cast(getContext()), size); + resource = std::make_unique( + *this, static_cast(getContext()), getSize()); } } diff --git a/platform/glfw/glfw_backend.hpp b/platform/glfw/glfw_backend.hpp index 60f2e5728..e68e1dd36 100644 --- a/platform/glfw/glfw_backend.hpp +++ b/platform/glfw/glfw_backend.hpp @@ -23,6 +23,6 @@ public: } virtual mln::gfx::RendererBackend& getRendererBackend() = 0; - virtual mln::Size getSize() const = 0; - virtual void setSize(mln::Size) = 0; + virtual mln::Size getFramebufferSize() const = 0; + virtual void setFramebufferSize(mln::Size) = 0; }; diff --git a/platform/glfw/glfw_gl_backend.cpp b/platform/glfw/glfw_gl_backend.cpp index 42e7dbd8e..9c0bdd100 100644 --- a/platform/glfw/glfw_gl_backend.cpp +++ b/platform/glfw/glfw_gl_backend.cpp @@ -15,7 +15,7 @@ public: MLN_TRACE_FUNC(); backend.setFramebufferBinding(0); - backend.setViewport(0, 0, backend.getSize()); + backend.setViewport(0, 0, backend.getFramebufferSize()); } void swap() override { @@ -72,15 +72,15 @@ void GLFWGLBackend::updateAssumedState() { MLN_TRACE_FUNC(); assumeFramebufferBinding(0); - setViewport(0, 0, size); + setViewport(0, 0, getSize()); } -mln::Size GLFWGLBackend::getSize() const { - return size; +mln::Size GLFWGLBackend::getFramebufferSize() const { + return getSize(); } -void GLFWGLBackend::setSize(const mln::Size newSize) { - size = newSize; +void GLFWGLBackend::setFramebufferSize(const mln::Size newSize) { + setRenderableSize(newSize); } void GLFWGLBackend::swap() { diff --git a/platform/glfw/glfw_gl_backend.hpp b/platform/glfw/glfw_gl_backend.hpp index 9a7a21421..35b5528da 100644 --- a/platform/glfw/glfw_gl_backend.hpp +++ b/platform/glfw/glfw_gl_backend.hpp @@ -17,8 +17,8 @@ public: // GLFWRendererBackend implementation public: mln::gfx::RendererBackend& getRendererBackend() override { return *this; } - mln::Size getSize() const override; - void setSize(mln::Size) override; + mln::Size getFramebufferSize() const override; + void setFramebufferSize(mln::Size) override; // mln::gfx::RendererBackend implementation public: diff --git a/platform/glfw/glfw_metal_backend.h b/platform/glfw/glfw_metal_backend.h index d66a914b0..9d280d7ab 100644 --- a/platform/glfw/glfw_metal_backend.h +++ b/platform/glfw/glfw_metal_backend.h @@ -14,8 +14,8 @@ public: GLFWMetalBackend(GLFWwindow *window_, const bool capFrameRate); ~GLFWMetalBackend() = default; mln::gfx::RendererBackend &getRendererBackend() override; - void setSize(mln::Size) override; - mln::Size getSize() const override; + void setFramebufferSize(mln::Size) override; + mln::Size getFramebufferSize() const override; private: NSWindow *window; diff --git a/platform/glfw/glfw_metal_backend.mm b/platform/glfw/glfw_metal_backend.mm index 92768f57a..616056b08 100644 --- a/platform/glfw/glfw_metal_backend.mm +++ b/platform/glfw/glfw_metal_backend.mm @@ -11,6 +11,6 @@ GLFWMetalBackend::GLFWMetalBackend(GLFWwindow* window_, [[maybe_unused]] const b mln::gfx::RendererBackend& GLFWMetalBackend::getRendererBackend() { return rendererBackend; } -void GLFWMetalBackend::setSize(mln::Size size) { rendererBackend.setSize(size); } +void GLFWMetalBackend::setFramebufferSize(mln::Size size) { rendererBackend.setSize(size); } -mln::Size GLFWMetalBackend::getSize() const { return rendererBackend.getSize(); } +mln::Size GLFWMetalBackend::getFramebufferSize() const { return rendererBackend.getSize(); } diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp index cbd5681c6..5df17a795 100644 --- a/platform/glfw/glfw_view.cpp +++ b/platform/glfw/glfw_view.cpp @@ -312,10 +312,10 @@ GLFWView::GLFWView(bool fullscreen_, #if defined(__APPLE__) && !defined(MLN_RENDER_BACKEND_VULKAN) int fbW, fbH; glfwGetFramebufferSize(window, &fbW, &fbH); - backend->setSize({static_cast(fbW), static_cast(fbH)}); + backend->setFramebufferSize({static_cast(fbW), static_cast(fbH)}); #endif - pixelRatio = static_cast(backend->getSize().width) / width; + pixelRatio = static_cast(backend->getFramebufferSize().width) / width; glfwMakeContextCurrent(nullptr); @@ -1026,7 +1026,7 @@ void GLFWView::onWindowResize(GLFWwindow *window, int width, int height) { #ifdef __APPLE__ int fbW, fbH; glfwGetFramebufferSize(window, &fbW, &fbH); - view->backend->setSize({static_cast(fbW), static_cast(fbH)}); + view->backend->setFramebufferSize({static_cast(fbW), static_cast(fbH)}); #endif } @@ -1034,7 +1034,7 @@ void GLFWView::onFramebufferResize(GLFWwindow *window, int width, int height) { MLN_TRACE_FUNC(); auto *view = reinterpret_cast(glfwGetWindowUserPointer(window)); - view->backend->setSize({static_cast(width), static_cast(height)}); + view->backend->setFramebufferSize({static_cast(width), static_cast(height)}); // This is only triggered when the framebuffer is resized, but not the // window. It can happen when you move the window between screens with a diff --git a/platform/glfw/glfw_vulkan_backend.cpp b/platform/glfw/glfw_vulkan_backend.cpp index 4b98500d5..e4f1262bb 100644 --- a/platform/glfw/glfw_vulkan_backend.cpp +++ b/platform/glfw/glfw_vulkan_backend.cpp @@ -156,12 +156,12 @@ GLFWVulkanBackend::GLFWVulkanBackend(GLFWwindow* window_, const bool capFrameRat GLFWVulkanBackend::~GLFWVulkanBackend() {} -mln::Size GLFWVulkanBackend::getSize() const { - return size; +mln::Size GLFWVulkanBackend::getFramebufferSize() const { + return getSize(); } -void GLFWVulkanBackend::setSize(const mln::Size newSize) { - size = newSize; +void GLFWVulkanBackend::setFramebufferSize(const mln::Size newSize) { + setRenderableSize(newSize); auto& contextImpl = static_cast(*context); contextImpl.requestSurfaceUpdate(); diff --git a/platform/glfw/glfw_vulkan_backend.hpp b/platform/glfw/glfw_vulkan_backend.hpp index 220178b2c..76824f072 100644 --- a/platform/glfw/glfw_vulkan_backend.hpp +++ b/platform/glfw/glfw_vulkan_backend.hpp @@ -23,8 +23,8 @@ public: // GLFWRendererBackend implementation public: mln::gfx::RendererBackend& getRendererBackend() override { return *this; } - mln::Size getSize() const override; - void setSize(mln::Size) override; + mln::Size getFramebufferSize() const override; + void setFramebufferSize(mln::Size) override; // mln::gfx::RendererBackend implementation public: diff --git a/platform/glfw/glfw_webgpu_backend.hpp b/platform/glfw/glfw_webgpu_backend.hpp index 7041ec3df..cc3f954c7 100644 --- a/platform/glfw/glfw_webgpu_backend.hpp +++ b/platform/glfw/glfw_webgpu_backend.hpp @@ -34,8 +34,8 @@ public: // GLFWBackend implementation public: mln::gfx::RendererBackend& getRendererBackend() override; - mln::Size getSize() const override; - void setSize(mln::Size) override; + mln::Size getFramebufferSize() const override; + void setFramebufferSize(mln::Size) override; // mln::gfx::RendererBackend implementation public: @@ -50,7 +50,6 @@ public: // Override virtual methods from RendererBackend void* getCurrentTextureView() override; void* getDepthStencilView() override; - mln::Size getFramebufferSize() const override; private: class SpinLock { diff --git a/platform/glfw/glfw_webgpu_backend_impl.ipp b/platform/glfw/glfw_webgpu_backend_impl.ipp index e3c8d06c2..09837af61 100644 --- a/platform/glfw/glfw_webgpu_backend_impl.ipp +++ b/platform/glfw/glfw_webgpu_backend_impl.ipp @@ -896,13 +896,13 @@ void GLFWWebGPUBackend::deactivate() { // WebGPU doesn't need explicit context deactivation like OpenGL } -mln::Size GLFWWebGPUBackend::getSize() const { - return size; +mln::Size GLFWWebGPUBackend::getFramebufferSize() const { + return getSize(); } -void GLFWWebGPUBackend::setSize(mln::Size newSize) { +void GLFWWebGPUBackend::setFramebufferSize(mln::Size newSize) { // Update swap chain size if needed - if (size != newSize) { + if (getSize() != newSize) { #ifdef __APPLE__ int width = 0; int height = 0; @@ -918,7 +918,7 @@ void GLFWWebGPUBackend::setSize(mln::Size newSize) { } } #endif - size = newSize; + setRenderableSize(newSize); surfaceNeedsReconfigure = true; } } @@ -1066,10 +1066,6 @@ void* GLFWWebGPUBackend::getCurrentTextureView() { #endif } -mln::Size GLFWWebGPUBackend::getFramebufferSize() const { - return getSize(); -} - void* GLFWWebGPUBackend::getDepthStencilView() { std::lock_guard guard(textureStateLock); if (!depthStencilView) { @@ -1126,7 +1122,8 @@ void GLFWWebGPUBackend::reconfigureSurface() { return; } - size = {static_cast(std::max(width, 0)), static_cast(std::max(height, 0))}; + setRenderableSize( + {static_cast(std::max(width, 0)), static_cast(std::max(height, 0))}); // Configure surface wgpu::SurfaceConfiguration config = {}; diff --git a/platform/glfw/metal_backend.h b/platform/glfw/metal_backend.h index 8458439c5..ba922e343 100644 --- a/platform/glfw/metal_backend.h +++ b/platform/glfw/metal_backend.h @@ -15,5 +15,4 @@ public: void activate() override; void deactivate() override; void setSize(mln::Size size_); - mln::Size getSize() const; }; diff --git a/platform/glfw/metal_backend.mm b/platform/glfw/metal_backend.mm index 7da88defc..0497b558d 100644 --- a/platform/glfw/metal_backend.mm +++ b/platform/glfw/metal_backend.mm @@ -19,15 +19,12 @@ public: swapchain->setDevice(backend.getDevice().get()); } - void setBackendSize(mln::Size size_) { - size = size_; + void setDrawableSize(const mln::Size& drawableSize) { swapchain->setDrawableSize( - {static_cast(size.width), static_cast(size.height)}); + {static_cast(drawableSize.width), static_cast(drawableSize.height)}); buffersInvalid = true; } - mln::Size getSize() const { return size; } - void bind() override { surface = NS::TransferPtr(swapchain->nextDrawable()); auto texSize = mln::Size{static_cast(swapchain->drawableSize().width), @@ -107,7 +104,6 @@ private: CAMetalLayerPtr swapchain; gfx::Texture2DPtr depthTexture; gfx::Texture2DPtr stencilTexture; - mln::Size size; bool buffersInvalid = true; }; @@ -129,10 +125,6 @@ void MetalBackend::activate() {} void MetalBackend::deactivate() {} void MetalBackend::setSize(mln::Size size_) { - size = size_; - getResource().setBackendSize(size_); -} - -mln::Size MetalBackend::getSize() const { - return getResource().getSize(); + setRenderableSize(size_); + getResource().setDrawableSize(size_); } diff --git a/platform/ios/src/MLNMapView+Metal.mm b/platform/ios/src/MLNMapView+Metal.mm index 55afc66f0..3722d424d 100644 --- a/platform/ios/src/MLNMapView+Metal.mm +++ b/platform/ios/src/MLNMapView+Metal.mm @@ -235,7 +235,7 @@ void MLNMapViewMetalImpl::layoutChanged() { resource.mtlView.drawableSize = resource.lastAppliedDrawableSize = target; } - size = {static_cast(target.width), static_cast(target.height)}; + setRenderableSize({static_cast(target.width), static_cast(target.height)}); } MLNBackendResource* MLNMapViewMetalImpl::getObject() { diff --git a/platform/ios/src/MLNMapView+OpenGL.mm b/platform/ios/src/MLNMapView+OpenGL.mm index 6a61a3ea2..40d842b44 100644 --- a/platform/ios/src/MLNMapView+OpenGL.mm +++ b/platform/ios/src/MLNMapView+OpenGL.mm @@ -241,8 +241,8 @@ UIImage* MLNMapViewOpenGLImpl::snapshot() { void MLNMapViewOpenGLImpl::layoutChanged() { const auto scaleFactor = contentScaleFactor(); - size = {static_cast(mapView.bounds.size.width * scaleFactor), - static_cast(mapView.bounds.size.height * scaleFactor)}; + setRenderableSize({static_cast(mapView.bounds.size.width * scaleFactor), + static_cast(mapView.bounds.size.height * scaleFactor)}); } EAGLContext* MLNMapViewOpenGLImpl::getEAGLContext() { diff --git a/platform/ios/src/MLNMapView+WebGPU.mm b/platform/ios/src/MLNMapView+WebGPU.mm index 244db2e25..3edc50f9b 100644 --- a/platform/ios/src/MLNMapView+WebGPU.mm +++ b/platform/ios/src/MLNMapView+WebGPU.mm @@ -94,8 +94,6 @@ public: WGPUTextureView currentTextureView = nullptr; bool needsPresent = false; - mln::Size framebufferSize; - MLNWebGPUView* webGPUView = nil; bool presentsWithTransaction = false; NSUInteger activationCount = 0; @@ -316,8 +314,7 @@ void MLNMapViewWebGPUImpl::createView() { uint32_t w = static_cast(drawableSize.width); uint32_t h = static_cast(drawableSize.height); if (w > 0 && h > 0) { - impl->framebufferSize = {w, h}; - size = impl->framebufferSize; + setRenderableSize({w, h}); configureSurface(w, h); } } @@ -497,7 +494,8 @@ void* MLNMapViewWebGPUImpl::getCurrentTextureView() { if (status == WGPUSurfaceGetCurrentTextureStatus_Outdated || status == WGPUSurfaceGetCurrentTextureStatus_Lost) { wgpuTextureRelease(surfaceTexture.texture); - configureSurface(impl->framebufferSize.width, impl->framebufferSize.height); + const auto framebufferSize = getSize(); + configureSurface(framebufferSize.width, framebufferSize.height); return nullptr; } @@ -557,7 +555,7 @@ void MLNMapViewWebGPUImpl::presentSurface() { void* MLNMapViewWebGPUImpl::getDepthStencilView() { return impl->depthStencilView; } -mln::Size MLNMapViewWebGPUImpl::getFramebufferSize() const { return impl->framebufferSize; } +mln::Size MLNMapViewWebGPUImpl::getFramebufferSize() const { return getSize(); } UIView* MLNMapViewWebGPUImpl::getView() { return impl->webGPUView; } @@ -624,8 +622,7 @@ void MLNMapViewWebGPUImpl::layoutChanged() { uint32_t w = static_cast(drawableSize.width); uint32_t h = static_cast(drawableSize.height); - impl->framebufferSize = {w, h}; - size = impl->framebufferSize; + setRenderableSize({w, h}); if (impl->currentTextureView) { wgpuTextureViewRelease(impl->currentTextureView); @@ -642,12 +639,12 @@ void MLNMapViewWebGPUImpl::layoutChanged() { } UIImage* MLNMapViewWebGPUImpl::snapshot() { - if (!impl->currentTexture || !impl->device || !impl->queue || impl->framebufferSize.width == 0 || - impl->framebufferSize.height == 0) { + const auto framebufferSize = getSize(); + if (!impl->currentTexture || !impl->device || !impl->queue || framebufferSize.isEmpty()) { return nil; } - const auto& fbSize = impl->framebufferSize; + const auto& fbSize = framebufferSize; constexpr uint32_t bytesPerPixel = 4; constexpr uint32_t bytesPerRowAlignment = 256u; const uint32_t rowStride = fbSize.width * bytesPerPixel; diff --git a/platform/macos/src/MLNMapView+Metal.mm b/platform/macos/src/MLNMapView+Metal.mm index 52296448f..8c9667d52 100644 --- a/platform/macos/src/MLNMapView+Metal.mm +++ b/platform/macos/src/MLNMapView+Metal.mm @@ -139,7 +139,8 @@ MLNMapViewMetalImpl::MLNMapViewMetalImpl(MLNMapView* nativeView_) } void MLNMapViewMetalImpl::drawableSizeChanged(CGSize drawableSize) { - size = {static_cast(drawableSize.width), static_cast(drawableSize.height)}; + setRenderableSize( + {static_cast(drawableSize.width), static_cast(drawableSize.height)}); } MLNMapViewMetalImpl::~MLNMapViewMetalImpl() = default; diff --git a/src/mln/gl/offscreen_texture.cpp b/src/mln/gl/offscreen_texture.cpp index a10df6625..8b735e5cb 100644 --- a/src/mln/gl/offscreen_texture.cpp +++ b/src/mln/gl/offscreen_texture.cpp @@ -57,7 +57,7 @@ private: }; OffscreenTexture::OffscreenTexture(gl::Context& context, const Size size_, const gfx::TextureChannelDataType type) - : gfx::OffscreenTexture(size, std::make_unique(context, size_, type)) {} + : gfx::OffscreenTexture(size_, std::make_unique(context, size_, type)) {} bool OffscreenTexture::isRenderable() { try { diff --git a/src/mln/mtl/offscreen_texture.cpp b/src/mln/mtl/offscreen_texture.cpp index 669dede23..5658c550d 100644 --- a/src/mln/mtl/offscreen_texture.cpp +++ b/src/mln/mtl/offscreen_texture.cpp @@ -134,7 +134,7 @@ private: OffscreenTexture::OffscreenTexture( Context& context, const Size size_, const gfx::TextureChannelDataType type, bool depth, bool stencil) - : gfx::OffscreenTexture(size, std::make_unique(context, size_, type, depth, stencil)) {} + : gfx::OffscreenTexture(size_, std::make_unique(context, size_, type, depth, stencil)) {} bool OffscreenTexture::isRenderable() { assert(false); diff --git a/src/mln/renderer/layers/heatmap_texture_layer_tweaker.cpp b/src/mln/renderer/layers/heatmap_texture_layer_tweaker.cpp index 87ecb7c2d..9b4341e4a 100644 --- a/src/mln/renderer/layers/heatmap_texture_layer_tweaker.cpp +++ b/src/mln/renderer/layers/heatmap_texture_layer_tweaker.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -30,7 +29,7 @@ void HeatmapTextureLayerTweaker::execute(LayerGroupBase& layerGroup, const Paint propertiesUpdated = false; mat4 matrix; - const auto& size = parameters.staticData.backendSize; + const auto& size = parameters.renderableSize; matrix::ortho(matrix, 0, size.width, size.height, 0, -1, 1); const HeatmapTexturePropsUBO propsUBO = {.matrix = util::cast(matrix), diff --git a/src/mln/renderer/paint_parameters.cpp b/src/mln/renderer/paint_parameters.cpp index b963def1f..1af20a01b 100644 --- a/src/mln/renderer/paint_parameters.cpp +++ b/src/mln/renderer/paint_parameters.cpp @@ -66,6 +66,7 @@ PaintParameters::PaintParameters(gfx::Context& context_, double tileLodScale_, double tileLodPitchThreshold_, TileLodMode tileLodMode_, + Size renderableSize_, const gfx::ScissorRect& scissorRect_) : context(context_), backend(backend_), @@ -80,6 +81,7 @@ PaintParameters::PaintParameters(gfx::Context& context_, debugOptions(debugOptions_), timePoint(timePoint_), pixelRatio(pixelRatio_), + renderableSize(renderableSize_), shaders(*staticData_.shaders), frameCount(frameCount_), tileLodMinRadius(tileLodMinRadius_), diff --git a/src/mln/renderer/paint_parameters.hpp b/src/mln/renderer/paint_parameters.hpp index c9569f3ca..c09ca9537 100644 --- a/src/mln/renderer/paint_parameters.hpp +++ b/src/mln/renderer/paint_parameters.hpp @@ -63,6 +63,7 @@ public: double tileLodScale, double tileLodPitchThreshold, TileLodMode tileLodMode, + Size renderableSize, const gfx::ScissorRect&); ~PaintParameters(); @@ -85,6 +86,7 @@ public: TimePoint timePoint; float pixelRatio; + const Size renderableSize; std::array pixelsToGLUnits; gfx::ShaderRegistry& shaders; diff --git a/src/mln/renderer/render_static_data.hpp b/src/mln/renderer/render_static_data.hpp index 797792e64..4bcb9ca50 100644 --- a/src/mln/renderer/render_static_data.hpp +++ b/src/mln/renderer/render_static_data.hpp @@ -48,7 +48,6 @@ public: std::optional> depthRenderbuffer; bool has3D = false; bool uploaded = false; - Size backendSize; std::unique_ptr shaders; diff --git a/src/mln/renderer/renderer_impl.cpp b/src/mln/renderer/renderer_impl.cpp index 54b378d6d..0c0f427c6 100644 --- a/src/mln/renderer/renderer_impl.cpp +++ b/src/mln/renderer/renderer_impl.cpp @@ -181,7 +181,7 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr< const auto& renderTreeParameters = renderTree.getParameters(); staticData->has3D = renderTreeParameters.has3D; - staticData->backendSize = backend.getDefaultRenderable().getSize(); + const Size renderableSize = backend.getDefaultRenderable().getSize(); if (renderState == RenderState::Never) { observer->onWillStartRenderingMap(); @@ -190,7 +190,6 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr< observer->onWillStartRenderingFrame(); const TransformState& state = renderTreeParameters.transformParams.state; - const Size& size = staticData->backendSize; const EdgeInsets& frustumOffset = state.getFrustumOffset(); const gfx::ScissorRect scissorRect = { .x = static_cast(frustumOffset.left() * pixelRatio), @@ -199,8 +198,10 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr< #else .y = static_cast(frustumOffset.top() * pixelRatio), #endif - .width = size.width - static_cast((frustumOffset.left() + frustumOffset.right()) * pixelRatio), - .height = size.height - static_cast((frustumOffset.top() + frustumOffset.bottom()) * pixelRatio), + .width = renderableSize.width - + static_cast((frustumOffset.left() + frustumOffset.right()) * pixelRatio), + .height = renderableSize.height - + static_cast((frustumOffset.top() + frustumOffset.bottom()) * pixelRatio), }; PaintParameters parameters{ @@ -220,6 +221,7 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr< updateParameters->tileLodScale, updateParameters->tileLodPitchThreshold, updateParameters->tileLodMode, + renderableSize, scissorRect, }; @@ -297,7 +299,7 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr< } const Size atlasSize = parameters.patternAtlas.getPixelSize(); - const auto& worldSize = parameters.staticData.backendSize; + const auto& worldSize = parameters.renderableSize; const shaders::GlobalPaintParamsUBO globalPaintParamsUBO = { .pattern_atlas_texsize = {static_cast(atlasSize.width), static_cast(atlasSize.height)}, .units_to_pixels = {1.0f / parameters.pixelsToGLUnits[0], 1.0f / parameters.pixelsToGLUnits[1]}, @@ -318,8 +320,6 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr< // attachments, but share the same depth rbo between them. const auto common3DPass = [&] { if (parameters.staticData.has3D) { - parameters.staticData.backendSize = parameters.backend.getDefaultRenderable().getSize(); - const auto debugGroup(parameters.encoder->createDebugGroup("common-3d")); parameters.pass = RenderPass::Pass3D; #if MLN_RENDER_BACKEND_OPENGL @@ -328,10 +328,10 @@ void Renderer::Impl::render(const RenderTree& renderTree, const std::shared_ptr< // TODO is this needed? // if (!parameters.staticData.depthRenderbuffer || - // parameters.staticData.depthRenderbuffer->getSize() != parameters.staticData.backendSize) { + // parameters.staticData.depthRenderbuffer->getSize() != parameters.renderableSize) { // parameters.staticData.depthRenderbuffer = // parameters.context.createRenderbuffer( - // parameters.staticData.backendSize); + // parameters.renderableSize); //} // parameters.staticData.depthRenderbuffer->setShouldClear(true); } diff --git a/src/mln/vulkan/offscreen_texture.cpp b/src/mln/vulkan/offscreen_texture.cpp index 097f15907..b71878bf6 100644 --- a/src/mln/vulkan/offscreen_texture.cpp +++ b/src/mln/vulkan/offscreen_texture.cpp @@ -133,7 +133,7 @@ OffscreenTexture::OffscreenTexture(Context& context, const gfx::TextureChannelDataType type, [[maybe_unused]] bool depth, [[maybe_unused]] bool stencil) - : gfx::OffscreenTexture(size, std::make_unique(context.getBackend(), size_, type)) { + : gfx::OffscreenTexture(size_, std::make_unique(context.getBackend(), size_, type)) { assert(!depth); assert(!stencil); } diff --git a/src/mln/webgpu/headless_backend.cpp b/src/mln/webgpu/headless_backend.cpp index 4636c4ff5..f8a072143 100644 --- a/src/mln/webgpu/headless_backend.cpp +++ b/src/mln/webgpu/headless_backend.cpp @@ -107,7 +107,7 @@ public: wgpu::TextureView offscreenTextureView; wgpu::Texture depthTexture; wgpu::TextureView depthTextureView; - Size framebufferSize; + Size offscreenTextureSize; }; HeadlessBackend::HeadlessBackend(Size size_, SwapBehaviour swapBehaviour_, gfx::ContextMode mode) @@ -116,8 +116,6 @@ HeadlessBackend::HeadlessBackend(Size size_, SwapBehaviour swapBehaviour_, gfx:: impl(std::make_unique()) { static_cast(swapBehaviour_); - impl->framebufferSize = size_; - #if MLN_WEBGPU_IMPL_DAWN // Initialize Dawn instance with TimedWaitAny feature enabled wgpu::InstanceFeatureName timedWaitAnyFeature = wgpu::InstanceFeatureName::TimedWaitAny; @@ -221,6 +219,9 @@ HeadlessBackend::~HeadlessBackend() { void HeadlessBackend::createOffscreenTextures() { if (!impl->device) return; + const auto renderableSize = getSize(); + impl->offscreenTextureSize = renderableSize; + // Release old textures if they exist impl->offscreenTextureView = nullptr; impl->offscreenTexture = nullptr; @@ -236,8 +237,7 @@ void HeadlessBackend::createOffscreenTextures() { #elif MLN_WEBGPU_IMPL_WGPU colorDesc.dimension = wgpu::TextureDimension::_2D; #endif - colorDesc.size = { - static_cast(impl->framebufferSize.width), static_cast(impl->framebufferSize.height), 1}; + colorDesc.size = {renderableSize.width, renderableSize.height, 1}; colorDesc.format = wgpu::TextureFormat::RGBA8Unorm; colorDesc.mipLevelCount = 1; colorDesc.sampleCount = 1; @@ -282,8 +282,7 @@ void HeadlessBackend::createOffscreenTextures() { #elif MLN_WEBGPU_IMPL_WGPU depthDesc.dimension = wgpu::TextureDimension::_2D; #endif - depthDesc.size = { - static_cast(impl->framebufferSize.width), static_cast(impl->framebufferSize.height), 1}; + depthDesc.size = {renderableSize.width, renderableSize.height, 1}; depthDesc.format = wgpu::TextureFormat::Depth24PlusStencil8; depthDesc.mipLevelCount = 1; depthDesc.sampleCount = 1; @@ -323,8 +322,8 @@ void HeadlessBackend::createOffscreenTextures() { gfx::Renderable& HeadlessBackend::getDefaultRenderable() { if (!hasResource()) { - setResource( - std::make_unique(*this, static_cast(getContext()), size)); + setResource(std::make_unique( + *this, static_cast(getContext()), getSize())); } return *this; } @@ -350,8 +349,7 @@ RendererBackend* HeadlessBackend::getRendererBackend() { void HeadlessBackend::activate() { active = true; // Ensure textures are created if size changed - if (impl && impl->framebufferSize != getSize()) { - impl->framebufferSize = getSize(); + if (impl && impl->offscreenTextureSize != getSize()) { createOffscreenTextures(); } } @@ -375,9 +373,6 @@ void* HeadlessBackend::getDepthStencilView() { } mln::Size HeadlessBackend::getFramebufferSize() const { - if (impl) { - return impl->framebufferSize; - } return getSize(); } diff --git a/src/mln/webgpu/offscreen_texture.cpp b/src/mln/webgpu/offscreen_texture.cpp index acdb0c2b4..ae420b566 100644 --- a/src/mln/webgpu/offscreen_texture.cpp +++ b/src/mln/webgpu/offscreen_texture.cpp @@ -354,7 +354,7 @@ OffscreenTexture::OffscreenTexture( Context& context, const Size size_, const gfx::TextureChannelDataType type, bool depth, bool stencil) : gfx::OffscreenTexture(size_, std::make_unique(context, size_, type, depth, stencil)) { auto& offscreenResource = getResource(); - offscreenResource.setSizeListener([this](const Size& newSize) { size = newSize; }); + offscreenResource.setSizeListener([this](const Size& newSize) { setRenderableSize(newSize); }); } bool OffscreenTexture::isRenderable() { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 50e426543..188e9eb40 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -21,6 +21,7 @@ add_library( ${PROJECT_SOURCE_DIR}/test/plugin/plugin.test.cpp ${PROJECT_SOURCE_DIR}/test/renderer/image_manager.test.cpp ${PROJECT_SOURCE_DIR}/test/renderer/pattern_atlas.test.cpp + ${PROJECT_SOURCE_DIR}/test/renderer/renderable.test.cpp ${PROJECT_SOURCE_DIR}/test/renderer/shader_registry.test.cpp $<$:${PROJECT_SOURCE_DIR}/test/renderer/wgsl_preprocessor.test.cpp> ${PROJECT_SOURCE_DIR}/test/sprite/sprite_loader.test.cpp diff --git a/test/renderer/renderable.test.cpp b/test/renderer/renderable.test.cpp new file mode 100644 index 000000000..4aa59b0cb --- /dev/null +++ b/test/renderer/renderable.test.cpp @@ -0,0 +1,23 @@ +#include + +#include + +namespace { + +class TestRenderable final : public mln::gfx::Renderable { +public: + explicit TestRenderable(mln::Size size_) + : Renderable(size_, nullptr) {} + + void resize(const mln::Size& size_) { setRenderableSize(size_); } +}; + +} // namespace + +TEST(Renderable, MaintainsCanonicalPhysicalSize) { + TestRenderable renderable({256, 128}); + EXPECT_EQ(renderable.getSize(), (mln::Size{256, 128})); + + renderable.resize({512, 384}); + EXPECT_EQ(renderable.getSize(), (mln::Size{512, 384})); +}