diff --git a/bazel/core.bzl b/bazel/core.bzl index a95631ec6..75b3cedfa 100644 --- a/bazel/core.bzl +++ b/bazel/core.bzl @@ -1005,6 +1005,7 @@ MLN_DRAWABLES_GL_SOURCE = [ "src/mbgl/gl/drawable_gl.cpp", "src/mbgl/gl/drawable_gl_builder.cpp", "src/mbgl/gl/drawable_gl_impl.hpp", + "src/mbgl/gl/dynamic_texture.cpp", "src/mbgl/gl/layer_group_gl.cpp", "src/mbgl/gl/texture2d.cpp", "src/mbgl/gl/uniform_buffer_gl.cpp", @@ -1017,6 +1018,7 @@ MLN_DRAWABLES_GL_HEADERS = [ "include/mbgl/gl/buffer_allocator.hpp", "include/mbgl/gl/drawable_gl.hpp", "include/mbgl/gl/drawable_gl_builder.hpp", + "include/mbgl/gl/dynamic_texture.hpp", "include/mbgl/gl/layer_group_gl.hpp", "include/mbgl/gl/uniform_buffer_gl.hpp", "include/mbgl/gl/vertex_attribute_gl.hpp", @@ -1033,6 +1035,7 @@ MLN_DRAWABLES_MTL_SOURCE = [ "src/mbgl/mtl/drawable.cpp", "src/mbgl/mtl/drawable_impl.hpp", "src/mbgl/mtl/drawable_builder.cpp", + "src/mbgl/mtl/dynamic_texture.cpp", "src/mbgl/mtl/index_buffer_resource.cpp", "src/mbgl/mtl/layer_group.cpp", "src/mbgl/mtl/mtl.cpp", @@ -1073,6 +1076,7 @@ MLN_DRAWABLES_MTL_HEADERS = [ "include/mbgl/mtl/context.hpp", "include/mbgl/mtl/drawable.hpp", "include/mbgl/mtl/drawable_builder.hpp", + "include/mbgl/mtl/dynamic_texture.hpp", "include/mbgl/mtl/index_buffer_resource.hpp", "include/mbgl/mtl/layer_group.hpp", "include/mbgl/mtl/mtl_fwd.hpp", @@ -1117,6 +1121,7 @@ MLN_DRAWABLES_WEBGPU_SOURCE = [ "src/mbgl/webgpu/draw_scope_resource.cpp", "src/mbgl/webgpu/drawable.cpp", "src/mbgl/webgpu/drawable_builder.cpp", + "src/mbgl/webgpu/dynamic_texture.cpp", "src/mbgl/webgpu/headless_backend.cpp", "src/mbgl/webgpu/index_buffer_resource.cpp", "src/mbgl/webgpu/layer_group.cpp", @@ -1158,6 +1163,7 @@ MLN_DRAWABLES_WEBGPU_HEADERS = [ "include/mbgl/webgpu/draw_scope_resource.hpp", "include/mbgl/webgpu/drawable.hpp", "include/mbgl/webgpu/drawable_builder.hpp", + "include/mbgl/webgpu/dynamic_texture.hpp", "include/mbgl/webgpu/index_buffer_resource.hpp", "include/mbgl/webgpu/layer_group.hpp", "include/mbgl/webgpu/offscreen_texture.hpp", diff --git a/cmake/metal.cmake b/cmake/metal.cmake index 31489c931..e456e2b9c 100644 --- a/cmake/metal.cmake +++ b/cmake/metal.cmake @@ -16,6 +16,7 @@ list(APPEND ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/context.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/drawable.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/drawable_builder.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/mtl/dynamic_texture.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 @@ -58,6 +59,7 @@ list(APPEND ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/drawable.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/dynamic_texture.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/index_buffer_resource.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/layer_group.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/mtl/mtl.cpp diff --git a/cmake/opengl.cmake b/cmake/opengl.cmake index eec3ee4d9..7edfe766e 100644 --- a/cmake/opengl.cmake +++ b/cmake/opengl.cmake @@ -127,10 +127,11 @@ list(APPEND INCLUDE_FILES ${PROJECT_SOURCE_DIR}/include/mbgl/gl/buffer_allocator.hpp ${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/dynamic_texture.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/gl/layer_group_gl.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/gl/texture2d.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/shaders/gl/shader_info.cpp @@ -139,6 +140,7 @@ list(APPEND SRC_FILES ${PROJECT_SOURCE_DIR}/src/mbgl/gl/drawable_gl.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/drawable_gl_builder.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/drawable_gl_impl.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/gl/dynamic_texture.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/layer_group_gl.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/texture2d.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/gl/uniform_buffer_gl.cpp diff --git a/cmake/vulkan.cmake b/cmake/vulkan.cmake index 95da2aced..35a86ea43 100644 --- a/cmake/vulkan.cmake +++ b/cmake/vulkan.cmake @@ -18,6 +18,7 @@ list(APPEND ${PROJECT_SOURCE_DIR}/include/mbgl/vulkan/drawable.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/vulkan/descriptor_set.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/vulkan/drawable_builder.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/vulkan/dynamic_texture.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/vulkan/index_buffer_resource.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/vulkan/layer_group.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/vulkan/offscreen_texture.hpp @@ -62,6 +63,7 @@ list(APPEND ${PROJECT_SOURCE_DIR}/src/mbgl/vulkan/drawable.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/vulkan/drawable_builder.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/vulkan/drawable_impl.hpp + ${PROJECT_SOURCE_DIR}/src/mbgl/vulkan/dynamic_texture.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/vulkan/index_buffer_resource.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/vulkan/layer_group.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/vulkan/offscreen_texture.cpp diff --git a/cmake/webgpu.cmake b/cmake/webgpu.cmake index bdd8060c9..31482fe66 100644 --- a/cmake/webgpu.cmake +++ b/cmake/webgpu.cmake @@ -19,6 +19,7 @@ list(APPEND ${PROJECT_SOURCE_DIR}/src/mbgl/webgpu/drawable.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/webgpu/drawable_builder.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/webgpu/draw_scope_resource.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/webgpu/dynamic_texture.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/webgpu/uniform_buffer.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/webgpu/shader_program.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/shaders/webgpu/wgsl_preprocessor.cpp @@ -55,6 +56,7 @@ list(APPEND ${PROJECT_SOURCE_DIR}/include/mbgl/webgpu/context.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/webgpu/drawable.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/webgpu/drawable_builder.hpp + ${PROJECT_SOURCE_DIR}/include/mbgl/webgpu/dynamic_texture.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/webgpu/index_buffer_resource.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/webgpu/render_pass.hpp ${PROJECT_SOURCE_DIR}/include/mbgl/webgpu/renderer_backend.hpp @@ -91,6 +93,7 @@ list(APPEND ${PROJECT_SOURCE_DIR}/src/mbgl/webgpu/context.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/webgpu/drawable.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/webgpu/drawable_builder.cpp + ${PROJECT_SOURCE_DIR}/src/mbgl/webgpu/dynamic_texture.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/webgpu/index_buffer_resource.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/webgpu/render_pass.cpp ${PROJECT_SOURCE_DIR}/src/mbgl/webgpu/renderer_backend.cpp diff --git a/include/mbgl/gfx/context.hpp b/include/mbgl/gfx/context.hpp index af84ad9e6..0f13663d9 100644 --- a/include/mbgl/gfx/context.hpp +++ b/include/mbgl/gfx/context.hpp @@ -35,11 +35,13 @@ class ShaderRegistry; class Drawable; class DrawableBuilder; +class DynamicTexture; class ShaderProgramBase; class Texture2D; class VertexAttributeArray; using DrawablePtr = std::shared_ptr; +using DynamicTexturePtr = std::shared_ptr; using ShaderProgramBasePtr = std::shared_ptr; using Texture2DPtr = std::shared_ptr; using UniformBufferPtr = std::shared_ptr; @@ -132,6 +134,9 @@ public: /// Create a texture virtual Texture2DPtr createTexture2D() = 0; + /// Create a dynamic texture + virtual DynamicTexturePtr createDynamicTexture(Size size, TexturePixelType pixelType) = 0; + /// Create a render target virtual RenderTargetPtr createRenderTarget(const Size size, const TextureChannelDataType type) = 0; diff --git a/include/mbgl/gfx/dynamic_texture.hpp b/include/mbgl/gfx/dynamic_texture.hpp index 024f1c8d4..06faf0335 100644 --- a/include/mbgl/gfx/dynamic_texture.hpp +++ b/include/mbgl/gfx/dynamic_texture.hpp @@ -10,12 +10,11 @@ #include namespace mbgl { - namespace gfx { class Context; class Texture2D; -using Texture2DPtr = std::shared_ptr; +using Texture2DPtr = std::shared_ptr; class TextureHandle { public: @@ -46,14 +45,13 @@ private: class DynamicTexture { public: DynamicTexture(Context& context, Size size, TexturePixelType pixelType); - ~DynamicTexture() = default; + virtual ~DynamicTexture() = default; const Texture2DPtr& getTexture() const; TexturePixelType getPixelFormat() const; bool isEmpty() const; std::optional reserveSize(const Size& size, int32_t uniqueId); - void uploadImage(const uint8_t* pixelData, TextureHandle& texHandle); template std::optional addImage(const Image& image, int32_t uniqueId = -1) { @@ -61,22 +59,16 @@ public: } std::optional addImage(const uint8_t* pixelData, const Size& imageSize, int32_t uniqueId = -1); - void uploadDeferredImages(); - void removeTexture(const TextureHandle& texHandle); + virtual void uploadImage(const uint8_t* pixelData, TextureHandle& texHandle); + virtual void uploadDeferredImages() {}; + virtual bool removeTexture(const TextureHandle& texHandle); - using ImagesToUpload = std::unordered_map, TextureHandle::Hasher>; - -private: - Texture2DPtr texture; +protected: mapbox::ShelfPack shelfPack; + Texture2DPtr texture; int numTextures = 0; - bool deferredCreation = false; - ImagesToUpload imagesToUpload; std::mutex mutex; }; -#define MLN_DEFER_UPLOAD_ON_RENDER_THREAD \ - (MLN_RENDER_BACKEND_OPENGL || MLN_RENDER_BACKEND_VULKAN || MLN_RENDER_BACKEND_WEBGPU) - } // namespace gfx } // namespace mbgl diff --git a/include/mbgl/gl/dynamic_texture.hpp b/include/mbgl/gl/dynamic_texture.hpp new file mode 100644 index 000000000..aa6ad2329 --- /dev/null +++ b/include/mbgl/gl/dynamic_texture.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace mbgl { +namespace gl { + +class Context; + +class DynamicTexture : public gfx::DynamicTexture { +public: + DynamicTexture(Context& context, Size size, gfx::TexturePixelType pixelType); + + void uploadImage(const uint8_t* pixelData, gfx::TextureHandle& texHandle) override; + void uploadDeferredImages() override; + bool removeTexture(const gfx::TextureHandle& texHandle) override; + + using ImagesToUpload = + std::unordered_map, gfx::TextureHandle::Hasher>; + +private: + bool deferredCreation = false; + ImagesToUpload imagesToUpload; +}; + +} // namespace gl +} // namespace mbgl diff --git a/include/mbgl/mtl/context.hpp b/include/mbgl/mtl/context.hpp index 36ea014f7..3dd2ab322 100644 --- a/include/mbgl/mtl/context.hpp +++ b/include/mbgl/mtl/context.hpp @@ -98,6 +98,8 @@ public: gfx::Texture2DPtr createTexture2D() override; + gfx::DynamicTexturePtr createDynamicTexture(Size size, gfx::TexturePixelType pixelType) override; + RenderTargetPtr createRenderTarget(const Size size, const gfx::TextureChannelDataType type) override; void resetState(gfx::DepthMode depthMode, gfx::ColorMode colorMode) override; diff --git a/include/mbgl/mtl/dynamic_texture.hpp b/include/mbgl/mtl/dynamic_texture.hpp new file mode 100644 index 000000000..d7e9e9047 --- /dev/null +++ b/include/mbgl/mtl/dynamic_texture.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace mbgl { +namespace mtl { + +class Context; + +class DynamicTexture : public gfx::DynamicTexture { +public: + DynamicTexture(Context& context, Size size, gfx::TexturePixelType pixelType); + + void uploadImage(const uint8_t* pixelData, gfx::TextureHandle& texHandle) override; +}; + +} // namespace mtl +} // namespace mbgl diff --git a/include/mbgl/vulkan/context.hpp b/include/mbgl/vulkan/context.hpp index bc230f877..d0e267e7c 100644 --- a/include/mbgl/vulkan/context.hpp +++ b/include/mbgl/vulkan/context.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,6 @@ struct ClipUBO; namespace vulkan { class RenderPass; -class RendererBackend; class ShaderProgram; class VertexBufferResource; class Texture2D; @@ -44,6 +44,9 @@ using UniqueShaderProgram = std::unique_ptr; using UniqueVertexBufferResource = std::unique_ptr; using UniqueUniformBufferArray = std::unique_ptr; +using DeletionTask = std::function; +using DeletionQueue = std::vector; + class Context final : public gfx::Context { public: Context(RendererBackend&); @@ -89,6 +92,8 @@ public: gfx::Texture2DPtr createTexture2D() override; + gfx::DynamicTexturePtr createDynamicTexture(Size size, gfx::TexturePixelType pixelType) override; + RenderTargetPtr createRenderTarget(const Size size, const gfx::TextureChannelDataType type) override; void resetState(gfx::DepthMode, gfx::ColorMode) override {} @@ -143,8 +148,10 @@ public: const vk::UniquePipelineLayout& getPushConstantPipelineLayout(); uint8_t getCurrentFrameResourceIndex() const { return frameResourceIndex; } - void enqueueDeletion(std::function&& function); - void submitOneTimeCommand(const std::function& function) const; + void enqueueDeletion(DeletionTask&& function); + void submitOneTimeCommand(const std::function& function); + void submitOneTimeCommand(const vk::UniqueCommandPool& commandPool, + const std::function& function); void requestSurfaceUpdate(bool useDelay = true); @@ -153,7 +160,7 @@ private: vk::UniqueCommandBuffer commandBuffer; vk::UniqueFence flightFrameFence; - std::vector> deletionQueue; + DeletionQueue deletionQueue; FrameResources(vk::UniqueCommandBuffer& cb, vk::UniqueFence&& flight) : commandBuffer(std::move(cb)), @@ -201,6 +208,10 @@ private: PipelineInfo pipelineInfo; } clipping; + +#if DYNAMIC_TEXTURE_VULKAN_MULTITHREADED_UPLOAD + std::mutex graphicsQueueSubmitMutex; +#endif }; } // namespace vulkan diff --git a/include/mbgl/vulkan/dynamic_texture.hpp b/include/mbgl/vulkan/dynamic_texture.hpp new file mode 100644 index 000000000..42692b4ad --- /dev/null +++ b/include/mbgl/vulkan/dynamic_texture.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include +#include + +#define DYNAMIC_TEXTURE_VULKAN_MULTITHREADED_UPLOAD 1 + +namespace mbgl { +namespace vulkan { + +class Context; +struct BufferAllocation; +using UniqueBufferAllocation = std::unique_ptr; + +class DynamicTexture : public gfx::DynamicTexture { +public: + DynamicTexture(Context& context, Size size, gfx::TexturePixelType pixelType); + + void uploadImage(const uint8_t* pixelData, gfx::TextureHandle& texHandle) override; + void uploadDeferredImages() override; + bool removeTexture(const gfx::TextureHandle& texHandle) override; + +#if DYNAMIC_TEXTURE_VULKAN_MULTITHREADED_UPLOAD + using TexturesToBlit = std::unordered_map; +#else + using TextureBuffersToUpload = + std::unordered_map; +#endif + +private: + Context& context; + +#if DYNAMIC_TEXTURE_VULKAN_MULTITHREADED_UPLOAD + TexturesToBlit texturesToBlit; + vk::UniqueCommandPool commandPool; +#else + TextureBuffersToUpload textureBuffersToUpload; +#endif +}; + +} // namespace vulkan +} // namespace mbgl diff --git a/include/mbgl/vulkan/texture2d.hpp b/include/mbgl/vulkan/texture2d.hpp index 4f2b1a992..30a303635 100644 --- a/include/mbgl/vulkan/texture2d.hpp +++ b/include/mbgl/vulkan/texture2d.hpp @@ -41,6 +41,7 @@ enum class Texture2DUsage { ShaderInput, Attachment, Read, + Blit, }; class Texture2D : public gfx::Texture2D { @@ -72,7 +73,8 @@ public: const Size& size, uint16_t xOffset, uint16_t yOffset, - const vk::UniqueCommandBuffer& buffer) noexcept; + const vk::UniqueCommandBuffer& buffer, + std::vector>* deletionQueue = nullptr) noexcept; bool needsUpload() const noexcept override { return !!imageData; }; @@ -83,7 +85,7 @@ public: const vk::Image& getVulkanImage() const { return imageAllocation->image; } const vk::Sampler& getVulkanSampler(); - void copyImage(vk::Image image); + void copyImage(vk::Image image, Size imageSize, uint16_t xOffset = 0, uint16_t yOffset = 0); std::shared_ptr readImage(); private: @@ -97,7 +99,8 @@ private: void destroyTexture(); void destroySampler(); - void transitionToTransferLayout(const vk::UniqueCommandBuffer&); + void transitionToTransferWriteLayout(const vk::UniqueCommandBuffer&); + void transitionToTransferReadLayout(const vk::UniqueCommandBuffer&); void transitionToShaderReadLayout(const vk::UniqueCommandBuffer&); void transitionToGeneralLayout(const vk::UniqueCommandBuffer&); @@ -123,6 +126,8 @@ private: vk::Sampler sampler{}; Texture2DUsage textureUsage{Texture2DUsage::ShaderInput}; + + friend class DynamicTexture; }; } // namespace vulkan diff --git a/include/mbgl/webgpu/context.hpp b/include/mbgl/webgpu/context.hpp index 6aa8853f9..d381cfb32 100644 --- a/include/mbgl/webgpu/context.hpp +++ b/include/mbgl/webgpu/context.hpp @@ -57,6 +57,7 @@ public: TileLayerGroupPtr createTileLayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name) override; LayerGroupPtr createLayerGroup(int32_t layerIndex, std::size_t initialCapacity, std::string name) override; gfx::Texture2DPtr createTexture2D() override; + gfx::DynamicTexturePtr createDynamicTexture(Size size, gfx::TexturePixelType pixelType) override; RenderTargetPtr createRenderTarget(const Size size, const gfx::TextureChannelDataType type) override; // State management diff --git a/include/mbgl/webgpu/dynamic_texture.hpp b/include/mbgl/webgpu/dynamic_texture.hpp new file mode 100644 index 000000000..766087be8 --- /dev/null +++ b/include/mbgl/webgpu/dynamic_texture.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace mbgl { +namespace webgpu { + +class Context; + +class DynamicTexture : public gfx::DynamicTexture { +public: + DynamicTexture(Context& context, Size size, gfx::TexturePixelType pixelType); + + void uploadImage(const uint8_t* pixelData, gfx::TextureHandle& texHandle) override; + void uploadDeferredImages() override; + bool removeTexture(const gfx::TextureHandle& texHandle) override; + + using ImagesToUpload = + std::unordered_map, gfx::TextureHandle::Hasher>; + +private: + bool deferredCreation = false; + ImagesToUpload imagesToUpload; +}; + +} // namespace webgpu +} // namespace mbgl diff --git a/platform/default/src/mbgl/vulkan/headless_backend.cpp b/platform/default/src/mbgl/vulkan/headless_backend.cpp index 307add68f..5083d1ec2 100644 --- a/platform/default/src/mbgl/vulkan/headless_backend.cpp +++ b/platform/default/src/mbgl/vulkan/headless_backend.cpp @@ -91,7 +91,7 @@ PremultipliedImage HeadlessBackend::readStillImage() { texture->setSize(size); contextImpl.waitFrame(); - texture->copyImage(resourceImpl.getAcquiredImage()); + texture->copyImage(resourceImpl.getAcquiredImage(), size); return std::move(*texture->readImage()); } diff --git a/src/mbgl/gfx/dynamic_texture.cpp b/src/mbgl/gfx/dynamic_texture.cpp index e57637cd0..60bec826e 100644 --- a/src/mbgl/gfx/dynamic_texture.cpp +++ b/src/mbgl/gfx/dynamic_texture.cpp @@ -12,25 +12,19 @@ DynamicTexture::DynamicTexture(Context& context, Size size, TexturePixelType pix texture = context.createTexture2D(); texture->setSize(size); - texture->setFormat(pixelType, TextureChannelDataType::UnsignedByte); + texture->setFormat(pixelType, gfx::TextureChannelDataType::UnsignedByte); texture->setSamplerConfiguration({.filter = gfx::TextureFilterType::Linear, .wrapU = gfx::TextureWrapType::Clamp, .wrapV = gfx::TextureWrapType::Clamp}); -#if MLN_DEFER_UPLOAD_ON_RENDER_THREAD - deferredCreation = true; -#else - texture->create(); -#endif } -const Texture2DPtr& DynamicTexture::getTexture() const { +const gfx::Texture2DPtr& DynamicTexture::getTexture() const { assert(texture); return texture; } TexturePixelType DynamicTexture::getPixelFormat() const { - assert(texture); - return texture->getFormat(); + return getTexture()->getFormat(); } bool DynamicTexture::isEmpty() const { @@ -49,22 +43,6 @@ std::optional DynamicTexture::reserveSize(const Size& size, int32 return TextureHandle(*bin); } -void DynamicTexture::uploadImage(const uint8_t* pixelData, TextureHandle& texHandle) { - std::scoped_lock lock(mutex); - const auto& rect = texHandle.getRectangle(); - const auto imageSize = Size(rect.w, rect.h); - -#if MLN_DEFER_UPLOAD_ON_RENDER_THREAD - auto size = imageSize.area() * texture->getPixelStride(); - auto imageData = std::make_unique(size); - std::copy(pixelData, pixelData + size, imageData.get()); - imagesToUpload.emplace(texHandle, std::move(imageData)); -#else - texture->uploadSubRegion(pixelData, imageSize, rect.x, rect.y); -#endif - texHandle.needsUpload = false; -} - std::optional DynamicTexture::addImage(const uint8_t* pixelData, const Size& imageSize, int32_t uniqueId) { @@ -75,30 +53,22 @@ std::optional DynamicTexture::addImage(const uint8_t* pixelData, return texHandle; } -void DynamicTexture::uploadDeferredImages() { - std::scoped_lock lock(mutex); - if (deferredCreation) { - texture->create(); - deferredCreation = false; - } - for (const auto& pair : imagesToUpload) { - const auto& rect = pair.first.getRectangle(); - texture->uploadSubRegion(pair.second.get(), Size(rect.w, rect.h), rect.x, rect.y); - } - imagesToUpload.clear(); +void DynamicTexture::uploadImage(const uint8_t* /*pixelData*/, gfx::TextureHandle& texHandle) { + texHandle.needsUpload = false; } -void DynamicTexture::removeTexture(const TextureHandle& texHandle) { +bool DynamicTexture::removeTexture(const TextureHandle& texHandle) { std::scoped_lock lock(mutex); auto* bin = shelfPack.getBin(texHandle.getId()); if (!bin) { - return; + return false; } auto refcount = shelfPack.unref(*bin); if (refcount == 0) { numTextures--; - imagesToUpload.erase(texHandle); + return true; } + return false; } } // namespace gfx diff --git a/src/mbgl/gfx/dynamic_texture_atlas.cpp b/src/mbgl/gfx/dynamic_texture_atlas.cpp index 39923da1c..42966f6b2 100644 --- a/src/mbgl/gfx/dynamic_texture_atlas.cpp +++ b/src/mbgl/gfx/dynamic_texture_atlas.cpp @@ -29,8 +29,7 @@ GlyphAtlas DynamicTextureAtlas::uploadGlyphs(const GlyphMap& glyphs) { if (!glyphAtlas.dynamicTexture) { AlphaImage dummyImage(dummySize); dummyImage.fill(0); - glyphAtlas.dynamicTexture = std::make_shared( - context, dummySize, TexturePixelType::Alpha); + glyphAtlas.dynamicTexture = context.createDynamicTexture(dummySize, TexturePixelType::Alpha); glyphAtlas.dynamicTexture->addImage(dummyImage.data.get(), dummySize); dummyDynamicTexture[TexturePixelType::Alpha] = glyphAtlas.dynamicTexture; } @@ -45,8 +44,7 @@ GlyphAtlas DynamicTextureAtlas::uploadGlyphs(const GlyphMap& glyphs) { if (dynTexIndex < dynamicTextures.size()) { glyphAtlas.dynamicTexture = dynamicTextures[dynTexIndex++]; } else { - glyphAtlas.dynamicTexture = std::make_shared( - context, dynTexSize, TexturePixelType::Alpha); + glyphAtlas.dynamicTexture = context.createDynamicTexture(dynTexSize, TexturePixelType::Alpha); dynTexSize = Size(dynTexSize.width * 2, dynTexSize.height * 2); dynTexIndex++; } @@ -118,8 +116,7 @@ ImageAtlas DynamicTextureAtlas::uploadIconsAndPatterns(const ImageMap& icons, if (!imageAtlas.dynamicTexture) { PremultipliedImage dummyImage(dummySize); dummyImage.fill(0); - imageAtlas.dynamicTexture = std::make_shared( - context, dummySize, TexturePixelType::RGBA); + imageAtlas.dynamicTexture = context.createDynamicTexture(dummySize, TexturePixelType::RGBA); imageAtlas.dynamicTexture->addImage(dummyImage.data.get(), dummySize); dummyDynamicTexture[TexturePixelType::RGBA] = imageAtlas.dynamicTexture; } @@ -137,8 +134,7 @@ ImageAtlas DynamicTextureAtlas::uploadIconsAndPatterns(const ImageMap& icons, if (dynTexIndex < dynamicTextures.size()) { imageAtlas.dynamicTexture = dynamicTextures[dynTexIndex++]; } else { - imageAtlas.dynamicTexture = std::make_shared( - context, dynTexSize, TexturePixelType::RGBA); + imageAtlas.dynamicTexture = context.createDynamicTexture(dynTexSize, TexturePixelType::RGBA); dynTexSize = Size(dynTexSize.width * 2, dynTexSize.height * 2); dynTexIndex++; } diff --git a/src/mbgl/gl/context.cpp b/src/mbgl/gl/context.cpp index b61474664..f8415d24f 100644 --- a/src/mbgl/gl/context.cpp +++ b/src/mbgl/gl/context.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -580,6 +581,12 @@ gfx::Texture2DPtr Context::createTexture2D() { return std::make_shared(*this); } +gfx::DynamicTexturePtr Context::createDynamicTexture(Size size, gfx::TexturePixelType pixelType) { + MLN_TRACE_FUNC(); + + return std::make_shared(*this, size, pixelType); +} + RenderTargetPtr Context::createRenderTarget(const Size size, const gfx::TextureChannelDataType type) { MLN_TRACE_FUNC(); diff --git a/src/mbgl/gl/context.hpp b/src/mbgl/gl/context.hpp index 8fd9bee72..b83625fe3 100644 --- a/src/mbgl/gl/context.hpp +++ b/src/mbgl/gl/context.hpp @@ -128,6 +128,8 @@ public: gfx::Texture2DPtr createTexture2D() override; + gfx::DynamicTexturePtr createDynamicTexture(Size size, gfx::TexturePixelType pixelType) override; + RenderTargetPtr createRenderTarget(const Size size, const gfx::TextureChannelDataType type) override; Framebuffer createFramebuffer(const gfx::Texture2D& color); diff --git a/src/mbgl/gl/dynamic_texture.cpp b/src/mbgl/gl/dynamic_texture.cpp new file mode 100644 index 000000000..daebcc3b8 --- /dev/null +++ b/src/mbgl/gl/dynamic_texture.cpp @@ -0,0 +1,49 @@ +#include +#include +#include + +namespace mbgl { +namespace gl { + +DynamicTexture::DynamicTexture(Context& context, Size size, gfx::TexturePixelType pixelType) + : gfx::DynamicTexture(context, size, pixelType) { + deferredCreation = true; +} + +void DynamicTexture::uploadImage(const uint8_t* pixelData, gfx::TextureHandle& texHandle) { + std::scoped_lock lock(mutex); + const auto& rect = texHandle.getRectangle(); + const auto imageSize = Size(rect.w, rect.h); + + auto size = imageSize.area() * texture->getPixelStride(); + auto imageData = std::make_unique(size); + std::copy(pixelData, pixelData + size, imageData.get()); + imagesToUpload.emplace(texHandle, std::move(imageData)); + + gfx::DynamicTexture::uploadImage(pixelData, texHandle); +} + +void DynamicTexture::uploadDeferredImages() { + std::scoped_lock lock(mutex); + if (deferredCreation) { + texture->create(); + deferredCreation = false; + } + for (const auto& pair : imagesToUpload) { + const auto& rect = pair.first.getRectangle(); + texture->uploadSubRegion(pair.second.get(), Size(rect.w, rect.h), rect.x, rect.y); + } + imagesToUpload.clear(); +} + +bool DynamicTexture::removeTexture(const gfx::TextureHandle& texHandle) { + if (gfx::DynamicTexture::removeTexture(texHandle)) { + std::scoped_lock lock(mutex); + imagesToUpload.erase(texHandle); + return true; + } + return false; +} + +} // namespace gl +} // namespace mbgl diff --git a/src/mbgl/mtl/context.cpp b/src/mbgl/mtl/context.cpp index 7e30e1ac1..7c4f44af4 100644 --- a/src/mbgl/mtl/context.cpp +++ b/src/mbgl/mtl/context.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -229,6 +230,10 @@ gfx::Texture2DPtr Context::createTexture2D() { return std::make_shared(*this); } +gfx::DynamicTexturePtr Context::createDynamicTexture(Size size, gfx::TexturePixelType pixelType) { + return std::make_shared(*this, size, pixelType); +} + RenderTargetPtr Context::createRenderTarget(const Size size, const gfx::TextureChannelDataType type) { return std::make_shared(*this, size, type); } diff --git a/src/mbgl/mtl/dynamic_texture.cpp b/src/mbgl/mtl/dynamic_texture.cpp new file mode 100644 index 000000000..88cbc621a --- /dev/null +++ b/src/mbgl/mtl/dynamic_texture.cpp @@ -0,0 +1,24 @@ +#include +#include +#include + +namespace mbgl { +namespace mtl { + +DynamicTexture::DynamicTexture(Context& context, Size size, gfx::TexturePixelType pixelType) + : gfx::DynamicTexture(context, size, pixelType) { + texture->create(); +} + +void DynamicTexture::uploadImage(const uint8_t* pixelData, gfx::TextureHandle& texHandle) { + std::scoped_lock lock(mutex); + const auto& rect = texHandle.getRectangle(); + const auto imageSize = Size(rect.w, rect.h); + + texture->uploadSubRegion(pixelData, imageSize, rect.x, rect.y); + + gfx::DynamicTexture::uploadImage(pixelData, texHandle); +} + +} // namespace mtl +} // namespace mbgl diff --git a/src/mbgl/vulkan/context.cpp b/src/mbgl/vulkan/context.cpp index 26b6c5303..f04dd53a1 100644 --- a/src/mbgl/vulkan/context.cpp +++ b/src/mbgl/vulkan/context.cpp @@ -158,7 +158,7 @@ void Context::destroyResources() { clipping.vertexBuffer.reset(); } -void Context::enqueueDeletion(std::function&& function) { +void Context::enqueueDeletion(DeletionTask&& function) { if (frameResources.empty()) { function(*this); return; @@ -167,11 +167,19 @@ void Context::enqueueDeletion(std::function&& function) { frameResources[frameResourceIndex].deletionQueue.push_back(std::move(function)); } -void Context::submitOneTimeCommand(const std::function& function) const { +void Context::submitOneTimeCommand(const std::function& function) { + submitOneTimeCommand({}, function); +} + +void Context::submitOneTimeCommand(const vk::UniqueCommandPool& commandPool, + const std::function& function) { MLN_TRACE_FUNC(); +#if DYNAMIC_TEXTURE_VULKAN_MULTITHREADED_UPLOAD + std::scoped_lock lock(graphicsQueueSubmitMutex); +#endif const vk::CommandBufferAllocateInfo allocateInfo( - backend.getCommandPool().get(), vk::CommandBufferLevel::ePrimary, 1); + commandPool ? commandPool.get() : backend.getCommandPool().get(), vk::CommandBufferLevel::ePrimary, 1); const auto& device = backend.getDevice(); const auto& dispatcher = backend.getDispatcher(); @@ -315,6 +323,10 @@ void Context::endFrame() {} void Context::submitFrame() { MLN_TRACE_FUNC(); +#if DYNAMIC_TEXTURE_VULKAN_MULTITHREADED_UPLOAD + std::scoped_lock lock(graphicsQueueSubmitMutex); +#endif + const auto& dispatcher = backend.getDispatcher(); const auto& frame = frameResources[frameResourceIndex]; frame.commandBuffer->end(dispatcher); @@ -433,6 +445,10 @@ gfx::Texture2DPtr Context::createTexture2D() { return std::make_shared(*this); } +gfx::DynamicTexturePtr Context::createDynamicTexture(Size size, gfx::TexturePixelType pixelType) { + return std::make_shared(*this, size, pixelType); +} + RenderTargetPtr Context::createRenderTarget(const Size size, const gfx::TextureChannelDataType type) { return std::make_shared(*this, size, type); } @@ -738,7 +754,9 @@ const vk::UniquePipelineLayout& Context::getPushConstantPipelineLayout() { void Context::FrameResources::runDeletionQueue(Context& context) { MLN_TRACE_FUNC(); - for (const auto& function : deletionQueue) function(context); + for (const auto& function : deletionQueue) { + function(context); + } deletionQueue.clear(); } diff --git a/src/mbgl/vulkan/dynamic_texture.cpp b/src/mbgl/vulkan/dynamic_texture.cpp new file mode 100644 index 000000000..612c2b423 --- /dev/null +++ b/src/mbgl/vulkan/dynamic_texture.cpp @@ -0,0 +1,164 @@ +#include +#include +#include + +namespace mbgl { +namespace vulkan { + +#if DYNAMIC_TEXTURE_VULKAN_MULTITHREADED_UPLOAD + +DynamicTexture::DynamicTexture(Context& context_, Size size, gfx::TexturePixelType pixelType) + : gfx::DynamicTexture(context_, size, pixelType), + context(context_) { + texture->create(); + const vk::CommandPoolCreateInfo createInfo(vk::CommandPoolCreateFlagBits::eResetCommandBuffer, + context.getBackend().getGraphicsQueueIndex()); + commandPool = context.getBackend().getDevice()->createCommandPoolUnique( + createInfo, nullptr, context.getBackend().getDispatcher()); +} + +void DynamicTexture::uploadImage(const uint8_t* pixelData, gfx::TextureHandle& texHandle) { + std::scoped_lock lock(mutex); + const auto& rect = texHandle.getRectangle(); + const auto imageSize = Size(rect.w, rect.h); + + gfx::Texture2DPtr textureToBlit = context.createTexture2D(); + texturesToBlit.emplace(texHandle, textureToBlit); + + const auto& textureToBlitVK = static_cast(textureToBlit.get()); + textureToBlitVK->setSize(imageSize); + textureToBlitVK->setFormat(texture.get()->getFormat(), gfx::TextureChannelDataType::UnsignedByte); + textureToBlitVK->setUsage(Texture2DUsage::Blit); + textureToBlitVK->create(); + + DeletionQueue deletionQueue; + context.submitOneTimeCommand(commandPool, [&](const vk::UniqueCommandBuffer& commandBuffer) { + textureToBlitVK->uploadSubRegion(pixelData, imageSize, 0, 0, commandBuffer, &deletionQueue); + }); + + for (const auto& function : deletionQueue) { + function(context); + } + + deletionQueue.clear(); + + gfx::DynamicTexture::uploadImage(pixelData, texHandle); +} + +void DynamicTexture::uploadDeferredImages() { + std::scoped_lock lock(mutex); + + const auto& textureVK = static_cast(texture.get()); + context.submitOneTimeCommand([&](const vk::UniqueCommandBuffer& commandBuffer) { + textureVK->transitionToTransferWriteLayout(commandBuffer); + for (const auto& pair : texturesToBlit) { + const auto& rect = pair.first.getRectangle(); + const auto copyInfo = vk::ImageCopy() + .setSrcSubresource({vk::ImageAspectFlagBits::eColor, 0, 0, 1}) + .setDstSubresource({vk::ImageAspectFlagBits::eColor, 0, 0, 1}) + .setExtent({rect.w, rect.h, 1}) + .setDstOffset({rect.x, rect.y, 0}); + + const auto& textureToBlitVK = static_cast(pair.second.get()); + commandBuffer->copyImage(textureToBlitVK->getVulkanImage(), + textureToBlitVK->getVulkanImageLayout(), + textureVK->getVulkanImage(), + textureVK->getVulkanImageLayout(), + copyInfo, + context.getBackend().getDispatcher()); + } + textureVK->transitionToShaderReadLayout(commandBuffer); + }); + texturesToBlit.clear(); +} + +bool DynamicTexture::removeTexture(const gfx::TextureHandle& texHandle) { + if (gfx::DynamicTexture::removeTexture(texHandle)) { + std::scoped_lock lock(mutex); + texturesToBlit.erase(texHandle); + return true; + } + return false; +} +#else + +DynamicTexture::DynamicTexture(Context& context_, Size size, gfx::TexturePixelType pixelType) + : gfx::DynamicTexture(context_, size, pixelType), + context(context_) { + texture->create(); +} + +void DynamicTexture::uploadImage(const uint8_t* pixelData, gfx::TextureHandle& texHandle) { + std::scoped_lock lock(mutex); + const auto& rect = texHandle.getRectangle(); + + const auto& backend = context.getBackend(); + const auto& allocator = backend.getAllocator(); + + const auto bufferInfo = vk::BufferCreateInfo() + .setSize(static_cast(rect.w) * rect.h * texture->getPixelStride()) + .setUsage(vk::BufferUsageFlagBits::eTransferSrc) + .setSharingMode(vk::SharingMode::eExclusive); + + VmaAllocationCreateInfo allocationInfo = {}; + + allocationInfo.usage = VMA_MEMORY_USAGE_AUTO_PREFER_HOST; + allocationInfo.requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + allocationInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; + + UniqueBufferAllocation bufferAllocation = std::make_unique(allocator); + if (!bufferAllocation->create(allocationInfo, bufferInfo)) { + mbgl::Log::Error(mbgl::Event::Render, "Vulkan texture buffer allocation failed"); + return; + } + + vmaMapMemory(allocator, bufferAllocation->allocation, &bufferAllocation->mappedBuffer); + memcpy(bufferAllocation->mappedBuffer, pixelData, bufferInfo.size); + + textureBuffersToUpload.emplace(texHandle, std::move(bufferAllocation)); + + gfx::DynamicTexture::uploadImage(pixelData, texHandle); +} + +void DynamicTexture::uploadDeferredImages() { + std::scoped_lock lock(mutex); + + const auto& textureVK = static_cast(texture.get()); + context.submitOneTimeCommand([&](const vk::UniqueCommandBuffer& commandBuffer) { + textureVK->transitionToTransferWriteLayout(commandBuffer); + for (const auto& pair : textureBuffersToUpload) { + const auto& rect = pair.first.getRectangle(); + const auto region = vk::BufferImageCopy() + .setBufferOffset(0) + .setBufferRowLength(rect.w) + .setImageSubresource( + vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1)) + .setImageOffset(vk::Offset3D(rect.x, rect.y)) + .setImageExtent(vk::Extent3D(rect.w, rect.h, 1)); + + commandBuffer->copyBufferToImage(pair.second->buffer, + textureVK->getVulkanImage(), + textureVK->getVulkanImageLayout(), + region, + context.getBackend().getDispatcher()); + + context.renderingStats().numTextureUpdates++; + context.renderingStats().textureUpdateBytes += rect.w * rect.h * texture->getPixelStride(); + } + textureVK->transitionToShaderReadLayout(commandBuffer); + }); + textureBuffersToUpload.clear(); +} + +bool DynamicTexture::removeTexture(const gfx::TextureHandle& texHandle) { + if (gfx::DynamicTexture::removeTexture(texHandle)) { + std::scoped_lock lock(mutex); + textureBuffersToUpload.erase(texHandle); + return true; + } + return false; +} +#endif + +} // namespace vulkan +} // namespace mbgl diff --git a/src/mbgl/vulkan/texture2d.cpp b/src/mbgl/vulkan/texture2d.cpp index e812ba368..d0e2968b7 100644 --- a/src/mbgl/vulkan/texture2d.cpp +++ b/src/mbgl/vulkan/texture2d.cpp @@ -158,7 +158,8 @@ void Texture2D::uploadSubRegion(const void* pixelData, const Size& size_, uint16_t xOffset, uint16_t yOffset, - const vk::UniqueCommandBuffer& commandBuffer) noexcept { + const vk::UniqueCommandBuffer& commandBuffer, + DeletionQueue* deletionQueue) noexcept { if (!pixelData || size_.width == 0 || size_.height == 0) return; create(); @@ -189,7 +190,7 @@ void Texture2D::uploadSubRegion(const void* pixelData, memcpy(bufferAllocation->mappedBuffer, pixelData, bufferInfo.size); const auto enqueueCommands = [&](const auto& buffer) { - transitionToTransferLayout(buffer); + transitionToTransferWriteLayout(buffer); const auto region = vk::BufferImageCopy() .setBufferOffset(0) @@ -204,6 +205,8 @@ void Texture2D::uploadSubRegion(const void* pixelData, if (samplerState.mipmapped && textureUsage == Texture2DUsage::ShaderInput) { generateMips(buffer); + } else if (textureUsage == Texture2DUsage::Blit) { + transitionToTransferReadLayout(buffer); } else { transitionToShaderReadLayout(buffer); } @@ -211,7 +214,15 @@ void Texture2D::uploadSubRegion(const void* pixelData, enqueueCommands(commandBuffer); - context.enqueueDeletion([buffAlloc = std::move(bufferAllocation)](auto&) mutable { buffAlloc.reset(); }); + const auto function = [buffAlloc = std::move(bufferAllocation)](auto&) mutable { + buffAlloc.reset(); + }; + + if (deletionQueue) { + deletionQueue->push_back(std::move(function)); + } else { + context.enqueueDeletion(std::move(function)); + } context.renderingStats().numTextureUpdates++; context.renderingStats().textureUpdateBytes += bufferInfo.size; @@ -304,6 +315,12 @@ void Texture2D::createTexture() { imageUsage = vk::ImageUsageFlags() | vk::ImageUsageFlagBits::eTransferDst; imageTiling = vk::ImageTiling::eLinear; break; + + case Texture2DUsage::Blit: + imageUsage = vk::ImageUsageFlags() | vk::ImageUsageFlagBits::eSampled | + vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eTransferSrc; + imageTiling = vk::ImageTiling::eLinear; + break; } const auto imageCreateInfo = vk::ImageCreateInfo() @@ -429,7 +446,7 @@ void Texture2D::destroySampler() { } } -void Texture2D::transitionToTransferLayout(const vk::UniqueCommandBuffer& buffer) { +void Texture2D::transitionToTransferWriteLayout(const vk::UniqueCommandBuffer& buffer) { const auto barrier = vk::ImageMemoryBarrier() .setImage(imageAllocation->image) .setOldLayout(imageLayout) @@ -451,6 +468,28 @@ void Texture2D::transitionToTransferLayout(const vk::UniqueCommandBuffer& buffer imageLayout = barrier.newLayout; } +void Texture2D::transitionToTransferReadLayout(const vk::UniqueCommandBuffer& buffer) { + const auto barrier = vk::ImageMemoryBarrier() + .setImage(imageAllocation->image) + .setOldLayout(imageLayout) + .setNewLayout(vk::ImageLayout::eTransferSrcOptimal) + .setSrcAccessMask(vk::AccessFlagBits::eTransferWrite) + .setDstAccessMask(vk::AccessFlagBits::eTransferRead) + .setSrcQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) + .setDstQueueFamilyIndex(VK_QUEUE_FAMILY_IGNORED) + .setSubresourceRange({vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}); + + buffer->pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, + vk::PipelineStageFlagBits::eTransfer, + {}, + nullptr, + nullptr, + barrier, + context.getBackend().getDispatcher()); + + imageLayout = barrier.newLayout; +} + void Texture2D::transitionToShaderReadLayout(const vk::UniqueCommandBuffer& buffer) { const auto barrier = vk::ImageMemoryBarrier() .setImage(imageAllocation->image) @@ -503,7 +542,7 @@ const vk::Sampler& Texture2D::getVulkanSampler() { return sampler; } -void Texture2D::copyImage(vk::Image image) { +void Texture2D::copyImage(vk::Image image, Size imageSize, uint16_t xOffset, uint16_t yOffset) { if (!image) return; create(); @@ -512,9 +551,10 @@ void Texture2D::copyImage(vk::Image image) { const auto copyInfo = vk::ImageCopy() .setSrcSubresource({vk::ImageAspectFlagBits::eColor, 0, 0, 1}) .setDstSubresource({vk::ImageAspectFlagBits::eColor, 0, 0, 1}) - .setExtent({size.width, size.height, 1}); + .setExtent({imageSize.width, imageSize.height, 1}) + .setDstOffset({xOffset, yOffset, 0}); - transitionToTransferLayout(commandBuffer); + transitionToTransferWriteLayout(commandBuffer); commandBuffer->copyImage(image, vk::ImageLayout::eTransferSrcOptimal, imageAllocation->image, diff --git a/src/mbgl/webgpu/context.cpp b/src/mbgl/webgpu/context.cpp index ad246ba27..4ef4ce9a4 100644 --- a/src/mbgl/webgpu/context.cpp +++ b/src/mbgl/webgpu/context.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -125,6 +126,10 @@ gfx::Texture2DPtr Context::createTexture2D() { return std::make_shared(*this); } +gfx::DynamicTexturePtr Context::createDynamicTexture(Size size, gfx::TexturePixelType pixelType) { + return std::make_shared(*this, size, pixelType); +} + RenderTargetPtr Context::createRenderTarget(const Size size, const gfx::TextureChannelDataType type) { return std::make_shared(*this, size, type); } diff --git a/src/mbgl/webgpu/dynamic_texture.cpp b/src/mbgl/webgpu/dynamic_texture.cpp new file mode 100644 index 000000000..4f9425cf9 --- /dev/null +++ b/src/mbgl/webgpu/dynamic_texture.cpp @@ -0,0 +1,49 @@ +#include +#include +#include + +namespace mbgl { +namespace webgpu { + +DynamicTexture::DynamicTexture(Context& context, Size size, gfx::TexturePixelType pixelType) + : gfx::DynamicTexture(context, size, pixelType) { + deferredCreation = true; +} + +void DynamicTexture::uploadImage(const uint8_t* pixelData, gfx::TextureHandle& texHandle) { + std::scoped_lock lock(mutex); + const auto& rect = texHandle.getRectangle(); + const auto imageSize = Size(rect.w, rect.h); + + auto size = imageSize.area() * texture->getPixelStride(); + auto imageData = std::make_unique(size); + std::copy(pixelData, pixelData + size, imageData.get()); + imagesToUpload.emplace(texHandle, std::move(imageData)); + + gfx::DynamicTexture::uploadImage(pixelData, texHandle); +} + +void DynamicTexture::uploadDeferredImages() { + std::scoped_lock lock(mutex); + if (deferredCreation) { + texture->create(); + deferredCreation = false; + } + for (const auto& pair : imagesToUpload) { + const auto& rect = pair.first.getRectangle(); + texture->uploadSubRegion(pair.second.get(), Size(rect.w, rect.h), rect.x, rect.y); + } + imagesToUpload.clear(); +} + +bool DynamicTexture::removeTexture(const gfx::TextureHandle& texHandle) { + if (gfx::DynamicTexture::removeTexture(texHandle)) { + std::scoped_lock lock(mutex); + imagesToUpload.erase(texHandle); + return true; + } + return false; +} + +} // namespace webgpu +} // namespace mbgl