From 8c229e00b4117eeece6a80c8700c9ceb39000bd4 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Tue, 9 Sep 2014 08:12:42 -0700 Subject: [PATCH] d3d: Begin centralizing framebuffer management. --- CMakeLists.txt | 2 + GPU/Common/FramebufferCommon.cpp | 117 ++++++++++++++++++++ GPU/Common/FramebufferCommon.h | 182 +++++++++++++++++++++++++++++++ GPU/Directx9/FramebufferDX9.cpp | 137 +++++++---------------- GPU/Directx9/FramebufferDX9.h | 96 +++------------- GPU/Directx9/GPU_DX9.cpp | 5 +- GPU/Directx9/TextureCacheDX9.cpp | 13 ++- GPU/Directx9/TextureCacheDX9.h | 19 ++-- GPU/Directx9/helper/fbo.cpp | 16 +-- GPU/Directx9/helper/fbo.h | 5 +- GPU/GLES/Framebuffer.cpp | 110 ++----------------- GPU/GLES/Framebuffer.h | 152 ++------------------------ GPU/GPU.vcxproj | 2 + GPU/GPU.vcxproj.filters | 6 + android/jni/Android.mk | 1 + 15 files changed, 412 insertions(+), 451 deletions(-) create mode 100644 GPU/Common/FramebufferCommon.cpp create mode 100644 GPU/Common/FramebufferCommon.h diff --git a/CMakeLists.txt b/CMakeLists.txt index d74aa541ed..5a08e3b2d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1304,6 +1304,8 @@ if(ARMV7) set(GPU_NEON GPU/Common/TextureDecoderNEON.cpp) endif() add_library(GPU OBJECT + GPU/Common/FramebufferCommon.cpp + GPU/Common/FramebufferCommon.h GPU/Common/GPUDebugInterface.h GPU/Common/VertexDecoderCommon.cpp GPU/Common/VertexDecoderCommon.h diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp new file mode 100644 index 0000000000..c2a8baee9b --- /dev/null +++ b/GPU/Common/FramebufferCommon.cpp @@ -0,0 +1,117 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include +#include "Common/Common.h" +#include "GPU/Common/FramebufferCommon.h" +#include "GPU/GPUState.h" + +FramebufferManagerCommon::FramebufferManagerCommon() : + displayFramebufPtr_(0), + displayStride_(0), + displayFormat_(GE_FORMAT_565), + displayFramebuf_(0), + prevDisplayFramebuf_(0), + prevPrevDisplayFramebuf_(0), + frameLastFramebufUsed_(0), + currentRenderVfb_(0), + framebufRangeEnd_(0) { +} + +FramebufferManagerCommon::~FramebufferManagerCommon() { +} + +void FramebufferManagerCommon::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) { + displayFramebufPtr_ = framebuf; + displayStride_ = stride; + displayFormat_ = format; +} + +// Heuristics to figure out the size of FBO to create. +void FramebufferManagerCommon::EstimateDrawingSize(int &drawing_width, int &drawing_height) { + static const int MAX_FRAMEBUF_HEIGHT = 512; + const int viewport_width = (int) gstate.getViewportX1(); + const int viewport_height = (int) gstate.getViewportY1(); + const int region_width = gstate.getRegionX2() + 1; + const int region_height = gstate.getRegionY2() + 1; + const int scissor_width = gstate.getScissorX2() + 1; + const int scissor_height = gstate.getScissorY2() + 1; + const int fb_stride = std::max(gstate.FrameBufStride(), 4); + + // Games don't always set any of these. Take the greatest parameter that looks valid based on stride. + if (viewport_width > 4 && viewport_width <= fb_stride) { + drawing_width = viewport_width; + drawing_height = viewport_height; + // Some games specify a viewport with 0.5, but don't have VRAM for 273. 480x272 is the buffer size. + if (viewport_width == 481 && region_width == 480 && viewport_height == 273 && region_height == 272) { + drawing_width = 480; + drawing_height = 272; + } + // Sometimes region is set larger than the VRAM for the framebuffer. + if (region_width <= fb_stride && region_width > drawing_width && region_height <= MAX_FRAMEBUF_HEIGHT) { + drawing_width = region_width; + drawing_height = std::max(drawing_height, region_height); + } + // Scissor is often set to a subsection of the framebuffer, so we pay the least attention to it. + if (scissor_width <= fb_stride && scissor_width > drawing_width && scissor_height <= MAX_FRAMEBUF_HEIGHT) { + drawing_width = scissor_width; + drawing_height = std::max(drawing_height, scissor_height); + } + } else { + // If viewport wasn't valid, let's just take the greatest anything regardless of stride. + drawing_width = std::min(std::max(region_width, scissor_width), fb_stride); + drawing_height = std::max(region_height, scissor_height); + } + + // Assume no buffer is > 512 tall, it couldn't be textured or displayed fully if so. + if (drawing_height >= MAX_FRAMEBUF_HEIGHT) { + if (region_height < MAX_FRAMEBUF_HEIGHT) { + drawing_height = region_height; + } else if (scissor_height < MAX_FRAMEBUF_HEIGHT) { + drawing_height = scissor_height; + } + } + + if (viewport_width != region_width) { + // The majority of the time, these are equal. If not, let's check what we know. + const u32 fb_address = gstate.getFrameBufAddress(); + u32 nearest_address = 0xFFFFFFFF; + for (size_t i = 0; i < vfbs_.size(); ++i) { + const u32 other_address = vfbs_[i]->fb_address | 0x44000000; + if (other_address > fb_address && other_address < nearest_address) { + nearest_address = other_address; + } + } + + // Unless the game is using overlapping buffers, the next buffer should be far enough away. + // This catches some cases where we can know this. + // Hmm. The problem is that we could only catch it for the first of two buffers... + const u32 bpp = gstate.FrameBufFormat() == GE_FORMAT_8888 ? 4 : 2; + int avail_height = (nearest_address - fb_address) / (fb_stride * bpp); + if (avail_height < drawing_height && avail_height == region_height) { + drawing_width = std::min(region_width, fb_stride); + drawing_height = avail_height; + } + + // Some games draw buffers interleaved, with a high stride/region/scissor but default viewport. + if (fb_stride == 1024 && region_width == 1024 && scissor_width == 1024) { + drawing_width = 1024; + } + } + + DEBUG_LOG(G3D, "Est: %08x V: %ix%i, R: %ix%i, S: %ix%i, STR: %i, THR:%i, Z:%08x = %ix%i", gstate.getFrameBufAddress(), viewport_width,viewport_height, region_width, region_height, scissor_width, scissor_height, fb_stride, gstate.isModeThrough(), gstate.isDepthWriteEnabled() ? gstate.getDepthBufAddress() : 0, drawing_width, drawing_height); +} diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h new file mode 100644 index 0000000000..bc9d46bd28 --- /dev/null +++ b/GPU/Common/FramebufferCommon.h @@ -0,0 +1,182 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#pragma once + +#include +#include "Common/CommonTypes.h" +#include "Core/MemMap.h" +#include "GPU/GPUState.h" +#include "GPU/ge_constants.h" + +enum { + FB_USAGE_DISPLAYED_FRAMEBUFFER = 1, + FB_USAGE_RENDERTARGET = 2, + FB_USAGE_TEXTURE = 4, +}; + +enum { + FB_NON_BUFFERED_MODE = 0, + FB_BUFFERED_MODE = 1, + + // Hm, it's unfortunate that GPU has ended up as two separate values in GL and GLES. +#ifndef USING_GLES2 + FB_READFBOMEMORY_CPU = 2, + FB_READFBOMEMORY_GPU = 3, +#else + FB_READFBOMEMORY_GPU = 2, +#endif + FBO_READFBOMEMORY_MIN = 2 +}; + +struct FBO; + +struct VirtualFramebuffer { + int last_frame_used; + int last_frame_attached; + int last_frame_render; + bool memoryUpdated; + bool depthUpdated; + + u32 fb_address; + u32 z_address; + int fb_stride; + int z_stride; + + // There's also a top left of the drawing region, but meh... + + // width/height: The detected size of the current framebuffer. + u16 width; + u16 height; + // renderWidth/renderHeight: The actual size we render at. May be scaled to render at higher resolutions. + u16 renderWidth; + u16 renderHeight; + // bufferWidth/bufferHeight: The actual (but non scaled) size of the buffer we render to. May only be bigger than width/height. + u16 bufferWidth; + u16 bufferHeight; + + u16 usageFlags; + + u16 newWidth; + u16 newHeight; + int lastFrameNewSize; + + GEBufferFormat format; // virtual, right now they are all RGBA8888 + // TODO: Handle fbo and colorDepth better. + u8 colorDepth; + FBO *fbo; + + u16 drawnWidth; + u16 drawnHeight; + GEBufferFormat drawnFormat; + + bool dirtyAfterDisplay; + bool reallyDirtyAfterDisplay; // takes frame skipping into account +}; + +class FramebufferManagerCommon { +public: + FramebufferManagerCommon(); + virtual ~FramebufferManagerCommon(); + + virtual void DoSetRenderFrameBuffer() = 0; + void SetRenderFrameBuffer() { + // Inlining this part since it's so frequent. + if (!gstate_c.framebufChanged && currentRenderVfb_) { + currentRenderVfb_->last_frame_render = gpuStats.numFlips; + currentRenderVfb_->dirtyAfterDisplay = true; + if (!gstate_c.skipDrawReason) + currentRenderVfb_->reallyDirtyAfterDisplay = true; + return; + } + DoSetRenderFrameBuffer(); + } + + size_t NumVFBs() const { return vfbs_.size(); } + + void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format); + + u32 PrevDisplayFramebufAddr() { + return prevDisplayFramebuf_ ? (0x04000000 | prevDisplayFramebuf_->fb_address) : 0; + } + u32 DisplayFramebufAddr() { + return displayFramebuf_ ? (0x04000000 | displayFramebuf_->fb_address) : 0; + } + + void SetDepthUpdated() { + if (currentRenderVfb_) { + currentRenderVfb_->depthUpdated = true; + } + } + void SetColorUpdated() { + if (currentRenderVfb_) { + SetColorUpdated(currentRenderVfb_); + } + } + + bool MayIntersectFramebuffer(u32 start) { + // Clear the cache/kernel bits. + start = start & 0x3FFFFFFF; + // Most games only have two framebuffers at the start. + if (start >= framebufRangeEnd_ || start < PSP_GetVidMemBase()) { + return false; + } + return true; + } + + int GetRenderWidth() const { return currentRenderVfb_ ? currentRenderVfb_->renderWidth : 480; } + int GetRenderHeight() const { return currentRenderVfb_ ? currentRenderVfb_->renderHeight : 272; } + int GetTargetWidth() const { return currentRenderVfb_ ? currentRenderVfb_->width : 480; } + int GetTargetHeight() const { return currentRenderVfb_ ? currentRenderVfb_->height : 272; } + int GetTargetBufferWidth() const { return currentRenderVfb_ ? currentRenderVfb_->bufferWidth : 480; } + int GetTargetBufferHeight() const { return currentRenderVfb_ ? currentRenderVfb_->bufferHeight : 272; } + int GetTargetStride() const { return currentRenderVfb_ ? currentRenderVfb_->fb_stride : 512; } + GEBufferFormat GetTargetFormat() const { return currentRenderVfb_ ? currentRenderVfb_->format : displayFormat_; } + +protected: + void EstimateDrawingSize(int &drawing_width, int &drawing_height); + + void SetColorUpdated(VirtualFramebuffer *dstBuffer) { + dstBuffer->memoryUpdated = false; + dstBuffer->dirtyAfterDisplay = true; + dstBuffer->drawnWidth = dstBuffer->width; + dstBuffer->drawnHeight = dstBuffer->height; + dstBuffer->drawnFormat = dstBuffer->format; + if ((gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0) + dstBuffer->reallyDirtyAfterDisplay = true; + } + + virtual void DisableState() = 0; + virtual void ClearBuffer() = 0; + virtual void ClearDepthBuffer() = 0; + + u32 displayFramebufPtr_; + u32 displayStride_; + GEBufferFormat displayFormat_; + + VirtualFramebuffer *displayFramebuf_; + VirtualFramebuffer *prevDisplayFramebuf_; + VirtualFramebuffer *prevPrevDisplayFramebuf_; + int frameLastFramebufUsed_; + + VirtualFramebuffer *currentRenderVfb_; + + // The range of PSP memory that may contain FBOs. So we can skip iterating. + u32 framebufRangeEnd_; + + std::vector vfbs_; +}; diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index c576b2749a..8c6bb70c44 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -27,6 +27,7 @@ #include "helper/dx_state.h" #include "helper/fbo.h" +#include "GPU/Common/FramebufferCommon.h" #include "GPU/Directx9/FramebufferDX9.h" #include "GPU/Directx9/TextureCacheDX9.h" #include "GPU/Directx9/ShaderManagerDX9.h" @@ -91,7 +92,7 @@ namespace DX9 { } } - static void ClearBuffer() { + void FramebufferManagerDX9::ClearBuffer() { dxstate.scissorTest.disable(); dxstate.depthWrite.set(TRUE); dxstate.colorMask.set(true, true, true, true); @@ -100,7 +101,15 @@ namespace DX9 { pD3Ddevice->Clear(0, NULL, D3DCLEAR_STENCIL|D3DCLEAR_TARGET |D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 0, 0); } - static void DisableState() { + void FramebufferManagerDX9::ClearDepthBuffer() { + dxstate.scissorTest.disable(); + dxstate.depthWrite.set(TRUE); + dxstate.colorMask.set(false, false, false, false); + dxstate.stencilFunc.set(D3DCMP_NEVER, 0, 0); + pD3Ddevice->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 0, 0); + } + + void FramebufferManagerDX9::DisableState() { dxstate.blend.disable(); dxstate.cullMode.set(false, false); dxstate.depthTest.disable(); @@ -112,14 +121,6 @@ namespace DX9 { FramebufferManagerDX9::FramebufferManagerDX9() : - displayFramebufPtr_(0), - displayStride_(0), - displayFormat_(GE_FORMAT_565), - displayFramebuf_(0), - prevDisplayFramebuf_(0), - prevPrevDisplayFramebuf_(0), - frameLastFramebufUsed(0), - currentRenderVfb_(0), drawPixelsTex_(0), drawPixelsTexFormat_(GE_FORMAT_INVALID), convBuf(0) @@ -280,10 +281,10 @@ namespace DX9 { } - VirtualFramebufferDX9 *FramebufferManagerDX9::GetVFBAt(u32 addr) { - VirtualFramebufferDX9 *match = NULL; + VirtualFramebuffer *FramebufferManagerDX9::GetVFBAt(u32 addr) { + VirtualFramebuffer *match = NULL; for (size_t i = 0; i < vfbs_.size(); ++i) { - VirtualFramebufferDX9 *v = vfbs_[i]; + VirtualFramebuffer *v = vfbs_[i]; if (MaskedEqual(v->fb_address, addr) && v->format == displayFormat_ && v->width >= 480) { // Could check w too but whatever if (match == NULL || match->last_frame_render < v->last_frame_render) { @@ -299,53 +300,7 @@ namespace DX9 { return 0; } - - - // Heuristics to figure out the size of FBO to create. - static void EstimateDrawingSize(int &drawing_width, int &drawing_height) { - int default_width = 480; - int default_height = 272; - int viewport_width = (int) gstate.getViewportX1(); - int viewport_height = (int) gstate.getViewportY1(); - int region_width = gstate.getRegionX2() + 1; - int region_height = gstate.getRegionY2() + 1; - int scissor_width = gstate.getScissorX2() + 1; - int scissor_height = gstate.getScissorY2() + 1; - int fb_stride = gstate.fbwidth & 0x3C0; - - DEBUG_LOG(SCEGE,"viewport : %ix%i, region : %ix%i , scissor: %ix%i, stride: %i, %i", viewport_width,viewport_height, region_width, region_height, scissor_width, scissor_height, fb_stride, gstate.isModeThrough()); - - // Viewport may return 0x0 for example FF Type-0 and we set it to 480x272 - if (viewport_width <= 1 && viewport_height <=1) { - viewport_width = default_width; - viewport_height = default_height; - } - - if (fb_stride > 0 && fb_stride < 512) { - // Correct scissor size has to be used to render like character shadow in Mortal Kombat . - if (fb_stride == scissor_width && region_width != scissor_width) { - drawing_width = scissor_width; - drawing_height = scissor_height; - } else { - drawing_width = viewport_width; - drawing_height = viewport_height; - } - } else { - // Correct region size has to be used when fb_width equals to region_width for exmaple GTA/Midnight Club/MSG Peace Maker . - if (fb_stride == region_width && region_width == viewport_width) { - drawing_width = region_width; - drawing_height = region_height; - } else if (fb_stride == viewport_width) { - drawing_width = viewport_width; - drawing_height = viewport_height; - } else { - drawing_width = default_width; - drawing_height = default_height; - } - } - } - - void FramebufferManagerDX9::DestroyFramebuf(VirtualFramebufferDX9 *v) { + void FramebufferManagerDX9::DestroyFramebuf(VirtualFramebuffer *v) { textureCache_->NotifyFramebuffer(v->fb_address, v, NOTIFY_FB_DESTROYED); if (v->fbo) { fbo_destroy(v->fbo); @@ -365,14 +320,7 @@ namespace DX9 { delete v; } - void FramebufferManagerDX9::SetRenderFrameBuffer() { - if (!gstate_c.framebufChanged && currentRenderVfb_) { - currentRenderVfb_->last_frame_render = gpuStats.numFlips; - currentRenderVfb_->dirtyAfterDisplay = true; - if (!gstate_c.skipDrawReason) - currentRenderVfb_->reallyDirtyAfterDisplay = true; - return; - } + void FramebufferManagerDX9::DoSetRenderFrameBuffer() { #if 0 if (g_Config.iRenderingMode != 0 && g_Config.bWipeFramebufferAlpha && currentRenderVfb_) { // Hack is enabled, and there was a previous framebuffer. @@ -422,9 +370,9 @@ namespace DX9 { int buffer_height = drawing_height; // Find a matching framebuffer - VirtualFramebufferDX9 *vfb = 0; + VirtualFramebuffer *vfb = 0; for (size_t i = 0; i < vfbs_.size(); ++i) { - VirtualFramebufferDX9 *v = vfbs_[i]; + VirtualFramebuffer *v = vfbs_[i]; if (MaskedEqual(v->fb_address, fb_address) && v->width >= drawing_width && v->height >= drawing_height) { // Let's not be so picky for now. Let's say this is the one. vfb = v; @@ -441,7 +389,7 @@ namespace DX9 { // None found? Create one. if (!vfb) { gstate_c.textureChanged = true; - vfb = new VirtualFramebufferDX9(); + vfb = new VirtualFramebuffer(); vfb->fbo = 0; vfb->fb_address = fb_address; vfb->fb_stride = fb_stride; @@ -483,7 +431,7 @@ namespace DX9 { } if (useBufferedRendering_) { - vfb->fbo = fbo_create(vfb->renderWidth, vfb->renderHeight, 1, true, vfb->colorDepth); + vfb->fbo = fbo_create(vfb->renderWidth, vfb->renderHeight, 1, true, (FBOColorDepth)vfb->colorDepth); if (vfb->fbo) { fbo_bind_as_render_target(vfb->fbo); } else { @@ -500,7 +448,7 @@ namespace DX9 { vfb->last_frame_render = gpuStats.numFlips; vfb->last_frame_used = 0; vfb->last_frame_attached = 0; - frameLastFramebufUsed = gpuStats.numFlips; + frameLastFramebufUsed_ = gpuStats.numFlips; vfbs_.push_back(vfb); ClearBuffer(); @@ -533,7 +481,7 @@ namespace DX9 { vfb->usageFlags |= FB_USAGE_RENDERTARGET; gstate_c.textureChanged = true; vfb->last_frame_render = gpuStats.numFlips; - frameLastFramebufUsed = gpuStats.numFlips; + frameLastFramebufUsed_ = gpuStats.numFlips; vfb->dirtyAfterDisplay = true; if ((gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0) vfb->reallyDirtyAfterDisplay = true; @@ -576,7 +524,7 @@ namespace DX9 { currentRenderVfb_ = vfb; } else { vfb->last_frame_render = gpuStats.numFlips; - frameLastFramebufUsed = gpuStats.numFlips; + frameLastFramebufUsed_ = gpuStats.numFlips; vfb->dirtyAfterDisplay = true; if ((gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0) vfb->reallyDirtyAfterDisplay = true; @@ -596,7 +544,7 @@ namespace DX9 { dxstate.viewport.set(0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight); currentRenderVfb_ = 0; - VirtualFramebufferDX9 *vfb = GetVFBAt(displayFramebufPtr_); + VirtualFramebuffer *vfb = GetVFBAt(displayFramebufPtr_); if (!vfb) { if (Memory::IsValidAddress(displayFramebufPtr_)) { // The game is displaying something directly from RAM. In GTA, it's decoded video. @@ -695,7 +643,7 @@ namespace DX9 { } } - void FramebufferManagerDX9::ReadFramebufferToMemory(VirtualFramebufferDX9 *vfb, bool sync) { + void FramebufferManagerDX9::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync) { #if 0 if (sync) { PackFramebufferAsync_(NULL); // flush async just in case when we go for synchronous update @@ -706,11 +654,11 @@ namespace DX9 { // We'll pseudo-blit framebuffers here to get a resized and flipped version of vfb. // For now we'll keep these on the same struct as the ones that can get displayed // (and blatantly copy work already done above while at it). - VirtualFramebufferDX9 *nvfb = 0; + VirtualFramebuffer *nvfb = 0; // We maintain a separate vector of framebuffer objects for blitting. for (size_t i = 0; i < bvfbs_.size(); ++i) { - VirtualFramebufferDX9 *v = bvfbs_[i]; + VirtualFramebuffer *v = bvfbs_[i]; if (MaskedEqual(v->fb_address, vfb->fb_address) && v->format == vfb->format) { if (v->bufferWidth == vfb->bufferWidth && v->bufferHeight == vfb->bufferHeight) { nvfb = v; @@ -724,7 +672,7 @@ namespace DX9 { // Create a new fbo if none was found for the size if(!nvfb) { - nvfb = new VirtualFramebufferDX9(); + nvfb = new VirtualFramebuffer(); nvfb->fbo = 0; nvfb->fb_address = vfb->fb_address; nvfb->fb_stride = vfb->fb_stride; @@ -757,7 +705,7 @@ namespace DX9 { break; } - nvfb->fbo = fbo_create(nvfb->width, nvfb->height, 1, true, nvfb->colorDepth); + nvfb->fbo = fbo_create(nvfb->width, nvfb->height, 1, true, (FBOColorDepth)nvfb->colorDepth); if (!(nvfb->fbo)) { ERROR_LOG(SCEGE, "Error creating FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight); return; @@ -807,7 +755,7 @@ namespace DX9 { } } - void FramebufferManagerDX9::BlitFramebuffer_(VirtualFramebufferDX9 *src, VirtualFramebufferDX9 *dst, bool flip, float upscale, float vscale) { + void FramebufferManagerDX9::BlitFramebuffer_(VirtualFramebuffer *src, VirtualFramebuffer *dst, bool flip, float upscale, float vscale) { if (dst->fbo) { fbo_bind_as_render_target(dst->fbo); } else { @@ -883,7 +831,7 @@ namespace DX9 { } } - void FramebufferManagerDX9::PackFramebufferDirectx9_(VirtualFramebufferDX9 *vfb) { + void FramebufferManagerDX9::PackFramebufferDirectx9_(VirtualFramebuffer *vfb) { if (vfb->fbo) { fbo_bind_for_read(vfb->fbo); } else { @@ -940,18 +888,11 @@ namespace DX9 { useBufferedRendering_ = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE; } - void FramebufferManagerDX9::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) { - - displayFramebufPtr_ = framebuf; - displayStride_ = stride; - displayFormat_ = format; - } - std::vector FramebufferManagerDX9::GetFramebufferList() { std::vector list; for (size_t i = 0; i < vfbs_.size(); ++i) { - VirtualFramebufferDX9 *vfb = vfbs_[i]; + VirtualFramebuffer *vfb = vfbs_[i]; FramebufferInfo info; info.fb_address = vfb->fb_address; @@ -983,8 +924,8 @@ namespace DX9 { bool updateVram = !(g_Config.iRenderingMode == FB_NON_BUFFERED_MODE || g_Config.iRenderingMode == FB_BUFFERED_MODE); for (size_t i = 0; i < vfbs_.size(); ++i) { - VirtualFramebufferDX9 *vfb = vfbs_[i]; - int age = frameLastFramebufUsed - std::max(vfb->last_frame_render, vfb->last_frame_used); + VirtualFramebuffer *vfb = vfbs_[i]; + int age = frameLastFramebufUsed_ - std::max(vfb->last_frame_render, vfb->last_frame_used); if (updateVram && age == 0 && !vfb->memoryUpdated && vfb == displayFramebuf_) ReadFramebufferToMemory(vfb); @@ -1002,8 +943,8 @@ namespace DX9 { // Do the same for ReadFramebuffersToMemory's VFBs for (size_t i = 0; i < bvfbs_.size(); ++i) { - VirtualFramebufferDX9 *vfb = bvfbs_[i]; - int age = frameLastFramebufUsed - vfb->last_frame_render; + VirtualFramebuffer *vfb = bvfbs_[i]; + int age = frameLastFramebufUsed_ - vfb->last_frame_render; 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); DestroyFramebuf(vfb); @@ -1020,7 +961,7 @@ namespace DX9 { prevPrevDisplayFramebuf_ = 0; for (size_t i = 0; i < vfbs_.size(); ++i) { - VirtualFramebufferDX9 *vfb = vfbs_[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); DestroyFramebuf(vfb); } @@ -1041,7 +982,7 @@ namespace DX9 { bool needUnbind = false; for (size_t i = 0; i < vfbs_.size(); ++i) { - VirtualFramebufferDX9 *vfb = vfbs_[i]; + VirtualFramebuffer *vfb = vfbs_[i]; if (MaskedEqual(vfb->fb_address, addr)) { vfb->dirtyAfterDisplay = true; vfb->reallyDirtyAfterDisplay = true; @@ -1073,7 +1014,7 @@ namespace DX9 { u32 fb_address = gstate.getFrameBufRawAddress(); int fb_stride = gstate.FrameBufStride(); - VirtualFramebufferDX9 *vfb = currentRenderVfb_; + VirtualFramebuffer *vfb = currentRenderVfb_; if (!vfb) { vfb = GetVFBAt(fb_address); } diff --git a/GPU/Directx9/FramebufferDX9.h b/GPU/Directx9/FramebufferDX9.h index 4191759e0c..b65f9f6f54 100644 --- a/GPU/Directx9/FramebufferDX9.h +++ b/GPU/Directx9/FramebufferDX9.h @@ -30,65 +30,20 @@ #include "Globals.h" #include "GPU/GPUCommon.h" +#include "GPU/Common/FramebufferCommon.h" namespace DX9 { struct GLSLProgram; class TextureCacheDX9; -enum { - FB_USAGE_DISPLAYED_FRAMEBUFFER = 1, - FB_USAGE_RENDERTARGET = 2, - FB_USAGE_TEXTURE = 4, -}; - -enum { - FB_NON_BUFFERED_MODE = 0, - FB_BUFFERED_MODE = 1, - FB_READFBOMEMORY_CPU = 2, - FB_READFBOMEMORY_GPU = 3, -}; - -struct VirtualFramebufferDX9 { - int last_frame_used; - int last_frame_attached; - int last_frame_render; - bool memoryUpdated; - - u32 fb_address; - u32 z_address; - int fb_stride; - int z_stride; - - // There's also a top left of the drawing region, but meh... - - // width/height: The detected size of the current framebuffer. - u16 width; - u16 height; - // renderWidth/renderHeight: The actual size we render at. May be scaled to render at higher resolutions. - u16 renderWidth; - u16 renderHeight; - // bufferWidth/bufferHeight: The actual (but non scaled) size of the buffer we render to. May only be bigger than width/height. - u16 bufferWidth; - u16 bufferHeight; - - u16 usageFlags; - - GEBufferFormat format; // virtual, right now they are all RGBA8888 - FBOColorDepth colorDepth; - FBO *fbo; - - bool dirtyAfterDisplay; - bool reallyDirtyAfterDisplay; // takes frame skipping into account -}; - void CenterRect(float *x, float *y, float *w, float *h, float origW, float origH, float frameW, float frameH); class ShaderManagerDX9; -class FramebufferManagerDX9 { +class FramebufferManagerDX9 : public FramebufferManagerCommon { public: FramebufferManagerDX9(); ~FramebufferManagerDX9(); @@ -112,62 +67,41 @@ public: void Resized(); void DeviceLost(); void CopyDisplayToOutput(); - void SetRenderFrameBuffer(); // Uses parameters computed from gstate + virtual void DoSetRenderFrameBuffer() override; // Uses parameters computed from gstate void UpdateFromMemory(u32 addr, int size, bool safe); - void ReadFramebufferToMemory(VirtualFramebufferDX9 *vfb, bool sync = true); + void ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync = true); // TODO: Break out into some form of FBO manager - VirtualFramebufferDX9 *GetVFBAt(u32 addr); - VirtualFramebufferDX9 *GetDisplayVFB() { + VirtualFramebuffer *GetVFBAt(u32 addr); + VirtualFramebuffer *GetDisplayVFB() { return GetVFBAt(displayFramebufPtr_); } - void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format); - size_t NumVFBs() const { return vfbs_.size(); } std::vector GetFramebufferList(); - int GetRenderWidth() const { return currentRenderVfb_ ? currentRenderVfb_->renderWidth : 480; } - int GetRenderHeight() const { return currentRenderVfb_ ? currentRenderVfb_->renderHeight : 272; } - int GetTargetWidth() const { return currentRenderVfb_ ? currentRenderVfb_->width : 480; } - int GetTargetHeight() const { return currentRenderVfb_ ? currentRenderVfb_->height : 272; } - - u32 PrevDisplayFramebufAddr() { - return prevDisplayFramebuf_ ? (0x04000000 | prevDisplayFramebuf_->fb_address) : 0; - } - u32 DisplayFramebufAddr() { - return displayFramebuf_ ? (0x04000000 | displayFramebuf_->fb_address) : 0; - } - void NotifyFramebufferCopy(u32 src, u32 dest, int size); - void DestroyFramebuf(VirtualFramebufferDX9 *vfb); + void DestroyFramebuf(VirtualFramebuffer *vfb); bool GetCurrentFramebuffer(GPUDebugBuffer &buffer); bool GetCurrentDepthbuffer(GPUDebugBuffer &buffer); bool GetCurrentStencilbuffer(GPUDebugBuffer &buffer); +protected: + virtual void DisableState() override; + virtual void ClearBuffer() override; + virtual void ClearDepthBuffer() override; + private: void CompileDraw2DProgram(); void DestroyDraw2DProgram(); void SetNumExtraFBOs(int num); - u32 displayFramebufPtr_; - u32 displayStride_; - GEBufferFormat displayFormat_; - - VirtualFramebufferDX9 *displayFramebuf_; - VirtualFramebufferDX9 *prevDisplayFramebuf_; - VirtualFramebufferDX9 *prevPrevDisplayFramebuf_; - int frameLastFramebufUsed; - - std::vector vfbs_; - - VirtualFramebufferDX9 *currentRenderVfb_; // Used by ReadFramebufferToMemory - void BlitFramebuffer_(VirtualFramebufferDX9 *src, VirtualFramebufferDX9 *dst, bool flip = false, float upscale = 1.0f, float vscale = 1.0f); - void PackFramebufferDirectx9_(VirtualFramebufferDX9 *vfb); + void BlitFramebuffer_(VirtualFramebuffer *src, VirtualFramebuffer *dst, bool flip = false, float upscale = 1.0f, float vscale = 1.0f); + void PackFramebufferDirectx9_(VirtualFramebuffer *vfb); // Used by DrawPixels LPDIRECT3DTEXTURE9 drawPixelsTex_; @@ -188,7 +122,7 @@ private: bool resized_; bool useBufferedRendering_; - std::vector bvfbs_; // blitting FBOs + std::vector bvfbs_; // blitting FBOs std::set> knownFramebufferCopies_; diff --git a/GPU/Directx9/GPU_DX9.cpp b/GPU/Directx9/GPU_DX9.cpp index 5697cf2121..bdb2f34a2b 100644 --- a/GPU/Directx9/GPU_DX9.cpp +++ b/GPU/Directx9/GPU_DX9.cpp @@ -31,6 +31,7 @@ #include "GPU/ge_constants.h" #include "GPU/GeDisasm.h" +#include "GPU/Common/FramebufferCommon.h" #include "GPU/Directx9/helper/global.h" #include "GPU/Directx9/ShaderManagerDX9.h" #include "GPU/Directx9/GPU_DX9.h" @@ -511,7 +512,7 @@ bool DIRECTX9_GPU::FramebufferDirty() { // Allow it to process fully before deciding if it's dirty. SyncThread(); } - VirtualFramebufferDX9 *vfb = framebufferManager_.GetDisplayVFB(); + VirtualFramebuffer *vfb = framebufferManager_.GetDisplayVFB(); if (vfb) { bool dirty = vfb->dirtyAfterDisplay; vfb->dirtyAfterDisplay = false; @@ -528,7 +529,7 @@ bool DIRECTX9_GPU::FramebufferReallyDirty() { SyncThread(); } - VirtualFramebufferDX9 *vfb = framebufferManager_.GetDisplayVFB(); + VirtualFramebuffer *vfb = framebufferManager_.GetDisplayVFB(); if (vfb) { bool dirty = vfb->reallyDirtyAfterDisplay; vfb->reallyDirtyAfterDisplay = false; diff --git a/GPU/Directx9/TextureCacheDX9.cpp b/GPU/Directx9/TextureCacheDX9.cpp index 99e0d2377b..6ca63c6ae8 100644 --- a/GPU/Directx9/TextureCacheDX9.cpp +++ b/GPU/Directx9/TextureCacheDX9.cpp @@ -27,6 +27,7 @@ #include "GPU/Directx9/TextureCacheDX9.h" #include "GPU/Directx9/FramebufferDX9.h" #include "GPU/Directx9/helper/dx_state.h" +#include "GPU/Common/FramebufferCommon.h" #include "GPU/Common/TextureDecoder.h" #include "Core/Config.h" #include "Core/Host.h" @@ -212,7 +213,7 @@ void TextureCacheDX9::ClearNextFrame() { } -void TextureCacheDX9::AttachFramebufferValid(TexCacheEntry *entry, VirtualFramebufferDX9 *framebuffer, const AttachedFramebufferInfo &fbInfo) { +void TextureCacheDX9::AttachFramebufferValid(TexCacheEntry *entry, VirtualFramebuffer *framebuffer, const AttachedFramebufferInfo &fbInfo) { const bool hasInvalidFramebuffer = entry->framebuffer == 0 || entry->invalidHint == -1; const bool hasOlderFramebuffer = entry->framebuffer != 0 && entry->framebuffer->last_frame_render < framebuffer->last_frame_render; bool hasFartherFramebuffer = false; @@ -235,7 +236,7 @@ void TextureCacheDX9::AttachFramebufferValid(TexCacheEntry *entry, VirtualFrameb } } -void TextureCacheDX9::AttachFramebufferInvalid(TexCacheEntry *entry, VirtualFramebufferDX9 *framebuffer, const AttachedFramebufferInfo &fbInfo) { +void TextureCacheDX9::AttachFramebufferInvalid(TexCacheEntry *entry, VirtualFramebuffer *framebuffer, const AttachedFramebufferInfo &fbInfo) { if (entry->framebuffer == 0 || entry->framebuffer == framebuffer) { entry->framebuffer = framebuffer; entry->invalidHint = -1; @@ -245,7 +246,7 @@ void TextureCacheDX9::AttachFramebufferInvalid(TexCacheEntry *entry, VirtualFram } } -bool TextureCacheDX9::AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebufferDX9 *framebuffer, u32 texaddrOffset) { +bool TextureCacheDX9::AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 texaddrOffset) { static const u32 MAX_SUBAREA_Y_OFFSET_SAFE = 32; AttachedFramebufferInfo fbInfo = {0}; @@ -352,14 +353,14 @@ bool TextureCacheDX9::AttachFramebuffer(TexCacheEntry *entry, u32 address, Virtu return false; } -inline void TextureCacheDX9::DetachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebufferDX9 *framebuffer) { +inline void TextureCacheDX9::DetachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer) { if (entry->framebuffer == framebuffer) { entry->framebuffer = 0; host->GPUNotifyTextureAttachment(entry->addr); } } -void TextureCacheDX9::NotifyFramebuffer(u32 address, VirtualFramebufferDX9 *framebuffer, FramebufferNotification msg) { +void TextureCacheDX9::NotifyFramebuffer(u32 address, VirtualFramebuffer *framebuffer, FramebufferNotification msg) { // Must be in VRAM so | 0x04000000 it is. Also, ignore memory mirrors. // These checks are mainly to reduce scanning all textures. const u32 addr = (address | 0x04000000) & 0x3F9FFFFF; @@ -812,7 +813,7 @@ inline u32 TextureCacheDX9::GetCurrentClutHash() { return clutHash_; } -void TextureCacheDX9::SetTextureFramebuffer(TexCacheEntry *entry, VirtualFramebufferDX9 *framebuffer) { +void TextureCacheDX9::SetTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) { _dbg_assert_msg_(G3D, framebuffer != nullptr, "Framebuffer must not be null."); framebuffer->usageFlags |= FB_USAGE_TEXTURE; diff --git a/GPU/Directx9/TextureCacheDX9.h b/GPU/Directx9/TextureCacheDX9.h index 3c6b4b61f4..55b62856ae 100644 --- a/GPU/Directx9/TextureCacheDX9.h +++ b/GPU/Directx9/TextureCacheDX9.h @@ -24,9 +24,10 @@ #include "GPU/GPUState.h" #include "GPU/Directx9/TextureScalerDX9.h" +struct VirtualFramebuffer; + namespace DX9 { -struct VirtualFramebufferDX9; class FramebufferManagerDX9; class ShaderManagerDX9; @@ -60,7 +61,7 @@ public: // FramebufferManager keeps TextureCache updated about what regions of memory // are being rendered to. This is barebones so far. - void NotifyFramebuffer(u32 address, VirtualFramebufferDX9 *framebuffer, FramebufferNotification msg); + void NotifyFramebuffer(u32 address, VirtualFramebuffer *framebuffer, FramebufferNotification msg); void SetFramebufferManager(FramebufferManagerDX9 *fbManager) { framebufferManager_ = fbManager; @@ -105,7 +106,7 @@ public: int status; u32 addr; u32 hash; - VirtualFramebufferDX9 *framebuffer; // if null, not sourced from an FBO. + VirtualFramebuffer *framebuffer; // if null, not sourced from an FBO. u32 sizeInRAM; int lastFrame; int numFrames; @@ -168,15 +169,15 @@ private: const T *GetCurrentClut(); u32 GetCurrentClutHash(); void UpdateCurrentClut(); - bool AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebufferDX9 *framebuffer, u32 texaddrOffset = 0); - void DetachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebufferDX9 *framebuffer); - void SetTextureFramebuffer(TexCacheEntry *entry, VirtualFramebufferDX9 *framebuffer); + bool AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, u32 texaddrOffset = 0); + void DetachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer); + void SetTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer); TexCacheEntry *GetEntryAt(u32 texaddr); TexCache cache; TexCache secondCache; - std::vector fbCache_; + std::vector fbCache_; // Separate to keep main texture cache size down. struct AttachedFramebufferInfo { @@ -184,8 +185,8 @@ private: u32 yOffset; }; std::map fbTexInfo_; - void AttachFramebufferValid(TexCacheEntry *entry, VirtualFramebufferDX9 *framebuffer, const AttachedFramebufferInfo &fbInfo); - void AttachFramebufferInvalid(TexCacheEntry *entry, VirtualFramebufferDX9 *framebuffer, const AttachedFramebufferInfo &fbInfo); + void AttachFramebufferValid(TexCacheEntry *entry, VirtualFramebuffer *framebuffer, const AttachedFramebufferInfo &fbInfo); + void AttachFramebufferInvalid(TexCacheEntry *entry, VirtualFramebuffer *framebuffer, const AttachedFramebufferInfo &fbInfo); bool clearCacheNextFrame_; bool lowMemoryMode_; diff --git a/GPU/Directx9/helper/fbo.cpp b/GPU/Directx9/helper/fbo.cpp index 7f80a5cee2..66990d080b 100644 --- a/GPU/Directx9/helper/fbo.cpp +++ b/GPU/Directx9/helper/fbo.cpp @@ -6,13 +6,6 @@ #include "fbo.h" #include "dx_state.h" -namespace DX9 { - -static LPDIRECT3DSURFACE9 deviceRTsurf; -static LPDIRECT3DSURFACE9 deviceDSsurf; - -#define FB_DIV 1 - struct FBO { uint32_t id; LPDIRECT3DSURFACE9 surf; @@ -21,9 +14,16 @@ struct FBO { int width; int height; - FBOColorDepth colorDepth; + DX9::FBOColorDepth colorDepth; }; +namespace DX9 { + +static LPDIRECT3DSURFACE9 deviceRTsurf; +static LPDIRECT3DSURFACE9 deviceDSsurf; + +#define FB_DIV 1 + void fbo_init() { pD3Ddevice->GetRenderTarget(0, &deviceRTsurf); pD3Ddevice->GetDepthStencilSurface(&deviceDSsurf); diff --git a/GPU/Directx9/helper/fbo.h b/GPU/Directx9/helper/fbo.h index 4fd9ae810c..492629dfa9 100644 --- a/GPU/Directx9/helper/fbo.h +++ b/GPU/Directx9/helper/fbo.h @@ -4,10 +4,10 @@ // Very C-ish API because that's what I felt like, and it's cool to completely // hide the data from callers... -namespace DX9 { - struct FBO; +namespace DX9 { + enum FBOColorDepth { FBO_8888, FBO_565, @@ -15,7 +15,6 @@ enum FBOColorDepth { FBO_5551, }; - // Creates a simple FBO with a RGBA32 color buffer stored in a texture, and // optionally an accompanying Z/stencil buffer. // No mipmap support. diff --git a/GPU/GLES/Framebuffer.cpp b/GPU/GLES/Framebuffer.cpp index f72026a75d..9604769a4e 100644 --- a/GPU/GLES/Framebuffer.cpp +++ b/GPU/GLES/Framebuffer.cpp @@ -339,14 +339,6 @@ void FramebufferManager::DestroyDraw2DProgram() { } FramebufferManager::FramebufferManager() : - displayFramebufPtr_(0), - displayStride_(0), - displayFormat_(GE_FORMAT_565), - displayFramebuf_(0), - prevDisplayFramebuf_(0), - prevPrevDisplayFramebuf_(0), - frameLastFramebufUsed(0), - currentRenderVfb_(0), drawPixelsTex_(0), drawPixelsTexFormat_(GE_FORMAT_INVALID), convBuf_(0), @@ -360,8 +352,7 @@ FramebufferManager::FramebufferManager() : usePostShader_(false), postShaderAtOutputResolution_(false), resized_(false), - gameUsesSequentialCopies_(false), - framebufRangeEnd_(0) + gameUsesSequentialCopies_(false) #ifndef USING_GLES2 , pixelBufObj_(0), @@ -669,81 +660,6 @@ VirtualFramebuffer *FramebufferManager::GetVFBAt(u32 addr) { return 0; } -// Heuristics to figure out the size of FBO to create. -void FramebufferManager::EstimateDrawingSize(int &drawing_width, int &drawing_height) { - static const int MAX_FRAMEBUF_HEIGHT = 512; - const int viewport_width = (int) gstate.getViewportX1(); - const int viewport_height = (int) gstate.getViewportY1(); - const int region_width = gstate.getRegionX2() + 1; - const int region_height = gstate.getRegionY2() + 1; - const int scissor_width = gstate.getScissorX2() + 1; - const int scissor_height = gstate.getScissorY2() + 1; - const int fb_stride = std::max(gstate.FrameBufStride(), 4); - - // Games don't always set any of these. Take the greatest parameter that looks valid based on stride. - if (viewport_width > 4 && viewport_width <= fb_stride) { - drawing_width = viewport_width; - drawing_height = viewport_height; - // Some games specify a viewport with 0.5, but don't have VRAM for 273. 480x272 is the buffer size. - if (viewport_width == 481 && region_width == 480 && viewport_height == 273 && region_height == 272) { - drawing_width = 480; - drawing_height = 272; - } - // Sometimes region is set larger than the VRAM for the framebuffer. - if (region_width <= fb_stride && region_width > drawing_width && region_height <= MAX_FRAMEBUF_HEIGHT) { - drawing_width = region_width; - drawing_height = std::max(drawing_height, region_height); - } - // Scissor is often set to a subsection of the framebuffer, so we pay the least attention to it. - if (scissor_width <= fb_stride && scissor_width > drawing_width && scissor_height <= MAX_FRAMEBUF_HEIGHT) { - drawing_width = scissor_width; - drawing_height = std::max(drawing_height, scissor_height); - } - } else { - // If viewport wasn't valid, let's just take the greatest anything regardless of stride. - drawing_width = std::min(std::max(region_width, scissor_width), fb_stride); - drawing_height = std::max(region_height, scissor_height); - } - - // Assume no buffer is > 512 tall, it couldn't be textured or displayed fully if so. - if (drawing_height >= MAX_FRAMEBUF_HEIGHT) { - if (region_height < MAX_FRAMEBUF_HEIGHT) { - drawing_height = region_height; - } else if (scissor_height < MAX_FRAMEBUF_HEIGHT) { - drawing_height = scissor_height; - } - } - - if (viewport_width != region_width) { - // The majority of the time, these are equal. If not, let's check what we know. - const u32 fb_address = gstate.getFrameBufAddress(); - u32 nearest_address = 0xFFFFFFFF; - for (size_t i = 0; i < vfbs_.size(); ++i) { - const u32 other_address = vfbs_[i]->fb_address | 0x44000000; - if (other_address > fb_address && other_address < nearest_address) { - nearest_address = other_address; - } - } - - // Unless the game is using overlapping buffers, the next buffer should be far enough away. - // This catches some cases where we can know this. - // Hmm. The problem is that we could only catch it for the first of two buffers... - const u32 bpp = gstate.FrameBufFormat() == GE_FORMAT_8888 ? 4 : 2; - int avail_height = (nearest_address - fb_address) / (fb_stride * bpp); - if (avail_height < drawing_height && avail_height == region_height) { - drawing_width = std::min(region_width, fb_stride); - drawing_height = avail_height; - } - - // Some games draw buffers interleaved, with a high stride/region/scissor but default viewport. - if (fb_stride == 1024 && region_width == 1024 && scissor_width == 1024) { - drawing_width = 1024; - } - } - - DEBUG_LOG(G3D, "Est: %08x V: %ix%i, R: %ix%i, S: %ix%i, STR: %i, THR:%i, Z:%08x = %ix%i", gstate.getFrameBufAddress(), viewport_width,viewport_height, region_width, region_height, scissor_width, scissor_height, fb_stride, gstate.isModeThrough(), gstate.isDepthWriteEnabled() ? gstate.getDepthBufAddress() : 0, drawing_width, drawing_height); -} - void FramebufferManager::DestroyFramebuf(VirtualFramebuffer *v) { textureCache_->NotifyFramebuffer(v->fb_address, v, NOTIFY_FB_DESTROYED); if (v->fbo) { @@ -829,7 +745,7 @@ void FramebufferManager::ResizeFramebufFBO(VirtualFramebuffer *vfb, u16 w, u16 h return; } - vfb->fbo = fbo_create(vfb->renderWidth, vfb->renderHeight, 1, true, vfb->colorDepth); + vfb->fbo = fbo_create(vfb->renderWidth, vfb->renderHeight, 1, true, (FBOColorDepth)vfb->colorDepth); if (old.fbo) { INFO_LOG(SCEGE, "Resizing FBO for %08x : %i x %i x %i", vfb->fb_address, w, h, vfb->format); if (vfb->fbo) { @@ -1008,7 +924,7 @@ void FramebufferManager::DoSetRenderFrameBuffer() { vfb->last_frame_render = gpuStats.numFlips; vfb->last_frame_used = 0; vfb->last_frame_attached = 0; - frameLastFramebufUsed = gpuStats.numFlips; + frameLastFramebufUsed_ = gpuStats.numFlips; vfbs_.push_back(vfb); glDisable(GL_DITHER); // why? currentRenderVfb_ = vfb; @@ -1071,7 +987,7 @@ void FramebufferManager::DoSetRenderFrameBuffer() { vfb->usageFlags |= FB_USAGE_RENDERTARGET; textureCache_->ForgetLastTexture(); vfb->last_frame_render = gpuStats.numFlips; - frameLastFramebufUsed = gpuStats.numFlips; + frameLastFramebufUsed_ = gpuStats.numFlips; vfb->dirtyAfterDisplay = true; if ((gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0) vfb->reallyDirtyAfterDisplay = true; @@ -1129,7 +1045,7 @@ void FramebufferManager::DoSetRenderFrameBuffer() { } vfb->last_frame_render = gpuStats.numFlips; - frameLastFramebufUsed = gpuStats.numFlips; + frameLastFramebufUsed_ = gpuStats.numFlips; vfb->dirtyAfterDisplay = true; if ((gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0) vfb->reallyDirtyAfterDisplay = true; @@ -1267,7 +1183,7 @@ void FramebufferManager::BindFramebufferColor(VirtualFramebuffer *framebuffer, b } if (!skipCopy && currentRenderVfb_ && framebuffer->fb_address == gstate.getFrameBufRawAddress()) { // TODO: Maybe merge with bvfbs_? Not sure if those could be packing, and they're created at a different size. - FBO *renderCopy = GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, framebuffer->colorDepth); + FBO *renderCopy = GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, (FBOColorDepth)framebuffer->colorDepth); if (renderCopy) { VirtualFramebuffer copyInfo = *framebuffer; copyInfo.fbo = renderCopy; @@ -1517,7 +1433,7 @@ void FramebufferManager::ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool s } textureCache_->ForgetLastTexture(); - nvfb->fbo = fbo_create(nvfb->width, nvfb->height, 1, false, nvfb->colorDepth); + nvfb->fbo = fbo_create(nvfb->width, nvfb->height, 1, false, (FBOColorDepth)nvfb->colorDepth); if (!(nvfb->fbo)) { ERROR_LOG(SCEGE, "Error creating FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight); return; @@ -2036,12 +1952,6 @@ void FramebufferManager::BeginFrame() { updateVRAM_ = !(g_Config.iRenderingMode == FB_NON_BUFFERED_MODE || g_Config.iRenderingMode == FB_BUFFERED_MODE); } -void FramebufferManager::SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format) { - displayFramebufPtr_ = framebuf; - displayStride_ = stride; - displayFormat_ = format; -} - std::vector FramebufferManager::GetFramebufferList() { std::vector list; @@ -2067,7 +1977,7 @@ void FramebufferManager::DecimateFBOs() { for (size_t i = 0; i < vfbs_.size(); ++i) { VirtualFramebuffer *vfb = vfbs_[i]; - int age = frameLastFramebufUsed - std::max(vfb->last_frame_render, vfb->last_frame_used); + int age = frameLastFramebufUsed_ - std::max(vfb->last_frame_render, vfb->last_frame_used); if (ShouldDownloadFramebuffer(vfb) && age == 0 && !vfb->memoryUpdated) { #ifdef USING_GLES2 @@ -2090,7 +2000,7 @@ void FramebufferManager::DecimateFBOs() { } for (auto it = tempFBOs_.begin(); it != tempFBOs_.end(); ) { - int age = frameLastFramebufUsed - it->second.last_frame_used; + int age = frameLastFramebufUsed_ - it->second.last_frame_used; if (age > FBO_OLD_AGE) { fbo_destroy(it->second.fbo); tempFBOs_.erase(it++); @@ -2102,7 +2012,7 @@ void FramebufferManager::DecimateFBOs() { // Do the same for ReadFramebuffersToMemory's VFBs for (size_t i = 0; i < bvfbs_.size(); ++i) { VirtualFramebuffer *vfb = bvfbs_[i]; - int age = frameLastFramebufUsed - vfb->last_frame_render; + int age = frameLastFramebufUsed_ - vfb->last_frame_render; 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); DestroyFramebuf(vfb); diff --git a/GPU/GLES/Framebuffer.h b/GPU/GLES/Framebuffer.h index ec5d564b43..54744c9df3 100644 --- a/GPU/GLES/Framebuffer.h +++ b/GPU/GLES/Framebuffer.h @@ -30,74 +30,13 @@ #include "../Globals.h" #include "GPU/GPUCommon.h" +#include "GPU/Common/FramebufferCommon.h" struct GLSLProgram; class TextureCache; class TransformDrawEngine; class ShaderManager; -enum { - FB_USAGE_DISPLAYED_FRAMEBUFFER = 1, - FB_USAGE_RENDERTARGET = 2, - FB_USAGE_TEXTURE = 4, -}; - -enum { - FB_NON_BUFFERED_MODE = 0, - FB_BUFFERED_MODE = 1, - - // Hm, it's unfortunate that GPU has ended up as two separate values in GL and GLES. -#ifndef USING_GLES2 - FB_READFBOMEMORY_CPU = 2, - FB_READFBOMEMORY_GPU = 3, -#else - FB_READFBOMEMORY_GPU = 2, -#endif - FBO_READFBOMEMORY_MIN = 2 -}; - -struct VirtualFramebuffer { - int last_frame_used; - int last_frame_attached; - int last_frame_render; - bool memoryUpdated; - bool depthUpdated; - - u32 fb_address; - u32 z_address; - int fb_stride; - int z_stride; - - // There's also a top left of the drawing region, but meh... - - // width/height: The detected size of the current framebuffer. - u16 width; - u16 height; - // renderWidth/renderHeight: The actual size we render at. May be scaled to render at higher resolutions. - u16 renderWidth; - u16 renderHeight; - // bufferWidth/bufferHeight: The actual (but non scaled) size of the buffer we render to. May only be bigger than width/height. - u16 bufferWidth; - u16 bufferHeight; - - u16 usageFlags; - - u16 newWidth; - u16 newHeight; - int lastFrameNewSize; - - GEBufferFormat format; // virtual, right now they are all RGBA8888 - FBOColorDepth colorDepth; - FBO *fbo; - - u16 drawnWidth; - u16 drawnHeight; - GEBufferFormat drawnFormat; - - bool dirtyAfterDisplay; - bool reallyDirtyAfterDisplay; // takes frame skipping into account -}; - void CenterRect(float *x, float *y, float *w, float *h, float origW, float origH, float frameW, float frameH); @@ -117,7 +56,7 @@ struct AsyncPBO { #endif -class FramebufferManager { +class FramebufferManager : public FramebufferManagerCommon { public: FramebufferManager(); ~FramebufferManager(); @@ -152,18 +91,7 @@ public: void Resized(); void DeviceLost(); void CopyDisplayToOutput(); - void DoSetRenderFrameBuffer(); // Uses parameters computed from gstate - void SetRenderFrameBuffer() { - // Inlining this part since it's so frequent. - if (!gstate_c.framebufChanged && currentRenderVfb_) { - currentRenderVfb_->last_frame_render = gpuStats.numFlips; - currentRenderVfb_->dirtyAfterDisplay = true; - if (!gstate_c.skipDrawReason) - currentRenderVfb_->reallyDirtyAfterDisplay = true; - return; - } - DoSetRenderFrameBuffer(); - } + virtual void DoSetRenderFrameBuffer() override; // Uses parameters computed from gstate void UpdateFromMemory(u32 addr, int size, bool safe); void SetLineWidth(); void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old); @@ -187,48 +115,9 @@ public: VirtualFramebuffer *GetDisplayVFB() { return GetVFBAt(displayFramebufPtr_); } - void SetDisplayFramebuffer(u32 framebuf, u32 stride, GEBufferFormat format); - size_t NumVFBs() const { return vfbs_.size(); } std::vector GetFramebufferList(); - int GetRenderWidth() const { return currentRenderVfb_ ? currentRenderVfb_->renderWidth : 480; } - int GetRenderHeight() const { return currentRenderVfb_ ? currentRenderVfb_->renderHeight : 272; } - int GetTargetWidth() const { return currentRenderVfb_ ? currentRenderVfb_->width : 480; } - int GetTargetHeight() const { return currentRenderVfb_ ? currentRenderVfb_->height : 272; } - int GetTargetBufferWidth() const { return currentRenderVfb_ ? currentRenderVfb_->bufferWidth : 480; } - int GetTargetBufferHeight() const { return currentRenderVfb_ ? currentRenderVfb_->bufferHeight : 272; } - int GetTargetStride() const { return currentRenderVfb_ ? currentRenderVfb_->fb_stride : 512; } - GEBufferFormat GetTargetFormat() const { return currentRenderVfb_ ? currentRenderVfb_->format : displayFormat_; } - - u32 PrevDisplayFramebufAddr() { - return prevDisplayFramebuf_ ? (0x04000000 | prevDisplayFramebuf_->fb_address) : 0; - } - u32 DisplayFramebufAddr() { - return displayFramebuf_ ? (0x04000000 | displayFramebuf_->fb_address) : 0; - } - - void SetDepthUpdated() { - if (currentRenderVfb_) { - currentRenderVfb_->depthUpdated = true; - } - } - void SetColorUpdated() { - if (currentRenderVfb_) { - SetColorUpdated(currentRenderVfb_); - } - } - - bool MayIntersectFramebuffer(u32 start) { - // Clear the cache/kernel bits. - start = start & 0x3FFFFFFF; - // Most games only have two framebuffers at the start. - if (start >= framebufRangeEnd_ || start < PSP_GetVidMemBase()) { - return false; - } - return true; - } - bool NotifyFramebufferCopy(u32 src, u32 dest, int size, bool isMemset = false); bool NotifyStencilUpload(u32 addr, int size, bool skipZero = false); @@ -243,6 +132,11 @@ public: FBO *GetTempFBO(u16 w, u16 h, FBOColorDepth depth = FBO_8888); +protected: + virtual void DisableState() override; + virtual void ClearBuffer() override; + virtual void ClearDepthBuffer() override; + private: void CompileDraw2DProgram(); void DestroyDraw2DProgram(); @@ -253,38 +147,11 @@ private: void SetNumExtraFBOs(int num); - void EstimateDrawingSize(int &drawing_width, int &drawing_height); - static void DisableState(); - static void ClearBuffer(); - static void ClearDepthBuffer(); static bool MaskedEqual(u32 addr1, u32 addr2); inline bool ShouldDownloadFramebuffer(const VirtualFramebuffer *vfb) const; inline bool ShouldDownloadUsingCPU(const VirtualFramebuffer *vfb) const; - void SetColorUpdated(VirtualFramebuffer *dstBuffer) { - dstBuffer->memoryUpdated = false; - dstBuffer->dirtyAfterDisplay = true; - dstBuffer->drawnWidth = dstBuffer->width; - dstBuffer->drawnHeight = dstBuffer->height; - dstBuffer->drawnFormat = dstBuffer->format; - if ((gstate_c.skipDrawReason & SKIPDRAW_SKIPFRAME) == 0) - dstBuffer->reallyDirtyAfterDisplay = true; - } - - u32 displayFramebufPtr_; - u32 displayStride_; - GEBufferFormat displayFormat_; - - VirtualFramebuffer *displayFramebuf_; - VirtualFramebuffer *prevDisplayFramebuf_; - VirtualFramebuffer *prevPrevDisplayFramebuf_; - int frameLastFramebufUsed; - - std::vector vfbs_; - - VirtualFramebuffer *currentRenderVfb_; - // 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, bool flip = false); #ifndef USING_GLES2 @@ -323,9 +190,6 @@ private: bool hackForce04154000Download_; - // The range of PSP memory that may contain FBOs. So we can skip iterating. - u32 framebufRangeEnd_; - struct TempFBO { FBO *fbo; int last_frame_used; diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index a556418a3d..847c215780 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -161,6 +161,7 @@ + @@ -217,6 +218,7 @@ + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 4b1b880a03..51c5e72990 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -171,6 +171,9 @@ GLES + + Common + @@ -323,6 +326,9 @@ GLES + + Common + diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 675d02d0db..b29776044c 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -136,6 +136,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/GPU/GPUCommon.cpp \ $(SRC)/GPU/GPUState.cpp \ $(SRC)/GPU/GeDisasm.cpp \ + $(SRC)/GPU/Common/FramebufferCommon.cpp \ $(SRC)/GPU/Common/IndexGenerator.cpp.arm \ $(SRC)/GPU/Common/VertexDecoderCommon.cpp.arm \ $(SRC)/GPU/Common/TransformCommon.cpp.arm \