d3d: Begin centralizing framebuffer management.

This commit is contained in:
Unknown W. Brackets 2014-09-09 08:12:42 -07:00
parent 7d6377295a
commit 8c229e00b4
15 changed files with 412 additions and 451 deletions

View File

@ -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

View File

@ -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 <algorithm>
#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);
}

View File

@ -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 <vector>
#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<VirtualFramebuffer *> vfbs_;
};

View File

@ -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<FramebufferInfo> FramebufferManagerDX9::GetFramebufferList() {
std::vector<FramebufferInfo> 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);
}

View File

@ -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<FramebufferInfo> 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<VirtualFramebufferDX9 *> 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<VirtualFramebufferDX9 *> bvfbs_; // blitting FBOs
std::vector<VirtualFramebuffer *> bvfbs_; // blitting FBOs
std::set<std::pair<u32, u32>> knownFramebufferCopies_;

View File

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

View File

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

View File

@ -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<VirtualFramebufferDX9 *> fbCache_;
std::vector<VirtualFramebuffer *> fbCache_;
// Separate to keep main texture cache size down.
struct AttachedFramebufferInfo {
@ -184,8 +185,8 @@ private:
u32 yOffset;
};
std::map<u32, AttachedFramebufferInfo> 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_;

View File

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

View File

@ -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.

View File

@ -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<FramebufferInfo> FramebufferManager::GetFramebufferList() {
std::vector<FramebufferInfo> 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);

View File

@ -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<FramebufferInfo> 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<VirtualFramebuffer *> 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;

View File

@ -161,6 +161,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="..\ext\xbrz\xbrz.h" />
<ClInclude Include="Common\FramebufferCommon.h" />
<ClInclude Include="Common\GPUDebugInterface.h" />
<ClInclude Include="Common\IndexGenerator.h" />
<ClInclude Include="Common\PostShader.h" />
@ -217,6 +218,7 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\ext\xbrz\xbrz.cpp" />
<ClCompile Include="Common\FramebufferCommon.cpp" />
<ClCompile Include="Common\IndexGenerator.cpp" />
<ClCompile Include="Common\PostShader.cpp" />
<ClCompile Include="Common\TextureDecoderNEON.cpp">

View File

@ -171,6 +171,9 @@
<ClInclude Include="GLES\FragmentTestCache.h">
<Filter>GLES</Filter>
</ClInclude>
<ClInclude Include="Common\FramebufferCommon.h">
<Filter>Common</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Math3D.cpp">
@ -323,6 +326,9 @@
<ClCompile Include="GLES\FragmentTestCache.cpp">
<Filter>GLES</Filter>
</ClCompile>
<ClCompile Include="Common\FramebufferCommon.cpp">
<Filter>Common</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />

View File

@ -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 \