mirror of
https://github.com/libretro/parallel-gx1.git
synced 2026-11-07 04:26:01 -10:00
libretro: one picture a run from the inline outputs too
On OpenGL and Direct3D 11, and on Vulkan and Direct3D 12 in single core, the GPU loop runs inside retro_run, and a run after one that ran out of time catches up on two fields: both presented, and the frontend's video_refresh was called twice in one run. A picture drawn or handed over on the hardware is now reported once, at the end of the run, the last one drawn, as the threaded outputs already did. Direct3D 11 version 1 is the exception, as the frontend reads its texture inside the callback: that output reports at once, the first picture of a run, and drops a second. So do pictures in memory (software rendering). What the output hands over in place, the XFB texture itself, may have been read in a layout of the core's own since it was presented, as a copy's source say: before the frontend is told, it goes back to the one the frontend reads it in, as it already did before a repeat (FrameOutput::KeepReadable, which Repeat was).
This commit is contained in:
1 parent
e4bac5f75c
commit
ba1e153dad
5 files changed
+54
-15
No files matched your search
@@ -20,10 +20,10 @@ namespace Video
|
||||
{
|
||||
static FrameOutput* s_active;
|
||||
|
||||
void OutputRepeat()
|
||||
void OutputKeepReadable()
|
||||
{
|
||||
if (s_active)
|
||||
s_active->Repeat();
|
||||
s_active->KeepReadable();
|
||||
}
|
||||
|
||||
void OutputHandOver()
|
||||
@@ -249,7 +249,7 @@ void DX11Output::Present()
|
||||
DX11::D3D::context->PSSetConstantBuffers(0, 3, null_buffers);
|
||||
DX11::D3D::context->GSSetConstantBuffers(0, 1, null_buffers);
|
||||
|
||||
video_cb(RETRO_HW_FRAME_BUFFER_VALID, m_width, m_height, 0);
|
||||
RefreshNow(m_width, m_height);
|
||||
|
||||
static_cast<DX11::Gfx*>(g_gfx.get())->RestoreContext();
|
||||
}
|
||||
@@ -428,7 +428,7 @@ bool DX12Output::HandOver()
|
||||
return true;
|
||||
}
|
||||
|
||||
void DX12Output::Repeat()
|
||||
void DX12Output::KeepReadable()
|
||||
{
|
||||
/* threaded, every execution already leaves it readable */
|
||||
if (m_threaded)
|
||||
@@ -686,7 +686,7 @@ bool VKOutput::PresentTexture(const AbstractTexture* texture, u32 width, u32 hei
|
||||
return true;
|
||||
}
|
||||
|
||||
void VKOutput::Repeat()
|
||||
void VKOutput::KeepReadable()
|
||||
{
|
||||
/* threaded, every submission already leaves it readable */
|
||||
if (m_threaded)
|
||||
|
||||
@@ -11,9 +11,10 @@ namespace Libretro
|
||||
{
|
||||
namespace Video
|
||||
{
|
||||
/* The output in use, told when the frontend is about to show the last
|
||||
* picture again, and asked to hand over what another thread published. */
|
||||
void OutputRepeat();
|
||||
/* The output in use, told when the frontend is about to read the last
|
||||
* picture handed on, and asked to hand over what another thread
|
||||
* published. */
|
||||
void OutputKeepReadable();
|
||||
void OutputHandOver();
|
||||
|
||||
/* A threaded output's pictures between the GPU thread, which publishes
|
||||
@@ -129,7 +130,7 @@ public:
|
||||
AbstractFramebuffer* Acquire() override;
|
||||
void Present() override;
|
||||
bool PresentTexture(const AbstractTexture* texture, u32 width, u32 height) override;
|
||||
void Repeat() override;
|
||||
void KeepReadable() override;
|
||||
bool IsTextureHeld(const AbstractTexture* texture) override;
|
||||
bool HandOver() override;
|
||||
u32 GetWidth() const override { return m_width; }
|
||||
@@ -176,7 +177,7 @@ public:
|
||||
AbstractFramebuffer* Acquire() override;
|
||||
void Present() override;
|
||||
bool PresentTexture(const AbstractTexture* texture, u32 width, u32 height) override;
|
||||
void Repeat() override;
|
||||
void KeepReadable() override;
|
||||
bool IsTextureHeld(const AbstractTexture* texture) override;
|
||||
bool HandOver() override;
|
||||
u32 GetWidth() const override { return m_width; }
|
||||
|
||||
@@ -992,14 +992,30 @@ void GpuThreadUnpark()
|
||||
/* The frontend's callback, behind one that counts what each retro_run
|
||||
* hands over: a run whose fields only repeated the last picture, or that
|
||||
* ran out of time before its field ended, draws nothing and reports a
|
||||
* repeat, with the last picture's size. */
|
||||
* repeat, with the last picture's size.
|
||||
*
|
||||
* A picture drawn or handed over on the hardware is reported at the end
|
||||
* of the run, the last one drawn: the GPU loop can catch up on two
|
||||
* fields in one run, after one that ran out of time, and the frontend
|
||||
* takes one frame a run. Pictures in memory, and those the frontend
|
||||
* reads inside the callback, go to it at once, the first of a run. */
|
||||
static retro_video_refresh_t s_frontend_video_cb;
|
||||
static unsigned s_frames_sent;
|
||||
static bool s_frame_drawn;
|
||||
static unsigned s_last_width;
|
||||
static unsigned s_last_height;
|
||||
|
||||
static void CountedVideoRefresh(const void* data, unsigned width, unsigned height, size_t pitch)
|
||||
{
|
||||
if (data == RETRO_HW_FRAME_BUFFER_VALID)
|
||||
{
|
||||
s_frame_drawn = true;
|
||||
s_last_width = width;
|
||||
s_last_height = height;
|
||||
return;
|
||||
}
|
||||
if (s_frames_sent)
|
||||
return;
|
||||
s_frames_sent++;
|
||||
if (data)
|
||||
{
|
||||
@@ -1009,9 +1025,27 @@ static void CountedVideoRefresh(const void* data, unsigned width, unsigned heigh
|
||||
s_frontend_video_cb(data, width, height, pitch);
|
||||
}
|
||||
|
||||
void RefreshNow(unsigned width, unsigned height)
|
||||
{
|
||||
if (s_frames_sent)
|
||||
return;
|
||||
s_frames_sent++;
|
||||
s_frame_drawn = false;
|
||||
s_last_width = width;
|
||||
s_last_height = height;
|
||||
s_frontend_video_cb(RETRO_HW_FRAME_BUFFER_VALID, width, height, 0);
|
||||
}
|
||||
|
||||
void EndFrame()
|
||||
{
|
||||
OutputHandOver();
|
||||
if (s_frame_drawn && !s_frames_sent)
|
||||
{
|
||||
OutputKeepReadable();
|
||||
s_frames_sent++;
|
||||
s_frontend_video_cb(RETRO_HW_FRAME_BUFFER_VALID, s_last_width, s_last_height, 0);
|
||||
}
|
||||
s_frame_drawn = false;
|
||||
if (!s_frames_sent)
|
||||
{
|
||||
/* before the first picture, the size the frontend was told */
|
||||
@@ -1022,7 +1056,7 @@ void EndFrame()
|
||||
s_last_width = info.geometry.base_width;
|
||||
s_last_height = info.geometry.base_height;
|
||||
}
|
||||
OutputRepeat();
|
||||
OutputKeepReadable();
|
||||
s_frontend_video_cb(nullptr, s_last_width, s_last_height, 0);
|
||||
}
|
||||
s_frames_sent = 0;
|
||||
|
||||
@@ -58,6 +58,9 @@ void D3D11Resume(unsigned depth);
|
||||
* over; when nothing new was shown, the frontend is told the last picture
|
||||
* repeats, so every run reports one frame. */
|
||||
void EndFrame();
|
||||
/* A picture the frontend reads inside video_refresh (D3D11 version 1),
|
||||
* reported at once: the first of the run. */
|
||||
void RefreshNow(unsigned width, unsigned height);
|
||||
|
||||
/* The GPU loop on a thread of its own, for the APIs whose frontend
|
||||
* interface lets another thread submit (Vulkan): the frontend's thread
|
||||
|
||||
@@ -34,9 +34,10 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Whoever shows the pictures is about to show the last one handed on
|
||||
* again: what it reads is left the way it reads it. */
|
||||
virtual void Repeat() {}
|
||||
/* Whoever shows the pictures is about to read the last one handed on,
|
||||
* again or for the first time, the core having gone on drawing since:
|
||||
* what it reads is left the way it reads it. */
|
||||
virtual void KeepReadable() {}
|
||||
|
||||
/* Whether a texture handed on with PresentTexture may still be read by
|
||||
* whoever shows the pictures, now or later: the caller keeps it alive
|
||||
|
||||
Reference in new issue
Block a user