mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-14 04:24:31 +00:00
[TEST] Depth stencil resolve + MSAA depth stencil
This commit is contained in:
@@ -140,6 +140,8 @@ RenderPassKey MakeRenderPassKey(const FixedPipelineState& state, const Device& d
|
||||
});
|
||||
key.resolve_color =
|
||||
key.samples != VK_SAMPLE_COUNT_1_BIT && has_color && device.IsTiler();
|
||||
key.resolve_depth_stencil = key.samples != VK_SAMPLE_COUNT_1_BIT && device.IsTiler() &&
|
||||
SupportsDepthStencilResolve(device, key.depth_format);
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
@@ -65,8 +65,61 @@ using VideoCore::Surface::SurfaceType;
|
||||
.finalLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
};
|
||||
}
|
||||
|
||||
struct ResolveAspects {
|
||||
bool depth;
|
||||
bool stencil;
|
||||
};
|
||||
|
||||
struct ResolveModes {
|
||||
VkResolveModeFlagBits depth;
|
||||
VkResolveModeFlagBits stencil;
|
||||
};
|
||||
|
||||
constexpr ResolveAspects GetResolveAspects(PixelFormat format) {
|
||||
const SurfaceType surface_type = GetSurfaceType(format);
|
||||
return ResolveAspects{
|
||||
.depth = surface_type == SurfaceType::Depth ||
|
||||
surface_type == SurfaceType::DepthStencil,
|
||||
.stencil = surface_type == SurfaceType::Stencil ||
|
||||
surface_type == SurfaceType::DepthStencil,
|
||||
};
|
||||
}
|
||||
|
||||
ResolveModes PickResolveModes(const Device& device, PixelFormat format) {
|
||||
constexpr VkResolveModeFlagBits mode = VK_RESOLVE_MODE_SAMPLE_ZERO_BIT;
|
||||
|
||||
const ResolveAspects aspects = GetResolveAspects(format);
|
||||
ResolveModes modes{
|
||||
.depth = VK_RESOLVE_MODE_NONE,
|
||||
.stencil = VK_RESOLVE_MODE_NONE,
|
||||
};
|
||||
if (aspects.depth && (device.GetDepthResolveModes() & mode) != 0) {
|
||||
modes.depth = mode;
|
||||
}
|
||||
if (aspects.stencil && (device.GetStencilResolveModes() & mode) != 0) {
|
||||
modes.stencil = mode;
|
||||
}
|
||||
return modes;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
bool SupportsDepthStencilResolve(const Device& device, PixelFormat depth_format) {
|
||||
if (depth_format == PixelFormat::Invalid || !device.IsKhrDepthStencilResolveSupported()) {
|
||||
return false;
|
||||
}
|
||||
const ResolveAspects aspects = GetResolveAspects(depth_format);
|
||||
if (!aspects.depth && !aspects.stencil) {
|
||||
return false;
|
||||
}
|
||||
const ResolveModes modes = PickResolveModes(device, depth_format);
|
||||
if ((aspects.depth && modes.depth == VK_RESOLVE_MODE_NONE) ||
|
||||
(aspects.stencil && modes.stencil == VK_RESOLVE_MODE_NONE)) {
|
||||
return false;
|
||||
}
|
||||
return modes.depth == modes.stencil || device.SupportsIndependentResolveNone();
|
||||
}
|
||||
|
||||
RenderPassCache::RenderPassCache(const Device& device_) : device{&device_} {}
|
||||
|
||||
VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
|
||||
@@ -75,7 +128,9 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
|
||||
if (!is_new) {
|
||||
return *pair->second;
|
||||
}
|
||||
boost::container::static_vector<VkAttachmentDescription, 9> descriptions;
|
||||
static constexpr size_t MAX_ATTACHMENTS =
|
||||
2 * std::tuple_size_v<decltype(RenderPassKey::color_formats)> + 2;
|
||||
boost::container::static_vector<VkAttachmentDescription, MAX_ATTACHMENTS> descriptions;
|
||||
std::array<VkAttachmentReference, 8> references{};
|
||||
u32 num_attachments{};
|
||||
u32 num_colors{};
|
||||
@@ -133,6 +188,21 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
|
||||
}
|
||||
}
|
||||
}
|
||||
const bool do_resolve_depth_stencil = key.resolve_depth_stencil && has_depth &&
|
||||
key.samples != VK_SAMPLE_COUNT_1_BIT &&
|
||||
SupportsDepthStencilResolve(*device, key.depth_format);
|
||||
VkAttachmentReference depth_resolve_reference{};
|
||||
if (do_resolve_depth_stencil) {
|
||||
depth_resolve_reference = VkAttachmentReference{
|
||||
.attachment = static_cast<u32>(descriptions.size()),
|
||||
.layout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
};
|
||||
VkAttachmentDescription resolve_desc =
|
||||
AttachmentDescription(*device, key.depth_format, VK_SAMPLE_COUNT_1_BIT,
|
||||
VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE);
|
||||
resolve_desc.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
descriptions.push_back(resolve_desc);
|
||||
}
|
||||
const VkSubpassDescription subpass{
|
||||
.flags = 0,
|
||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
@@ -155,6 +225,107 @@ VkRenderPass RenderPassCache::Get(const RenderPassKey& key) {
|
||||
.dependencyFlags = 0,
|
||||
};
|
||||
const bool can_resume_transform_feedback = device->IsExtTransformFeedbackSupported();
|
||||
|
||||
if (device->IsKhrCreateRenderPass2Supported()) {
|
||||
boost::container::static_vector<VkAttachmentDescription2, MAX_ATTACHMENTS> descriptions2;
|
||||
for (const VkAttachmentDescription& description : descriptions) {
|
||||
descriptions2.push_back(VkAttachmentDescription2{
|
||||
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2,
|
||||
.pNext = nullptr,
|
||||
.flags = description.flags,
|
||||
.format = description.format,
|
||||
.samples = description.samples,
|
||||
.loadOp = description.loadOp,
|
||||
.storeOp = description.storeOp,
|
||||
.stencilLoadOp = description.stencilLoadOp,
|
||||
.stencilStoreOp = description.stencilStoreOp,
|
||||
.initialLayout = description.initialLayout,
|
||||
.finalLayout = description.finalLayout,
|
||||
});
|
||||
}
|
||||
const auto promote = [](const VkAttachmentReference& reference) {
|
||||
return VkAttachmentReference2{
|
||||
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2,
|
||||
.pNext = nullptr,
|
||||
.attachment = reference.attachment,
|
||||
.layout = reference.layout,
|
||||
.aspectMask = 0,
|
||||
};
|
||||
};
|
||||
std::array<VkAttachmentReference2, 8> references2{};
|
||||
std::array<VkAttachmentReference2, 8> resolve_references2{};
|
||||
for (size_t index = 0; index < references.size(); ++index) {
|
||||
references2[index] = promote(references[index]);
|
||||
resolve_references2[index] = promote(resolve_references[index]);
|
||||
}
|
||||
const VkAttachmentReference2 depth_reference2 = promote(depth_reference);
|
||||
const VkAttachmentReference2 depth_resolve_reference2 = promote(depth_resolve_reference);
|
||||
const ResolveModes resolve_modes = PickResolveModes(*device, key.depth_format);
|
||||
const VkSubpassDescriptionDepthStencilResolve depth_stencil_resolve{
|
||||
.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_DEPTH_STENCIL_RESOLVE,
|
||||
.pNext = nullptr,
|
||||
.depthResolveMode = resolve_modes.depth,
|
||||
.stencilResolveMode = resolve_modes.stencil,
|
||||
.pDepthStencilResolveAttachment = &depth_resolve_reference2,
|
||||
};
|
||||
const VkSubpassDescription2 subpass2{
|
||||
.sType = VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2,
|
||||
.pNext = do_resolve_depth_stencil ? &depth_stencil_resolve : nullptr,
|
||||
.flags = 0,
|
||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
.viewMask = 0,
|
||||
.inputAttachmentCount = 0,
|
||||
.pInputAttachments = nullptr,
|
||||
.colorAttachmentCount = num_attachments,
|
||||
.pColorAttachments = references2.data(),
|
||||
.pResolveAttachments = do_resolve_color ? resolve_references2.data() : nullptr,
|
||||
.pDepthStencilAttachment = has_depth ? &depth_reference2 : nullptr,
|
||||
.preserveAttachmentCount = 0,
|
||||
.pPreserveAttachments = nullptr,
|
||||
};
|
||||
const VkMemoryBarrier2 counter_resume_barrier{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER_2,
|
||||
.pNext = nullptr,
|
||||
.srcStageMask = VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT,
|
||||
.srcAccessMask = VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT,
|
||||
.dstStageMask = VK_PIPELINE_STAGE_2_TRANSFORM_FEEDBACK_BIT_EXT,
|
||||
.dstAccessMask = VK_ACCESS_2_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT,
|
||||
};
|
||||
VkSubpassDependency2 counter_resume_dependency2{
|
||||
.sType = VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2,
|
||||
.pNext = nullptr,
|
||||
.srcSubpass = counter_resume_dependency.srcSubpass,
|
||||
.dstSubpass = counter_resume_dependency.dstSubpass,
|
||||
.srcStageMask = counter_resume_dependency.srcStageMask,
|
||||
.dstStageMask = counter_resume_dependency.dstStageMask,
|
||||
.srcAccessMask = counter_resume_dependency.srcAccessMask,
|
||||
.dstAccessMask = counter_resume_dependency.dstAccessMask,
|
||||
.dependencyFlags = counter_resume_dependency.dependencyFlags,
|
||||
.viewOffset = 0,
|
||||
};
|
||||
if (device->HasSynchronization2()) {
|
||||
counter_resume_dependency2.pNext = &counter_resume_barrier;
|
||||
counter_resume_dependency2.srcStageMask = 0;
|
||||
counter_resume_dependency2.dstStageMask = 0;
|
||||
counter_resume_dependency2.srcAccessMask = 0;
|
||||
counter_resume_dependency2.dstAccessMask = 0;
|
||||
}
|
||||
pair->second = device->GetLogical().CreateRenderPass2({
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.attachmentCount = static_cast<u32>(descriptions2.size()),
|
||||
.pAttachments = descriptions2.empty() ? nullptr : descriptions2.data(),
|
||||
.subpassCount = 1,
|
||||
.pSubpasses = &subpass2,
|
||||
.dependencyCount = can_resume_transform_feedback ? 1u : 0u,
|
||||
.pDependencies = can_resume_transform_feedback ? &counter_resume_dependency2 : nullptr,
|
||||
.correlatedViewMaskCount = 0,
|
||||
.pCorrelatedViewMasks = nullptr,
|
||||
});
|
||||
return *pair->second;
|
||||
}
|
||||
|
||||
pair->second = device->GetLogical().CreateRenderPass({
|
||||
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
||||
@@ -22,6 +22,7 @@ struct RenderPassKey {
|
||||
VideoCore::Surface::PixelFormat depth_format;
|
||||
VkSampleCountFlagBits samples;
|
||||
bool resolve_color;
|
||||
bool resolve_depth_stencil;
|
||||
u32 color_clear_mask;
|
||||
bool depth_stencil_clear;
|
||||
u32 color_discard_mask;
|
||||
@@ -47,7 +48,8 @@ struct hash<Vulkan::RenderPassKey> {
|
||||
(static_cast<u64>(key.color_clear_mask) << 16) |
|
||||
(static_cast<u64>(key.color_discard_mask) << 24) |
|
||||
(static_cast<u64>(key.resolve_color) << 32) |
|
||||
(static_cast<u64>(key.depth_stencil_clear) << 33);
|
||||
(static_cast<u64>(key.depth_stencil_clear) << 33) |
|
||||
(static_cast<u64>(key.resolve_depth_stencil) << 34);
|
||||
size_t seed = 0;
|
||||
Common::HashCombine(seed, formats);
|
||||
Common::HashCombine(seed, state);
|
||||
@@ -60,6 +62,9 @@ namespace Vulkan {
|
||||
|
||||
class Device;
|
||||
|
||||
[[nodiscard]] bool SupportsDepthStencilResolve(const Device& device,
|
||||
VideoCore::Surface::PixelFormat depth_format);
|
||||
|
||||
class RenderPassCache {
|
||||
public:
|
||||
explicit RenderPassCache(const Device& device_);
|
||||
|
||||
@@ -993,13 +993,25 @@ VkBuffer TextureCacheRuntime::GetTemporaryBuffer(size_t needed_size) {
|
||||
}
|
||||
|
||||
VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, VkFormat format,
|
||||
VkExtent2D extent, u32 layers) {
|
||||
VkExtent2D extent, u32 layers,
|
||||
VkImageAspectFlags aspect_mask) {
|
||||
ResolveShadow& shadow = resolve_shadows[msaa_image];
|
||||
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 &&
|
||||
shadow.aspect_mask == aspect_mask) {
|
||||
shadow.up_to_date = true;
|
||||
return *shadow.view;
|
||||
}
|
||||
VkImageUsageFlags shadow_usage =
|
||||
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
|
||||
if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) {
|
||||
shadow_usage |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
|
||||
} else {
|
||||
shadow_usage |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
}
|
||||
if (shadow.image) {
|
||||
pending_resolve_shadows.emplace_back(scheduler.CurrentTick(), std::move(shadow));
|
||||
}
|
||||
shadow.image = memory_allocator.CreateImage(VkImageCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
@@ -1011,8 +1023,7 @@ VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, Vk
|
||||
.arrayLayers = layers,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||
.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
|
||||
.usage = shadow_usage,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = nullptr,
|
||||
@@ -1027,7 +1038,7 @@ VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, Vk
|
||||
.format = format,
|
||||
.components{},
|
||||
.subresourceRange{
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.aspectMask = aspect_mask,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
@@ -1037,6 +1048,7 @@ VkImageView TextureCacheRuntime::GetOrCreateResolveShadow(VkImage msaa_image, Vk
|
||||
shadow.format = format;
|
||||
shadow.extent = extent;
|
||||
shadow.layers = layers;
|
||||
shadow.aspect_mask = aspect_mask;
|
||||
shadow.up_to_date = true;
|
||||
return *shadow.view;
|
||||
}
|
||||
@@ -1058,7 +1070,14 @@ void TextureCacheRuntime::InvalidateResolveShadow(VkImage msaa_image) {
|
||||
}
|
||||
|
||||
void TextureCacheRuntime::EraseResolveShadow(VkImage msaa_image) {
|
||||
resolve_shadows.erase(msaa_image);
|
||||
const auto it = resolve_shadows.find(msaa_image);
|
||||
if (it == resolve_shadows.end()) {
|
||||
return;
|
||||
}
|
||||
if (it->second.image) {
|
||||
pending_resolve_shadows.emplace_back(scheduler.CurrentTick(), std::move(it->second));
|
||||
}
|
||||
resolve_shadows.erase(it);
|
||||
}
|
||||
|
||||
void TextureCacheRuntime::BarrierFeedbackLoop() {
|
||||
@@ -1589,31 +1608,41 @@ 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 (dst.AspectMask() != VK_IMAGE_ASPECT_COLOR_BIT ||
|
||||
VideoCore::Surface::IsPixelFormatInteger(dst.info.format)) {
|
||||
UNIMPLEMENTED_MSG("Copying images with different samples is not supported.");
|
||||
return;
|
||||
}
|
||||
if (ENABLE_MSAA_RESOLVE_CONSUME && msaa_to_non_msaa && copies.size() == 1 &&
|
||||
src.info.format == dst.info.format) {
|
||||
const VideoCommon::ImageCopy& copy = copies.front();
|
||||
const ResolveShadow* const shadow = GetValidResolveShadow(src.Handle());
|
||||
if (shadow != nullptr && copy.src_offset.x == 0 && copy.src_offset.y == 0 &&
|
||||
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.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;
|
||||
VkPipelineStageFlags attachment_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
VkAccessFlags attachment_write = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
VkAccessFlags attachment_read_write =
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != 0) {
|
||||
attachment_stage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT |
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
||||
attachment_write = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
attachment_read_write = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
}
|
||||
const VkImage shadow_image = *shadow->image;
|
||||
const VkImage dst_image = dst.Handle();
|
||||
const VkImageCopy region{
|
||||
.srcSubresource{
|
||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.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 = VK_IMAGE_ASPECT_COLOR_BIT,
|
||||
.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),
|
||||
@@ -1622,26 +1651,27 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src,
|
||||
.extent = {copy.extent.width, copy.extent.height, 1},
|
||||
};
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([shadow_image, dst_image, region](vk::CommandBuffer cmdbuf) {
|
||||
scheduler.Record([shadow_image, dst_image, region, aspect_mask, attachment_stage,
|
||||
attachment_write,
|
||||
attachment_read_write](vk::CommandBuffer cmdbuf) {
|
||||
const std::array pre_barriers{
|
||||
VkImageMemoryBarrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
.srcAccessMask = attachment_write,
|
||||
.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 = shadow_image,
|
||||
.subresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
.subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
VK_REMAINING_ARRAY_LAYERS},
|
||||
},
|
||||
VkImageMemoryBarrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT | attachment_write |
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.oldLayout = VK_IMAGE_LAYOUT_GENERAL,
|
||||
@@ -1649,7 +1679,7 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = dst_image,
|
||||
.subresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
.subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
VK_REMAINING_ARRAY_LAYERS},
|
||||
},
|
||||
};
|
||||
@@ -1664,28 +1694,25 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src,
|
||||
.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
|
||||
.image = shadow_image,
|
||||
.subresourceRange{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
.subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
VK_REMAINING_ARRAY_LAYERS},
|
||||
},
|
||||
VkImageMemoryBarrier{
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
|
||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | attachment_read_write |
|
||||
VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
.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{VK_IMAGE_ASPECT_COLOR_BIT, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
.subresourceRange{aspect_mask, 0, VK_REMAINING_MIP_LEVELS, 0,
|
||||
VK_REMAINING_ARRAY_LAYERS},
|
||||
},
|
||||
};
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
cmdbuf.PipelineBarrier(attachment_stage | VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, 0, nullptr, nullptr,
|
||||
pre_barriers);
|
||||
cmdbuf.CopyImage(shadow_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_image,
|
||||
@@ -1697,6 +1724,11 @@ void TextureCacheRuntime::CopyImageMSAA(Image& dst, Image& src,
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (dst.AspectMask() != VK_IMAGE_ASPECT_COLOR_BIT ||
|
||||
VideoCore::Surface::IsPixelFormatInteger(dst.info.format)) {
|
||||
UNIMPLEMENTED_MSG("Copying images with different samples is not supported.");
|
||||
return;
|
||||
}
|
||||
blit_image_helper.CopyMSAA(render_pass_cache, dst.Handle(), dst.info.format, src.Handle(),
|
||||
src.info.format, num_samples, copies, msaa_to_non_msaa);
|
||||
}
|
||||
@@ -1721,6 +1753,9 @@ void TextureCacheRuntime::TickFrame() {
|
||||
std::erase_if(pending_msaa_images, [this](const auto& pending) {
|
||||
return scheduler.IsFree(pending.first);
|
||||
});
|
||||
std::erase_if(pending_resolve_shadows, [this](const auto& pending) {
|
||||
return scheduler.IsFree(pending.first);
|
||||
});
|
||||
}
|
||||
|
||||
Image::Image(TextureCacheRuntime& runtime_, const ImageInfo& info_, GPUVAddr gpu_addr_,
|
||||
@@ -2663,7 +2698,7 @@ Framebuffer::~Framebuffer() = default;
|
||||
void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
||||
std::span<ImageView*, NUM_RT> color_buffers,
|
||||
ImageView* depth_buffer, bool is_rescaled_) {
|
||||
boost::container::small_vector<VkImageView, NUM_RT + 1> attachments;
|
||||
boost::container::small_vector<VkImageView, NUM_RT * 2 + 2> attachments;
|
||||
RenderPassKey renderpass_key{};
|
||||
s32 num_layers = 1;
|
||||
|
||||
@@ -2692,6 +2727,8 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
||||
++num_images;
|
||||
}
|
||||
const size_t num_colors = attachments.size();
|
||||
VkImage depth_image = VK_NULL_HANDLE;
|
||||
VkImageAspectFlags depth_aspect_mask = 0;
|
||||
if (depth_buffer) {
|
||||
width = (std::min)(width, is_rescaled ? resolution.ScaleUp(depth_buffer->size.width)
|
||||
: depth_buffer->size.width);
|
||||
@@ -2707,6 +2744,8 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
||||
++num_images;
|
||||
has_depth = (subresource_range.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0;
|
||||
has_stencil = (subresource_range.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0;
|
||||
depth_image = depth_buffer->ImageHandle();
|
||||
depth_aspect_mask = subresource_range.aspectMask;
|
||||
} else {
|
||||
renderpass_key.depth_format = PixelFormat::Invalid;
|
||||
}
|
||||
@@ -2715,6 +2754,12 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
||||
samples != VK_SAMPLE_COUNT_1_BIT && num_colors > 0 && runtime.device.IsTiler();
|
||||
renderpass_key.resolve_color = do_resolve_color;
|
||||
|
||||
const bool do_resolve_depth_stencil =
|
||||
samples != VK_SAMPLE_COUNT_1_BIT && depth_image != VK_NULL_HANDLE &&
|
||||
runtime.device.IsTiler() &&
|
||||
SupportsDepthStencilResolve(runtime.device, renderpass_key.depth_format);
|
||||
renderpass_key.resolve_depth_stencil = do_resolve_depth_stencil;
|
||||
|
||||
discard_msaa_color =
|
||||
ENABLE_MSAA_RESOLVE_CONSUME && ENABLE_MSAA_COLOR_DISCARD && do_resolve_color;
|
||||
|
||||
@@ -2735,8 +2780,8 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
||||
MaxwellToVK::SurfaceFormat(runtime.device, FormatType::Optimal, true, format).format;
|
||||
if (ENABLE_MSAA_RESOLVE_CONSUME) {
|
||||
const VkImage msaa_image = images[rt_map[index]];
|
||||
attachments.push_back(runtime.GetOrCreateResolveShadow(msaa_image, vk_format,
|
||||
render_area, layers));
|
||||
attachments.push_back(runtime.GetOrCreateResolveShadow(
|
||||
msaa_image, vk_format, render_area, layers, VK_IMAGE_ASPECT_COLOR_BIT));
|
||||
continue;
|
||||
}
|
||||
VkImageCreateInfo resolve_ci{
|
||||
@@ -2781,6 +2826,16 @@ void Framebuffer::CreateFramebuffer(TextureCacheRuntime& runtime,
|
||||
}
|
||||
}
|
||||
|
||||
if (do_resolve_depth_stencil) {
|
||||
const u32 layers = static_cast<u32>((std::max)(num_layers, 1));
|
||||
const VkFormat vk_format =
|
||||
MaxwellToVK::SurfaceFormat(runtime.device, FormatType::Optimal, true,
|
||||
renderpass_key.depth_format)
|
||||
.format;
|
||||
attachments.push_back(runtime.GetOrCreateResolveShadow(depth_image, vk_format, render_area,
|
||||
layers, depth_aspect_mask));
|
||||
}
|
||||
|
||||
num_color_buffers = static_cast<u32>(num_colors);
|
||||
framebuffer = runtime.device.GetLogical().CreateFramebuffer({
|
||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
|
||||
@@ -117,11 +117,13 @@ public:
|
||||
VkFormat format = VK_FORMAT_UNDEFINED;
|
||||
VkExtent2D extent{};
|
||||
u32 layers = 0;
|
||||
VkImageAspectFlags aspect_mask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
bool up_to_date = false;
|
||||
};
|
||||
|
||||
[[nodiscard]] VkImageView GetOrCreateResolveShadow(VkImage msaa_image, VkFormat format,
|
||||
VkExtent2D extent, u32 layers);
|
||||
VkExtent2D extent, u32 layers,
|
||||
VkImageAspectFlags aspect_mask);
|
||||
|
||||
[[nodiscard]] const ResolveShadow* GetValidResolveShadow(VkImage msaa_image) const;
|
||||
|
||||
@@ -158,6 +160,7 @@ public:
|
||||
std::array<vk::Buffer, indexing_slots> buffers{};
|
||||
std::vector<std::pair<u64, vk::Image>> pending_msaa_images;
|
||||
ankerl::unordered_dense::map<VkImage, ResolveShadow> resolve_shadows;
|
||||
std::vector<std::pair<u64, ResolveShadow>> pending_resolve_shadows;
|
||||
};
|
||||
|
||||
class Framebuffer {
|
||||
|
||||
@@ -1075,6 +1075,12 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
FOR_EACH_VK_FEATURE_EXT(FEATURE_EXTENSION);
|
||||
FOR_EACH_VK_EXTENSION(EXTENSION);
|
||||
|
||||
extensions.depth_stencil_resolve =
|
||||
extensions.depth_stencil_resolve &&
|
||||
(instance_version >= VK_API_VERSION_1_2 || extensions.create_renderpass2);
|
||||
RemoveExtensionIfUnsuitable(extensions.depth_stencil_resolve,
|
||||
VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME);
|
||||
|
||||
if (supported_extensions.contains(VK_KHR_ROBUSTNESS_2_EXTENSION_NAME)) {
|
||||
loaded_extensions.erase(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
|
||||
loaded_extensions.insert(VK_KHR_ROBUSTNESS_2_EXTENSION_NAME);
|
||||
@@ -1222,6 +1228,11 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR;
|
||||
SetNext(next, properties.push_descriptor);
|
||||
}
|
||||
if (extensions.depth_stencil_resolve || 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);
|
||||
}
|
||||
if (extensions.descriptor_buffer) {
|
||||
properties.descriptor_buffer.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT;
|
||||
|
||||
@@ -90,6 +90,8 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
||||
EXTENSION(EXT, SHADER_VIEWPORT_INDEX_LAYER, shader_viewport_index_layer) \
|
||||
EXTENSION(EXT, TOOLING_INFO, tooling_info) \
|
||||
EXTENSION(EXT, VERTEX_ATTRIBUTE_DIVISOR, vertex_attribute_divisor) \
|
||||
EXTENSION(KHR, CREATE_RENDERPASS_2, create_renderpass2) \
|
||||
EXTENSION(KHR, DEPTH_STENCIL_RESOLVE, depth_stencil_resolve) \
|
||||
EXTENSION(KHR, DRAW_INDIRECT_COUNT, draw_indirect_count) \
|
||||
EXTENSION(KHR, DRIVER_PROPERTIES, driver_properties) \
|
||||
EXTENSION(KHR, PUSH_DESCRIPTOR, push_descriptor) \
|
||||
@@ -611,6 +613,37 @@ FN_MAX_LIMIT_LIST
|
||||
return extensions.shader_stencil_export;
|
||||
}
|
||||
|
||||
/// Returns true if the device supports VK_KHR_create_renderpass2.
|
||||
bool IsKhrCreateRenderPass2Supported() const {
|
||||
return extensions.create_renderpass2 || instance_version >= VK_API_VERSION_1_2;
|
||||
}
|
||||
|
||||
/// Returns true if the device supports VK_KHR_depth_stencil_resolve.
|
||||
bool IsKhrDepthStencilResolveSupported() const {
|
||||
return (extensions.depth_stencil_resolve || instance_version >= VK_API_VERSION_1_2) &&
|
||||
IsKhrCreateRenderPass2Supported();
|
||||
}
|
||||
|
||||
/// Returns the supported resolve modes for the depth aspect.
|
||||
VkResolveModeFlags GetDepthResolveModes() const {
|
||||
return properties.depth_stencil_resolve.supportedDepthResolveModes;
|
||||
}
|
||||
|
||||
/// Returns the supported resolve modes for the stencil aspect.
|
||||
VkResolveModeFlags GetStencilResolveModes() const {
|
||||
return properties.depth_stencil_resolve.supportedStencilResolveModes;
|
||||
}
|
||||
|
||||
/// Returns true if the depth and stencil aspects may resolve with different modes.
|
||||
bool SupportsIndependentResolve() const {
|
||||
return properties.depth_stencil_resolve.independentResolve == VK_TRUE;
|
||||
}
|
||||
|
||||
/// Returns true if only one of the depth and stencil aspects may be resolved.
|
||||
bool SupportsIndependentResolveNone() const {
|
||||
return properties.depth_stencil_resolve.independentResolveNone == VK_TRUE;
|
||||
}
|
||||
|
||||
/// Returns true if depth/stencil operations can be performed efficiently.
|
||||
/// Either through shader export or hardware blits.
|
||||
bool CanPerformDepthStencilOperations() const {
|
||||
@@ -1166,6 +1199,7 @@ private:
|
||||
VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};
|
||||
VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback{};
|
||||
VkPhysicalDeviceMaintenance5PropertiesKHR maintenance5{};
|
||||
VkPhysicalDeviceDepthStencilResolveProperties depth_stencil_resolve{};
|
||||
|
||||
VkPhysicalDeviceProperties properties{};
|
||||
};
|
||||
|
||||
@@ -184,6 +184,7 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
|
||||
X(vkCreatePipelineLayout);
|
||||
X(vkCreateQueryPool);
|
||||
X(vkCreateRenderPass);
|
||||
X(vkCreateRenderPass2);
|
||||
X(vkCreateSampler);
|
||||
X(vkCreateSemaphore);
|
||||
X(vkCreateShaderModule);
|
||||
@@ -270,6 +271,11 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
|
||||
if (!dld.vkQueueSubmit2) {
|
||||
Proc(dld.vkQueueSubmit2, dld, "vkQueueSubmit2KHR", device);
|
||||
}
|
||||
|
||||
// Render pass creation v2 is core in Vulkan 1.2, otherwise requires VK_KHR_create_renderpass2
|
||||
if (!dld.vkCreateRenderPass2) {
|
||||
Proc(dld.vkCreateRenderPass2, dld, "vkCreateRenderPass2KHR", device);
|
||||
}
|
||||
#undef X
|
||||
}
|
||||
|
||||
@@ -725,6 +731,12 @@ RenderPass Device::CreateRenderPass(const VkRenderPassCreateInfo& ci) const {
|
||||
return RenderPass(object, handle, *dld);
|
||||
}
|
||||
|
||||
RenderPass Device::CreateRenderPass2(const VkRenderPassCreateInfo2& ci) const {
|
||||
VkRenderPass object;
|
||||
Check(dld->vkCreateRenderPass2(handle, &ci, nullptr, &object));
|
||||
return RenderPass(object, handle, *dld);
|
||||
}
|
||||
|
||||
DescriptorSetLayout Device::CreateDescriptorSetLayout(
|
||||
const VkDescriptorSetLayoutCreateInfo& ci) const {
|
||||
VkDescriptorSetLayout object;
|
||||
|
||||
@@ -300,6 +300,7 @@ struct DeviceDispatch : InstanceDispatch {
|
||||
PFN_vkCreatePipelineLayout vkCreatePipelineLayout{};
|
||||
PFN_vkCreateQueryPool vkCreateQueryPool{};
|
||||
PFN_vkCreateRenderPass vkCreateRenderPass{};
|
||||
PFN_vkCreateRenderPass2 vkCreateRenderPass2{};
|
||||
PFN_vkCreateSampler vkCreateSampler{};
|
||||
PFN_vkCreateSemaphore vkCreateSemaphore{};
|
||||
PFN_vkCreateShaderModule vkCreateShaderModule{};
|
||||
@@ -1045,6 +1046,8 @@ public:
|
||||
|
||||
[[nodiscard]] RenderPass CreateRenderPass(const VkRenderPassCreateInfo& ci) const;
|
||||
|
||||
[[nodiscard]] RenderPass CreateRenderPass2(const VkRenderPassCreateInfo2& ci) const;
|
||||
|
||||
[[nodiscard]] DescriptorSetLayout CreateDescriptorSetLayout(
|
||||
const VkDescriptorSetLayoutCreateInfo& ci) const;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user