Move all the framebuffer management out into its own file.
This commit is contained in:
parent
b2020ee243
commit
64a376516e
4 changed files with 301 additions and 298 deletions
|
@ -15,11 +15,11 @@
|
|||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "../../Core/MemMap.h"
|
||||
#include "../../Core/Host.h"
|
||||
#include "../../Core/Config.h"
|
||||
#include "../../Core/System.h"
|
||||
#include "../../native/gfx_es2/gl_state.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/System.h"
|
||||
#include "gfx_es2/gl_state.h"
|
||||
|
||||
#include "../GPUState.h"
|
||||
#include "../ge_constants.h"
|
||||
|
@ -37,12 +37,7 @@
|
|||
extern u32 curTextureWidth;
|
||||
extern u32 curTextureHeight;
|
||||
|
||||
// Aggressively delete unused FBO:s to save gpu memory.
|
||||
enum {
|
||||
FBO_OLD_AGE = 4
|
||||
};
|
||||
|
||||
const int flushOnChangedBeforeCommandList[] = {
|
||||
static const int flushOnChangedBeforeCommandList[] = {
|
||||
GE_CMD_VERTEXTYPE,
|
||||
GE_CMD_BLENDMODE,
|
||||
GE_CMD_BLENDFIXEDA,
|
||||
|
@ -121,7 +116,7 @@ const int flushOnChangedBeforeCommandList[] = {
|
|||
GE_CMD_MASKALPHA,
|
||||
};
|
||||
|
||||
const int flushBeforeCommandList[] = {
|
||||
static const int flushBeforeCommandList[] = {
|
||||
GE_CMD_BEZIER,
|
||||
GE_CMD_SPLINE,
|
||||
GE_CMD_SIGNAL,
|
||||
|
@ -165,9 +160,6 @@ const int flushBeforeCommandList[] = {
|
|||
|
||||
GLES_GPU::GLES_GPU()
|
||||
: interruptsEnabled_(true),
|
||||
displayFramebufPtr_(0),
|
||||
prevDisplayFramebuf_(0),
|
||||
prevPrevDisplayFramebuf_(0),
|
||||
resized_(false)
|
||||
{
|
||||
shaderManager_ = new ShaderManager();
|
||||
|
@ -191,11 +183,7 @@ GLES_GPU::GLES_GPU()
|
|||
}
|
||||
|
||||
GLES_GPU::~GLES_GPU() {
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) {
|
||||
fbo_destroy((*iter)->fbo);
|
||||
delete (*iter);
|
||||
}
|
||||
vfbs_.clear();
|
||||
framebufferManager_.DestroyAllFBOs();
|
||||
shaderManager_->ClearCache(true);
|
||||
delete shaderManager_;
|
||||
delete [] flushBeforeCommand_;
|
||||
|
@ -221,9 +209,21 @@ void GLES_GPU::DumpNextFrame() {
|
|||
dumpNextFrame_ = true;
|
||||
}
|
||||
|
||||
void GLES_GPU::BeginDebugDraw() {
|
||||
if (g_Config.bDrawWireframe) {
|
||||
#ifndef USING_GLES2
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
void GLES_GPU::EndDebugDraw() {
|
||||
#ifndef USING_GLES2
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GLES_GPU::BeginFrame() {
|
||||
textureCache_.StartFrame();
|
||||
DecimateFBOs();
|
||||
transformDraw_.DecimateTrackedVertexArrays();
|
||||
|
||||
if (dumpNextFrame_) {
|
||||
|
@ -238,28 +238,11 @@ void GLES_GPU::BeginFrame() {
|
|||
// Not sure if this is really needed.
|
||||
shaderManager_->DirtyUniform(DIRTY_ALL);
|
||||
|
||||
// NOTE - this is all wrong. At the beginning of the frame is a TERRIBLE time to draw the fb.
|
||||
if (g_Config.bDisplayFramebuffer && displayFramebufPtr_) {
|
||||
INFO_LOG(HLE, "Drawing the framebuffer");
|
||||
const u8 *pspframebuf = Memory::GetPointer((0x44000000) | (displayFramebufPtr_ & 0x1FFFFF)); // TODO - check
|
||||
glstate.cullFace.disable();
|
||||
glstate.depthTest.disable();
|
||||
glstate.blend.disable();
|
||||
framebufferManager.DrawPixels(pspframebuf, displayFormat_, displayStride_);
|
||||
// TODO: restore state?
|
||||
}
|
||||
currentRenderVfb_ = 0;
|
||||
framebufferManager_.BeginFrame();
|
||||
}
|
||||
|
||||
void GLES_GPU::SetDisplayFramebuffer(u32 framebuf, u32 stride, int format) {
|
||||
if (framebuf & 0x04000000) {
|
||||
//DEBUG_LOG(G3D, "Switch display framebuffer %08x", framebuf);
|
||||
displayFramebufPtr_ = framebuf;
|
||||
displayStride_ = stride;
|
||||
displayFormat_ = format;
|
||||
} else {
|
||||
ERROR_LOG(HLE, "Bogus framebuffer address: %08x", framebuf);
|
||||
}
|
||||
framebufferManager_.SetDisplayFramebuffer(framebuf, stride, format);
|
||||
}
|
||||
|
||||
void GLES_GPU::CopyDisplayToOutput() {
|
||||
|
@ -269,200 +252,15 @@ void GLES_GPU::CopyDisplayToOutput() {
|
|||
|
||||
EndDebugDraw();
|
||||
|
||||
fbo_unbind();
|
||||
|
||||
VirtualFramebuffer *vfb = GetDisplayFBO();
|
||||
if (!vfb) {
|
||||
DEBUG_LOG(HLE, "Found no FBO! displayFBPtr = %08x", displayFramebufPtr_);
|
||||
// No framebuffer to display! Clear to black.
|
||||
glClearColor(0,0,0,1);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
return;
|
||||
}
|
||||
|
||||
prevPrevDisplayFramebuf_ = prevDisplayFramebuf_;
|
||||
prevDisplayFramebuf_ = displayFramebuf_;
|
||||
displayFramebuf_ = vfb;
|
||||
|
||||
glstate.viewport.set(0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight);
|
||||
|
||||
currentRenderVfb_ = 0;
|
||||
|
||||
DEBUG_LOG(HLE, "Displaying FBO %08x", vfb->fb_address);
|
||||
glstate.blend.disable();
|
||||
glstate.cullFace.disable();
|
||||
glstate.depthTest.disable();
|
||||
glstate.scissorTest.disable();
|
||||
|
||||
fbo_bind_color_as_texture(vfb->fbo, 0);
|
||||
|
||||
// These are in the output display coordinates
|
||||
framebufferManager.DrawActiveTexture(480, 272, true);
|
||||
framebufferManager_.CopyDisplayToOutput();
|
||||
|
||||
shaderManager_->DirtyShader();
|
||||
shaderManager_->DirtyUniform(DIRTY_ALL);
|
||||
gstate_c.textureChanged = true;
|
||||
|
||||
if (resized_) {
|
||||
DestroyAllFBOs();
|
||||
glstate.viewport.set(0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight);
|
||||
resized_ = false;
|
||||
}
|
||||
|
||||
BeginDebugDraw();
|
||||
}
|
||||
|
||||
void GLES_GPU::DecimateFBOs() {
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end();) {
|
||||
VirtualFramebuffer *v = *iter;
|
||||
if (v == displayFramebuf_ ||
|
||||
v == prevDisplayFramebuf_ ||
|
||||
v == prevPrevDisplayFramebuf_) {
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
if ((*iter)->last_frame_used + FBO_OLD_AGE < gpuStats.numFrames) {
|
||||
INFO_LOG(HLE, "Destroying FBO %i (%i x %i x %i)", v->fb_address, v->width, v->height, v->format);
|
||||
fbo_destroy(v->fbo);
|
||||
delete v;
|
||||
vfbs_.erase(iter++);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
static bool MaskedEqual(u32 addr1, u32 addr2) {
|
||||
return (addr1 & 0x3FFFFFF) == (addr2 & 0x3FFFFFF);
|
||||
}
|
||||
|
||||
GLES_GPU::VirtualFramebuffer *GLES_GPU::GetDisplayFBO() {
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) {
|
||||
VirtualFramebuffer *v = *iter;
|
||||
if (MaskedEqual(v->fb_address, displayFramebufPtr_) && v->format == displayFormat_) {
|
||||
// Could check w too but whatever
|
||||
return *iter;
|
||||
}
|
||||
}
|
||||
DEBUG_LOG(HLE, "Finding no FBO matching address %08x", displayFramebufPtr_);
|
||||
#if 0 // defined(_DEBUG)
|
||||
std::string debug = "FBOs: ";
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) {
|
||||
char temp[256];
|
||||
sprintf(temp, "%08x %i %i", (*iter)->fb_address, (*iter)->width, (*iter)->height);
|
||||
debug += std::string(temp);
|
||||
}
|
||||
ERROR_LOG(HLE, "FBOs: %s", debug.c_str());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GLES_GPU::SetRenderFrameBuffer() {
|
||||
if (!g_Config.bBufferedRendering)
|
||||
return;
|
||||
// Get parameters
|
||||
u32 fb_address = (gstate.fbptr & 0xFFE000) | ((gstate.fbwidth & 0xFF0000) << 8);
|
||||
int fb_stride = gstate.fbwidth & 0x3C0;
|
||||
|
||||
u32 z_address = (gstate.zbptr & 0xFFE000) | ((gstate.zbwidth & 0xFF0000) << 8);
|
||||
int z_stride = gstate.zbwidth & 0x3C0;
|
||||
|
||||
// Yeah this is not completely right. but it'll do for now.
|
||||
int drawing_width = ((gstate.region2) & 0x3FF) + 1;
|
||||
int drawing_height = ((gstate.region2 >> 10) & 0x3FF) + 1;
|
||||
|
||||
// HACK for first frame where some games don't init things right
|
||||
if (drawing_width == 1 && drawing_height == 1) {
|
||||
drawing_width = 480;
|
||||
drawing_height = 272;
|
||||
}
|
||||
|
||||
int fmt = gstate.framebufpixformat & 3;
|
||||
|
||||
// Find a matching framebuffer
|
||||
VirtualFramebuffer *vfb = 0;
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) {
|
||||
VirtualFramebuffer *v = *iter;
|
||||
if (MaskedEqual(v->fb_address, fb_address) && v->width == drawing_width && v->height == drawing_height && v->format == fmt) {
|
||||
// Let's not be so picky for now. Let's say this is the one.
|
||||
vfb = v;
|
||||
// Update fb stride in case it changed
|
||||
vfb->fb_stride = fb_stride;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// None found? Create one.
|
||||
if (!vfb) {
|
||||
transformDraw_.Flush();
|
||||
gstate_c.textureChanged = true;
|
||||
vfb = new VirtualFramebuffer();
|
||||
vfb->fb_address = fb_address;
|
||||
vfb->fb_stride = fb_stride;
|
||||
vfb->z_address = z_address;
|
||||
vfb->z_stride = z_stride;
|
||||
vfb->width = drawing_width;
|
||||
vfb->height = drawing_height;
|
||||
vfb->format = fmt;
|
||||
|
||||
vfb->colorDepth = FBO_8888;
|
||||
switch (fmt) {
|
||||
case GE_FORMAT_4444: vfb->colorDepth = FBO_4444;
|
||||
case GE_FORMAT_5551: vfb->colorDepth = FBO_5551;
|
||||
case GE_FORMAT_565: vfb->colorDepth = FBO_565;
|
||||
case GE_FORMAT_8888: vfb->colorDepth = FBO_8888;
|
||||
}
|
||||
//#ifdef ANDROID
|
||||
// vfb->colorDepth = FBO_8888;
|
||||
//#endif
|
||||
float renderWidthFactor = (float)PSP_CoreParameter().renderWidth / 480.0f;
|
||||
float renderHeightFactor = (float)PSP_CoreParameter().renderHeight / 272.0f;
|
||||
vfb->fbo = fbo_create(vfb->width * renderWidthFactor, vfb->height * renderHeightFactor, 1, true, vfb->colorDepth);
|
||||
|
||||
vfb->last_frame_used = gpuStats.numFrames;
|
||||
vfbs_.push_back(vfb);
|
||||
fbo_bind_as_render_target(vfb->fbo);
|
||||
glEnable(GL_DITHER);
|
||||
glstate.viewport.set(0, 0, PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight);
|
||||
currentRenderVfb_ = vfb;
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
INFO_LOG(HLE, "Creating FBO for %08x : %i x %i x %i", vfb->fb_address, vfb->width, vfb->height, vfb->format);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vfb != currentRenderVfb_) {
|
||||
transformDraw_.Flush();
|
||||
// Use it as a render target.
|
||||
DEBUG_LOG(HLE, "Switching render target to FBO for %08x", vfb->fb_address);
|
||||
gstate_c.textureChanged = true;
|
||||
fbo_bind_as_render_target(vfb->fbo);
|
||||
|
||||
#ifdef USING_GLES2
|
||||
// Tiled renderers benefit IMMENSELY from clearing an FBO before rendering
|
||||
// to it. Let's hope this doesn't break too many things...
|
||||
// It did, will have to find a better solution like clearing only if this is
|
||||
// the first time the buffer is bound on this frame.
|
||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
#endif
|
||||
glstate.viewport.set(0, 0, PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight);
|
||||
currentRenderVfb_ = vfb;
|
||||
vfb->last_frame_used = gpuStats.numFrames;
|
||||
}
|
||||
}
|
||||
|
||||
void GLES_GPU::BeginDebugDraw() {
|
||||
if (g_Config.bDrawWireframe) {
|
||||
#ifndef USING_GLES2
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
void GLES_GPU::EndDebugDraw() {
|
||||
#ifndef USING_GLES2
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Render queue
|
||||
|
||||
void GLES_GPU::DrawSync(int mode)
|
||||
|
@ -531,7 +329,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff) {
|
|||
|
||||
case GE_CMD_PRIM:
|
||||
{
|
||||
SetRenderFrameBuffer();
|
||||
framebufferManager_.SetRenderFrameBuffer();
|
||||
|
||||
u32 count = data & 0xFFFF;
|
||||
u32 type = data >> 16;
|
||||
|
@ -1193,7 +991,7 @@ void GLES_GPU::UpdateStats() {
|
|||
gpuStats.numFragmentShaders = shaderManager_->NumFragmentShaders();
|
||||
gpuStats.numShaders = shaderManager_->NumPrograms();
|
||||
gpuStats.numTextures = textureCache_.NumLoadedTextures();
|
||||
gpuStats.numFBOs = (int)vfbs_.size();
|
||||
gpuStats.numFBOs = framebufferManager_.NumVFBs();
|
||||
}
|
||||
|
||||
void GLES_GPU::DoBlockTransfer() {
|
||||
|
@ -1255,15 +1053,6 @@ void GLES_GPU::Flush() {
|
|||
transformDraw_.Flush();
|
||||
}
|
||||
|
||||
void GLES_GPU::DestroyAllFBOs() {
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) {
|
||||
VirtualFramebuffer *v = *iter;
|
||||
fbo_destroy(v->fbo);
|
||||
delete v;
|
||||
}
|
||||
vfbs_.clear();
|
||||
}
|
||||
|
||||
void GLES_GPU::Resized() {
|
||||
resized_ = true;
|
||||
}
|
||||
|
@ -1274,6 +1063,6 @@ void GLES_GPU::DoState(PointerWrap &p) {
|
|||
textureCache_.Clear(true);
|
||||
|
||||
gstate_c.textureChanged = true;
|
||||
DestroyAllFBOs();
|
||||
framebufferManager_.DestroyAllFBOs();
|
||||
shaderManager_->ClearCache(true);
|
||||
}
|
||||
|
|
|
@ -68,11 +68,7 @@ private:
|
|||
void BeginDebugDraw();
|
||||
void EndDebugDraw();
|
||||
|
||||
// Deletes old FBOs.
|
||||
void DecimateFBOs();
|
||||
void DestroyAllFBOs();
|
||||
|
||||
FramebufferManager framebufferManager;
|
||||
FramebufferManager framebufferManager_;
|
||||
TextureCache textureCache_;
|
||||
TransformDrawEngine transformDraw_;
|
||||
ShaderManager *shaderManager_;
|
||||
|
@ -80,45 +76,4 @@ private:
|
|||
u8 *flushBeforeCommand_;
|
||||
bool interruptsEnabled_;
|
||||
bool resized_;
|
||||
|
||||
u32 displayFramebufPtr_;
|
||||
u32 displayStride_;
|
||||
int displayFormat_;
|
||||
|
||||
struct CmdProcessorState {
|
||||
u32 pc;
|
||||
u32 stallAddr;
|
||||
int subIntrBase;
|
||||
};
|
||||
|
||||
struct VirtualFramebuffer {
|
||||
int last_frame_used;
|
||||
|
||||
u32 fb_address;
|
||||
u32 z_address;
|
||||
int fb_stride;
|
||||
int z_stride;
|
||||
|
||||
// There's also a top left of the drawing region, but meh...
|
||||
int width;
|
||||
int height;
|
||||
|
||||
int format; // virtual, right now they are all RGBA8888
|
||||
FBOColorDepth colorDepth;
|
||||
FBO *fbo;
|
||||
};
|
||||
|
||||
VirtualFramebuffer *displayFramebuf_;
|
||||
VirtualFramebuffer *prevDisplayFramebuf_;
|
||||
VirtualFramebuffer *prevPrevDisplayFramebuf_;
|
||||
|
||||
void SetRenderFrameBuffer(); // Uses parameters computed from gstate
|
||||
// TODO: Break out into some form of FBO manager
|
||||
VirtualFramebuffer *GetDisplayFBO();
|
||||
|
||||
std::list<VirtualFramebuffer *> vfbs_;
|
||||
|
||||
VirtualFramebuffer *currentRenderVfb_;
|
||||
|
||||
u8 bezierBuf[16000];
|
||||
};
|
||||
|
|
|
@ -17,16 +17,20 @@
|
|||
|
||||
#include "gfx_es2/glsl_program.h"
|
||||
#include "gfx_es2/gl_state.h"
|
||||
#include "gfx_es2/fbo.h"
|
||||
|
||||
#include "math/lin/matrix4x4.h"
|
||||
|
||||
#include "../../Core/Host.h"
|
||||
#include "../../Core/MemMap.h"
|
||||
#include "../ge_constants.h"
|
||||
#include "../GPUState.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/System.h"
|
||||
#include "GPU/ge_constants.h"
|
||||
#include "GPU/GPUState.h"
|
||||
|
||||
#include "Framebuffer.h"
|
||||
#include "GPU/GLES/Framebuffer.h"
|
||||
|
||||
const char tex_fs[] =
|
||||
static const char tex_fs[] =
|
||||
"#ifdef GL_ES\n"
|
||||
"precision mediump float;\n"
|
||||
"#endif\n"
|
||||
|
@ -36,7 +40,7 @@ const char tex_fs[] =
|
|||
" gl_FragColor = texture2D(sampler0, v_texcoord0);\n"
|
||||
"}\n";
|
||||
|
||||
const char basic_vs[] =
|
||||
static const char basic_vs[] =
|
||||
#ifndef USING_GLES2
|
||||
"#version 120\n"
|
||||
#endif
|
||||
|
@ -50,7 +54,20 @@ const char basic_vs[] =
|
|||
" gl_Position = u_viewproj * a_position;\n"
|
||||
"}\n";
|
||||
|
||||
FramebufferManager::FramebufferManager() {
|
||||
// Aggressively delete unused FBO:s to save gpu memory.
|
||||
enum {
|
||||
FBO_OLD_AGE = 5
|
||||
};
|
||||
|
||||
static bool MaskedEqual(u32 addr1, u32 addr2) {
|
||||
return (addr1 & 0x3FFFFFF) == (addr2 & 0x3FFFFFF);
|
||||
}
|
||||
|
||||
FramebufferManager::FramebufferManager() :
|
||||
displayFramebufPtr_(0),
|
||||
prevDisplayFramebuf_(0),
|
||||
prevPrevDisplayFramebuf_(0)
|
||||
{
|
||||
glGenTextures(1, &backbufTex);
|
||||
|
||||
//initialize backbuffer texture
|
||||
|
@ -177,3 +194,207 @@ void FramebufferManager::DrawActiveTexture(float w, float h, bool flip) {
|
|||
glDisableVertexAttribArray(draw2dprogram->a_texcoord0);
|
||||
glsl_unbind();
|
||||
}
|
||||
|
||||
FramebufferManager::VirtualFramebuffer *FramebufferManager::GetDisplayFBO() {
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) {
|
||||
VirtualFramebuffer *v = *iter;
|
||||
if (MaskedEqual(v->fb_address, displayFramebufPtr_) && v->format == displayFormat_) {
|
||||
// Could check w too but whatever
|
||||
return *iter;
|
||||
}
|
||||
}
|
||||
DEBUG_LOG(HLE, "Finding no FBO matching address %08x", displayFramebufPtr_);
|
||||
#if 0 // defined(_DEBUG)
|
||||
std::string debug = "FBOs: ";
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) {
|
||||
char temp[256];
|
||||
sprintf(temp, "%08x %i %i", (*iter)->fb_address, (*iter)->width, (*iter)->height);
|
||||
debug += std::string(temp);
|
||||
}
|
||||
ERROR_LOG(HLE, "FBOs: %s", debug.c_str());
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FramebufferManager::SetRenderFrameBuffer() {
|
||||
if (!g_Config.bBufferedRendering)
|
||||
return;
|
||||
// Get parameters
|
||||
u32 fb_address = (gstate.fbptr & 0xFFE000) | ((gstate.fbwidth & 0xFF0000) << 8);
|
||||
int fb_stride = gstate.fbwidth & 0x3C0;
|
||||
|
||||
u32 z_address = (gstate.zbptr & 0xFFE000) | ((gstate.zbwidth & 0xFF0000) << 8);
|
||||
int z_stride = gstate.zbwidth & 0x3C0;
|
||||
|
||||
// Yeah this is not completely right. but it'll do for now.
|
||||
int drawing_width = ((gstate.region2) & 0x3FF) + 1;
|
||||
int drawing_height = ((gstate.region2 >> 10) & 0x3FF) + 1;
|
||||
|
||||
// HACK for first frame where some games don't init things right
|
||||
if (drawing_width == 1 && drawing_height == 1) {
|
||||
drawing_width = 480;
|
||||
drawing_height = 272;
|
||||
}
|
||||
|
||||
int fmt = gstate.framebufpixformat & 3;
|
||||
|
||||
// Find a matching framebuffer
|
||||
VirtualFramebuffer *vfb = 0;
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) {
|
||||
VirtualFramebuffer *v = *iter;
|
||||
if (MaskedEqual(v->fb_address, fb_address) && v->width == drawing_width && v->height == drawing_height && v->format == fmt) {
|
||||
// Let's not be so picky for now. Let's say this is the one.
|
||||
vfb = v;
|
||||
// Update fb stride in case it changed
|
||||
vfb->fb_stride = fb_stride;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// None found? Create one.
|
||||
if (!vfb) {
|
||||
gstate_c.textureChanged = true;
|
||||
vfb = new VirtualFramebuffer();
|
||||
vfb->fb_address = fb_address;
|
||||
vfb->fb_stride = fb_stride;
|
||||
vfb->z_address = z_address;
|
||||
vfb->z_stride = z_stride;
|
||||
vfb->width = drawing_width;
|
||||
vfb->height = drawing_height;
|
||||
vfb->format = fmt;
|
||||
|
||||
vfb->colorDepth = FBO_8888;
|
||||
switch (fmt) {
|
||||
case GE_FORMAT_4444: vfb->colorDepth = FBO_4444;
|
||||
case GE_FORMAT_5551: vfb->colorDepth = FBO_5551;
|
||||
case GE_FORMAT_565: vfb->colorDepth = FBO_565;
|
||||
case GE_FORMAT_8888: vfb->colorDepth = FBO_8888;
|
||||
}
|
||||
//#ifdef ANDROID
|
||||
// vfb->colorDepth = FBO_8888;
|
||||
//#endif
|
||||
float renderWidthFactor = (float)PSP_CoreParameter().renderWidth / 480.0f;
|
||||
float renderHeightFactor = (float)PSP_CoreParameter().renderHeight / 272.0f;
|
||||
vfb->fbo = fbo_create((int)(vfb->width * renderWidthFactor), (int)(vfb->height * renderHeightFactor), 1, true, vfb->colorDepth);
|
||||
|
||||
vfb->last_frame_used = gpuStats.numFrames;
|
||||
vfbs_.push_back(vfb);
|
||||
fbo_bind_as_render_target(vfb->fbo);
|
||||
glEnable(GL_DITHER);
|
||||
glstate.viewport.set(0, 0, PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight);
|
||||
currentRenderVfb_ = vfb;
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
INFO_LOG(HLE, "Creating FBO for %08x : %i x %i x %i", vfb->fb_address, vfb->width, vfb->height, vfb->format);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vfb != currentRenderVfb_) {
|
||||
// Use it as a render target.
|
||||
DEBUG_LOG(HLE, "Switching render target to FBO for %08x", vfb->fb_address);
|
||||
gstate_c.textureChanged = true;
|
||||
fbo_bind_as_render_target(vfb->fbo);
|
||||
|
||||
#ifdef USING_GLES2
|
||||
// Tiled renderers benefit IMMENSELY from clearing an FBO before rendering
|
||||
// to it. Let's hope this doesn't break too many things...
|
||||
// It did, will have to find a better solution like clearing only if this is
|
||||
// the first time the buffer is bound on this frame.
|
||||
// glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
#endif
|
||||
glstate.viewport.set(0, 0, PSP_CoreParameter().renderWidth, PSP_CoreParameter().renderHeight);
|
||||
currentRenderVfb_ = vfb;
|
||||
vfb->last_frame_used = gpuStats.numFrames;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void FramebufferManager::CopyDisplayToOutput() {
|
||||
fbo_unbind();
|
||||
|
||||
VirtualFramebuffer *vfb = GetDisplayFBO();
|
||||
if (!vfb) {
|
||||
DEBUG_LOG(HLE, "Found no FBO! displayFBPtr = %08x", displayFramebufPtr_);
|
||||
// No framebuffer to display! Clear to black.
|
||||
glClearColor(0,0,0,1);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
return;
|
||||
}
|
||||
|
||||
prevPrevDisplayFramebuf_ = prevDisplayFramebuf_;
|
||||
prevDisplayFramebuf_ = displayFramebuf_;
|
||||
displayFramebuf_ = vfb;
|
||||
|
||||
glstate.viewport.set(0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight);
|
||||
|
||||
currentRenderVfb_ = 0;
|
||||
|
||||
DEBUG_LOG(HLE, "Displaying FBO %08x", vfb->fb_address);
|
||||
glstate.blend.disable();
|
||||
glstate.cullFace.disable();
|
||||
glstate.depthTest.disable();
|
||||
glstate.scissorTest.disable();
|
||||
|
||||
fbo_bind_color_as_texture(vfb->fbo, 0);
|
||||
|
||||
// These are in the output display coordinates
|
||||
DrawActiveTexture(480, 272, true);
|
||||
|
||||
if (resized_) {
|
||||
DestroyAllFBOs();
|
||||
glstate.viewport.set(0, 0, PSP_CoreParameter().pixelWidth, PSP_CoreParameter().pixelHeight);
|
||||
resized_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManager::BeginFrame() {
|
||||
DecimateFBOs();
|
||||
// NOTE - this is all wrong. At the beginning of the frame is a TERRIBLE time to draw the fb.
|
||||
if (g_Config.bDisplayFramebuffer && displayFramebufPtr_) {
|
||||
INFO_LOG(HLE, "Drawing the framebuffer");
|
||||
const u8 *pspframebuf = Memory::GetPointer((0x44000000) | (displayFramebufPtr_ & 0x1FFFFF)); // TODO - check
|
||||
glstate.cullFace.disable();
|
||||
glstate.depthTest.disable();
|
||||
glstate.blend.disable();
|
||||
DrawPixels(pspframebuf, displayFormat_, displayStride_);
|
||||
// TODO: restore state?
|
||||
}
|
||||
currentRenderVfb_ = 0;
|
||||
}
|
||||
|
||||
void FramebufferManager::SetDisplayFramebuffer(u32 framebuf, u32 stride, int format) {
|
||||
if (framebuf & 0x04000000) {
|
||||
//DEBUG_LOG(G3D, "Switch display framebuffer %08x", framebuf);
|
||||
displayFramebufPtr_ = framebuf;
|
||||
displayStride_ = stride;
|
||||
displayFormat_ = format;
|
||||
} else {
|
||||
ERROR_LOG(HLE, "Bogus framebuffer address: %08x", framebuf);
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManager::DecimateFBOs() {
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end();) {
|
||||
VirtualFramebuffer *v = *iter;
|
||||
if (v == displayFramebuf_ || v == prevDisplayFramebuf_ || v == prevPrevDisplayFramebuf_) {
|
||||
++iter;
|
||||
continue;
|
||||
}
|
||||
if ((*iter)->last_frame_used + FBO_OLD_AGE < gpuStats.numFrames) {
|
||||
INFO_LOG(HLE, "Destroying FBO %i (%i x %i x %i)", v->fb_address, v->width, v->height, v->format)
|
||||
fbo_destroy(v->fbo);
|
||||
delete v;
|
||||
vfbs_.erase(iter++);
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManager::DestroyAllFBOs() {
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) {
|
||||
VirtualFramebuffer *v = *iter;
|
||||
fbo_destroy(v->fbo);
|
||||
delete v;
|
||||
}
|
||||
vfbs_.clear();
|
||||
}
|
||||
|
|
|
@ -17,8 +17,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
// Keeps track of allocated FBOs.
|
||||
#include <list>
|
||||
|
||||
#include "gfx_es2/fbo.h"
|
||||
// Keeps track of allocated FBOs.
|
||||
// Also provides facilities for drawing and later converting raw
|
||||
// pixel data.
|
||||
|
||||
|
||||
#include "../Globals.h"
|
||||
|
@ -37,22 +41,56 @@ public:
|
|||
FramebufferManager();
|
||||
~FramebufferManager();
|
||||
|
||||
/* Better do this first:
|
||||
glstate.cullFace.disable();
|
||||
glstate.depthTest.disable();
|
||||
glstate.blend.disable();
|
||||
*/
|
||||
struct VirtualFramebuffer {
|
||||
int last_frame_used;
|
||||
|
||||
u32 fb_address;
|
||||
u32 z_address;
|
||||
int fb_stride;
|
||||
int z_stride;
|
||||
|
||||
// There's also a top left of the drawing region, but meh...
|
||||
int width;
|
||||
int height;
|
||||
|
||||
int format; // virtual, right now they are all RGBA8888
|
||||
FBOColorDepth colorDepth;
|
||||
FBO *fbo;
|
||||
};
|
||||
|
||||
void DrawPixels(const u8 *framebuf, int pixelFormat, int linesize);
|
||||
void DrawActiveTexture(float w, float h, bool flip = false);
|
||||
|
||||
void DestroyAllFBOs();
|
||||
void DecimateFBOs();
|
||||
|
||||
void BeginFrame();
|
||||
void CopyDisplayToOutput();
|
||||
void SetRenderFrameBuffer(); // Uses parameters computed from gstate
|
||||
// TODO: Break out into some form of FBO manager
|
||||
VirtualFramebuffer *GetDisplayFBO();
|
||||
void SetDisplayFramebuffer(u32 framebuf, u32 stride, int format);
|
||||
size_t NumVFBs() const { return vfbs_.size(); }
|
||||
|
||||
private:
|
||||
// Deletes old FBOs.
|
||||
|
||||
u32 displayFramebufPtr_;
|
||||
u32 displayStride_;
|
||||
int displayFormat_;
|
||||
|
||||
VirtualFramebuffer *displayFramebuf_;
|
||||
VirtualFramebuffer *prevDisplayFramebuf_;
|
||||
VirtualFramebuffer *prevPrevDisplayFramebuf_;
|
||||
|
||||
std::list<VirtualFramebuffer *> vfbs_;
|
||||
|
||||
VirtualFramebuffer *currentRenderVfb_;
|
||||
|
||||
// Used by DrawPixels
|
||||
unsigned int backbufTex;
|
||||
|
||||
u8 *convBuf;
|
||||
GLSLProgram *draw2dprogram;
|
||||
bool resized_;
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue