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:
parent
5597752a5b
commit
cebcfb1bbd
17 changed files with 31 additions and 26 deletions
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -71,7 +71,7 @@ private:
|
|||
|
||||
void InitClear() override;
|
||||
void BeginFrame() override;
|
||||
void CopyDisplayToOutput() override;
|
||||
void CopyDisplayToOutput(bool reallyDirty) override;
|
||||
|
||||
ID3D11Device *device_;
|
||||
ID3D11DeviceContext *context_;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -70,7 +70,7 @@ private:
|
|||
|
||||
void InitClear() override;
|
||||
void BeginFrame() override;
|
||||
void CopyDisplayToOutput() override;
|
||||
void CopyDisplayToOutput(bool reallyDirty) override;
|
||||
|
||||
LPDIRECT3DDEVICE9 device_;
|
||||
LPDIRECT3DDEVICE9EX deviceEx_;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -76,7 +76,7 @@ private:
|
|||
|
||||
void InitClear() override;
|
||||
void BeginFrame() override;
|
||||
void CopyDisplayToOutput() override;
|
||||
void CopyDisplayToOutput(bool reallyDirty) override;
|
||||
void Reinitialize() override;
|
||||
|
||||
FramebufferManagerGLES *framebufferManagerGL_;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue