From 0e95f660942758d33c418b4d34c705dedc98e555 Mon Sep 17 00:00:00 2001 From: Alex Cristici Date: Mon, 18 Sep 2023 19:49:31 +0300 Subject: [PATCH] Metal render target (#1484) Signed-off-by: dependabot[bot] Co-authored-by: Tim Sylvester Co-authored-by: mwilsnd Co-authored-by: Stefan Karschti Co-authored-by: Bart Louwers Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: mwilsnd <53413200+mwilsnd@users.noreply.github.com> Co-authored-by: Alex Cristici Co-authored-by: Bart Louwers Co-authored-by: Wei Chen Co-authored-by: Siarhei Fedartsou Co-authored-by: tdcosta100 Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- CMakeLists.txt | 29 ++-- bazel/core.bzl | 10 +- include/mbgl/gl/render_target_gl.hpp | 29 ---- include/mbgl/mtl/context.hpp | 18 --- include/mbgl/mtl/offscreen_texture.hpp | 23 +++ include/mbgl/mtl/texture2d.hpp | 7 + include/mbgl/renderer/render_target.hpp | 20 ++- include/mbgl/shaders/heatmap_layer_ubo.hpp | 41 +++++ .../shaders/heatmap_texture_layer_ubo.hpp | 19 +++ include/mbgl/shaders/mtl/heatmap.hpp | 145 ++++++++++++++++++ include/mbgl/shaders/mtl/heatmap_texture.hpp | 77 ++++++++++ src/mbgl/gfx/offscreen_texture.hpp | 7 + src/mbgl/gl/context.cpp | 8 +- src/mbgl/gl/context.hpp | 5 +- src/mbgl/gl/offscreen_texture.cpp | 30 ++++ src/mbgl/gl/offscreen_texture.hpp | 5 + src/mbgl/gl/render_target_gl.cpp | 85 ---------- src/mbgl/mtl/context.cpp | 10 +- src/mbgl/mtl/offscreen_texture.cpp | 95 ++++++++++++ src/mbgl/mtl/renderer_backend.cpp | 21 ++- src/mbgl/mtl/texture2d.cpp | 13 +- .../renderer/layers/heatmap_layer_tweaker.cpp | 64 ++++++-- .../renderer/layers/heatmap_layer_tweaker.hpp | 5 + .../layers/heatmap_texture_layer_tweaker.cpp | 17 +- .../renderer/layers/render_heatmap_layer.cpp | 69 ++++++--- .../renderer/layers/render_heatmap_layer.hpp | 22 ++- src/mbgl/renderer/render_target.cpp | 56 +++++++ 27 files changed, 707 insertions(+), 223 deletions(-) delete mode 100644 include/mbgl/gl/render_target_gl.hpp create mode 100644 include/mbgl/mtl/offscreen_texture.hpp create mode 100644 include/mbgl/shaders/heatmap_layer_ubo.hpp create mode 100644 include/mbgl/shaders/heatmap_texture_layer_ubo.hpp create mode 100644 include/mbgl/shaders/mtl/heatmap.hpp create mode 100644 include/mbgl/shaders/mtl/heatmap_texture.hpp delete mode 100644 src/mbgl/gl/render_target_gl.cpp create mode 100644 src/mbgl/mtl/offscreen_texture.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 00d201df9..58fb76e1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,7 +159,6 @@ if(MLN_DRAWABLE_RENDERER) ${PROJECT_SOURCE_DIR}/include/mbgl/gl/drawable_gl.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gl/drawable_gl_builder.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gl/layer_group_gl.hpp - ${PROJECT_SOURCE_DIR}/include/mbgl/gl/render_target_gl.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gl/uniform_block_gl.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gl/uniform_buffer_gl.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gl/vertex_attribute_gl.hpp @@ -180,7 +179,6 @@ if(MLN_DRAWABLE_RENDERER) ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/uniform_buffer.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gfx/vertex_attribute.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/render_target.cpp - ${PROJECT_SOURCE_DIR}/src/mbgl/gl/render_target_gl.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/change_request.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/layer_group.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/renderer/tile_layer_group.cpp @@ -1115,6 +1113,8 @@ if(MLN_WITH_OPENGL) ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/circle_layer_ubo.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/fill_layer_ubo.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/fill_extrusion_layer_ubo.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/heatmap_layer_ubo.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/heatmap_texture_layer_ubo.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/layer_ubo.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/line_layer_ubo.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/raster_layer_ubo.hpp @@ -1122,14 +1122,12 @@ if(MLN_WITH_OPENGL) ${PROJECT_SOURCE_DIR}/include/mbgl/gl/drawable_gl.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gl/drawable_gl_builder.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gl/layer_group_gl.hpp - ${PROJECT_SOURCE_DIR}/include/mbgl/gl/render_target_gl.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gl/uniform_block_gl.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gl/uniform_buffer_gl.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gl/vertex_attribute_gl.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gl/texture2d.hpp ) list(APPEND SRC_FILES - ${PROJECT_SOURCE_DIR}/src/mbgl/gl/render_target_gl.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/gl/shader_program_gl.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/drawable_gl.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/drawable_gl_builder.cpp @@ -1154,12 +1152,15 @@ if(MBGL_WITH_METAL) ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/buffer_resource.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/command_encoder.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/context.hpp - ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/layer_group.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/drawable.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/drawable_builder.hpp - ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/drawable_tweaker.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/index_buffer_resource.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/layer_group.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/mtl_fwd.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/offscreen_texture.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/render_pass.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/renderer_backend.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/renderable_resource.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/texture2d.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/tile_layer_group.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/uniform_block.hpp @@ -1167,14 +1168,21 @@ if(MBGL_WITH_METAL) ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/upload_pass.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/vertex_attribute.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/vertex_buffer_resource.hpp - ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/shader_program.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/background.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/background_pattern.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/circle.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/clipping_mask.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/common.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/fill.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/fill_extrusion.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/fill_extrusion_pattern.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/heatmap.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/heatmap_texture.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/line.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/line_gradient.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/raster.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/shader_group.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/shaders/mtl/shader_program.hpp ) list(APPEND SRC_FILES @@ -1182,18 +1190,21 @@ if(MBGL_WITH_METAL) ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/command_encoder.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/context.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/drawable.cpp - ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/drawable_impl.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/drawable_impl.hpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/drawable_builder.cpp - ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/drawable_tweaker.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/layer_group.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/mtl.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/offscreen_texture.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/renderer_backend.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/texture2d.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/render_pass.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/tile_layer_group.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/uniform_block.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/uniform_buffer.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/upload_pass.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/vertex_attribute.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/mtl/shader_program.cpp + ] ) endif() diff --git a/bazel/core.bzl b/bazel/core.bzl index 14975cdfe..2cdd1e9f4 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -964,6 +964,8 @@ MLN_DRAWABLES_HEADERS = [ "include/mbgl/shaders/circle_layer_ubo.hpp", "include/mbgl/shaders/fill_layer_ubo.hpp", "include/mbgl/shaders/fill_extrusion_layer_ubo.hpp", + "include/mbgl/shaders/heatmap_layer_ubo.hpp", + "include/mbgl/shaders/heatmap_texture_layer_ubo.hpp", "include/mbgl/shaders/layer_ubo.hpp", "include/mbgl/shaders/line_layer_ubo.hpp", "include/mbgl/shaders/raster_layer_ubo.hpp", @@ -976,7 +978,6 @@ MLN_DRAWABLES_GL_SOURCE = [ "src/mbgl/gl/drawable_gl_builder.cpp", "src/mbgl/gl/drawable_gl_impl.hpp", "src/mbgl/gl/layer_group_gl.cpp", - "src/mbgl/gl/render_target_gl.cpp", "src/mbgl/gl/texture2d.cpp", "src/mbgl/gl/uniform_block_gl.cpp", "src/mbgl/gl/uniform_buffer_gl.cpp", @@ -988,7 +989,6 @@ MLN_DRAWABLES_GL_HEADERS = [ "include/mbgl/gl/drawable_gl.hpp", "include/mbgl/gl/drawable_gl_builder.hpp", "include/mbgl/gl/layer_group_gl.hpp", - "include/mbgl/gl/render_target_gl.hpp", "include/mbgl/gl/uniform_block_gl.hpp", "include/mbgl/gl/uniform_buffer_gl.hpp", "include/mbgl/gl/vertex_attribute_gl.hpp", @@ -1006,6 +1006,7 @@ MLN_DRAWABLES_MTL_SOURCE = [ "src/mbgl/mtl/drawable_builder.cpp", "src/mbgl/mtl/layer_group.cpp", "src/mbgl/mtl/mtl.cpp", + "src/mbgl/mtl/offscreen_texture.cpp", "src/mbgl/mtl/renderer_backend.cpp", "src/mbgl/mtl/texture2d.cpp", "src/mbgl/mtl/render_pass.cpp", @@ -1026,6 +1027,7 @@ MLN_DRAWABLES_MTL_HEADERS = [ "include/mbgl/mtl/index_buffer_resource.hpp", "include/mbgl/mtl/layer_group.hpp", "include/mbgl/mtl/mtl_fwd.hpp", + "include/mbgl/mtl/offscreen_texture.hpp", "include/mbgl/mtl/render_pass.hpp", "include/mbgl/mtl/renderer_backend.hpp", "include/mbgl/mtl/renderable_resource.hpp", @@ -1041,10 +1043,12 @@ MLN_DRAWABLES_MTL_HEADERS = [ "include/mbgl/shaders/mtl/circle.hpp", "include/mbgl/shaders/mtl/clipping_mask.hpp", "include/mbgl/shaders/mtl/common.hpp", + "include/mbgl/shaders/mtl/fill.hpp", "include/mbgl/shaders/mtl/fill_extrusion.hpp", "include/mbgl/shaders/mtl/fill_extrusion_pattern.hpp", + "include/mbgl/shaders/mtl/heatmap.hpp", + "include/mbgl/shaders/mtl/heatmap_texture.hpp", "include/mbgl/shaders/mtl/line.hpp", - "include/mbgl/shaders/mtl/fill.hpp", "include/mbgl/shaders/mtl/line_gradient.hpp", "include/mbgl/shaders/mtl/raster.hpp", "include/mbgl/shaders/mtl/shader_group.hpp", diff --git a/include/mbgl/gl/render_target_gl.hpp b/include/mbgl/gl/render_target_gl.hpp deleted file mode 100644 index 0a3c2c0e7..000000000 --- a/include/mbgl/gl/render_target_gl.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace mbgl { -namespace gl { - -class Context; -using UniqueFramebufferPtr = std::shared_ptr; - -class RenderTargetGL final : public RenderTarget { -public: - RenderTargetGL(Context& context, const Size size, const gfx::TextureChannelDataType type); - ~RenderTargetGL() override; - - void upload(gfx::UploadPass& uploadPass) override; - void render(RenderOrchestrator&, const RenderTree&, PaintParameters&) override; - -private: - Context& glContext; - UniqueFramebufferPtr framebuffer; -}; - -} // namespace gl -} // namespace mbgl diff --git a/include/mbgl/mtl/context.hpp b/include/mbgl/mtl/context.hpp index b17de073b..7e47a7695 100644 --- a/include/mbgl/mtl/context.hpp +++ b/include/mbgl/mtl/context.hpp @@ -54,24 +54,6 @@ public: MTLTexturePtr createMetalTexture(MTLTextureDescriptorPtr textureDescriptor) const; MTLSamplerStatePtr createMetalSamplerState(MTLSamplerDescriptorPtr samplerDescriptor) const; - /* - Framebuffer createFramebuffer(const gfx::Renderbuffer&, - const gfx::Renderbuffer&); - Framebuffer createFramebuffer(const gfx::Renderbuffer&); - Framebuffer createFramebuffer(const gfx::Texture&, - const gfx::Renderbuffer&); - Framebuffer createFramebuffer(const gfx::Texture&); - Framebuffer createFramebuffer(const gfx::Texture&, const gfx::Renderbuffer&); - - template - Image readFramebuffer(const Size size, bool flip = true) { - static_assert(Image::channels == (format == gfx::TexturePixelType::RGBA ? 4 : 1), "image format mismatch"); - return {size, readFramebuffer(size, format, flip)}; - } -*/ - // Actually remove the objects we marked as abandoned with the above methods. void performCleanup() override {} diff --git a/include/mbgl/mtl/offscreen_texture.hpp b/include/mbgl/mtl/offscreen_texture.hpp new file mode 100644 index 000000000..c131838b9 --- /dev/null +++ b/include/mbgl/mtl/offscreen_texture.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +namespace mbgl { +namespace mtl { + +class Context; +class Texture2D; + +class OffscreenTexture final : public gfx::OffscreenTexture { +public: + OffscreenTexture(Context&, Size size, gfx::TextureChannelDataType type = gfx::TextureChannelDataType::UnsignedByte); + + bool isRenderable() override; + + PremultipliedImage readStillImage() override; + const gfx::Texture2DPtr& getTexture() override; +}; + +} // namespace mtl +} // namespace mbgl diff --git a/include/mbgl/mtl/texture2d.hpp b/include/mbgl/mtl/texture2d.hpp index ad85efc78..78d032e3a 100644 --- a/include/mbgl/mtl/texture2d.hpp +++ b/include/mbgl/mtl/texture2d.hpp @@ -6,6 +6,7 @@ #include #include +#include #include @@ -44,6 +45,11 @@ public: bool needsUpload() const noexcept override { return !!image; }; +public: + gfx::Texture2D& setUsage(MTL::TextureUsage usage_) noexcept; + + MTL::Texture* getMetalTexture() const noexcept; + void updateSamplerConfiguration() noexcept; /// @brief Bind this texture to the specified location @@ -67,6 +73,7 @@ private: Size size{0, 0}; gfx::TexturePixelType pixelFormat{gfx::TexturePixelType::RGBA}; gfx::TextureChannelDataType channelType{gfx::TextureChannelDataType::UnsignedByte}; + MTL::TextureUsage usage{MTL::TextureUsageShaderRead}; SamplerState samplerState{}; std::shared_ptr image{nullptr}; diff --git a/include/mbgl/renderer/render_target.hpp b/include/mbgl/renderer/render_target.hpp index 886758fcf..5375dfef3 100644 --- a/include/mbgl/renderer/render_target.hpp +++ b/include/mbgl/renderer/render_target.hpp @@ -1,5 +1,8 @@ #pragma once +#include +#include + #include #include #include @@ -8,7 +11,9 @@ namespace mbgl { namespace gfx { +class Context; class Texture2D; +class OffscreenTexture; class UploadPass; using Texture2DPtr = std::shared_ptr; } // namespace gfx @@ -23,13 +28,11 @@ using LayerGroupBasePtr = std::shared_ptr; /// Render target class class RenderTarget { public: - virtual ~RenderTarget() = default; - - /// Set the render target texture - void setTexture(const gfx::Texture2DPtr& texture_) { texture = std::move(texture_); }; + RenderTarget(gfx::Context& context, const Size size, const gfx::TextureChannelDataType type); + ~RenderTarget(); /// Get the render target texture - const gfx::Texture2DPtr& getTexture() const { return texture; }; + const gfx::Texture2DPtr& getTexture(); /// @brief Add a layer group to the render target /// @param replace Flag to replace if exists @@ -54,13 +57,14 @@ public: void visitLayerGroups(std::function) const; /// Upload the layer groups - virtual void upload(gfx::UploadPass& uploadPass) = 0; + void upload(gfx::UploadPass& uploadPass); /// Render the layer groups - virtual void render(RenderOrchestrator&, const RenderTree&, PaintParameters&) = 0; + void render(RenderOrchestrator&, const RenderTree&, PaintParameters&); protected: - gfx::Texture2DPtr texture; + gfx::Context& context; + std::unique_ptr offscreenTexture; using LayerGroupMap = std::map; LayerGroupMap layerGroupsByLayerIndex; }; diff --git a/include/mbgl/shaders/heatmap_layer_ubo.hpp b/include/mbgl/shaders/heatmap_layer_ubo.hpp new file mode 100644 index 000000000..534a9750a --- /dev/null +++ b/include/mbgl/shaders/heatmap_layer_ubo.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include + +namespace mbgl { +namespace shaders { + +struct alignas(16) HeatmapDrawableUBO { + std::array matrix; + float extrude_scale; + std::array padding; +}; +static_assert(sizeof(HeatmapDrawableUBO) % 16 == 0); + +struct alignas(16) HeatmapEvaluatedPropsUBO { + float weight; + float radius; + float intensity; + float padding; +}; +static_assert(sizeof(HeatmapEvaluatedPropsUBO) % 16 == 0); + +struct alignas(16) HeatmapInterpolateUBO { + float weight_t; + float radius_t; + std::array padding; +}; +static_assert(sizeof(HeatmapInterpolateUBO) % 16 == 0); + +struct alignas(16) HeatmapPermutationUBO { + /* 0 */ Attribute weight; + /* 8 */ Attribute radius; + /* 16 */ bool overdrawInspector; + /* 17 */ uint8_t pad1, pad2, pad3; + /* 20 */ float pad4, pad5, pad6; + /* 32 */ +}; +static_assert(sizeof(HeatmapPermutationUBO) == 2 * 16); + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/heatmap_texture_layer_ubo.hpp b/include/mbgl/shaders/heatmap_texture_layer_ubo.hpp new file mode 100644 index 000000000..278223c51 --- /dev/null +++ b/include/mbgl/shaders/heatmap_texture_layer_ubo.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace mbgl { +namespace shaders { + +struct alignas(16) HeatmapTextureDrawableUBO { + std::array matrix; + std::array world; + float opacity; + // overdrawInspector is used only in Metal, while in GL this is a 4 bytes empty padding. + bool overdrawInspector; + uint8_t pad1, pad2, pad3; +}; +static_assert(sizeof(HeatmapTextureDrawableUBO) % 16 == 0); + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/mtl/heatmap.hpp b/include/mbgl/shaders/mtl/heatmap.hpp new file mode 100644 index 000000000..9aef72564 --- /dev/null +++ b/include/mbgl/shaders/mtl/heatmap.hpp @@ -0,0 +1,145 @@ +#pragma once + +#include +#include +#include +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr auto name = "HeatmapShader"; + static constexpr auto vertexMainFunction = "vertexMain"; + static constexpr auto fragmentMainFunction = "fragmentMain"; + + static constexpr AttributeInfo attributes[] = { + {0, gfx::AttributeDataType::Short2, 1, "a_pos"}, + {1, gfx::AttributeDataType::Float2, 1, "a_weight"}, + {2, gfx::AttributeDataType::Float2, 1, "a_radius"}, + }; + static constexpr UniformBlockInfo uniforms[] = { + MLN_MTL_UNIFORM_BLOCK(3, true, false, HeatmapDrawableUBO), + MLN_MTL_UNIFORM_BLOCK(4, true, true, HeatmapEvaluatedPropsUBO), + MLN_MTL_UNIFORM_BLOCK(5, true, false, HeatmapInterpolateUBO), + MLN_MTL_UNIFORM_BLOCK(6, true, true, HeatmapPermutationUBO), + MLN_MTL_UNIFORM_BLOCK(7, true, false, ExpressionInputsUBO), + }; + static constexpr TextureInfo textures[] = {}; + + static constexpr auto source = R"( + +struct VertexStage { + short2 pos [[attribute(0)]]; + float2 weight [[attribute(1)]]; + float2 radius [[attribute(2)]]; +}; + +struct FragmentStage { + float4 position [[position, invariant]]; + float weight; + float2 extrude; +}; + +struct alignas(16) HeatmapDrawableUBO { + float4x4 matrix; + float extrude_scale; + float pad1; + float2 pad2; +}; + +struct alignas(16) HeatmapEvaluatedPropsUBO { + float weight; + float radius; + float intensity; + float pad1; +}; + +struct alignas(16) HeatmapInterpolateUBO { + float weight_t; + float radius_t; + float2 pad1; +}; + +struct alignas(16) HeatmapPermutationUBO { + Attribute weight; + Attribute radius; + bool overdrawInspector; + uint8_t pad1, pad2, pad3; + float pad4, pad5, pad6; +}; + +// Effective "0" in the kernel density texture to adjust the kernel size to; +// this empirically chosen number minimizes artifacts on overlapping kernels +// for typical heatmap cases (assuming clustered source) +constant const float ZERO = 1.0 / 255.0 / 16.0; + +// Gaussian kernel coefficient: 1 / sqrt(2 * PI) +#define GAUSS_COEF 0.3989422804014327 + +FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], + device const HeatmapDrawableUBO& drawable [[buffer(3)]], + device const HeatmapEvaluatedPropsUBO& props [[buffer(4)]], + device const HeatmapInterpolateUBO& interp [[buffer(5)]], + device const HeatmapPermutationUBO& permutation [[buffer(6)]], + device const ExpressionInputsUBO& expr [[buffer(7)]]) { + + const auto weight = valueFor(permutation.weight, props.weight, vertx.weight, interp.weight_t, expr); + const auto radius = valueFor(permutation.radius, props.radius, vertx.radius, interp.radius_t, expr); + + // unencode the extrusion vector that we snuck into the a_pos vector + float2 unscaled_extrude = float2(glMod(float2(vertx.pos), 2.0) * 2.0 - 1.0); + + // This 'extrude' comes in ranging from [-1, -1], to [1, 1]. We'll use + // it to produce the vertices of a square mesh framing the point feature + // we're adding to the kernel density texture. We'll also pass it as + // a varying, so that the fragment shader can determine the distance of + // each fragment from the point feature. + // Before we do so, we need to scale it up sufficiently so that the + // kernel falls effectively to zero at the edge of the mesh. + // That is, we want to know S such that + // weight * u_intensity * GAUSS_COEF * exp(-0.5 * 3.0^2 * S^2) == ZERO + // Which solves to: + // S = sqrt(-2.0 * log(ZERO / (weight * u_intensity * GAUSS_COEF))) / 3.0 + float S = sqrt(-2.0 * log(ZERO / weight / props.intensity / GAUSS_COEF)) / 3.0; + + // Pass the varying in units of radius + float2 extrude = S * unscaled_extrude; + + // Scale by radius and the zoom-based scale factor to produce actual + // mesh position + float2 scaled_extrude = extrude * radius * drawable.extrude_scale; + + // multiply a_pos by 0.5, since we had it * 2 in order to sneak + // in extrusion data + float4 pos = float4(floor(float2(vertx.pos) * 0.5) + scaled_extrude, 0, 1); + + float4 position = drawable.matrix * pos; + + return { + .position = position, + .weight = weight, + .extrude = extrude, + }; +} + +half4 fragment fragmentMain(FragmentStage in [[stage_in]], + device const HeatmapEvaluatedPropsUBO& props [[buffer(4)]], + device const HeatmapPermutationUBO& permutation [[buffer(6)]]) { + + if (permutation.overdrawInspector) { + return half4(1.0); + } + + // Kernel density estimation with a Gaussian kernel of size 5x5 + float d = -0.5 * 3.0 * 3.0 * dot(in.extrude, in.extrude); + float val = in.weight * props.intensity * GAUSS_COEF * exp(d); + + return half4(val, 1.0, 1.0, 1.0); +} +)"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/include/mbgl/shaders/mtl/heatmap_texture.hpp b/include/mbgl/shaders/mtl/heatmap_texture.hpp new file mode 100644 index 000000000..3c4873f8f --- /dev/null +++ b/include/mbgl/shaders/mtl/heatmap_texture.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include +#include +#include +#include + +namespace mbgl { +namespace shaders { + +template <> +struct ShaderSource { + static constexpr auto name = "HeatmapTextureShader"; + static constexpr auto vertexMainFunction = "vertexMain"; + static constexpr auto fragmentMainFunction = "fragmentMain"; + + static constexpr AttributeInfo attributes[] = { + {0, gfx::AttributeDataType::Short2, 1, "a_pos"}, + }; + static constexpr UniformBlockInfo uniforms[] = { + MLN_MTL_UNIFORM_BLOCK(1, true, true, HeatmapTextureDrawableUBO), + }; + static constexpr TextureInfo textures[] = { + {0, "u_image"}, + {1, "u_color_ramp"}, + }; + static constexpr auto source = R"( + +struct VertexStage { + short2 pos [[attribute(0)]]; +}; + +struct FragmentStage { + float4 position [[position, invariant]]; + float2 pos; +}; + +struct alignas(16) HeatmapTextureDrawableUBO { + float4x4 matrix; + float2 world; + float opacity; + bool overdrawInspector; + uint8_t pad1, pad2, pad3; +}; + +FragmentStage vertex vertexMain(thread const VertexStage vertx [[stage_in]], + device const HeatmapTextureDrawableUBO& drawable [[buffer(1)]]) { + + const float2 pos = float2(vertx.pos); + const float4 position = drawable.matrix * float4(pos * drawable.world, 0, 1); + + return { + .position = position, + .pos = pos, + }; +} + +half4 fragment fragmentMain(FragmentStage in [[stage_in]], + device const HeatmapTextureDrawableUBO& drawable [[buffer(1)]], + texture2d image [[texture(0)]], + texture2d color_ramp [[texture(1)]], + sampler image_sampler [[sampler(0)]], + sampler color_ramp_sampler [[sampler(1)]]) { + + if (drawable.overdrawInspector) { + return half4(0.0); + } + + float t = image.sample(image_sampler, in.pos).r; + float4 color = color_ramp.sample(color_ramp_sampler, float2(t, 0.5)); + return half4(color * drawable.opacity); +} +)"; +}; + +} // namespace shaders +} // namespace mbgl diff --git a/src/mbgl/gfx/offscreen_texture.hpp b/src/mbgl/gfx/offscreen_texture.hpp index 7e83a5111..cfe1bc6a7 100644 --- a/src/mbgl/gfx/offscreen_texture.hpp +++ b/src/mbgl/gfx/offscreen_texture.hpp @@ -7,6 +7,8 @@ namespace mbgl { namespace gfx { class Texture; +class Texture2D; +using Texture2DPtr = std::shared_ptr; class OffscreenTexture : public gfx::Renderable { protected: @@ -19,7 +21,12 @@ public: virtual bool isRenderable() = 0; virtual PremultipliedImage readStillImage() = 0; + +#if MLN_LEGACY_RENDERER virtual gfx::Texture& getTexture() = 0; +#else + virtual const gfx::Texture2DPtr& getTexture() = 0; +#endif }; } // namespace gfx diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index ede26f86d..82cef14a2 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -20,9 +20,9 @@ #include #include #include -#include #include #include +#include #include #endif @@ -510,10 +510,10 @@ gfx::Texture2DPtr Context::createTexture2D() { } RenderTargetPtr Context::createRenderTarget(const Size size, const gfx::TextureChannelDataType type) { - return std::make_shared(*this, size, type); + return std::make_shared(*this, size, type); } -UniqueFramebuffer Context::createFramebuffer(const gfx::Texture2D& color) { +Framebuffer Context::createFramebuffer(const gfx::Texture2D& color) { auto fbo = createFramebuffer(); bindFramebuffer = fbo; MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, @@ -522,7 +522,7 @@ UniqueFramebuffer Context::createFramebuffer(const gfx::Texture2D& color) { static_cast(color).getTextureID(), 0)); checkFramebuffer(); - return fbo; + return {color.getSize(), std::move(fbo)}; } #endif diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 87888a60f..a8f030d4c 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -118,7 +118,7 @@ public: RenderTargetPtr createRenderTarget(const Size size, const gfx::TextureChannelDataType type) override; - UniqueFramebuffer createFramebuffer(const gfx::Texture2D& color); + Framebuffer createFramebuffer(const gfx::Texture2D& color); void resetState(gfx::DepthMode depthMode, gfx::ColorMode colorMode) override; @@ -172,9 +172,8 @@ private: State cullFaceSide; State cullFaceWinding; - std::unique_ptr createOffscreenTexture(Size, gfx::TextureChannelDataType) override; - public: + std::unique_ptr createOffscreenTexture(Size, gfx::TextureChannelDataType) override; std::unique_ptr createTextureResource(Size, gfx::TexturePixelType, gfx::TextureChannelDataType) override; diff --git a/src/mbgl/gl/offscreen_texture.cpp b/src/mbgl/gl/offscreen_texture.cpp index 0382eac6c..40e816317 100644 --- a/src/mbgl/gl/offscreen_texture.cpp +++ b/src/mbgl/gl/offscreen_texture.cpp @@ -13,15 +13,28 @@ public: size(size_), type(type_) { assert(!size.isEmpty()); +#if MLN_DRAWABLE_RENDERER + texture = context.createTexture2D(); + texture->setSize(size); + texture->setFormat(gfx::TexturePixelType::RGBA, type); + texture->setSamplerConfiguration( + {gfx::TextureFilterType::Nearest, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp}); +#endif } ~OffscreenTextureResource() noexcept override = default; void bind() override { if (!framebuffer) { +#if MLN_LEGACY_RENDERER assert(!texture); texture = context.createTexture(size, gfx::TexturePixelType::RGBA, type); framebuffer = context.createFramebuffer(*texture); +#else + assert(texture); + texture->create(); + framebuffer = context.createFramebuffer(*texture); +#endif } else { context.bindFramebuffer = framebuffer->framebuffer; } @@ -37,15 +50,26 @@ public: return context.readFramebuffer(size); } +#if MLN_LEGACY_RENDERER gfx::Texture& getTexture() { assert(texture); return *texture; } +#else + gfx::Texture2DPtr& getTexture() { + assert(texture); + return texture; + } +#endif private: gl::Context& context; const Size size; +#if MLN_LEGACY_RENDERER std::optional texture; +#else + gfx::Texture2DPtr texture; +#endif const gfx::TextureChannelDataType type; std::optional framebuffer; }; @@ -66,9 +90,15 @@ PremultipliedImage OffscreenTexture::readStillImage() { return getResource().readStillImage(); } +#if MLN_LEGACY_RENDERER gfx::Texture& OffscreenTexture::getTexture() { return getResource().getTexture(); } +#else +const gfx::Texture2DPtr& OffscreenTexture::getTexture() { + return getResource().getTexture(); +} +#endif } // namespace gl } // namespace mbgl diff --git a/src/mbgl/gl/offscreen_texture.hpp b/src/mbgl/gl/offscreen_texture.hpp index 5f3863d3e..da2f544fd 100644 --- a/src/mbgl/gl/offscreen_texture.hpp +++ b/src/mbgl/gl/offscreen_texture.hpp @@ -17,7 +17,12 @@ public: bool isRenderable() override; PremultipliedImage readStillImage() override; + +#if MLN_LEGACY_RENDERER gfx::Texture& getTexture() override; +#else + const gfx::Texture2DPtr& getTexture() override; +#endif }; } // namespace gl diff --git a/src/mbgl/gl/render_target_gl.cpp b/src/mbgl/gl/render_target_gl.cpp deleted file mode 100644 index 03621b5bd..000000000 --- a/src/mbgl/gl/render_target_gl.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace mbgl { -namespace gl { - -using namespace platform; - -RenderTargetGL::RenderTargetGL(Context& context, const Size size, const gfx::TextureChannelDataType type) - : glContext(context) { - texture = glContext.createTexture2D(); - texture->setSize(size); - texture->setFormat(gfx::TexturePixelType::RGBA, type); - texture->setSamplerConfiguration( - {gfx::TextureFilterType::Linear, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp}); -} - -RenderTargetGL::~RenderTargetGL() { - if (framebuffer) { - MBGL_CHECK_ERROR(glDeleteFramebuffers(1, &framebuffer->get())); - framebuffer.reset(); - } -} - -void RenderTargetGL::upload(gfx::UploadPass& uploadPass) { - visitLayerGroups(([&](LayerGroupBase& layerGroup) { layerGroup.upload(uploadPass); })); -} - -void RenderTargetGL::render(RenderOrchestrator& orchestrator, - const RenderTree& renderTree, - PaintParameters& parameters) { - texture->create(); - if (!framebuffer) { - framebuffer = std::make_shared(glContext.createFramebuffer(*texture)); - } - - glContext.bindFramebuffer = *framebuffer; - glContext.activeTextureUnit = 0; - glContext.scissorTest = false; - glContext.viewport = {0, 0, texture->getSize()}; - glContext.clear(Color{0.0f, 0.0f, 0.0f, 1.0f}, {}, {}); - - // Run layer tweakers to update any dynamic elements - visitLayerGroups([&](LayerGroupBase& layerGroup) { - if (layerGroup.getLayerTweaker()) { - layerGroup.getLayerTweaker()->execute(layerGroup, renderTree, parameters); - } - }); - - // draw layer groups, opaque pass - parameters.pass = RenderPass::Opaque; - parameters.currentLayer = 0; - parameters.depthRangeSize = 1 - (numLayerGroups() + 2) * parameters.numSublayers * PaintParameters::depthEpsilon; - - visitLayerGroups([&](LayerGroupBase& layerGroup) { - layerGroup.render(orchestrator, parameters); - parameters.currentLayer++; - }); - - // draw layer groups, translucent pass - parameters.pass = RenderPass::Translucent; - parameters.currentLayer = static_cast(numLayerGroups()) - 1; - parameters.depthRangeSize = 1 - (numLayerGroups() + 2) * parameters.numSublayers * PaintParameters::depthEpsilon; - - visitLayerGroups([&](LayerGroupBase& layerGroup) { - layerGroup.render(orchestrator, parameters); - if (parameters.currentLayer != 0) { - parameters.currentLayer--; - } - }); -} - -} // namespace gl -} // namespace mbgl diff --git a/src/mbgl/mtl/context.cpp b/src/mbgl/mtl/context.cpp index 6dc67aac1..b92adf543 100644 --- a/src/mbgl/mtl/context.cpp +++ b/src/mbgl/mtl/context.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -170,8 +172,7 @@ gfx::Texture2DPtr Context::createTexture2D() { } RenderTargetPtr Context::createRenderTarget(const Size size, const gfx::TextureChannelDataType type) { - assert(false); - return nullptr; + return std::make_shared(*this, size, type); } void Context::resetState(gfx::DepthMode depthMode, gfx::ColorMode colorMode) {} @@ -188,9 +189,8 @@ bool Context::emplaceOrUpdateUniformBuffer(gfx::UniformBufferPtr& buffer, const void Context::setDirtyState() {} -std::unique_ptr Context::createOffscreenTexture(Size, gfx::TextureChannelDataType) { - assert(false); - return nullptr; +std::unique_ptr Context::createOffscreenTexture(Size size, gfx::TextureChannelDataType type) { + return std::make_unique(*this, size, type); } std::unique_ptr Context::createTextureResource(Size, diff --git a/src/mbgl/mtl/offscreen_texture.cpp b/src/mbgl/mtl/offscreen_texture.cpp new file mode 100644 index 000000000..11895f807 --- /dev/null +++ b/src/mbgl/mtl/offscreen_texture.cpp @@ -0,0 +1,95 @@ +#include +#include +#include +#include +#include + +#include + +namespace mbgl { +namespace mtl { + +class OffscreenTextureResource final : public RenderableResource { +public: + OffscreenTextureResource(Context& context_, const Size size_, const gfx::TextureChannelDataType type_) + : context(context_), + size(size_), + type(type_) { + assert(!size.isEmpty()); + texture = context.createTexture2D(); + texture->setSize(size); + texture->setFormat(gfx::TexturePixelType::RGBA, type); + texture->setSamplerConfiguration( + {gfx::TextureFilterType::Nearest, gfx::TextureWrapType::Clamp, gfx::TextureWrapType::Clamp}); + static_cast(texture.get()) + ->setUsage(MTL::TextureUsageShaderRead | MTL::TextureUsageShaderWrite | MTL::TextureUsageRenderTarget); + } + + ~OffscreenTextureResource() noexcept override = default; + + void bind() override { + assert(context.getBackend().getCommandQueue()); + commandBuffer = NS::RetainPtr(context.getBackend().getCommandQueue()->commandBuffer()); + texture->create(); + } + + void swap() override { + assert(commandBuffer); + commandBuffer->commit(); + commandBuffer->waitUntilCompleted(); + commandBuffer.reset(); + } + + PremultipliedImage readStillImage() { + assert(false); + return PremultipliedImage(); + } + + gfx::Texture2DPtr& getTexture() { + assert(texture); + return texture; + } + + const RendererBackend& getBackend() const override { return context.getBackend(); } + + const MTLCommandBufferPtr& getCommandBuffer() const override { return commandBuffer; } + + MTLBlitPassDescriptorPtr getUploadPassDescriptor() const override { + assert(false); + return NS::TransferPtr(MTL::BlitPassDescriptor::alloc()->init()); + } + + MTLRenderPassDescriptorPtr getRenderPassDescriptor() const override { + auto renderPassDescriptor = NS::TransferPtr(MTL::RenderPassDescriptor::alloc()->init()); + if (auto* colorTarget = renderPassDescriptor->colorAttachments()->object(0)) { + colorTarget->setTexture(static_cast(texture.get())->getMetalTexture()); + } + return renderPassDescriptor; + } + +private: + Context& context; + const Size size; + const gfx::TextureChannelDataType type; + gfx::Texture2DPtr texture; + MTLCommandBufferPtr commandBuffer; +}; + +OffscreenTexture::OffscreenTexture(Context& context, const Size size_, const gfx::TextureChannelDataType type) + : gfx::OffscreenTexture(size, std::make_unique(context, size_, type)) {} + +bool OffscreenTexture::isRenderable() { + assert(false); + return true; +} + +PremultipliedImage OffscreenTexture::readStillImage() { + return getResource().readStillImage(); +} + +const gfx::Texture2DPtr& OffscreenTexture::getTexture() { + return getResource().getTexture(); +} + +} // namespace mtl +} // namespace mbgl diff --git a/src/mbgl/mtl/renderer_backend.cpp b/src/mbgl/mtl/renderer_backend.cpp index b8d448966..ffb444954 100644 --- a/src/mbgl/mtl/renderer_backend.cpp +++ b/src/mbgl/mtl/renderer_backend.cpp @@ -15,11 +15,13 @@ #include #include #include +#include #include #include +#include +#include #include #include -#include #include #include @@ -116,24 +118,21 @@ void RendererBackend::initShaders(gfx::ShaderRegistry& shaders, const ProgramPar shaders::BuiltIn::BackgroundPatternShader, shaders::BuiltIn::CircleShader, shaders::BuiltIn::ClippingMaskProgram, - shaders::BuiltIn::LineShader, - shaders::BuiltIn::LineGradientShader, - shaders::BuiltIn::RasterShader, shaders::BuiltIn::FillShader, shaders::BuiltIn::FillOutlineShader, shaders::BuiltIn::FillOutlinePatternShader, - shaders::BuiltIn::FillPatternShader/*, - shaders::BuiltIn::LineSDFShader, - shaders::BuiltIn::LinePatternShader, - shaders::BuiltIn::LineGradientShader, + shaders::BuiltIn::FillPatternShader, shaders::BuiltIn::FillExtrusionShader, shaders::BuiltIn::FillExtrusionPatternShader, shaders::BuiltIn::HeatmapShader, shaders::BuiltIn::HeatmapTextureShader, + shaders::BuiltIn::LineShader, + shaders::BuiltIn::LineGradientShader, + shaders::BuiltIn::RasterShader/*, + shaders::BuiltIn::LineSDFShader, + shaders::BuiltIn::LinePatternShader, shaders::BuiltIn::HillshadePrepareShader, - shaders::BuiltIn::HillshadeShader*/, - shaders::BuiltIn::FillExtrusionShader, - shaders::BuiltIn::FillExtrusionPatternShader/*, + shaders::BuiltIn::HillshadeShader, shaders::BuiltIn::SymbolIconShader, shaders::BuiltIn::SymbolSDFTextShader, shaders::BuiltIn::SymbolSDFIconShader, diff --git a/src/mbgl/mtl/texture2d.cpp b/src/mbgl/mtl/texture2d.cpp index 19239019f..fe0e541d2 100644 --- a/src/mbgl/mtl/texture2d.cpp +++ b/src/mbgl/mtl/texture2d.cpp @@ -6,7 +6,6 @@ #include #include #include -#include namespace mbgl { namespace mtl { @@ -113,6 +112,7 @@ void Texture2D::createMetalTexture() noexcept { // Create a new texture object if (auto textureDescriptor = NS::RetainPtr( MTL::TextureDescriptor::texture2DDescriptor(format, size.width, size.height, /*mipmapped=*/false))) { + textureDescriptor->setUsage(usage); metalTexture = context.createMetalTexture(std::move(textureDescriptor)); } @@ -131,6 +131,17 @@ void Texture2D::create() noexcept { } } +gfx::Texture2D& Texture2D::setUsage(MTL::TextureUsage usage_) noexcept { + usage = usage_; + textureDirty = true; + return *this; +} + +MTL::Texture* Texture2D::getMetalTexture() const noexcept { + assert(metalTexture); + return metalTexture.get(); +} + void Texture2D::updateSamplerConfiguration() noexcept { auto samplerDescriptor = NS::RetainPtr(MTL::SamplerDescriptor::alloc()->init()); samplerDescriptor->setMinFilter(samplerState.filter == gfx::TextureFilterType::Nearest diff --git a/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp b/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp index b70109eae..4fa4f5699 100644 --- a/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/heatmap_layer_tweaker.cpp @@ -6,31 +6,24 @@ #include #include #include +#include #include #include #include +#if MLN_RENDER_BACKEND_METAL +#include +#endif + namespace mbgl { using namespace style; - -struct alignas(16) HeatmapDrawableUBO { - std::array matrix; - float extrude_scale; - std::array padding; -}; -static_assert(sizeof(HeatmapDrawableUBO) % 16 == 0); - -struct alignas(16) HeatmapEvaluatedPropsUBO { - float weight; - float radius; - float intensity; - float padding; -}; -static_assert(sizeof(HeatmapEvaluatedPropsUBO) % 16 == 0); +using namespace shaders; static const StringIdentity idHeatmapDrawableUBOName = StringIndexer::get("HeatmapDrawableUBO"); static const StringIdentity idHeatmapEvaluatedPropsUBOName = StringIndexer::get("HeatmapEvaluatedPropsUBO"); +static const StringIdentity idHeatmapPermutationUBOName = StringIndexer::get("HeatmapPermutationUBO"); +static const StringIdentity idExpressionInputsUBOName = StringIndexer::get("ExpressionInputsUBO"); void HeatmapLayerTweaker::execute(LayerGroupBase& layerGroup, const RenderTree& renderTree, @@ -47,6 +40,40 @@ void HeatmapLayerTweaker::execute(LayerGroupBase& layerGroup, const auto debugGroup = parameters.encoder->createDebugGroup(label.c_str()); #endif + const auto zoom = parameters.state.getZoom(); + +#if MLN_RENDER_BACKEND_METAL + using ShaderClass = shaders::ShaderSource; + if (propertiesChanged) { + const auto source = [this](const std::string_view& attrName) { + return hasPropertyAsUniform(attrName) ? AttributeSource::Constant : AttributeSource::PerVertex; + }; + + const HeatmapPermutationUBO permutationUBO = { + /* .weight = */ {/*.source=*/source(ShaderClass::attributes[1].name), /*.expression=*/{}}, + /* .radius = */ {/*.source=*/source(ShaderClass::attributes[2].name), /*.expression=*/{}}, + /* .overdrawInspector = */ overdrawInspector, + /* .pad1/2/3 = */ 0, + 0, + 0, + /* .pad4/5/6 = */ 0, + 0, + 0}; + + if (permutationUniformBuffer) { + permutationUniformBuffer->update(&permutationUBO, sizeof(permutationUBO)); + } else { + permutationUniformBuffer = context.createUniformBuffer(&permutationUBO, sizeof(permutationUBO)); + } + + propertiesChanged = false; + } + if (!expressionUniformBuffer) { + const auto expressionUBO = buildExpressionUBO(zoom, parameters.frameCount); + expressionUniformBuffer = context.createUniformBuffer(&expressionUBO, sizeof(expressionUBO)); + } +#endif + if (!evaluatedPropsUniformBuffer) { const HeatmapEvaluatedPropsUBO evaluatedPropsUBO = { /* .weight = */ evaluated.get().constantOr(HeatmapWeight::defaultValue()), @@ -76,10 +103,15 @@ void HeatmapLayerTweaker::execute(LayerGroupBase& layerGroup, inViewportPixelUnits); const HeatmapDrawableUBO drawableUBO = { /* .matrix = */ util::cast(matrix), - /* .extrude_scale = */ tileID.pixelsToTileUnits(1.0f, static_cast(parameters.state.getZoom())), + /* .extrude_scale = */ tileID.pixelsToTileUnits(1.0f, static_cast(zoom)), /* .padding = */ {0}}; uniforms.createOrUpdate(idHeatmapDrawableUBOName, &drawableUBO, context); + +#if MLN_RENDER_BACKEND_METAL + uniforms.addOrReplace(idHeatmapPermutationUBOName, permutationUniformBuffer); + uniforms.addOrReplace(idExpressionInputsUBOName, expressionUniformBuffer); +#endif // MLN_RENDER_BACKEND_METAL }); } diff --git a/src/mbgl/renderer/layers/heatmap_layer_tweaker.hpp b/src/mbgl/renderer/layers/heatmap_layer_tweaker.hpp index 7a2f0368d..5a1859f71 100644 --- a/src/mbgl/renderer/layers/heatmap_layer_tweaker.hpp +++ b/src/mbgl/renderer/layers/heatmap_layer_tweaker.hpp @@ -19,6 +19,11 @@ public: protected: gfx::UniformBufferPtr evaluatedPropsUniformBuffer; + +#if MLN_RENDER_BACKEND_METAL + gfx::UniformBufferPtr permutationUniformBuffer; + gfx::UniformBufferPtr expressionUniformBuffer; +#endif // MLN_RENDER_BACKEND_METAL }; } // namespace mbgl diff --git a/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.cpp b/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.cpp index c12e1e5eb..2331c6846 100644 --- a/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.cpp +++ b/src/mbgl/renderer/layers/heatmap_texture_layer_tweaker.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -13,14 +14,7 @@ namespace mbgl { using namespace style; - -struct alignas(16) HeatmapTextureDrawableUBO { - std::array matrix; - std::array world; - float opacity; - float padding; -}; -static_assert(sizeof(HeatmapTextureDrawableUBO) % 16 == 0); +using namespace shaders; static const StringIdentity idHeatmapTextureDrawableUBOName = StringIndexer::get("HeatmapTextureDrawableUBO"); @@ -41,12 +35,15 @@ void HeatmapTextureLayerTweaker::execute(LayerGroupBase& layerGroup, layerGroup.visitDrawables([&](gfx::Drawable& drawable) { const auto& size = parameters.staticData.backendSize; mat4 viewportMat; - matrix::ortho(viewportMat, 0, size.width, size.height, 0, 0, 1); + matrix::ortho(viewportMat, 0, size.width, size.height, 0, -1, 1); const HeatmapTextureDrawableUBO drawableUBO = { /* .matrix = */ util::cast(viewportMat), /* .world = */ {static_cast(size.width), static_cast(size.height)}, /* .opacity = */ evaluated.get(), - /* .padding = */ 0}; + /* .overdrawInspector = */ overdrawInspector, + /* .pad1 = */ 0, + /* .pad2 = */ 0, + /* .pad3 = */ 0}; drawable.mutableUniformBuffers().createOrUpdate( idHeatmapTextureDrawableUBOName, &drawableUBO, parameters.context); diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp index bc37572ae..e980da01e 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -68,13 +70,8 @@ void RenderHeatmapLayer::evaluate(const PropertyEvaluationParameters& parameters evaluatedProperties = std::move(properties); #if MLN_DRAWABLE_RENDERER - if (renderTarget) { - renderTarget->getLayerGroup(0)->setLayerTweaker( - std::make_shared(getID(), evaluatedProperties)); - } - if (layerGroup) { - layerGroup->setLayerTweaker(std::make_shared(getID(), evaluatedProperties)); - } + updateLayerTweaker(); + updateLayerTextureTweaker(); #endif } @@ -86,13 +83,13 @@ bool RenderHeatmapLayer::hasCrossfade() const { return false; } +#if MLN_LEGACY_RENDERER void RenderHeatmapLayer::upload(gfx::UploadPass& uploadPass) { if (!colorRampTexture) { colorRampTexture = uploadPass.createTexture(*colorRamp, gfx::TextureChannelDataType::UnsignedByte); } } -#if MLN_LEGACY_RENDERER void RenderHeatmapLayer::render(PaintParameters& parameters) { assert(renderTiles); if (parameters.pass == RenderPass::Opaque) { @@ -265,13 +262,6 @@ void RenderHeatmapLayer::removeAllDrawables() { namespace { -struct alignas(16) HeatmapInterpolateUBO { - float weight_t; - float radius_t; - std::array padding; -}; -static_assert(sizeof(HeatmapInterpolateUBO) % 16 == 0); - constexpr auto HeatmapShaderGroupName = "HeatmapShader"; constexpr auto HeatmapTextureShaderGroupName = "HeatmapTextureShader"; static const StringIdentity idHeatmapInterpolateUBOName = StringIndexer::get("HeatmapInterpolateUBO"); @@ -281,10 +271,33 @@ static const StringIdentity idTexColorRampName = StringIndexer::get("u_color_ram } // namespace +using namespace shaders; + +#if MLN_DRAWABLE_RENDERER +void RenderHeatmapLayer::updateLayerTweaker() { + if (renderTarget) { + tweaker = std::make_shared(getID(), evaluatedProperties); +#if MLN_RENDER_BACKEND_METAL + tweaker->setPropertiesAsUniforms(propertiesAsUniforms); +#endif // MLN_RENDER_BACKEND_METAL + tweaker->enableOverdrawInspector(overdrawInspector); + renderTarget->getLayerGroup(0)->setLayerTweaker(tweaker); + } +} + +void RenderHeatmapLayer::updateLayerTextureTweaker() { + if (layerGroup) { + textureTweaker = std::make_shared(getID(), evaluatedProperties); + textureTweaker->enableOverdrawInspector(overdrawInspector); + layerGroup->setLayerTweaker(textureTweaker); + } +} +#endif // MLN_DRAWABLE_RENDERER + void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, gfx::Context& context, const TransformState& state, - const std::shared_ptr&, + const std::shared_ptr& updateParameters, [[maybe_unused]] const RenderTree& renderTree, UniqueChangeRequestVec& changes) { std::unique_lock guard(mutex); @@ -310,8 +323,8 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, if (!tileLayerGroup) { return; } - tileLayerGroup->setLayerTweaker(std::make_shared(getID(), evaluatedProperties)); renderTarget->addLayerGroup(tileLayerGroup, /*replace=*/true); + updateLayerTweaker(); } if (renderTarget->getTexture()->getSize() != size) { @@ -328,6 +341,15 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, return; } + const bool overdraw = !!(updateParameters->debugOptions & MapDebugOptions::Overdraw); + if (overdrawInspector != overdraw) { + overdrawInspector = overdraw; + if (tweaker) { + tweaker->enableOverdrawInspector(overdrawInspector); + textureTweaker->enableOverdrawInspector(overdrawInspector); + } + } + std::unique_ptr heatmapBuilder; constexpr auto renderPass = RenderPass::Translucent; @@ -376,18 +398,25 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, gfx::VertexAttributeArray heatmapVertexAttrs; - const auto propertiesAsUniforms = + const auto propertiesAsUniforms_ = heatmapVertexAttrs.readDataDrivenPaintProperties(paintPropertyBinders, evaluated); if (!heatmapShaderGroup) { continue; } - const auto heatmapShader = heatmapShaderGroup->getOrCreateShader(context, propertiesAsUniforms); + const auto heatmapShader = heatmapShaderGroup->getOrCreateShader(context, propertiesAsUniforms_); if (!heatmapShader) { continue; } +#if MLN_RENDER_BACKEND_METAL + propertiesAsUniforms = std::move(propertiesAsUniforms_); + if (tweaker) { + tweaker->setPropertiesAsUniforms(propertiesAsUniforms); + } +#endif // MLN_RENDER_BACKEND_METAL + if (const auto& attr = heatmapVertexAttrs.add(idVertexAttribName)) { attr->setSharedRawData(bucket.sharedVertices, offsetof(HeatmapLayoutVertex, a1), @@ -425,8 +454,8 @@ void RenderHeatmapLayer::update(gfx::ShaderRegistry& shaders, if (!layerGroup_) { return; } - layerGroup_->setLayerTweaker(std::make_shared(getID(), evaluatedProperties)); setLayerGroup(std::move(layerGroup_), changes); + updateLayerTextureTweaker(); } if (!heatmapTextureShader) { diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.hpp b/src/mbgl/renderer/layers/render_heatmap_layer.hpp index 196454305..4d259fc06 100644 --- a/src/mbgl/renderer/layers/render_heatmap_layer.hpp +++ b/src/mbgl/renderer/layers/render_heatmap_layer.hpp @@ -11,6 +11,13 @@ namespace mbgl { +#if MLN_DRAWABLE_RENDERER +class HeatmapLayerTweaker; +class HeatmapTextureLayerTweaker; +using HeatmapLayerTweakerPtr = std::shared_ptr; +using HeatmapTextureLayerTweakerPtr = std::shared_ptr; +#endif // MLN_DRAWABLE_RENDERER + class RenderHeatmapLayer final : public RenderLayer { public: explicit RenderHeatmapLayer(Immutable); @@ -34,12 +41,17 @@ private: void evaluate(const PropertyEvaluationParameters&) override; bool hasTransition() const override; bool hasCrossfade() const override; - void upload(gfx::UploadPass&) override; #if MLN_LEGACY_RENDERER + void upload(gfx::UploadPass&) override; void render(PaintParameters&) override; #endif +#if MLN_DRAWABLE_RENDERER + void updateLayerTweaker(); + void updateLayerTextureTweaker(); +#endif // MLN_DRAWABLE_RENDERER + bool queryIntersectsFeature(const GeometryCoordinates&, const GeometryTileFeature&, float, @@ -77,6 +89,14 @@ private: using TextureVertexVector = gfx::VertexVector; std::shared_ptr sharedTextureVertices; + + HeatmapLayerTweakerPtr tweaker; + HeatmapTextureLayerTweakerPtr textureTweaker; +#if MLN_RENDER_BACKEND_METAL + std::vector propertiesAsUniforms; +#endif // MLN_RENDER_BACKEND_METAL + + bool overdrawInspector = false; #endif }; diff --git a/src/mbgl/renderer/render_target.cpp b/src/mbgl/renderer/render_target.cpp index 2dfa6b048..924dae958 100644 --- a/src/mbgl/renderer/render_target.cpp +++ b/src/mbgl/renderer/render_target.cpp @@ -1,10 +1,25 @@ #include #include +#include +#include #include +#include +#include namespace mbgl { +RenderTarget::RenderTarget(gfx::Context& context_, const Size size, const gfx::TextureChannelDataType type) + : context(context_) { + offscreenTexture = context.createOffscreenTexture(size, type); +} + +RenderTarget::~RenderTarget() {} + +const gfx::Texture2DPtr& RenderTarget::getTexture() { + return offscreenTexture->getTexture(); +}; + bool RenderTarget::addLayerGroup(LayerGroupBasePtr layerGroup, const bool replace) { const auto index = layerGroup->getLayerIndex(); const auto result = layerGroupsByLayerIndex.insert(std::make_pair(index, LayerGroupBasePtr{})); @@ -60,4 +75,45 @@ void RenderTarget::visitLayerGroups(std::function f } } +void RenderTarget::upload(gfx::UploadPass& uploadPass) { + visitLayerGroups(([&](LayerGroupBase& layerGroup) { layerGroup.upload(uploadPass); })); +} + +void RenderTarget::render(RenderOrchestrator& orchestrator, const RenderTree& renderTree, PaintParameters& parameters) { + parameters.renderPass = parameters.encoder->createRenderPass( + "render target", {*offscreenTexture, Color{0.0f, 0.0f, 0.0f, 1.0f}, {}, {}}); + + // Run layer tweakers to update any dynamic elements + visitLayerGroups([&](LayerGroupBase& layerGroup) { + if (layerGroup.getLayerTweaker()) { + layerGroup.getLayerTweaker()->execute(layerGroup, renderTree, parameters); + } + }); + + // draw layer groups, opaque pass + parameters.pass = RenderPass::Opaque; + parameters.currentLayer = 0; + parameters.depthRangeSize = 1 - (numLayerGroups() + 2) * parameters.numSublayers * PaintParameters::depthEpsilon; + + visitLayerGroups([&](LayerGroupBase& layerGroup) { + layerGroup.render(orchestrator, parameters); + parameters.currentLayer++; + }); + + // draw layer groups, translucent pass + parameters.pass = RenderPass::Translucent; + parameters.currentLayer = static_cast(numLayerGroups()) - 1; + parameters.depthRangeSize = 1 - (numLayerGroups() + 2) * parameters.numSublayers * PaintParameters::depthEpsilon; + + visitLayerGroups([&](LayerGroupBase& layerGroup) { + layerGroup.render(orchestrator, parameters); + if (parameters.currentLayer != 0) { + parameters.currentLayer--; + } + }); + + parameters.renderPass.reset(); + parameters.encoder->present(*offscreenTexture); +} + } // namespace mbgl