From d282b3ba6b3198c0240f6f31854f4f8609ceca94 Mon Sep 17 00:00:00 2001 From: Adrian Cojocaru Date: Wed, 20 Nov 2024 15:17:39 +0200 Subject: [PATCH] Implement Android surface pre-rotation for Vulkan (#2955) --- include/mbgl/shaders/layer_ubo.hpp | 3 + include/mbgl/shaders/vulkan/background.hpp | 4 +- include/mbgl/shaders/vulkan/circle.hpp | 2 +- include/mbgl/shaders/vulkan/clipping_mask.hpp | 2 +- include/mbgl/shaders/vulkan/collision.hpp | 4 +- include/mbgl/shaders/vulkan/common.hpp | 18 +++++- include/mbgl/shaders/vulkan/debug.hpp | 2 +- include/mbgl/shaders/vulkan/fill.hpp | 20 +++---- include/mbgl/shaders/vulkan/heatmap.hpp | 4 +- include/mbgl/shaders/vulkan/hillshade.hpp | 4 +- include/mbgl/shaders/vulkan/line.hpp | 8 +-- include/mbgl/shaders/vulkan/raster.hpp | 2 +- include/mbgl/shaders/vulkan/symbol.hpp | 10 ++-- include/mbgl/vulkan/context.hpp | 1 + include/mbgl/vulkan/renderable_resource.hpp | 22 +++++++ .../cpp/android_vulkan_renderer_backend.cpp | 7 ++- .../cpp/android_vulkan_renderer_backend.hpp | 4 +- platform/glfw/glfw_vulkan_backend.cpp | 2 +- platform/glfw/glfw_vulkan_backend.hpp | 6 +- src/mbgl/renderer/paint_parameters.cpp | 2 +- src/mbgl/shaders/vulkan/shader_program.cpp | 6 ++ src/mbgl/vulkan/context.cpp | 58 +++++++++++++++---- src/mbgl/vulkan/renderable_resource.cpp | 50 +++++++++++++++- src/mbgl/vulkan/renderer_backend.cpp | 9 ++- 24 files changed, 195 insertions(+), 55 deletions(-) diff --git a/include/mbgl/shaders/layer_ubo.hpp b/include/mbgl/shaders/layer_ubo.hpp index 347fb15e752..d46d16104b6 100644 --- a/include/mbgl/shaders/layer_ubo.hpp +++ b/include/mbgl/shaders/layer_ubo.hpp @@ -51,6 +51,9 @@ static_assert(sizeof(GlobalPaintParamsUBO) == 3 * 16); enum { idGlobalPaintParamsUBO, +#if MLN_RENDER_BACKEND_VULKAN + PlatformParamsUBO, +#endif globalUBOCount }; diff --git a/include/mbgl/shaders/vulkan/background.hpp b/include/mbgl/shaders/vulkan/background.hpp index 8bfb59514c7..63a760df8b5 100644 --- a/include/mbgl/shaders/vulkan/background.hpp +++ b/include/mbgl/shaders/vulkan/background.hpp @@ -25,7 +25,7 @@ layout(set = DRAWABLE_UBO_SET_INDEX, binding = 0) uniform BackgroundDrawableUBO void main() { gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0); - gl_Position.y *= -1.0; + applySurfaceTransform(); } )"; @@ -101,7 +101,7 @@ void main() { in_position); gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0); - gl_Position.y *= -1.0; + applySurfaceTransform(); } )"; diff --git a/include/mbgl/shaders/vulkan/circle.hpp b/include/mbgl/shaders/vulkan/circle.hpp index 9f4402f6862..0adafd5d97d 100644 --- a/include/mbgl/shaders/vulkan/circle.hpp +++ b/include/mbgl/shaders/vulkan/circle.hpp @@ -150,7 +150,7 @@ void main() { gl_Position.xy += scaled_extrude * (radius + stroke_width) * factor; } - gl_Position.y *= -1.0; + applySurfaceTransform(); // This is a minimum blur distance that serves as a faux-antialiasing for // the circle. since blur is a ratio of the circle's size and the intent is diff --git a/include/mbgl/shaders/vulkan/clipping_mask.hpp b/include/mbgl/shaders/vulkan/clipping_mask.hpp index dd349775081..7a803fe087f 100644 --- a/include/mbgl/shaders/vulkan/clipping_mask.hpp +++ b/include/mbgl/shaders/vulkan/clipping_mask.hpp @@ -8,7 +8,7 @@ namespace mbgl { namespace shaders { struct ClipUBO { - matf4 matrix; + mat4 matrix; std::uint32_t stencil_ref; }; diff --git a/include/mbgl/shaders/vulkan/collision.hpp b/include/mbgl/shaders/vulkan/collision.hpp index 7066e35ed6f..d511ead2dd0 100644 --- a/include/mbgl/shaders/vulkan/collision.hpp +++ b/include/mbgl/shaders/vulkan/collision.hpp @@ -44,7 +44,7 @@ void main() { gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0); gl_Position.xy += (in_extrude + in_shift) * drawable.extrude_scale * gl_Position.w * collision_perspective_ratio; - gl_Position.y *= -1.0; + applySurfaceTransform(); frag_placed = in_placed.x; frag_notUsed = in_placed.y; @@ -128,7 +128,7 @@ void main() { float padding_factor = 1.2; // Pad the vertices slightly to make room for anti-alias blur gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0); gl_Position.xy += in_extrude * drawable.extrude_scale * padding_factor * gl_Position.w * collision_perspective_ratio; - gl_Position.y *= -1.0; + applySurfaceTransform(); frag_placed = in_placed.x; frag_notUsed = in_placed.y; diff --git a/include/mbgl/shaders/vulkan/common.hpp b/include/mbgl/shaders/vulkan/common.hpp index 202feb40eee..cb0f13a804e 100644 --- a/include/mbgl/shaders/vulkan/common.hpp +++ b/include/mbgl/shaders/vulkan/common.hpp @@ -84,6 +84,20 @@ layout(set = GLOBAL_SET_INDEX, binding = 0) uniform GlobalPaintParamsUBO { float pad1; } global; +#ifdef USE_SURFACE_TRANSFORM +layout(set = GLOBAL_SET_INDEX, binding = 1) uniform PlatformParamsUBO { + mat2 rotation; +} platform; +#endif + +void applySurfaceTransform() { +#ifdef USE_SURFACE_TRANSFORM + gl_Position.xy = platform.rotation * gl_Position.xy; +#endif + + gl_Position.y *= -1.0; +} + )"; static constexpr auto fragment = R"( @@ -130,7 +144,7 @@ layout(set = DRAWABLE_UBO_SET_INDEX, binding = 0) uniform CommonUBO { void main() { gl_Position = ubo.matrix * vec4(in_position, 0, 1); - gl_Position.y *= -1.0; + applySurfaceTransform(); } )"; @@ -170,7 +184,7 @@ layout(location = 0) out vec2 frag_uv; void main() { gl_Position = ubo.matrix * vec4(in_position, 0, 1); - gl_Position.y *= -1.0; + applySurfaceTransform(); frag_uv = in_texcoord; } diff --git a/include/mbgl/shaders/vulkan/debug.hpp b/include/mbgl/shaders/vulkan/debug.hpp index 2e2bb636085..bbd3e9e7652 100644 --- a/include/mbgl/shaders/vulkan/debug.hpp +++ b/include/mbgl/shaders/vulkan/debug.hpp @@ -31,7 +31,7 @@ layout(location = 0) out vec2 frag_uv; void main() { gl_Position = debug.matrix * vec4(in_position * debug.overlay_scale, 0, 1); - gl_Position.y *= -1.0; + applySurfaceTransform(); // This vertex shader expects a EXTENT x EXTENT quad, // The UV co-ordinates for the overlay texture can be calculated using that knowledge diff --git a/include/mbgl/shaders/vulkan/fill.hpp b/include/mbgl/shaders/vulkan/fill.hpp index ee378a09b30..63fc4f2b951 100644 --- a/include/mbgl/shaders/vulkan/fill.hpp +++ b/include/mbgl/shaders/vulkan/fill.hpp @@ -55,7 +55,7 @@ void main() { #endif gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0); - gl_Position.y *= -1.0; + applySurfaceTransform(); } )"; @@ -150,7 +150,7 @@ void main() { #endif gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0); - gl_Position.y *= -1.0; + applySurfaceTransform(); frag_position = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * global.world_size; } @@ -309,7 +309,7 @@ void main() { frag_pos_b = get_pattern_pos(drawable.pixel_coord_upper, drawable.pixel_coord_lower, toScale * display_size_b, tileZoomRatio, in_position), gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0); - gl_Position.y *= -1.0; + applySurfaceTransform(); } )"; @@ -502,14 +502,12 @@ void main() { const vec2 display_size_b = vec2((pattern_br_b.x - pattern_tl_b.x) / pixelRatio, (pattern_br_b.y - pattern_tl_b.y) / pixelRatio); const vec2 position2 = in_position.xy; - vec4 position = drawable.matrix * vec4(in_position, 0.0, 1.0); - position.y *= -1.0; + gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0); + applySurfaceTransform(); frag_pos_a = get_pattern_pos(drawable.pixel_coord_upper, drawable.pixel_coord_lower, fromScale * display_size_a, tileZoomRatio, position2), frag_pos_b = get_pattern_pos(drawable.pixel_coord_upper, drawable.pixel_coord_lower, toScale * display_size_b, tileZoomRatio, position2), - frag_pos = (position.xy / position.w + 1.0) / 2.0 * global.world_size; - - gl_Position = position; + frag_pos = (gl_Position.xy / gl_Position.w + 1.0) / 2.0 * global.world_size; } )"; @@ -655,7 +653,7 @@ void main() { vec4 projected_extrude = drawable.matrix * vec4(dist / drawable.ratio, 0.0, 0.0); gl_Position = drawable.matrix * vec4(pos, 0.0, 1.0) + projected_extrude; - gl_Position.y *= -1.0; + applySurfaceTransform(); // calculate how much the perspective view squishes or stretches the extrude float extrude_length_without_perspective = length(dist); @@ -788,7 +786,7 @@ void main() { const float z = t != 0.0 ? height : base; gl_Position = drawable.matrix * vec4(in_position, z, 1.0); - gl_Position.y *= -1.0; + applySurfaceTransform(); #if defined(OVERDRAW_INSPECTOR) frag_color = vec4(1.0); @@ -944,7 +942,7 @@ void main() { const float z = t != 0.0 ? height : base; gl_Position = drawable.matrix * vec4(in_position, z, 1.0); - gl_Position.y *= -1.0; + applySurfaceTransform(); #if defined(OVERDRAW_INSPECTOR) frag_color = vec4(1.0); diff --git a/include/mbgl/shaders/vulkan/heatmap.hpp b/include/mbgl/shaders/vulkan/heatmap.hpp index 89a8f7d9019..8d45f7e7241 100644 --- a/include/mbgl/shaders/vulkan/heatmap.hpp +++ b/include/mbgl/shaders/vulkan/heatmap.hpp @@ -98,7 +98,7 @@ void main() { // multiply a_pos by 0.5, since we had it * 2 in order to sneak // in extrusion data gl_Position = drawable.matrix * vec4(floor(in_position * 0.5) + scaled_extrude, 0, 1); - gl_Position.y *= -1.0; + applySurfaceTransform(); frag_weight = weight; frag_extrude = extrude; @@ -162,7 +162,7 @@ layout(location = 0) out vec2 frag_position; void main() { gl_Position = props.matrix * vec4(in_position * global.world_size, 0, 1); - gl_Position.y *= -1.0; + applySurfaceTransform(); frag_position = in_position; } diff --git a/include/mbgl/shaders/vulkan/hillshade.hpp b/include/mbgl/shaders/vulkan/hillshade.hpp index 433532650d8..f034a07e5fe 100644 --- a/include/mbgl/shaders/vulkan/hillshade.hpp +++ b/include/mbgl/shaders/vulkan/hillshade.hpp @@ -33,7 +33,7 @@ layout(location = 0) out vec2 frag_position; void main() { gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0); - gl_Position.y *= -1.0; + applySurfaceTransform(); const vec2 epsilon = vec2(1.0) / drawable.dimension; const float scale = (drawable.dimension.x - 2.0) / drawable.dimension.x; @@ -149,7 +149,7 @@ layout(location = 0) out vec2 frag_position; void main() { gl_Position = drawable.matrix * vec4(in_position, 0.0, 1.0); - gl_Position.y *= -1.0; + applySurfaceTransform(); frag_position = vec2(in_texture_position) / 8192.0; frag_position.y = 1.0 - frag_position.y; // TODO check this. prepare should ignore the flip diff --git a/include/mbgl/shaders/vulkan/line.hpp b/include/mbgl/shaders/vulkan/line.hpp index 347f212dc5f..08716d654c0 100644 --- a/include/mbgl/shaders/vulkan/line.hpp +++ b/include/mbgl/shaders/vulkan/line.hpp @@ -155,7 +155,7 @@ void main() { vec4 projected_extrude = drawable.matrix * vec4(dist / drawable.ratio, 0.0, 0.0); gl_Position = drawable.matrix * vec4(pos + offset2 / drawable.ratio, 0.0, 1.0) + projected_extrude; - gl_Position.y *= -1.0; + applySurfaceTransform(); // calculate how much the perspective view squishes or stretches the extrude float extrude_length_without_perspective = length(dist); @@ -376,7 +376,7 @@ void main() { vec4 projected_extrude = drawable.matrix * vec4(dist / drawable.ratio, 0.0, 0.0); gl_Position = drawable.matrix * vec4(pos + offset2 / drawable.ratio, 0.0, 1.0) + projected_extrude; - gl_Position.y *= -1.0; + applySurfaceTransform(); // calculate how much the perspective view squishes or stretches the extrude float extrude_length_without_perspective = length(dist); @@ -626,7 +626,7 @@ void main() { vec4 projected_extrude = drawable.matrix * vec4(dist / drawable.ratio, 0.0, 0.0); gl_Position = drawable.matrix * vec4(pos + offset2 / drawable.ratio, 0.0, 1.0) + projected_extrude; - gl_Position.y *= -1.0; + applySurfaceTransform(); // calculate how much the perspective view squishes or stretches the extrude float extrude_length_without_perspective = length(dist); @@ -941,7 +941,7 @@ void main() { vec4 projected_extrude = drawable.matrix * vec4(dist / drawable.ratio, 0.0, 0.0); gl_Position = drawable.matrix * vec4(pos + offset2 / drawable.ratio, 0.0, 1.0) + projected_extrude; - gl_Position.y *= -1.0; + applySurfaceTransform(); // calculate how much the perspective view squishes or stretches the extrude float extrude_length_without_perspective = length(dist); diff --git a/include/mbgl/shaders/vulkan/raster.hpp b/include/mbgl/shaders/vulkan/raster.hpp index ed2d08957fe..c8677d6d488 100644 --- a/include/mbgl/shaders/vulkan/raster.hpp +++ b/include/mbgl/shaders/vulkan/raster.hpp @@ -44,7 +44,7 @@ layout(location = 1) out vec2 frag_position1; void main() { gl_Position = drawable.matrix * vec4(in_position, 0, 1); - gl_Position.y *= -1.0; + applySurfaceTransform(); // We are using Int16 for texture position coordinates to give us enough precision for // fractional coordinates. We use 8192 to scale the texture coordinates in the buffer diff --git a/include/mbgl/shaders/vulkan/symbol.hpp b/include/mbgl/shaders/vulkan/symbol.hpp index 72e7513b5c3..67511b5a2f4 100644 --- a/include/mbgl/shaders/vulkan/symbol.hpp +++ b/include/mbgl/shaders/vulkan/symbol.hpp @@ -117,7 +117,7 @@ void main() { const vec2 pos0 = projected_pos.xy / projected_pos.w; const vec2 posOffset = a_offset * max(a_minFontScale, fontScale) / 32.0 + a_pxoffset / 16.0; gl_Position = drawable.coord_matrix * vec4(pos0 + rotation_matrix * posOffset, 0.0, 1.0); - gl_Position.y *= -1.0; + applySurfaceTransform(); const vec2 raw_fade_opacity = unpack_opacity(in_fade_opacity); const float fade_change = raw_fade_opacity[1] > 0.5 ? global.symbol_fade_change : -global.symbol_fade_change; @@ -339,8 +339,8 @@ void main() { const vec2 pos_rot = a_offset / 32.0 * fontScale + a_pxoffset; const vec2 pos0 = projected_pos.xy / projected_pos.w + rotation_matrix * pos_rot; gl_Position = drawable.coord_matrix * vec4(pos0, 0.0, 1.0); - gl_Position.y *= -1.0; - + applySurfaceTransform(); + const vec2 raw_fade_opacity = unpack_opacity(in_fade_opacity); const float fade_change = raw_fade_opacity[1] > 0.5 ? global.symbol_fade_change : -global.symbol_fade_change; @@ -640,7 +640,7 @@ void main() { const vec2 pos_rot = a_offset / 32.0 * fontScale; const vec2 pos0 = projected_pos.xy / projected_pos.w + rotation_matrix * pos_rot; gl_Position = drawable.coord_matrix * vec4(pos0, 0.0, 1.0); - gl_Position.y *= -1.0; + applySurfaceTransform(); const vec2 raw_fade_opacity = unpack_opacity(in_fade_opacity); const float fade_change = raw_fade_opacity[1] > 0.5 ? global.symbol_fade_change : -global.symbol_fade_change; @@ -862,7 +862,7 @@ void main() { } gl_Position = position; - gl_Position.y *= -1.0; + applySurfaceTransform(); frag_tex = in_tex; } diff --git a/include/mbgl/vulkan/context.hpp b/include/mbgl/vulkan/context.hpp index 87a45811622..e17160d6589 100644 --- a/include/mbgl/vulkan/context.hpp +++ b/include/mbgl/vulkan/context.hpp @@ -197,6 +197,7 @@ class Context final : public gfx::Context { uint8_t frameResourceIndex = 0; std::vector frameResources; bool surfaceUpdateRequested{false}; + int32_t currentFrameCount{0}; struct { gfx::ShaderProgramBasePtr shader; diff --git a/include/mbgl/vulkan/renderable_resource.hpp b/include/mbgl/vulkan/renderable_resource.hpp index 4c0bbe062a9..1c619d6ceb3 100644 --- a/include/mbgl/vulkan/renderable_resource.hpp +++ b/include/mbgl/vulkan/renderable_resource.hpp @@ -58,12 +58,22 @@ class SurfaceRenderableResource : public RenderableResource { void setAcquiredImageIndex(uint32_t index) { acquiredImageIndex = index; }; const vk::Image getAcquiredImage() const; + bool hasSurfaceTransformSupport() const; + bool didSurfaceTransformUpdate() const; + + // rotation needed to align framebuffer contents with device surface + float getRotation(); + + void setSurfaceTransformPollingInterval(int32_t value) { surfaceTransformPollingInterval = value; } + int32_t getSurfaceTransformPollingInterval() const { return surfaceTransformPollingInterval; } + void init(uint32_t w, uint32_t h); void recreateSwapchain(); protected: vk::UniqueSurfaceKHR surface; vk::UniqueSwapchainKHR swapchain; + vk::SurfaceCapabilitiesKHR capabilities; uint32_t acquiredImageIndex{0}; @@ -77,6 +87,18 @@ class SurfaceRenderableResource : public RenderableResource { UniqueImageAllocation depthAllocation; vk::Format depthFormat{vk::Format::eUndefined}; + + int32_t surfaceTransformPollingInterval{-1}; +}; + +class Renderable : public gfx::Renderable { +protected: + Renderable(const Size size_, std::unique_ptr resource_) + : gfx::Renderable(size_, std::move(resource_)) {} + virtual ~Renderable() override = default; + +public: + void setSize(const Size& size_) { size = size_; } }; } // namespace vulkan diff --git a/platform/android/MapLibreAndroid/src/cpp/android_vulkan_renderer_backend.cpp b/platform/android/MapLibreAndroid/src/cpp/android_vulkan_renderer_backend.cpp index b9c1ebd6d7a..2957f7095af 100644 --- a/platform/android/MapLibreAndroid/src/cpp/android_vulkan_renderer_backend.cpp +++ b/platform/android/MapLibreAndroid/src/cpp/android_vulkan_renderer_backend.cpp @@ -25,6 +25,11 @@ class AndroidVulkanRenderableResource final : public mbgl::vulkan::SurfaceRender auto& backendImpl = static_cast(backend); const vk::AndroidSurfaceCreateInfoKHR createInfo({}, backendImpl.getWindow()); surface = backendImpl.getInstance()->createAndroidSurfaceKHRUnique(createInfo); + + const int apiLevel = android_get_device_api_level(); + if (apiLevel < __ANDROID_API_Q__) { + setSurfaceTransformPollingInterval(30); + } } void bind() override {} @@ -42,7 +47,7 @@ class AndroidVulkanRenderableResource final : public mbgl::vulkan::SurfaceRender AndroidVulkanRendererBackend::AndroidVulkanRendererBackend(ANativeWindow* window_) : vulkan::RendererBackend(gfx::ContextMode::Unique), - mbgl::gfx::Renderable({64, 64}, std::make_unique(*this)), + vulkan::Renderable({64, 64}, std::make_unique(*this)), window(window_) { init(); } diff --git a/platform/android/MapLibreAndroid/src/cpp/android_vulkan_renderer_backend.hpp b/platform/android/MapLibreAndroid/src/cpp/android_vulkan_renderer_backend.hpp index 80c7382b75a..8094a2f5cca 100644 --- a/platform/android/MapLibreAndroid/src/cpp/android_vulkan_renderer_backend.hpp +++ b/platform/android/MapLibreAndroid/src/cpp/android_vulkan_renderer_backend.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include "android_renderer_backend.hpp" #include @@ -10,7 +10,7 @@ namespace android { class AndroidVulkanRendererBackend : public AndroidRendererBackend, public vulkan::RendererBackend, - public mbgl::gfx::Renderable { + public vulkan::Renderable { public: AndroidVulkanRendererBackend(ANativeWindow*); ~AndroidVulkanRendererBackend() override; diff --git a/platform/glfw/glfw_vulkan_backend.cpp b/platform/glfw/glfw_vulkan_backend.cpp index a5f5d9144d7..ad7fd96dd0f 100644 --- a/platform/glfw/glfw_vulkan_backend.cpp +++ b/platform/glfw/glfw_vulkan_backend.cpp @@ -36,7 +36,7 @@ class GLFWVulkanRenderableResource final : public mbgl::vulkan::SurfaceRenderabl GLFWVulkanBackend::GLFWVulkanBackend(GLFWwindow* window_, const bool) : mbgl::vulkan::RendererBackend(mbgl::gfx::ContextMode::Unique), - mbgl::gfx::Renderable( + mbgl::vulkan::Renderable( [window_] { int fbWidth; int fbHeight; diff --git a/platform/glfw/glfw_vulkan_backend.hpp b/platform/glfw/glfw_vulkan_backend.hpp index 49596e73569..6eab1dfea0a 100644 --- a/platform/glfw/glfw_vulkan_backend.hpp +++ b/platform/glfw/glfw_vulkan_backend.hpp @@ -2,12 +2,14 @@ #include "glfw_backend.hpp" -#include +#include #include struct GLFWwindow; -class GLFWVulkanBackend final : public GLFWBackend, public mbgl::vulkan::RendererBackend, public mbgl::gfx::Renderable { +class GLFWVulkanBackend final : public GLFWBackend, + public mbgl::vulkan::RendererBackend, + public mbgl::vulkan::Renderable { public: GLFWVulkanBackend(GLFWwindow*, bool capFrameRate); ~GLFWVulkanBackend() override; diff --git a/src/mbgl/renderer/paint_parameters.cpp b/src/mbgl/renderer/paint_parameters.cpp index e4957ff65b0..1e088cee970 100644 --- a/src/mbgl/renderer/paint_parameters.cpp +++ b/src/mbgl/renderer/paint_parameters.cpp @@ -229,7 +229,7 @@ void PaintParameters::renderTileClippingMasks(const RenderTiles& renderTiles) { tileUBOs.reserve(count); } - tileUBOs.emplace_back(shaders::ClipUBO{util::cast(matrixForTile(tileID)), stencilID}); + tileUBOs.emplace_back(shaders::ClipUBO{matrixForTile(tileID), stencilID}); } if (!tileUBOs.empty()) { diff --git a/src/mbgl/shaders/vulkan/shader_program.cpp b/src/mbgl/shaders/vulkan/shader_program.cpp index 2f7793bb988..14052e1b995 100644 --- a/src/mbgl/shaders/vulkan/shader_program.cpp +++ b/src/mbgl/shaders/vulkan/shader_program.cpp @@ -41,6 +41,12 @@ ShaderProgram::ShaderProgram(shaders::BuiltIn shaderID, for (const auto& define : additionalDefines) { defineStr += "#define " + define.first + " " + define.second + "\n"; } + + const auto& renderableResource = backend.getDefaultRenderable().getResource(); + if (renderableResource.hasSurfaceTransformSupport()) { + defineStr += "#define USE_SURFACE_TRANSFORM"; + } + observer.onPreCompileShader(shaderID, gfx::Backend::Type::Metal, defineStr); constexpr auto targetClientVersion = glslang::EShTargetVulkan_1_0; diff --git a/src/mbgl/vulkan/context.cpp b/src/mbgl/vulkan/context.cpp index 5a6e9863438..1acb4d691d4 100644 --- a/src/mbgl/vulkan/context.cpp +++ b/src/mbgl/vulkan/context.cpp @@ -189,6 +189,20 @@ void Context::beginFrame() { auto& renderableResource = backend.getDefaultRenderable().getResource(); const auto& platformSurface = renderableResource.getPlatformSurface(); + // poll for surface transform updates if enabled + const int32_t surfaceTransformPollingInterval = renderableResource.getSurfaceTransformPollingInterval(); + if (surfaceTransformPollingInterval >= 0 && !surfaceUpdateRequested) { + if (currentFrameCount > surfaceTransformPollingInterval) { + if (renderableResource.didSurfaceTransformUpdate()) { + requestSurfaceUpdate(); + } + + currentFrameCount = 0; + } else { + ++currentFrameCount; + } + } + if (platformSurface && surfaceUpdateRequested) { renderableResource.recreateSwapchain(); @@ -201,6 +215,14 @@ void Context::beginFrame() { // sync resources with swapchain frameResourceIndex = 0; surfaceUpdateRequested = false; + + // update renderable size + if (renderableResource.hasSurfaceTransformSupport()) { + const auto& extent = renderableResource.getExtent(); + + auto& renderable = static_cast(backend.getDefaultRenderable()); + renderable.setSize({extent.width, extent.height}); + } } backend.startFrameCapture(); @@ -221,13 +243,9 @@ void Context::beginFrame() { if (acquireImageResult.result == vk::Result::eSuccess) { renderableResource.setAcquiredImageIndex(acquireImageResult.value); } else if (acquireImageResult.result == vk::Result::eSuboptimalKHR) { - renderableResource.setAcquiredImageIndex(acquireImageResult.value); - // TODO implement pre-rotation transform for surface orientation -#if defined(__APPLE__) requestSurfaceUpdate(); beginFrame(); return; -#endif } } catch (const vk::OutOfDateKHRError& e) { @@ -289,10 +307,7 @@ void Context::submitFrame() { const auto& presentQueue = backend.getPresentQueue(); const vk::Result presentResult = presentQueue.presentKHR(presentInfo); if (presentResult == vk::Result::eSuboptimalKHR) { - // TODO implement pre-rotation transform for surface orientation -#if defined(__APPLE__) requestSurfaceUpdate(); -#endif } } catch (const vk::OutOfDateKHRError& e) { requestSurfaceUpdate(); @@ -409,7 +424,22 @@ void Context::clearStencilBuffer(int32_t) { void Context::bindGlobalUniformBuffers(gfx::RenderPass& renderPass) const noexcept { auto& renderPassImpl = static_cast(renderPass); - const_cast(this)->globalUniformBuffers.bindDescriptorSets(renderPassImpl.getEncoder()); + auto& context = const_cast(*this); + + auto& renderableResource = renderPassImpl.getDescriptor().renderable.getResource(); + if (renderableResource.hasSurfaceTransformSupport()) { + float surfaceRotation = renderableResource.getRotation(); + + struct alignas(16) { + alignas(16) std::array rotation0; + alignas(16) std::array rotation1; + } data; + + data = {{cosf(surfaceRotation), -sinf(surfaceRotation)}, {sinf(surfaceRotation), cosf(surfaceRotation)}}; + context.globalUniformBuffers.createOrUpdate(shaders::PlatformParamsUBO, &data, sizeof(data), context); + } + + context.globalUniformBuffers.bindDescriptorSets(renderPassImpl.getEncoder()); } bool Context::renderTileClippingMasks(gfx::RenderPass& renderPass, @@ -489,15 +519,23 @@ bool Context::renderTileClippingMasks(gfx::RenderPass& renderPass, commandBuffer->bindVertexBuffers(0, vertexBuffers, offset); commandBuffer->bindIndexBuffer(clipping.indexBuffer->getVulkanBuffer(), 0, vk::IndexType::eUint16); + auto& renderableResource = renderPassImpl.getDescriptor().renderable.getResource(); + const float rad = renderableResource.getRotation(); + const mat4 rotationMat = {cos(rad), -sin(rad), 0, 0, sin(rad), cos(rad), 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; + for (const auto& tileInfo : tileUBOs) { commandBuffer->setStencilReference(vk::StencilFaceFlagBits::eFrontAndBack, tileInfo.stencil_ref); + mat4 matrix; + matrix::multiply(matrix, rotationMat, tileInfo.matrix); + const auto& matrixf = util::cast(matrix); + commandBuffer->pushConstants( getPushConstantPipelineLayout().get(), vk::ShaderStageFlags() | vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0, - sizeof(tileInfo.matrix), - &tileInfo.matrix); + sizeof(matrixf), + &matrixf); commandBuffer->drawIndexed(clipping.indexCount, 1, 0, 0, 0); } diff --git a/src/mbgl/vulkan/renderable_resource.cpp b/src/mbgl/vulkan/renderable_resource.cpp index 89bbbb6a352..be91db09358 100644 --- a/src/mbgl/vulkan/renderable_resource.cpp +++ b/src/mbgl/vulkan/renderable_resource.cpp @@ -1,6 +1,7 @@ #include #include #include +#include namespace mbgl { namespace vulkan { @@ -95,7 +96,7 @@ void SurfaceRenderableResource::initSwapchain(uint32_t w, uint32_t h, vk::Presen } // pick surface size - const vk::SurfaceCapabilitiesKHR& capabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface.get()); + capabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface.get()); if (capabilities.currentExtent.width != std::numeric_limits::max()) { extent = capabilities.currentExtent; @@ -105,6 +106,13 @@ void SurfaceRenderableResource::initSwapchain(uint32_t w, uint32_t h, vk::Presen extent.height = std::min(std::max(h, capabilities.minImageExtent.height), capabilities.maxImageExtent.height); } + if (hasSurfaceTransformSupport()) { + if (capabilities.currentTransform & vk::SurfaceTransformFlagBitsKHR::eRotate90 || + capabilities.currentTransform & vk::SurfaceTransformFlagBitsKHR::eRotate270) { + std::swap(extent.width, extent.height); + } + } + uint32_t swapchainImageCount = capabilities.minImageCount + 1; // check surface limits (0 is unlimited) if (capabilities.maxImageCount > 0) swapchainImageCount = std::min(swapchainImageCount, capabilities.maxImageCount); @@ -133,7 +141,8 @@ void SurfaceRenderableResource::initSwapchain(uint32_t w, uint32_t h, vk::Presen swapchainCreateInfo.setImageSharingMode(vk::SharingMode::eExclusive); } - swapchainCreateInfo.setPreTransform(vk::SurfaceTransformFlagBitsKHR::eIdentity); + swapchainCreateInfo.setPreTransform(hasSurfaceTransformSupport() ? capabilities.currentTransform + : vk::SurfaceTransformFlagBitsKHR::eIdentity); swapchainCreateInfo.setClipped(VK_TRUE); if (capabilities.supportedCompositeAlpha & vk::CompositeAlphaFlagBitsKHR::eInherit) { @@ -143,7 +152,7 @@ void SurfaceRenderableResource::initSwapchain(uint32_t w, uint32_t h, vk::Presen } // update this when recreating - swapchainCreateInfo.setOldSwapchain(vk::SwapchainKHR(swapchain.get())); + swapchainCreateInfo.setOldSwapchain(swapchain.get()); swapchain = device->createSwapchainKHRUnique(swapchainCreateInfo); swapchainImages = device->getSwapchainImagesKHR(swapchain.get()); @@ -231,6 +240,41 @@ const vk::Image SurfaceRenderableResource::getAcquiredImage() const { return colorAllocations[acquiredImageIndex]->image; } +bool SurfaceRenderableResource::hasSurfaceTransformSupport() const { +#ifdef __ANDROID__ + return surface && capabilities.supportedTransforms != vk::SurfaceTransformFlagBitsKHR::eIdentity; +#else + return false; +#endif +} + +bool SurfaceRenderableResource::didSurfaceTransformUpdate() const { + const auto& physicalDevice = backend.getPhysicalDevice(); + const auto& updatedCapabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface.get()); + + return capabilities.currentTransform != updatedCapabilities.currentTransform; +} + +float SurfaceRenderableResource::getRotation() { + switch (capabilities.currentTransform) { + default: + case vk::SurfaceTransformFlagBitsKHR::eIdentity: + return 0.0f * M_PI / 180.0f; + + case vk::SurfaceTransformFlagBitsKHR::eRotate90: + case vk::SurfaceTransformFlagBitsKHR::eHorizontalMirrorRotate90: + return 90.0f * M_PI / 180.0f; + + case vk::SurfaceTransformFlagBitsKHR::eRotate180: + case vk::SurfaceTransformFlagBitsKHR::eHorizontalMirrorRotate180: + return 180.0f * M_PI / 180.0f; + + case vk::SurfaceTransformFlagBitsKHR::eRotate270: + case vk::SurfaceTransformFlagBitsKHR::eHorizontalMirrorRotate270: + return 270.0f * M_PI / 180.0f; + } +} + void SurfaceRenderableResource::init(uint32_t w, uint32_t h) { if (surface) { initSwapchain(w, h); diff --git a/src/mbgl/vulkan/renderer_backend.cpp b/src/mbgl/vulkan/renderer_backend.cpp index dddeb243315..1dd5d64a131 100644 --- a/src/mbgl/vulkan/renderer_backend.cpp +++ b/src/mbgl/vulkan/renderer_backend.cpp @@ -557,7 +557,7 @@ void RendererBackend::initDevice() { } void RendererBackend::initSwapchain() { - const auto& renderable = getDefaultRenderable(); + auto& renderable = getDefaultRenderable(); auto& renderableResource = renderable.getResource(); const auto& size = renderable.getSize(); @@ -566,6 +566,13 @@ void RendererBackend::initSwapchain() { maxFrames = renderableResource.getPlatformSurface() ? 3 : 1; renderableResource.init(size.width, size.height); + + if (renderableResource.hasSurfaceTransformSupport()) { + auto& renderableImpl = static_cast(renderable); + const auto& extent = renderableResource.getExtent(); + + renderableImpl.setSize({extent.width, extent.height}); + } } void RendererBackend::initCommandPool() {