[vk] texture

This commit is contained in:
wildcard 2025-10-04 12:41:21 +02:00
parent 14cf60bce8
commit 5ddb0b3d5f

View file

@ -144,8 +144,8 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
.imageType = ConvertImageType(info.type), .imageType = ConvertImageType(info.type),
.format = format_info.format, .format = format_info.format,
.extent{ .extent{
.width = info.size.width >> samples_x, .width = info.size.width,
.height = info.size.height >> samples_y, .height = info.size.height,
.depth = info.size.depth, .depth = info.size.depth,
}, },
.mipLevels = static_cast<u32>(info.resources.levels), .mipLevels = static_cast<u32>(info.resources.levels),
@ -962,23 +962,35 @@ void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
std::ranges::transform(copies, vk_out_copies.begin(), [dst_aspect_mask](const auto& copy) { std::ranges::transform(copies, vk_out_copies.begin(), [dst_aspect_mask](const auto& copy) {
return MakeBufferImageCopy(copy, false, dst_aspect_mask); return MakeBufferImageCopy(copy, false, dst_aspect_mask);
}); });
const u32 img_bpp = BytesPerBlock(dst.info.format);
size_t total_size = 0;
for (const auto& copy : copies) {
total_size += copy.extent.width * copy.extent.height * copy.extent.depth * img_bpp;
}
const VkBuffer copy_buffer = GetTemporaryBuffer(total_size);
const VkImage dst_image = dst.Handle(); const VkImage dst_image = dst.Handle();
const VkImage src_image = src.Handle(); const VkImage src_image = src.Handle();
scheduler.RequestOutsideRenderPassOperationContext(); scheduler.RequestOutsideRenderPassOperationContext();
auto vk_in_sp = std::make_shared<decltype(vk_in_copies)>(std::move(vk_in_copies));
auto vk_out_sp = std::make_shared<decltype(vk_out_copies)>(std::move(vk_out_copies));
// Assign per-region offsets and compute total staging size (block-aware, 4-byte aligned)
size_t staging_size = 0;
const u32 dst_block_w = DefaultBlockWidth(dst.info.format);
const u32 dst_block_h = DefaultBlockHeight(dst.info.format);
const size_t dst_block_bytes = BytesPerBlock(dst.info.format);
for (size_t i = 0; i < copies.size(); ++i) {
const auto& c = copies[i];
const u32 blocks_w = (c.extent.width + dst_block_w - 1) / dst_block_w;
const u32 blocks_h = (c.extent.height + dst_block_h - 1) / dst_block_h;
const size_t region_bytes = size_t(blocks_w) * blocks_h * c.extent.depth * dst_block_bytes;
(*vk_in_sp)[i].bufferOffset = static_cast<VkDeviceSize>(staging_size);
(*vk_out_sp)[i].bufferOffset = static_cast<VkDeviceSize>(staging_size);
// Vulkan requires bufferOffset to be a multiple of 4.
staging_size = (staging_size + region_bytes + 3) & ~size_t(3);
}
const VkBuffer copy_buffer = GetTemporaryBuffer(staging_size);
scheduler.Record([dst_image, src_image, copy_buffer, src_aspect_mask, dst_aspect_mask, scheduler.Record([dst_image, src_image, copy_buffer, src_aspect_mask, dst_aspect_mask,
vk_in_copies, vk_out_copies](vk::CommandBuffer cmdbuf) { vk_in_sp, vk_out_sp](vk::CommandBuffer cmdbuf) {
RangedBarrierRange dst_range; RangedBarrierRange dst_range;
RangedBarrierRange src_range; RangedBarrierRange src_range;
for (const VkBufferImageCopy& copy : vk_in_copies) { for (const VkBufferImageCopy& copy : *vk_in_sp) {
src_range.AddLayers(copy.imageSubresource); src_range.AddLayers(copy.imageSubresource);
} }
for (const VkBufferImageCopy& copy : vk_out_copies) { for (const VkBufferImageCopy& copy : *vk_out_sp) {
dst_range.AddLayers(copy.imageSubresource); dst_range.AddLayers(copy.imageSubresource);
} }
static constexpr VkMemoryBarrier READ_BARRIER{ static constexpr VkMemoryBarrier READ_BARRIER{
@ -1062,13 +1074,13 @@ void TextureCacheRuntime::ReinterpretImage(Image& dst, Image& src,
0, {}, {}, pre_barriers); 0, {}, {}, pre_barriers);
cmdbuf.CopyImageToBuffer(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, copy_buffer, cmdbuf.CopyImageToBuffer(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, copy_buffer,
vk_in_copies); *vk_in_sp);
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, WRITE_BARRIER, nullptr, middle_in_barrier); 0, WRITE_BARRIER, nullptr, middle_in_barrier);
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, READ_BARRIER, {}, middle_out_barrier); 0, READ_BARRIER, {}, middle_out_barrier);
cmdbuf.CopyBufferToImage(copy_buffer, dst_image, VK_IMAGE_LAYOUT_GENERAL, vk_out_copies); cmdbuf.CopyBufferToImage(copy_buffer, dst_image, VK_IMAGE_LAYOUT_GENERAL, *vk_out_sp);
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, {}, {}, post_barriers); 0, {}, {}, post_barriers);
}); });
@ -1397,10 +1409,11 @@ void TextureCacheRuntime::CopyImage(Image& dst, Image& src,
const VkImage dst_image = dst.Handle(); const VkImage dst_image = dst.Handle();
const VkImage src_image = src.Handle(); const VkImage src_image = src.Handle();
scheduler.RequestOutsideRenderPassOperationContext(); scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([dst_image, src_image, aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) { auto vk_copies_sp = std::make_shared<decltype(vk_copies)>(std::move(vk_copies));
scheduler.Record([dst_image, src_image, aspect_mask, vk_copies_sp](vk::CommandBuffer cmdbuf) {
RangedBarrierRange dst_range; RangedBarrierRange dst_range;
RangedBarrierRange src_range; RangedBarrierRange src_range;
for (const VkImageCopy& copy : vk_copies) { for (const VkImageCopy& copy : *vk_copies_sp) {
dst_range.AddLayers(copy.dstSubresource); dst_range.AddLayers(copy.dstSubresource);
src_range.AddLayers(copy.srcSubresource); src_range.AddLayers(copy.srcSubresource);
} }
@ -1471,7 +1484,7 @@ void TextureCacheRuntime::CopyImage(Image& dst, Image& src,
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, nullptr, nullptr, pre_barriers); 0, nullptr, nullptr, pre_barriers);
cmdbuf.CopyImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image, cmdbuf.CopyImage(src_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, vk_copies); VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, *vk_copies_sp);
cmdbuf.PipelineBarrier( cmdbuf.PipelineBarrier(
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT |
@ -1597,10 +1610,10 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset,
const VkBuffer src_buffer = buffer; const VkBuffer src_buffer = buffer;
const VkImage temp_vk_image = *temp_wrapper->original_image; const VkImage temp_vk_image = *temp_wrapper->original_image;
const VkImageAspectFlags vk_aspect_mask = temp_wrapper->aspect_mask; const VkImageAspectFlags vk_aspect_mask = temp_wrapper->aspect_mask;
auto vk_copies_sp = std::make_shared<decltype(vk_copies)>(std::move(vk_copies));
scheduler->Record([src_buffer, temp_vk_image, vk_aspect_mask, vk_copies, scheduler->Record([src_buffer, temp_vk_image, vk_aspect_mask, vk_copies_sp,
keep = temp_wrapper](vk::CommandBuffer cmdbuf) { keep = temp_wrapper](vk::CommandBuffer cmdbuf) {
CopyBufferToImage(cmdbuf, src_buffer, temp_vk_image, vk_aspect_mask, false, vk_copies); CopyBufferToImage(cmdbuf, src_buffer, temp_vk_image, vk_aspect_mask, false, *vk_copies_sp);
}); });
// Use MSAACopyPass to convert from non-MSAA to MSAA // Use MSAACopyPass to convert from non-MSAA to MSAA
@ -1632,14 +1645,15 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset,
// Regular non-MSAA upload (original behavior preserved) // Regular non-MSAA upload (original behavior preserved)
scheduler->RequestOutsideRenderPassOperationContext(); scheduler->RequestOutsideRenderPassOperationContext();
auto vk_copies = TransformBufferImageCopies(copies, offset, aspect_mask); auto vk_copies = TransformBufferImageCopies(copies, offset, aspect_mask);
auto vk_copies_sp = std::make_shared<decltype(vk_copies)>(std::move(vk_copies));
const VkBuffer src_buffer = buffer; const VkBuffer src_buffer = buffer;
const VkImage vk_image = *original_image; const VkImage vk_image = *original_image;
const VkImageAspectFlags vk_aspect_mask = aspect_mask; const VkImageAspectFlags vk_aspect_mask = aspect_mask;
const bool was_initialized = std::exchange(initialized, true); const bool is_initialized = std::exchange(initialized, true);
scheduler->Record([src_buffer, vk_image, vk_aspect_mask, is_initialized, vk_copies_sp]
scheduler->Record([src_buffer, vk_image, vk_aspect_mask, was_initialized, (vk::CommandBuffer cmdbuf) {
vk_copies](vk::CommandBuffer cmdbuf) { CopyBufferToImage(cmdbuf, src_buffer, vk_image, vk_aspect_mask, is_initialized,
CopyBufferToImage(cmdbuf, src_buffer, vk_image, vk_aspect_mask, was_initialized, vk_copies); *vk_copies_sp);
}); });
if (is_rescaled) { if (is_rescaled) {
@ -1678,13 +1692,11 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
VkImageCreateInfo image_ci = MakeImageCreateInfo(runtime->device, temp_info); VkImageCreateInfo image_ci = MakeImageCreateInfo(runtime->device, temp_info);
image_ci.usage = original_image.UsageFlags(); image_ci.usage = original_image.UsageFlags();
vk::Image temp_image = runtime->memory_allocator.CreateImage(image_ci); auto temp_wrapper = std::make_shared<Image>(*runtime, temp_info, 0, 0);
temp_wrapper->original_image = runtime->memory_allocator.CreateImage(image_ci);
Image temp_wrapper(*runtime, temp_info, 0, 0); temp_wrapper->current_image = &Image::original_image;
temp_wrapper.original_image = std::move(temp_image); temp_wrapper->aspect_mask = aspect_mask;
temp_wrapper.current_image = &Image::original_image; temp_wrapper->initialized = true;
temp_wrapper.aspect_mask = aspect_mask;
temp_wrapper.initialized = true;
std::vector<VideoCommon::ImageCopy> image_copies; std::vector<VideoCommon::ImageCopy> image_copies;
for (const auto& copy : copies) { for (const auto& copy : copies) {
@ -1697,7 +1709,7 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
image_copies.push_back(image_copy); image_copies.push_back(image_copy);
} }
runtime->msaa_copy_pass->CopyImage(temp_wrapper, *this, image_copies, true); runtime->msaa_copy_pass->CopyImage(*temp_wrapper, *this, image_copies, true);
boost::container::small_vector<VkBuffer, 8> buffers_vector{}; boost::container::small_vector<VkBuffer, 8> buffers_vector{};
boost::container::small_vector<boost::container::small_vector<VkBufferImageCopy, 16>, 8> boost::container::small_vector<boost::container::small_vector<VkBufferImageCopy, 16>, 8>
@ -1709,8 +1721,13 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
} }
scheduler->RequestOutsideRenderPassOperationContext(); scheduler->RequestOutsideRenderPassOperationContext();
scheduler->Record([buffers = std::move(buffers_vector), image = *temp_wrapper.original_image, auto buffers_sp = std::make_shared<decltype(buffers_vector)>(std::move(buffers_vector));
aspect_mask_ = aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) { auto vk_copies_sp = std::make_shared<decltype(vk_copies)>(std::move(vk_copies));
scheduler->Record([buffers_sp,
image = *temp_wrapper->original_image,
aspect_mask_ = aspect_mask,
vk_copies_sp,
keep = temp_wrapper](vk::CommandBuffer cmdbuf) {
const VkImageMemoryBarrier read_barrier{ const VkImageMemoryBarrier read_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr, .pNext = nullptr,
@ -1732,9 +1749,9 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, read_barrier); 0, read_barrier);
for (size_t index = 0; index < buffers.size(); index++) { for (size_t index = 0; index < buffers_sp->size(); ++index) {
cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffers[index], cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
vk_copies[index]); (*buffers_sp)[index], (*vk_copies_sp)[index]);
} }
const VkMemoryBarrier memory_write_barrier{ const VkMemoryBarrier memory_write_barrier{
@ -1776,8 +1793,10 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
TransformBufferImageCopies(copies, offsets_span[index], aspect_mask)); TransformBufferImageCopies(copies, offsets_span[index], aspect_mask));
} }
scheduler->RequestOutsideRenderPassOperationContext(); scheduler->RequestOutsideRenderPassOperationContext();
scheduler->Record([buffers = std::move(buffers_vector), image = *original_image, auto buffers_sp = std::make_shared<decltype(buffers_vector)>(std::move(buffers_vector));
aspect_mask_ = aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) { auto vk_copies_sp = std::make_shared<decltype(vk_copies)>(std::move(vk_copies));
scheduler->Record([buffers_sp, image = *original_image,
aspect_mask_ = aspect_mask, vk_copies_sp](vk::CommandBuffer cmdbuf) {
const VkImageMemoryBarrier read_barrier{ const VkImageMemoryBarrier read_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr, .pNext = nullptr,
@ -1799,9 +1818,9 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, read_barrier); 0, read_barrier);
for (size_t index = 0; index < buffers.size(); index++) { for (size_t index = 0; index < buffers_sp->size(); index++) {
cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffers[index], cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, (*buffers_sp)[index],
vk_copies[index]); (*vk_copies_sp)[index]);
} }
const VkMemoryBarrier memory_write_barrier{ const VkMemoryBarrier memory_write_barrier{