mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
d3d: Begin centralizing framebuffer management.
This commit is contained in:
parent
7d6377295a
commit
8c229e00b4
@ -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
|
||||
|
117
GPU/Common/FramebufferCommon.cpp
Normal file
117
GPU/Common/FramebufferCommon.cpp
Normal 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);
|
||||
}
|
182
GPU/Common/FramebufferCommon.h
Normal file
182
GPU/Common/FramebufferCommon.h
Normal 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_;
|
||||
};
|
@ -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);
|
||||
}
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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_;
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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">
|
||||
|
@ -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" />
|
||||
|
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user