GPU: Use old frame when presenting a skip.

If we flip using a skipped frame, we may show an even older frame causing
weird flickering.
This commit is contained in:
Unknown W. Brackets 2020-03-01 13:55:28 -08:00
parent 5597752a5b
commit cebcfb1bbd
17 changed files with 31 additions and 26 deletions

View file

@ -781,7 +781,7 @@ void __DisplayFlip(int cyclesLate) {
// Check first though, might've just quit / been paused.
if (coreState == CORE_RUNNING) {
coreState = CORE_NEXTFRAME;
gpu->CopyDisplayToOutput();
gpu->CopyDisplayToOutput(fbReallyDirty);
if (fbReallyDirty) {
actualFlips++;
}

View file

@ -846,7 +846,7 @@ void FramebufferManagerCommon::SetViewport2D(int x, int y, int w, int h) {
draw_->SetViewports(1, &vp);
}
void FramebufferManagerCommon::CopyDisplayToOutput() {
void FramebufferManagerCommon::CopyDisplayToOutput(bool reallyDirty) {
DownloadFramebufferOnSwitch(currentRenderVfb_);
shaderManager_->DirtyLastShader();
@ -869,12 +869,16 @@ void FramebufferManagerCommon::CopyDisplayToOutput() {
CardboardSettings cardboardSettings;
GetCardboardSettings(&cardboardSettings);
VirtualFramebuffer *vfb = GetVFBAt(displayFramebufPtr_);
// If it's not really dirty, we're probably frameskipping. Use the last working one.
u32 fbaddr = reallyDirty ? displayFramebufPtr_ : prevDisplayFramebufPtr_;
prevDisplayFramebufPtr_ = fbaddr;
VirtualFramebuffer *vfb = GetVFBAt(fbaddr);
if (!vfb) {
// Let's search for a framebuf within this range. Note that we also look for
// "framebuffers" sitting in RAM (created from block transfer or similar) so we only take off the kernel
// and uncached bits of the address when comparing.
const u32 addr = displayFramebufPtr_ & 0x3FFFFFFF;
const u32 addr = fbaddr & 0x3FFFFFFF;
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *v = vfbs_[i];
const u32 v_addr = v->fb_address & 0x3FFFFFFF;
@ -912,7 +916,7 @@ void FramebufferManagerCommon::CopyDisplayToOutput() {
}
if (!vfb) {
if (Memory::IsValidAddress(displayFramebufPtr_)) {
if (Memory::IsValidAddress(fbaddr)) {
// The game is displaying something directly from RAM. In GTA, it's decoded video.
if (!vfb) {
shaderManager_->DirtyLastShader();
@ -923,12 +927,12 @@ void FramebufferManagerCommon::CopyDisplayToOutput() {
// Just a pointer to plain memory to draw. We should create a framebuffer, then draw to it.
SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
draw_->SetScissorRect(0, 0, pixelWidth_, pixelHeight_);
DrawFramebufferToOutput(Memory::GetPointer(displayFramebufPtr_), displayFormat_, displayStride_, true);
DrawFramebufferToOutput(Memory::GetPointer(fbaddr), displayFormat_, displayStride_, true);
gstate_c.Dirty(DIRTY_BLEND_STATE);
return;
}
} else {
DEBUG_LOG(FRAMEBUF, "Found no FBO to display! displayFBPtr = %08x", displayFramebufPtr_);
DEBUG_LOG(FRAMEBUF, "Found no FBO to display! displayFBPtr = %08x", fbaddr);
// No framebuffer to display! Clear to black.
if (useBufferedRendering_) {
shaderManager_->DirtyLastShader();

View file

@ -228,7 +228,7 @@ public:
void RebindFramebuffer();
std::vector<FramebufferInfo> GetFramebufferList();
void CopyDisplayToOutput();
void CopyDisplayToOutput(bool reallyDirty);
bool NotifyFramebufferCopy(u32 src, u32 dest, int size, bool isMemset, u32 skipDrawReason);
void NotifyVideoUpload(u32 addr, int size, int width, GEBufferFormat fmt);
@ -383,6 +383,7 @@ protected:
u32 displayFramebufPtr_ = 0;
u32 displayStride_ = 0;
GEBufferFormat displayFormat_;
u32 prevDisplayFramebufPtr_ = 0;
VirtualFramebuffer *displayFramebuf_ = nullptr;
VirtualFramebuffer *prevDisplayFramebuf_ = nullptr;

View file

@ -262,13 +262,13 @@ void GPU_D3D11::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat f
framebufferManagerD3D11_->SetDisplayFramebuffer(framebuf, stride, format);
}
void GPU_D3D11::CopyDisplayToOutput() {
void GPU_D3D11::CopyDisplayToOutput(bool reallyDirty) {
float blendColor[4]{};
context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0xF], blendColor, 0xFFFFFFFF);
drawEngine_.Flush();
framebufferManagerD3D11_->CopyDisplayToOutput();
framebufferManagerD3D11_->CopyDisplayToOutput(reallyDirty);
framebufferManagerD3D11_->EndFrame();
// shaderManager_->EndFrame();

View file

@ -71,7 +71,7 @@ private:
void InitClear() override;
void BeginFrame() override;
void CopyDisplayToOutput() override;
void CopyDisplayToOutput(bool reallyDirty) override;
ID3D11Device *device_;
ID3D11DeviceContext *context_;

View file

@ -299,13 +299,13 @@ void GPU_DX9::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat for
framebufferManagerDX9_->SetDisplayFramebuffer(framebuf, stride, format);
}
void GPU_DX9::CopyDisplayToOutput() {
void GPU_DX9::CopyDisplayToOutput(bool reallyDirty) {
dxstate.depthWrite.set(true);
dxstate.colorMask.set(true, true, true, true);
drawEngine_.Flush();
framebufferManagerDX9_->CopyDisplayToOutput();
framebufferManagerDX9_->CopyDisplayToOutput(reallyDirty);
framebufferManagerDX9_->EndFrame();
// shaderManager_->EndFrame();

View file

@ -70,7 +70,7 @@ private:
void InitClear() override;
void BeginFrame() override;
void CopyDisplayToOutput() override;
void CopyDisplayToOutput(bool reallyDirty) override;
LPDIRECT3DDEVICE9 device_;
LPDIRECT3DDEVICE9EX deviceEx_;

View file

@ -400,14 +400,14 @@ void GPU_GLES::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat fo
framebufferManagerGL_->SetDisplayFramebuffer(framebuf, stride, format);
}
void GPU_GLES::CopyDisplayToOutput() {
void GPU_GLES::CopyDisplayToOutput(bool reallyDirty) {
// Flush anything left over.
framebufferManagerGL_->RebindFramebuffer();
drawEngine_.Flush();
shaderManagerGL_->DirtyLastShader();
framebufferManagerGL_->CopyDisplayToOutput();
framebufferManagerGL_->CopyDisplayToOutput(reallyDirty);
framebufferManagerGL_->EndFrame();
// If buffered, discard the depth buffer of the backbuffer. Don't even know if we need one.

View file

@ -76,7 +76,7 @@ private:
void InitClear() override;
void BeginFrame() override;
void CopyDisplayToOutput() override;
void CopyDisplayToOutput(bool reallyDirty) override;
void Reinitialize() override;
FramebufferManagerGLES *framebufferManagerGL_;

View file

@ -111,7 +111,7 @@ public:
u32 Break(int mode) override;
void ReapplyGfxState() override;
void CopyDisplayToOutput() override = 0;
void CopyDisplayToOutput(bool reallyDirty) override = 0;
void InitClear() override = 0;
bool PerformMemoryCopy(u32 dest, u32 src, int size) override;
bool PerformMemorySet(u32 dest, u8 v, int size) override;

View file

@ -200,7 +200,7 @@ public:
// Framebuffer management
virtual void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) = 0;
virtual void BeginFrame() = 0; // Can be a good place to draw the "memory" framebuffer for accelerated plugins
virtual void CopyDisplayToOutput() = 0;
virtual void CopyDisplayToOutput(bool reallyDirty) = 0;
// Tells the GPU to update the gpuStats structure.
virtual void GetStats(char *buffer, size_t bufsize) = 0;

View file

@ -32,7 +32,7 @@ public:
void ExecuteOp(u32 op, u32 diff) override;
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override {}
void CopyDisplayToOutput() override {}
void CopyDisplayToOutput(bool reallyDirty) override {}
void GetStats(char *buffer, size_t bufsize) override;
void InvalidateCache(u32 addr, int size, GPUInvalidationType type) override;
void NotifyVideoUpload(u32 addr, int size, int width, int format) override;

View file

@ -353,7 +353,7 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
draw_->BindIndexBuffer(nullptr, 0);
}
void SoftGPU::CopyDisplayToOutput() {
void SoftGPU::CopyDisplayToOutput(bool reallyDirty) {
// The display always shows 480x272.
CopyToCurrentFboFromDisplayRam(FB_WIDTH, FB_HEIGHT);
framebufferDirty_ = false;

View file

@ -62,7 +62,7 @@ public:
void ExecuteOp(u32 op, u32 diff) override;
void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) override;
void CopyDisplayToOutput() override;
void CopyDisplayToOutput(bool reallyDirty) override;
void GetStats(char *buffer, size_t bufsize) override;
void InvalidateCache(u32 addr, int size, GPUInvalidationType type) override;
void NotifyVideoUpload(u32 addr, int size, int width, int format) override;

View file

@ -431,13 +431,13 @@ void GPU_Vulkan::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat
framebufferManager_->SetDisplayFramebuffer(framebuf, stride, format);
}
void GPU_Vulkan::CopyDisplayToOutput() {
void GPU_Vulkan::CopyDisplayToOutput(bool reallyDirty) {
// Flush anything left over.
drawEngine_.Flush();
shaderManagerVulkan_->DirtyLastShader();
framebufferManagerVulkan_->CopyDisplayToOutput();
framebufferManagerVulkan_->CopyDisplayToOutput(reallyDirty);
gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);
}

View file

@ -78,7 +78,7 @@ private:
void CheckFlushOp(int cmd, u32 diff);
void BuildReportingInfo();
void InitClear() override;
void CopyDisplayToOutput() override;
void CopyDisplayToOutput(bool reallyDirty) override;
void Reinitialize() override;
void InitDeviceObjects();

View file

@ -1315,7 +1315,7 @@ void EmuScreen::render() {
thin3d->BindFramebufferAsRenderTarget(nullptr, { RPAction::CLEAR, RPAction::DONT_CARE, RPAction::DONT_CARE });
// Just to make sure.
if (PSP_IsInited()) {
gpu->CopyDisplayToOutput();
gpu->CopyDisplayToOutput(true);
}
} else {
// Didn't actually reach the end of the frame, ran out of the blockTicks cycles.