mirror of
https://github.com/libretro/ppsspp.git
synced 2025-02-01 14:24:02 +00:00
Initial support for texturing from framebuffers.
This commit is contained in:
parent
02936d5090
commit
a0c0d6a977
@ -165,6 +165,8 @@ GLES_GPU::GLES_GPU()
|
||||
shaderManager_ = new ShaderManager();
|
||||
transformDraw_.SetShaderManager(shaderManager_);
|
||||
transformDraw_.SetTextureCache(&textureCache_);
|
||||
transformDraw_.SetFramebufferManager(&framebufferManager_);
|
||||
framebufferManager_.SetTextureCache(&textureCache_);
|
||||
|
||||
// Sanity check gstate
|
||||
if ((int *)&gstate.transferstart - (int *)&gstate != 0xEA) {
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "GPU/GPUState.h"
|
||||
|
||||
#include "GPU/GLES/Framebuffer.h"
|
||||
#include "GPU/GLES/TextureCache.h"
|
||||
|
||||
static const char tex_fs[] =
|
||||
"#ifdef GL_ES\n"
|
||||
@ -66,7 +67,8 @@ static bool MaskedEqual(u32 addr1, u32 addr2) {
|
||||
FramebufferManager::FramebufferManager() :
|
||||
displayFramebufPtr_(0),
|
||||
prevDisplayFramebuf_(0),
|
||||
prevPrevDisplayFramebuf_(0)
|
||||
prevPrevDisplayFramebuf_(0),
|
||||
currentRenderVfb_(0)
|
||||
{
|
||||
glGenTextures(1, &backbufTex);
|
||||
|
||||
@ -216,6 +218,13 @@ FramebufferManager::VirtualFramebuffer *FramebufferManager::GetDisplayFBO() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GetViewportDimensions(int *w, int *h) {
|
||||
float vpXa = getFloat24(gstate.viewportx1);
|
||||
float vpYa = getFloat24(gstate.viewporty1);
|
||||
*w = fabsf(vpXa * 2);
|
||||
*h = fabsf(vpYa * 2);
|
||||
}
|
||||
|
||||
void FramebufferManager::SetRenderFrameBuffer() {
|
||||
if (!g_Config.bBufferedRendering)
|
||||
return;
|
||||
@ -226,12 +235,23 @@ void FramebufferManager::SetRenderFrameBuffer() {
|
||||
u32 z_address = (gstate.zbptr & 0xFFE000) | ((gstate.zbwidth & 0xFF0000) << 8);
|
||||
int z_stride = gstate.zbwidth & 0x3C0;
|
||||
|
||||
// We guess that the viewport size during the first draw call is an appropriate
|
||||
// size for a render target.
|
||||
//UpdateViewportAndProjection();
|
||||
|
||||
// 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 drawing_width = ((gstate.region2) & 0x3FF) + 1;
|
||||
//int drawing_height = ((gstate.region2 >> 10) & 0x3FF) + 1;
|
||||
|
||||
// As there are no clear "framebuffer width" and "framebuffer height" registers,
|
||||
// we need to infer the size of the current framebuffer somehow. Let's try the viewport.
|
||||
|
||||
int drawing_width, drawing_height;
|
||||
GetViewportDimensions(&drawing_width, &drawing_height);
|
||||
|
||||
// HACK for first frame where some games don't init things right
|
||||
if (drawing_width == 1 && drawing_height == 1) {
|
||||
|
||||
if (drawing_width <= 1 && drawing_height <= 1) {
|
||||
drawing_width = 480;
|
||||
drawing_height = 272;
|
||||
}
|
||||
@ -251,6 +271,9 @@ void FramebufferManager::SetRenderFrameBuffer() {
|
||||
}
|
||||
}
|
||||
|
||||
float renderWidthFactor = (float)PSP_CoreParameter().renderWidth / 480.0f;
|
||||
float renderHeightFactor = (float)PSP_CoreParameter().renderHeight / 272.0f;
|
||||
|
||||
// None found? Create one.
|
||||
if (!vfb) {
|
||||
gstate_c.textureChanged = true;
|
||||
@ -261,6 +284,8 @@ void FramebufferManager::SetRenderFrameBuffer() {
|
||||
vfb->z_stride = z_stride;
|
||||
vfb->width = drawing_width;
|
||||
vfb->height = drawing_height;
|
||||
vfb->renderWidth = drawing_width * renderWidthFactor;
|
||||
vfb->renderHeight = drawing_height * renderHeightFactor;
|
||||
vfb->format = fmt;
|
||||
|
||||
vfb->colorDepth = FBO_8888;
|
||||
@ -273,15 +298,16 @@ void FramebufferManager::SetRenderFrameBuffer() {
|
||||
//#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->fbo = fbo_create(vfb->renderWidth, vfb->renderHeight, 1, true, vfb->colorDepth);
|
||||
textureCache_->NotifyFramebuffer(vfb->fb_address, vfb->fbo);
|
||||
|
||||
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);
|
||||
glstate.viewport.set(0, 0, vfb->renderWidth, vfb->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);
|
||||
@ -292,8 +318,15 @@ void FramebufferManager::SetRenderFrameBuffer() {
|
||||
// Use it as a render target.
|
||||
DEBUG_LOG(HLE, "Switching render target to FBO for %08x", vfb->fb_address);
|
||||
gstate_c.textureChanged = true;
|
||||
if (vfb->last_frame_used != gpuStats.numFrames) {
|
||||
// Android optimization
|
||||
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
}
|
||||
vfb->last_frame_used = gpuStats.numFrames;
|
||||
|
||||
fbo_bind_as_render_target(vfb->fbo);
|
||||
|
||||
textureCache_->NotifyFramebuffer(vfb->fb_address, 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...
|
||||
@ -301,9 +334,8 @@ void FramebufferManager::SetRenderFrameBuffer() {
|
||||
// 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);
|
||||
glstate.viewport.set(0, 0, vfb->renderWidth, vfb->renderHeight);
|
||||
currentRenderVfb_ = vfb;
|
||||
vfb->last_frame_used = gpuStats.numFrames;
|
||||
}
|
||||
}
|
||||
|
||||
@ -374,15 +406,16 @@ void FramebufferManager::SetDisplayFramebuffer(u32 framebuf, u32 stride, int for
|
||||
|
||||
void FramebufferManager::DecimateFBOs() {
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end();) {
|
||||
VirtualFramebuffer *v = *iter;
|
||||
if (v == displayFramebuf_ || v == prevDisplayFramebuf_ || v == prevPrevDisplayFramebuf_) {
|
||||
VirtualFramebuffer *vfb = *iter;
|
||||
if (vfb == displayFramebuf_ || vfb == prevDisplayFramebuf_ || vfb == 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;
|
||||
INFO_LOG(HLE, "Destroying FBO for %08x (%i x %i x %i)", vfb->fb_address, vfb->width, vfb->height, vfb->format)
|
||||
textureCache_->NotifyFramebufferDestroyed(vfb->fb_address, vfb->fbo);
|
||||
fbo_destroy(vfb->fbo);
|
||||
delete vfb;
|
||||
vfbs_.erase(iter++);
|
||||
}
|
||||
else
|
||||
@ -392,9 +425,10 @@ void FramebufferManager::DecimateFBOs() {
|
||||
|
||||
void FramebufferManager::DestroyAllFBOs() {
|
||||
for (auto iter = vfbs_.begin(); iter != vfbs_.end(); ++iter) {
|
||||
VirtualFramebuffer *v = *iter;
|
||||
fbo_destroy(v->fbo);
|
||||
delete v;
|
||||
VirtualFramebuffer *vfb = *iter;
|
||||
textureCache_->NotifyFramebufferDestroyed(vfb->fb_address, vfb->fbo);
|
||||
fbo_destroy(vfb->fbo);
|
||||
delete vfb;
|
||||
}
|
||||
vfbs_.clear();
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "../Globals.h"
|
||||
|
||||
struct GLSLProgram;
|
||||
class TextureCache;
|
||||
|
||||
enum PspDisplayPixelFormat {
|
||||
PSP_DISPLAY_PIXEL_FORMAT_565 = 0,
|
||||
@ -41,6 +42,10 @@ public:
|
||||
FramebufferManager();
|
||||
~FramebufferManager();
|
||||
|
||||
void SetTextureCache(TextureCache *tc) {
|
||||
textureCache_ = tc;
|
||||
}
|
||||
|
||||
struct VirtualFramebuffer {
|
||||
int last_frame_used;
|
||||
|
||||
@ -50,8 +55,10 @@ public:
|
||||
int z_stride;
|
||||
|
||||
// There's also a top left of the drawing region, but meh...
|
||||
int width;
|
||||
int height;
|
||||
u16 width;
|
||||
u16 height;
|
||||
u16 renderWidth;
|
||||
u16 renderHeight;
|
||||
|
||||
int format; // virtual, right now they are all RGBA8888
|
||||
FBOColorDepth colorDepth;
|
||||
@ -73,6 +80,11 @@ public:
|
||||
void SetDisplayFramebuffer(u32 framebuf, u32 stride, int format);
|
||||
size_t NumVFBs() const { return vfbs_.size(); }
|
||||
|
||||
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; }
|
||||
|
||||
private:
|
||||
// Deletes old FBOs.
|
||||
|
||||
@ -93,5 +105,9 @@ private:
|
||||
|
||||
u8 *convBuf;
|
||||
GLSLProgram *draw2dprogram;
|
||||
|
||||
|
||||
TextureCache *textureCache_;
|
||||
|
||||
bool resized_;
|
||||
};
|
||||
|
@ -213,11 +213,11 @@ void TransformDrawEngine::ApplyDrawState(int prim) {
|
||||
glstate.depthRange.set(depthRangeMin, depthRangeMax);
|
||||
}
|
||||
|
||||
void UpdateViewportAndProjection() {
|
||||
int renderWidth = PSP_CoreParameter().renderWidth;
|
||||
int renderHeight = PSP_CoreParameter().renderHeight;
|
||||
float renderWidthFactor = (float)renderWidth / 480.0f;
|
||||
float renderHeightFactor = (float)renderHeight / 272.0f;
|
||||
void TransformDrawEngine::UpdateViewportAndProjection() {
|
||||
int renderWidth = framebufferManager_->GetRenderWidth();
|
||||
int renderHeight = framebufferManager_->GetRenderHeight();
|
||||
float renderWidthFactor = (float)renderWidth / framebufferManager_->GetTargetWidth();
|
||||
float renderHeightFactor = (float)renderHeight / framebufferManager_->GetTargetHeight();
|
||||
bool throughmode = (gstate.vertType & GE_VTYPE_THROUGH_MASK) != 0;
|
||||
|
||||
// We can probably use these to simply set scissors? Maybe we need to offset by regionX1/Y1
|
||||
|
@ -6,5 +6,4 @@ extern const GLint eqLookup[];
|
||||
extern const GLint cullingMode[];
|
||||
extern const GLuint ztests[];
|
||||
|
||||
void UpdateViewportAndProjection();
|
||||
|
||||
|
@ -111,6 +111,31 @@ void TextureCache::InvalidateAll(bool force) {
|
||||
Invalidate(0, 0xFFFFFFFF, force);
|
||||
}
|
||||
|
||||
TextureCache::TexCacheEntry *TextureCache::GetEntryAt(u32 texaddr) {
|
||||
for (auto entry = cache.begin(); entry != cache.end(); ++entry) {
|
||||
if (entry->second.addr == texaddr) {
|
||||
return &entry->second;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TextureCache::NotifyFramebuffer(u32 address, FBO *fbo) {
|
||||
TexCacheEntry *entry = GetEntryAt(address | 0x04000000);
|
||||
if (entry) {
|
||||
INFO_LOG(HLE, "Render to texture detected at %08x!", address);
|
||||
if (!entry->fbo)
|
||||
entry->fbo = fbo;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCache::NotifyFramebufferDestroyed(u32 address, FBO *fbo) {
|
||||
TexCacheEntry *entry = GetEntryAt(address | 0x04000000);
|
||||
if (entry && entry->fbo) {
|
||||
entry->fbo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 GetClutAddr(u32 clutEntrySize) {
|
||||
return ((gstate.clutaddr & 0xFFFFFF) | ((gstate.clutaddrupper << 8) & 0x0F000000)) + ((gstate.clutformat >> 16) & 0x1f) * clutEntrySize;
|
||||
}
|
||||
@ -622,6 +647,7 @@ void TextureCache::SetTexture() {
|
||||
ERROR_LOG(G3D, "Unknown texture format %i", format);
|
||||
format = 0;
|
||||
}
|
||||
bool hasClut = formatUsesClut[format];
|
||||
|
||||
u32 clutformat = gstate.clutformat & 3;
|
||||
u32 clutaddr = GetClutAddr(clutformat == GE_CMODE_32BIT_ABGR8888 ? 4 : 2);
|
||||
@ -630,9 +656,18 @@ void TextureCache::SetTexture() {
|
||||
u32 texhash = texptr ? MiniHash((const u32*)texptr) : 0;
|
||||
|
||||
u64 cachekey = texaddr ^ texhash;
|
||||
if (formatUsesClut[format])
|
||||
if (hasClut) {
|
||||
cachekey |= (u64) clutaddr << 32;
|
||||
}
|
||||
|
||||
// Check for FBO - slow!
|
||||
TexCacheEntry *fboEntry = GetEntryAt(texaddr);
|
||||
if (fboEntry && fboEntry->fbo) {
|
||||
fbo_bind_color_as_texture(fboEntry->fbo, 0);
|
||||
UpdateSamplingParams(*fboEntry, false);
|
||||
return;
|
||||
}
|
||||
|
||||
TexCache::iterator iter = cache.find(cachekey);
|
||||
if (iter != cache.end()) {
|
||||
//Validate the texture here (width, height etc)
|
||||
@ -693,6 +728,7 @@ void TextureCache::SetTexture() {
|
||||
entry.hash = texhash;
|
||||
entry.format = format;
|
||||
entry.frameCounter = gpuStats.numFrames;
|
||||
entry.fbo = 0;
|
||||
|
||||
if (format >= GE_TFMT_CLUT4 && format <= GE_TFMT_CLUT32) {
|
||||
entry.clutformat = clutformat;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Globals.h"
|
||||
#include "gfx_es2/fbo.h"
|
||||
|
||||
class TextureCache
|
||||
{
|
||||
@ -32,21 +33,28 @@ public:
|
||||
void Invalidate(u32 addr, int size, bool force);
|
||||
void InvalidateAll(bool force);
|
||||
|
||||
// FramebufferManager keeps TextureCache updated about what regions of memory
|
||||
// are being rendered to. This is barebones so far.
|
||||
void NotifyFramebuffer(u32 address, FBO *fbo);
|
||||
void NotifyFramebufferDestroyed(u32 address, FBO *fbo);
|
||||
|
||||
size_t NumLoadedTextures() const {
|
||||
return cache.size();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
struct TexCacheEntry {
|
||||
u32 addr;
|
||||
u32 hash;
|
||||
FBO *fbo; // if null, not sourced from an FBO.
|
||||
u32 sizeInRAM;
|
||||
int frameCounter;
|
||||
u32 format;
|
||||
u8 format;
|
||||
u8 clutformat;
|
||||
u16 dim;
|
||||
u32 clutaddr;
|
||||
u32 clutformat;
|
||||
u32 cluthash;
|
||||
int dim;
|
||||
u32 texture; //GLuint
|
||||
int invalidHint;
|
||||
u32 fullhash;
|
||||
@ -63,6 +71,8 @@ private:
|
||||
void *readIndexedTex(int level, u32 texaddr, int bytesPerIndex);
|
||||
void UpdateSamplingParams(TexCacheEntry &entry, bool force);
|
||||
|
||||
TexCacheEntry *GetEntryAt(u32 texaddr);
|
||||
|
||||
typedef std::map<u64, TexCacheEntry> TexCache;
|
||||
|
||||
// TODO: Speed up by switching to ReadUnchecked*.
|
||||
|
@ -24,6 +24,8 @@
|
||||
class LinkedShader;
|
||||
class ShaderManager;
|
||||
class TextureCache;
|
||||
class FramebufferManager;
|
||||
|
||||
struct DecVtxFormat;
|
||||
|
||||
// States transitions:
|
||||
@ -100,7 +102,9 @@ public:
|
||||
void SetTextureCache(TextureCache *textureCache) {
|
||||
textureCache_ = textureCache;
|
||||
}
|
||||
|
||||
void SetFramebufferManager(FramebufferManager *fbManager) {
|
||||
framebufferManager_ = fbManager;
|
||||
}
|
||||
void InitDeviceObjects();
|
||||
void DestroyDeviceObjects();
|
||||
void GLLost();
|
||||
@ -111,6 +115,7 @@ public:
|
||||
private:
|
||||
void SoftwareTransformAndDraw(int prim, u8 *decoded, LinkedShader *program, int vertexCount, u32 vertexType, void *inds, int indexType, const DecVtxFormat &decVtxFormat, int maxIndex);
|
||||
void ApplyDrawState(int prim);
|
||||
void UpdateViewportAndProjection();
|
||||
|
||||
// drawcall ID
|
||||
u32 ComputeFastDCID();
|
||||
@ -155,6 +160,7 @@ private:
|
||||
// Other
|
||||
ShaderManager *shaderManager_;
|
||||
TextureCache *textureCache_;
|
||||
FramebufferManager *framebufferManager_;
|
||||
|
||||
enum { MAX_DEFERRED_DRAW_CALLS = 128 };
|
||||
DeferredDrawCall drawCalls[MAX_DEFERRED_DRAW_CALLS];
|
||||
|
2
native
2
native
@ -1 +1 @@
|
||||
Subproject commit c21e1ee2cced55bb68edefbb58ba4b30bde807ba
|
||||
Subproject commit 09950112d3bd60fbfbd877446d5dfe5117b8b9e1
|
@ -1 +1 @@
|
||||
Subproject commit 31e3915d4e4302e5e7dc2f6c2a4f191c420f38f9
|
||||
Subproject commit 3870083f15c69aa47a159fda148a8df3db6891e4
|
Loading…
x
Reference in New Issue
Block a user