Merge pull request 'perf(image): release static texture staging after upload (#114)' (#136) from claude/issue-114 into master
This commit is contained in:
commit
faf1e5f5e8
4 changed files with 314 additions and 3 deletions
|
|
@ -90,12 +90,24 @@ export namespace Crafter {
|
|||
// consumer. Defaults to RT — the font atlas overrides it to COMPUTE,
|
||||
// since UI text is rendered by a compute shader, not an RT pipeline.
|
||||
VkPipelineStageFlags consumerStage = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR;
|
||||
// Whether this image is continuously re-uploaded from a persistent
|
||||
// CPU-side staging map. False (the default) marks a static texture
|
||||
// uploaded once — e.g. Sponza albedo: the first Update's buffer→image
|
||||
// copy is the only reader of the host-visible staging `buffer`, so it
|
||||
// is released to the fence-keyed deletion queue (#101/#102) right after
|
||||
// the copy instead of pinning HOST_VISIBLE / small-BAR memory for the
|
||||
// image's whole life (issue #114). True keeps `buffer` alive: a streamed
|
||||
// image (the FontAtlas) re-fills buffer.value on the CPU and re-uploads
|
||||
// every frame, so the persistent map must survive — its uploads go
|
||||
// through UpdateRegion, which never releases the staging.
|
||||
bool streamed = false;
|
||||
|
||||
void Create(std::uint16_t width, std::uint16_t height, std::uint8_t mipLevels, VkCommandBuffer cmd, VkFormat format, VkImageCreateFlags flags, VkImageLayout layout, VkPipelineStageFlags consumerStage = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR) {
|
||||
void Create(std::uint16_t width, std::uint16_t height, std::uint8_t mipLevels, VkCommandBuffer cmd, VkFormat format, VkImageCreateFlags flags, VkImageLayout layout, VkPipelineStageFlags consumerStage = VK_PIPELINE_STAGE_RAY_TRACING_SHADER_BIT_KHR, bool streamed = false) {
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->mipLevels = mipLevels;
|
||||
this->consumerStage = consumerStage;
|
||||
this->streamed = streamed;
|
||||
buffer.Create(
|
||||
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
|
||||
|
|
@ -212,6 +224,7 @@ export namespace Crafter {
|
|||
} else {
|
||||
TransitionImageLayout(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, layout, VK_PIPELINE_STAGE_TRANSFER_BIT, consumerStage, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, 0, mipLevels);
|
||||
}
|
||||
ReleaseStaging();
|
||||
}
|
||||
|
||||
// Upload only the sub-rectangle [x, x+w) × [y, y+h) of the staging
|
||||
|
|
@ -365,15 +378,37 @@ export namespace Crafter {
|
|||
} else {
|
||||
TransitionImageLayout(cmd, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, layout, VK_PIPELINE_STAGE_TRANSFER_BIT, consumerStage, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, 0, mipLevels);
|
||||
}
|
||||
ReleaseStaging();
|
||||
}
|
||||
|
||||
void Destroy() {
|
||||
vkDestroyImageView(Device::device, imageView, nullptr);
|
||||
vkDestroyImage(Device::device, image, nullptr);
|
||||
vkFreeMemory(Device::device, imageMemory, nullptr);
|
||||
// Free any staging this image still owns: a streamed image's
|
||||
// persistent `buffer`, or either staging buffer on an image
|
||||
// destroyed before its first upload released them (issue #114).
|
||||
// ReleaseStaging()/Update already null released handles, so these
|
||||
// are no-ops then; Clear() is gated on a live handle so a static
|
||||
// texture (whose `buffer` was deferred-cleared) can't double-free.
|
||||
if (buffer.buffer != VK_NULL_HANDLE) buffer.Clear();
|
||||
if (compressedStaging.buffer != VK_NULL_HANDLE) compressedStaging.Clear();
|
||||
}
|
||||
|
||||
private:
|
||||
// Release the host-visible staging `buffer` after a one-shot upload,
|
||||
// unless this is a streamed image (FontAtlas) whose persistent map must
|
||||
// survive. The recorded buffer→image copy still references buffer.buffer,
|
||||
// so route through the fence-keyed deletion queue (#101/#102) instead of
|
||||
// an immediate Clear(): DeferredClear nulls the handle (so re-entry and
|
||||
// Destroy treat the staging as already gone) while the allocation
|
||||
// outlives this submit's frame. Issue #114.
|
||||
void ReleaseStaging() {
|
||||
if (!streamed) {
|
||||
buffer.DeferredClear();
|
||||
}
|
||||
}
|
||||
|
||||
void TransitionImageLayout(VkCommandBuffer cmd, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, VkPipelineStageFlags sourceStage, VkPipelineStageFlags destinationStage, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, std::uint32_t mipLevel, std::uint32_t count) {
|
||||
VkImageMemoryBarrier barrier = {};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue