Merge pull request #8757 from unknownbrackets/gpu-save-decimate

Save FBOs on decimate when a safe size is known
This commit is contained in:
Henrik Rydgård 2016-05-20 08:41:54 +02:00
commit a0ce8025d6
17 changed files with 102 additions and 44 deletions

View File

@ -383,18 +383,15 @@ void DoState(PointerWrap &p)
p.DoMarker("ScratchPad");
}
void Shutdown()
{
void Shutdown() {
lock_guard guard(g_shutdownLock);
u32 flags = 0;
MemoryMap_Shutdown(flags);
base = NULL;
base = nullptr;
DEBUG_LOG(MEMMAP, "Memory system shut down.");
}
void Clear()
{
void Clear() {
if (m_pRAM)
memset(GetPointerUnchecked(PSP_GetKernelMemoryBase()), 0, g_MemorySize);
if (m_pScratchPad)
@ -403,6 +400,10 @@ void Clear()
memset(m_pVRAM, 0, VRAM_SIZE);
}
bool IsActive() {
return base != nullptr;
}
// Wanting to avoid include pollution, MemMap.h is included a lot.
MemoryInitedLock::MemoryInitedLock()
{

View File

@ -130,6 +130,8 @@ void Init();
void Shutdown();
void DoState(PointerWrap &p);
void Clear();
// False when shutdown has already been called.
bool IsActive();
class MemoryInitedLock
{

View File

@ -355,6 +355,9 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
needsRecreate = needsRecreate || vfb->newHeight > vfb->bufferHeight || vfb->newHeight * 2 < vfb->bufferHeight;
if (needsRecreate) {
ResizeFramebufFBO(vfb, vfb->width, vfb->height, true);
// Let's discard this information, might be wrong now.
vfb->safeWidth = 0;
vfb->safeHeight = 0;
} else {
// Even though we won't resize it, let's at least change the size params.
vfb->width = drawing_width;
@ -378,7 +381,8 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
// None found? Create one.
if (!vfb) {
vfb = new VirtualFramebuffer();
vfb->fbo = 0;
memset(vfb, 0, sizeof(VirtualFramebuffer));
vfb->fbo = nullptr;
vfb->fb_address = params.fb_address;
vfb->fb_stride = params.fb_stride;
vfb->z_address = params.z_address;
@ -393,8 +397,6 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
vfb->bufferWidth = drawing_width;
vfb->bufferHeight = drawing_height;
vfb->format = params.fmt;
vfb->drawnWidth = 0;
vfb->drawnHeight = 0;
vfb->drawnFormat = params.fmt;
vfb->usageFlags = FB_USAGE_RENDERTARGET;
SetColorUpdated(vfb, skipDrawReason);
@ -412,10 +414,6 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
INFO_LOG(SCEGE, "Creating FBO for %08x : %i x %i x %i", vfb->fb_address, vfb->width, vfb->height, vfb->format);
vfb->last_frame_render = gpuStats.numFlips;
vfb->last_frame_used = 0;
vfb->last_frame_attached = 0;
vfb->last_frame_displayed = 0;
vfb->last_frame_clut = 0;
frameLastFramebufUsed_ = gpuStats.numFlips;
vfbs_.push_back(vfb);
currentRenderVfb_ = vfb;
@ -771,6 +769,7 @@ VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFram
// Create a new fbo if none was found for the size
if (!nvfb) {
nvfb = new VirtualFramebuffer();
memset(nvfb, 0, sizeof(VirtualFramebuffer));
nvfb->fbo = nullptr;
nvfb->fb_address = vfb->fb_address;
nvfb->fb_stride = vfb->fb_stride;
@ -964,16 +963,27 @@ void FramebufferManagerCommon::SetRenderSize(VirtualFramebuffer *vfb) {
break;
}
if (hackForce04154000Download_ && vfb->fb_address == 0x00154000) {
force1x = true;
}
if (force1x && g_Config.iInternalResolution != 1) {
vfb->renderWidth = vfb->bufferWidth;
vfb->renderHeight = vfb->bufferHeight;
}
else {
} else {
vfb->renderWidth = (u16)(vfb->bufferWidth * renderWidthFactor);
vfb->renderHeight = (u16)(vfb->bufferHeight * renderHeightFactor);
}
}
void FramebufferManagerCommon::SetSafeSize(u16 w, u16 h) {
VirtualFramebuffer *vfb = currentRenderVfb_;
if (vfb) {
vfb->safeWidth = std::max(vfb->safeWidth, w);
vfb->safeHeight = std::max(vfb->safeHeight, h);
}
}
void FramebufferManagerCommon::UpdateFramebufUsage(VirtualFramebuffer *vfb) {
auto checkFlag = [&](u16 flag, int last_frame) {
if (vfb->usageFlags & flag) {

View File

@ -99,6 +99,8 @@ struct VirtualFramebuffer {
u16 drawnWidth;
u16 drawnHeight;
GEBufferFormat drawnFormat;
u16 safeWidth;
u16 safeHeight;
bool dirtyAfterDisplay;
bool reallyDirtyAfterDisplay; // takes frame skipping into account
@ -224,6 +226,7 @@ public:
}
}
void SetRenderSize(VirtualFramebuffer *vfb);
void SetSafeSize(u16 w, u16 h);
protected:
void UpdateSize();

View File

@ -92,7 +92,7 @@ static void RotateUVThrough(TransformedVertex v[4]) {
// Clears on the PSP are best done by drawing a series of vertical strips
// in clear mode. This tries to detect that.
static bool IsReallyAClear(const TransformedVertex *transformed, int numVerts) {
static bool IsReallyAClear(const TransformedVertex *transformed, int numVerts, float x2, float y2) {
if (transformed[0].x != 0.0f || transformed[0].y != 0.0f)
return false;
@ -100,21 +100,18 @@ static bool IsReallyAClear(const TransformedVertex *transformed, int numVerts) {
u32 matchcolor = transformed[1].color0_32;
float matchz = transformed[1].z;
int bufW = gstate_c.curRTWidth;
int bufH = gstate_c.curRTHeight;
for (int i = 1; i < numVerts; i++) {
if ((i & 1) == 0) {
// Top left of a rectangle
if (transformed[i].y != 0)
if (transformed[i].y != 0.0f)
return false;
if (i > 0 && transformed[i].x != transformed[i - 1].x)
return false;
} else {
if ((i & 1) && (transformed[i].color0_32 != matchcolor || transformed[i].z != matchz))
if (transformed[i].color0_32 != matchcolor || transformed[i].z != matchz)
return false;
// Bottom right
if (transformed[i].y != bufH)
if (transformed[i].y < y2)
return false;
if (transformed[i].x <= transformed[i - 1].x)
return false;
@ -122,7 +119,7 @@ static bool IsReallyAClear(const TransformedVertex *transformed, int numVerts) {
}
// The last vertical strip often extends outside the drawing area.
if (transformed[numVerts - 1].x < bufW)
if (transformed[numVerts - 1].x < x2)
return false;
return true;
@ -411,7 +408,13 @@ void SoftwareTransform(
// rectangle out of many. Quite a small optimization though.
// Experiment: Disable on PowerVR (see issue #6290)
// TODO: This bleeds outside the play area in non-buffered mode. Big deal? Probably not.
if (maxIndex > 1 && gstate.isModeClear() && prim == GE_PRIM_RECTANGLES && IsReallyAClear(transformed, maxIndex) && gl_extensions.gpuVendor != GPU_VENDOR_POWERVR) { // && g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) {
bool reallyAClear = false;
if (maxIndex > 1 && prim == GE_PRIM_RECTANGLES && gstate.isModeClear()) {
int scissorX2 = gstate.getScissorX2() + 1;
int scissorY2 = gstate.getScissorY2() + 1;
reallyAClear = IsReallyAClear(transformed, maxIndex, scissorX2, scissorY2);
}
if (reallyAClear && gl_extensions.gpuVendor != GPU_VENDOR_POWERVR) { // && g_Config.iRenderingMode != FB_NON_BUFFERED_MODE) {
// If alpha is not allowed to be separate, it must match for both depth/stencil and color. Vulkan requires this.
bool alphaMatchesColor = gstate.isClearModeColorMask() == gstate.isClearModeAlphaMask();
bool depthMatchesStencil = gstate.isClearModeAlphaMask() == gstate.isClearModeDepthMask();

View File

@ -885,6 +885,10 @@ rotateVBO:
dxstate.colorMask.set((mask & D3DCLEAR_TARGET) != 0, (mask & D3DCLEAR_TARGET) != 0, (mask & D3DCLEAR_TARGET) != 0, (mask & D3DCLEAR_STENCIL) != 0);
pD3Ddevice->Clear(0, NULL, mask, clearColor, clearDepth, clearColor >> 24);
int scissorX2 = gstate.getScissorX2() + 1;
int scissorY2 = gstate.getScissorY2() + 1;
framebufferManager_->SetSafeSize(scissorX2, scissorY2);
}
}

View File

@ -1140,7 +1140,7 @@ namespace DX9 {
void FramebufferManagerDX9::EndFrame() {
if (resized_) {
DestroyAllFBOs();
DestroyAllFBOs(false);
// Actually, auto mode should be more granular...
// Round up to a zoom factor for the render size.
int zoom = g_Config.iInternalResolution;
@ -1173,7 +1173,7 @@ namespace DX9 {
}
void FramebufferManagerDX9::DeviceLost() {
DestroyAllFBOs();
DestroyAllFBOs(false);
resized_ = false;
}
@ -1218,6 +1218,9 @@ namespace DX9 {
if (vfb != displayFramebuf_ && vfb != prevDisplayFramebuf_ && vfb != prevPrevDisplayFramebuf_) {
if (age > FBO_OLD_AGE) {
INFO_LOG(SCEGE, "Decimating FBO for %08x (%i x %i x %i), age %i", vfb->fb_address, vfb->width, vfb->height, vfb->format, age);
if (!g_Config.bDisableSlowFramebufEffects && vfb->safeWidth > 0 && vfb->safeHeight > 0) {
ReadFramebufferToMemory(vfb, true, 0, 0, vfb->safeWidth, vfb->safeHeight);
}
DestroyFramebuf(vfb);
vfbs_.erase(vfbs_.begin() + i--);
}
@ -1256,7 +1259,7 @@ namespace DX9 {
}
}
void FramebufferManagerDX9::DestroyAllFBOs() {
void FramebufferManagerDX9::DestroyAllFBOs(bool forceDelete) {
fbo_unbind();
currentRenderVfb_ = 0;
displayFramebuf_ = 0;
@ -1266,6 +1269,12 @@ namespace DX9 {
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *vfb = vfbs_[i];
INFO_LOG(SCEGE, "Destroying FBO for %08x : %i x %i x %i", vfb->fb_address, vfb->width, vfb->height, vfb->format);
if (!forceDelete && !g_Config.bDisableSlowFramebufEffects && vfb->safeWidth > 0 && vfb->safeHeight > 0) {
// But also let's check if Memory is shut down already.
if (Memory::IsActive()) {
ReadFramebufferToMemory(vfb, true, 0, 0, vfb->safeWidth, vfb->safeHeight);
}
}
DestroyFramebuf(vfb);
}
vfbs_.clear();

View File

@ -60,7 +60,7 @@ public:
void DrawActiveTexture(LPDIRECT3DTEXTURE9 texture, float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation);
void DestroyAllFBOs();
void DestroyAllFBOs(bool forceDelete);
void EndFrame();
void Resized();

View File

@ -511,7 +511,7 @@ void GPU_DX9::CheckGPUFeatures() {
}
GPU_DX9::~GPU_DX9() {
framebufferManager_.DestroyAllFBOs();
framebufferManager_.DestroyAllFBOs(true);
shaderManager_->ClearCache(true);
delete shaderManager_;
}
@ -2137,7 +2137,7 @@ void GPU_DX9::DoState(PointerWrap &p) {
drawEngine_.ClearTrackedVertexArrays();
gstate_c.textureChanged = TEXCHANGE_UPDATED;
framebufferManager_.DestroyAllFBOs();
framebufferManager_.DestroyAllFBOs(true);
shaderManager_->ClearCache(true);
}
}

View File

@ -981,6 +981,10 @@ rotateVBO:
glClearStencil(clearColor >> 24);
glClear(target);
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);
int scissorX2 = gstate.getScissorX2() + 1;
int scissorY2 = gstate.getScissorY2() + 1;
framebufferManager_->SetSafeSize(scissorX2, scissorY2);
}
}

View File

@ -1784,7 +1784,7 @@ void FramebufferManager::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y,
void FramebufferManager::EndFrame() {
if (resized_) {
// TODO: Only do this if the new size actually changed the renderwidth/height.
DestroyAllFBOs();
DestroyAllFBOs(false);
// Probably not necessary
glstate.viewport.set(0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight);
@ -1854,7 +1854,7 @@ void FramebufferManager::EndFrame() {
}
void FramebufferManager::DeviceLost() {
DestroyAllFBOs();
DestroyAllFBOs(false);
DestroyDraw2DProgram();
resized_ = false;
}
@ -1897,6 +1897,9 @@ void FramebufferManager::DecimateFBOs() {
if (vfb != displayFramebuf_ && vfb != prevDisplayFramebuf_ && vfb != prevPrevDisplayFramebuf_) {
if (age > FBO_OLD_AGE) {
INFO_LOG(SCEGE, "Decimating FBO for %08x (%i x %i x %i), age %i", vfb->fb_address, vfb->width, vfb->height, vfb->format, age);
if (!g_Config.bDisableSlowFramebufEffects && vfb->safeWidth > 0 && vfb->safeHeight > 0) {
ReadFramebufferToMemory(vfb, true, 0, 0, vfb->safeWidth, vfb->safeHeight);
}
DestroyFramebuf(vfb);
vfbs_.erase(vfbs_.begin() + i--);
}
@ -1925,7 +1928,7 @@ void FramebufferManager::DecimateFBOs() {
}
}
void FramebufferManager::DestroyAllFBOs() {
void FramebufferManager::DestroyAllFBOs(bool forceDelete) {
fbo_unbind();
currentRenderVfb_ = 0;
displayFramebuf_ = 0;
@ -1935,6 +1938,12 @@ void FramebufferManager::DestroyAllFBOs() {
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *vfb = vfbs_[i];
INFO_LOG(SCEGE, "Destroying FBO for %08x : %i x %i x %i", vfb->fb_address, vfb->width, vfb->height, vfb->format);
if (!forceDelete && !g_Config.bDisableSlowFramebufEffects && vfb->safeWidth > 0 && vfb->safeHeight > 0) {
// But also let's check if Memory is shut down already.
if (Memory::IsActive()) {
ReadFramebufferToMemory(vfb, true, 0, 0, vfb->safeWidth, vfb->safeHeight);
}
}
DestroyFramebuf(vfb);
}
vfbs_.clear();

View File

@ -82,7 +82,7 @@ public:
// x,y,w,h are relative to destW, destH which fill out the target completely.
void DrawActiveTexture(GLuint texture, float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, GLSLProgram *program, int uvRotation);
void DestroyAllFBOs();
void DestroyAllFBOs(bool forceDelete);
virtual void Init() override;
void EndFrame();

View File

@ -469,7 +469,7 @@ GPU_GLES::GPU_GLES(GraphicsContext *ctx)
}
GPU_GLES::~GPU_GLES() {
framebufferManager_.DestroyAllFBOs();
framebufferManager_.DestroyAllFBOs(true);
shaderManager_->ClearCache(true);
depalShaderCache_.Clear();
fragmentTestCache_.Clear();
@ -660,7 +660,7 @@ void GPU_GLES::Reinitialize() {
void GPU_GLES::ReinitializeInternal() {
textureCache_.Clear(true);
depalShaderCache_.Clear();
framebufferManager_.DestroyAllFBOs();
framebufferManager_.DestroyAllFBOs(true);
framebufferManager_.Resized();
}
@ -2401,7 +2401,7 @@ void GPU_GLES::DoState(PointerWrap &p) {
drawEngine_.ClearTrackedVertexArrays();
gstate_c.textureChanged = TEXCHANGE_UPDATED;
framebufferManager_.DestroyAllFBOs();
framebufferManager_.DestroyAllFBOs(true);
shaderManager_->ClearCache(true);
}
}

View File

@ -826,6 +826,10 @@ void DrawEngineVulkan::DoFlush(VkCommandBuffer cmd) {
// We let the framebuffer manager handle the clear. It can use renderpasses to optimize on tilers.
framebufferManager_->NotifyClear(gstate.isClearModeColorMask(), gstate.isClearModeAlphaMask(), gstate.isClearModeDepthMask(), result.color, result.depth);
int scissorX2 = gstate.getScissorX2() + 1;
int scissorY2 = gstate.getScissorY2() + 1;
framebufferManager_->SetSafeSize(scissorX2, scissorY2);
}
}

View File

@ -1456,7 +1456,7 @@ void FramebufferManagerVulkan::BeginFrameVulkan() {
void FramebufferManagerVulkan::EndFrame() {
if (resized_) {
// TODO: Only do this if the new size actually changed the renderwidth/height.
DestroyAllFBOs();
DestroyAllFBOs(false);
// Check if postprocessing shader is doing upscaling as it requires native resolution
const ShaderInfo *shaderInfo = 0;
@ -1512,7 +1512,7 @@ void FramebufferManagerVulkan::EndFrame() {
}
void FramebufferManagerVulkan::DeviceLost() {
DestroyAllFBOs();
DestroyAllFBOs(false);
resized_ = false;
}
@ -1553,6 +1553,9 @@ void FramebufferManagerVulkan::DecimateFBOs() {
if (vfb != displayFramebuf_ && vfb != prevDisplayFramebuf_ && vfb != prevPrevDisplayFramebuf_) {
if (age > FBO_OLD_AGE) {
INFO_LOG(SCEGE, "Decimating FBO for %08x (%i x %i x %i), age %i", vfb->fb_address, vfb->width, vfb->height, vfb->format, age);
if (!g_Config.bDisableSlowFramebufEffects && vfb->safeWidth > 0 && vfb->safeHeight > 0) {
ReadFramebufferToMemory(vfb, true, 0, 0, vfb->safeWidth, vfb->safeHeight);
}
DestroyFramebuf(vfb);
vfbs_.erase(vfbs_.begin() + i--);
}
@ -1560,7 +1563,7 @@ void FramebufferManagerVulkan::DecimateFBOs() {
}
}
void FramebufferManagerVulkan::DestroyAllFBOs() {
void FramebufferManagerVulkan::DestroyAllFBOs(bool forceDelete) {
currentRenderVfb_ = 0;
displayFramebuf_ = 0;
prevDisplayFramebuf_ = 0;
@ -1569,6 +1572,12 @@ void FramebufferManagerVulkan::DestroyAllFBOs() {
for (size_t i = 0; i < vfbs_.size(); ++i) {
VirtualFramebuffer *vfb = vfbs_[i];
INFO_LOG(SCEGE, "Destroying FBO for %08x : %i x %i x %i", vfb->fb_address, vfb->width, vfb->height, vfb->format);
if (!forceDelete && !g_Config.bDisableSlowFramebufEffects && vfb->safeWidth > 0 && vfb->safeHeight > 0) {
// But also let's check if Memory is shut down already.
if (Memory::IsActive()) {
ReadFramebufferToMemory(vfb, true, 0, 0, vfb->safeWidth, vfb->safeHeight);
}
}
DestroyFramebuf(vfb);
}
vfbs_.clear();

View File

@ -95,7 +95,7 @@ public:
// x,y,w,h are relative to destW, destH which fill out the target completely.
void DrawTexture(VulkanTexture *texture, float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, VkPipeline pipeline, int uvRotation);
void DestroyAllFBOs();
void DestroyAllFBOs(bool forceDelete);
virtual void Init() override;

View File

@ -455,7 +455,7 @@ GPU_Vulkan::GPU_Vulkan(GraphicsContext *ctx)
}
GPU_Vulkan::~GPU_Vulkan() {
framebufferManager_->DestroyAllFBOs();
framebufferManager_->DestroyAllFBOs(true);
depalShaderCache_.Clear();
delete framebufferManager_;
delete pipelineManager_;
@ -614,7 +614,7 @@ void GPU_Vulkan::Reinitialize() {
void GPU_Vulkan::ReinitializeInternal() {
textureCache_.Clear(true);
depalShaderCache_.Clear();
framebufferManager_->DestroyAllFBOs();
framebufferManager_->DestroyAllFBOs(true);
framebufferManager_->Resized();
}
@ -2236,7 +2236,7 @@ void GPU_Vulkan::DoState(PointerWrap &p) {
depalShaderCache_.Clear();
gstate_c.textureChanged = TEXCHANGE_UPDATED;
framebufferManager_->DestroyAllFBOs();
framebufferManager_->DestroyAllFBOs(true);
shaderManager_->ClearShaders();
pipelineManager_->Clear();
}