Add multithreaded upload to dynamic texture on Vulkan [Core feature] (#4028)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Adrian Cojocaru <adrian.cojocaru92@yahoo.com>
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -35,11 +35,13 @@ class ShaderRegistry;
|
||||
|
||||
class Drawable;
|
||||
class DrawableBuilder;
|
||||
class DynamicTexture;
|
||||
class ShaderProgramBase;
|
||||
class Texture2D;
|
||||
class VertexAttributeArray;
|
||||
|
||||
using DrawablePtr = std::shared_ptr<Drawable>;
|
||||
using DynamicTexturePtr = std::shared_ptr<DynamicTexture>;
|
||||
using ShaderProgramBasePtr = std::shared_ptr<ShaderProgramBase>;
|
||||
using Texture2DPtr = std::shared_ptr<Texture2D>;
|
||||
using UniformBufferPtr = std::shared_ptr<UniformBuffer>;
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -10,12 +10,11 @@
|
||||
#include <mutex>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
namespace gfx {
|
||||
|
||||
class Context;
|
||||
class Texture2D;
|
||||
using Texture2DPtr = std::shared_ptr<gfx::Texture2D>;
|
||||
using Texture2DPtr = std::shared_ptr<Texture2D>;
|
||||
|
||||
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<TextureHandle> reserveSize(const Size& size, int32_t uniqueId);
|
||||
void uploadImage(const uint8_t* pixelData, TextureHandle& texHandle);
|
||||
|
||||
template <typename Image>
|
||||
std::optional<TextureHandle> addImage(const Image& image, int32_t uniqueId = -1) {
|
||||
@@ -61,22 +59,16 @@ public:
|
||||
}
|
||||
std::optional<TextureHandle> 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, std::unique_ptr<uint8_t[]>, 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
|
||||
|
||||
27
include/mbgl/gl/dynamic_texture.hpp
Normal file
27
include/mbgl/gl/dynamic_texture.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/gfx/dynamic_texture.hpp>
|
||||
|
||||
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, std::unique_ptr<uint8_t[]>, gfx::TextureHandle::Hasher>;
|
||||
|
||||
private:
|
||||
bool deferredCreation = false;
|
||||
ImagesToUpload imagesToUpload;
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
} // namespace mbgl
|
||||
@@ -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;
|
||||
|
||||
18
include/mbgl/mtl/dynamic_texture.hpp
Normal file
18
include/mbgl/mtl/dynamic_texture.hpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/gfx/dynamic_texture.hpp>
|
||||
|
||||
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
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <mbgl/gfx/context.hpp>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/util/containers.hpp>
|
||||
#include <mbgl/vulkan/dynamic_texture.hpp>
|
||||
#include <mbgl/vulkan/uniform_buffer.hpp>
|
||||
#include <mbgl/vulkan/renderer_backend.hpp>
|
||||
#include <mbgl/vulkan/pipeline.hpp>
|
||||
@@ -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<ShaderProgram>;
|
||||
using UniqueVertexBufferResource = std::unique_ptr<VertexBufferResource>;
|
||||
using UniqueUniformBufferArray = std::unique_ptr<gfx::UniformBufferArray>;
|
||||
|
||||
using DeletionTask = std::function<void(Context&)>;
|
||||
using DeletionQueue = std::vector<DeletionTask>;
|
||||
|
||||
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<void(Context&)>&& function);
|
||||
void submitOneTimeCommand(const std::function<void(const vk::UniqueCommandBuffer&)>& function) const;
|
||||
void enqueueDeletion(DeletionTask&& function);
|
||||
void submitOneTimeCommand(const std::function<void(const vk::UniqueCommandBuffer&)>& function);
|
||||
void submitOneTimeCommand(const vk::UniqueCommandPool& commandPool,
|
||||
const std::function<void(const vk::UniqueCommandBuffer&)>& function);
|
||||
|
||||
void requestSurfaceUpdate(bool useDelay = true);
|
||||
|
||||
@@ -153,7 +160,7 @@ private:
|
||||
vk::UniqueCommandBuffer commandBuffer;
|
||||
vk::UniqueFence flightFrameFence;
|
||||
|
||||
std::vector<std::function<void(Context&)>> 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
|
||||
|
||||
42
include/mbgl/vulkan/dynamic_texture.hpp
Normal file
42
include/mbgl/vulkan/dynamic_texture.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/gfx/dynamic_texture.hpp>
|
||||
#include <mbgl/vulkan/texture2d.hpp>
|
||||
|
||||
#define DYNAMIC_TEXTURE_VULKAN_MULTITHREADED_UPLOAD 1
|
||||
|
||||
namespace mbgl {
|
||||
namespace vulkan {
|
||||
|
||||
class Context;
|
||||
struct BufferAllocation;
|
||||
using UniqueBufferAllocation = std::unique_ptr<BufferAllocation>;
|
||||
|
||||
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<gfx::TextureHandle, gfx::Texture2DPtr, gfx::TextureHandle::Hasher>;
|
||||
#else
|
||||
using TextureBuffersToUpload =
|
||||
std::unordered_map<gfx::TextureHandle, UniqueBufferAllocation, gfx::TextureHandle::Hasher>;
|
||||
#endif
|
||||
|
||||
private:
|
||||
Context& context;
|
||||
|
||||
#if DYNAMIC_TEXTURE_VULKAN_MULTITHREADED_UPLOAD
|
||||
TexturesToBlit texturesToBlit;
|
||||
vk::UniqueCommandPool commandPool;
|
||||
#else
|
||||
TextureBuffersToUpload textureBuffersToUpload;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace vulkan
|
||||
} // namespace mbgl
|
||||
@@ -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<std::function<void(Context&)>>* 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<PremultipliedImage> 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
|
||||
|
||||
@@ -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
|
||||
|
||||
27
include/mbgl/webgpu/dynamic_texture.hpp
Normal file
27
include/mbgl/webgpu/dynamic_texture.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/gfx/dynamic_texture.hpp>
|
||||
|
||||
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, std::unique_ptr<uint8_t[]>, gfx::TextureHandle::Hasher>;
|
||||
|
||||
private:
|
||||
bool deferredCreation = false;
|
||||
ImagesToUpload imagesToUpload;
|
||||
};
|
||||
|
||||
} // namespace webgpu
|
||||
} // namespace mbgl
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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<TextureHandle> 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<uint8_t[]>(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<TextureHandle> DynamicTexture::addImage(const uint8_t* pixelData,
|
||||
const Size& imageSize,
|
||||
int32_t uniqueId) {
|
||||
@@ -75,30 +53,22 @@ std::optional<TextureHandle> 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
|
||||
|
||||
@@ -29,8 +29,7 @@ GlyphAtlas DynamicTextureAtlas::uploadGlyphs(const GlyphMap& glyphs) {
|
||||
if (!glyphAtlas.dynamicTexture) {
|
||||
AlphaImage dummyImage(dummySize);
|
||||
dummyImage.fill(0);
|
||||
glyphAtlas.dynamicTexture = std::make_shared<gfx::DynamicTexture>(
|
||||
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<gfx::DynamicTexture>(
|
||||
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<gfx::DynamicTexture>(
|
||||
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<gfx::DynamicTexture>(
|
||||
context, dynTexSize, TexturePixelType::RGBA);
|
||||
imageAtlas.dynamicTexture = context.createDynamicTexture(dynTexSize, TexturePixelType::RGBA);
|
||||
dynTexSize = Size(dynTexSize.width * 2, dynTexSize.height * 2);
|
||||
dynTexIndex++;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#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/texture2d.hpp>
|
||||
@@ -580,6 +581,12 @@ gfx::Texture2DPtr Context::createTexture2D() {
|
||||
return std::make_shared<gl::Texture2D>(*this);
|
||||
}
|
||||
|
||||
gfx::DynamicTexturePtr Context::createDynamicTexture(Size size, gfx::TexturePixelType pixelType) {
|
||||
MLN_TRACE_FUNC();
|
||||
|
||||
return std::make_shared<DynamicTexture>(*this, size, pixelType);
|
||||
}
|
||||
|
||||
RenderTargetPtr Context::createRenderTarget(const Size size, const gfx::TextureChannelDataType type) {
|
||||
MLN_TRACE_FUNC();
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
49
src/mbgl/gl/dynamic_texture.cpp
Normal file
49
src/mbgl/gl/dynamic_texture.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <mbgl/gl/dynamic_texture.hpp>
|
||||
#include <mbgl/gl/texture2d.hpp>
|
||||
#include <mbgl/gl/context.hpp>
|
||||
|
||||
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<uint8_t[]>(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
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <mbgl/gfx/shader_registry.hpp>
|
||||
#include <mbgl/mtl/command_encoder.hpp>
|
||||
#include <mbgl/mtl/drawable_builder.hpp>
|
||||
#include <mbgl/mtl/dynamic_texture.hpp>
|
||||
#include <mbgl/mtl/layer_group.hpp>
|
||||
#include <mbgl/mtl/offscreen_texture.hpp>
|
||||
#include <mbgl/mtl/renderer_backend.hpp>
|
||||
@@ -229,6 +230,10 @@ gfx::Texture2DPtr Context::createTexture2D() {
|
||||
return std::make_shared<Texture2D>(*this);
|
||||
}
|
||||
|
||||
gfx::DynamicTexturePtr Context::createDynamicTexture(Size size, gfx::TexturePixelType pixelType) {
|
||||
return std::make_shared<DynamicTexture>(*this, size, pixelType);
|
||||
}
|
||||
|
||||
RenderTargetPtr Context::createRenderTarget(const Size size, const gfx::TextureChannelDataType type) {
|
||||
return std::make_shared<RenderTarget>(*this, size, type);
|
||||
}
|
||||
|
||||
24
src/mbgl/mtl/dynamic_texture.cpp
Normal file
24
src/mbgl/mtl/dynamic_texture.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include <mbgl/mtl/dynamic_texture.hpp>
|
||||
#include <mbgl/mtl/texture2d.hpp>
|
||||
#include <mbgl/mtl/context.hpp>
|
||||
|
||||
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
|
||||
@@ -158,7 +158,7 @@ void Context::destroyResources() {
|
||||
clipping.vertexBuffer.reset();
|
||||
}
|
||||
|
||||
void Context::enqueueDeletion(std::function<void(Context&)>&& function) {
|
||||
void Context::enqueueDeletion(DeletionTask&& function) {
|
||||
if (frameResources.empty()) {
|
||||
function(*this);
|
||||
return;
|
||||
@@ -167,11 +167,19 @@ void Context::enqueueDeletion(std::function<void(Context&)>&& function) {
|
||||
frameResources[frameResourceIndex].deletionQueue.push_back(std::move(function));
|
||||
}
|
||||
|
||||
void Context::submitOneTimeCommand(const std::function<void(const vk::UniqueCommandBuffer&)>& function) const {
|
||||
void Context::submitOneTimeCommand(const std::function<void(const vk::UniqueCommandBuffer&)>& function) {
|
||||
submitOneTimeCommand({}, function);
|
||||
}
|
||||
|
||||
void Context::submitOneTimeCommand(const vk::UniqueCommandPool& commandPool,
|
||||
const std::function<void(const vk::UniqueCommandBuffer&)>& 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<Texture2D>(*this);
|
||||
}
|
||||
|
||||
gfx::DynamicTexturePtr Context::createDynamicTexture(Size size, gfx::TexturePixelType pixelType) {
|
||||
return std::make_shared<DynamicTexture>(*this, size, pixelType);
|
||||
}
|
||||
|
||||
RenderTargetPtr Context::createRenderTarget(const Size size, const gfx::TextureChannelDataType type) {
|
||||
return std::make_shared<RenderTarget>(*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();
|
||||
}
|
||||
|
||||
164
src/mbgl/vulkan/dynamic_texture.cpp
Normal file
164
src/mbgl/vulkan/dynamic_texture.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
#include <mbgl/vulkan/dynamic_texture.hpp>
|
||||
#include <mbgl/vulkan/context.hpp>
|
||||
#include <mbgl/util/logging.hpp>
|
||||
|
||||
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<Texture2D*>(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<Texture2D*>(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<Texture2D*>(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<vk::DeviceSize>(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<BufferAllocation>(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<Texture2D*>(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
|
||||
@@ -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,
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <mbgl/webgpu/command_encoder.hpp>
|
||||
#include <mbgl/webgpu/drawable_builder.hpp>
|
||||
#include <mbgl/webgpu/draw_scope_resource.hpp>
|
||||
#include <mbgl/webgpu/dynamic_texture.hpp>
|
||||
#include <mbgl/webgpu/offscreen_texture.hpp>
|
||||
#include <mbgl/gfx/upload_pass.hpp>
|
||||
#include <mbgl/webgpu/uniform_buffer.hpp>
|
||||
@@ -125,6 +126,10 @@ gfx::Texture2DPtr Context::createTexture2D() {
|
||||
return std::make_shared<Texture2D>(*this);
|
||||
}
|
||||
|
||||
gfx::DynamicTexturePtr Context::createDynamicTexture(Size size, gfx::TexturePixelType pixelType) {
|
||||
return std::make_shared<DynamicTexture>(*this, size, pixelType);
|
||||
}
|
||||
|
||||
RenderTargetPtr Context::createRenderTarget(const Size size, const gfx::TextureChannelDataType type) {
|
||||
return std::make_shared<RenderTarget>(*this, size, type);
|
||||
}
|
||||
|
||||
49
src/mbgl/webgpu/dynamic_texture.cpp
Normal file
49
src/mbgl/webgpu/dynamic_texture.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include <mbgl/webgpu/dynamic_texture.hpp>
|
||||
#include <mbgl/webgpu/texture2d.hpp>
|
||||
#include <mbgl/webgpu/context.hpp>
|
||||
|
||||
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<uint8_t[]>(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
|
||||
Reference in New Issue
Block a user