mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-04 23:55:08 +01:00
Fix Render Pass Cache
The Vulkan render pass cache was fundamentally broken since it was designed around the Render Pass Compatibility clause due to being designed for framebuffer compatibility initially. As this scope was extended to a general render pass cache, the amount of data in the key was not extended to include everything it should have. This commit introduces the missing pieces in the RP cache and simplifies the underlying code in the process.
This commit is contained in:
parent
25a29f9044
commit
47bc3b4d99
23
app/src/main/cpp/skyline/gpu/cache/common.h
vendored
23
app/src/main/cpp/skyline/gpu/cache/common.h
vendored
@ -1,23 +0,0 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
// Copyright © 2022 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
#include <common.h>
|
||||
|
||||
namespace skyline::gpu::cache {
|
||||
/**
|
||||
* @brief All unique metadata in a single attachment for a compatible render pass according to Render Pass Compatibility clause in the Vulkan specification
|
||||
* @url https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#renderpass-compatibility
|
||||
* @url https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkAttachmentDescription.html
|
||||
*/
|
||||
struct AttachmentMetadata {
|
||||
vk::Format format;
|
||||
vk::SampleCountFlagBits sampleCount;
|
||||
|
||||
constexpr AttachmentMetadata(vk::Format format, vk::SampleCountFlagBits sampleCount) : format(format), sampleCount(sampleCount) {}
|
||||
|
||||
bool operator==(const AttachmentMetadata &rhs) const = default;
|
||||
};
|
||||
}
|
@ -3,7 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
#include <common.h>
|
||||
|
||||
namespace skyline::gpu::cache {
|
||||
using FramebufferCreateInfo = vk::StructureChain<vk::FramebufferCreateInfo, vk::FramebufferAttachmentsCreateInfo>;
|
||||
|
@ -3,8 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
#include <gpu/texture/texture.h>
|
||||
#include "common.h"
|
||||
|
||||
namespace skyline::gpu::cache {
|
||||
/**
|
||||
@ -48,6 +48,24 @@ namespace skyline::gpu::cache {
|
||||
};
|
||||
|
||||
private:
|
||||
GPU &gpu;
|
||||
std::mutex mutex; //!< Synchronizes accesses to the pipeline cache
|
||||
vk::raii::PipelineCache vkPipelineCache; //!< A Vulkan Pipeline Cache which stores all unique graphics pipelines
|
||||
|
||||
/**
|
||||
* @brief All unique metadata in a single attachment for a compatible render pass according to Render Pass Compatibility clause in the Vulkan specification
|
||||
* @url https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#renderpass-compatibility
|
||||
* @url https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkAttachmentDescription.html
|
||||
*/
|
||||
struct AttachmentMetadata {
|
||||
vk::Format format;
|
||||
vk::SampleCountFlagBits sampleCount;
|
||||
|
||||
constexpr AttachmentMetadata(vk::Format format, vk::SampleCountFlagBits sampleCount) : format(format), sampleCount(sampleCount) {}
|
||||
|
||||
bool operator==(const AttachmentMetadata &rhs) const = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief All data in PipelineState in value form to allow cheap heterogenous lookups with reference types while still storing a value-based key in the map
|
||||
*/
|
||||
@ -92,11 +110,6 @@ namespace skyline::gpu::cache {
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
GPU &gpu;
|
||||
std::mutex mutex; //!< Synchronizes accesses to the pipeline cache
|
||||
vk::raii::PipelineCache vkPipelineCache; //!< A Vulkan Pipeline Cache which stores all unique graphics pipelines
|
||||
|
||||
struct PipelineStateHash {
|
||||
using is_transparent = std::true_type;
|
||||
|
||||
|
@ -6,37 +6,24 @@
|
||||
#include "renderpass_cache.h"
|
||||
|
||||
namespace skyline::gpu::cache {
|
||||
RenderPassCache::RenderPassCache(gpu::GPU &gpu) : gpu(gpu) {}
|
||||
RenderPassCache::RenderPassCache(gpu::GPU &gpu) : gpu{gpu} {}
|
||||
|
||||
RenderPassCache::RenderPassMetadata::RenderPassMetadata(const vk::RenderPassCreateInfo &createInfo) {
|
||||
for (const auto &attachment : span<const vk::AttachmentDescription>{createInfo.pAttachments, createInfo.attachmentCount})
|
||||
attachments.emplace_back(attachment.format, attachment.samples);
|
||||
#define VEC_CPY(pointer, size) description.pointer, description.pointer + description.size
|
||||
|
||||
subpasses.reserve(createInfo.subpassCount);
|
||||
for (const auto &subpass : span<const vk::SubpassDescription>{createInfo.pSubpasses, createInfo.subpassCount}) {
|
||||
auto &subpassMetadata{subpasses.emplace_back()};
|
||||
RenderPassCache::SubpassDescription::SubpassDescription(const vk::SubpassDescription &description)
|
||||
: flags{description.flags},
|
||||
pipelineBindPoint{description.pipelineBindPoint},
|
||||
inputAttachments{VEC_CPY(pInputAttachments, inputAttachmentCount)},
|
||||
colorAttachments{VEC_CPY(pColorAttachments, colorAttachmentCount)},
|
||||
resolveAttachments{description.pResolveAttachments, description.pResolveAttachments + (description.pResolveAttachments ? description.colorAttachmentCount : 0)},
|
||||
depthStencilAttachment{description.pDepthStencilAttachment ? *description.pDepthStencilAttachment : std::optional<vk::AttachmentReference>{}},
|
||||
preserveAttachments{VEC_CPY(pPreserveAttachments, preserveAttachmentCount)} {}
|
||||
|
||||
subpassMetadata.inputAttachments.reserve(subpass.inputAttachmentCount);
|
||||
for (const auto &reference : span<const vk::AttachmentReference>{subpass.pInputAttachments, subpass.inputAttachmentCount})
|
||||
subpassMetadata.inputAttachments.emplace_back(reference.attachment);
|
||||
#undef VEC_CPY
|
||||
|
||||
subpassMetadata.colorAttachments.reserve(subpass.colorAttachmentCount);
|
||||
for (const auto &reference : span<const vk::AttachmentReference>{subpass.pColorAttachments, subpass.colorAttachmentCount})
|
||||
subpassMetadata.colorAttachments.emplace_back(reference.attachment);
|
||||
|
||||
auto resolveAttachmentCount{subpass.pResolveAttachments ? subpass.colorAttachmentCount : 0};
|
||||
subpassMetadata.resolveAttachments.reserve(resolveAttachmentCount);
|
||||
for (const auto &reference : span<const vk::AttachmentReference>{subpass.pResolveAttachments, resolveAttachmentCount})
|
||||
subpassMetadata.resolveAttachments.emplace_back(reference.attachment);
|
||||
|
||||
if (subpass.pDepthStencilAttachment)
|
||||
subpassMetadata.depthStencilAttachment.emplace(subpass.pDepthStencilAttachment->attachment);
|
||||
|
||||
subpassMetadata.preserveAttachments.reserve(subpass.preserveAttachmentCount);
|
||||
for (const auto &index : span<const u32>{subpass.pPreserveAttachments, subpass.preserveAttachmentCount})
|
||||
subpassMetadata.resolveAttachments.emplace_back(index);
|
||||
}
|
||||
}
|
||||
RenderPassCache::RenderPassMetadata::RenderPassMetadata(const vk::RenderPassCreateInfo &createInfo)
|
||||
: attachments{createInfo.pAttachments, createInfo.pAttachments + createInfo.attachmentCount},
|
||||
subpasses{createInfo.pSubpasses, createInfo.pSubpasses + createInfo.subpassCount} {}
|
||||
|
||||
#define HASH(x) boost::hash_combine(hash, x)
|
||||
|
||||
@ -45,27 +32,39 @@ namespace skyline::gpu::cache {
|
||||
|
||||
HASH(key.attachments.size());
|
||||
for (const auto &attachment : key.attachments) {
|
||||
HASH(static_cast<VkAttachmentDescriptionFlags>(attachment.flags));
|
||||
HASH(attachment.format);
|
||||
HASH(attachment.sampleCount);
|
||||
HASH(attachment.samples);
|
||||
HASH(attachment.loadOp);
|
||||
HASH(attachment.storeOp);
|
||||
HASH(attachment.stencilLoadOp);
|
||||
HASH(attachment.stencilStoreOp);
|
||||
HASH(attachment.initialLayout);
|
||||
HASH(attachment.finalLayout);
|
||||
}
|
||||
|
||||
HASH(key.subpasses.size());
|
||||
for (const auto &subpass : key.subpasses) {
|
||||
HASH(subpass.inputAttachments.size());
|
||||
for (const auto &reference : subpass.inputAttachments)
|
||||
HASH(reference);
|
||||
HASH(static_cast<VkSubpassDescriptionFlags>(subpass.flags));
|
||||
HASH(subpass.pipelineBindPoint);
|
||||
|
||||
HASH(subpass.colorAttachments.size());
|
||||
for (const auto &reference : subpass.colorAttachments)
|
||||
HASH(reference);
|
||||
auto hashReferences{[&hash](const auto &references) {
|
||||
HASH(references.size());
|
||||
for (const auto &reference : references) {
|
||||
HASH(reference.attachment);
|
||||
HASH(reference.layout);
|
||||
}
|
||||
}};
|
||||
|
||||
HASH(subpass.resolveAttachments.size());
|
||||
for (const auto &reference : subpass.resolveAttachments)
|
||||
HASH(reference);
|
||||
hashReferences(subpass.inputAttachments);
|
||||
hashReferences(subpass.colorAttachments);
|
||||
hashReferences(subpass.resolveAttachments);
|
||||
|
||||
HASH(subpass.depthStencilAttachment.has_value());
|
||||
if (subpass.depthStencilAttachment)
|
||||
HASH(*subpass.depthStencilAttachment);
|
||||
if (subpass.depthStencilAttachment) {
|
||||
HASH(subpass.depthStencilAttachment->attachment);
|
||||
HASH(subpass.depthStencilAttachment->layout);
|
||||
}
|
||||
|
||||
HASH(subpass.preserveAttachments.size());
|
||||
for (const auto &index : subpass.preserveAttachments)
|
||||
@ -80,28 +79,40 @@ namespace skyline::gpu::cache {
|
||||
|
||||
HASH(key.attachmentCount);
|
||||
for (const auto &attachment : span<const vk::AttachmentDescription>{key.pAttachments, key.attachmentCount}) {
|
||||
HASH(static_cast<VkAttachmentDescriptionFlags>(attachment.flags));
|
||||
HASH(attachment.format);
|
||||
HASH(attachment.samples);
|
||||
HASH(attachment.loadOp);
|
||||
HASH(attachment.storeOp);
|
||||
HASH(attachment.stencilLoadOp);
|
||||
HASH(attachment.stencilStoreOp);
|
||||
HASH(attachment.initialLayout);
|
||||
HASH(attachment.finalLayout);
|
||||
}
|
||||
|
||||
HASH(key.subpassCount);
|
||||
for (const auto &subpass : span<const vk::SubpassDescription>{key.pSubpasses, key.subpassCount}) {
|
||||
HASH(subpass.inputAttachmentCount);
|
||||
for (const auto &reference : span<const vk::AttachmentReference>{subpass.pInputAttachments, subpass.inputAttachmentCount})
|
||||
HASH(reference.attachment);
|
||||
HASH(static_cast<VkSubpassDescriptionFlags>(subpass.flags));
|
||||
HASH(subpass.pipelineBindPoint);
|
||||
|
||||
HASH(subpass.colorAttachmentCount);
|
||||
for (const auto &reference : span<const vk::AttachmentReference>{subpass.pColorAttachments, subpass.colorAttachmentCount})
|
||||
HASH(reference.attachment);
|
||||
auto hashReferences{[&hash](const vk::AttachmentReference *data, u32 count) {
|
||||
HASH(count);
|
||||
for (const auto &reference : span<const vk::AttachmentReference>{data, count}) {
|
||||
HASH(reference.attachment);
|
||||
HASH(reference.layout);
|
||||
}
|
||||
}};
|
||||
|
||||
u32 resolveAttachmentCount{subpass.pResolveAttachments ? subpass.colorAttachmentCount : 0};
|
||||
HASH(resolveAttachmentCount);
|
||||
for (const auto &reference : span<const vk::AttachmentReference>{subpass.pResolveAttachments, resolveAttachmentCount})
|
||||
HASH(reference.attachment);
|
||||
hashReferences(subpass.pInputAttachments, subpass.inputAttachmentCount);
|
||||
hashReferences(subpass.pColorAttachments, subpass.colorAttachmentCount);
|
||||
if (subpass.pResolveAttachments)
|
||||
hashReferences(subpass.pResolveAttachments, subpass.colorAttachmentCount);
|
||||
|
||||
HASH(subpass.pDepthStencilAttachment != nullptr);
|
||||
if (subpass.pDepthStencilAttachment)
|
||||
if (subpass.pDepthStencilAttachment) {
|
||||
HASH(subpass.pDepthStencilAttachment->attachment);
|
||||
HASH(subpass.pDepthStencilAttachment->layout);
|
||||
}
|
||||
|
||||
HASH(subpass.preserveAttachmentCount);
|
||||
for (const auto &index : span<const u32>{subpass.pPreserveAttachments, subpass.preserveAttachmentCount})
|
||||
@ -119,41 +130,29 @@ namespace skyline::gpu::cache {
|
||||
|
||||
bool RenderPassCache::RenderPassEqual::operator()(const RenderPassMetadata &lhs, const vk::RenderPassCreateInfo &rhs) const {
|
||||
#define RETF(condition) if (condition) { return false; }
|
||||
#define RETARRNEQ(array, pointer, count) RETF(!std::equal(array.begin(), array.end(), pointer, pointer + count))
|
||||
|
||||
RETF(lhs.attachments.size() != rhs.attachmentCount)
|
||||
const vk::AttachmentDescription *vkAttachment{rhs.pAttachments};
|
||||
for (const auto &attachment : lhs.attachments) {
|
||||
RETF(attachment.format != vkAttachment->format)
|
||||
RETF(attachment.sampleCount != vkAttachment->samples)
|
||||
vkAttachment++;
|
||||
}
|
||||
RETARRNEQ(lhs.attachments, rhs.pAttachments, rhs.attachmentCount)
|
||||
|
||||
RETF(lhs.subpasses.size() != rhs.subpassCount)
|
||||
const vk::SubpassDescription *vkSubpass{rhs.pSubpasses};
|
||||
for (const auto &subpass : lhs.subpasses) {
|
||||
RETF(subpass.inputAttachments.size() != vkSubpass->inputAttachmentCount)
|
||||
const vk::AttachmentReference *vkReference{vkSubpass->pInputAttachments};
|
||||
for (const auto &reference : subpass.inputAttachments)
|
||||
RETF(reference != (vkReference++)->attachment)
|
||||
RETF(subpass.flags != vkSubpass->flags)
|
||||
RETF(subpass.pipelineBindPoint != vkSubpass->pipelineBindPoint)
|
||||
|
||||
RETF(subpass.colorAttachments.size() != vkSubpass->colorAttachmentCount)
|
||||
vkReference = vkSubpass->pColorAttachments;
|
||||
for (const auto &reference : subpass.colorAttachments)
|
||||
RETF(reference != (vkReference++)->attachment)
|
||||
RETARRNEQ(subpass.inputAttachments, vkSubpass->pInputAttachments, vkSubpass->inputAttachmentCount)
|
||||
RETARRNEQ(subpass.colorAttachments, vkSubpass->pColorAttachments, vkSubpass->colorAttachmentCount)
|
||||
|
||||
RETF(subpass.resolveAttachments.size() != (vkSubpass->pResolveAttachments ? vkSubpass->colorAttachmentCount : 0))
|
||||
vkReference = vkSubpass->pResolveAttachments;
|
||||
for (const auto &reference : subpass.resolveAttachments)
|
||||
RETF(reference != (vkReference++)->attachment)
|
||||
if (!subpass.resolveAttachments.empty())
|
||||
RETARRNEQ(subpass.resolveAttachments, vkSubpass->pResolveAttachments, vkSubpass->colorAttachmentCount)
|
||||
|
||||
RETF(subpass.depthStencilAttachment.has_value() != (vkSubpass->pDepthStencilAttachment != nullptr))
|
||||
if (subpass.depthStencilAttachment)
|
||||
RETF(*subpass.depthStencilAttachment != vkSubpass->pDepthStencilAttachment->attachment)
|
||||
RETF(subpass.depthStencilAttachment->attachment != vkSubpass->pDepthStencilAttachment->attachment &&
|
||||
subpass.depthStencilAttachment->layout != vkSubpass->pDepthStencilAttachment->layout)
|
||||
|
||||
RETF(subpass.preserveAttachments.size() != vkSubpass->preserveAttachmentCount)
|
||||
const u32 *vkIndex{vkSubpass->pPreserveAttachments};
|
||||
for (const auto &attachment : subpass.preserveAttachments)
|
||||
RETF(attachment != *(vkIndex++))
|
||||
RETARRNEQ(subpass.preserveAttachments, vkSubpass->pPreserveAttachments, vkSubpass->preserveAttachmentCount)
|
||||
|
||||
vkSubpass++;
|
||||
}
|
||||
|
@ -3,7 +3,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include <vulkan/vulkan_raii.hpp>
|
||||
#include <common.h>
|
||||
|
||||
namespace skyline::gpu::cache {
|
||||
/**
|
||||
@ -14,31 +15,29 @@ namespace skyline::gpu::cache {
|
||||
GPU &gpu;
|
||||
std::mutex mutex; //!< Synchronizes access to the cache
|
||||
|
||||
using AttachmentReference = u32;
|
||||
|
||||
/**
|
||||
* @brief All unique metadata in a single subpass for a compatible render pass according to Render Pass Compatibility clause in the Vulkan specification
|
||||
* @url https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#renderpass-compatibility
|
||||
* @url https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSubpassDescription.html
|
||||
*/
|
||||
struct SubpassMetadata {
|
||||
std::vector<AttachmentReference> inputAttachments;
|
||||
std::vector<AttachmentReference> colorAttachments;
|
||||
std::vector<AttachmentReference> resolveAttachments;
|
||||
std::optional<AttachmentReference> depthStencilAttachment;
|
||||
std::vector<AttachmentReference> preserveAttachments;
|
||||
struct SubpassDescription {
|
||||
vk::SubpassDescriptionFlags flags;
|
||||
vk::PipelineBindPoint pipelineBindPoint;
|
||||
std::vector<vk::AttachmentReference> inputAttachments;
|
||||
std::vector<vk::AttachmentReference> colorAttachments;
|
||||
std::vector<vk::AttachmentReference> resolveAttachments;
|
||||
std::optional<vk::AttachmentReference> depthStencilAttachment;
|
||||
std::vector<u32> preserveAttachments;
|
||||
|
||||
bool operator==(const SubpassMetadata &rhs) const = default;
|
||||
SubpassDescription(const vk::SubpassDescription &description);
|
||||
|
||||
bool operator==(const SubpassDescription &rhs) const = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief All unique metadata in a render pass for a corresponding compatible render pass according to Render Pass Compatibility clause in the Vulkan specification
|
||||
* @url https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#renderpass-compatibility
|
||||
* @url https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkRenderPassCreateInfo.html
|
||||
*/
|
||||
struct RenderPassMetadata {
|
||||
std::vector<AttachmentMetadata> attachments;
|
||||
std::vector<SubpassMetadata> subpasses;
|
||||
std::vector<vk::AttachmentDescription> attachments;
|
||||
std::vector<SubpassDescription> subpasses;
|
||||
|
||||
RenderPassMetadata(const vk::RenderPassCreateInfo &createInfo);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user