mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-11 06:17:41 +00:00
[TEST] depth stencil resolve implementation + fixes
This commit is contained in:
@@ -107,6 +107,9 @@ void Scheduler::BeginDynamicRendering(const Framebuffer* framebuffer, const Defe
|
|||||||
state.attachment_views = attachment_views;
|
state.attachment_views = attachment_views;
|
||||||
state.color_resolve_views = framebuffer->ColorResolveAttachments();
|
state.color_resolve_views = framebuffer->ColorResolveAttachments();
|
||||||
state.color_resolve_modes = framebuffer->ColorResolveModes();
|
state.color_resolve_modes = framebuffer->ColorResolveModes();
|
||||||
|
state.depth_resolve_view = framebuffer->DepthResolveAttachment();
|
||||||
|
state.depth_resolve_mode = framebuffer->DepthResolveMode();
|
||||||
|
state.stencil_resolve_mode = framebuffer->StencilResolveMode();
|
||||||
state.discards_msaa_color = framebuffer->DiscardsMsaaColor();
|
state.discards_msaa_color = framebuffer->DiscardsMsaaColor();
|
||||||
state.discards_msaa_depth = framebuffer->DiscardsMsaaDepth();
|
state.discards_msaa_depth = framebuffer->DiscardsMsaaDepth();
|
||||||
state.render_area = render_area;
|
state.render_area = render_area;
|
||||||
@@ -453,9 +456,13 @@ void Scheduler::RecordDynamicBegin(const DeferredClear* clear) {
|
|||||||
const bool ds_clear = clear != nullptr && clear->depth_stencil;
|
const bool ds_clear = clear != nullptr && clear->depth_stencil;
|
||||||
const VkClearValue ds_clear_value = clear ? clear->depth_stencil_value : VkClearValue{};
|
const VkClearValue ds_clear_value = clear ? clear->depth_stencil_value : VkClearValue{};
|
||||||
const bool ds_discard = state.discards_msaa_depth;
|
const bool ds_discard = state.discards_msaa_depth;
|
||||||
|
const VkImageView ds_resolve_view = state.depth_resolve_view;
|
||||||
|
const VkResolveModeFlagBits depth_resolve_mode = state.depth_resolve_mode;
|
||||||
|
const VkResolveModeFlagBits stencil_resolve_mode = state.stencil_resolve_mode;
|
||||||
Record([views, resolve_views, resolve_modes, num_color, has_depth, has_stencil, layers,
|
Record([views, resolve_views, resolve_modes, num_color, has_depth, has_stencil, layers,
|
||||||
render_area, color_clear_mask, color_discard_mask, color_clear_values, ds_clear,
|
render_area, color_clear_mask, color_discard_mask, color_clear_values, ds_clear,
|
||||||
ds_clear_value, ds_discard](vk::CommandBuffer cmdbuf) {
|
ds_clear_value, ds_discard, ds_resolve_view, depth_resolve_mode,
|
||||||
|
stencil_resolve_mode](vk::CommandBuffer cmdbuf) {
|
||||||
std::array<VkRenderingAttachmentInfo, VideoCommon::NUM_RT> color_infos{};
|
std::array<VkRenderingAttachmentInfo, VideoCommon::NUM_RT> color_infos{};
|
||||||
for (u32 index = 0; index < num_color; ++index) {
|
for (u32 index = 0; index < num_color; ++index) {
|
||||||
const bool clear_slot = ((color_clear_mask >> index) & 1u) != 0;
|
const bool clear_slot = ((color_clear_mask >> index) & 1u) != 0;
|
||||||
@@ -477,17 +484,37 @@ void Scheduler::RecordDynamicBegin(const DeferredClear* clear) {
|
|||||||
.clearValue = clear_slot ? color_clear_values[index] : VkClearValue{},
|
.clearValue = clear_slot ? color_clear_values[index] : VkClearValue{},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
const bool has_ds_resolve = ds_resolve_view != VK_NULL_HANDLE;
|
||||||
|
const VkAttachmentLoadOp ds_load_op = ds_clear ? VK_ATTACHMENT_LOAD_OP_CLEAR
|
||||||
|
: ds_discard ? VK_ATTACHMENT_LOAD_OP_DONT_CARE
|
||||||
|
: VK_ATTACHMENT_LOAD_OP_LOAD;
|
||||||
|
const VkAttachmentStoreOp ds_store_op =
|
||||||
|
ds_discard ? VK_ATTACHMENT_STORE_OP_DONT_CARE : VK_ATTACHMENT_STORE_OP_STORE;
|
||||||
const VkRenderingAttachmentInfo depth_info{
|
const VkRenderingAttachmentInfo depth_info{
|
||||||
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
|
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.imageView = views[8],
|
.imageView = views[8],
|
||||||
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
.resolveMode = VK_RESOLVE_MODE_NONE,
|
.resolveMode = has_ds_resolve ? depth_resolve_mode : VK_RESOLVE_MODE_NONE,
|
||||||
.resolveImageView = VK_NULL_HANDLE,
|
.resolveImageView = has_ds_resolve ? ds_resolve_view : VK_NULL_HANDLE,
|
||||||
.resolveImageLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
.resolveImageLayout =
|
||||||
.loadOp = ds_clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD,
|
has_ds_resolve ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
.storeOp = ds_discard ? VK_ATTACHMENT_STORE_OP_DONT_CARE
|
.loadOp = ds_load_op,
|
||||||
: VK_ATTACHMENT_STORE_OP_STORE,
|
.storeOp = ds_store_op,
|
||||||
|
.clearValue = ds_clear ? ds_clear_value : VkClearValue{},
|
||||||
|
};
|
||||||
|
// Stencil gets its own struct because its resolve mode may differ from depth's.
|
||||||
|
const VkRenderingAttachmentInfo stencil_info{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.imageView = views[8],
|
||||||
|
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
|
.resolveMode = has_ds_resolve ? stencil_resolve_mode : VK_RESOLVE_MODE_NONE,
|
||||||
|
.resolveImageView = has_ds_resolve ? ds_resolve_view : VK_NULL_HANDLE,
|
||||||
|
.resolveImageLayout =
|
||||||
|
has_ds_resolve ? VK_IMAGE_LAYOUT_GENERAL : VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
|
.loadOp = ds_load_op,
|
||||||
|
.storeOp = ds_store_op,
|
||||||
.clearValue = ds_clear ? ds_clear_value : VkClearValue{},
|
.clearValue = ds_clear ? ds_clear_value : VkClearValue{},
|
||||||
};
|
};
|
||||||
const VkRenderingInfo rendering_info{
|
const VkRenderingInfo rendering_info{
|
||||||
@@ -504,7 +531,7 @@ void Scheduler::RecordDynamicBegin(const DeferredClear* clear) {
|
|||||||
.colorAttachmentCount = num_color,
|
.colorAttachmentCount = num_color,
|
||||||
.pColorAttachments = color_infos.data(),
|
.pColorAttachments = color_infos.data(),
|
||||||
.pDepthAttachment = has_depth ? &depth_info : nullptr,
|
.pDepthAttachment = has_depth ? &depth_info : nullptr,
|
||||||
.pStencilAttachment = has_stencil ? &depth_info : nullptr,
|
.pStencilAttachment = has_stencil ? &stencil_info : nullptr,
|
||||||
};
|
};
|
||||||
cmdbuf.BeginRendering(rendering_info);
|
cmdbuf.BeginRendering(rendering_info);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -270,6 +270,9 @@ private:
|
|||||||
std::array<VkImageView, 9> attachment_views{};
|
std::array<VkImageView, 9> attachment_views{};
|
||||||
std::array<VkImageView, 8> color_resolve_views{};
|
std::array<VkImageView, 8> color_resolve_views{};
|
||||||
std::array<VkResolveModeFlagBits, 8> color_resolve_modes{};
|
std::array<VkResolveModeFlagBits, 8> color_resolve_modes{};
|
||||||
|
VkImageView depth_resolve_view{};
|
||||||
|
VkResolveModeFlagBits depth_resolve_mode = VK_RESOLVE_MODE_NONE;
|
||||||
|
VkResolveModeFlagBits stencil_resolve_mode = VK_RESOLVE_MODE_NONE;
|
||||||
VkExtent2D render_area = {0, 0};
|
VkExtent2D render_area = {0, 0};
|
||||||
GraphicsPipeline* graphics_pipeline = nullptr;
|
GraphicsPipeline* graphics_pipeline = nullptr;
|
||||||
bool rendering = false;
|
bool rendering = false;
|
||||||
|
|||||||
@@ -1005,7 +1005,10 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, VkFormat format,
|
VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, VkFormat format,
|
||||||
VkExtent2D extent, u32 layers) {
|
VkExtent2D extent, u32 layers,
|
||||||
|
VkImageAspectFlags aspect) {
|
||||||
|
const bool is_depth_stencil =
|
||||||
|
(aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0;
|
||||||
ResolveShadow& shadow = resolve_shadows[msaa_image];
|
ResolveShadow& shadow = resolve_shadows[msaa_image];
|
||||||
if (shadow.image && shadow.format == format && shadow.extent.width == extent.width &&
|
if (shadow.image && shadow.format == format && shadow.extent.width == extent.width &&
|
||||||
shadow.extent.height == extent.height && shadow.layers == layers) {
|
shadow.extent.height == extent.height && shadow.layers == layers) {
|
||||||
@@ -1023,8 +1026,9 @@ VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, Vk
|
|||||||
.arrayLayers = layers,
|
.arrayLayers = layers,
|
||||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||||
.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
|
.usage = (is_depth_stencil ? VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
|
||||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
|
: VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) |
|
||||||
|
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
|
||||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||||
.queueFamilyIndexCount = 0,
|
.queueFamilyIndexCount = 0,
|
||||||
.pQueueFamilyIndices = nullptr,
|
.pQueueFamilyIndices = nullptr,
|
||||||
@@ -1039,7 +1043,7 @@ VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, Vk
|
|||||||
.format = format,
|
.format = format,
|
||||||
.components{},
|
.components{},
|
||||||
.subresourceRange{
|
.subresourceRange{
|
||||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
.aspectMask = aspect,
|
||||||
.baseMipLevel = 0,
|
.baseMipLevel = 0,
|
||||||
.levelCount = 1,
|
.levelCount = 1,
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = 0,
|
||||||
@@ -1052,28 +1056,33 @@ VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, Vk
|
|||||||
shadow.up_to_date = true;
|
shadow.up_to_date = true;
|
||||||
if (device.IsKhrDynamicRenderingSupported()) {
|
if (device.IsKhrDynamicRenderingSupported()) {
|
||||||
scheduler.RecordWithUploadBuffer(
|
scheduler.RecordWithUploadBuffer(
|
||||||
[image = *shadow.image, layers](vk::CommandBuffer, vk::CommandBuffer upload_cmdbuf) {
|
[image = *shadow.image, layers, aspect, is_depth_stencil](
|
||||||
|
vk::CommandBuffer, vk::CommandBuffer upload_cmdbuf) {
|
||||||
const VkImageMemoryBarrier barrier{
|
const VkImageMemoryBarrier barrier{
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.srcAccessMask = 0,
|
.srcAccessMask = 0,
|
||||||
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
.dstAccessMask = is_depth_stencil
|
||||||
|
? VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
|
||||||
|
: VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||||
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
||||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.image = image,
|
.image = image,
|
||||||
.subresourceRange{
|
.subresourceRange{
|
||||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
.aspectMask = aspect,
|
||||||
.baseMipLevel = 0,
|
.baseMipLevel = 0,
|
||||||
.levelCount = 1,
|
.levelCount = 1,
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = 0,
|
||||||
.layerCount = layers,
|
.layerCount = layers,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
upload_cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
upload_cmdbuf.PipelineBarrier(
|
||||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0,
|
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||||
barrier);
|
is_depth_stencil ? VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT
|
||||||
|
: VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||||
|
0, barrier);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return *shadow.view;
|
return *shadow.view;
|
||||||
@@ -1668,18 +1677,6 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src,
|
|||||||
std::span<const VideoCommon::ImageCopy> copies) {
|
std::span<const VideoCommon::ImageCopy> copies) {
|
||||||
const bool msaa_to_non_msaa = src.info.num_samples > 1 && dst.info.num_samples == 1;
|
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;
|
const u32 num_samples = msaa_to_non_msaa ? src.info.num_samples : dst.info.num_samples;
|
||||||
if (dst.AspectMask() != VK_IMAGE_ASPECT_COLOR_BIT ||
|
|
||||||
VideoCore::Surface::IsPixelFormatInteger(dst.info.format)) {
|
|
||||||
const u64 key{(static_cast<u64>(dst.AspectMask()) << 32) |
|
|
||||||
static_cast<u64>(dst.info.format)};
|
|
||||||
if (unsupported_msaa_resolves.insert(key).second) {
|
|
||||||
LOG_WARNING(Render_Vulkan,
|
|
||||||
"MSAA resolve unsupported: format={}, aspect={:#x}, samples {}->{}",
|
|
||||||
dst.info.format, dst.AspectMask(), src.info.num_samples,
|
|
||||||
dst.info.num_samples);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (ENABLE_MSAA_RESOLVE_CONSUME && msaa_to_non_msaa && copies.size() == 1 &&
|
if (ENABLE_MSAA_RESOLVE_CONSUME && msaa_to_non_msaa && copies.size() == 1 &&
|
||||||
src.info.format == dst.info.format) {
|
src.info.format == dst.info.format) {
|
||||||
const VideoCommon::ImageCopy& copy = copies.front();
|
const VideoCommon::ImageCopy& copy = copies.front();
|
||||||
@@ -1690,16 +1687,19 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src,
|
|||||||
static_cast<u32>(copy.extent.height) <= shadow->extent.height) {
|
static_cast<u32>(copy.extent.height) <= shadow->extent.height) {
|
||||||
const VkImage shadow_image = *shadow->image;
|
const VkImage shadow_image = *shadow->image;
|
||||||
const VkImage dst_image = dst.Handle();
|
const VkImage dst_image = dst.Handle();
|
||||||
|
const VkImageAspectFlags aspect = dst.AspectMask();
|
||||||
|
const bool is_depth_stencil =
|
||||||
|
(aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0;
|
||||||
const VkImageCopy region{
|
const VkImageCopy region{
|
||||||
.srcSubresource{
|
.srcSubresource{
|
||||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
.aspectMask = aspect,
|
||||||
.mipLevel = 0,
|
.mipLevel = 0,
|
||||||
.baseArrayLayer = static_cast<u32>(copy.src_subresource.base_layer),
|
.baseArrayLayer = static_cast<u32>(copy.src_subresource.base_layer),
|
||||||
.layerCount = static_cast<u32>(copy.src_subresource.num_layers),
|
.layerCount = static_cast<u32>(copy.src_subresource.num_layers),
|
||||||
},
|
},
|
||||||
.srcOffset = {0, 0, 0},
|
.srcOffset = {0, 0, 0},
|
||||||
.dstSubresource{
|
.dstSubresource{
|
||||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
.aspectMask = aspect,
|
||||||
.mipLevel = static_cast<u32>(copy.dst_subresource.base_level),
|
.mipLevel = static_cast<u32>(copy.dst_subresource.base_level),
|
||||||
.baseArrayLayer = static_cast<u32>(copy.dst_subresource.base_layer),
|
.baseArrayLayer = static_cast<u32>(copy.dst_subresource.base_layer),
|
||||||
.layerCount = static_cast<u32>(copy.dst_subresource.num_layers),
|
.layerCount = static_cast<u32>(copy.dst_subresource.num_layers),
|
||||||
@@ -1708,34 +1708,38 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src,
|
|||||||
.extent = {copy.extent.width, copy.extent.height, 1},
|
.extent = {copy.extent.width, copy.extent.height, 1},
|
||||||
};
|
};
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
scheduler.Record([shadow_image, dst_image, region](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([shadow_image, dst_image, region, aspect,
|
||||||
|
is_depth_stencil](vk::CommandBuffer cmdbuf) {
|
||||||
|
const VkAccessFlags attachment_write =
|
||||||
|
is_depth_stencil ? VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT
|
||||||
|
: VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||||
const std::array pre_barriers{
|
const std::array pre_barriers{
|
||||||
VkImageMemoryBarrier{
|
VkImageMemoryBarrier{
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
.srcAccessMask = attachment_write,
|
||||||
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT,
|
||||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.image = shadow_image,
|
.image = shadow_image,
|
||||||
.subresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0,
|
.subresourceRange{aspect, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||||
VK_REMAINING_ARRAY_LAYERS},
|
VK_REMAINING_ARRAY_LAYERS},
|
||||||
},
|
},
|
||||||
VkImageMemoryBarrier{
|
VkImageMemoryBarrier{
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT |
|
.srcAccessMask =
|
||||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
VK_ACCESS_SHADER_WRITE_BIT | attachment_write |
|
||||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.image = dst_image,
|
.image = dst_image,
|
||||||
.subresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0,
|
.subresourceRange{aspect, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||||
VK_REMAINING_ARRAY_LAYERS},
|
VK_REMAINING_ARRAY_LAYERS},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -1750,7 +1754,7 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src,
|
|||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.image = shadow_image,
|
.image = shadow_image,
|
||||||
.subresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0,
|
.subresourceRange{aspect, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||||
VK_REMAINING_ARRAY_LAYERS},
|
VK_REMAINING_ARRAY_LAYERS},
|
||||||
},
|
},
|
||||||
VkImageMemoryBarrier{
|
VkImageMemoryBarrier{
|
||||||
@@ -1760,17 +1764,20 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src,
|
|||||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT |
|
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT |
|
||||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
||||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||||
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
||||||
|
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
|
||||||
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||||
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
.newLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||||
.image = dst_image,
|
.image = dst_image,
|
||||||
.subresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0,
|
.subresourceRange{aspect, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||||
VK_REMAINING_ARRAY_LAYERS},
|
VK_REMAINING_ARRAY_LAYERS},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||||
|
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT |
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, nullptr, nullptr,
|
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, nullptr, nullptr,
|
||||||
pre_barriers);
|
pre_barriers);
|
||||||
@@ -1783,6 +1790,18 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (dst.AspectMask() != VK_IMAGE_ASPECT_COLOR_BIT ||
|
||||||
|
VideoCore::Surface::IsPixelFormatInteger(dst.info.format)) {
|
||||||
|
const u64 key{(static_cast<u64>(dst.AspectMask()) << 32) |
|
||||||
|
static_cast<u64>(dst.info.format)};
|
||||||
|
if (unsupported_msaa_resolves.insert(key).second) {
|
||||||
|
LOG_WARNING(Render_Vulkan,
|
||||||
|
"MSAA resolve unsupported: format={}, aspect={:#x}, samples {}->{}",
|
||||||
|
dst.info.format, dst.AspectMask(), src.info.num_samples,
|
||||||
|
dst.info.num_samples);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
blit_image_helper.CopyMSAA(render_pass_cache, dst.Handle(), dst.info.format, src.Handle(),
|
blit_image_helper.CopyMSAA(render_pass_cache, dst.Handle(), dst.info.format, src.Handle(),
|
||||||
src.info.format, num_samples, copies, msaa_to_non_msaa);
|
src.info.format, num_samples, copies, msaa_to_non_msaa);
|
||||||
}
|
}
|
||||||
@@ -2806,10 +2825,21 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
|||||||
samples != VK_SAMPLE_COUNT_1_BIT && num_colors > 0 && runtime.device.IsTiler();
|
samples != VK_SAMPLE_COUNT_1_BIT && num_colors > 0 && runtime.device.IsTiler();
|
||||||
renderpass_key.resolve_color = do_resolve_color;
|
renderpass_key.resolve_color = do_resolve_color;
|
||||||
|
|
||||||
|
const VkResolveModeFlagBits depth_mode = runtime.device.GetDepthResolveMode();
|
||||||
|
const VkResolveModeFlagBits stencil_mode = runtime.device.GetStencilResolveMode();
|
||||||
|
const bool resolve_modes_compatible =
|
||||||
|
depth_mode != VK_RESOLVE_MODE_NONE &&
|
||||||
|
(!has_stencil || (stencil_mode != VK_RESOLVE_MODE_NONE &&
|
||||||
|
(runtime.device.IsIndependentResolveSupported() ||
|
||||||
|
depth_mode == stencil_mode)));
|
||||||
|
const bool do_resolve_depth =
|
||||||
|
samples != VK_SAMPLE_COUNT_1_BIT && has_depth && runtime.device.IsTiler() &&
|
||||||
|
runtime.device.IsKhrDynamicRenderingSupported() && resolve_modes_compatible;
|
||||||
|
|
||||||
discard_msaa_color =
|
discard_msaa_color =
|
||||||
ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_COLOR_DISCARD && do_resolve_color;
|
ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_COLOR_DISCARD && do_resolve_color;
|
||||||
discard_msaa_depth = ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_DEPTH_DISCARD &&
|
discard_msaa_depth =
|
||||||
samples != VK_SAMPLE_COUNT_1_BIT && has_depth && runtime.device.IsTiler();
|
ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_DEPTH_DISCARD && do_resolve_depth;
|
||||||
|
|
||||||
render_pass_key = renderpass_key;
|
render_pass_key = renderpass_key;
|
||||||
render_pass_cache = &runtime.render_pass_cache;
|
render_pass_cache = &runtime.render_pass_cache;
|
||||||
@@ -2831,7 +2861,7 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
|||||||
if (ENABLE_MSAA_RESOLVE_CONSUME) {
|
if (ENABLE_MSAA_RESOLVE_CONSUME) {
|
||||||
const VkImage msaa_image = images[rt_map[index]];
|
const VkImage msaa_image = images[rt_map[index]];
|
||||||
const VkImageView shadow_view = runtime.GetOrCreateResolveShadow(
|
const VkImageView shadow_view = runtime.GetOrCreateResolveShadow(
|
||||||
msaa_image, vk_format, render_area, layers);
|
msaa_image, vk_format, render_area, layers, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||||
color_resolve_attachments[index] = shadow_view;
|
color_resolve_attachments[index] = shadow_view;
|
||||||
attachments.push_back(shadow_view);
|
attachments.push_back(shadow_view);
|
||||||
continue;
|
continue;
|
||||||
@@ -2905,6 +2935,22 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (do_resolve_depth && depth_buffer != nullptr) {
|
||||||
|
const u32 layers = static_cast<u32>((std::max)(num_layers, 1));
|
||||||
|
VkImageAspectFlags aspect = 0;
|
||||||
|
if (has_depth) {
|
||||||
|
aspect |= VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||||
|
}
|
||||||
|
if (has_stencil) {
|
||||||
|
aspect |= VK_IMAGE_ASPECT_STENCIL_BIT;
|
||||||
|
}
|
||||||
|
depth_resolve_attachment =
|
||||||
|
runtime.GetOrCreateResolveShadow(depth_buffer->ImageHandle(), depth_attachment_format,
|
||||||
|
render_area, layers, aspect);
|
||||||
|
depth_resolve_mode = depth_mode;
|
||||||
|
stencil_resolve_mode = has_stencil ? stencil_mode : VK_RESOLVE_MODE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
num_color_buffers = static_cast<u32>(num_colors);
|
num_color_buffers = static_cast<u32>(num_colors);
|
||||||
layer_count = static_cast<u32>((std::max)(num_layers, 1));
|
layer_count = static_cast<u32>((std::max)(num_layers, 1));
|
||||||
if (runtime.device.IsKhrDynamicRenderingSupported()) {
|
if (runtime.device.IsKhrDynamicRenderingSupported()) {
|
||||||
|
|||||||
@@ -133,7 +133,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] VkImageView GetOrCreateResolveShadow(VkImage msaa_image, VkFormat format,
|
[[nodiscard]] VkImageView GetOrCreateResolveShadow(VkImage msaa_image, VkFormat format,
|
||||||
VkExtent2D extent, u32 layers);
|
VkExtent2D extent, u32 layers,
|
||||||
|
VkImageAspectFlags aspect);
|
||||||
|
|
||||||
[[nodiscard]] const ResolveShadow* GetValidResolveShadow(VkImage msaa_image) const;
|
[[nodiscard]] const ResolveShadow* GetValidResolveShadow(VkImage msaa_image) const;
|
||||||
|
|
||||||
@@ -233,6 +234,18 @@ public:
|
|||||||
return depth_attachment;
|
return depth_attachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] VkImageView DepthResolveAttachment() const noexcept {
|
||||||
|
return depth_resolve_attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] VkResolveModeFlagBits DepthResolveMode() const noexcept {
|
||||||
|
return depth_resolve_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] VkResolveModeFlagBits StencilResolveMode() const noexcept {
|
||||||
|
return stencil_resolve_mode;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] VkFormat DepthAttachmentFormat() const noexcept {
|
[[nodiscard]] VkFormat DepthAttachmentFormat() const noexcept {
|
||||||
return depth_attachment_format;
|
return depth_attachment_format;
|
||||||
}
|
}
|
||||||
@@ -312,6 +325,9 @@ private:
|
|||||||
std::array<VkImageView, NUM_RT> color_resolve_attachments{};
|
std::array<VkImageView, NUM_RT> color_resolve_attachments{};
|
||||||
std::array<VkResolveModeFlagBits, NUM_RT> color_resolve_modes{};
|
std::array<VkResolveModeFlagBits, NUM_RT> color_resolve_modes{};
|
||||||
VkImageView depth_attachment{};
|
VkImageView depth_attachment{};
|
||||||
|
VkImageView depth_resolve_attachment{};
|
||||||
|
VkResolveModeFlagBits depth_resolve_mode = VK_RESOLVE_MODE_NONE;
|
||||||
|
VkResolveModeFlagBits stencil_resolve_mode = VK_RESOLVE_MODE_NONE;
|
||||||
VkFormat depth_attachment_format = VK_FORMAT_UNDEFINED;
|
VkFormat depth_attachment_format = VK_FORMAT_UNDEFINED;
|
||||||
u32 num_color_attachments = 0;
|
u32 num_color_attachments = 0;
|
||||||
u32 layer_count = 1;
|
u32 layer_count = 1;
|
||||||
|
|||||||
@@ -1120,6 +1120,11 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
|||||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES_KHR;
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES_KHR;
|
||||||
SetNext(next, properties.maintenance5);
|
SetNext(next, properties.maintenance5);
|
||||||
}
|
}
|
||||||
|
if (instance_version >= VK_API_VERSION_1_2) {
|
||||||
|
properties.depth_stencil_resolve.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES;
|
||||||
|
SetNext(next, properties.depth_stencil_resolve);
|
||||||
|
}
|
||||||
|
|
||||||
// Perform the property fetch.
|
// Perform the property fetch.
|
||||||
physical.GetProperties2(properties2);
|
physical.GetProperties2(properties2);
|
||||||
|
|||||||
@@ -1006,6 +1006,26 @@ FN_MAX_LIMIT_LIST
|
|||||||
return ENABLE_DYNAMIC_RENDERING && extensions.dynamic_rendering;
|
return ENABLE_DYNAMIC_RENDERING && extensions.dynamic_rendering;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the resolve mode to use for multisampled depth.
|
||||||
|
VkResolveModeFlagBits GetDepthResolveMode() const {
|
||||||
|
return PickResolveMode(properties.depth_stencil_resolve.supportedDepthResolveModes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as GetDepthResolveMode, for the stencil aspect.
|
||||||
|
VkResolveModeFlagBits GetStencilResolveMode() const {
|
||||||
|
return PickResolveMode(properties.depth_stencil_resolve.supportedStencilResolveModes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if depth and stencil may resolve with independent modes.
|
||||||
|
bool IsIndependentResolveSupported() const {
|
||||||
|
return properties.depth_stencil_resolve.independentResolve == VK_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if one aspect may resolve while the other does not.
|
||||||
|
bool IsIndependentResolveNoneSupported() const {
|
||||||
|
return properties.depth_stencil_resolve.independentResolveNone == VK_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the device supports VK_KHR_maintenance4.
|
/// Returns true if the device supports VK_KHR_maintenance4.
|
||||||
bool IsKhrMaintenance4Supported() const {
|
bool IsKhrMaintenance4Supported() const {
|
||||||
return extensions.maintenance4;
|
return extensions.maintenance4;
|
||||||
@@ -1087,6 +1107,22 @@ FN_MAX_LIMIT_LIST
|
|||||||
void ShutdownGPULogging();
|
void ShutdownGPULogging();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// Picks a usable resolve mode out of a supported-modes mask. SAMPLE_ZERO is preferred because
|
||||||
|
/// it is the only mode the spec guarantees whenever any depth/stencil resolve is supported,
|
||||||
|
/// and averaging depth samples is not meaningful for depth testing anyway.
|
||||||
|
static VkResolveModeFlagBits PickResolveMode(VkResolveModeFlags supported) {
|
||||||
|
if ((supported & VK_RESOLVE_MODE_SAMPLE_ZERO_BIT) != 0) {
|
||||||
|
return VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
|
||||||
|
}
|
||||||
|
if ((supported & VK_RESOLVE_MODE_MIN_BIT) != 0) {
|
||||||
|
return VK_RESOLVE_MODE_MIN_BIT;
|
||||||
|
}
|
||||||
|
if ((supported & VK_RESOLVE_MODE_MAX_BIT) != 0) {
|
||||||
|
return VK_RESOLVE_MODE_MAX_BIT;
|
||||||
|
}
|
||||||
|
return VK_RESOLVE_MODE_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks if the physical device is suitable and configures the object state
|
/// Checks if the physical device is suitable and configures the object state
|
||||||
/// with all necessary info about its properties.
|
/// with all necessary info about its properties.
|
||||||
bool GetSuitability(bool requires_swapchain);
|
bool GetSuitability(bool requires_swapchain);
|
||||||
@@ -1176,6 +1212,7 @@ private:
|
|||||||
VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};
|
VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};
|
||||||
VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback{};
|
VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback{};
|
||||||
VkPhysicalDeviceMaintenance5PropertiesKHR maintenance5{};
|
VkPhysicalDeviceMaintenance5PropertiesKHR maintenance5{};
|
||||||
|
VkPhysicalDeviceDepthStencilResolveProperties depth_stencil_resolve{};
|
||||||
|
|
||||||
VkPhysicalDeviceProperties properties{};
|
VkPhysicalDeviceProperties properties{};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user