From 156872f4c85ba76addd2bad5e0a2559311ee69f1 Mon Sep 17 00:00:00 2001 From: Adrian Cojocaru Date: Tue, 8 Oct 2024 19:20:12 +0300 Subject: [PATCH] Use drawables for location indicator layer (#2836) Co-authored-by: Bart Louwers --- CMakeLists.txt | 4 + bazel/core.bzl | 1 + include/mbgl/gfx/texture2d.hpp | 3 + include/mbgl/shaders/common_ubo.hpp | 20 + include/mbgl/shaders/shader_defines.hpp | 15 + include/mbgl/shaders/shader_source.hpp | 2 + include/mbgl/shaders/vulkan/common.hpp | 78 +++ include/mbgl/vulkan/texture2d.hpp | 3 + .../gradle/download-vulkan-validation.gradle | 2 +- .../src/mbgl/layermanager/layer_manager.cpp | 2 + platform/glfw/glfw_view.cpp | 7 +- platform/glfw/glfw_view.hpp | 14 +- .../location_indicator_layer_tweaker.cpp | 59 +++ .../location_indicator_layer_tweaker.hpp | 33 ++ .../render_location_indicator_layer.cpp | 470 ++++++++++++++++-- .../render_location_indicator_layer.hpp | 25 + src/mbgl/renderer/renderer_impl.cpp | 2 +- src/mbgl/shaders/vulkan/common.cpp | 28 ++ src/mbgl/vulkan/buffer_resource.cpp | 4 - src/mbgl/vulkan/drawable.cpp | 2 +- src/mbgl/vulkan/renderer_backend.cpp | 17 +- src/mbgl/vulkan/texture2d.cpp | 132 ++++- 22 files changed, 847 insertions(+), 76 deletions(-) create mode 100644 include/mbgl/shaders/common_ubo.hpp create mode 100644 src/mbgl/renderer/layers/location_indicator_layer_tweaker.cpp create mode 100644 src/mbgl/renderer/layers/location_indicator_layer_tweaker.hpp create mode 100644 src/mbgl/shaders/vulkan/common.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f9b40ce9b9b..a93c428fe51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -203,6 +203,8 @@ if(MLN_DRAWABLE_RENDERER) ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/hillshade_prepare_layer_tweaker.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/line_layer_tweaker.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/line_layer_tweaker.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/location_indicator_layer_tweaker.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/location_indicator_layer_tweaker.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/raster_layer_tweaker.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/raster_layer_tweaker.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layers/symbol_layer_tweaker.cpp @@ -1135,6 +1137,7 @@ if(MLN_WITH_OPENGL) ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/background_layer_ubo.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/circle_layer_ubo.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/collision_layer_ubo.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/common_ubo.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/style/layers/custom_drawable_layer.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/layermanager/custom_drawable_layer_factory.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/debug_layer_ubo.hpp @@ -1351,6 +1354,7 @@ if(MLN_WITH_VULKAN) ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/vulkan/circle.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/vulkan/clipping_mask.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/vulkan/collision.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/vulkan/common.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/vulkan/debug.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/vulkan/fill.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/vulkan/heatmap.cpp diff --git a/bazel/core.bzl b/bazel/core.bzl index de289ad2647..7a5d9bcacdf 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -999,6 +999,7 @@ MLN_DRAWABLES_HEADERS = [ "include/mbgl/shaders/background_layer_ubo.hpp", "include/mbgl/shaders/circle_layer_ubo.hpp", "include/mbgl/shaders/collision_layer_ubo.hpp", + "include/mbgl/shaders/common_ubo.hpp", "include/mbgl/shaders/custom_drawable_layer_ubo.hpp", "include/mbgl/shaders/debug_layer_ubo.hpp", "include/mbgl/shaders/fill_layer_ubo.hpp", diff --git a/include/mbgl/gfx/texture2d.hpp b/include/mbgl/gfx/texture2d.hpp index 3412179102f..aa7ece65d71 100644 --- a/include/mbgl/gfx/texture2d.hpp +++ b/include/mbgl/gfx/texture2d.hpp @@ -24,6 +24,9 @@ class Texture2D { TextureWrapType wrapU{TextureWrapType::Clamp}; /// Wrapping behavior along V coordinate TextureWrapType wrapV{TextureWrapType::Clamp}; + + uint8_t maxAnisotropy{1}; + bool mipmapped{false}; }; public: diff --git a/include/mbgl/shaders/common_ubo.hpp b/include/mbgl/shaders/common_ubo.hpp new file mode 100644 index 00000000000..9fc0f1bd4d1 --- /dev/null +++ b/include/mbgl/shaders/common_ubo.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace mbgl { +namespace shaders { + +struct alignas(16) CommonUBO { + std::array matrix; + Color color; +}; +static_assert(sizeof(CommonUBO) % 16 == 0); + +enum { + idCommonUBO = globalUBOCount, + commonUBOCount +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/shader_defines.hpp b/include/mbgl/shaders/shader_defines.hpp index 937d6d49970..6c9810a7074 100644 --- a/include/mbgl/shaders/shader_defines.hpp +++ b/include/mbgl/shaders/shader_defines.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -31,6 +32,7 @@ static constexpr auto maxUBOCountPerShader = std::max({static_cast(backg static_cast(circleUBOCount), static_cast(clippingMaskUBOCount), static_cast(collisionUBOCount), + static_cast(commonUBOCount), static_cast(customSymbolUBOCount), static_cast(debugUBOCount), static_cast(fillUBOCount), @@ -62,6 +64,11 @@ enum { collisionTextureCount }; +enum { + idCommonTexture, + commonTextureCount +}; + enum { idCustomSymbolImageTexture, customSymbolTextureCount @@ -114,6 +121,7 @@ static constexpr auto maxTextureCountPerShader = std::max({static_cast(b static_cast(circleTextureCount), static_cast(clippingMaskTextureCount), static_cast(collisionTextureCount), + static_cast(commonTextureCount), static_cast(customSymbolTextureCount), static_cast(debugTextureCount), static_cast(fillTextureCount), @@ -159,6 +167,12 @@ enum { collisionVertexAttributeCount }; +enum { + idCommonPosVertexAttribute, + idCommonTexVertexAttribute, + commonVertexAttributeCount +}; + enum { idCustomSymbolPosVertexAttribute, idCustomSymbolTexVertexAttribute, @@ -276,6 +290,7 @@ static constexpr auto maxVertexAttributeCountPerShader = std::max({ static_cast(circleVertexAttributeCount), static_cast(clippingMaskVertexAttributeCount), static_cast(collisionVertexAttributeCount), + static_cast(commonVertexAttributeCount), static_cast(customSymbolVertexAttributeCount), static_cast(debugVertexAttributeCount), static_cast(fillVertexAttributeCount), diff --git a/include/mbgl/shaders/shader_source.hpp b/include/mbgl/shaders/shader_source.hpp index 4a2fc2c19f3..debb932ea86 100644 --- a/include/mbgl/shaders/shader_source.hpp +++ b/include/mbgl/shaders/shader_source.hpp @@ -14,6 +14,8 @@ enum class BuiltIn { CircleShader, CollisionBoxShader, CollisionCircleShader, + CommonShader, + CommonTexturedShader, DebugShader, FillShader, FillOutlineShader, diff --git a/include/mbgl/shaders/vulkan/common.hpp b/include/mbgl/shaders/vulkan/common.hpp index c9909a6921f..2908c24b796 100644 --- a/include/mbgl/shaders/vulkan/common.hpp +++ b/include/mbgl/shaders/vulkan/common.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include namespace mbgl { namespace shaders { @@ -100,5 +101,82 @@ layout(set = 0, binding = 0) uniform GlobalPaintParamsUBO { )"; }; +template <> +struct ShaderSource { + static constexpr const char* name = "CommonShader"; + + static const std::array uniforms; + static const std::array attributes; + static constexpr std::array instanceAttributes{}; + static constexpr std::array textures{}; + + static constexpr auto vertex = R"( +layout(location = 0) in vec2 in_position; + +layout(set = 0, binding = 1) uniform CommonUBO { + mat4 matrix; + vec4 color; +} ubo; + +void main() { + gl_Position = ubo.matrix * vec4(in_position, 0, 1); + gl_Position.y *= -1.0; +} +)"; + + static constexpr auto fragment = R"( +layout(location = 0) out vec4 out_color; + +layout(set = 0, binding = 1) uniform CommonUBO { + mat4 matrix; + vec4 color; +} ubo; + +void main() { + out_color = ubo.color; +} +)"; +}; + +template <> +struct ShaderSource { + static constexpr const char* name = "CommonTexturedShader"; + + static const std::array uniforms; + static const std::array attributes; + static constexpr std::array instanceAttributes{}; + static const std::array textures; + + static constexpr auto vertex = R"( +layout(location = 0) in vec2 in_position; +layout(location = 1) in vec2 in_texcoord; + +layout(set = 0, binding = 1) uniform CommonUBO { + mat4 matrix; + vec4 color; +} ubo; + +layout(location = 0) out vec2 frag_uv; + +void main() { + gl_Position = ubo.matrix * vec4(in_position, 0, 1); + gl_Position.y *= -1.0; + + frag_uv = in_texcoord; +} +)"; + + static constexpr auto fragment = R"( +layout(location = 0) in vec2 frag_uv; +layout(location = 0) out vec4 out_color; + +layout(set = 1, binding = 0) uniform sampler2D image_sampler; + +void main() { + out_color = texture(image_sampler, frag_uv); +} +)"; +}; + } // namespace shaders } // namespace mbgl diff --git a/include/mbgl/vulkan/texture2d.hpp b/include/mbgl/vulkan/texture2d.hpp index ae7456c88be..7d88e3e87c0 100644 --- a/include/mbgl/vulkan/texture2d.hpp +++ b/include/mbgl/vulkan/texture2d.hpp @@ -96,6 +96,9 @@ class Texture2D : public gfx::Texture2D { void transitionToShaderReadLayout(const vk::UniqueCommandBuffer&); void transitionToGeneralLayout(const vk::UniqueCommandBuffer&); + uint32_t getMipLevels() const; + void generateMips(const vk::UniqueCommandBuffer& buffer); + private: Context& context; diff --git a/platform/android/gradle/download-vulkan-validation.gradle b/platform/android/gradle/download-vulkan-validation.gradle index d707c245a6e..85f54d0f478 100644 --- a/platform/android/gradle/download-vulkan-validation.gradle +++ b/platform/android/gradle/download-vulkan-validation.gradle @@ -48,4 +48,4 @@ task unzip(dependsOn: download, type: Copy) { android.sourceSets.vulkan.jniLibs { srcDir(tasks.unzip) -} \ No newline at end of file +} diff --git a/platform/default/src/mbgl/layermanager/layer_manager.cpp b/platform/default/src/mbgl/layermanager/layer_manager.cpp index b9e999e7ad3..982accce96a 100644 --- a/platform/default/src/mbgl/layermanager/layer_manager.cpp +++ b/platform/default/src/mbgl/layermanager/layer_manager.cpp @@ -69,6 +69,8 @@ LayerManagerDefault::LayerManagerDefault() { #if !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) addLayerType(std::make_unique()); #endif +#endif +#if defined(MLN_RENDER_BACKEND_OPENGL) || MLN_RENDER_BACKEND_VULKAN #if !defined(MBGL_LAYER_LOCATION_INDICATOR_DISABLE_ALL) addLayerType(std::make_unique()); #endif diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp index b20e11e14fe..febb52d3ffe 100644 --- a/platform/glfw/glfw_view.cpp +++ b/platform/glfw/glfw_view.cpp @@ -63,8 +63,7 @@ using namespace std::numbers; -#if defined(MLN_RENDER_BACKEND_OPENGL) && !defined(MBGL_LAYER_LOCATION_INDICATOR_DISABLE_ALL) -#include +#ifdef ENABLE_LOCATION_INDICATOR namespace { const std::string mbglPuckAssetsPath{MAPBOX_PUCK_ASSETS_PATH}; @@ -1244,7 +1243,7 @@ void GLFWView::toggleCustomSource() { void GLFWView::toggleLocationIndicatorLayer() { MLN_TRACE_FUNC(); -#if defined(MLN_RENDER_BACKEND_OPENGL) && !defined(MBGL_LAYER_LOCATION_INDICATOR_DISABLE_ALL) +#ifdef ENABLE_LOCATION_INDICATOR puck = static_cast(map->getStyle().getLayer("puck")); static const mbgl::LatLng puckLocation{35.683389, 139.76525}; // A location on the crossing of 4 tiles if (puck == nullptr) { @@ -1309,7 +1308,7 @@ using Nanoseconds = std::chrono::nanoseconds; void GLFWView::onWillStartRenderingFrame() { MLN_TRACE_FUNC(); -#if defined(MLN_RENDER_BACKEND_OPENGL) && !defined(MBGL_LAYER_LOCATION_INDICATOR_DISABLE_ALL) +#ifdef ENABLE_LOCATION_INDICATOR puck = static_cast(map->getStyle().getLayer("puck")); if (puck) { uint64_t ns = mbgl::Clock::now().time_since_epoch().count(); diff --git a/platform/glfw/glfw_view.hpp b/platform/glfw/glfw_view.hpp index c97042937be..2ee15e7435f 100644 --- a/platform/glfw/glfw_view.hpp +++ b/platform/glfw/glfw_view.hpp @@ -5,13 +5,19 @@ #include #include #include -#if defined(MLN_RENDER_BACKEND_OPENGL) && !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) -#include -#endif #include #include +#if (defined(MLN_RENDER_BACKEND_OPENGL) || defined(MLN_RENDER_BACKEND_VULKAN)) && \ + !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) +#define ENABLE_LOCATION_INDICATOR +#endif + +#ifdef ENABLE_LOCATION_INDICATOR +#include +#endif + struct GLFWwindow; class GLFWBackend; class GLFWRendererFrontend; @@ -163,7 +169,7 @@ class GLFWView : public mbgl::MapObserver { mbgl::ResourceOptions mapResourceOptions; mbgl::ClientOptions mapClientOptions; -#if defined(MLN_RENDER_BACKEND_OPENGL) && !defined(MBGL_LAYER_CUSTOM_DISABLE_ALL) +#ifdef ENABLE_LOCATION_INDICATOR bool puckFollowsCameraCenter = false; mbgl::style::LocationIndicatorLayer *puck = nullptr; #endif diff --git a/src/mbgl/renderer/layers/location_indicator_layer_tweaker.cpp b/src/mbgl/renderer/layers/location_indicator_layer_tweaker.cpp new file mode 100644 index 00000000000..d226b2a0ce8 --- /dev/null +++ b/src/mbgl/renderer/layers/location_indicator_layer_tweaker.cpp @@ -0,0 +1,59 @@ +#include + +#include +#include +#include +#include + +namespace mbgl { + +void LocationIndicatorLayerTweaker::execute(LayerGroupBase& layerGroup, const PaintParameters& params) { + if (layerGroup.empty()) { + return; + } + + const auto& props = static_cast(*evaluatedProperties); + + const shaders::CommonUBO quadUBO = {/* .matrix */ util::cast(projectionPuck), + /* .color */ Color::black()}; + + visitLayerGroupDrawables(layerGroup, [&](gfx::Drawable& drawable) { + auto& drawableUniforms = drawable.mutableUniformBuffers(); + + if (!drawable.getEnabled()) { + return; + } + + switch (static_cast(drawable.getType())) { + case RenderLocationIndicatorLayer::LocationIndicatorComponentType::Circle: { + shaders::CommonUBO circleUBO = {/* .matrix */ util::cast(projectionCircle), + /* .color */ props.evaluated.get()}; + + drawableUniforms.createOrUpdate(shaders::idCommonUBO, &circleUBO, params.context); + break; + } + + case RenderLocationIndicatorLayer::LocationIndicatorComponentType::CircleOutline: { + shaders::CommonUBO circleUBO = {/* .matrix */ util::cast(projectionCircle), + /* .color */ props.evaluated.get()}; + + drawableUniforms.createOrUpdate(shaders::idCommonUBO, &circleUBO, params.context); + break; + } + + case RenderLocationIndicatorLayer::LocationIndicatorComponentType::PuckShadow: + [[fallthrough]]; + case RenderLocationIndicatorLayer::LocationIndicatorComponentType::Puck: + [[fallthrough]]; + case RenderLocationIndicatorLayer::LocationIndicatorComponentType::PuckHat: + drawableUniforms.createOrUpdate(shaders::idCommonUBO, &quadUBO, params.context); + break; + + default: + assert(false); + break; + } + }); +} + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/location_indicator_layer_tweaker.hpp b/src/mbgl/renderer/layers/location_indicator_layer_tweaker.hpp new file mode 100644 index 00000000000..e3dcac6d83a --- /dev/null +++ b/src/mbgl/renderer/layers/location_indicator_layer_tweaker.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include + +namespace mbgl { + +/** + Location indicator layer specific tweaker + */ +class LocationIndicatorLayerTweaker : public LayerTweaker { +public: + LocationIndicatorLayerTweaker(std::string id_, + Immutable properties, + const mbgl::mat4& projectionCircle_, + const mbgl::mat4& projectionPuck_) + : LayerTweaker(std::move(id_), properties), + projectionCircle(projectionCircle_), + projectionPuck(projectionPuck_) {} + +public: + ~LocationIndicatorLayerTweaker() override = default; + + void execute(LayerGroupBase&, const PaintParameters& params) override; + +private: + const mbgl::mat4& projectionCircle; + const mbgl::mat4& projectionPuck; +}; + +} // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_location_indicator_layer.cpp b/src/mbgl/renderer/layers/render_location_indicator_layer.cpp index 91a8d5e602b..e23070d6d0a 100644 --- a/src/mbgl/renderer/layers/render_location_indicator_layer.cpp +++ b/src/mbgl/renderer/layers/render_location_indicator_layer.cpp @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -38,11 +40,20 @@ #include #include -#else +#endif -#define MBGL_CHECK_ERROR(x) \ - while (0) { \ - } +#if !MLN_RENDER_BACKEND_OPENGL + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #endif @@ -86,20 +97,19 @@ struct LocationIndicatorRenderParameters { std::string puckHatImagePath; }; -#if MLN_RENDER_BACKEND_OPENGL class RenderLocationIndicatorImpl { -protected: +public: struct vec2 { - GLfloat x = 0.0f; - GLfloat y = 0.0f; + float x = 0.0f; + float y = 0.0f; - vec2(GLfloat x_, GLfloat y_) + vec2(float x_, float y_) : x(x_), y(y_) {} vec2() = default; explicit vec2(const Point& p) - : x(static_cast(p.x)), - y(static_cast(p.y)) {} + : x(static_cast(p.x)), + y(static_cast(p.y)) {} vec2(const vec2& o) = default; vec2(vec2&& o) = default; vec2& operator=(vec2&& o) = default; @@ -130,11 +140,12 @@ class RenderLocationIndicatorImpl { Point toPoint() const { return {x, y}; } friend vec2 operator-(const vec2& v) { return {-v.x, -v.y}; } - friend vec2 operator*(double a, const vec2& v) { return {GLfloat(v.x * a), GLfloat(v.y * a)}; } + friend vec2 operator*(double a, const vec2& v) { return {float(v.x * a), float(v.y * a)}; } friend vec2 operator+(const vec2& v1, const vec2& v2) { return {v1.x + v2.x, v1.y + v2.y}; } friend vec2 operator-(const vec2& v1, const vec2& v2) { return {v1.x - v2.x, v1.y - v2.y}; } }; +#if MLN_RENDER_BACKEND_OPENGL struct Shader { virtual ~Shader() { release(); } void release() { @@ -374,13 +385,6 @@ void main() { float pixelRatio = 1.0f; }; - RenderLocationIndicatorImpl(std::string sourceLayer) - : ruler(0, mapbox::cheap_ruler::CheapRuler::Meters), - feature(std::make_shared()), - featureEnvelope(std::make_shared>()) { - feature->sourceLayer = std::move(sourceLayer); - } - static bool hasAnisotropicFiltering() { const auto* extensions = reinterpret_cast(glGetString(GL_EXTENSIONS)); GLenum error = glGetError(); @@ -414,7 +418,74 @@ void main() { drawHat(); } +#endif + +#if !MLN_RENDER_BACKEND_OPENGL + struct TextureInfo { + std::shared_ptr texture; + std::optional> image; + std::string id = ""; + float pixelRatio = 1.0f; + size_t width = 0; + size_t height = 0; + bool dirty = false; + + void assign(const Immutable& img) { + reset(); + + image = img; + + id = img->id; + pixelRatio = img->pixelRatio; + + width = img->image.size.width; + height = img->image.size.height; + } + + void reset() { + texture.reset(); + image.reset(); + pixelRatio = 1.0f; + width = 0; + height = 0; + dirty = true; + } + }; + + bool setTextureFromImageID(const std::string& imagePath, + TextureInfo& textureInfo, + const mbgl::LocationIndicatorRenderParameters& params) { + bool updated = false; + const Immutable* sharedImage = nullptr; + + if (!imagePath.empty() && params.imageManager) { + sharedImage = params.imageManager->getSharedImage(imagePath); + } + + if (sharedImage) { + if (!textureInfo.texture || textureInfo.id != sharedImage->get()->id) { + textureInfo.assign(*sharedImage); + updated = true; + } + } else if (textureInfo.image) { + textureInfo.reset(); + updated = true; + } + + return updated; + } +#endif + +public: + RenderLocationIndicatorImpl(std::string sourceLayer) + : ruler(0, mapbox::cheap_ruler::CheapRuler::Meters), + feature(std::make_shared()), + featureEnvelope(std::make_shared>()) { + feature->sourceLayer = std::move(sourceLayer); + } + void release() { +#if MLN_RENDER_BACKEND_OPENGL if (!simpleShader.program) return; for (const auto& t : textures) t.second->release(); buffer.release(); @@ -424,6 +495,11 @@ void main() { texCoordsBuffer.release(); simpleShader.release(); texturedShader.release(); +#else + shadowDrawableInfo.reset(); + puckDrawableInfo.reset(); + hatDrawableInfo.reset(); +#endif } void updatePuckGeometry(const mbgl::LocationIndicatorRenderParameters& params) { @@ -439,9 +515,15 @@ void main() { params.puckShadowScale != oldParams.puckShadowScale) bearingChanged = true; // changes puck geometry but not necessarily the location if (params.errorRadiusMeters != oldParams.errorRadiusMeters) radiusChanged = true; +#if MLN_RENDER_BACKEND_OPENGL bearingChanged |= setTextureFromImageID(params.puckImagePath, texPuck, params); bearingChanged |= setTextureFromImageID(params.puckShadowImagePath, texShadow, params); bearingChanged |= setTextureFromImageID(params.puckHatImagePath, texPuckHat, params); +#else + bearingChanged |= setTextureFromImageID(params.puckShadowImagePath, shadowDrawableInfo.textureInfo, params); + bearingChanged |= setTextureFromImageID(params.puckImagePath, puckDrawableInfo.textureInfo, params); + bearingChanged |= setTextureFromImageID(params.puckHatImagePath, hatDrawableInfo.textureInfo, params); +#endif projectionCircle = params.projectionMatrix; const Point positionMercator = project(params.puckPosition, *params.state); @@ -469,7 +551,13 @@ void main() { if (!dirtyFeature) return; dirtyFeature = false; featureEnvelope->clear(); +#if MLN_RENDER_BACKEND_OPENGL if (!texPuck || !texPuck->isValid()) return; +#else + if (!puckDrawableInfo.textureInfo.texture) return; + + auto& puckGeometry = puckDrawableInfo.geometry; +#endif feature->geometry = mapbox::geometry::point{oldParams.puckPosition.latitude(), oldParams.puckPosition.longitude()}; @@ -505,6 +593,11 @@ void main() { } void updateRadius(const mbgl::LocationIndicatorRenderParameters& params) { +#if !MLN_RENDER_BACKEND_OPENGL + auto& circle = circleDrawableInfo.geometry; + circleDrawableInfo.dirty = true; +#endif + const TransformState& s = *params.state; const auto numVtxCircumference = static_cast(circle.size() - 1); const float bearingStep = 360.0f / @@ -617,6 +710,8 @@ void main() { util::clamp(pixelSizeToWorldSizeH(params.puckPosition, s), 0.8f, 100.1f) * params.perspectiveCompensation; // Compensation factor for the perspective deformation // ^ clamping this to 0.8 to avoid growing the puck too much close to the camera. + +#if MLN_RENDER_BACKEND_OPENGL const double shadowRadius = ((texShadow) ? texShadow->width / texShadow->pixelRatio : 0.0) * params.puckShadowScale * M_SQRT2 * 0.5 * horizontalScaleFactor; // Technically it's not the radius, but @@ -625,6 +720,24 @@ void main() { M_SQRT2 * 0.5 * horizontalScaleFactor; const double hatRadius = ((texPuckHat) ? texPuckHat->width / texPuckHat->pixelRatio : 0.0) * params.puckHatScale * M_SQRT2 * 0.5 * horizontalScaleFactor; +#else + const double shadowScale = shadowDrawableInfo.textureInfo.width / shadowDrawableInfo.textureInfo.pixelRatio; + const double shadowRadius = shadowScale * params.puckShadowScale * M_SQRT2 * 0.5 * horizontalScaleFactor; + + const double puckScale = puckDrawableInfo.textureInfo.width / puckDrawableInfo.textureInfo.pixelRatio; + const double puckRadius = puckScale * params.puckScale * M_SQRT2 * 0.5 * horizontalScaleFactor; + + const double hatScale = hatDrawableInfo.textureInfo.width / hatDrawableInfo.textureInfo.pixelRatio; + const double hatRadius = hatScale * params.puckHatScale * M_SQRT2 * 0.5 * horizontalScaleFactor; + + auto& shadowGeometry = shadowDrawableInfo.geometry; + auto& puckGeometry = puckDrawableInfo.geometry; + auto& hatGeometry = hatDrawableInfo.geometry; + + shadowDrawableInfo.dirty = true; + puckDrawableInfo.dirty = true; + hatDrawableInfo.dirty = true; +#endif for (unsigned long i = 0; i < 4; ++i) { const auto b = util::wrap(static_cast(params.puckBearing) + bearings[i], 0.0f, 360.0f); @@ -643,6 +756,7 @@ void main() { } } +#if MLN_RENDER_BACKEND_OPENGL void drawRadius(const mbgl::LocationIndicatorRenderParameters& params) { if (!(params.errorRadiusMeters > 0.0) || (params.errorRadiusColor.a == 0.0 && params.errorRadiusBorderColor.a == 0.0)) @@ -694,6 +808,7 @@ void main() { void drawPuck() { drawQuad(puckBuffer, puckGeometry, texPuck); } void drawHat() { drawQuad(hatBuffer, hatGeometry, texPuckHat); } +#endif static LatLng screenCoordinateToLatLng(const ScreenCoordinate& p, const TransformState& s, @@ -703,6 +818,7 @@ void main() { return s.screenCoordinateToLatLng(flippedPoint, wrapMode); } +#if MLN_RENDER_BACKEND_OPENGL bool setTextureFromImageID(const std::string& imagePath, std::shared_ptr& texture, const mbgl::LocationIndicatorRenderParameters& params) { @@ -731,7 +847,6 @@ void main() { } std::map> textures; - mapbox::cheap_ruler::CheapRuler ruler; SimpleShader simpleShader; TexturedShader texturedShader; Buffer buffer; @@ -749,6 +864,10 @@ void main() { std::array puckGeometry; std::array hatGeometry; std::array texCoords; +#endif + + mapbox::cheap_ruler::CheapRuler ruler; + mbgl::mat4 translation; mbgl::mat4 projectionCircle; mbgl::mat4 projectionPuck; @@ -760,23 +879,39 @@ void main() { bool initialized = false; bool dirtyFeature = true; +#if !MLN_RENDER_BACKEND_OPENGL + public: - mbgl::LocationIndicatorRenderParameters parameters; - std::shared_ptr feature; - std::shared_ptr> featureEnvelope; - static bool anisotropicFilteringAvailable; -}; + struct QuadDrawableInfo { + std::optional> drawable; + std::array geometry; + TextureInfo textureInfo; + bool dirty{false}; + + gfx::Drawable& getDrawable() { return drawable.value().get(); } + void reset() { textureInfo.reset(); } + }; -bool RenderLocationIndicatorImpl::anisotropicFilteringAvailable = false; -#else + struct CircleDrawableInfo { + std::optional> drawable; + std::optional> outlineDrawable; + std::array geometry; + TextureInfo textureInfo; + bool dirty{false}; -class RenderLocationIndicatorImpl { -public: - RenderLocationIndicatorImpl(std::string) {} + gfx::Drawable& getDrawable() { return drawable.value().get(); } + void reset() { textureInfo.reset(); } + }; - void release() {} - void updateFeature() {} - void updatePuckGeometry([[maybe_unused]] const mbgl::LocationIndicatorRenderParameters& params) {} + CircleDrawableInfo circleDrawableInfo; + QuadDrawableInfo shadowDrawableInfo; + QuadDrawableInfo puckDrawableInfo; + QuadDrawableInfo hatDrawableInfo; + + const auto& getProjectionCircle() const { return projectionCircle; } + const auto& getProjectionPuck() const { return projectionPuck; } + +#endif public: mbgl::LocationIndicatorRenderParameters parameters; @@ -786,7 +921,6 @@ class RenderLocationIndicatorImpl { }; bool RenderLocationIndicatorImpl::anisotropicFilteringAvailable = false; -#endif using namespace style; namespace { @@ -805,7 +939,7 @@ RenderLocationIndicatorLayer::RenderLocationIndicatorLayer(Immutablerelease()); + if (!contextDestroyed) renderImpl->release(); } void RenderLocationIndicatorLayer::transition(const TransitionParameters& parameters) { @@ -876,6 +1010,11 @@ void RenderLocationIndicatorLayer::prepare(const LayerPrepareParameters& p) { renderImpl->updatePuckGeometry(renderImpl->parameters); } +void RenderLocationIndicatorLayer::populateDynamicRenderFeatureIndex(DynamicFeatureIndex& index) const { + renderImpl->updateFeature(); + if (!renderImpl->featureEnvelope->empty()) index.insert(renderImpl->feature, renderImpl->featureEnvelope); +} + #if MLN_RENDER_BACKEND_OPENGL void RenderLocationIndicatorLayer::render(PaintParameters& paintParameters) { auto& glContext = static_cast(paintParameters.context); @@ -894,12 +1033,265 @@ void RenderLocationIndicatorLayer::render(PaintParameters& paintParameters) { paintParameters.backend.getDefaultRenderable().getResource().bind(); glContext.setDirtyState(); } - #endif -void RenderLocationIndicatorLayer::populateDynamicRenderFeatureIndex(DynamicFeatureIndex& index) const { - renderImpl->updateFeature(); - if (!renderImpl->featureEnvelope->empty()) index.insert(renderImpl->feature, renderImpl->featureEnvelope); +#if !MLN_RENDER_BACKEND_OPENGL + +void RenderLocationIndicatorLayer::update(gfx::ShaderRegistry& shaders, + gfx::Context& context, + const TransformState&, + const std::shared_ptr&, + const RenderTree&, + UniqueChangeRequestVec& changes) { + const auto drawPasses = RenderPass::Translucent; + + // If the result is transparent or missing, just remove any existing drawables and stop + if (drawPasses == RenderPass::None) { + removeAllDrawables(); + return; + } + + if (!quadShader) { + quadShader = context.getGenericShader(shaders, "CommonTexturedShader"); + } + + if (!quadShader) { + removeAllDrawables(); + return; + } + + if (!circleShader) { + circleShader = context.getGenericShader(shaders, "CommonShader"); + } + + if (!circleShader) { + removeAllDrawables(); + return; + } + + if (!layerGroup) { + if (auto layerGroup_ = context.createLayerGroup(layerIndex, /*initialCapacity=*/4, getID())) { + setLayerGroup(std::move(layerGroup_), changes); + } else { + return; + } + } + + if (!layerTweaker) { + layerTweaker = std::make_shared( + getID(), evaluatedProperties, renderImpl->getProjectionCircle(), renderImpl->getProjectionPuck()); + layerGroup->addLayerTweaker(layerTweaker); + } + + auto* localLayerGroup = static_cast(layerGroup.get()); + + if (localLayerGroup->getDrawableCount() == 0) { + // create empty drawable using a builder + const gfx::UniqueDrawableBuilder& builder = context.createDrawableBuilder(getID()); + + const auto createQuadGeometry = [&](gfx::Drawable& drawable, const auto& geometry) { + auto vertexAttrs = context.createVertexAttributeArray(); + + if (const auto& attr = vertexAttrs->set( + shaders::idCommonTexVertexAttribute, 0, gfx::AttributeDataType::Float2)) { + const std::array texCoords = { + {{0.0f, 1.0f}, {0.0f, 0.0f}, {1.0f, 0.0f}, {1.0f, 1.0f}}}; + + auto geoDataPtr = reinterpret_cast(texCoords.data()); + auto geoDataSize = texCoords.size() * sizeof(RenderLocationIndicatorImpl::vec2); + + std::vector rawData; + std::copy(geoDataPtr, geoDataPtr + geoDataSize, std::back_inserter(rawData)); + attr->setRawData(std::move(rawData)); + } + + drawable.setVertexAttributes(vertexAttrs); + + gfx::IndexVector indices; + indices.emplace_back(0, 1, 2); + indices.emplace_back(0, 2, 3); + + std::vector drawSegments; + drawSegments.emplace_back( + builder->createSegment(gfx::Triangles(), SegmentBase(0, 0, geometry.size(), indices.elements()))); + drawable.setIndexData(indices.vector(), std::move(drawSegments)); + }; + + const auto createQuadDrawable = [&](RenderLocationIndicatorImpl::QuadDrawableInfo& drawableInfo, + std::string&& name, + LocationIndicatorComponentType type) { + auto& drawable = builder->getCurrentDrawable(true); + drawable->setType(static_cast(type)); + + drawable->setName(name); + drawable->setRenderPass(drawPasses); + drawable->setDepthType(gfx::DepthMaskType::ReadWrite); + drawable->setColorMode(drawPasses == RenderPass::Translucent ? gfx::ColorMode::alphaBlended() + : gfx::ColorMode::unblended()); + + drawable->setShader(quadShader); + + createQuadGeometry(*drawable, drawableInfo.geometry); + + drawableInfo.drawable.emplace(*drawable); + + // add drawable to layer group + localLayerGroup->addDrawable(std::move(drawable)); + ++stats.drawablesAdded; + }; + + // create circle drawable + const auto getCircleDrawable = [&](const auto& name, auto& vertexAttrib) -> gfx::UniqueDrawable& { + auto& drawable = builder->getCurrentDrawable(true); + + drawable->setName(name); + drawable->setRenderPass(drawPasses); + drawable->setDepthType(gfx::DepthMaskType::ReadWrite); + drawable->setColorMode(drawPasses == RenderPass::Translucent ? gfx::ColorMode::alphaBlended() + : gfx::ColorMode::unblended()); + + drawable->setShader(circleShader); + drawable->setVertexAttributes(vertexAttrib); + + return drawable; + }; + + const auto createCircleDrawable = [&]() { + // circle[0] is the center + const auto& geometry = renderImpl->circleDrawableInfo.geometry; + const uint16_t vertexCount = static_cast(geometry.size()); + auto vertexAttrib = context.createVertexAttributeArray(); + + { + auto& drawable = getCircleDrawable("locationAccuracyCircle", vertexAttrib); + drawable->setType(static_cast(LocationIndicatorComponentType::Circle)); + + std::vector drawSegments; + std::vector indices; + + for (uint16_t i = 1; i < vertexCount - 1; ++i) { + indices.insert(indices.end(), {0, i, static_cast(i + 1)}); + } + indices.insert(indices.end(), {0, static_cast(vertexCount - 1), 1}); + + SegmentBase segment(0, 0, vertexCount, indices.size()); + drawSegments.emplace_back(builder->createSegment(gfx::Triangles(), std::move(segment))); + drawable->setIndexData(indices, std::move(drawSegments)); + + renderImpl->circleDrawableInfo.drawable.emplace(*drawable); + + localLayerGroup->addDrawable(std::move(drawable)); + ++stats.drawablesAdded; + } + + { + auto& drawable = getCircleDrawable("locationAccuracyCircleOutline", vertexAttrib); + drawable->setType(static_cast(LocationIndicatorComponentType::CircleOutline)); + + std::vector drawSegments; + std::vector indices; + + for (uint16_t i = 1; i < vertexCount; ++i) { + indices.push_back(i); + } + + SegmentBase segment(0, 0, vertexCount, indices.size()); + drawSegments.emplace_back(builder->createSegment(gfx::LineStrip(1.0f), std::move(segment))); + drawable->setIndexData(indices, std::move(drawSegments)); + + renderImpl->circleDrawableInfo.outlineDrawable.emplace(*drawable); + + localLayerGroup->addDrawable(std::move(drawable)); + ++stats.drawablesAdded; + } + }; + + createCircleDrawable(); + createQuadDrawable( + renderImpl->shadowDrawableInfo, "locationShadow", LocationIndicatorComponentType::PuckShadow); + createQuadDrawable(renderImpl->puckDrawableInfo, "locationPuck", LocationIndicatorComponentType::Puck); + createQuadDrawable(renderImpl->hatDrawableInfo, "locationPuckHat", LocationIndicatorComponentType::PuckHat); + }; + + const auto updateCircleDrawable = [&]() { + auto& circleDrawable = renderImpl->circleDrawableInfo.drawable.value().get(); + auto& circleOutlineDrawable = renderImpl->circleDrawableInfo.outlineDrawable.value().get(); + + if (!(renderImpl->parameters.errorRadiusMeters > 0.0) || + (renderImpl->parameters.errorRadiusColor.a == 0.0 && + renderImpl->parameters.errorRadiusBorderColor.a == 0.0)) { + circleDrawable.setEnabled(false); + circleOutlineDrawable.setEnabled(false); + return; + } else { + circleDrawable.setEnabled(true); + circleOutlineDrawable.setEnabled(true); + } + + // update attributes + if (renderImpl->circleDrawableInfo.dirty) { + // vertex attribute data is shared between the 2 circle drawables + const auto& geometry = renderImpl->circleDrawableInfo.geometry; + + using VertexVector = gfx::VertexVector; + std::shared_ptr verts = std::make_shared(); + for (const auto& elem : geometry) { + verts->emplace_back(elem); + } + + auto& circleVertexAttrs = circleDrawable.getVertexAttributes(); + if (const auto& attr = circleVertexAttrs->set(shaders::idCommonPosVertexAttribute)) { + attr->setSharedRawData( + verts, 0, 0, sizeof(RenderLocationIndicatorImpl::vec2), gfx::AttributeDataType::Float2); + } + } + }; + + const auto updateQuadDrawable = [&](RenderLocationIndicatorImpl::QuadDrawableInfo& info) { + auto& drawable = info.getDrawable(); + + if (info.dirty) { + auto vertexAttrs = drawable.getVertexAttributes(); + + if (const auto& attr = vertexAttrs->set( + shaders::idCommonPosVertexAttribute, 0, gfx::AttributeDataType::Float2)) { + auto geoDataPtr = reinterpret_cast(info.geometry.data()); + auto geoDataSize = info.geometry.size() * sizeof(RenderLocationIndicatorImpl::vec2); + + std::vector rawData; + std::copy(geoDataPtr, geoDataPtr + geoDataSize, std::back_inserter(rawData)); + attr->setRawData(std::move(rawData)); + } + + info.dirty = false; + } + + if (info.textureInfo.dirty) { + if (info.textureInfo.image) { + if (!info.textureInfo.texture) { + info.textureInfo.texture = context.createTexture2D(); + info.textureInfo.texture->setSamplerConfiguration({gfx::TextureFilterType::Linear, + gfx::TextureWrapType::Clamp, + gfx::TextureWrapType::Clamp, + 16, + true}); + } + + info.textureInfo.texture->upload(info.textureInfo.image->get()->image); + info.textureInfo.image.reset(); + } + + drawable.setTexture(info.textureInfo.texture, shaders::idCommonTexture); + info.textureInfo.dirty = false; + } + }; + + updateCircleDrawable(); + updateQuadDrawable(renderImpl->shadowDrawableInfo); + updateQuadDrawable(renderImpl->puckDrawableInfo); + updateQuadDrawable(renderImpl->hatDrawableInfo); } +#endif + } // namespace mbgl diff --git a/src/mbgl/renderer/layers/render_location_indicator_layer.hpp b/src/mbgl/renderer/layers/render_location_indicator_layer.hpp index dc9f1b28223..fffeae0b3f9 100644 --- a/src/mbgl/renderer/layers/render_location_indicator_layer.hpp +++ b/src/mbgl/renderer/layers/render_location_indicator_layer.hpp @@ -9,9 +9,27 @@ namespace mbgl { class RenderLocationIndicatorImpl; class RenderLocationIndicatorLayer final : public RenderLayer { public: + enum class LocationIndicatorComponentType : uint8_t { + Circle, + CircleOutline, + PuckShadow, + Puck, + PuckHat, + Undefined = 255 + }; + explicit RenderLocationIndicatorLayer(Immutable); ~RenderLocationIndicatorLayer() override; +#if !MLN_RENDER_BACKEND_OPENGL + void update(gfx::ShaderRegistry &, + gfx::Context &, + const TransformState &, + const std::shared_ptr &, + const RenderTree &, + UniqueChangeRequestVec &) override; +#endif + private: void transition(const TransitionParameters &) override; void evaluate(const PropertyEvaluationParameters &) override; @@ -26,9 +44,16 @@ class RenderLocationIndicatorLayer final : public RenderLayer { void populateDynamicRenderFeatureIndex(DynamicFeatureIndex &) const override; +private: bool contextDestroyed = false; std::unique_ptr renderImpl; style::LocationIndicatorPaintProperties::Unevaluated unevaluated; + +#if !MLN_RENDER_BACKEND_OPENGL + // Drawable shaders + gfx::ShaderProgramBasePtr quadShader; + gfx::ShaderProgramBasePtr circleShader; +#endif }; } // namespace mbgl diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index 150bf43efc2..5086281410b 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -525,10 +525,10 @@ void Renderer::Impl::render(const RenderTree& renderTree, parameters.renderPass.reset(); const auto startRendering = util::MonotonicTimer::now().count(); + // present submits render commands parameters.encoder->present(parameters.backend.getDefaultRenderable()); const auto renderingTime = util::MonotonicTimer::now().count() - startRendering; - // CommandEncoder destructor submits render commands. parameters.encoder.reset(); context.endFrame(); diff --git a/src/mbgl/shaders/vulkan/common.cpp b/src/mbgl/shaders/vulkan/common.cpp new file mode 100644 index 00000000000..52531b3479a --- /dev/null +++ b/src/mbgl/shaders/vulkan/common.cpp @@ -0,0 +1,28 @@ +#include +#include + +namespace mbgl { +namespace shaders { + +const std::array ShaderSource::uniforms = { + UniformBlockInfo{true, true, sizeof(CommonUBO), idCommonUBO}, +}; +const std::array ShaderSource::attributes = { + AttributeInfo{0, gfx::AttributeDataType::Float2, idCommonPosVertexAttribute}, +}; + +const std::array + ShaderSource::uniforms = { + UniformBlockInfo{true, true, sizeof(CommonUBO), idCommonUBO}, +}; +const std::array ShaderSource::attributes = + { + AttributeInfo{0, gfx::AttributeDataType::Float2, idCommonPosVertexAttribute}, + AttributeInfo{1, gfx::AttributeDataType::Float2, idCommonTexVertexAttribute}, +}; +const std::array ShaderSource::textures = { + TextureInfo{0, idCommonTexture}, +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/vulkan/buffer_resource.cpp b/src/mbgl/vulkan/buffer_resource.cpp index 27557897fb3..adf392fda49 100644 --- a/src/mbgl/vulkan/buffer_resource.cpp +++ b/src/mbgl/vulkan/buffer_resource.cpp @@ -164,9 +164,5 @@ std::size_t BufferResource::getVulkanBufferOffset() const noexcept { return context.getCurrentFrameResourceIndex() * bufferWindowSize; } -std::size_t BufferResource::getVulkanBufferSize() const noexcept { - return bufferWindowSize > 0 ? bufferWindowSize : size; -} - } // namespace vulkan } // namespace mbgl diff --git a/src/mbgl/vulkan/drawable.cpp b/src/mbgl/vulkan/drawable.cpp index 9593496e7cd..fb87dcdb8b4 100644 --- a/src/mbgl/vulkan/drawable.cpp +++ b/src/mbgl/vulkan/drawable.cpp @@ -425,7 +425,7 @@ bool Drawable::bindDescriptors(CommandEncoder& encoder) const noexcept { const auto& bufferResource = uniformBufferImpl.getBufferResource(); descriptorBufferInfo.setBuffer(bufferResource.getVulkanBuffer()) .setOffset(bufferResource.getVulkanBufferOffset()) - .setRange(bufferResource.getVulkanBufferSize()); + .setRange(bufferResource.getSizeInBytes()); } else if (fillGaps) { descriptorBufferInfo.setBuffer(context.getDummyUniformBuffer()->getVulkanBuffer()) .setOffset(0) diff --git a/src/mbgl/vulkan/renderer_backend.cpp b/src/mbgl/vulkan/renderer_backend.cpp index 0f0a04556eb..dddeb243315 100644 --- a/src/mbgl/vulkan/renderer_backend.cpp +++ b/src/mbgl/vulkan/renderer_backend.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -195,7 +196,8 @@ void RendererBackend::initFrameCapture() { void RendererBackend::startFrameCapture() { #ifdef ENABLE_RENDERDOC_FRAME_CAPTURE if (g_rdoc_api) { - g_rdoc_api->StartFrameCapture(nullptr, nullptr); + RENDERDOC_DevicePointer devicePtr = RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(instance->operator VkInstance_T*()); + g_rdoc_api->StartFrameCapture(devicePtr, nullptr); } #endif } @@ -203,7 +205,8 @@ void RendererBackend::startFrameCapture() { void RendererBackend::endFrameCapture() { #ifdef ENABLE_RENDERDOC_FRAME_CAPTURE if (g_rdoc_api) { - g_rdoc_api->EndFrameCapture(nullptr, nullptr); + RENDERDOC_DevicePointer devicePtr = RENDERDOC_DEVICEPOINTER_FROM_VKINSTANCE(instance->operator VkInstance_T*()); + g_rdoc_api->EndFrameCapture(devicePtr, nullptr); } #endif } @@ -525,10 +528,16 @@ void RendererBackend::initDevice() { // physicalDeviceProperties.limits.lineWidthRange; // physicalDeviceProperties.limits.lineWidthGranularity; } else { - mbgl::Log::Error(mbgl::Event::Render, "Wide line support not available"); + mbgl::Log::Error(mbgl::Event::Render, "Feature not available: wideLines"); } #endif + if (supportedDeviceFeatures.samplerAnisotropy) { + physicalDeviceFeatures.setSamplerAnisotropy(true); + } else { + mbgl::Log::Error(mbgl::Event::Render, "Feature not available: samplerAnisotropy"); + } + auto createInfo = vk::DeviceCreateInfo() .setQueueCreateInfos(queueCreateInfos) .setEnabledExtensionCount(static_cast(extensions.size())) @@ -612,6 +621,8 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar shaders::BuiltIn::ClippingMaskProgram, shaders::BuiltIn::CollisionBoxShader, shaders::BuiltIn::CollisionCircleShader, + shaders::BuiltIn::CommonShader, + shaders::BuiltIn::CommonTexturedShader, shaders::BuiltIn::CustomSymbolIconShader, shaders::BuiltIn::DebugShader, shaders::BuiltIn::FillShader, diff --git a/src/mbgl/vulkan/texture2d.cpp b/src/mbgl/vulkan/texture2d.cpp index bd7210645d6..86bcd8137b2 100644 --- a/src/mbgl/vulkan/texture2d.cpp +++ b/src/mbgl/vulkan/texture2d.cpp @@ -190,7 +190,11 @@ void Texture2D::uploadSubRegion(const void* pixelData, buffer->copyBufferToImage(bufferAllocation->buffer, imageAllocation->image, imageLayout, region); - transitionToShaderReadLayout(buffer); + if (samplerState.mipmapped && textureUsage == Texture2DUsage::ShaderInput) { + generateMips(buffer); + } else { + transitionToShaderReadLayout(buffer); + } }; enqueueCommands(commandBuffer); @@ -269,6 +273,10 @@ void Texture2D::createTexture() { imageUsage = vk::ImageUsageFlags() | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled; imageTiling = vk::ImageTiling::eOptimal; + + if (samplerState.mipmapped) { + imageUsage |= vk::ImageUsageFlagBits::eTransferSrc; + } break; case Texture2DUsage::Attachment: @@ -287,7 +295,7 @@ void Texture2D::createTexture() { .setImageType(vk::ImageType::e2D) .setFormat(format) .setExtent({size.width, size.height, 1}) - .setMipLevels(1) + .setMipLevels(getMipLevels()) .setArrayLayers(1) .setSamples(vk::SampleCountFlagBits::e1) .setTiling(imageTiling) @@ -331,7 +339,7 @@ void Texture2D::createTexture() { .setFormat(format) .setComponents(imageSwizzle) .setSubresourceRange( - vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)); + {vk::ImageAspectFlagBits::eColor, 0, imageCreateInfo.mipLevels, 0, 1}); imageAllocation->imageView = backend.getDevice()->createImageViewUnique(imageViewCreateInfo); } @@ -357,16 +365,22 @@ void Texture2D::createSampler() { const auto addressModeU = vulkanAddressMode(samplerState.wrapU); const auto addressModeV = vulkanAddressMode(samplerState.wrapV); - const auto samplerCreateInfo = vk::SamplerCreateInfo() - .setMinFilter(filter) - .setMagFilter(filter) - .setMipmapMode(vk::SamplerMipmapMode::eNearest) - .setMinLod(-VK_LOD_CLAMP_NONE) - .setMaxLod(VK_LOD_CLAMP_NONE) - .setAddressModeU(addressModeU) - .setAddressModeV(addressModeV) - .setAddressModeW(vk::SamplerAddressMode::eRepeat) - .setAnisotropyEnable(false); + auto samplerCreateInfo = vk::SamplerCreateInfo() + .setMinFilter(filter) + .setMagFilter(filter) + .setMinLod(-VK_LOD_CLAMP_NONE) + .setMaxLod(VK_LOD_CLAMP_NONE) + .setAddressModeU(addressModeU) + .setAddressModeV(addressModeV) + .setAddressModeW(vk::SamplerAddressMode::eRepeat); + + if (samplerState.mipmapped) { + samplerCreateInfo.setMipmapMode(vk::SamplerMipmapMode::eLinear); + } + + if (samplerState.maxAnisotropy != 1 && context.getBackend().getDeviceFeatures().samplerAnisotropy) { + samplerCreateInfo.setAnisotropyEnable(true).setMaxAnisotropy(samplerState.maxAnisotropy); + } sampler = context.getBackend().getDevice()->createSampler(samplerCreateInfo); @@ -400,8 +414,7 @@ void Texture2D::transitionToTransferLayout(const vk::UniqueCommandBuffer& buffer .setDstAccessMask(vk::AccessFlagBits::eTransferWrite) .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) - .setSubresourceRange( - vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)); + .setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, getMipLevels(), 0, 1}); buffer->pipelineBarrier( vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, nullptr, nullptr, barrier); @@ -418,8 +431,7 @@ void Texture2D::transitionToShaderReadLayout(const vk::UniqueCommandBuffer& buff .setDstAccessMask(vk::AccessFlagBits::eShaderRead) .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) - .setSubresourceRange( - vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)); + .setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}); buffer->pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, @@ -440,8 +452,7 @@ void Texture2D::transitionToGeneralLayout(const vk::UniqueCommandBuffer& buffer) .setDstAccessMask(vk::AccessFlagBits::eMemoryRead) .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) - .setSubresourceRange( - vk::ImageSubresourceRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1)); + .setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}); buffer->pipelineBarrier( vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, nullptr, nullptr, barrier); @@ -507,5 +518,88 @@ std::shared_ptr Texture2D::readImage() { return imageData; } +uint32_t Texture2D::getMipLevels() const { + if (samplerState.mipmapped && size.width > 0 && size.height > 0) { + return static_cast(std::floor(std::log2(std::max(size.width, size.height))) + 1); + } + + return 1; +} + +void Texture2D::generateMips(const vk::UniqueCommandBuffer& buffer) { + const uint32_t mipLevels = getMipLevels(); + + if (mipLevels <= 1) { + return; + } + + int32_t mipWidth = size.width; + int32_t mipHeight = size.height; + + auto barrier = vk::ImageMemoryBarrier() + .setImage(imageAllocation->image) + .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) + .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) + .setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}); + + for (uint32_t i = 1; i < mipLevels; ++i) { + barrier.subresourceRange.baseMipLevel = i - 1; + + // flip transfer direction + barrier.setOldLayout(vk::ImageLayout::eTransferDstOptimal) + .setNewLayout(vk::ImageLayout::eTransferSrcOptimal) + .setSrcAccessMask(vk::AccessFlagBits::eTransferWrite) + .setDstAccessMask(vk::AccessFlagBits::eTransferRead); + + buffer->pipelineBarrier( + vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, nullptr, nullptr, barrier); + + const auto blit = vk::ImageBlit() + .setSrcOffsets({vk::Offset3D{0, 0, 0}, {mipWidth, mipHeight, 1}}) + .setDstOffsets({vk::Offset3D{0, 0, 0}, {mipWidth / 2, mipHeight / 2, 1}}) + .setSrcSubresource({vk::ImageAspectFlagBits::eColor, i - 1, 0, 1}) + .setDstSubresource({vk::ImageAspectFlagBits::eColor, i, 0, 1}); + + buffer->blitImage(imageAllocation->image, + barrier.newLayout, + imageAllocation->image, + barrier.oldLayout, + blit, + vk::Filter::eLinear); + + barrier.setOldLayout(vk::ImageLayout::eTransferSrcOptimal) + .setNewLayout(vk::ImageLayout::eShaderReadOnlyOptimal) + .setSrcAccessMask(vk::AccessFlagBits::eTransferRead) + .setDstAccessMask(vk::AccessFlagBits::eShaderRead); + + buffer->pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eFragmentShader, + {}, + nullptr, + nullptr, + barrier); + + mipWidth = std::max(1, mipWidth / 2); + mipHeight = std::max(1, mipHeight / 2); + } + + // transition the last mip + barrier.subresourceRange.baseMipLevel = mipLevels - 1; + + barrier.setOldLayout(vk::ImageLayout::eTransferDstOptimal) + .setNewLayout(vk::ImageLayout::eShaderReadOnlyOptimal) + .setSrcAccessMask(vk::AccessFlagBits::eTransferRead) + .setDstAccessMask(vk::AccessFlagBits::eShaderRead); + + buffer->pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eFragmentShader, + {}, + nullptr, + nullptr, + barrier); + + imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal; +} + } // namespace vulkan } // namespace mbgl