core: Fix Vulkan dynamic texture threading (#4102)
This commit is contained in:
@@ -47,6 +47,7 @@ public:
|
||||
BufferResource& operator=(BufferResource&&) noexcept;
|
||||
|
||||
BufferResource clone() const;
|
||||
void destroy(bool deferred = true);
|
||||
|
||||
void update(const void* data, std::size_t size, std::size_t offset) noexcept;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <mbgl/vulkan/renderer_backend.hpp>
|
||||
#include <mbgl/vulkan/pipeline.hpp>
|
||||
#include <mbgl/vulkan/descriptor_set.hpp>
|
||||
#include <mbgl/util/util.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
@@ -150,7 +151,8 @@ public:
|
||||
uint8_t getCurrentFrameResourceIndex() const { return frameResourceIndex; }
|
||||
void enqueueDeletion(DeletionTask&& function);
|
||||
void submitOneTimeCommand(const std::function<void(const vk::UniqueCommandBuffer&)>& function);
|
||||
void submitOneTimeCommand(const vk::UniqueCommandPool& commandPool,
|
||||
void submitOneTimeCommand(const vk::UniqueCommandBuffer& buffer);
|
||||
void submitOneTimeCommand(const vk::UniqueCommandPool& pool,
|
||||
const std::function<void(const vk::UniqueCommandBuffer&)>& function);
|
||||
|
||||
void requestSurfaceUpdate(bool useDelay = true);
|
||||
@@ -212,6 +214,8 @@ private:
|
||||
#if DYNAMIC_TEXTURE_VULKAN_MULTITHREADED_UPLOAD
|
||||
std::mutex graphicsQueueSubmitMutex;
|
||||
#endif
|
||||
|
||||
MBGL_STORE_THREAD(tid);
|
||||
};
|
||||
|
||||
} // namespace vulkan
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <mbgl/gfx/dynamic_texture.hpp>
|
||||
#include <mbgl/vulkan/texture2d.hpp>
|
||||
|
||||
#define DYNAMIC_TEXTURE_VULKAN_MULTITHREADED_UPLOAD 1
|
||||
#define DYNAMIC_TEXTURE_VULKAN_MULTITHREADED_UPLOAD 0
|
||||
|
||||
namespace mbgl {
|
||||
namespace vulkan {
|
||||
@@ -15,20 +15,22 @@ using UniqueBufferAllocation = std::unique_ptr<BufferAllocation>;
|
||||
class DynamicTexture : public gfx::DynamicTexture {
|
||||
public:
|
||||
DynamicTexture(Context& context, Size size, gfx::TexturePixelType pixelType);
|
||||
~DynamicTexture() override;
|
||||
|
||||
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>;
|
||||
using TexturesToBlit =
|
||||
std::unordered_map<gfx::TextureHandle, std::shared_ptr<vulkan::Texture2D>, gfx::TextureHandle::Hasher>;
|
||||
#else
|
||||
using TextureBuffersToUpload =
|
||||
std::unordered_map<gfx::TextureHandle, UniqueBufferAllocation, gfx::TextureHandle::Hasher>;
|
||||
#endif
|
||||
|
||||
private:
|
||||
Context& context;
|
||||
vulkan::Context& context;
|
||||
|
||||
#if DYNAMIC_TEXTURE_VULKAN_MULTITHREADED_UPLOAD
|
||||
TexturesToBlit texturesToBlit;
|
||||
|
||||
@@ -65,6 +65,7 @@ public:
|
||||
bool isModifiedAfter(const std::chrono::duration<double>& t) const { return t < lastModified; }
|
||||
|
||||
void create() noexcept override;
|
||||
void destroy(bool deferred = true) noexcept;
|
||||
|
||||
void upload() noexcept override;
|
||||
void upload(const void* pixelData, const Size& size_) noexcept override;
|
||||
@@ -74,7 +75,7 @@ public:
|
||||
uint16_t xOffset,
|
||||
uint16_t yOffset,
|
||||
const vk::UniqueCommandBuffer& buffer,
|
||||
std::vector<std::function<void(Context&)>>* deletionQueue = nullptr) noexcept;
|
||||
bool submit) noexcept;
|
||||
|
||||
bool needsUpload() const noexcept override { return !!imageData; };
|
||||
|
||||
@@ -96,8 +97,8 @@ private:
|
||||
void createTexture();
|
||||
void createSampler();
|
||||
|
||||
void destroyTexture();
|
||||
void destroySampler();
|
||||
void destroyTexture(bool deferred = true);
|
||||
void destroySampler(bool deferred = true);
|
||||
|
||||
void transitionToTransferWriteLayout(const vk::UniqueCommandBuffer&);
|
||||
void transitionToTransferReadLayout(const vk::UniqueCommandBuffer&);
|
||||
|
||||
@@ -128,6 +128,10 @@ BufferResource::BufferResource(BufferResource&& other) noexcept
|
||||
}
|
||||
|
||||
BufferResource::~BufferResource() noexcept {
|
||||
destroy(true);
|
||||
}
|
||||
|
||||
void BufferResource::destroy(bool deferred) {
|
||||
if (isValid()) {
|
||||
context.threadSafeAccessRenderingStats([&](gfx::RenderingStats& stats) {
|
||||
stats.numBuffers--;
|
||||
@@ -140,9 +144,15 @@ BufferResource::~BufferResource() noexcept {
|
||||
});
|
||||
}
|
||||
|
||||
if (!bufferAllocation) return;
|
||||
if (!bufferAllocation) {
|
||||
return;
|
||||
}
|
||||
|
||||
context.enqueueDeletion([allocation = std::move(bufferAllocation)](auto&) mutable { allocation.reset(); });
|
||||
if (deferred) {
|
||||
context.enqueueDeletion([allocation = std::move(bufferAllocation)](auto&) mutable { allocation.reset(); });
|
||||
} else {
|
||||
bufferAllocation.reset();
|
||||
}
|
||||
}
|
||||
|
||||
BufferResource BufferResource::clone() const {
|
||||
|
||||
@@ -66,6 +66,8 @@ Context::Context(RendererBackend& backend_)
|
||||
}
|
||||
|
||||
Context::~Context() noexcept {
|
||||
MBGL_VERIFY_THREAD(tid);
|
||||
|
||||
backend.getThreadPool().runRenderJobs(true /* closeQueue */);
|
||||
|
||||
destroyResources();
|
||||
@@ -143,6 +145,8 @@ void Context::initFrameResources() {
|
||||
}
|
||||
|
||||
void Context::destroyResources() {
|
||||
MBGL_VERIFY_THREAD(tid);
|
||||
|
||||
backend.getDevice()->waitIdle(backend.getDispatcher());
|
||||
|
||||
for (auto& frame : frameResources) {
|
||||
@@ -166,6 +170,8 @@ void Context::destroyResources() {
|
||||
}
|
||||
|
||||
void Context::enqueueDeletion(DeletionTask&& function) {
|
||||
MBGL_VERIFY_THREAD(tid);
|
||||
|
||||
if (frameResources.empty()) {
|
||||
function(*this);
|
||||
return;
|
||||
@@ -175,32 +181,19 @@ void Context::enqueueDeletion(DeletionTask&& function) {
|
||||
}
|
||||
|
||||
void Context::submitOneTimeCommand(const std::function<void(const vk::UniqueCommandBuffer&)>& function) {
|
||||
submitOneTimeCommand({}, function);
|
||||
submitOneTimeCommand(backend.getCommandPool(), function);
|
||||
}
|
||||
|
||||
void Context::submitOneTimeCommand(const vk::UniqueCommandPool& commandPool,
|
||||
const std::function<void(const vk::UniqueCommandBuffer&)>& function) {
|
||||
void Context::submitOneTimeCommand(const vk::UniqueCommandBuffer& commandBuffer) {
|
||||
MLN_TRACE_FUNC();
|
||||
|
||||
#if DYNAMIC_TEXTURE_VULKAN_MULTITHREADED_UPLOAD
|
||||
std::scoped_lock lock(graphicsQueueSubmitMutex);
|
||||
#endif
|
||||
|
||||
const vk::CommandBufferAllocateInfo allocateInfo(
|
||||
commandPool ? commandPool.get() : backend.getCommandPool().get(), vk::CommandBufferLevel::ePrimary, 1);
|
||||
|
||||
const auto& device = backend.getDevice();
|
||||
const auto& dispatcher = backend.getDispatcher();
|
||||
const auto& commandBuffers = device->allocateCommandBuffersUnique(allocateInfo, dispatcher);
|
||||
auto& commandBuffer = commandBuffers.front();
|
||||
|
||||
backend.setDebugName(commandBuffer.get(), "OneTimeSubmitCommandBuffer");
|
||||
|
||||
commandBuffer->begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit), dispatcher);
|
||||
function(commandBuffer);
|
||||
commandBuffer->end(dispatcher);
|
||||
|
||||
const auto submitInfo = vk::SubmitInfo().setCommandBuffers(commandBuffer.get());
|
||||
|
||||
const auto& fence = device->createFenceUnique(vk::FenceCreateInfo(vk::FenceCreateFlags()), nullptr, dispatcher);
|
||||
backend.getGraphicsQueue().submit(submitInfo, fence.get(), dispatcher);
|
||||
|
||||
@@ -211,6 +204,22 @@ void Context::submitOneTimeCommand(const vk::UniqueCommandPool& commandPool,
|
||||
}
|
||||
}
|
||||
|
||||
void Context::submitOneTimeCommand(const vk::UniqueCommandPool& pool,
|
||||
const std::function<void(const vk::UniqueCommandBuffer&)>& function) {
|
||||
const auto& device = backend.getDevice();
|
||||
const auto& dispatcher = backend.getDispatcher();
|
||||
|
||||
const vk::CommandBufferAllocateInfo allocateInfo(pool.get(), vk::CommandBufferLevel::ePrimary, 1);
|
||||
const auto& commandBuffers = device->allocateCommandBuffersUnique(allocateInfo, dispatcher);
|
||||
const auto& commandBuffer = commandBuffers.front();
|
||||
|
||||
commandBuffer->begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit), dispatcher);
|
||||
function(commandBuffer);
|
||||
commandBuffer->end(dispatcher);
|
||||
|
||||
submitOneTimeCommand(commandBuffer);
|
||||
}
|
||||
|
||||
void Context::requestSurfaceUpdate(bool useDelay) {
|
||||
if (surfaceUpdateRequested) {
|
||||
if (!useDelay) {
|
||||
@@ -226,6 +235,8 @@ void Context::requestSurfaceUpdate(bool useDelay) {
|
||||
|
||||
void Context::waitFrame() const {
|
||||
MLN_TRACE_FUNC();
|
||||
MBGL_VERIFY_THREAD(tid);
|
||||
|
||||
const auto& device = backend.getDevice();
|
||||
const auto& dispatcher = backend.getDispatcher();
|
||||
auto& frame = frameResources[frameResourceIndex];
|
||||
@@ -240,6 +251,7 @@ void Context::waitFrame() const {
|
||||
|
||||
void Context::beginFrame() {
|
||||
MLN_TRACE_FUNC();
|
||||
MBGL_VERIFY_THREAD(tid);
|
||||
|
||||
frameResourceIndex = (frameResourceIndex + 1) % frameResources.size();
|
||||
|
||||
@@ -330,6 +342,7 @@ void Context::endFrame() {}
|
||||
|
||||
void Context::submitFrame() {
|
||||
MLN_TRACE_FUNC();
|
||||
|
||||
#if DYNAMIC_TEXTURE_VULKAN_MULTITHREADED_UPLOAD
|
||||
std::scoped_lock lock(graphicsQueueSubmitMutex);
|
||||
#endif
|
||||
@@ -640,7 +653,7 @@ const std::unique_ptr<Texture2D>& Context::getDummyTexture() {
|
||||
dummyTexture2D->setSize(size);
|
||||
|
||||
submitOneTimeCommand([&](const vk::UniqueCommandBuffer& commandBuffer) {
|
||||
dummyTexture2D->uploadSubRegion(data.data(), size, 0, 0, commandBuffer);
|
||||
dummyTexture2D->uploadSubRegion(data.data(), size, 0, 0, commandBuffer, false);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -17,30 +17,38 @@ DynamicTexture::DynamicTexture(Context& context_, Size size, gfx::TexturePixelTy
|
||||
createInfo, nullptr, context.getBackend().getDispatcher());
|
||||
}
|
||||
|
||||
DynamicTexture::~DynamicTexture() {
|
||||
for (auto& texture : texturesToBlit) {
|
||||
texture.second->destroy(false);
|
||||
}
|
||||
|
||||
if (texture) {
|
||||
static_cast<Texture2D&>(*texture).destroy(false);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
auto textureToBlit = std::static_pointer_cast<Texture2D>(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();
|
||||
textureToBlit->setSize(imageSize);
|
||||
textureToBlit->setFormat(texture.get()->getFormat(), gfx::TextureChannelDataType::UnsignedByte);
|
||||
textureToBlit->setUsage(Texture2DUsage::Blit);
|
||||
textureToBlit->create();
|
||||
|
||||
DeletionQueue deletionQueue;
|
||||
context.submitOneTimeCommand(commandPool, [&](const vk::UniqueCommandBuffer& commandBuffer) {
|
||||
textureToBlitVK->uploadSubRegion(pixelData, imageSize, 0, 0, commandBuffer, &deletionQueue);
|
||||
});
|
||||
const auto& device = context.getBackend().getDevice();
|
||||
const auto& dispatcher = context.getBackend().getDispatcher();
|
||||
|
||||
for (const auto& function : deletionQueue) {
|
||||
function(context);
|
||||
}
|
||||
const vk::CommandBufferAllocateInfo allocateInfo(commandPool.get(), vk::CommandBufferLevel::ePrimary, 1);
|
||||
const auto& commandBuffers = device->allocateCommandBuffersUnique(allocateInfo, dispatcher);
|
||||
const auto& commandBuffer = commandBuffers.front();
|
||||
|
||||
deletionQueue.clear();
|
||||
commandBuffer->begin(vk::CommandBufferBeginInfo(vk::CommandBufferUsageFlagBits::eOneTimeSubmit), dispatcher);
|
||||
textureToBlit->uploadSubRegion(pixelData, imageSize, 0, 0, commandBuffer, true);
|
||||
|
||||
gfx::DynamicTexture::uploadImage(pixelData, texHandle);
|
||||
}
|
||||
@@ -49,7 +57,7 @@ void DynamicTexture::uploadDeferredImages() {
|
||||
std::scoped_lock lock(mutex);
|
||||
|
||||
const auto& textureVK = static_cast<Texture2D*>(texture.get());
|
||||
context.submitOneTimeCommand([&](const vk::UniqueCommandBuffer& commandBuffer) {
|
||||
context.submitOneTimeCommand(commandPool, [&](const vk::UniqueCommandBuffer& commandBuffer) {
|
||||
textureVK->transitionToTransferWriteLayout(commandBuffer);
|
||||
for (const auto& pair : texturesToBlit) {
|
||||
const auto& rect = pair.first.getRectangle();
|
||||
@@ -69,13 +77,23 @@ void DynamicTexture::uploadDeferredImages() {
|
||||
}
|
||||
textureVK->transitionToShaderReadLayout(commandBuffer);
|
||||
});
|
||||
|
||||
for (auto& texture : texturesToBlit) {
|
||||
texture.second->destroy(false);
|
||||
}
|
||||
|
||||
texturesToBlit.clear();
|
||||
}
|
||||
|
||||
bool DynamicTexture::removeTexture(const gfx::TextureHandle& texHandle) {
|
||||
if (gfx::DynamicTexture::removeTexture(texHandle)) {
|
||||
std::scoped_lock lock(mutex);
|
||||
texturesToBlit.erase(texHandle);
|
||||
|
||||
const auto& tex = texturesToBlit.find(texHandle);
|
||||
if (tex != texturesToBlit.end()) {
|
||||
tex->second->destroy(false);
|
||||
texturesToBlit.erase(tex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -88,6 +106,12 @@ DynamicTexture::DynamicTexture(Context& context_, Size size, gfx::TexturePixelTy
|
||||
texture->create();
|
||||
}
|
||||
|
||||
DynamicTexture::~DynamicTexture() {
|
||||
if (texture) {
|
||||
static_cast<Texture2D&>(*texture).destroy(false);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicTexture::uploadImage(const uint8_t* pixelData, gfx::TextureHandle& texHandle) {
|
||||
std::scoped_lock lock(mutex);
|
||||
const auto& rect = texHandle.getRectangle();
|
||||
@@ -142,11 +166,14 @@ void DynamicTexture::uploadDeferredImages() {
|
||||
region,
|
||||
context.getBackend().getDispatcher());
|
||||
|
||||
context.renderingStats().numTextureUpdates++;
|
||||
context.renderingStats().textureUpdateBytes += rect.w * rect.h * texture->getPixelStride();
|
||||
context.threadSafeAccessRenderingStats([&](gfx::RenderingStats& stats) {
|
||||
stats.numTextureUpdates++;
|
||||
stats.textureUpdateBytes += rect.w * rect.h * texture->getPixelStride();
|
||||
});
|
||||
}
|
||||
textureVK->transitionToShaderReadLayout(commandBuffer);
|
||||
});
|
||||
|
||||
textureBuffersToUpload.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -42,8 +42,7 @@ Texture2D::Texture2D(Context& context_)
|
||||
: context(context_) {}
|
||||
|
||||
Texture2D::~Texture2D() {
|
||||
destroyTexture();
|
||||
destroySampler();
|
||||
destroy(true);
|
||||
}
|
||||
|
||||
gfx::Texture2D& Texture2D::setSamplerConfiguration(const SamplerState& samplerState_) noexcept {
|
||||
@@ -132,6 +131,11 @@ void Texture2D::create() noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
void Texture2D::destroy(bool deferred) noexcept {
|
||||
destroyTexture(deferred);
|
||||
destroySampler(deferred);
|
||||
}
|
||||
|
||||
void Texture2D::upload() noexcept {
|
||||
if (!imageData) return;
|
||||
|
||||
@@ -151,7 +155,7 @@ void Texture2D::uploadSubRegion(const void* pixelData, const Size& size_, uint16
|
||||
const auto& encoder = context.createCommandEncoder();
|
||||
const auto& encoderImpl = static_cast<const CommandEncoder&>(*encoder);
|
||||
|
||||
uploadSubRegion(pixelData, size_, xOffset, yOffset, encoderImpl.getCommandBuffer());
|
||||
uploadSubRegion(pixelData, size_, xOffset, yOffset, encoderImpl.getCommandBuffer(), false);
|
||||
}
|
||||
|
||||
void Texture2D::uploadSubRegion(const void* pixelData,
|
||||
@@ -159,7 +163,7 @@ void Texture2D::uploadSubRegion(const void* pixelData,
|
||||
uint16_t xOffset,
|
||||
uint16_t yOffset,
|
||||
const vk::UniqueCommandBuffer& commandBuffer,
|
||||
DeletionQueue* deletionQueue) noexcept {
|
||||
bool submit) noexcept {
|
||||
if (!pixelData || size_.width == 0 || size_.height == 0) return;
|
||||
|
||||
create();
|
||||
@@ -189,39 +193,32 @@ void Texture2D::uploadSubRegion(const void* pixelData,
|
||||
vmaMapMemory(allocator, bufferAllocation->allocation, &bufferAllocation->mappedBuffer);
|
||||
memcpy(bufferAllocation->mappedBuffer, pixelData, bufferInfo.size);
|
||||
|
||||
const auto enqueueCommands = [&](const auto& buffer) {
|
||||
transitionToTransferWriteLayout(buffer);
|
||||
transitionToTransferWriteLayout(commandBuffer);
|
||||
|
||||
const auto region = vk::BufferImageCopy()
|
||||
.setBufferOffset(0)
|
||||
.setBufferRowLength(size_.width)
|
||||
.setImageSubresource(
|
||||
vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1))
|
||||
.setImageOffset(vk::Offset3D(xOffset, yOffset))
|
||||
.setImageExtent(vk::Extent3D(size_.width, size_.height, 1));
|
||||
const auto region = vk::BufferImageCopy()
|
||||
.setBufferOffset(0)
|
||||
.setBufferRowLength(size_.width)
|
||||
.setImageSubresource(vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1))
|
||||
.setImageOffset(vk::Offset3D(xOffset, yOffset))
|
||||
.setImageExtent(vk::Extent3D(size_.width, size_.height, 1));
|
||||
|
||||
buffer->copyBufferToImage(
|
||||
bufferAllocation->buffer, imageAllocation->image, imageLayout, region, backend.getDispatcher());
|
||||
commandBuffer->copyBufferToImage(
|
||||
bufferAllocation->buffer, imageAllocation->image, imageLayout, region, backend.getDispatcher());
|
||||
|
||||
if (samplerState.mipmapped && textureUsage == Texture2DUsage::ShaderInput) {
|
||||
generateMips(buffer);
|
||||
} else if (textureUsage == Texture2DUsage::Blit) {
|
||||
transitionToTransferReadLayout(buffer);
|
||||
} else {
|
||||
transitionToShaderReadLayout(buffer);
|
||||
}
|
||||
};
|
||||
|
||||
enqueueCommands(commandBuffer);
|
||||
|
||||
const auto function = [buffAlloc = std::move(bufferAllocation)](auto&) mutable {
|
||||
buffAlloc.reset();
|
||||
};
|
||||
|
||||
if (deletionQueue) {
|
||||
deletionQueue->push_back(std::move(function));
|
||||
if (samplerState.mipmapped && textureUsage == Texture2DUsage::ShaderInput) {
|
||||
generateMips(commandBuffer);
|
||||
} else if (textureUsage == Texture2DUsage::Blit) {
|
||||
transitionToTransferReadLayout(commandBuffer);
|
||||
} else {
|
||||
context.enqueueDeletion(std::move(function));
|
||||
transitionToShaderReadLayout(commandBuffer);
|
||||
}
|
||||
|
||||
if (submit) {
|
||||
commandBuffer->end(context.getBackend().getDispatcher());
|
||||
context.submitOneTimeCommand(commandBuffer);
|
||||
bufferAllocation.reset();
|
||||
} else {
|
||||
context.enqueueDeletion([buffAlloc = std::move(bufferAllocation)](auto&) mutable { buffAlloc.reset(); });
|
||||
}
|
||||
|
||||
context.threadSafeAccessRenderingStats([&](gfx::RenderingStats& stats) {
|
||||
@@ -429,9 +426,13 @@ void Texture2D::createSampler() {
|
||||
lastModified = util::MonotonicTimer::now();
|
||||
}
|
||||
|
||||
void Texture2D::destroyTexture() {
|
||||
void Texture2D::destroyTexture(bool deferred) {
|
||||
if (imageAllocation) {
|
||||
context.enqueueDeletion([allocation = std::move(imageAllocation)](auto&) mutable { allocation.reset(); });
|
||||
if (deferred) {
|
||||
context.enqueueDeletion([allocation = std::move(imageAllocation)](auto&) mutable { allocation.reset(); });
|
||||
} else {
|
||||
imageAllocation.reset();
|
||||
}
|
||||
|
||||
imageLayout = vk::ImageLayout::eUndefined;
|
||||
|
||||
@@ -442,11 +443,16 @@ void Texture2D::destroyTexture() {
|
||||
}
|
||||
}
|
||||
|
||||
void Texture2D::destroySampler() {
|
||||
void Texture2D::destroySampler(bool deferred) {
|
||||
if (sampler) {
|
||||
context.enqueueDeletion([sampler_ = std::move(sampler)](auto& context_) mutable {
|
||||
context_.getBackend().getDevice()->destroySampler(sampler_, nullptr, context_.getBackend().getDispatcher());
|
||||
});
|
||||
if (deferred) {
|
||||
context.enqueueDeletion([sampler_ = std::move(sampler)](auto& context_) mutable {
|
||||
context_.getBackend().getDevice()->destroySampler(
|
||||
sampler_, nullptr, context_.getBackend().getDispatcher());
|
||||
});
|
||||
} else {
|
||||
context.getBackend().getDevice()->destroySampler(sampler, nullptr, context.getBackend().getDispatcher());
|
||||
}
|
||||
|
||||
sampler = nullptr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user