Vulkan: Use explicit barriers instead of dependancies

At least on NV, some of these don't seem to have the intended effect. One
known instance of this is in texture conversion.
This commit is contained in:
Stenzek 2016-11-21 01:59:19 +10:00
parent a475792163
commit 9736198c3b
5 changed files with 77 additions and 178 deletions

View File

@ -183,24 +183,12 @@ bool FramebufferManager::CreateEFBRenderPass()
VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
// Ensure all reads have finished from the resolved texture before overwriting it.
VkSubpassDependency dependencies[] = {
{VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_SHADER_READ_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_DEPENDENCY_BY_REGION_BIT},
{0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT, VK_DEPENDENCY_BY_REGION_BIT}};
subpass_description.pDepthStencilAttachment = nullptr; subpass_description.pDepthStencilAttachment = nullptr;
pass_info.pAttachments = &resolve_attachment; pass_info.pAttachments = &resolve_attachment;
pass_info.attachmentCount = 1; pass_info.attachmentCount = 1;
pass_info.dependencyCount = static_cast<u32>(ArraySize(dependencies));
pass_info.pDependencies = dependencies;
res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr, res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr,
&m_depth_resolve_render_pass); &m_depth_resolve_render_pass);
@ -696,6 +684,9 @@ bool FramebufferManager::PopulateColorReadbackTexture()
if (m_efb_width != EFB_WIDTH || m_efb_height != EFB_HEIGHT) if (m_efb_width != EFB_WIDTH || m_efb_height != EFB_HEIGHT)
{ {
m_color_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
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),
m_copy_color_render_pass, g_object_cache->GetScreenQuadVertexShader(), m_copy_color_render_pass, g_object_cache->GetScreenQuadVertexShader(),
@ -720,7 +711,6 @@ bool FramebufferManager::PopulateColorReadbackTexture()
} }
// Use this as a source texture now. // Use this as a source texture now.
m_color_copy_texture->OverrideImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
src_texture = m_color_copy_texture.get(); src_texture = m_color_copy_texture.get();
} }
@ -777,6 +767,9 @@ bool FramebufferManager::PopulateDepthReadbackTexture()
} }
if (m_efb_width != EFB_WIDTH || m_efb_height != EFB_HEIGHT) if (m_efb_width != EFB_WIDTH || m_efb_height != EFB_HEIGHT)
{ {
m_depth_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
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),
m_copy_depth_render_pass, g_object_cache->GetScreenQuadVertexShader(), m_copy_depth_render_pass, g_object_cache->GetScreenQuadVertexShader(),
@ -801,7 +794,6 @@ bool FramebufferManager::PopulateDepthReadbackTexture()
} }
// Use this as a source texture now. // Use this as a source texture now.
m_depth_copy_texture->OverrideImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
src_texture = m_depth_copy_texture.get(); src_texture = m_depth_copy_texture.get();
src_aspect = VK_IMAGE_ASPECT_COLOR_BIT; src_aspect = VK_IMAGE_ASPECT_COLOR_BIT;
} }
@ -847,8 +839,8 @@ bool FramebufferManager::CreateReadbackRenderPasses()
VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp VK_ATTACHMENT_STORE_OP_STORE, // VkAttachmentStoreOp storeOp
VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp VK_ATTACHMENT_LOAD_OP_DONT_CARE, // VkAttachmentLoadOp stencilLoadOp
VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp VK_ATTACHMENT_STORE_OP_DONT_CARE, // VkAttachmentStoreOp stencilStoreOp
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, // VkImageLayout initialLayout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // VkImageLayout initialLayout
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL // VkImageLayout finalLayout VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL // VkImageLayout finalLayout
}; };
VkAttachmentReference copy_attachment_ref = { VkAttachmentReference copy_attachment_ref = {
0, // uint32_t attachment 0, // uint32_t attachment
@ -866,14 +858,6 @@ bool FramebufferManager::CreateReadbackRenderPasses()
0, // uint32_t preserveAttachmentCount 0, // uint32_t preserveAttachmentCount
nullptr // const uint32_t* pPreserveAttachments nullptr // const uint32_t* pPreserveAttachments
}; };
VkSubpassDependency copy_dependency = {
0,
VK_SUBPASS_EXTERNAL,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_TRANSFER_READ_BIT,
VK_DEPENDENCY_BY_REGION_BIT};
VkRenderPassCreateInfo copy_pass = { VkRenderPassCreateInfo copy_pass = {
VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, // VkStructureType sType
nullptr, // const void* pNext nullptr, // const void* pNext
@ -882,8 +866,8 @@ bool FramebufferManager::CreateReadbackRenderPasses()
&copy_attachment, // const VkAttachmentDescription* pAttachments &copy_attachment, // const VkAttachmentDescription* pAttachments
1, // uint32_t subpassCount 1, // uint32_t subpassCount
&copy_subpass, // const VkSubpassDescription* pSubpasses &copy_subpass, // const VkSubpassDescription* pSubpasses
1, // uint32_t dependencyCount 0, // uint32_t dependencyCount
&copy_dependency // const VkSubpassDependency* pDependencies nullptr // const VkSubpassDependency* pDependencies
}; };
VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &copy_pass, nullptr, VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &copy_pass, nullptr,
@ -1023,12 +1007,6 @@ bool FramebufferManager::CreateReadbackTextures()
return false; return false;
} }
// Transition to TRANSFER_SRC, as this is expected by the render pass.
m_color_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
m_depth_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
return true; return true;
} }

View File

@ -613,6 +613,9 @@ void Renderer::DrawVirtualXFB(VkRenderPass render_pass, const TargetRectangle& t
for (u32 i = 0; i < xfb_count; ++i) for (u32 i = 0; i < xfb_count; ++i)
{ {
const XFBSource* xfb_source = static_cast<const XFBSource*>(xfb_sources[i]); const XFBSource* xfb_source = static_cast<const XFBSource*>(xfb_sources[i]);
xfb_source->GetTexture()->GetTexture()->TransitionToLayout(
g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
TargetRectangle source_rect = xfb_source->sourceRc; TargetRectangle source_rect = xfb_source->sourceRc;
TargetRectangle draw_rect; TargetRectangle draw_rect;
@ -646,6 +649,9 @@ void Renderer::DrawRealXFB(VkRenderPass render_pass, const TargetRectangle& targ
for (u32 i = 0; i < xfb_count; ++i) for (u32 i = 0; i < xfb_count; ++i)
{ {
const XFBSource* xfb_source = static_cast<const XFBSource*>(xfb_sources[i]); const XFBSource* xfb_source = static_cast<const XFBSource*>(xfb_sources[i]);
xfb_source->GetTexture()->GetTexture()->TransitionToLayout(
g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
TargetRectangle source_rect = xfb_source->sourceRc; TargetRectangle source_rect = xfb_source->sourceRc;
TargetRectangle draw_rect = target_rect; TargetRectangle draw_rect = target_rect;
source_rect.right -= fb_stride - fb_width; source_rect.right -= fb_stride - fb_width;

View File

@ -36,10 +36,8 @@ TextureCache::TextureCache()
TextureCache::~TextureCache() TextureCache::~TextureCache()
{ {
if (m_initialize_render_pass != VK_NULL_HANDLE) if (m_render_pass != VK_NULL_HANDLE)
vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_initialize_render_pass, nullptr); vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_render_pass, nullptr);
if (m_update_render_pass != VK_NULL_HANDLE)
vkDestroyRenderPass(g_vulkan_context->GetDevice(), m_update_render_pass, nullptr);
TextureCache::DeleteShaders(); TextureCache::DeleteShaders();
} }
@ -87,11 +85,7 @@ void TextureCache::ConvertTexture(TCacheEntryBase* base_entry, TCacheEntryBase*
TCacheEntry* entry = static_cast<TCacheEntry*>(base_entry); TCacheEntry* entry = static_cast<TCacheEntry*>(base_entry);
TCacheEntry* unconverted = static_cast<TCacheEntry*>(base_unconverted); TCacheEntry* unconverted = static_cast<TCacheEntry*>(base_unconverted);
m_texture_converter->ConvertTexture( m_texture_converter->ConvertTexture(entry, unconverted, m_render_pass, palette, format);
entry, unconverted, GetRenderPassForTextureUpdate(entry->GetTexture()), palette, format);
// Render pass transitions to SHADER_READ_ONLY.
entry->GetTexture()->OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
} }
static bool IsDepthCopyFormat(PEControl::PixelFormat format) static bool IsDepthCopyFormat(PEControl::PixelFormat format)
@ -203,11 +197,10 @@ void TextureCache::ScaleTextureRectangle(TCacheEntry* dst_texture,
src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
dst_texture->GetTexture()->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), dst_texture->GetTexture()->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
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), m_render_pass,
GetRenderPassForTextureUpdate(dst_texture->GetTexture()),
g_object_cache->GetPassthroughVertexShader(), g_object_cache->GetPassthroughVertexShader(),
g_object_cache->GetPassthroughGeometryShader(), m_copy_shader); g_object_cache->GetPassthroughGeometryShader(), m_copy_shader);
@ -221,9 +214,6 @@ void TextureCache::ScaleTextureRectangle(TCacheEntry* dst_texture,
static_cast<int>(src_texture->GetWidth()), static_cast<int>(src_texture->GetWidth()),
static_cast<int>(src_texture->GetHeight())); static_cast<int>(src_texture->GetHeight()));
draw.EndRenderPass(); draw.EndRenderPass();
// Render pass transitions destination texture to SHADER_READ_ONLY.
dst_texture->GetTexture()->OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
} }
TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntryConfig& config) TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntryConfig& config)
@ -251,7 +241,7 @@ TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntry
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
nullptr, nullptr,
0, 0,
m_initialize_render_pass, m_render_pass,
static_cast<u32>(ArraySize(framebuffer_attachments)), static_cast<u32>(ArraySize(framebuffer_attachments)),
framebuffer_attachments, framebuffer_attachments,
texture->GetWidth(), texture->GetWidth(),
@ -281,17 +271,6 @@ TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntry
bool TextureCache::CreateRenderPasses() bool TextureCache::CreateRenderPasses()
{ {
static constexpr VkAttachmentDescription initialize_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_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
static constexpr VkAttachmentDescription update_attachment = { static constexpr VkAttachmentDescription update_attachment = {
0, 0,
TEXTURECACHE_TEXTURE_FORMAT, TEXTURECACHE_TEXTURE_FORMAT,
@ -300,8 +279,8 @@ bool TextureCache::CreateRenderPasses()
VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_STORE_OP_STORE,
VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL}; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
static constexpr VkAttachmentReference color_attachment_reference = { static constexpr VkAttachmentReference color_attachment_reference = {
0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}; 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
@ -313,36 +292,6 @@ bool TextureCache::CreateRenderPasses()
nullptr, nullptr, nullptr, nullptr,
0, nullptr}; 0, nullptr};
static constexpr VkSubpassDependency initialize_dependancies[] = {
{VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_DEPENDENCY_BY_REGION_BIT},
{0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT, VK_DEPENDENCY_BY_REGION_BIT}};
static constexpr VkSubpassDependency update_dependancies[] = {
{VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_ACCESS_SHADER_READ_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_DEPENDENCY_BY_REGION_BIT},
{0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_SHADER_READ_BIT, VK_DEPENDENCY_BY_REGION_BIT}};
VkRenderPassCreateInfo initialize_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
nullptr,
0,
1,
&initialize_attachment,
1,
&subpass_description,
static_cast<u32>(ArraySize(initialize_dependancies)),
initialize_dependancies};
VkRenderPassCreateInfo update_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, VkRenderPassCreateInfo update_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
nullptr, nullptr,
0, 0,
@ -350,44 +299,20 @@ bool TextureCache::CreateRenderPasses()
&update_attachment, &update_attachment,
1, 1,
&subpass_description, &subpass_description,
static_cast<u32>(ArraySize(update_dependancies)), 0,
update_dependancies}; nullptr};
VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &initialize_info, nullptr, VkResult res =
&m_initialize_render_pass); vkCreateRenderPass(g_vulkan_context->GetDevice(), &update_info, nullptr, &m_render_pass);
if (res != VK_SUCCESS) if (res != VK_SUCCESS)
{ {
LOG_VULKAN_ERROR(res, "vkCreateRenderPass (initialize) failed: "); LOG_VULKAN_ERROR(res, "vkCreateRenderPass failed: ");
return false;
}
res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &update_info, nullptr,
&m_update_render_pass);
if (res != VK_SUCCESS)
{
LOG_VULKAN_ERROR(res, "vkCreateRenderPass (update) failed: ");
return false; return false;
} }
return true; return true;
} }
VkRenderPass TextureCache::GetRenderPassForTextureUpdate(const Texture2D* texture) const
{
// EFB copies can be re-used as part of the texture pool. If this is the case, we need to insert
// a pipeline barrier to ensure that all reads from the texture expecting the old data have
// completed before overwriting the texture's contents. New textures will be in TRANSFER_DST
// due to the clear after creation.
// These two render passes are compatible, so even though the framebuffer was created with
// the initialize render pass it's still allowed.
if (texture->GetLayout() == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
return m_initialize_render_pass;
else
return m_update_render_pass;
}
TextureCache::TCacheEntry::TCacheEntry(const TCacheEntryConfig& config_, TextureCache::TCacheEntry::TCacheEntry(const TCacheEntryConfig& config_,
std::unique_ptr<Texture2D> texture, std::unique_ptr<Texture2D> texture,
VkFramebuffer framebuffer) VkFramebuffer framebuffer)
@ -410,27 +335,23 @@ void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
width = std::max(1u, std::min(width, m_texture->GetWidth() >> level)); width = std::max(1u, std::min(width, m_texture->GetWidth() >> level));
height = std::max(1u, std::min(height, m_texture->GetHeight() >> level)); height = std::max(1u, std::min(height, m_texture->GetHeight() >> level));
// We don't care about the existing contents of the texture, so we set the image layout to // We don't care about the existing contents of the texture, so we could the image layout to
// VK_IMAGE_LAYOUT_UNDEFINED here. However, if this texture is being re-used from the texture // VK_IMAGE_LAYOUT_UNDEFINED here. However, under section 2.2.1, Queue Operation of the Vulkan
// pool, it may still be in use. We assume that it's not, as non-efb-copy textures are only // specification, it states:
// returned to the pool when the frame number is different, furthermore, we're doing this //
// on the initialize command buffer, so a texture being re-used mid-frame would have undesirable // Command buffer submissions to a single queue must always adhere to command order and
// effects regardless. // API order, but otherwise may overlap or execute out of order.
VkImageMemoryBarrier barrier = { //
VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // VkStructureType sType // Therefore, if a previous frame's command buffer is still sampling from this texture, and we
nullptr, // const void* pNext // overwrite it without a pipeline barrier, a texture sample could occur in parallel with the
0, // VkAccessFlags srcAccessMask // texture upload/copy. I'm not sure if any drivers currently take advantage of this, but we
VK_ACCESS_TRANSFER_WRITE_BIT, // VkAccessFlags dstAccessMask // should insert an explicit pipeline barrier just in case (done by TransitionToLayout).
VK_IMAGE_LAYOUT_UNDEFINED, // VkImageLayout oldLayout //
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, // VkImageLayout newLayout // We transition to TRANSFER_DST, ready for the image copy, and leave the texture in this state.
VK_QUEUE_FAMILY_IGNORED, // uint32_t srcQueueFamilyIndex // This is so that the remaining mip levels can be uploaded without barriers, and then when the
VK_QUEUE_FAMILY_IGNORED, // uint32_t dstQueueFamilyIndex // texture is used, it can be transitioned to SHADER_READ_ONLY (see TCacheEntry::Bind).
m_texture->GetImage(), // VkImage image m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
{VK_IMAGE_ASPECT_COLOR_BIT, level, 1, 0, 1}, // VkImageSubresourceRange subresourceRange VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
};
vkCmdPipelineBarrier(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0,
nullptr, 0, nullptr, 1, &barrier);
// Does this texture data fit within the streaming buffer? // Does this texture data fit within the streaming buffer?
u32 upload_width = width; u32 upload_width = width;
@ -513,16 +434,6 @@ void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
m_texture->GetImage(), VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, width, m_texture->GetImage(), VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, width,
height, level, 0); height, level, 0);
} }
// Transition to shader read only.
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
vkCmdPipelineBarrier(g_command_buffer_mgr->GetCurrentInitCommandBuffer(),
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0,
nullptr, 0, nullptr, 1, &barrier);
m_texture->OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
} }
void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat src_format, void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat src_format,
@ -559,11 +470,12 @@ void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat
scale_by_half ? g_object_cache->GetLinearSampler() : g_object_cache->GetPointSampler(); scale_by_half ? g_object_cache->GetLinearSampler() : g_object_cache->GetPointSampler();
VkImageLayout original_layout = src_texture->GetLayout(); VkImageLayout original_layout = src_texture->GetLayout();
src_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); src_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
m_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
UtilityShaderDraw draw( UtilityShaderDraw draw(
command_buffer, g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT), command_buffer, g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT),
TextureCache::GetInstance()->GetRenderPassForTextureUpdate(m_texture.get()), TextureCache::GetInstance()->m_render_pass, g_object_cache->GetPassthroughVertexShader(),
g_object_cache->GetPassthroughVertexShader(), g_object_cache->GetPassthroughGeometryShader(), g_object_cache->GetPassthroughGeometryShader(),
is_depth_copy ? TextureCache::GetInstance()->m_efb_depth_to_tex_shader : is_depth_copy ? TextureCache::GetInstance()->m_efb_depth_to_tex_shader :
TextureCache::GetInstance()->m_efb_color_to_tex_shader); TextureCache::GetInstance()->m_efb_color_to_tex_shader);
@ -587,7 +499,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat
src_texture->TransitionToLayout(command_buffer, original_layout); src_texture->TransitionToLayout(command_buffer, original_layout);
// Render pass transitions texture to SHADER_READ_ONLY. // Render pass transitions texture to SHADER_READ_ONLY.
m_texture->OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
} }
void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase* source, void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase* source,
@ -607,6 +519,8 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase*
void TextureCache::TCacheEntry::Bind(unsigned int stage) void TextureCache::TCacheEntry::Bind(unsigned int stage)
{ {
m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
StateTracker::GetInstance()->SetTexture(stage, m_texture->GetView()); StateTracker::GetInstance()->SetTexture(stage, m_texture->GetView());
} }

View File

@ -68,7 +68,6 @@ public:
private: private:
bool CreateRenderPasses(); bool CreateRenderPasses();
VkRenderPass GetRenderPassForTextureUpdate(const Texture2D* texture) const;
// Copies the contents of a texture using vkCmdCopyImage // Copies the contents of a texture using vkCmdCopyImage
void CopyTextureRectangle(TCacheEntry* dst_texture, const MathUtil::Rectangle<int>& dst_rect, void CopyTextureRectangle(TCacheEntry* dst_texture, const MathUtil::Rectangle<int>& dst_rect,
@ -78,8 +77,7 @@ private:
void ScaleTextureRectangle(TCacheEntry* dst_texture, const MathUtil::Rectangle<int>& dst_rect, void ScaleTextureRectangle(TCacheEntry* dst_texture, const MathUtil::Rectangle<int>& dst_rect,
Texture2D* src_texture, const MathUtil::Rectangle<int>& src_rect); Texture2D* src_texture, const MathUtil::Rectangle<int>& src_rect);
VkRenderPass m_initialize_render_pass = VK_NULL_HANDLE; VkRenderPass m_render_pass = VK_NULL_HANDLE;
VkRenderPass m_update_render_pass = VK_NULL_HANDLE;
std::unique_ptr<StreamBuffer> m_texture_upload_buffer; std::unique_ptr<StreamBuffer> m_texture_upload_buffer;

View File

@ -180,6 +180,10 @@ void TextureConverter::ConvertTexture(TextureCache::TCacheEntry* dst_entry,
m_texel_buffer->CommitMemory(palette_size); m_texel_buffer->CommitMemory(palette_size);
VkCommandBuffer command_buffer = GetCommandBufferForTextureConversion(src_entry); VkCommandBuffer command_buffer = GetCommandBufferForTextureConversion(src_entry);
src_entry->GetTexture()->TransitionToLayout(command_buffer,
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
dst_entry->GetTexture()->TransitionToLayout(command_buffer,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
// Bind and draw to the destination. // Bind and draw to the destination.
UtilityShaderDraw draw(command_buffer, UtilityShaderDraw draw(command_buffer,
@ -216,6 +220,9 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p
// Can't do our own draw within a render pass. // Can't do our own draw within a render pass.
StateTracker::GetInstance()->EndRenderPass(); StateTracker::GetInstance()->EndRenderPass();
m_encoding_render_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
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_object_cache->GetScreenQuadVertexShader(), m_encoding_render_pass, g_object_cache->GetScreenQuadVertexShader(),
@ -242,7 +249,8 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p
draw.EndRenderPass(); draw.EndRenderPass();
// Transition the image before copying // Transition the image before copying
m_encoding_render_texture->OverrideImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); m_encoding_render_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
m_encoding_download_texture->CopyFromImage( m_encoding_download_texture->CopyFromImage(
g_command_buffer_mgr->GetCurrentCommandBuffer(), m_encoding_render_texture->GetImage(), g_command_buffer_mgr->GetCurrentCommandBuffer(), m_encoding_render_texture->GetImage(),
VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, render_width, render_height, 0, 0); VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, render_width, render_height, 0, 0);
@ -286,7 +294,8 @@ void TextureConverter::EncodeTextureToMemoryYUYV(void* dst_ptr, u32 dst_width, u
draw.EndRenderPass(); draw.EndRenderPass();
// Render pass transitions to TRANSFER_SRC. // Render pass transitions to TRANSFER_SRC.
m_encoding_render_texture->OverrideImageLayout(VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); m_encoding_render_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
// Copy from encoding texture to download buffer. // Copy from encoding texture to download buffer.
m_encoding_download_texture->CopyFromImage(command_buffer, m_encoding_render_texture->GetImage(), m_encoding_download_texture->CopyFromImage(command_buffer, m_encoding_render_texture->GetImage(),
@ -530,8 +539,8 @@ bool TextureConverter::CreateEncodingRenderPass()
VkAttachmentDescription attachments[] = { VkAttachmentDescription attachments[] = {
{0, ENCODING_TEXTURE_FORMAT, VK_SAMPLE_COUNT_1_BIT, VK_ATTACHMENT_LOAD_OP_DONT_CARE, {0, 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_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE,
VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_UNDEFINED, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL}}; VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}};
VkAttachmentReference color_attachment_references[] = { VkAttachmentReference color_attachment_references[] = {
{0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}}; {0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}};
@ -540,12 +549,6 @@ bool TextureConverter::CreateEncodingRenderPass()
color_attachment_references, nullptr, nullptr, 0, color_attachment_references, nullptr, nullptr, 0,
nullptr}}; nullptr}};
VkSubpassDependency dependancies[] = {
{0, VK_SUBPASS_EXTERNAL, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_TRANSFER_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_TRANSFER_READ_BIT, VK_DEPENDENCY_BY_REGION_BIT}};
VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, VkRenderPassCreateInfo pass_info = {VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
nullptr, nullptr,
0, 0,
@ -553,8 +556,8 @@ bool TextureConverter::CreateEncodingRenderPass()
attachments, attachments,
static_cast<u32>(ArraySize(subpass_descriptions)), static_cast<u32>(ArraySize(subpass_descriptions)),
subpass_descriptions, subpass_descriptions,
static_cast<u32>(ArraySize(dependancies)), 0,
dependancies}; nullptr};
VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr, VkResult res = vkCreateRenderPass(g_vulkan_context->GetDevice(), &pass_info, nullptr,
&m_encoding_render_pass); &m_encoding_render_pass);