some MSAA fixes

This commit is contained in:
MrPurple666 2025-05-13 05:47:14 -03:00
parent 38d18af8ba
commit 1ffa98a40d

View file

@ -1532,45 +1532,53 @@ void Image::UploadMemory(VkBuffer buffer, VkDeviceSize offset,
// Handle MSAA upload if necessary // Handle MSAA upload if necessary
if (info.num_samples > 1 && runtime->CanUploadMSAA()) { if (info.num_samples > 1 && runtime->CanUploadMSAA()) {
// Create a temporary non-MSAA image to upload the data first // Only use MSAA copy pass for color formats
ImageInfo temp_info = info; // Depth/stencil formats need special handling
temp_info.num_samples = 1; if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT) {
// Create a temporary non-MSAA image to upload the data first
ImageInfo temp_info = info;
temp_info.num_samples = 1;
vk::Image temp_image = MakeImage(runtime->device, runtime->memory_allocator, temp_info, // Create image with same usage flags as the target image to avoid validation errors
runtime->ViewFormats(info.format)); VkImageCreateInfo image_ci = MakeImageCreateInfo(runtime->device, temp_info);
image_ci.usage = original_image.UsageFlags();
vk::Image temp_image = runtime->memory_allocator.CreateImage(image_ci);
// Upload to the temporary non-MSAA image // Upload to the temporary non-MSAA image
scheduler->RequestOutsideRenderPassOperationContext(); scheduler->RequestOutsideRenderPassOperationContext();
auto vk_copies = TransformBufferImageCopies(copies, offset, aspect_mask); auto vk_copies = TransformBufferImageCopies(copies, offset, aspect_mask);
const VkBuffer src_buffer = buffer; const VkBuffer src_buffer = buffer;
const VkImage temp_vk_image = *temp_image; const VkImage temp_vk_image = *temp_image;
const VkImageAspectFlags vk_aspect_mask = aspect_mask; const VkImageAspectFlags vk_aspect_mask = aspect_mask;
scheduler->Record([src_buffer, temp_vk_image, vk_aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) { scheduler->Record([src_buffer, temp_vk_image, vk_aspect_mask, vk_copies](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);
}); });
// Now use MSAACopyPass to convert from non-MSAA to MSAA // Now use MSAACopyPass to convert from non-MSAA to MSAA
std::vector<VideoCommon::ImageCopy> image_copies; std::vector<VideoCommon::ImageCopy> image_copies;
for (const auto& copy : copies) { for (const auto& copy : copies) {
VideoCommon::ImageCopy image_copy; VideoCommon::ImageCopy image_copy;
image_copy.src_offset = {0, 0, 0}; // Use zero offset for source image_copy.src_offset = {0, 0, 0}; // Use zero offset for source
image_copy.dst_offset = copy.image_offset; image_copy.dst_offset = copy.image_offset;
image_copy.src_subresource = copy.image_subresource; image_copy.src_subresource = copy.image_subresource;
image_copy.dst_subresource = copy.image_subresource; image_copy.dst_subresource = copy.image_subresource;
image_copy.extent = copy.image_extent; image_copy.extent = copy.image_extent;
image_copies.push_back(image_copy); image_copies.push_back(image_copy);
}
// Create a wrapper Image for the temporary image
Image temp_wrapper(*runtime, temp_info, 0, 0);
temp_wrapper.original_image = std::move(temp_image);
temp_wrapper.current_image = &Image::original_image;
temp_wrapper.aspect_mask = aspect_mask;
temp_wrapper.initialized = true;
// Use MSAACopyPass to convert from non-MSAA to MSAA
runtime->msaa_copy_pass->CopyImage(*this, temp_wrapper, image_copies, false);
std::exchange(initialized, true);
return;
} }
// For depth/stencil formats, fall back to regular upload
// Create a wrapper Image for the temporary image
Image temp_wrapper(*runtime, temp_info, 0, 0);
temp_wrapper.original_image = std::move(temp_image);
temp_wrapper.current_image = &Image::original_image;
temp_wrapper.aspect_mask = aspect_mask;
temp_wrapper.initialized = true;
// Use MSAACopyPass to convert from non-MSAA to MSAA
runtime->msaa_copy_pass->CopyImage(*this, temp_wrapper, image_copies, false);
std::exchange(initialized, true);
} else { } else {
// Regular non-MSAA upload // Regular non-MSAA upload
scheduler->RequestOutsideRenderPassOperationContext(); scheduler->RequestOutsideRenderPassOperationContext();
@ -1614,101 +1622,109 @@ void Image::DownloadMemory(std::span<VkBuffer> buffers_span, std::span<size_t> o
// Handle MSAA download if necessary // Handle MSAA download if necessary
if (info.num_samples > 1 && runtime->msaa_copy_pass) { if (info.num_samples > 1 && runtime->msaa_copy_pass) {
// Create a temporary non-MSAA image to download the data // Only use MSAA copy pass for color formats
ImageInfo temp_info = info; // Depth/stencil formats need special handling
temp_info.num_samples = 1; if (aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT) {
// Create a temporary non-MSAA image to download the data
ImageInfo temp_info = info;
temp_info.num_samples = 1;
vk::Image temp_image = MakeImage(runtime->device, runtime->memory_allocator, temp_info, // Create image with same usage flags as the target image to avoid validation errors
runtime->ViewFormats(info.format)); VkImageCreateInfo image_ci = MakeImageCreateInfo(runtime->device, temp_info);
image_ci.usage = original_image.UsageFlags();
vk::Image temp_image = runtime->memory_allocator.CreateImage(image_ci);
// Create a wrapper Image for the temporary image // Create a wrapper Image for the temporary image
Image temp_wrapper(*runtime, temp_info, 0, 0); Image temp_wrapper(*runtime, temp_info, 0, 0);
temp_wrapper.original_image = std::move(temp_image); temp_wrapper.original_image = std::move(temp_image);
temp_wrapper.current_image = &Image::original_image; temp_wrapper.current_image = &Image::original_image;
temp_wrapper.aspect_mask = aspect_mask; temp_wrapper.aspect_mask = aspect_mask;
temp_wrapper.initialized = true; temp_wrapper.initialized = true;
// Convert from MSAA to non-MSAA using MSAACopyPass // Convert from MSAA to non-MSAA using MSAACopyPass
std::vector<VideoCommon::ImageCopy> image_copies; std::vector<VideoCommon::ImageCopy> image_copies;
for (const auto& copy : copies) { for (const auto& copy : copies) {
VideoCommon::ImageCopy image_copy; VideoCommon::ImageCopy image_copy;
image_copy.src_offset = copy.image_offset; image_copy.src_offset = copy.image_offset;
image_copy.dst_offset = copy.image_offset; image_copy.dst_offset = copy.image_offset;
image_copy.src_subresource = copy.image_subresource; image_copy.src_subresource = copy.image_subresource;
image_copy.dst_subresource = copy.image_subresource; image_copy.dst_subresource = copy.image_subresource;
image_copy.extent = copy.image_extent; image_copy.extent = copy.image_extent;
image_copies.push_back(image_copy); image_copies.push_back(image_copy);
}
// Use MSAACopyPass to convert from MSAA to non-MSAA
runtime->msaa_copy_pass->CopyImage(temp_wrapper, *this, image_copies, true);
// Now download from the non-MSAA image
boost::container::small_vector<VkBuffer, 8> buffers_vector{};
boost::container::small_vector<boost::container::small_vector<VkBufferImageCopy, 16>, 8>
vk_copies;
for (size_t index = 0; index < buffers_span.size(); index++) {
buffers_vector.emplace_back(buffers_span[index]);
vk_copies.emplace_back(
TransformBufferImageCopies(copies, offsets_span[index], aspect_mask));
}
scheduler->RequestOutsideRenderPassOperationContext();
scheduler->Record([buffers = std::move(buffers_vector), image = *temp_wrapper.original_image,
aspect_mask_ = aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) {
const VkImageMemoryBarrier read_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange{
.aspectMask = aspect_mask_,
.baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, read_barrier);
for (size_t index = 0; index < buffers.size(); index++) {
cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffers[index],
vk_copies[index]);
} }
const VkMemoryBarrier memory_write_barrier{ // Use MSAACopyPass to convert from MSAA to non-MSAA
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER, runtime->msaa_copy_pass->CopyImage(temp_wrapper, *this, image_copies, true);
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, // Now download from the non-MSAA image
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, boost::container::small_vector<VkBuffer, 8> buffers_vector{};
}; boost::container::small_vector<boost::container::small_vector<VkBufferImageCopy, 16>, 8>
const VkImageMemoryBarrier image_write_barrier{ vk_copies;
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, for (size_t index = 0; index < buffers_span.size(); index++) {
.pNext = nullptr, buffers_vector.emplace_back(buffers_span[index]);
.srcAccessMask = 0, vk_copies.emplace_back(
.dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT, TransformBufferImageCopies(copies, offsets_span[index], aspect_mask));
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, }
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, scheduler->RequestOutsideRenderPassOperationContext();
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, scheduler->Record([buffers = std::move(buffers_vector), image = *temp_wrapper.original_image,
.image = image, aspect_mask_ = aspect_mask, vk_copies](vk::CommandBuffer cmdbuf) {
.subresourceRange{ const VkImageMemoryBarrier read_barrier{
.aspectMask = aspect_mask_, .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.baseMipLevel = 0, .pNext = nullptr,
.levelCount = VK_REMAINING_MIP_LEVELS, .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
.baseArrayLayer = 0, .dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
.layerCount = VK_REMAINING_ARRAY_LAYERS, .oldLayout = VK_IMAGE_LAYOUT_GENERAL,
}, .newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
}; .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
0, memory_write_barrier, nullptr, image_write_barrier); .image = image,
}); .subresourceRange{
.aspectMask = aspect_mask_,
.baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
0, read_barrier);
for (size_t index = 0; index < buffers.size(); index++) {
cmdbuf.CopyImageToBuffer(image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffers[index],
vk_copies[index]);
}
const VkMemoryBarrier memory_write_barrier{
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
};
const VkImageMemoryBarrier image_write_barrier{
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.pNext = nullptr,
.srcAccessMask = 0,
.dstAccessMask = VK_ACCESS_MEMORY_WRITE_BIT,
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
.image = image,
.subresourceRange{
.aspectMask = aspect_mask_,
.baseMipLevel = 0,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
0, memory_write_barrier, nullptr, image_write_barrier);
});
return;
}
// For depth/stencil formats, fall back to regular download
} else { } else {
// Regular non-MSAA download // Regular non-MSAA download
boost::container::small_vector<VkBuffer, 8> buffers_vector{}; boost::container::small_vector<VkBuffer, 8> buffers_vector{};