Vulkan: Move render pass management to ObjectCache

This commit is contained in:
Stenzek 2017-09-09 14:04:26 +10:00
parent 0e50b2c9f2
commit 173a33886c
12 changed files with 178 additions and 376 deletions

View File

@ -40,14 +40,12 @@ FramebufferManager::FramebufferManager()
FramebufferManager::~FramebufferManager() FramebufferManager::~FramebufferManager()
{ {
DestroyEFBFramebuffer(); DestroyEFBFramebuffer();
DestroyEFBRenderPass();
DestroyConversionShaders(); DestroyConversionShaders();
DestroyReadbackFramebuffer(); DestroyReadbackFramebuffer();
DestroyReadbackTextures(); DestroyReadbackTextures();
DestroyReadbackShaders(); DestroyReadbackShaders();
DestroyReadbackRenderPasses();
DestroyPokeVertexBuffer(); DestroyPokeVertexBuffer();
DestroyPokeShaders(); DestroyPokeShaders();
@ -88,7 +86,7 @@ MultisamplingState FramebufferManager::GetEFBMultisamplingState() const
bool FramebufferManager::Initialize() bool FramebufferManager::Initialize()
{ {
if (!CreateEFBRenderPass()) if (!CreateEFBRenderPasses())
{ {
PanicAlert("Failed to create EFB render pass"); PanicAlert("Failed to create EFB render pass");
return false; return false;
@ -142,108 +140,18 @@ bool FramebufferManager::Initialize()
return true; return true;
} }
bool FramebufferManager::CreateEFBRenderPass() bool FramebufferManager::CreateEFBRenderPasses()
{ {
VkSampleCountFlagBits samples = static_cast<VkSampleCountFlagBits>(g_ActiveConfig.iMultisamples); m_efb_load_render_pass =
g_object_cache->GetRenderPass(EFB_COLOR_TEXTURE_FORMAT, EFB_DEPTH_TEXTURE_FORMAT,
// render pass for rendering to the efb g_ActiveConfig.iMultisamples, VK_ATTACHMENT_LOAD_OP_LOAD);
VkAttachmentDescription attachments[] = { m_efb_clear_render_pass =
{0, EFB_COLOR_TEXTURE_FORMAT, samples, VK_ATTACHMENT_LOAD_OP_LOAD, g_object_cache->GetRenderPass(EFB_COLOR_TEXTURE_FORMAT, EFB_DEPTH_TEXTURE_FORMAT,
VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, g_ActiveConfig.iMultisamples, VK_ATTACHMENT_LOAD_OP_CLEAR);
VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, m_depth_resolve_render_pass = g_object_cache->GetRenderPass(
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT, VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
{0, EFB_DEPTH_TEXTURE_FORMAT, samples, VK_ATTACHMENT_LOAD_OP_LOAD, return m_efb_load_render_pass != VK_NULL_HANDLE && m_efb_clear_render_pass != VK_NULL_HANDLE &&
VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, m_depth_resolve_render_pass != VK_NULL_HANDLE;
VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}};
VkAttachmentReference color_attachment_references[] = {
{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}};
VkAttachmentReference depth_attachment_reference = {
1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
VkSubpassDescription subpass_description = {
0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1, color_attachment_references,
nullptr, &depth_attachment_reference, 0, nullptr};
VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
nullptr,
0,
static_cast<u32>(ArraySize(attachments)),
attachments,
1,
&subpass_description,
0,
nullptr};
VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr,
&m_efb_load_render_pass);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateRenderPass (EFB) failed: ");
return false;
}
// render pass for clearing color/depth on load, as opposed to loading it
attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr,
&m_efb_clear_render_pass);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateRenderPass (EFB) failed: ");
return false;
}
// render pass for resolving depth, since we can't do it with vkCmdResolveImage
if (g_ActiveConfig.MultisamplingEnabled())
{
VkAttachmentDescription resolve_attachment = {0,
EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT,
VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
subpass_description.pDepthStencilAttachment = nullptr;
pass_info.pAttachments = &resolve_attachment;
pass_info.attachmentCount = 1;
res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr,
&m_depth_resolve_render_pass);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateRenderPass (EFB depth resolve) failed: ");
return false;
}
}
return true;
}
void FramebufferManager::DestroyEFBRenderPass()
{
if (m_efb_load_render_pass != VK_NULL_HANDLE)
{
vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_efb_load_render_pass, nullptr);
m_efb_load_render_pass = VK_NULL_HANDLE;
}
if (m_efb_clear_render_pass != VK_NULL_HANDLE)
{
vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_efb_clear_render_pass, nullptr);
m_efb_clear_render_pass = VK_NULL_HANDLE;
}
if (m_depth_resolve_render_pass != VK_NULL_HANDLE)
{
vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_depth_resolve_render_pass, nullptr);
m_depth_resolve_render_pass = VK_NULL_HANDLE;
}
} }
bool FramebufferManager::CreateEFBFramebuffer() bool FramebufferManager::CreateEFBFramebuffer()
@ -419,9 +327,7 @@ void FramebufferManager::ResizeEFBTextures()
void FramebufferManager::RecreateRenderPass() void FramebufferManager::RecreateRenderPass()
{ {
DestroyEFBRenderPass(); if (!CreateEFBRenderPasses())
if (!CreateEFBRenderPass())
PanicAlert("Failed to create EFB render pass"); PanicAlert("Failed to create EFB render pass");
} }
@ -849,62 +755,12 @@ void FramebufferManager::InvalidatePeekCache()
bool FramebufferManager::CreateReadbackRenderPasses() bool FramebufferManager::CreateReadbackRenderPasses()
{ {
VkAttachmentDescription copy_attachment = { m_copy_color_render_pass = g_object_cache->GetRenderPass(
0, // VkAttachmentDescriptionFlags flags EFB_COLOR_TEXTURE_FORMAT, VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
EFB_COLOR_TEXTURE_FORMAT, // VkFormat format m_copy_depth_render_pass = g_object_cache->GetRenderPass(
VK_SAMPLE_COUNT_1_BIT, // VkSampleCountFlagBits samples EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT, VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp loadOp if (m_copy_color_render_pass == VK_NULL_HANDLE || m_copy_depth_render_pass == VK_NULL_HANDLE)
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout
};
VkAttachmentReference copy_attachment_ref = {
0, // uint32_t attachment
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout layout
};
VkSubpassDescription copy_subpass = {
0, // VkSubpassDescriptionFlags flags
VK_PIPELINE_BIND_POINT_GRAPHICS, // VkPipelineBindPoint pipelineBindPoint
0, // uint32_t inputAttachmentCount
nullptr, // const VkAttachmentReference* pInputAttachments
1, // uint32_t colorAttachmentCount
&copy_attachment_ref, // const VkAttachmentReference* pColorAttachments
nullptr, // const VkAttachmentReference* pResolveAttachments
nullptr, // const VkAttachmentReference* pDepthStencilAttachment
0, // uint32_t preserveAttachmentCount
nullptr // const uint32_t* pPreserveAttachments
};
VkRenderPassCreateInfo copy_pass = {
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType
nullptr, // const void* pNext
0, // VkRenderPassCreateFlags flags
1, // uint32_t attachmentCount
&copy_attachment, // const VkAttachmentDescription* pAttachments
1, // uint32_t subpassCount
&copy_subpass, // const VkSubpassDescription* pSubpasses
0, // uint32_t dependencyCount
nullptr // const VkSubpassDependency* pDependencies
};
VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &copy_pass, nullptr,
&m_copy_color_render_pass);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateRenderPass failed: ");
return false; return false;
}
// Depth is similar to copy, just a different format.
copy_attachment.format = EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT;
res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &copy_pass, nullptr,
&m_copy_depth_render_pass);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateRenderPass failed: ");
return false;
}
// Some devices don't support point sizes >1 (e.g. Adreno). // Some devices don't support point sizes >1 (e.g. Adreno).
// If we can't use a point size above our maximum IR, use triangles instead. // If we can't use a point size above our maximum IR, use triangles instead.
@ -925,20 +781,6 @@ bool FramebufferManager::CreateReadbackRenderPasses()
return true; return true;
} }
void FramebufferManager::DestroyReadbackRenderPasses()
{
if (m_copy_color_render_pass != VK_NULL_HANDLE)
{
vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_copy_color_render_pass, nullptr);
m_copy_color_render_pass = VK_NULL_HANDLE;
}
if (m_copy_depth_render_pass != VK_NULL_HANDLE)
{
vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_copy_depth_render_pass, nullptr);
m_copy_depth_render_pass = VK_NULL_HANDLE;
}
}
bool FramebufferManager::CompileReadbackShaders() bool FramebufferManager::CompileReadbackShaders()
{ {
std::string source; std::string source;

View File

@ -82,8 +82,7 @@ private:
u32 color; u32 color;
}; };
bool CreateEFBRenderPass(); bool CreateEFBRenderPasses();
void DestroyEFBRenderPass();
bool CreateEFBFramebuffer(); bool CreateEFBFramebuffer();
void DestroyEFBFramebuffer(); void DestroyEFBFramebuffer();
@ -91,7 +90,6 @@ private:
void DestroyConversionShaders(); void DestroyConversionShaders();
bool CreateReadbackRenderPasses(); bool CreateReadbackRenderPasses();
void DestroyReadbackRenderPasses();
bool CompileReadbackShaders(); bool CompileReadbackShaders();
void DestroyReadbackShaders(); void DestroyReadbackShaders();
bool CreateReadbackTextures(); bool CreateReadbackTextures();

View File

@ -37,6 +37,7 @@ ObjectCache::~ObjectCache()
DestroySamplers(); DestroySamplers();
DestroyPipelineLayouts(); DestroyPipelineLayouts();
DestroyDescriptorSetLayouts(); DestroyDescriptorSetLayouts();
DestroyRenderPassCache();
} }
bool ObjectCache::Initialize() bool ObjectCache::Initialize()
@ -358,4 +359,90 @@ VkSampler ObjectCache::GetSampler(const SamplerState& info)
m_sampler_cache.emplace(info, sampler); m_sampler_cache.emplace(info, sampler);
return sampler; return sampler;
} }
VkRenderPass ObjectCache::GetRenderPass(VkFormat color_format, VkFormat depth_format,
u32 multisamples, VkAttachmentLoadOp load_op)
{
auto key = std::tie(color_format, depth_format, multisamples, load_op);
auto it = m_render_pass_cache.find(key);
if (it != m_render_pass_cache.end())
return it->second;
VkAttachmentReference color_reference;
VkAttachmentReference* color_reference_ptr = nullptr;
VkAttachmentReference depth_reference;
VkAttachmentReference* depth_reference_ptr = nullptr;
std::array<VkAttachmentDescription, 2> attachments;
u32 num_attachments = 0;
if (color_format != VK_FORMAT_UNDEFINED)
{
attachments[num_attachments] = {0,
color_format,
static_cast<VkSampleCountFlagBits>(multisamples),
load_op,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
color_reference.attachment = num_attachments;
color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
color_reference_ptr = &color_reference;
num_attachments++;
}
if (depth_format != VK_FORMAT_UNDEFINED)
{
attachments[num_attachments] = {0,
depth_format,
static_cast<VkSampleCountFlagBits>(multisamples),
load_op,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL};
depth_reference.attachment = num_attachments;
depth_reference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depth_reference_ptr = &depth_reference;
num_attachments++;
}
VkSubpassDescription subpass = {0,
VK_PIPELINE_BIND_POINT_GRAPHICS,
0,
nullptr,
color_reference_ptr ? 1u : 0u,
color_reference_ptr ? color_reference_ptr : nullptr,
nullptr,
depth_reference_ptr,
0,
nullptr};
VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
nullptr,
0,
num_attachments,
attachments.data(),
1,
&subpass,
0,
nullptr};
VkRenderPass pass;
VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr, &pass);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateRenderPass failed: ");
return VK_NULL_HANDLE;
}
m_render_pass_cache.emplace(key, pass);
return pass;
}
void ObjectCache::DestroyRenderPassCache()
{
for (auto& it : m_render_pass_cache)
vkDestroyRenderPass(g_vulkan_context->GetDevice(), it.second, nullptr);
m_render_pass_cache.clear();
}
} }

View File

@ -9,6 +9,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <tuple>
#include <unordered_map> #include <unordered_map>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
@ -66,6 +67,10 @@ public:
// Dummy image for samplers that are unbound // Dummy image for samplers that are unbound
Texture2D* GetDummyImage() const { return m_dummy_texture.get(); } Texture2D* GetDummyImage() const { return m_dummy_texture.get(); }
VkImageView GetDummyImageView() const { return m_dummy_texture->GetView(); } VkImageView GetDummyImageView() const { return m_dummy_texture->GetView(); }
// Render pass cache.
VkRenderPass GetRenderPass(VkFormat color_format, VkFormat depth_format, u32 multisamples,
VkAttachmentLoadOp load_op);
// Perform at startup, create descriptor layouts, compiles all static shaders. // Perform at startup, create descriptor layouts, compiles all static shaders.
bool Initialize(); bool Initialize();
@ -81,6 +86,7 @@ private:
bool CreateUtilityShaderVertexFormat(); bool CreateUtilityShaderVertexFormat();
bool CreateStaticSamplers(); bool CreateStaticSamplers();
void DestroySamplers(); void DestroySamplers();
void DestroyRenderPassCache();
std::array<VkDescriptorSetLayout, NUM_DESCRIPTOR_SET_LAYOUTS> m_descriptor_set_layouts = {}; std::array<VkDescriptorSetLayout, NUM_DESCRIPTOR_SET_LAYOUTS> m_descriptor_set_layouts = {};
std::array<VkPipelineLayout, NUM_PIPELINE_LAYOUTS> m_pipeline_layouts = {}; std::array<VkPipelineLayout, NUM_PIPELINE_LAYOUTS> m_pipeline_layouts = {};
@ -96,6 +102,10 @@ private:
// Dummy image for samplers that are unbound // Dummy image for samplers that are unbound
std::unique_ptr<Texture2D> m_dummy_texture; std::unique_ptr<Texture2D> m_dummy_texture;
// Render pass cache
using RenderPassCacheKey = std::tuple<VkFormat, VkFormat, u32, VkAttachmentLoadOp>;
std::map<RenderPassCacheKey, VkRenderPass> m_render_pass_cache;
}; };
extern std::unique_ptr<ObjectCache> g_object_cache; extern std::unique_ptr<ObjectCache> g_object_cache;

View File

@ -33,7 +33,6 @@ SwapChain::~SwapChain()
{ {
DestroySwapChainImages(); DestroySwapChainImages();
DestroySwapChain(); DestroySwapChain();
DestroyRenderPass();
DestroySurface(); DestroySurface();
} }
@ -229,48 +228,9 @@ bool SwapChain::SelectPresentMode()
bool SwapChain::CreateRenderPass() bool SwapChain::CreateRenderPass()
{ {
// render pass for rendering to the swap chain // render pass for rendering to the swap chain
VkAttachmentDescription present_render_pass_attachments[] = { m_render_pass = g_object_cache->GetRenderPass(m_surface_format.format, VK_FORMAT_UNDEFINED, 1,
{0, m_surface_format.format, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_LOAD_OP_CLEAR);
VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, return m_render_pass != VK_NULL_HANDLE;
VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}};
VkAttachmentReference present_render_pass_color_attachment_references[] = {
{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}};
VkSubpassDescription present_render_pass_subpass_descriptions[] = {
{0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1,
present_render_pass_color_attachment_references, nullptr, nullptr, 0, nullptr}};
VkRenderPassCreateInfo present_render_pass_info = {
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
nullptr,
0,
static_cast<u32>(ArraySize(present_render_pass_attachments)),
present_render_pass_attachments,
static_cast<u32>(ArraySize(present_render_pass_subpass_descriptions)),
present_render_pass_subpass_descriptions,
0,
nullptr};
VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &present_render_pass_info,
nullptr, &m_render_pass);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateRenderPass (present) failed: ");
return false;
}
return true;
}
void SwapChain::DestroyRenderPass()
{
if (!m_render_pass)
return;
vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_render_pass, nullptr);
m_render_pass = VK_NULL_HANDLE;
} }
bool SwapChain::CreateSwapChain() bool SwapChain::CreateSwapChain()
@ -498,7 +458,6 @@ bool SwapChain::SetVSync(bool enabled)
bool SwapChain::RecreateSurface(void* native_handle) bool SwapChain::RecreateSurface(void* native_handle)
{ {
// Destroy the old swap chain, images, and surface. // Destroy the old swap chain, images, and surface.
DestroyRenderPass();
DestroySwapChainImages(); DestroySwapChainImages();
DestroySwapChain(); DestroySwapChain();
DestroySurface(); DestroySurface();

View File

@ -68,7 +68,6 @@ private:
void DestroySwapChain(); void DestroySwapChain();
bool CreateRenderPass(); bool CreateRenderPass();
void DestroyRenderPass();
bool SetupSwapChainImages(); bool SetupSwapChainImages();
void DestroySwapChainImages(); void DestroySwapChainImages();

View File

@ -37,8 +37,6 @@ TextureCache::TextureCache()
TextureCache::~TextureCache() TextureCache::~TextureCache()
{ {
if (m_render_pass != VK_NULL_HANDLE)
vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_render_pass, nullptr);
TextureCache::DeleteShaders(); TextureCache::DeleteShaders();
} }
@ -47,11 +45,6 @@ VkShaderModule TextureCache::GetCopyShader() const
return m_copy_shader; return m_copy_shader;
} }
VkRenderPass TextureCache::GetTextureCopyRenderPass() const
{
return m_render_pass;
}
StreamBuffer* TextureCache::GetTextureUploadBuffer() const StreamBuffer* TextureCache::GetTextureUploadBuffer() const
{ {
return m_texture_upload_buffer.get(); return m_texture_upload_buffer.get();
@ -73,12 +66,6 @@ bool TextureCache::Initialize()
return false; return false;
} }
if (!CreateRenderPasses())
{
PanicAlert("Failed to create copy render pass");
return false;
}
m_texture_converter = std::make_unique<TextureConverter>(); m_texture_converter = std::make_unique<TextureConverter>();
if (!m_texture_converter->Initialize()) if (!m_texture_converter->Initialize())
{ {
@ -98,7 +85,7 @@ bool TextureCache::Initialize()
void TextureCache::ConvertTexture(TCacheEntry* destination, TCacheEntry* source, void TextureCache::ConvertTexture(TCacheEntry* destination, TCacheEntry* source,
const void* palette, TLUTFormat format) const void* palette, TLUTFormat format)
{ {
m_texture_converter->ConvertTexture(destination, source, m_render_pass, palette, format); m_texture_converter->ConvertTexture(destination, source, palette, format);
// Ensure both textures remain in the SHADER_READ_ONLY layout so they can be bound. // Ensure both textures remain in the SHADER_READ_ONLY layout so they can be bound.
static_cast<VKTexture*>(source->texture.get()) static_cast<VKTexture*>(source->texture.get())
@ -178,50 +165,6 @@ void TextureCache::DecodeTextureOnGPU(TCacheEntry* entry, u32 dst_level, const u
} }
} }
bool TextureCache::CreateRenderPasses()
{
static constexpr VkAttachmentDescription update_attachment = {
0,
TEXTURECACHE_TEXTURE_FORMAT,
VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
static constexpr VkAttachmentReference color_attachment_reference = {
0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
static constexpr VkSubpassDescription subpass_description = {
0, VK_PIPELINE_BIND_POINT_GRAPHICS,
0, nullptr,
1, &color_attachment_reference,
nullptr, nullptr,
0, nullptr};
VkRenderPassCreateInfo update_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
nullptr,
0,
1,
&update_attachment,
1,
&subpass_description,
0,
nullptr};
VkResult res =
vkCreateRenderPass(g_vulkan_context->GetDevice(), &update_info, nullptr, &m_render_pass);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateRenderPass failed: ");
return false;
}
return true;
}
bool TextureCache::CompileShaders() bool TextureCache::CompileShaders()
{ {
static const char COPY_SHADER_SOURCE[] = R"( static const char COPY_SHADER_SOURCE[] = R"(
@ -322,8 +265,12 @@ void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy,
shader = Util::CompileAndCreateFragmentShader(source); shader = Util::CompileAndCreateFragmentShader(source);
} }
VkRenderPass render_pass = g_object_cache->GetRenderPass(
texture->GetRawTexIdentifier()->GetFormat(), VK_FORMAT_UNDEFINED,
texture->GetRawTexIdentifier()->GetSamples(), VK_ATTACHMENT_LOAD_OP_DONT_CARE);
UtilityShaderDraw draw(command_buffer, UtilityShaderDraw draw(command_buffer,
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), m_render_pass, g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), render_pass,
g_shader_cache->GetPassthroughVertexShader(), g_shader_cache->GetPassthroughVertexShader(),
g_shader_cache->GetPassthroughGeometryShader(), shader); g_shader_cache->GetPassthroughGeometryShader(), shader);

View File

@ -48,18 +48,13 @@ public:
TLUTFormat palette_format) override; TLUTFormat palette_format) override;
VkShaderModule GetCopyShader() const; VkShaderModule GetCopyShader() const;
VkRenderPass GetTextureCopyRenderPass() const;
StreamBuffer* GetTextureUploadBuffer() const; StreamBuffer* GetTextureUploadBuffer() const;
private: private:
bool CreateRenderPasses();
void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect, void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect,
bool scale_by_half, EFBCopyFormat dst_format, bool scale_by_half, EFBCopyFormat dst_format,
bool is_intensity) override; bool is_intensity) override;
VkRenderPass m_render_pass = VK_NULL_HANDLE;
std::unique_ptr<StreamBuffer> m_texture_upload_buffer; std::unique_ptr<StreamBuffer> m_texture_upload_buffer;
std::unique_ptr<TextureConverter> m_texture_converter; std::unique_ptr<TextureConverter> m_texture_converter;

View File

@ -63,9 +63,6 @@ TextureConverter::~TextureConverter()
if (m_texel_buffer_view_rgba8_uint != VK_NULL_HANDLE) if (m_texel_buffer_view_rgba8_uint != VK_NULL_HANDLE)
vkDestroyBufferView(g_vulkan_context->GetDevice(), m_texel_buffer_view_rgba8_uint, nullptr); vkDestroyBufferView(g_vulkan_context->GetDevice(), m_texel_buffer_view_rgba8_uint, nullptr);
if (m_encoding_render_pass != VK_NULL_HANDLE)
vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_encoding_render_pass, nullptr);
for (auto& it : m_encoding_shaders) for (auto& it : m_encoding_shaders)
vkDestroyShaderModule(g_vulkan_context->GetDevice(), it.second, nullptr); vkDestroyShaderModule(g_vulkan_context->GetDevice(), it.second, nullptr);
@ -95,12 +92,6 @@ bool TextureConverter::Initialize()
return false; return false;
} }
if (!CreateEncodingRenderPass())
{
PanicAlert("Failed to create encode render pass");
return false;
}
if (!CreateEncodingTexture()) if (!CreateEncodingTexture())
{ {
PanicAlert("Failed to create encoding texture"); PanicAlert("Failed to create encoding texture");
@ -165,8 +156,7 @@ TextureConverter::GetCommandBufferForTextureConversion(const TextureCache::TCach
} }
void TextureConverter::ConvertTexture(TextureCacheBase::TCacheEntry* dst_entry, void TextureConverter::ConvertTexture(TextureCacheBase::TCacheEntry* dst_entry,
TextureCacheBase::TCacheEntry* src_entry, TextureCacheBase::TCacheEntry* src_entry, const void* palette,
VkRenderPass render_pass, const void* palette,
TLUTFormat palette_format) TLUTFormat palette_format)
{ {
struct PSUniformBlock struct PSUniformBlock
@ -199,6 +189,9 @@ void TextureConverter::ConvertTexture(TextureCacheBase::TCacheEntry* dst_entry,
command_buffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); command_buffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Bind and draw to the destination. // Bind and draw to the destination.
VkRenderPass render_pass = g_object_cache->GetRenderPass(
destination_texture->GetRawTexIdentifier()->GetFormat(), VK_FORMAT_UNDEFINED,
destination_texture->GetRawTexIdentifier()->GetSamples(), VK_ATTACHMENT_LOAD_OP_DONT_CARE);
UtilityShaderDraw draw(command_buffer, UtilityShaderDraw draw(command_buffer,
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_TEXTURE_CONVERSION), g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_TEXTURE_CONVERSION),
render_pass, g_shader_cache->GetScreenQuadVertexShader(), VK_NULL_HANDLE, render_pass, g_shader_cache->GetScreenQuadVertexShader(), VK_NULL_HANDLE,
@ -240,10 +233,13 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p
->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), ->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
VkRenderPass render_pass = g_object_cache->GetRenderPass(
Util::GetVkFormatForHostTextureFormat(m_encoding_render_texture->GetConfig().format),
VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT), g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT),
m_encoding_render_pass, g_shader_cache->GetScreenQuadVertexShader(), render_pass, g_shader_cache->GetScreenQuadVertexShader(), VK_NULL_HANDLE,
VK_NULL_HANDLE, shader); shader);
// Uniform - int4 of left,top,native_width,scale // Uniform - int4 of left,top,native_width,scale
EFBEncodeParams encoder_params; EFBEncodeParams encoder_params;
@ -297,10 +293,12 @@ void TextureConverter::EncodeTextureToMemoryYUYV(void* dst_ptr, u32 dst_width, u
// the order the guest is expecting and we don't have to swap it at readback time. The width // the order the guest is expecting and we don't have to swap it at readback time. The width
// is halved because we're using an RGBA8 texture, but the YUYV data is two bytes per pixel. // is halved because we're using an RGBA8 texture, but the YUYV data is two bytes per pixel.
u32 output_width = dst_width / 2; u32 output_width = dst_width / 2;
UtilityShaderDraw draw(command_buffer, VkRenderPass render_pass = g_object_cache->GetRenderPass(
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), Util::GetVkFormatForHostTextureFormat(m_encoding_render_texture->GetConfig().format),
m_encoding_render_pass, g_shader_cache->GetPassthroughVertexShader(), VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
VK_NULL_HANDLE, m_rgb_to_yuyv_shader); UtilityShaderDraw draw(
command_buffer, g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), render_pass,
g_shader_cache->GetPassthroughVertexShader(), VK_NULL_HANDLE, m_rgb_to_yuyv_shader);
VkRect2D region = {{0, 0}, {output_width, dst_height}}; VkRect2D region = {{0, 0}, {output_width, dst_height}};
draw.BeginRenderPass(static_cast<VKTexture*>(m_encoding_render_texture.get())->GetFramebuffer(), draw.BeginRenderPass(static_cast<VKTexture*>(m_encoding_render_texture.get())->GetFramebuffer(),
region); region);
@ -368,10 +366,13 @@ void TextureConverter::DecodeYUYVTextureFromMemory(VKTexture* dst_texture, const
static_cast<int>(src_width / 2)}; static_cast<int>(src_width / 2)};
// Convert from the YUYV data now in the intermediate texture to RGBA in the destination. // Convert from the YUYV data now in the intermediate texture to RGBA in the destination.
VkRenderPass render_pass = g_object_cache->GetRenderPass(
dst_texture->GetRawTexIdentifier()->GetFormat(), VK_FORMAT_UNDEFINED,
dst_texture->GetRawTexIdentifier()->GetSamples(), VK_ATTACHMENT_LOAD_OP_DONT_CARE);
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_TEXTURE_CONVERSION), g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_TEXTURE_CONVERSION),
m_encoding_render_pass, g_shader_cache->GetScreenQuadVertexShader(), render_pass, g_shader_cache->GetScreenQuadVertexShader(), VK_NULL_HANDLE,
VK_NULL_HANDLE, m_yuyv_to_rgb_shader); m_yuyv_to_rgb_shader);
VkRect2D region = {{0, 0}, {src_width, src_height}}; VkRect2D region = {{0, 0}, {src_width, src_height}};
draw.BeginRenderPass(dst_texture->GetFramebuffer(), region); draw.BeginRenderPass(dst_texture->GetFramebuffer(), region);
draw.SetViewportAndScissor(0, 0, static_cast<int>(src_width), static_cast<int>(src_height)); draw.SetViewportAndScissor(0, 0, static_cast<int>(src_width), static_cast<int>(src_height));
@ -711,42 +712,6 @@ VkShaderModule TextureConverter::GetEncodingShader(const EFBCopyParams& params)
return shader; return shader;
} }
bool TextureConverter::CreateEncodingRenderPass()
{
VkAttachmentDescription attachments[] = {
{0, Util::GetVkFormatForHostTextureFormat(ENCODING_TEXTURE_FORMAT), VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}};
VkAttachmentReference color_attachment_references[] = {
{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}};
VkSubpassDescription subpass_descriptions[] = {{0, VK_PIPELINE_BIND_POINT_GRAPHICS, 0, nullptr, 1,
color_attachment_references, nullptr, nullptr, 0,
nullptr}};
VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
nullptr,
0,
static_cast<u32>(ArraySize(attachments)),
attachments,
static_cast<u32>(ArraySize(subpass_descriptions)),
subpass_descriptions,
0,
nullptr};
VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr,
&m_encoding_render_pass);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateRenderPass (Encode) failed: ");
return false;
}
return true;
}
bool TextureConverter::CreateEncodingTexture() bool TextureConverter::CreateEncodingTexture()
{ {
TextureConfig config(ENCODING_TEXTURE_WIDTH, ENCODING_TEXTURE_HEIGHT, 1, 1, TextureConfig config(ENCODING_TEXTURE_WIDTH, ENCODING_TEXTURE_HEIGHT, 1, 1,

View File

@ -35,8 +35,8 @@ public:
// Applies palette to dst_entry, using indices from src_entry. // Applies palette to dst_entry, using indices from src_entry.
void ConvertTexture(TextureCacheBase::TCacheEntry* dst_entry, void ConvertTexture(TextureCacheBase::TCacheEntry* dst_entry,
TextureCache::TCacheEntry* src_entry, VkRenderPass render_pass, TextureCache::TCacheEntry* src_entry, const void* palette,
const void* palette, TLUTFormat palette_format); TLUTFormat palette_format);
// Uses an encoding shader to copy src_texture to dest_ptr. // Uses an encoding shader to copy src_texture to dest_ptr.
// NOTE: Executes the current command buffer. // NOTE: Executes the current command buffer.
@ -76,7 +76,6 @@ private:
VkShaderModule CompileEncodingShader(const EFBCopyParams& params); VkShaderModule CompileEncodingShader(const EFBCopyParams& params);
VkShaderModule GetEncodingShader(const EFBCopyParams& params); VkShaderModule GetEncodingShader(const EFBCopyParams& params);
bool CreateEncodingRenderPass();
bool CreateEncodingTexture(); bool CreateEncodingTexture();
bool CreateDecodingTexture(); bool CreateDecodingTexture();
@ -109,7 +108,6 @@ private:
std::map<EFBCopyParams, VkShaderModule> m_encoding_shaders; std::map<EFBCopyParams, VkShaderModule> m_encoding_shaders;
std::unique_ptr<AbstractTexture> m_encoding_render_texture; std::unique_ptr<AbstractTexture> m_encoding_render_texture;
std::unique_ptr<AbstractStagingTexture> m_encoding_readback_texture; std::unique_ptr<AbstractStagingTexture> m_encoding_readback_texture;
VkRenderPass m_encoding_render_pass = VK_NULL_HANDLE;
// Texture decoding - GX format in memory->RGBA8 // Texture decoding - GX format in memory->RGBA8
struct TextureDecodingPipeline struct TextureDecodingPipeline

View File

@ -56,11 +56,13 @@ std::unique_ptr<VKTexture> VKTexture::Create(const TextureConfig& tex_config)
if (tex_config.rendertarget) if (tex_config.rendertarget)
{ {
VkImageView framebuffer_attachments[] = {texture->GetView()}; VkImageView framebuffer_attachments[] = {texture->GetView()};
VkRenderPass render_pass = g_object_cache->GetRenderPass(
texture->GetFormat(), VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
VkFramebufferCreateInfo framebuffer_info = { VkFramebufferCreateInfo framebuffer_info = {
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
nullptr, nullptr,
0, 0,
TextureCache::GetInstance()->GetTextureCopyRenderPass(), render_pass,
static_cast<u32>(ArraySize(framebuffer_attachments)), static_cast<u32>(ArraySize(framebuffer_attachments)),
framebuffer_attachments, framebuffer_attachments,
texture->GetWidth(), texture->GetWidth(),
@ -175,9 +177,10 @@ void VKTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
VkRenderPass render_pass = g_object_cache->GetRenderPass(
m_texture->GetFormat(), VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), render_pass,
TextureCache::GetInstance()->GetTextureCopyRenderPass(),
g_shader_cache->GetPassthroughVertexShader(), g_shader_cache->GetPassthroughVertexShader(),
g_shader_cache->GetPassthroughGeometryShader(), g_shader_cache->GetPassthroughGeometryShader(),
TextureCache::GetInstance()->GetCopyShader()); TextureCache::GetInstance()->GetCopyShader());

View File

@ -186,6 +186,25 @@ bool VideoBackend::Initialize(void* window_handle)
// With the backend information populated, we can now initialize videocommon. // With the backend information populated, we can now initialize videocommon.
InitializeShared(); InitializeShared();
// Create command buffers. We do this separately because the other classes depend on it.
g_command_buffer_mgr = std::make_unique<CommandBufferManager>(g_Config.bBackendMultithreading);
if (!g_command_buffer_mgr->Initialize())
{
PanicAlert("Failed to create Vulkan command buffers");
Shutdown();
return false;
}
// Remaining classes are also dependent on object/shader cache.
g_object_cache = std::make_unique<ObjectCache>();
g_shader_cache = std::make_unique<ShaderCache>();
if (!g_object_cache->Initialize() || !g_shader_cache->Initialize())
{
PanicAlert("Failed to initialize Vulkan object cache.");
Shutdown();
return false;
}
// Create swap chain. This has to be done early so that the target size is correct for auto-scale. // Create swap chain. This has to be done early so that the target size is correct for auto-scale.
std::unique_ptr<SwapChain> swap_chain; std::unique_ptr<SwapChain> swap_chain;
if (surface != VK_NULL_HANDLE) if (surface != VK_NULL_HANDLE)
@ -199,39 +218,19 @@ bool VideoBackend::Initialize(void* window_handle)
} }
} }
// Create command buffers. We do this separately because the other classes depend on it.
g_command_buffer_mgr = std::make_unique<CommandBufferManager>(g_Config.bBackendMultithreading);
if (!g_command_buffer_mgr->Initialize())
{
PanicAlert("Failed to create Vulkan command buffers");
Shutdown();
return false;
}
// Create main wrapper instances. // Create main wrapper instances.
g_object_cache = std::make_unique<ObjectCache>();
g_shader_cache = std::make_unique<ShaderCache>();
g_framebuffer_manager = std::make_unique<FramebufferManager>(); g_framebuffer_manager = std::make_unique<FramebufferManager>();
g_renderer = std::make_unique<Renderer>(std::move(swap_chain)); g_renderer = std::make_unique<Renderer>(std::move(swap_chain));
g_vertex_manager = std::make_unique<VertexManager>();
g_texture_cache = std::make_unique<TextureCache>();
g_perf_query = std::make_unique<PerfQuery>();
// Invoke init methods on main wrapper classes. // Invoke init methods on main wrapper classes.
// These have to be done before the others because the destructors // These have to be done before the others because the destructors
// for the remaining classes may call methods on these. // for the remaining classes may call methods on these.
if (!g_object_cache->Initialize() || !g_shader_cache->Initialize() || if (!StateTracker::CreateInstance() || !FramebufferManager::GetInstance()->Initialize() ||
!StateTracker::CreateInstance() || !FramebufferManager::GetInstance()->Initialize() || !Renderer::GetInstance()->Initialize() || !VertexManager::GetInstance()->Initialize() ||
!Renderer::GetInstance()->Initialize()) !TextureCache::GetInstance()->Initialize() || !PerfQuery::GetInstance()->Initialize())
{
PanicAlert("Failed to initialize Vulkan classes.");
Shutdown();
return false;
}
// Create remaining wrapper instances.
g_vertex_manager = std::make_unique<VertexManager>();
g_texture_cache = std::make_unique<TextureCache>();
g_perf_query = std::make_unique<PerfQuery>();
if (!VertexManager::GetInstance()->Initialize() || !TextureCache::GetInstance()->Initialize() ||
!PerfQuery::GetInstance()->Initialize())
{ {
PanicAlert("Failed to initialize Vulkan classes."); PanicAlert("Failed to initialize Vulkan classes.");
Shutdown(); Shutdown();