mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-06 14:09:58 +00:00
Address some corrections towards MSAA discard/enable removal
This commit is contained in:
@@ -690,9 +690,7 @@ void BlitImageHelper::BlitColor(const Framebuffer* dst_framebuffer, VkImageView
|
||||
};
|
||||
const VkPipelineLayout layout = *one_texture_pipeline_layout;
|
||||
const VkPipeline pipeline = FindOrEmplaceColorPipeline(key);
|
||||
const auto attachments =
|
||||
std::span(dst_framebuffer->Images()).first(dst_framebuffer->NumImages());
|
||||
if (std::ranges::find(attachments, src_image) != attachments.end()) {
|
||||
if (scheduler.IsRenderPassImage(src_image)) {
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
}
|
||||
scheduler.RequestRenderpass(dst_framebuffer);
|
||||
@@ -958,9 +956,14 @@ void BlitImageHelper::CopyMSAAImpl(const RenderingFormats& formats, VkPipeline p
|
||||
.extent = dst_extent,
|
||||
};
|
||||
const VkImageView dst_view_handle = *dst_view;
|
||||
const RenderingAttachments attachments =
|
||||
RenderingAttachments attachments =
|
||||
MakeRenderingAttachments(formats, std::span(&dst_view_handle, formats.num_colors),
|
||||
dst_view_handle, render_area, 1);
|
||||
attachments.colors[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachments.depth.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
if (copy_stencil) {
|
||||
attachments.stencil.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
}
|
||||
const MSAACopyPushConstants push_constants{
|
||||
.dst_offset = {dst_offset.x, dst_offset.y},
|
||||
.src_offset = {copy.src_offset.x, copy.src_offset.y},
|
||||
|
||||
@@ -575,8 +575,16 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
prepare_stage(4);
|
||||
}
|
||||
texture_cache.UpdateRenderTargets(false);
|
||||
texture_cache.CheckFeedbackLoop(std::span<const VideoCommon::ImageViewInOut>{views.data(),
|
||||
views.size()});
|
||||
const std::span<const VideoCommon::ImageViewInOut> view_span{views.data(), views.size()};
|
||||
texture_cache.CheckFeedbackLoop(view_span);
|
||||
const auto samples_render_pass_image = [&](const VideoCommon::ImageViewInOut& view) {
|
||||
return view.id &&
|
||||
scheduler.IsRenderPassImage(texture_cache.GetImageView(view.id).ImageHandle());
|
||||
};
|
||||
if (scheduler.CanAliasRenderPass(texture_cache.GetFramebuffer()) &&
|
||||
std::ranges::any_of(view_span, samples_render_pass_image)) {
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
}
|
||||
if (IsBuilt() && !pipeline) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,12 @@ using Tegra::Engines::Maxwell3D;
|
||||
using VideoCommon::QueryType;
|
||||
|
||||
namespace {
|
||||
bool LacksQueryWriteBack(const Device& device) {
|
||||
const VkDriverId driver_id = device.GetDriverID();
|
||||
return driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY ||
|
||||
driver_id == VK_DRIVER_ID_ARM_PROPRIETARY || driver_id == VK_DRIVER_ID_MESA_TURNIP;
|
||||
}
|
||||
|
||||
class SamplesQueryBank : public VideoCommon::BankBase {
|
||||
public:
|
||||
static constexpr size_t BANK_SIZE = 256;
|
||||
@@ -235,9 +241,7 @@ public:
|
||||
return;
|
||||
}
|
||||
PauseCounter();
|
||||
const auto driver_id = device.GetDriverID();
|
||||
if (driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY ||
|
||||
driver_id == VK_DRIVER_ID_ARM_PROPRIETARY || driver_id == VK_DRIVER_ID_MESA_TURNIP) {
|
||||
if (LacksQueryWriteBack(device)) {
|
||||
pending_sync.clear();
|
||||
sync_values_stash.clear();
|
||||
return;
|
||||
@@ -1467,6 +1471,10 @@ bool QueryCacheRuntime::HostConditionalRenderingCompareValue(VideoCommon::Lookup
|
||||
if (!impl->device.IsExtConditionalRendering()) {
|
||||
return false;
|
||||
}
|
||||
if (LacksQueryWriteBack(impl->device)) {
|
||||
EndHostConditionalRendering();
|
||||
return true;
|
||||
}
|
||||
HostConditionalRenderingCompareBCImpl(object_1.address, true, true);
|
||||
return true;
|
||||
}
|
||||
@@ -1516,7 +1524,8 @@ bool QueryCacheRuntime::HostConditionalRenderingCompareValues(VideoCommon::Looku
|
||||
auto driver_id = impl->device.GetDriverID();
|
||||
const bool is_gpu_high = Settings::IsGPULevelHigh();
|
||||
|
||||
if ((!is_gpu_high && driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) || driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY || driver_id == VK_DRIVER_ID_ARM_PROPRIETARY || driver_id == VK_DRIVER_ID_MESA_TURNIP) {
|
||||
if ((!is_gpu_high && driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) ||
|
||||
LacksQueryWriteBack(impl->device)) {
|
||||
EndHostConditionalRendering();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
|
||||
namespace Vulkan {
|
||||
namespace {
|
||||
constexpr size_t DEPTH_VIEW = 8;
|
||||
|
||||
struct BeginRenderingCommand {
|
||||
void operator()(vk::CommandBuffer cmdbuf, vk::CommandBuffer) const {
|
||||
BeginRendering(cmdbuf, attachments);
|
||||
@@ -37,6 +39,24 @@ struct BeginRenderingCommand {
|
||||
|
||||
RenderingAttachments attachments;
|
||||
};
|
||||
|
||||
VkImageView DepthStencilView(const RenderingAttachments& attachments) {
|
||||
if (attachments.depth.imageView != VK_NULL_HANDLE) {
|
||||
return attachments.depth.imageView;
|
||||
}
|
||||
return attachments.stencil.imageView;
|
||||
}
|
||||
|
||||
VkAccessFlags2 AttachmentWriteAccess(VkImageAspectFlags aspect_mask) {
|
||||
if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
|
||||
return VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) {
|
||||
return VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
return VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT |
|
||||
VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void Scheduler::CommandChunk::ExecuteAll(vk::CommandBuffer cmdbuf,
|
||||
@@ -129,6 +149,12 @@ void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer) {
|
||||
state.framebuffer_id = framebuffer->Id();
|
||||
++renderpass_serial;
|
||||
renderpass_pristine = true;
|
||||
alias_framebuffer_id = 0;
|
||||
std::ranges::transform(attachments.colors, renderpass_views.begin(),
|
||||
&VkRenderingAttachmentInfo::imageView);
|
||||
renderpass_views[DEPTH_VIEW] = DepthStencilView(attachments);
|
||||
renderpass_extent = attachments.render_area.extent;
|
||||
renderpass_layers = attachments.layers;
|
||||
attachments_touched = 0;
|
||||
attachments_written = 0;
|
||||
|
||||
@@ -153,11 +179,49 @@ void Scheduler::BeginRenderPassImpl(const Framebuffer* framebuffer) {
|
||||
framebuffer->MarkResolveShadowsUpToDate();
|
||||
}
|
||||
|
||||
void Scheduler::RequestRenderpass(const Framebuffer* framebuffer, u32 touched, u32 written) {
|
||||
if (framebuffer->Id() != state.framebuffer_id) {
|
||||
EndRenderPass();
|
||||
BeginRenderPassImpl(framebuffer);
|
||||
void Scheduler::BindFramebuffer(const Framebuffer* framebuffer) {
|
||||
if (framebuffer->Id() == state.framebuffer_id) {
|
||||
return;
|
||||
}
|
||||
if (CanAliasRenderPass(framebuffer)) {
|
||||
alias_framebuffer_id = framebuffer->Id();
|
||||
return;
|
||||
}
|
||||
EndRenderPass();
|
||||
BeginRenderPassImpl(framebuffer);
|
||||
}
|
||||
|
||||
bool Scheduler::CanAliasRenderPass(const Framebuffer* framebuffer) const {
|
||||
const u64 id = framebuffer->Id();
|
||||
if (id == alias_framebuffer_id) {
|
||||
return true;
|
||||
}
|
||||
if (id == state.framebuffer_id || state.framebuffer_id == 0 ||
|
||||
!device.IsExtDynamicRenderingUnusedAttachmentsSupported()) {
|
||||
return false;
|
||||
}
|
||||
const RenderingAttachments& attachments = framebuffer->Attachments();
|
||||
if (attachments.layers != renderpass_layers ||
|
||||
attachments.render_area.extent.width != renderpass_extent.width ||
|
||||
attachments.render_area.extent.height != renderpass_extent.height) {
|
||||
return false;
|
||||
}
|
||||
for (u32 slot = 0; slot < attachments.num_colors; ++slot) {
|
||||
if (attachments.colors[slot].imageView != renderpass_views[slot]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const VkImageView depth_stencil = DepthStencilView(attachments);
|
||||
return depth_stencil == VK_NULL_HANDLE || depth_stencil == renderpass_views[DEPTH_VIEW];
|
||||
}
|
||||
|
||||
bool Scheduler::IsRenderPassImage(VkImage image) const {
|
||||
const auto images = std::span(renderpass_images).first(num_renderpass_images);
|
||||
return std::ranges::find(images, image) != images.end();
|
||||
}
|
||||
|
||||
void Scheduler::RequestRenderpass(const Framebuffer* framebuffer, u32 touched, u32 written) {
|
||||
BindFramebuffer(framebuffer);
|
||||
renderpass_pristine = false;
|
||||
attachments_touched |= touched;
|
||||
attachments_written |= written;
|
||||
@@ -165,10 +229,7 @@ void Scheduler::RequestRenderpass(const Framebuffer* framebuffer, u32 touched, u
|
||||
|
||||
bool Scheduler::OverrideLoadOps(const Framebuffer* framebuffer, u32 attachments,
|
||||
VkAttachmentLoadOp load_op, const VkClearValue& value) {
|
||||
if (framebuffer->Id() != state.framebuffer_id) {
|
||||
EndRenderPass();
|
||||
BeginRenderPassImpl(framebuffer);
|
||||
}
|
||||
BindFramebuffer(framebuffer);
|
||||
if (!renderpass_pristine || recorded_attachments == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@@ -252,6 +313,36 @@ void Scheduler::RelaxAttachmentOps(RenderingAttachments& attachments) const {
|
||||
}
|
||||
}
|
||||
|
||||
u32 Scheduler::RefineImageAccesses(const RenderingAttachments& attachments,
|
||||
std::array<VkAccessFlags2, 9>& accesses) const {
|
||||
const auto stores = [](const VkRenderingAttachmentInfo& attachment) {
|
||||
return attachment.imageView != VK_NULL_HANDLE &&
|
||||
attachment.storeOp != VK_ATTACHMENT_STORE_OP_NONE;
|
||||
};
|
||||
u32 unused_images = 0;
|
||||
u32 image = 0;
|
||||
const auto refine = [&](bool used, bool stored) {
|
||||
if (!used) {
|
||||
unused_images |= 1u << image;
|
||||
}
|
||||
if (!stored) {
|
||||
accesses[image] = 0;
|
||||
}
|
||||
++image;
|
||||
};
|
||||
for (u32 slot = 0; slot < attachments.num_colors; ++slot) {
|
||||
if (renderpass_views[slot] != VK_NULL_HANDLE) {
|
||||
const VkRenderingAttachmentInfo& color = attachments.colors[slot];
|
||||
refine(color.imageView != VK_NULL_HANDLE, stores(color));
|
||||
}
|
||||
}
|
||||
if (renderpass_views[DEPTH_VIEW] != VK_NULL_HANDLE) {
|
||||
refine(DepthStencilView(attachments) != VK_NULL_HANDLE,
|
||||
stores(attachments.depth) || stores(attachments.stencil));
|
||||
}
|
||||
return unused_images;
|
||||
}
|
||||
|
||||
void Scheduler::PublishComputeWrites() {
|
||||
if (!std::exchange(compute_writes, false)) {
|
||||
return;
|
||||
@@ -428,78 +519,68 @@ void Scheduler::EndPendingOperations() {
|
||||
EndRenderPass();
|
||||
}
|
||||
|
||||
void Scheduler::EndRenderPass()
|
||||
{
|
||||
if (state.framebuffer_id == 0) {
|
||||
return;
|
||||
}
|
||||
if (recorded_attachments != nullptr) {
|
||||
RelaxAttachmentOps(*recorded_attachments);
|
||||
}
|
||||
ended_attachments = std::exchange(recorded_attachments, nullptr);
|
||||
void Scheduler::EndRenderPass() {
|
||||
if (state.framebuffer_id == 0) {
|
||||
return;
|
||||
}
|
||||
std::array<VkAccessFlags2, 9> accesses{};
|
||||
for (u32 index = 0; index < num_renderpass_images; ++index) {
|
||||
accesses[index] = AttachmentWriteAccess(renderpass_image_ranges[index].aspectMask);
|
||||
}
|
||||
u32 unused_images = 0;
|
||||
if (recorded_attachments != nullptr) {
|
||||
RelaxAttachmentOps(*recorded_attachments);
|
||||
unused_images = RefineImageAccesses(*recorded_attachments, accesses);
|
||||
}
|
||||
ended_attachments = std::exchange(recorded_attachments, nullptr);
|
||||
|
||||
query_cache->CounterClose(VideoCommon::QueryType::StreamingByteCount);
|
||||
query_cache->CounterClose(VideoCommon::QueryType::StreamingByteCount);
|
||||
|
||||
// Log render pass end
|
||||
if (GPU::Logging::IsActive() &&
|
||||
Settings::values.gpu_log_vulkan_calls.GetValue()) {
|
||||
GPU::Logging::GPULogger::GetInstance().LogRenderPassEnd();
|
||||
}
|
||||
|
||||
query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false);
|
||||
query_cache->NotifySegment(false);
|
||||
|
||||
Record([num_images = num_renderpass_images,
|
||||
images = renderpass_images,
|
||||
ranges = renderpass_image_ranges,
|
||||
write_barrier = &renderpass_write_barrier,
|
||||
num_memory_barriers =
|
||||
static_cast<size_t>(std::exchange(renderpass_writes, false))](
|
||||
vk::CommandBuffer cmdbuf) {
|
||||
std::array<VkImageMemoryBarrier2, 9> barriers;
|
||||
for (size_t i = 0; i < num_images; ++i) {
|
||||
const VkImageSubresourceRange& range = ranges[i];
|
||||
const bool is_color = (range.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) != 0;
|
||||
const bool is_depth_stencil = (range.aspectMask
|
||||
& (VK_IMAGE_ASPECT_DEPTH_BIT
|
||||
| VK_IMAGE_ASPECT_STENCIL_BIT)) !=0;
|
||||
|
||||
VkAccessFlags2 src_access = 0;
|
||||
|
||||
if (is_color)
|
||||
src_access |= VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
else if (is_depth_stencil)
|
||||
src_access |= VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
else
|
||||
src_access |= VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT
|
||||
| VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
|
||||
barriers[i] = VkImageMemoryBarrier2{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT
|
||||
| VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT
|
||||
| VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
.srcAccessMask = src_access,
|
||||
.dstStageMask = vk::PIPELINE_STAGE_IMAGE_USERS,
|
||||
.dstAccessMask = vk::ACCESS_IMAGE_USERS,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = images[i],
|
||||
.subresourceRange = range,
|
||||
};
|
||||
}
|
||||
cmdbuf.EndRendering();
|
||||
cmdbuf.PipelineBarrier(0, vk::Span(write_barrier, num_memory_barriers), {},
|
||||
vk::Span(barriers.data(), num_images));
|
||||
});
|
||||
|
||||
state.framebuffer_id = 0;
|
||||
num_renderpass_images = 0;
|
||||
// Log render pass end
|
||||
if (GPU::Logging::IsActive() && Settings::values.gpu_log_vulkan_calls.GetValue()) {
|
||||
GPU::Logging::GPULogger::GetInstance().LogRenderPassEnd();
|
||||
}
|
||||
|
||||
query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false);
|
||||
query_cache->NotifySegment(false);
|
||||
|
||||
Record([num_images = num_renderpass_images, images = renderpass_images,
|
||||
ranges = renderpass_image_ranges, accesses, unused_images,
|
||||
write_barrier = &renderpass_write_barrier,
|
||||
num_memory_barriers = static_cast<size_t>(std::exchange(renderpass_writes, false))](
|
||||
vk::CommandBuffer cmdbuf) {
|
||||
std::array<VkImageMemoryBarrier2, 9> barriers;
|
||||
size_t num_barriers = 0;
|
||||
for (size_t i = 0; i < num_images; ++i) {
|
||||
if (((unused_images >> i) & 1) != 0) {
|
||||
continue;
|
||||
}
|
||||
barriers[num_barriers++] = VkImageMemoryBarrier2{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = vk::PIPELINE_STAGE_ATTACHMENTS,
|
||||
.srcAccessMask = accesses[i],
|
||||
.dstStageMask = vk::PIPELINE_STAGE_IMAGE_USERS,
|
||||
.dstAccessMask = vk::ACCESS_IMAGE_USERS,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = images[i],
|
||||
.subresourceRange = ranges[i],
|
||||
};
|
||||
}
|
||||
cmdbuf.EndRendering();
|
||||
if (num_barriers + num_memory_barriers != 0) {
|
||||
cmdbuf.PipelineBarrier(0, vk::Span(write_barrier, num_memory_barriers), {},
|
||||
vk::Span(barriers.data(), num_barriers));
|
||||
}
|
||||
});
|
||||
|
||||
state.framebuffer_id = 0;
|
||||
alias_framebuffer_id = 0;
|
||||
num_renderpass_images = 0;
|
||||
}
|
||||
|
||||
void Scheduler::AcquireNewChunk() {
|
||||
std::scoped_lock rl{reserve_mutex};
|
||||
|
||||
@@ -71,6 +71,10 @@ public:
|
||||
|
||||
void DiscardResolvedAttachments(VkImageView resolve_view);
|
||||
|
||||
bool CanAliasRenderPass(const Framebuffer* framebuffer) const;
|
||||
|
||||
bool IsRenderPassImage(VkImage image) const;
|
||||
|
||||
/// Requests the current execution context to be able to execute operations only allowed outside
|
||||
/// of a renderpass.
|
||||
void RequestOutsideRenderPassOperationContext();
|
||||
@@ -300,6 +304,8 @@ private:
|
||||
|
||||
void BeginRenderPassImpl(const Framebuffer* framebuffer);
|
||||
|
||||
void BindFramebuffer(const Framebuffer* framebuffer);
|
||||
|
||||
void WorkerThread(std::stop_token stop_token);
|
||||
|
||||
void AllocateWorkerCommandBuffer();
|
||||
@@ -314,6 +320,9 @@ private:
|
||||
|
||||
void RelaxAttachmentOps(RenderingAttachments& attachments) const;
|
||||
|
||||
u32 RefineImageAccesses(const RenderingAttachments& attachments,
|
||||
std::array<VkAccessFlags2, 9>& accesses) const;
|
||||
|
||||
void AcquireNewChunk();
|
||||
|
||||
const Device& device;
|
||||
@@ -333,6 +342,7 @@ private:
|
||||
State state;
|
||||
|
||||
u64 renderpass_serial = 0;
|
||||
u64 alias_framebuffer_id = 0;
|
||||
u64 wfi_serial = 0;
|
||||
bool renderpass_writes = false;
|
||||
bool renderpass_pristine = false;
|
||||
@@ -347,6 +357,9 @@ private:
|
||||
u32 num_renderpass_images = 0;
|
||||
std::array<VkImage, 9> renderpass_images{};
|
||||
std::array<VkImageSubresourceRange, 9> renderpass_image_ranges{};
|
||||
std::array<VkImageView, 9> renderpass_views{};
|
||||
VkExtent2D renderpass_extent{};
|
||||
u32 renderpass_layers = 0;
|
||||
|
||||
std::queue<std::unique_ptr<CommandChunk>> work_queue;
|
||||
std::vector<std::unique_ptr<CommandChunk>> chunk_reserve;
|
||||
|
||||
@@ -1373,7 +1373,24 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
|
||||
return;
|
||||
}
|
||||
ASSERT(src.format == dst.format);
|
||||
if (is_src_msaa && !is_dst_msaa &&
|
||||
const bool is_resolve = is_src_msaa && !is_dst_msaa;
|
||||
if (ENABLE_MSAA_RESOLVE_CONSUME && is_resolve && HaveSameExtent(dst_region, src_region)) {
|
||||
const VkImageResolve2 resolve = MakeImageResolve(
|
||||
dst_region, src_region, MakeSubresourceLayers(&dst), MakeSubresourceLayers(&src));
|
||||
const VkImageCopy2 region{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_COPY_2,
|
||||
.pNext = nullptr,
|
||||
.srcSubresource = resolve.srcSubresource,
|
||||
.srcOffset = resolve.srcOffset,
|
||||
.dstSubresource = resolve.dstSubresource,
|
||||
.dstOffset = resolve.dstOffset,
|
||||
.extent = resolve.extent,
|
||||
};
|
||||
if (CopyResolveShadow(src.ImageHandle(), dst.ImageHandle(), region)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (is_resolve &&
|
||||
(aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) {
|
||||
if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) == 0) {
|
||||
UNIMPLEMENTED_MSG("Stencil-only MSAA resolve is not supported");
|
||||
@@ -1416,7 +1433,6 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
|
||||
return;
|
||||
}
|
||||
|
||||
const bool is_resolve = is_src_msaa && !is_dst_msaa;
|
||||
if (is_resolve && !HaveSameExtent(dst_region, src_region)) {
|
||||
blit_image_helper.BlitColorMSAA(dst_framebuffer, src, dst_region, src_region);
|
||||
return;
|
||||
@@ -1729,120 +1745,126 @@ void TextureCacheRuntime::CopyImage(Image& dst, Image& src,
|
||||
});
|
||||
}
|
||||
|
||||
bool TextureCacheRuntime::CopyResolveShadow(VkImage msaa_image, VkImage dst_image,
|
||||
const VkImageCopy2& region) {
|
||||
const ResolveShadow* const shadow = GetValidResolveShadow(msaa_image);
|
||||
if (shadow == nullptr || shadow->aspect_mask != region.srcSubresource.aspectMask ||
|
||||
region.srcSubresource.mipLevel != 0 || region.srcOffset.x < 0 || region.srcOffset.y < 0 ||
|
||||
static_cast<u32>(region.srcOffset.x) + region.extent.width > shadow->extent.width ||
|
||||
static_cast<u32>(region.srcOffset.y) + region.extent.height > shadow->extent.height ||
|
||||
region.srcSubresource.baseArrayLayer + region.srcSubresource.layerCount >
|
||||
shadow->layers) {
|
||||
return false;
|
||||
}
|
||||
const VkImageAspectFlags aspect_mask = shadow->aspect_mask;
|
||||
const VkImage shadow_image = *shadow->image;
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([shadow_image, dst_image, region, aspect_mask](vk::CommandBuffer cmdbuf) {
|
||||
const std::array pre_barriers{
|
||||
VkImageMemoryBarrier2{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = vk::PIPELINE_STAGE_IMAGE_USERS,
|
||||
.srcAccessMask = vk::ACCESS_IMAGE_WRITES,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
|
||||
.dstAccessMask = VK_ACCESS_2_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 = shadow_image,
|
||||
.subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
VK_REMAINING_ARRAY_LAYERS},
|
||||
},
|
||||
VkImageMemoryBarrier2{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = vk::PIPELINE_STAGE_IMAGE_USERS,
|
||||
.srcAccessMask = vk::ACCESS_IMAGE_WRITES,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
|
||||
.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = dst_image,
|
||||
.subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
VK_REMAINING_ARRAY_LAYERS},
|
||||
},
|
||||
};
|
||||
const std::array post_barriers{
|
||||
VkImageMemoryBarrier2{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
|
||||
.srcAccessMask = 0,
|
||||
.dstStageMask = vk::PIPELINE_STAGE_IMAGE_USERS,
|
||||
.dstAccessMask = vk::ACCESS_IMAGE_USERS,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = shadow_image,
|
||||
.subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
VK_REMAINING_ARRAY_LAYERS},
|
||||
},
|
||||
VkImageMemoryBarrier2{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
|
||||
.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
|
||||
.dstStageMask = vk::PIPELINE_STAGE_IMAGE_USERS,
|
||||
.dstAccessMask = vk::ACCESS_IMAGE_USERS,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = dst_image,
|
||||
.subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
VK_REMAINING_ARRAY_LAYERS},
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(0, {}, {}, pre_barriers);
|
||||
cmdbuf.CopyImage(shadow_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, region);
|
||||
cmdbuf.PipelineBarrier(0, {}, {}, post_barriers);
|
||||
});
|
||||
const bool is_color = aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
if ((is_color && ENABLE_MSAA_COLOR_DISCARD) ||
|
||||
(!is_color && ENABLE_MSAA_DEPTH_STENCIL_DISCARD)) {
|
||||
scheduler.DiscardResolvedAttachments(*shadow->view);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src,
|
||||
std::span<const VideoCommon::ImageCopy> copies) {
|
||||
const bool msaa_to_non_msaa = src.info.num_samples > 1 && dst.info.num_samples == 1;
|
||||
const u32 num_samples = msaa_to_non_msaa ? src.info.num_samples : dst.info.num_samples;
|
||||
if (ENABLE_MSAA_RESOLVE_CONSUME && msaa_to_non_msaa && copies.size() == 1 &&
|
||||
src.info.format == dst.info.format) {
|
||||
src.info.format == dst.info.format && copies.front().src_offset.x == 0 &&
|
||||
copies.front().src_offset.y == 0) {
|
||||
const VideoCommon::ImageCopy& copy = copies.front();
|
||||
const ResolveShadow* const shadow = GetValidResolveShadow(src.Handle());
|
||||
if (shadow != nullptr && shadow->aspect_mask == dst.AspectMask() &&
|
||||
copy.src_offset.x == 0 && copy.src_offset.y == 0 &&
|
||||
copy.src_subresource.base_level == 0 &&
|
||||
static_cast<u32>(copy.extent.width) <= shadow->extent.width &&
|
||||
static_cast<u32>(copy.extent.height) <= shadow->extent.height &&
|
||||
static_cast<u32>(copy.src_subresource.base_layer + copy.src_subresource.num_layers) <=
|
||||
shadow->layers) {
|
||||
const VkImageAspectFlags aspect_mask = shadow->aspect_mask;
|
||||
const VkImage shadow_image = *shadow->image;
|
||||
const VkImage dst_image = dst.Handle();
|
||||
const VkImageCopy2 region{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_COPY_2,
|
||||
.pNext = nullptr,
|
||||
.srcSubresource{
|
||||
.aspectMask = aspect_mask,
|
||||
.mipLevel = 0,
|
||||
.baseArrayLayer = static_cast<u32>(copy.src_subresource.base_layer),
|
||||
.layerCount = static_cast<u32>(copy.src_subresource.num_layers),
|
||||
},
|
||||
.srcOffset = {0, 0, 0},
|
||||
.dstSubresource{
|
||||
.aspectMask = aspect_mask,
|
||||
.mipLevel = static_cast<u32>(copy.dst_subresource.base_level),
|
||||
.baseArrayLayer = static_cast<u32>(copy.dst_subresource.base_layer),
|
||||
.layerCount = static_cast<u32>(copy.dst_subresource.num_layers),
|
||||
},
|
||||
.dstOffset = {copy.dst_offset.x, copy.dst_offset.y, copy.dst_offset.z},
|
||||
.extent = {copy.extent.width, copy.extent.height, 1},
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([shadow_image, dst_image, region,
|
||||
aspect_mask](vk::CommandBuffer cmdbuf) {
|
||||
const std::array pre_barriers{
|
||||
VkImageMemoryBarrier2{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = vk::PIPELINE_STAGE_IMAGE_USERS,
|
||||
.srcAccessMask = vk::ACCESS_IMAGE_WRITES,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
|
||||
.dstAccessMask = VK_ACCESS_2_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 = shadow_image,
|
||||
.subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
VK_REMAINING_ARRAY_LAYERS},
|
||||
},
|
||||
VkImageMemoryBarrier2{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = vk::PIPELINE_STAGE_IMAGE_USERS,
|
||||
.srcAccessMask = vk::ACCESS_IMAGE_WRITES,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
|
||||
.dstAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = dst_image,
|
||||
.subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
VK_REMAINING_ARRAY_LAYERS},
|
||||
},
|
||||
};
|
||||
const std::array post_barriers{
|
||||
VkImageMemoryBarrier2{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
|
||||
.srcAccessMask = 0,
|
||||
.dstStageMask = vk::PIPELINE_STAGE_IMAGE_USERS,
|
||||
.dstAccessMask = vk::ACCESS_IMAGE_USERS,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = shadow_image,
|
||||
.subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
VK_REMAINING_ARRAY_LAYERS},
|
||||
},
|
||||
VkImageMemoryBarrier2{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFER_BIT,
|
||||
.srcAccessMask = VK_ACCESS_2_TRANSFER_WRITE_BIT,
|
||||
.dstStageMask = vk::PIPELINE_STAGE_IMAGE_USERS,
|
||||
.dstAccessMask = vk::ACCESS_IMAGE_USERS,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = dst_image,
|
||||
.subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
VK_REMAINING_ARRAY_LAYERS},
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(0, {}, {}, pre_barriers);
|
||||
cmdbuf.CopyImage(shadow_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, region);
|
||||
cmdbuf.PipelineBarrier(0, {}, {}, post_barriers);
|
||||
});
|
||||
const bool is_color = aspect_mask == VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
if ((is_color && ENABLE_MSAA_COLOR_DISCARD) ||
|
||||
(!is_color && ENABLE_MSAA_DEPTH_STENCIL_DISCARD)) {
|
||||
scheduler.DiscardResolvedAttachments(*shadow->view);
|
||||
}
|
||||
const VkImageCopy2 region{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_COPY_2,
|
||||
.pNext = nullptr,
|
||||
.srcSubresource{
|
||||
.aspectMask = dst.AspectMask(),
|
||||
.mipLevel = static_cast<u32>(copy.src_subresource.base_level),
|
||||
.baseArrayLayer = static_cast<u32>(copy.src_subresource.base_layer),
|
||||
.layerCount = static_cast<u32>(copy.src_subresource.num_layers),
|
||||
},
|
||||
.srcOffset = {0, 0, 0},
|
||||
.dstSubresource{
|
||||
.aspectMask = dst.AspectMask(),
|
||||
.mipLevel = static_cast<u32>(copy.dst_subresource.base_level),
|
||||
.baseArrayLayer = static_cast<u32>(copy.dst_subresource.base_layer),
|
||||
.layerCount = static_cast<u32>(copy.dst_subresource.num_layers),
|
||||
},
|
||||
.dstOffset = {copy.dst_offset.x, copy.dst_offset.y, copy.dst_offset.z},
|
||||
.extent = {copy.extent.width, copy.extent.height, 1},
|
||||
};
|
||||
if (CopyResolveShadow(src.Handle(), dst.Handle(), region)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,6 +130,8 @@ public:
|
||||
|
||||
void EraseResolveShadow(VkImage msaa_image);
|
||||
|
||||
bool CopyResolveShadow(VkImage msaa_image, VkImage dst_image, const VkImageCopy2& region);
|
||||
|
||||
std::span<const VkFormat> ViewFormats(PixelFormat format) {
|
||||
return view_formats[static_cast<std::size_t>(format)];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user