mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-12-12 07:56:03 +00:00
Try to workaround Breath of Fire 3's render-to-tex.
It renders to two areas but textures with a high V to reach the second texture. We've been wrapping the V around but this may show the right buffer.
This commit is contained in:
parent
80301ef053
commit
3d8f078b6c
@ -188,6 +188,8 @@ public:
|
||||
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;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "GPU/Common/TransformCommon.h"
|
||||
#include "GPU/GLES/Framebuffer.h"
|
||||
#include "GPU/GLES/ShaderManager.h"
|
||||
#include "GPU/GLES/TextureCache.h"
|
||||
#include "GPU/GLES/TransformPipeline.h"
|
||||
|
||||
// This is the software transform pipeline, which is necessary for supporting RECT
|
||||
@ -379,7 +380,6 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
|
||||
|
||||
// Here's the best opportunity to try to detect rectangles used to clear the screen, and
|
||||
// replace them with real OpenGL clears. This can provide a speedup on certain mobile chips.
|
||||
// Disabled for now - depth does not come out exactly the same.
|
||||
//
|
||||
// An alternative option is to simply ditch all the verts except the first and last to create a single
|
||||
// rectangle out of many. Quite a small optimization though.
|
||||
@ -421,6 +421,27 @@ void TransformDrawEngine::SoftwareTransformAndDraw(
|
||||
return;
|
||||
}
|
||||
|
||||
if (gstate_c.flipTexture && transformed[0].v < 0.0f && transformed[0].v > 1.0f - heightFactor) {
|
||||
// Okay, so we're texturing from outside the framebuffer, but inside the texture height.
|
||||
// Breath of Fire 3 does this to access a render surface at +curTextureHeight.
|
||||
const u32 bpp = framebufferManager_->GetTargetFormat() == GE_FORMAT_8888 ? 4 : 2;
|
||||
const u32 fb_size = bpp * framebufferManager_->GetTargetStride() * gstate_c.curTextureHeight;
|
||||
if (textureCache_->SetOffsetTexture(fb_size)) {
|
||||
const float oldWidthFactor = widthFactor;
|
||||
const float oldHeightFactor = heightFactor;
|
||||
widthFactor = (float) w / (float) gstate_c.curTextureWidth;
|
||||
heightFactor = (float) h / (float) gstate_c.curTextureHeight;
|
||||
|
||||
for (int index = 0; index < maxIndex; ++index) {
|
||||
transformed[index].u *= widthFactor / oldWidthFactor;
|
||||
// Inverse it back to scale to the new FBO, and add 1.0f to account for old FBO.
|
||||
transformed[index].v = 1.0f - transformed[index].v - 1.0f;
|
||||
transformed[index].v *= heightFactor / oldHeightFactor;
|
||||
transformed[index].v = 1.0f - transformed[index].v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: expand rectangles.
|
||||
const TransformedVertex *drawBuffer = transformed;
|
||||
int numTrans = 0;
|
||||
|
@ -883,17 +883,17 @@ bool SetDebugTexture() {
|
||||
}
|
||||
#endif
|
||||
|
||||
void TextureCache::SetTextureFramebuffer(TexCacheEntry *entry) {
|
||||
entry->framebuffer->usageFlags |= FB_USAGE_TEXTURE;
|
||||
void TextureCache::SetTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer) {
|
||||
framebuffer->usageFlags |= FB_USAGE_TEXTURE;
|
||||
bool useBufferedRendering = g_Config.iRenderingMode != FB_NON_BUFFERED_MODE;
|
||||
if (useBufferedRendering) {
|
||||
GLuint program = 0;
|
||||
if (entry->status & TexCacheEntry::STATUS_DEPALETTIZE) {
|
||||
program = depalShaderCache_->GetDepalettizeShader(entry->framebuffer->format);
|
||||
program = depalShaderCache_->GetDepalettizeShader(framebuffer->format);
|
||||
}
|
||||
if (program) {
|
||||
GLuint clutTexture = depalShaderCache_->GetClutTexture(clutHash_, clutBuf_);
|
||||
FBO *depalFBO = framebufferManager_->GetTempFBO(entry->framebuffer->renderWidth, entry->framebuffer->renderHeight, FBO_8888);
|
||||
FBO *depalFBO = framebufferManager_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, FBO_8888);
|
||||
fbo_bind_as_render_target(depalFBO);
|
||||
static const float pos[12] = {
|
||||
-1, -1, -1,
|
||||
@ -925,7 +925,7 @@ void TextureCache::SetTextureFramebuffer(TexCacheEntry *entry) {
|
||||
glBindTexture(GL_TEXTURE_2D, clutTexture);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
framebufferManager_->BindFramebufferColor(entry->framebuffer, true);
|
||||
framebufferManager_->BindFramebufferColor(framebuffer, true);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
entry->status |= TexCacheEntry::STATUS_TEXPARAM_DIRTY;
|
||||
@ -939,7 +939,7 @@ void TextureCache::SetTextureFramebuffer(TexCacheEntry *entry) {
|
||||
#if !defined(USING_GLES2)
|
||||
glDisable(GL_LOGIC_OP);
|
||||
#endif
|
||||
glViewport(0, 0, entry->framebuffer->renderWidth, entry->framebuffer->renderHeight);
|
||||
glViewport(0, 0, framebuffer->renderWidth, framebuffer->renderHeight);
|
||||
|
||||
glVertexAttribPointer(a_position, 3, GL_FLOAT, GL_FALSE, 12, pos);
|
||||
glVertexAttribPointer(a_texcoord0, 2, GL_FLOAT, GL_FALSE, 8, uv);
|
||||
@ -961,27 +961,67 @@ void TextureCache::SetTextureFramebuffer(TexCacheEntry *entry) {
|
||||
gstate_c.textureSimpleAlpha = alphaStatus == TexCacheEntry::STATUS_ALPHA_SIMPLE;
|
||||
} else {
|
||||
entry->status &= ~TexCacheEntry::STATUS_DEPALETTIZE;
|
||||
framebufferManager_->BindFramebufferColor(entry->framebuffer);
|
||||
framebufferManager_->BindFramebufferColor(framebuffer);
|
||||
|
||||
gstate_c.textureFullAlpha = entry->framebuffer->format == GE_FORMAT_565;
|
||||
gstate_c.textureFullAlpha = framebuffer->format == GE_FORMAT_565;
|
||||
gstate_c.textureSimpleAlpha = gstate_c.textureFullAlpha;
|
||||
}
|
||||
|
||||
// Keep the framebuffer alive.
|
||||
entry->framebuffer->last_frame_used = gpuStats.numFlips;
|
||||
framebuffer->last_frame_used = gpuStats.numFlips;
|
||||
|
||||
// We need to force it, since we may have set it on a texture before attaching.
|
||||
gstate_c.curTextureWidth = entry->framebuffer->bufferWidth;
|
||||
gstate_c.curTextureHeight = entry->framebuffer->bufferHeight;
|
||||
gstate_c.curTextureWidth = framebuffer->bufferWidth;
|
||||
gstate_c.curTextureHeight = framebuffer->bufferHeight;
|
||||
gstate_c.flipTexture = true;
|
||||
UpdateSamplingParams(*entry, true);
|
||||
} else {
|
||||
if (entry->framebuffer->fbo)
|
||||
entry->framebuffer->fbo = 0;
|
||||
if (framebuffer->fbo)
|
||||
framebuffer->fbo = 0;
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool TextureCache::SetOffsetTexture(u32 offset) {
|
||||
if (g_Config.iRenderingMode != FB_BUFFERED_MODE) {
|
||||
return false;
|
||||
}
|
||||
u32 texaddr = gstate.getTextureAddress(0);
|
||||
if (!Memory::IsValidAddress(texaddr) || !Memory::IsValidAddress(texaddr + offset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
u64 cachekey = (u64)(texaddr & 0x0FFFFFFF) << 32;
|
||||
TexCache::iterator iter = cache.find(cachekey);
|
||||
if (iter == cache.end()) {
|
||||
return false;
|
||||
}
|
||||
TexCacheEntry *entry = &iter->second;
|
||||
|
||||
texaddr += offset;
|
||||
cachekey = (u64)(texaddr & 0x0FFFFFFF) << 32;
|
||||
|
||||
for (size_t i = 0, n = fbCache_.size(); i < n; ++i) {
|
||||
auto framebuffer = fbCache_[i];
|
||||
// This is a rough heuristic, because sometimes our framebuffers are too tall.
|
||||
static const u32 MAX_SUBAREA_Y_OFFSET = 32;
|
||||
|
||||
// Must be in VRAM so | 0x04000000 it is, and ignore any uncached bit.
|
||||
const u32 addr = (framebuffer->fb_address | 0x04000000) & 0x0FFFFFFF;
|
||||
const u64 cacheKeyStart = (u64)addr << 32;
|
||||
// If it has a clut, those are the low 32 bits, so it'll be inside this range.
|
||||
// Also, if it's a subsample of the buffer, it'll also be within the FBO.
|
||||
const u64 cacheKeyEnd = cacheKeyStart + ((u64)(framebuffer->fb_stride * MAX_SUBAREA_Y_OFFSET) << 32);
|
||||
|
||||
if (cachekey >= cacheKeyStart && cachekey < cacheKeyEnd) {
|
||||
SetTextureFramebuffer(entry, framebuffer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void TextureCache::SetTexture(bool force) {
|
||||
#ifdef DEBUG_TEXTURES
|
||||
if (SetDebugTexture()) {
|
||||
@ -1053,7 +1093,7 @@ void TextureCache::SetTexture(bool force) {
|
||||
// Check for FBO - slow!
|
||||
if (entry->framebuffer) {
|
||||
if (match) {
|
||||
SetTextureFramebuffer(entry);
|
||||
SetTextureFramebuffer(entry, entry->framebuffer);
|
||||
lastBoundTexture = -1;
|
||||
entry->lastFrame = gpuStats.numFlips;
|
||||
return;
|
||||
@ -1266,7 +1306,7 @@ void TextureCache::SetTexture(bool force) {
|
||||
|
||||
// If we ended up with a framebuffer, attach it - no texture decoding needed.
|
||||
if (entry->framebuffer) {
|
||||
SetTextureFramebuffer(entry);
|
||||
SetTextureFramebuffer(entry, entry->framebuffer);
|
||||
lastBoundTexture = -1;
|
||||
entry->lastFrame = gpuStats.numFlips;
|
||||
return;
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
~TextureCache();
|
||||
|
||||
void SetTexture(bool force = false);
|
||||
bool SetOffsetTexture(u32 offset);
|
||||
|
||||
void Clear(bool delete_them);
|
||||
void StartFrame();
|
||||
@ -180,7 +181,7 @@ private:
|
||||
void UpdateCurrentClut();
|
||||
void AttachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer, bool exactMatch);
|
||||
void DetachFramebuffer(TexCacheEntry *entry, u32 address, VirtualFramebuffer *framebuffer);
|
||||
void SetTextureFramebuffer(TexCacheEntry *entry);
|
||||
void SetTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuffer *framebuffer);
|
||||
|
||||
TexCacheEntry *GetEntryAt(u32 texaddr);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user