mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 14:19:46 -06:00
Remove old XFB logic
This commit is contained in:
@ -61,11 +61,6 @@ Renderer::~Renderer()
|
||||
{
|
||||
UpdateActiveConfig();
|
||||
|
||||
// Ensure all frames are written to frame dump at shutdown.
|
||||
if (m_frame_dumping_active)
|
||||
EndFrameDumping();
|
||||
|
||||
DestroyFrameDumpResources();
|
||||
DestroyShaders();
|
||||
DestroySemaphores();
|
||||
}
|
||||
@ -491,12 +486,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ti
|
||||
// Pending/batched EFB pokes should be included in the final image.
|
||||
FramebufferManager::GetInstance()->FlushEFBPokes();
|
||||
|
||||
// Check that we actually have an image to render in XFB-on modes.
|
||||
if (!m_xfb_written)
|
||||
{
|
||||
Core::Callback_VideoCopiedToXFB(false);
|
||||
}
|
||||
|
||||
auto* xfb_texture = static_cast<VKTexture*>(texture);
|
||||
|
||||
// End the current render pass.
|
||||
@ -563,90 +552,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ti
|
||||
g_shader_cache->RetrieveAsyncShaders();
|
||||
}
|
||||
|
||||
void Renderer::TransitionBuffersForSwap(const TargetRectangle& scaled_rect,
|
||||
const XFBSourceBase* const* xfb_sources, u32 xfb_count)
|
||||
{
|
||||
VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer();
|
||||
|
||||
// Drawing XFB sources, so transition all of them.
|
||||
// Don't need the EFB, so leave it as-is.
|
||||
for (u32 i = 0; i < xfb_count; i++)
|
||||
{
|
||||
const XFBSource* xfb_source = static_cast<const XFBSource*>(xfb_sources[i]);
|
||||
xfb_source->GetTexture()->GetRawTexIdentifier()->TransitionToLayout(
|
||||
command_buffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::DrawFrame(VkRenderPass render_pass, const TargetRectangle& target_rect,
|
||||
const TargetRectangle& scaled_efb_rect, u32 xfb_addr,
|
||||
const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width,
|
||||
u32 fb_stride, u32 fb_height)
|
||||
{
|
||||
}
|
||||
|
||||
void Renderer::DrawEFB(VkRenderPass render_pass, const TargetRectangle& target_rect,
|
||||
const TargetRectangle& scaled_efb_rect)
|
||||
{
|
||||
// Transition the EFB render target to a shader resource.
|
||||
Texture2D* efb_color_texture =
|
||||
g_ActiveConfig.iMultisamples > 1 ?
|
||||
FramebufferManager::GetInstance()->GetResolvedEFBColorTexture() :
|
||||
FramebufferManager::GetInstance()->GetEFBColorTexture();
|
||||
|
||||
// Copy EFB -> backbuffer
|
||||
BlitScreen(render_pass, target_rect, scaled_efb_rect, efb_color_texture);
|
||||
}
|
||||
|
||||
void Renderer::DrawVirtualXFB(VkRenderPass render_pass, const TargetRectangle& target_rect,
|
||||
u32 xfb_addr, const XFBSourceBase* const* xfb_sources, u32 xfb_count,
|
||||
u32 fb_width, u32 fb_stride, u32 fb_height)
|
||||
{
|
||||
for (u32 i = 0; i < xfb_count; ++i)
|
||||
{
|
||||
const XFBSource* xfb_source = static_cast<const XFBSource*>(xfb_sources[i]);
|
||||
TargetRectangle source_rect = xfb_source->sourceRc;
|
||||
TargetRectangle draw_rect;
|
||||
|
||||
int xfb_width = static_cast<int>(xfb_source->srcWidth);
|
||||
int xfb_height = static_cast<int>(xfb_source->srcHeight);
|
||||
int h_offset = (static_cast<s32>(xfb_source->srcAddr) - static_cast<s32>(xfb_addr)) /
|
||||
(static_cast<s32>(fb_stride) * 2);
|
||||
draw_rect.top =
|
||||
target_rect.top + h_offset * target_rect.GetHeight() / static_cast<s32>(fb_height);
|
||||
draw_rect.bottom =
|
||||
target_rect.top +
|
||||
(h_offset + xfb_height) * target_rect.GetHeight() / static_cast<s32>(fb_height);
|
||||
draw_rect.left = target_rect.left +
|
||||
(target_rect.GetWidth() -
|
||||
xfb_width * target_rect.GetWidth() / static_cast<s32>(fb_stride)) /
|
||||
2;
|
||||
draw_rect.right = target_rect.left +
|
||||
(target_rect.GetWidth() +
|
||||
xfb_width * target_rect.GetWidth() / static_cast<s32>(fb_stride)) /
|
||||
2;
|
||||
|
||||
source_rect.right -= Renderer::EFBToScaledX(fb_stride - fb_width);
|
||||
BlitScreen(render_pass, draw_rect, source_rect,
|
||||
xfb_source->GetTexture()->GetRawTexIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::DrawRealXFB(VkRenderPass render_pass, const TargetRectangle& target_rect,
|
||||
const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width,
|
||||
u32 fb_stride, u32 fb_height)
|
||||
{
|
||||
for (u32 i = 0; i < xfb_count; ++i)
|
||||
{
|
||||
const XFBSource* xfb_source = static_cast<const XFBSource*>(xfb_sources[i]);
|
||||
TargetRectangle source_rect = xfb_source->sourceRc;
|
||||
TargetRectangle draw_rect = target_rect;
|
||||
source_rect.right -= fb_stride - fb_width;
|
||||
BlitScreen(render_pass, draw_rect, source_rect,
|
||||
xfb_source->GetTexture()->GetRawTexIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::DrawScreen(VKTexture* xfb_texture)
|
||||
{
|
||||
VkResult res;
|
||||
@ -718,173 +623,6 @@ void Renderer::DrawScreen(VKTexture* xfb_texture)
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
}
|
||||
|
||||
bool Renderer::DrawFrameDump(const TargetRectangle& scaled_efb_rect, u32 xfb_addr,
|
||||
const XFBSourceBase* const* xfb_sources, u32 xfb_count, u32 fb_width,
|
||||
u32 fb_stride, u32 fb_height, u64 ticks)
|
||||
{
|
||||
TargetRectangle target_rect = CalculateFrameDumpDrawRectangle();
|
||||
u32 width = std::max(1u, static_cast<u32>(target_rect.GetWidth()));
|
||||
u32 height = std::max(1u, static_cast<u32>(target_rect.GetHeight()));
|
||||
if (!ResizeFrameDumpBuffer(width, height))
|
||||
return false;
|
||||
|
||||
// If there was a previous frame dumped, we'll still be in TRANSFER_SRC layout.
|
||||
m_frame_dump_render_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
|
||||
VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||
VkClearRect clear_rect = {{{0, 0}, {width, height}}, 0, 1};
|
||||
VkClearAttachment clear_attachment = {VK_IMAGE_ASPECT_COLOR_BIT, 0, clear_value};
|
||||
VkRenderPassBeginInfo info = {
|
||||
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
||||
nullptr,
|
||||
FramebufferManager::GetInstance()->GetColorCopyForReadbackRenderPass(),
|
||||
m_frame_dump_framebuffer,
|
||||
{{0, 0}, {width, height}},
|
||||
1,
|
||||
&clear_value};
|
||||
vkCmdBeginRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer(), &info,
|
||||
VK_SUBPASS_CONTENTS_INLINE);
|
||||
vkCmdClearAttachments(g_command_buffer_mgr->GetCurrentCommandBuffer(), 1, &clear_attachment, 1,
|
||||
&clear_rect);
|
||||
DrawFrame(FramebufferManager::GetInstance()->GetColorCopyForReadbackRenderPass(), target_rect,
|
||||
scaled_efb_rect, xfb_addr, xfb_sources, xfb_count, fb_width, fb_stride, fb_height);
|
||||
vkCmdEndRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer());
|
||||
|
||||
// Prepare the readback texture for copying.
|
||||
StagingTexture2D* readback_texture = PrepareFrameDumpImage(width, height, ticks);
|
||||
if (!readback_texture)
|
||||
return false;
|
||||
|
||||
// Queue a copy to the current frame dump buffer. It will be written to the frame dump later.
|
||||
m_frame_dump_render_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
readback_texture->CopyFromImage(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
m_frame_dump_render_texture->GetImage(),
|
||||
VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, width, height, 0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Renderer::StartFrameDumping()
|
||||
{
|
||||
_assert_(!m_frame_dumping_active);
|
||||
|
||||
// Register fence callback so that we know when frames are ready to be written to the dump.
|
||||
// This is done by clearing the fence pointer, so WriteFrameDumpFrame doesn't have to wait.
|
||||
auto queued_callback = [](VkCommandBuffer, VkFence) {};
|
||||
auto signaled_callback = std::bind(&Renderer::OnFrameDumpImageReady, this, std::placeholders::_1);
|
||||
|
||||
// We use the array pointer as a key here, that way if Renderer needed fence callbacks in
|
||||
// the future it could be used without conflicting.
|
||||
// We're not interested in when fences are submitted, so the first callback is a no-op.
|
||||
g_command_buffer_mgr->AddFencePointCallback(
|
||||
m_frame_dump_images.data(), std::move(queued_callback), std::move(signaled_callback));
|
||||
m_frame_dumping_active = true;
|
||||
}
|
||||
|
||||
void Renderer::EndFrameDumping()
|
||||
{
|
||||
_assert_(m_frame_dumping_active);
|
||||
|
||||
// Write any pending frames to the frame dump.
|
||||
FlushFrameDump();
|
||||
|
||||
// Remove the fence callback that we registered earlier, one less function that needs to be
|
||||
// called when preparing a command buffer.
|
||||
g_command_buffer_mgr->RemoveFencePointCallback(m_frame_dump_images.data());
|
||||
m_frame_dumping_active = false;
|
||||
}
|
||||
|
||||
void Renderer::OnFrameDumpImageReady(VkFence fence)
|
||||
{
|
||||
for (FrameDumpImage& frame : m_frame_dump_images)
|
||||
{
|
||||
// fence being a null handle means that we don't have to wait to re-use this image.
|
||||
if (frame.fence == fence)
|
||||
frame.fence = VK_NULL_HANDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::WriteFrameDumpImage(size_t index)
|
||||
{
|
||||
/*FrameDumpImage& frame = m_frame_dump_images[index];
|
||||
_assert_(frame.pending);
|
||||
|
||||
// Check fence has been signaled.
|
||||
// The callback here should set fence to null.
|
||||
if (frame.fence != VK_NULL_HANDLE)
|
||||
{
|
||||
g_command_buffer_mgr->WaitForFence(frame.fence);
|
||||
_assert_(frame.fence == VK_NULL_HANDLE);
|
||||
}
|
||||
|
||||
// Copy the now-populated image data to the output file.
|
||||
DumpFrameData(reinterpret_cast<const u8*>(frame.readback_texture->GetMapPointer()),
|
||||
static_cast<int>(frame.readback_texture->GetWidth()),
|
||||
static_cast<int>(frame.readback_texture->GetHeight()),
|
||||
static_cast<int>(frame.readback_texture->GetRowStride()), frame.dump_state);
|
||||
|
||||
frame.pending = false;*/
|
||||
}
|
||||
|
||||
StagingTexture2D* Renderer::PrepareFrameDumpImage(u32 width, u32 height, u64 ticks)
|
||||
{
|
||||
// Ensure the last frame that was sent to the frame dump has completed encoding before we send
|
||||
// the next image to it.
|
||||
//FinishFrameData();
|
||||
|
||||
// If the last image hasn't been written to the frame dump yet, write it now.
|
||||
// This is necessary so that the worker thread is no more than one frame behind, and the pointer
|
||||
// (which is actually the buffer) is safe for us to re-use next time.
|
||||
if (m_frame_dump_images[m_current_frame_dump_image].pending)
|
||||
WriteFrameDumpImage(m_current_frame_dump_image);
|
||||
|
||||
// Move to the next image buffer
|
||||
m_current_frame_dump_image = (m_current_frame_dump_image + 1) % FRAME_DUMP_BUFFERED_FRAMES;
|
||||
FrameDumpImage& image = m_frame_dump_images[m_current_frame_dump_image];
|
||||
|
||||
// Ensure the dimensions of the readback texture are sufficient.
|
||||
if (!image.readback_texture || width != image.readback_texture->GetWidth() ||
|
||||
height != image.readback_texture->GetHeight())
|
||||
{
|
||||
// Allocate a new readback texture.
|
||||
// The reset() call is here so that the memory is released before allocating the new texture.
|
||||
image.readback_texture.reset();
|
||||
image.readback_texture = StagingTexture2D::Create(STAGING_BUFFER_TYPE_READBACK, width, height,
|
||||
EFB_COLOR_TEXTURE_FORMAT);
|
||||
|
||||
if (!image.readback_texture || !image.readback_texture->Map())
|
||||
{
|
||||
// Not actually fatal, just means we can't dump this frame.
|
||||
PanicAlert("Failed to allocate frame dump readback texture.");
|
||||
image.readback_texture.reset();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// The copy happens immediately after this function returns, so flag this frame as pending.
|
||||
image.fence = g_command_buffer_mgr->GetCurrentCommandBufferFence();
|
||||
image.dump_state = AVIDump::FetchState(ticks);
|
||||
image.pending = true;
|
||||
return image.readback_texture.get();
|
||||
}
|
||||
|
||||
void Renderer::FlushFrameDump()
|
||||
{
|
||||
// We must write frames in order, so this is why we use a counter rather than a range.
|
||||
for (size_t i = 0; i < FRAME_DUMP_BUFFERED_FRAMES; i++)
|
||||
{
|
||||
if (m_frame_dump_images[m_current_frame_dump_image].pending)
|
||||
WriteFrameDumpImage(m_current_frame_dump_image);
|
||||
|
||||
m_current_frame_dump_image = (m_current_frame_dump_image + 1) % FRAME_DUMP_BUFFERED_FRAMES;
|
||||
}
|
||||
|
||||
// Since everything has been written now, may as well start at index zero.
|
||||
// count-1 here because the index is incremented before usage.
|
||||
m_current_frame_dump_image = FRAME_DUMP_BUFFERED_FRAMES - 1;
|
||||
}
|
||||
|
||||
void Renderer::BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_rect,
|
||||
const TargetRectangle& src_rect, const Texture2D* src_tex)
|
||||
{
|
||||
@ -908,100 +646,6 @@ void Renderer::BlitScreen(VkRenderPass render_pass, const TargetRectangle& dst_r
|
||||
}
|
||||
}
|
||||
|
||||
bool Renderer::ResizeFrameDumpBuffer(u32 new_width, u32 new_height)
|
||||
{
|
||||
if (m_frame_dump_render_texture && m_frame_dump_render_texture->GetWidth() == new_width &&
|
||||
m_frame_dump_render_texture->GetHeight() == new_height)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ensure all previous frames have been dumped, since we are destroying a framebuffer
|
||||
// that may still be in use.
|
||||
FlushFrameDump();
|
||||
|
||||
if (m_frame_dump_framebuffer != VK_NULL_HANDLE)
|
||||
{
|
||||
vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_frame_dump_framebuffer, nullptr);
|
||||
m_frame_dump_framebuffer = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
m_frame_dump_render_texture =
|
||||
Texture2D::Create(new_width, new_height, 1, 1, EFB_COLOR_TEXTURE_FORMAT,
|
||||
VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D, VK_IMAGE_TILING_OPTIMAL,
|
||||
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
|
||||
|
||||
if (!m_frame_dump_render_texture)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Failed to resize frame dump render texture");
|
||||
m_frame_dump_render_texture.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
VkImageView attachment = m_frame_dump_render_texture->GetView();
|
||||
VkFramebufferCreateInfo info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
info.renderPass = FramebufferManager::GetInstance()->GetColorCopyForReadbackRenderPass();
|
||||
info.attachmentCount = 1;
|
||||
info.pAttachments = &attachment;
|
||||
info.width = new_width;
|
||||
info.height = new_height;
|
||||
info.layers = 1;
|
||||
|
||||
VkResult res =
|
||||
vkCreateFramebuffer(g_vulkan_context->GetDevice(), &info, nullptr, &m_frame_dump_framebuffer);
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
WARN_LOG(VIDEO, "Failed to create frame dump framebuffer");
|
||||
m_frame_dump_render_texture.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Render pass expects texture is in transfer src to start with.
|
||||
m_frame_dump_render_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Renderer::DestroyFrameDumpResources()
|
||||
{
|
||||
if (m_frame_dump_framebuffer != VK_NULL_HANDLE)
|
||||
{
|
||||
vkDestroyFramebuffer(g_vulkan_context->GetDevice(), m_frame_dump_framebuffer, nullptr);
|
||||
m_frame_dump_framebuffer = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
m_frame_dump_render_texture.reset();
|
||||
|
||||
for (FrameDumpImage& image : m_frame_dump_images)
|
||||
{
|
||||
image.readback_texture.reset();
|
||||
image.fence = VK_NULL_HANDLE;
|
||||
image.dump_state = {};
|
||||
image.pending = false;
|
||||
}
|
||||
m_current_frame_dump_image = FRAME_DUMP_BUFFERED_FRAMES - 1;
|
||||
}
|
||||
|
||||
void Renderer::CheckForTargetResize(u32 fb_width, u32 fb_stride, u32 fb_height)
|
||||
{
|
||||
/*if (FramebufferManagerBase::LastXfbWidth() == fb_stride &&
|
||||
FramebufferManagerBase::LastXfbHeight() == fb_height)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
u32 new_width = (fb_stride < 1 || fb_stride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fb_stride;
|
||||
u32 new_height = (fb_height < 1 || fb_height > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fb_height;
|
||||
FramebufferManagerBase::SetLastXfbWidth(new_width);
|
||||
FramebufferManagerBase::SetLastXfbHeight(new_height);
|
||||
|
||||
// Changing the XFB source area may alter the target size.
|
||||
if (CalculateTargetSize())
|
||||
ResizeEFBTextures();*/
|
||||
}
|
||||
|
||||
void Renderer::CheckForSurfaceChange()
|
||||
{
|
||||
if (!m_surface_needs_change.IsSet())
|
||||
|
Reference in New Issue
Block a user