mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-11 00:29:11 +01:00
Vulkan: Move CopyRectangleFromTexture to TextureCache
This commit is contained in:
parent
01b3c0f036
commit
3593fa27ab
@ -121,6 +121,11 @@ void TextureCache::ConvertTexture(TCacheEntryBase* base_entry, TCacheEntryBase*
|
|||||||
entry->GetTexture()->OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
entry->GetTexture()->OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool IsDepthCopyFormat(PEControl::PixelFormat format)
|
||||||
|
{
|
||||||
|
return format == PEControl::Z24;
|
||||||
|
}
|
||||||
|
|
||||||
void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row,
|
void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_row,
|
||||||
u32 num_blocks_y, u32 memory_stride, PEControl::PixelFormat src_format,
|
u32 num_blocks_y, u32 memory_stride, PEControl::PixelFormat src_format,
|
||||||
const EFBRectangle& src_rect, bool is_intensity, bool scale_by_half)
|
const EFBRectangle& src_rect, bool is_intensity, bool scale_by_half)
|
||||||
@ -135,7 +140,7 @@ void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_
|
|||||||
{static_cast<u32>(scaled_src_rect.GetWidth()),
|
{static_cast<u32>(scaled_src_rect.GetWidth()),
|
||||||
static_cast<u32>(scaled_src_rect.GetHeight())}};
|
static_cast<u32>(scaled_src_rect.GetHeight())}};
|
||||||
Texture2D* src_texture;
|
Texture2D* src_texture;
|
||||||
if (src_format == PEControl::Z24)
|
if (IsDepthCopyFormat(src_format))
|
||||||
src_texture = FramebufferManager::GetInstance()->ResolveEFBDepthTexture(region);
|
src_texture = FramebufferManager::GetInstance()->ResolveEFBDepthTexture(region);
|
||||||
else
|
else
|
||||||
src_texture = FramebufferManager::GetInstance()->ResolveEFBColorTexture(region);
|
src_texture = FramebufferManager::GetInstance()->ResolveEFBColorTexture(region);
|
||||||
@ -159,6 +164,95 @@ void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_
|
|||||||
src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), original_layout);
|
src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), original_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextureCache::CopyRectangleFromTexture(TCacheEntry* dst_texture,
|
||||||
|
const MathUtil::Rectangle<int>& dst_rect,
|
||||||
|
Texture2D* src_texture,
|
||||||
|
const MathUtil::Rectangle<int>& src_rect)
|
||||||
|
{
|
||||||
|
// Fast path when not scaling the image.
|
||||||
|
if (src_rect.GetWidth() == dst_rect.GetWidth() && src_rect.GetHeight() == dst_rect.GetHeight())
|
||||||
|
CopyTextureRectangle(dst_texture, dst_rect, src_texture, src_rect);
|
||||||
|
else
|
||||||
|
ScaleTextureRectangle(dst_texture, dst_rect, src_texture, src_rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureCache::CopyTextureRectangle(TCacheEntry* dst_texture,
|
||||||
|
const MathUtil::Rectangle<int>& dst_rect,
|
||||||
|
Texture2D* src_texture,
|
||||||
|
const MathUtil::Rectangle<int>& src_rect)
|
||||||
|
{
|
||||||
|
_assert_msg_(VIDEO, static_cast<u32>(src_rect.GetWidth()) <= src_texture->GetWidth() &&
|
||||||
|
static_cast<u32>(src_rect.GetHeight()) <= src_texture->GetHeight(),
|
||||||
|
"Source rect is too large for CopyRectangleFromTexture");
|
||||||
|
|
||||||
|
_assert_msg_(VIDEO, static_cast<u32>(dst_rect.GetWidth()) <= dst_texture->config.width &&
|
||||||
|
static_cast<u32>(dst_rect.GetHeight()) <= dst_texture->config.height,
|
||||||
|
"Dest rect is too large for CopyRectangleFromTexture");
|
||||||
|
|
||||||
|
VkImageCopy image_copy = {
|
||||||
|
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0,
|
||||||
|
src_texture->GetLayers()}, // VkImageSubresourceLayers srcSubresource
|
||||||
|
{src_rect.left, src_rect.top, 0}, // VkOffset3D srcOffset
|
||||||
|
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, // VkImageSubresourceLayers dstSubresource
|
||||||
|
dst_texture->config.layers},
|
||||||
|
{dst_rect.left, dst_rect.top, 0}, // VkOffset3D dstOffset
|
||||||
|
{static_cast<uint32_t>(src_rect.GetWidth()), static_cast<uint32_t>(src_rect.GetHeight()),
|
||||||
|
1} // VkExtent3D extent
|
||||||
|
};
|
||||||
|
|
||||||
|
// Must be called outside of a render pass.
|
||||||
|
StateTracker::GetInstance()->EndRenderPass();
|
||||||
|
|
||||||
|
src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||||
|
dst_texture->GetTexture()->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||||
|
|
||||||
|
vkCmdCopyImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), src_texture->GetImage(),
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_texture->GetTexture()->GetImage(),
|
||||||
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureCache::ScaleTextureRectangle(TCacheEntry* dst_texture,
|
||||||
|
const MathUtil::Rectangle<int>& dst_rect,
|
||||||
|
Texture2D* src_texture,
|
||||||
|
const MathUtil::Rectangle<int>& src_rect)
|
||||||
|
{
|
||||||
|
// Can't do this within a game render pass.
|
||||||
|
StateTracker::GetInstance()->EndRenderPass();
|
||||||
|
StateTracker::GetInstance()->SetPendingRebind();
|
||||||
|
|
||||||
|
// Can't render to a non-rendertarget (no framebuffer).
|
||||||
|
_assert_msg_(VIDEO, dst_texture->config.rendertarget,
|
||||||
|
"Destination texture for partial copy is not a rendertarget");
|
||||||
|
|
||||||
|
// Render pass expects dst_texture to be in SHADER_READ_ONLY state.
|
||||||
|
src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
dst_texture->GetTexture()->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
|
|
||||||
|
UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
|
g_object_cache->GetStandardPipelineLayout(),
|
||||||
|
GetRenderPassForTextureUpdate(dst_texture->GetTexture()),
|
||||||
|
g_object_cache->GetPassthroughVertexShader(),
|
||||||
|
g_object_cache->GetPassthroughGeometryShader(), m_copy_shader);
|
||||||
|
|
||||||
|
VkRect2D region = {
|
||||||
|
{dst_rect.left, dst_rect.top},
|
||||||
|
{static_cast<u32>(dst_rect.GetWidth()), static_cast<u32>(dst_rect.GetHeight())}};
|
||||||
|
draw.BeginRenderPass(dst_texture->GetFramebuffer(), region);
|
||||||
|
draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetLinearSampler());
|
||||||
|
draw.DrawQuad(dst_rect.left, dst_rect.top, dst_rect.GetWidth(), dst_rect.GetHeight(),
|
||||||
|
src_rect.left, src_rect.top, 0, src_rect.GetWidth(), src_rect.GetHeight(),
|
||||||
|
static_cast<int>(src_texture->GetWidth()),
|
||||||
|
static_cast<int>(src_texture->GetHeight()));
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
// Determine image usage, we need to flag as an attachment if it can be used as a rendertarget.
|
// Determine image usage, we need to flag as an attachment if it can be used as a rendertarget.
|
||||||
@ -466,7 +560,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat
|
|||||||
FramebufferManager* framebuffer_mgr =
|
FramebufferManager* framebuffer_mgr =
|
||||||
static_cast<FramebufferManager*>(g_framebuffer_manager.get());
|
static_cast<FramebufferManager*>(g_framebuffer_manager.get());
|
||||||
TargetRectangle scaled_src_rect = g_renderer->ConvertEFBRectangle(src_rect);
|
TargetRectangle scaled_src_rect = g_renderer->ConvertEFBRectangle(src_rect);
|
||||||
bool is_depth_copy = (src_format == PEControl::Z24);
|
bool is_depth_copy = IsDepthCopyFormat(src_format);
|
||||||
|
|
||||||
// Flush EFB pokes first, as they're expected to be included.
|
// Flush EFB pokes first, as they're expected to be included.
|
||||||
framebuffer_mgr->FlushEFBPokes();
|
framebuffer_mgr->FlushEFBPokes();
|
||||||
@ -528,74 +622,14 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase*
|
|||||||
const MathUtil::Rectangle<int>& dst_rect)
|
const MathUtil::Rectangle<int>& dst_rect)
|
||||||
{
|
{
|
||||||
const TCacheEntry* source_vk = static_cast<const TCacheEntry*>(source);
|
const TCacheEntry* source_vk = static_cast<const TCacheEntry*>(source);
|
||||||
VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer();
|
TextureCache::GetInstance()->CopyRectangleFromTexture(this, dst_rect, source_vk->GetTexture(),
|
||||||
|
src_rect);
|
||||||
|
|
||||||
// Fast path when not scaling the image.
|
// Ensure textures are ready for use again.
|
||||||
if (src_rect.GetWidth() == dst_rect.GetWidth() && src_rect.GetHeight() == dst_rect.GetHeight())
|
m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
{
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
// These assertions should hold true unless the base code is passing us sizes too large, in
|
source_vk->GetTexture()->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||||
// which case it should be fixed instead.
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||||
_assert_msg_(VIDEO, static_cast<u32>(src_rect.GetWidth()) <= source->config.width &&
|
|
||||||
static_cast<u32>(src_rect.GetHeight()) <= source->config.height,
|
|
||||||
"Source rect is too large for CopyRectangleFromTexture");
|
|
||||||
|
|
||||||
_assert_msg_(VIDEO, static_cast<u32>(dst_rect.GetWidth()) <= config.width &&
|
|
||||||
static_cast<u32>(dst_rect.GetHeight()) <= config.height,
|
|
||||||
"Dest rect is too large for CopyRectangleFromTexture");
|
|
||||||
|
|
||||||
VkImageCopy image_copy = {
|
|
||||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0,
|
|
||||||
source->config.layers}, // VkImageSubresourceLayers srcSubresource
|
|
||||||
{src_rect.left, src_rect.top, 0}, // VkOffset3D srcOffset
|
|
||||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0,
|
|
||||||
config.layers}, // VkImageSubresourceLayers dstSubresource
|
|
||||||
{dst_rect.left, dst_rect.top, 0}, // VkOffset3D dstOffset
|
|
||||||
{static_cast<uint32_t>(src_rect.GetWidth()), static_cast<uint32_t>(src_rect.GetHeight()),
|
|
||||||
1} // VkExtent3D extent
|
|
||||||
};
|
|
||||||
|
|
||||||
// Must be called outside of a render pass.
|
|
||||||
StateTracker::GetInstance()->EndRenderPass();
|
|
||||||
|
|
||||||
source_vk->m_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
|
||||||
m_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
|
||||||
|
|
||||||
vkCmdCopyImage(command_buffer, source_vk->m_texture->GetImage(),
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_texture->GetImage(),
|
|
||||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &image_copy);
|
|
||||||
|
|
||||||
m_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
|
||||||
source_vk->m_texture->TransitionToLayout(command_buffer,
|
|
||||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can't do this within a game render pass.
|
|
||||||
StateTracker::GetInstance()->EndRenderPass();
|
|
||||||
StateTracker::GetInstance()->SetPendingRebind();
|
|
||||||
|
|
||||||
// Can't render to a non-rendertarget (no framebuffer).
|
|
||||||
_assert_msg_(VIDEO, config.rendertarget,
|
|
||||||
"Destination texture for partial copy is not a rendertarget");
|
|
||||||
|
|
||||||
UtilityShaderDraw draw(
|
|
||||||
g_command_buffer_mgr->GetCurrentCommandBuffer(), g_object_cache->GetStandardPipelineLayout(),
|
|
||||||
TextureCache::GetInstance()->GetRenderPassForTextureUpdate(m_texture.get()),
|
|
||||||
g_object_cache->GetPassthroughVertexShader(), VK_NULL_HANDLE,
|
|
||||||
TextureCache::GetInstance()->m_copy_shader);
|
|
||||||
|
|
||||||
VkRect2D region = {
|
|
||||||
{dst_rect.left, dst_rect.top},
|
|
||||||
{static_cast<u32>(dst_rect.GetWidth()), static_cast<u32>(dst_rect.GetHeight())}};
|
|
||||||
draw.BeginRenderPass(m_framebuffer, region);
|
|
||||||
draw.SetPSSampler(0, source_vk->GetTexture()->GetView(), g_object_cache->GetLinearSampler());
|
|
||||||
draw.DrawQuad(dst_rect.left, dst_rect.top, dst_rect.GetWidth(), dst_rect.GetHeight(),
|
|
||||||
src_rect.left, src_rect.top, 0, src_rect.GetWidth(), src_rect.GetHeight(),
|
|
||||||
source->config.width, source->config.height);
|
|
||||||
draw.EndRenderPass();
|
|
||||||
|
|
||||||
// Render pass transitions texture to SHADER_READ_ONLY.
|
|
||||||
m_texture->OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextureCache::TCacheEntry::Bind(unsigned int stage)
|
void TextureCache::TCacheEntry::Bind(unsigned int stage)
|
||||||
|
@ -63,10 +63,21 @@ public:
|
|||||||
u32 memory_stride, PEControl::PixelFormat src_format, const EFBRectangle& src_rect,
|
u32 memory_stride, PEControl::PixelFormat src_format, const EFBRectangle& src_rect,
|
||||||
bool is_intensity, bool scale_by_half) override;
|
bool is_intensity, bool scale_by_half) override;
|
||||||
|
|
||||||
|
void CopyRectangleFromTexture(TCacheEntry* dst_texture, const MathUtil::Rectangle<int>& dst_rect,
|
||||||
|
Texture2D* src_texture, const MathUtil::Rectangle<int>& src_rect);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool CreateRenderPasses();
|
bool CreateRenderPasses();
|
||||||
VkRenderPass GetRenderPassForTextureUpdate(const Texture2D* texture) const;
|
VkRenderPass GetRenderPassForTextureUpdate(const Texture2D* texture) const;
|
||||||
|
|
||||||
|
// Copies the contents of a texture using vkCmdCopyImage
|
||||||
|
void CopyTextureRectangle(TCacheEntry* dst_texture, const MathUtil::Rectangle<int>& dst_rect,
|
||||||
|
Texture2D* src_texture, const MathUtil::Rectangle<int>& src_rect);
|
||||||
|
|
||||||
|
// Copies (and optionally scales) the contents of a texture using a framgent shader.
|
||||||
|
void ScaleTextureRectangle(TCacheEntry* dst_texture, const MathUtil::Rectangle<int>& dst_rect,
|
||||||
|
Texture2D* src_texture, const MathUtil::Rectangle<int>& src_rect);
|
||||||
|
|
||||||
VkRenderPass m_initialize_render_pass = VK_NULL_HANDLE;
|
VkRenderPass m_initialize_render_pass = VK_NULL_HANDLE;
|
||||||
VkRenderPass m_update_render_pass = VK_NULL_HANDLE;
|
VkRenderPass m_update_render_pass = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user