core: Fix Vulkan dynamic texture threading (#4102)

This commit is contained in:
Adrian Cojocaru
2026-02-17 20:23:53 +02:00
committed by GitHub
parent 9737694916
commit 3fc501dfdf
8 changed files with 147 additions and 83 deletions

View File

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