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:
Alex Cristici
2026-01-20 17:04:34 +02:00
committed by GitHub
parent 0de907f91a
commit 6a77854632
28 changed files with 556 additions and 82 deletions

View File

@@ -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",

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View 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

View File

@@ -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;

View 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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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());
}

View File

@@ -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

View File

@@ -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++;
}

View File

@@ -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();

View File

@@ -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);

View 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

View File

@@ -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);
}

View 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

View File

@@ -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();
}

View 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

View File

@@ -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,

View File

@@ -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);
}

View 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