Skip to content

Commit

Permalink
Merge pull request #13634 from hrydgard/device-lost-improvements
Browse files Browse the repository at this point in the history
Device lost improvements, unify BindFramebufferAsColorTexture
  • Loading branch information
hrydgard committed Nov 7, 2020
2 parents 106fc70 + c23ed09 commit 614540a
Show file tree
Hide file tree
Showing 18 changed files with 112 additions and 196 deletions.
2 changes: 2 additions & 0 deletions Common/GPU/Vulkan/thin3d_vulkan.cpp
Expand Up @@ -465,6 +465,8 @@ class VKContext : public DrawContext {

uint64_t GetNativeObject(NativeObject obj) override {
switch (obj) {
case NativeObject::CONTEXT:
return (uint64_t)vulkan_;
case NativeObject::FRAMEBUFFER_RENDERPASS:
// Return a representative renderpass.
return (uint64_t)renderManager_.GetFramebufferRenderPass();
Expand Down
55 changes: 55 additions & 0 deletions GPU/Common/FramebufferManagerCommon.cpp
Expand Up @@ -36,6 +36,7 @@
#include "GPU/Common/PresentationCommon.h"
#include "GPU/Common/TextureCacheCommon.h"
#include "GPU/Debugger/Record.h"
#include "GPU/Debugger/Stepping.h"
#include "GPU/GPUInterface.h"
#include "GPU/GPUState.h"

Expand Down Expand Up @@ -702,6 +703,49 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int
}
}

bool FramebufferManagerCommon::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) {
if (!framebuffer->fbo || !useBufferedRendering_) {
draw_->BindTexture(0, nullptr);
gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE;
return false;
}

// currentRenderVfb_ will always be set when this is called, except from the GE debugger.
// Let's just not bother with the copy in that case.
bool skipCopy = (flags & BINDFBCOLOR_MAY_COPY) == 0;
if (GPUStepping::IsStepping()) {
skipCopy = true;
}
// Currently rendering to this framebuffer. Need to make a copy.
if (!skipCopy && framebuffer == currentRenderVfb_) {
// TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size.
Draw::Framebuffer *renderCopy = GetTempFBO(TempFBO::COPY, framebuffer->renderWidth, framebuffer->renderHeight);
if (renderCopy) {
VirtualFramebuffer copyInfo = *framebuffer;
copyInfo.fbo = renderCopy;
CopyFramebufferForColorTexture(&copyInfo, framebuffer, flags);
RebindFramebuffer("After BindFramebufferAsColorTexture");
draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, 0);
} else {
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0);
}
return true;
} else if (framebuffer != currentRenderVfb_ || (flags & BINDFBCOLOR_FORCE_SELF) != 0) {
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0);
return true;
} else {
ERROR_LOG_REPORT_ONCE(vulkanSelfTexture, G3D, "Attempting to texture from target (src=%08x / target=%08x / flags=%d)", framebuffer->fb_address, currentRenderVfb_->fb_address, flags);
// To do this safely in Vulkan, we need to use input attachments.
// Actually if the texture region and render regions don't overlap, this is safe, but we need
// to transition to GENERAL image layout which will take some trickery.
// Badness on D3D11 to bind the currently rendered-to framebuffer as a texture.
draw_->BindTexture(0, nullptr);
gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE;
return false;
}

}

void FramebufferManagerCommon::CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags) {
int x = 0;
int y = 0;
Expand Down Expand Up @@ -2102,3 +2146,14 @@ std::vector<FramebufferInfo> FramebufferManagerCommon::GetFramebufferList() {

return list;
}

void FramebufferManagerCommon::DeviceLost() {
DestroyAllFBOs();
presentation_->DeviceLost();
draw_ = nullptr;
}

void FramebufferManagerCommon::DeviceRestore(Draw::DrawContext *draw) {
draw_ = draw;
presentation_->DeviceRestore(draw);
}
9 changes: 4 additions & 5 deletions GPU/Common/FramebufferManagerCommon.h
Expand Up @@ -233,6 +233,7 @@ class FramebufferManagerCommon {
bool NotifyBlockTransferBefore(u32 dstBasePtr, int dstStride, int dstX, int dstY, u32 srcBasePtr, int srcStride, int srcX, int srcY, int w, int h, int bpp, u32 skipDrawReason);
void NotifyBlockTransferAfter(u32 dstBasePtr, int dstStride, int dstX, int dstY, u32 srcBasePtr, int srcStride, int srcX, int srcY, int w, int h, int bpp, u32 skipDrawReason);

bool BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
void ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h);

void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes);
Expand Down Expand Up @@ -305,6 +306,9 @@ class FramebufferManagerCommon {
virtual void Resized();
virtual void DestroyAllFBOs();

virtual void DeviceLost();
virtual void DeviceRestore(Draw::DrawContext *draw);

Draw::Framebuffer *GetTempFBO(TempFBO reason, u16 w, u16 h);

// Debug features
Expand Down Expand Up @@ -424,9 +428,4 @@ class FramebufferManagerCommon {
FBO_OLD_AGE = 5,
FBO_OLD_USAGE_FLAG = 15,
};

// Thin3D stuff for reinterpreting image data between the various 16-bit formats.
// Safe, not optimal - there might be input attachment tricks, etc, but we can't use them
// since we don't want N different implementations.
Draw::Pipeline *reinterpretFromTo_[3][3];
};
43 changes: 0 additions & 43 deletions GPU/D3D11/FramebufferManagerD3D11.cpp
Expand Up @@ -314,45 +314,6 @@ static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) {
}
}

void FramebufferManagerD3D11::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) {
if (!framebuffer->fbo || !useBufferedRendering_) {
ID3D11ShaderResourceView *view = nullptr;
context_->PSSetShaderResources(stage, 1, &view);
gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE;
return;
}

// currentRenderVfb_ will always be set when this is called, except from the GE debugger.
// Let's just not bother with the copy in that case.
bool skipCopy = (flags & BINDFBCOLOR_MAY_COPY) == 0;
if (GPUStepping::IsStepping()) {
skipCopy = true;
}
// Currently rendering to this framebuffer. Need to make a copy.
if (!skipCopy && framebuffer == currentRenderVfb_) {
// TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size.
Draw::Framebuffer *renderCopy = GetTempFBO(TempFBO::COPY, framebuffer->renderWidth, framebuffer->renderHeight);
if (renderCopy) {
VirtualFramebuffer copyInfo = *framebuffer;
copyInfo.fbo = renderCopy;
CopyFramebufferForColorTexture(&copyInfo, framebuffer, flags);
RebindFramebuffer("RebindFramebuffer - BindFramebufferAsColorTexture");
draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, 0);
} else {
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0);
}
} else if (framebuffer != currentRenderVfb_ || (flags & BINDFBCOLOR_FORCE_SELF) != 0) {
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0);
} else {
ERROR_LOG_REPORT_ONCE(d3d11SelfTexture, G3D, "Attempting to texture from target (src=%08x / target=%08x / flags=%d)", framebuffer->fb_address, currentRenderVfb_->fb_address, flags);
// Badness on D3D11 to bind the currently rendered-to framebuffer as a texture.
ID3D11ShaderResourceView *view = nullptr;
context_->PSSetShaderResources(stage, 1, &view);
gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE;
return;
}
}

void FramebufferManagerD3D11::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
// Nothing to do here.
}
Expand Down Expand Up @@ -468,7 +429,3 @@ void FramebufferManagerD3D11::PackDepthbuffer(VirtualFramebuffer *vfb, int x, in

void FramebufferManagerD3D11::EndFrame() {
}

void FramebufferManagerD3D11::DeviceLost() {
DestroyAllFBOs();
}
3 changes: 0 additions & 3 deletions GPU/D3D11/FramebufferManagerD3D11.h
Expand Up @@ -42,11 +42,8 @@ class FramebufferManagerD3D11 : public FramebufferManagerCommon {
void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags) override;

void EndFrame();
void DeviceLost();
void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override;

void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);

virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;

// TODO: Remove
Expand Down
4 changes: 3 additions & 1 deletion GPU/D3D11/GPU_D3D11.cpp
Expand Up @@ -198,10 +198,12 @@ void GPU_D3D11::DeviceLost() {
shaderManagerD3D11_->ClearShaders();
drawEngine_.ClearInputLayoutMap();
textureCacheD3D11_->Clear(false);
framebufferManagerD3D11_->DeviceLost();

GPUCommon::DeviceLost();
}

void GPU_D3D11::DeviceRestore() {
GPUCommon::DeviceRestore();
// Nothing needed.
}

Expand Down
39 changes: 0 additions & 39 deletions GPU/Directx9/FramebufferManagerDX9.cpp
Expand Up @@ -336,41 +336,6 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
return offscreen;
}

void FramebufferManagerDX9::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) {
if (framebuffer == NULL) {
framebuffer = currentRenderVfb_;
}

if (!framebuffer->fbo || !useBufferedRendering_) {
device_->SetTexture(stage, nullptr);
gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE;
return;
}

// currentRenderVfb_ will always be set when this is called, except from the GE debugger.
// Let's just not bother with the copy in that case.
bool skipCopy = (flags & BINDFBCOLOR_MAY_COPY) == 0;
if (GPUStepping::IsStepping()) {
skipCopy = true;
}
if (!skipCopy && framebuffer == currentRenderVfb_) {
// TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size.
Draw::Framebuffer *renderCopy = GetTempFBO(TempFBO::COPY, framebuffer->renderWidth, framebuffer->renderHeight);
if (renderCopy) {
VirtualFramebuffer copyInfo = *framebuffer;
copyInfo.fbo = renderCopy;

CopyFramebufferForColorTexture(&copyInfo, framebuffer, flags);
RebindFramebuffer("RebindFramebuffer - BindFramebufferAsColorTexture");
draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, 0);
} else {
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0);
}
} else {
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0);
}
}

void FramebufferManagerDX9::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
// Nothing to do here.
}
Expand Down Expand Up @@ -559,10 +524,6 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
void FramebufferManagerDX9::EndFrame() {
}

void FramebufferManagerDX9::DeviceLost() {
DestroyAllFBOs();
}

void FramebufferManagerDX9::DecimateFBOs() {
FramebufferManagerCommon::DecimateFBOs();
for (auto it = offscreenSurfaces_.begin(); it != offscreenSurfaces_.end(); ) {
Expand Down
3 changes: 0 additions & 3 deletions GPU/Directx9/FramebufferManagerDX9.h
Expand Up @@ -47,11 +47,8 @@ class FramebufferManagerDX9 : public FramebufferManagerCommon {
void DestroyAllFBOs();

void EndFrame();
void DeviceLost();
void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override;

void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);

virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;

bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes);
Expand Down
4 changes: 2 additions & 2 deletions GPU/Directx9/GPU_DX9.cpp
Expand Up @@ -242,13 +242,13 @@ void GPU_DX9::BuildReportingInfo() {

void GPU_DX9::DeviceLost() {
// Simply drop all caches and textures.
// FBOs appear to survive? Or no?
shaderManagerDX9_->ClearCache(false);
textureCacheDX9_->Clear(false);
framebufferManagerDX9_->DeviceLost();
GPUCommon::DeviceLost();
}

void GPU_DX9::DeviceRestore() {
GPUCommon::DeviceRestore();
// Nothing needed.
}

Expand Down
38 changes: 3 additions & 35 deletions GPU/GLES/FramebufferManagerGLES.cpp
Expand Up @@ -263,36 +263,6 @@ void FramebufferManagerGLES::ReformatFramebufferFrom(VirtualFramebuffer *vfb, GE
}
}

void FramebufferManagerGLES::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) {
if (!framebuffer->fbo || !useBufferedRendering_) {
render_->BindTexture(stage, nullptr);
gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE;
return;
}

// currentRenderVfb_ will always be set when this is called, except from the GE debugger.
// Let's just not bother with the copy in that case.
bool skipCopy = (flags & BINDFBCOLOR_MAY_COPY) == 0;
if (GPUStepping::IsStepping()) {
skipCopy = true;
}
if (!skipCopy && framebuffer == currentRenderVfb_) {
// TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size.
Draw::Framebuffer *renderCopy = GetTempFBO(TempFBO::COPY, framebuffer->renderWidth, framebuffer->renderHeight);
if (renderCopy) {
VirtualFramebuffer copyInfo = *framebuffer;
copyInfo.fbo = renderCopy;

CopyFramebufferForColorTexture(&copyInfo, framebuffer, flags);
draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, 0);
} else {
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0);
}
} else {
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0);
}
}

void FramebufferManagerGLES::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
_assert_msg_(nvfb->fbo, "Expecting a valid nvfb in UpdateDownloadTempBuffer");

Expand Down Expand Up @@ -389,16 +359,14 @@ void FramebufferManagerGLES::EndFrame() {
}

void FramebufferManagerGLES::DeviceLost() {
DestroyAllFBOs();
FramebufferManagerCommon::DeviceLost();
DestroyDeviceObjects();
presentation_->DeviceLost();
}

void FramebufferManagerGLES::DeviceRestore(Draw::DrawContext *draw) {
draw_ = draw;
presentation_->DeviceRestore(draw);
render_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
FramebufferManagerCommon::DeviceRestore(draw);
CreateDeviceObjects();
render_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);
}

void FramebufferManagerGLES::Resized() {
Expand Down
10 changes: 4 additions & 6 deletions GPU/GLES/FramebufferManagerGLES.h
Expand Up @@ -46,18 +46,16 @@ class FramebufferManagerGLES : public FramebufferManagerCommon {
virtual void Init() override;
void EndFrame();
void Resized() override;
void DeviceLost();
void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override;

// For use when texturing from a framebuffer. May create a duplicate if target.
void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags);
void DeviceLost() override;
void DeviceRestore(Draw::DrawContext *draw) override;

void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override;

bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override;

bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override;

void DeviceRestore(Draw::DrawContext *draw);

protected:
// Used by ReadFramebufferToMemory and later framebuffer block copies
void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) override;
Expand Down
9 changes: 3 additions & 6 deletions GPU/GLES/GPU_GLES.cpp
Expand Up @@ -300,21 +300,18 @@ void GPU_GLES::DeviceLost() {
fragmentTestCache_.DeviceLost();
depalShaderCache_.DeviceLost();
drawEngine_.DeviceLost();
framebufferManagerGL_->DeviceLost();
// Don't even try to access the lost device.
draw_ = nullptr;

GPUCommon::DeviceLost();
}

void GPU_GLES::DeviceRestore() {
draw_ = (Draw::DrawContext *)PSP_CoreParameter().graphicsContext->GetDrawContext();
INFO_LOG(G3D, "GPU_GLES: DeviceRestore");
GPUCommon::DeviceRestore();

UpdateCmdInfo();
UpdateVsyncInterval(true);

shaderManagerGL_->DeviceRestore(draw_);
textureCacheGL_->DeviceRestore(draw_);
framebufferManagerGL_->DeviceRestore(draw_);
drawEngine_.DeviceRestore(draw_);
fragmentTestCache_.DeviceRestore(draw_);
depalShaderCache_.DeviceRestore(draw_);
Expand Down
12 changes: 12 additions & 0 deletions GPU/GPUCommon.cpp
Expand Up @@ -468,6 +468,18 @@ void GPUCommon::Reinitialize() {
framebufferManager_->DestroyAllFBOs();
}

// Call at the END of the GPU implementation's DeviceLost
void GPUCommon::DeviceLost() {
framebufferManager_->DeviceLost();
draw_ = nullptr;
}

// Call at the start of the GPU implementation's DeviceRestore
void GPUCommon::DeviceRestore() {
draw_ = (Draw::DrawContext *)PSP_CoreParameter().graphicsContext->GetDrawContext();
framebufferManager_->DeviceRestore(draw_);
}

void GPUCommon::UpdateVsyncInterval(bool force) {
#if !(PPSSPP_PLATFORM(ANDROID) || defined(USING_QT_UI) || PPSSPP_PLATFORM(UWP) || PPSSPP_PLATFORM(IOS))
int desiredVSyncInterval = g_Config.bVSync ? 1 : 0;
Expand Down

0 comments on commit 614540a

Please sign in to comment.