Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save FBOs on decimate when a safe size is known #8757

Merged
merged 4 commits into from
May 20, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions Core/MemMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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()
{
Expand Down
2 changes: 2 additions & 0 deletions Core/MemMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
28 changes: 19 additions & 9 deletions GPU/Common/FramebufferCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
3 changes: 3 additions & 0 deletions GPU/Common/FramebufferCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -224,6 +226,7 @@ class FramebufferManagerCommon {
}
}
void SetRenderSize(VirtualFramebuffer *vfb);
void SetSafeSize(u16 w, u16 h);

protected:
void UpdateSize();
Expand Down
21 changes: 12 additions & 9 deletions GPU/Common/SoftwareTransformCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,37 +92,34 @@ 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;

// Color and Z are decided by the second vertex, so only need to check those for matching color.
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)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove "i & 1"? It's there because only the color of the 2nd of every pair of vertices used to draw rectangles matter in clear-mode.

Copy link
Collaborator Author

@unknownbrackets unknownbrackets May 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if ((i & 1) == 0) {
    /// stuff
} else {
    if ((i & 1) != 0) {
        // other stuff
    }
}

It's not needed, we're already in the else condition for that check. To me it just makes the code more confusing because it's in the else and makes me have to do a double-take on the code to make sure it's an always-true condition.

-[Unknown]

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, I missed that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW i > 0 is also always true since the loop starts at 1, but that one isn't confusing.

-[Unknown]

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;
}
}

// 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;
Expand Down Expand Up @@ -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();
Expand Down
4 changes: 4 additions & 0 deletions GPU/Directx9/DrawEngineDX9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,10 @@ void DrawEngineDX9::DoFlush() {

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);
}
}

Expand Down
15 changes: 12 additions & 3 deletions GPU/Directx9/FramebufferDX9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -1173,7 +1173,7 @@ namespace DX9 {
}

void FramebufferManagerDX9::DeviceLost() {
DestroyAllFBOs();
DestroyAllFBOs(false);
resized_ = false;
}

Expand Down Expand Up @@ -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--);
}
Expand Down Expand Up @@ -1256,7 +1259,7 @@ namespace DX9 {
}
}

void FramebufferManagerDX9::DestroyAllFBOs() {
void FramebufferManagerDX9::DestroyAllFBOs(bool forceDelete) {
fbo_unbind();
currentRenderVfb_ = 0;
displayFramebuf_ = 0;
Expand All @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion GPU/Directx9/FramebufferDX9.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class FramebufferManagerDX9 : public FramebufferManagerCommon {

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();
Expand Down
4 changes: 2 additions & 2 deletions GPU/Directx9/GPU_DX9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ void GPU_DX9::CheckGPUFeatures() {
}

GPU_DX9::~GPU_DX9() {
framebufferManager_.DestroyAllFBOs();
framebufferManager_.DestroyAllFBOs(true);
shaderManager_->ClearCache(true);
delete shaderManager_;
}
Expand Down Expand Up @@ -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);
}
}
Expand Down
4 changes: 4 additions & 0 deletions GPU/GLES/DrawEngineGLES.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -981,6 +981,10 @@ void DrawEngineGLES::DoFlush() {
glClearStencil(clearColor >> 24);
glClear(target);
framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);

int scissorX2 = gstate.getScissorX2() + 1;
int scissorY2 = gstate.getScissorY2() + 1;
framebufferManager_->SetSafeSize(scissorX2, scissorY2);
}
}

Expand Down
15 changes: 12 additions & 3 deletions GPU/GLES/Framebuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -1854,7 +1854,7 @@ void FramebufferManager::EndFrame() {
}

void FramebufferManager::DeviceLost() {
DestroyAllFBOs();
DestroyAllFBOs(false);
DestroyDraw2DProgram();
resized_ = false;
}
Expand Down Expand Up @@ -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--);
}
Expand Down Expand Up @@ -1925,7 +1928,7 @@ void FramebufferManager::DecimateFBOs() {
}
}

void FramebufferManager::DestroyAllFBOs() {
void FramebufferManager::DestroyAllFBOs(bool forceDelete) {
fbo_unbind();
currentRenderVfb_ = 0;
displayFramebuf_ = 0;
Expand All @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion GPU/GLES/Framebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class FramebufferManager : public FramebufferManagerCommon {
// 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();
Expand Down
6 changes: 3 additions & 3 deletions GPU/GLES/GPU_GLES.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -660,7 +660,7 @@ void GPU_GLES::Reinitialize() {
void GPU_GLES::ReinitializeInternal() {
textureCache_.Clear(true);
depalShaderCache_.Clear();
framebufferManager_.DestroyAllFBOs();
framebufferManager_.DestroyAllFBOs(true);
framebufferManager_.Resized();
}

Expand Down Expand Up @@ -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);
}
}
Expand Down
4 changes: 4 additions & 0 deletions GPU/Vulkan/DrawEngineVulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
Loading