mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-10-07 10:53:31 +00:00
GL: Framebuffer management using FBOs. Fixes flicker in Lumines and many others.
This commit is contained in:
parent
91e1cce17e
commit
8b67975a47
@ -128,6 +128,7 @@ void hleEnterVblank(u64 userdata, int cyclesLate)
|
||||
DEBUG_LOG(HLE, "Setting latched framebuffer %08x (prev: %08x)", latchedFramebuf.topaddr, framebuf.topaddr);
|
||||
framebuf = latchedFramebuf;
|
||||
framebufIsLatched = false;
|
||||
gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.pspFramebufLinesize, framebuf.pspFramebufFormat);
|
||||
}
|
||||
|
||||
// Draw screen overlays before blitting. Saves and restores the Ge context.
|
||||
@ -145,9 +146,10 @@ void hleEnterVblank(u64 userdata, int cyclesLate)
|
||||
PPGeDrawText("This is PPGeDraw speaking", 10, 100, 0, 0.5f, 0xFFFFFFFF);
|
||||
PPGeEnd();
|
||||
*/
|
||||
// Yeah, this has to be the right moment to end the frame. Should possibly blit the right buffer
|
||||
// depending on what's set in sceDisplaySetFramebuf, in order to support half-framerate games -
|
||||
// an initial hack could be to NOT end the frame if the buffer didn't change? that should work okay.
|
||||
// Yeah, this has to be the right moment to end the frame. Give the graphics backend opportunity
|
||||
// to blit the framebuffer, in order to support half-framerate games that otherwise wouldn't have
|
||||
// anything to draw here.
|
||||
gpu->CopyDisplayToOutput();
|
||||
{
|
||||
host->EndFrame();
|
||||
host->BeginFrame();
|
||||
@ -215,6 +217,7 @@ void sceDisplaySetFramebuf()
|
||||
{
|
||||
// Write immediately to the current framebuffer parameters
|
||||
framebuf = fbstate;
|
||||
gpu->SetDisplayFramebuffer(framebuf.topaddr, framebuf.pspFramebufLinesize, framebuf.pspFramebufFormat);
|
||||
}
|
||||
else if (topaddr != 0)
|
||||
{
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "../../Core/MemMap.h"
|
||||
#include "../../Core/Host.h"
|
||||
#include "../../Core/Config.h"
|
||||
#include "../../Core/System.h"
|
||||
|
||||
#include "../GPUState.h"
|
||||
#include "../ge_constants.h"
|
||||
@ -53,14 +54,27 @@ ShaderManager shaderManager;
|
||||
extern u32 curTextureWidth;
|
||||
extern u32 curTextureHeight;
|
||||
|
||||
GLES_GPU::~GLES_GPU()
|
||||
{
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter)
|
||||
{
|
||||
fbo_destroy((*iter)->fbo);
|
||||
delete (*iter);
|
||||
}
|
||||
vfbs_.clear();
|
||||
}
|
||||
|
||||
void GLES_GPU::InitClear(int renderWidth, int renderHeight)
|
||||
{
|
||||
renderWidth_ = renderWidth;
|
||||
renderHeight_ = renderHeight;
|
||||
widthFactor_ = (float)renderWidth / 480.0f;
|
||||
heightFactor_ = (float)renderHeight / 272.0f;
|
||||
|
||||
glClearColor(0,0,0,1);
|
||||
// glClearColor(1,0,1,1);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
glViewport(0, 0, renderWidth_, renderHeight_);
|
||||
}
|
||||
|
||||
void GLES_GPU::BeginFrame()
|
||||
@ -75,14 +89,110 @@ void GLES_GPU::BeginFrame()
|
||||
|
||||
void GLES_GPU::SetDisplayFramebuffer(u32 framebuf, u32 stride, int format)
|
||||
{
|
||||
// TODO
|
||||
displayFramebufPtr_ = framebuf;
|
||||
displayStride_ = stride;
|
||||
displayFormat_ = format;
|
||||
}
|
||||
|
||||
void GLES_GPU::CopyDisplayToOutput()
|
||||
{
|
||||
// TODO
|
||||
VirtualFramebuffer *vfb = GetDisplayFBO();
|
||||
fbo_unbind();
|
||||
|
||||
glViewport(0, 0, PSP_CoreParameter().outputWidth, PSP_CoreParameter().outputHeight);
|
||||
|
||||
currentRenderVfb_ = 0;
|
||||
|
||||
if (!vfb) {
|
||||
// No framebuffer to display! Clear to black.
|
||||
glClearColor(0,0,0,1);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
return;
|
||||
}
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
fbo_bind_color_as_texture(vfb->fbo, 0);
|
||||
|
||||
// These are in the output pixel coordinates
|
||||
DrawActiveTexture(480, 272, true);
|
||||
|
||||
shaderManager.DirtyShader();
|
||||
shaderManager.DirtyUniform(DIRTY_ALL);
|
||||
|
||||
// Restore some state
|
||||
ExecuteOp(gstate.cmdmem[GE_CMD_CULLFACEENABLE], 0xFFFFFFFF);
|
||||
ExecuteOp(gstate.cmdmem[GE_CMD_ZTESTENABLE], 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
GLES_GPU::VirtualFramebuffer *GLES_GPU::GetDisplayFBO()
|
||||
{
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter)
|
||||
{
|
||||
if (((*iter)->fb_address & 0x3FFFFFF) == (displayFramebufPtr_ & 0x3FFFFFF)) {
|
||||
// Could check w to but whatever
|
||||
return *iter;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GLES_GPU::SetRenderFrameBuffer()
|
||||
{
|
||||
// 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;
|
||||
|
||||
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 (v->fb_address == fb_address) {
|
||||
// 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) {
|
||||
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->fbo = fbo_create(vfb->width * widthFactor_, vfb->height * heightFactor_, 1, true);
|
||||
vfbs_.push_back(vfb);
|
||||
fbo_bind_as_render_target(vfb->fbo);
|
||||
glViewport(0, 0, renderWidth_, renderHeight_);
|
||||
currentRenderVfb_ = vfb;
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vfb != currentRenderVfb_)
|
||||
{
|
||||
// Use it as a render target.
|
||||
fbo_bind_as_render_target(vfb->fbo);
|
||||
glViewport(0, 0, renderWidth_, renderHeight_);
|
||||
currentRenderVfb_ = vfb;
|
||||
}
|
||||
}
|
||||
|
||||
bool GLES_GPU::ProcessDLQueue()
|
||||
{
|
||||
@ -279,6 +389,8 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff)
|
||||
|
||||
case GE_CMD_PRIM:
|
||||
{
|
||||
SetRenderFrameBuffer();
|
||||
|
||||
u32 count = data & 0xFFFF;
|
||||
u32 type = data >> 16;
|
||||
static const char* types[7] = {
|
||||
@ -584,7 +696,11 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff)
|
||||
}
|
||||
break;
|
||||
|
||||
// case GE_CMD_TRANSFERSRC:
|
||||
case GE_CMD_TRANSFERSRC:
|
||||
{
|
||||
// Nothing to do, the next one prints
|
||||
}
|
||||
break;
|
||||
|
||||
case GE_CMD_TRANSFERSRCW:
|
||||
{
|
||||
@ -593,7 +709,12 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff)
|
||||
DEBUG_LOG(G3D,"Block Transfer Src: %08x W: %i", xferSrc, xferSrcW);
|
||||
break;
|
||||
}
|
||||
// case GE_CMD_TRANSFERDST:
|
||||
|
||||
case GE_CMD_TRANSFERDST:
|
||||
{
|
||||
// Nothing to do, the next one prints
|
||||
}
|
||||
break;
|
||||
|
||||
case GE_CMD_TRANSFERDSTW:
|
||||
{
|
||||
@ -629,7 +750,7 @@ void GLES_GPU::ExecuteOp(u32 op, u32 diff)
|
||||
|
||||
case GE_CMD_TRANSFERSTART:
|
||||
{
|
||||
DEBUG_LOG(G3D, "DL Texture Transfer Start: PixFormat %i", data);
|
||||
ERROR_LOG(G3D, "UNIMPL DL Block Transfer Start: PixFormat %i", data);
|
||||
// TODO: Here we should check if the transfer overlaps a framebuffer or any textures,
|
||||
// and take appropriate action. If not, this should just be a block transfer within
|
||||
// GPU memory which could be implemented by a copy loop.
|
||||
|
@ -17,16 +17,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include "../GPUInterface.h"
|
||||
|
||||
#include "gfx_es2/fbo.h"
|
||||
|
||||
class ShaderManager;
|
||||
|
||||
class GLES_GPU : public GPUInterface
|
||||
{
|
||||
public:
|
||||
GLES_GPU() : interruptsEnabled_(true), dlIdGenerator(1) {}
|
||||
~GLES_GPU();
|
||||
virtual void InitClear(int renderWidth, int renderHeight);
|
||||
virtual u32 EnqueueList(u32 listpc, u32 stall);
|
||||
virtual void UpdateStall(int listid, u32 newstall);
|
||||
@ -42,6 +46,7 @@ public:
|
||||
virtual void BeginFrame();
|
||||
|
||||
private:
|
||||
|
||||
bool ProcessDLQueue();
|
||||
bool interruptsEnabled_;
|
||||
|
||||
@ -52,6 +57,9 @@ private:
|
||||
int renderWidth_;
|
||||
int renderHeight_;
|
||||
|
||||
float widthFactor_;
|
||||
float heightFactor_;
|
||||
|
||||
struct CmdProcessorState
|
||||
{
|
||||
u32 pc;
|
||||
@ -76,6 +84,27 @@ private:
|
||||
u32 stackptr;
|
||||
bool finished;
|
||||
|
||||
u8 bezierBuf[16000];
|
||||
struct VirtualFramebuffer {
|
||||
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
|
||||
FBO *fbo;
|
||||
};
|
||||
|
||||
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];
|
||||
};
|
||||
|
@ -103,9 +103,6 @@ void DisplayDrawer_Init()
|
||||
|
||||
glsl_bind(draw2dprogram);
|
||||
glUniform1i(draw2dprogram->sampler0, 0);
|
||||
Matrix4x4 ortho;
|
||||
ortho.setOrtho(0, 480, 272, 0, -1, 1);
|
||||
glUniformMatrix4fv(draw2dprogram->u_viewproj, 1, GL_FALSE, ortho.getReadPtr());
|
||||
glsl_unbind();
|
||||
|
||||
// And an initial clear. We don't clear per frame as the games are supposed to handle that
|
||||
@ -125,9 +122,6 @@ void DisplayDrawer_Shutdown()
|
||||
|
||||
void DisplayDrawer_DrawFramebuffer(u8 *framebuf, int pixelFormat, int linesize)
|
||||
{
|
||||
float u1 = 1.0f;
|
||||
float v1 = 1.0f;
|
||||
|
||||
for (int y = 0; y < 272; y++)
|
||||
{
|
||||
switch (pixelFormat)
|
||||
@ -196,10 +190,23 @@ void DisplayDrawer_DrawFramebuffer(u8 *framebuf, int pixelFormat, int linesize)
|
||||
glBindTexture(GL_TEXTURE_2D,backbufTex);
|
||||
glTexSubImage2D(GL_TEXTURE_2D,0,0,0,480,272, GL_RGBA, GL_UNSIGNED_BYTE, realFB);
|
||||
|
||||
const float pos[12] = {0,0,0, 480,0,0, 480,272,0, 0,272,0};
|
||||
const float texCoords[8] = {0, 0, u1, 0, u1, v1, 0, v1};
|
||||
DrawActiveTexture(480, 272);
|
||||
}
|
||||
|
||||
void DrawActiveTexture(int w, int h, bool flip)
|
||||
{
|
||||
float u2 = 1.0f;
|
||||
float v1 = flip ? 1.0 : 0.0f;
|
||||
float v2 = flip ? 0.0 : 1.0f;
|
||||
|
||||
const float pos[12] = {0,0,0, w,0,0, w,h,0, 0,h,0};
|
||||
const float texCoords[8] = {0, v1, u2, v1, u2, v2, 0, v2};
|
||||
|
||||
glsl_bind(draw2dprogram);
|
||||
Matrix4x4 ortho;
|
||||
ortho.setOrtho(0, 480, 272, 0, -1, 1);
|
||||
glUniformMatrix4fv(draw2dprogram->u_viewproj, 1, GL_FALSE, ortho.getReadPtr());
|
||||
|
||||
glEnableVertexAttribArray(draw2dprogram->a_position);
|
||||
glEnableVertexAttribArray(draw2dprogram->a_texcoord0);
|
||||
glVertexAttribPointer(draw2dprogram->a_position, 3, GL_FLOAT, GL_FALSE, 12, pos);
|
||||
|
@ -32,3 +32,4 @@ enum PspDisplayPixelFormat {
|
||||
void DisplayDrawer_Init();
|
||||
void DisplayDrawer_DrawFramebuffer(u8 *framebuf, int pixelFormat, int linesize);
|
||||
void DisplayDrawer_Shutdown();
|
||||
void DrawActiveTexture(int w, int h, bool flip = false);
|
||||
|
@ -16,6 +16,7 @@
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "gfx_es2/glsl_program.h"
|
||||
#include "gfx_es2/fbo.h"
|
||||
|
||||
#include "input/input_state.h"
|
||||
#include "ui/ui.h"
|
||||
@ -137,6 +138,7 @@ void EmuScreen::update(InputState &input)
|
||||
}
|
||||
|
||||
if (input.pad_buttons_down & (PAD_BUTTON_MENU | PAD_BUTTON_BACK)) {
|
||||
fbo_unbind();
|
||||
screenManager()->push(new InGameMenuScreen());
|
||||
}
|
||||
}
|
||||
|
2
native
2
native
@ -1 +1 @@
|
||||
Subproject commit 7e36cef3aeac81dd8071422be93b00128a0cb110
|
||||
Subproject commit 0598fc425c6b898af9fee5b49b2054b2fffa55e6
|
Loading…
Reference in New Issue
Block a user