Use texture UV range to optimize framebuf copies.

This commit is contained in:
Unknown W. Brackets 2015-09-13 11:14:51 -07:00
parent f4df7f076e
commit 62de281e35
9 changed files with 161 additions and 30 deletions

View file

@ -115,6 +115,12 @@ extern GPUgstate gstate;
void GetFramebufferHeuristicInputs(FramebufferHeuristicParams *params, const GPUgstate &gstate);
enum BindFramebufferColorFlags {
BINDFBCOLOR_SKIP_COPY = 0,
BINDFBCOLOR_MAY_COPY = 1,
BINDFBCOLOR_MAY_COPY_WITH_UV = 3,
};
class FramebufferManagerCommon {
public:
FramebufferManagerCommon();

View file

@ -608,7 +608,7 @@ namespace DX9 {
return offscreen;
}
void FramebufferManagerDX9::BindFramebufferColor(int stage, VirtualFramebuffer *framebuffer, bool skipCopy) {
void FramebufferManagerDX9::BindFramebufferColor(int stage, VirtualFramebuffer *framebuffer, int flags) {
if (framebuffer == NULL) {
framebuffer = currentRenderVfb_;
}
@ -621,6 +621,7 @@ namespace DX9 {
// currentRenderVfb_ will always be set when this is called, except from the GE debugger.
// Let's just not bother with the copy in that case.
bool skipCopy = (flags & BINDFBCOLOR_MAY_COPY) == 0;
if (GPUStepping::IsStepping() || g_Config.bDisableSlowFramebufEffects) {
skipCopy = true;
}
@ -630,7 +631,22 @@ namespace DX9 {
if (renderCopy) {
VirtualFramebuffer copyInfo = *framebuffer;
copyInfo.fbo = renderCopy;
BlitFramebuffer(&copyInfo, 0, 0, framebuffer, 0, 0, framebuffer->drawnWidth, framebuffer->drawnHeight, 0, false);
int x = 0;
int y = 0;
int w = framebuffer->drawnWidth;
int h = framebuffer->drawnHeight;
// If max is not > min, we probably could not detect it. Skip.
// See the vertex decoder, where this is updated.
if ((flags & BINDFBCOLOR_MAY_COPY_WITH_UV) != 0 && gstate_c.vertMaxU > gstate_c.vertMinU) {
x = gstate_c.vertMinU;
y = gstate_c.vertMinV;
w = gstate_c.vertMaxU - x;
h = gstate_c.vertMaxV - y;
}
BlitFramebuffer(&copyInfo, x, y, framebuffer, x, y, w, h, 0, false);
RebindFramebuffer();
pD3Ddevice->SetTexture(stage, fbo_get_color_texture(renderCopy));

View file

@ -71,7 +71,7 @@ public:
void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst);
void BindFramebufferColor(int stage, VirtualFramebuffer *framebuffer, bool skipCopy = false);
void BindFramebufferColor(int stage, VirtualFramebuffer *framebuffer, int flags);
virtual void ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) override;

View file

@ -815,7 +815,7 @@ void TransformDrawEngineDX9::ApplyDrawStateLate() {
textureCache_->ApplyTexture();
if (fboTexNeedBind_) {
framebufferManager_->BindFramebufferColor(1, nullptr, false);
framebufferManager_->BindFramebufferColor(1, nullptr, BINDFBCOLOR_MAY_COPY_WITH_UV);
// If we are rendering at a higher resolution, linear is probably best for the dest color.
pD3Ddevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
pD3Ddevice->SetSamplerState(1, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);

View file

@ -960,12 +960,60 @@ void TextureCacheDX9::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFrame
float xoff = -0.5f / framebuffer->renderWidth;
float yoff = 0.5f / framebuffer->renderHeight;
const float pos[12 + 8] = {
-1 + xoff, 1 + yoff, 0, 0, 0,
1 + xoff, 1 + yoff, 0, 1, 0,
1 + xoff, -1 + yoff, 0, 1, 1,
-1 + xoff, -1 + yoff, 0, 0, 1,
struct Pos {
Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {
}
float x;
float y;
float z;
};
struct UV {
UV(float u_, float v_) : u(u_), v(v_) {
}
float u;
float v;
};
struct PosUV {
Pos pos;
UV uv;
};
PosUV verts[4] = {
{ { -1 + xoff, 1 + yoff, -1 }, { 0, 0 } },
{ { 1 + xoff, 1 + yoff, -1 }, { 1, 0 } },
{ { 1 + xoff, -1 + yoff, -1 }, { 1, 1 } },
{ { -1 + xoff, -1 + yoff, -1 }, { 0, 1 } },
};
// If min is not < max, then we don't have values (wasn't set during decode.)
if (gstate_c.vertMinV < gstate_c.vertMaxV) {
const float invWidth = 1.0f / (float)framebuffer->bufferWidth;
const float invHeight = 1.0f / (float)framebuffer->bufferHeight;
// Inverse of half = double.
const float invHalfWidth = invWidth * 2.0f;
const float invHalfHeight = invHeight * 2.0f;
const float left = gstate_c.vertMinU * invHalfWidth - 1.0f + xoff;
const float right = gstate_c.vertMaxU * invHalfWidth - 1.0f + xoff;
const float top = gstate_c.vertMinV * invHalfHeight - 1.0f + yoff;
const float bottom = gstate_c.vertMaxV * invHalfHeight - 1.0f + yoff;
// Points are: BL, BR, TR, TL.
verts[0].pos = Pos(left, bottom, -1.0f);
verts[1].pos = Pos(right, bottom, -1.0f);
verts[2].pos = Pos(right, top, -1.0f);
verts[3].pos = Pos(left, top, -1.0f);
// And also the UVs, same order.
const float uvleft = gstate_c.vertMinU * invWidth;
const float uvright = gstate_c.vertMaxU * invWidth;
const float uvtop = 1.0f - gstate_c.vertMinV * invHeight;
const float uvbottom = 1.0f - gstate_c.vertMaxV * invHeight;
verts[0].uv = UV(uvleft, uvbottom);
verts[1].uv = UV(uvright, uvbottom);
verts[2].uv = UV(uvright, uvtop);
verts[3].uv = UV(uvleft, uvtop);
}
shaderManager_->DirtyLastShader();
@ -977,7 +1025,7 @@ void TextureCacheDX9::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFrame
pD3Ddevice->SetSamplerState(1, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
pD3Ddevice->SetSamplerState(1, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
framebufferManager_->BindFramebufferColor(0, framebuffer, true);
framebufferManager_->BindFramebufferColor(0, framebuffer, BINDFBCOLOR_SKIP_COPY);
pD3Ddevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
pD3Ddevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
pD3Ddevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
@ -999,7 +1047,7 @@ void TextureCacheDX9::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFrame
vp.Height = framebuffer->renderHeight;
pD3Ddevice->SetViewport(&vp);
HRESULT hr = pD3Ddevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, pos, (3 + 2) * sizeof(float));
HRESULT hr = pD3Ddevice->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, verts, (3 + 2) * sizeof(float));
if (FAILED(hr)) {
ERROR_LOG_REPORT(G3D, "Depal render failed: %08x", hr);
}
@ -1011,7 +1059,7 @@ void TextureCacheDX9::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFrame
framebufferManager_->RebindFramebuffer();
} else {
framebufferManager_->BindFramebufferColor(0, framebuffer);
framebufferManager_->BindFramebufferColor(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV);
}
SetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight);

View file

@ -838,7 +838,7 @@ FBO *FramebufferManager::GetTempFBO(u16 w, u16 h, FBOColorDepth depth) {
return fbo;
}
void FramebufferManager::BindFramebufferColor(int stage, u32 fbRawAddress, VirtualFramebuffer *framebuffer, bool skipCopy) {
void FramebufferManager::BindFramebufferColor(int stage, u32 fbRawAddress, VirtualFramebuffer *framebuffer, int flags) {
if (framebuffer == NULL) {
framebuffer = currentRenderVfb_;
}
@ -856,6 +856,7 @@ void FramebufferManager::BindFramebufferColor(int stage, u32 fbRawAddress, Virtu
// currentRenderVfb_ will always be set when this is called, except from the GE debugger.
// Let's just not bother with the copy in that case.
bool skipCopy = (flags & BINDFBCOLOR_MAY_COPY) == 0;
if (GPUStepping::IsStepping() || g_Config.bDisableSlowFramebufEffects) {
skipCopy = true;
}
@ -865,9 +866,23 @@ void FramebufferManager::BindFramebufferColor(int stage, u32 fbRawAddress, Virtu
if (renderCopy) {
VirtualFramebuffer copyInfo = *framebuffer;
copyInfo.fbo = renderCopy;
BlitFramebuffer(&copyInfo, 0, 0, framebuffer, 0, 0, framebuffer->drawnWidth, framebuffer->drawnHeight, 0, false);
RebindFramebuffer();
int x = 0;
int y = 0;
int w = framebuffer->drawnWidth;
int h = framebuffer->drawnHeight;
// If max is not > min, we probably could not detect it. Skip.
// See the vertex decoder, where this is updated.
if ((flags & BINDFBCOLOR_MAY_COPY_WITH_UV) != 0 && gstate_c.vertMaxU > gstate_c.vertMinU) {
x = gstate_c.vertMinU;
y = gstate_c.vertMinV;
w = gstate_c.vertMaxU - x;
h = gstate_c.vertMaxV - y;
}
BlitFramebuffer(&copyInfo, x, y, framebuffer, x, y, w, h, 0, false);
fbo_bind_color_as_texture(renderCopy, 0);
} else {
fbo_bind_color_as_texture(framebuffer->fbo, 0);

View file

@ -98,7 +98,7 @@ public:
void BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst);
// For use when texturing from a framebuffer. May create a duplicate if target.
void BindFramebufferColor(int stage, u32 fbRawAddress, VirtualFramebuffer *framebuffer, bool skipCopy = false);
void BindFramebufferColor(int stage, u32 fbRawAddress, VirtualFramebuffer *framebuffer, int flags);
// Reads a rectangular subregion of a framebuffer to the right position in its backing memory.
virtual void ReadFramebufferToMemory(VirtualFramebuffer *vfb, bool sync, int x, int y, int w, int h) override;

View file

@ -904,7 +904,9 @@ void TransformDrawEngine::ApplyDrawStateLate() {
textureCache_->ApplyTexture();
if (fboTexNeedBind_) {
framebufferManager_->BindFramebufferColor(GL_TEXTURE1, gstate.getFrameBufRawAddress(), nullptr);
framebufferManager_->BindFramebufferColor(GL_TEXTURE1, gstate.getFrameBufRawAddress(), nullptr, BINDFBCOLOR_MAY_COPY_WITH_UV);
framebufferManager_->RebindFramebuffer();
glActiveTexture(GL_TEXTURE1);
// If we are rendering at a higher resolution, linear is probably best for the dest color.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

View file

@ -1023,20 +1023,64 @@ void TextureCache::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuf
GLuint clutTexture = depalShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBuf_);
FBO *depalFBO = framebufferManager_->GetTempFBO(framebuffer->renderWidth, framebuffer->renderHeight, FBO_8888);
fbo_bind_as_render_target(depalFBO);
static const float pos[12] = {
-1, -1, -1,
1, -1, -1,
1, 1, -1,
-1, 1, -1
struct Pos {
Pos(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {
}
float x;
float y;
float z;
};
static const float uv[8] = {
0, 0,
1, 0,
1, 1,
0, 1,
struct UV {
UV(float u_, float v_) : u(u_), v(v_) {
}
float u;
float v;
};
Pos pos[4] = {
{-1, -1, -1},
{ 1, -1, -1},
{ 1, 1, -1},
{-1, 1, -1},
};
UV uv[4] = {
{0, 0},
{1, 0},
{1, 1},
{0, 1},
};
static const GLubyte indices[4] = { 0, 1, 3, 2 };
// If min is not < max, then we don't have values (wasn't set during decode.)
if (gstate_c.vertMinV < gstate_c.vertMaxV) {
const float invWidth = 1.0f / (float)framebuffer->bufferWidth;
const float invHeight = 1.0f / (float)framebuffer->bufferHeight;
// Inverse of half = double.
const float invHalfWidth = invWidth * 2.0f;
const float invHalfHeight = invHeight * 2.0f;
const float left = gstate_c.vertMinU * invHalfWidth - 1.0f;
const float right = gstate_c.vertMaxU * invHalfWidth - 1.0f;
const float top = -(gstate_c.vertMinV * invHalfHeight - 1.0f);
const float bottom = -(gstate_c.vertMaxV * invHalfHeight - 1.0f);
// Points are: BL, BR, TR, TL.
pos[0] = Pos(left, bottom, -1.0f);
pos[1] = Pos(right, bottom, -1.0f);
pos[2] = Pos(right, top, -1.0f);
pos[3] = Pos(left, top, -1.0f);
// And also the UVs, same order.
const float uvleft = gstate_c.vertMinU * invWidth;
const float uvright = gstate_c.vertMaxU * invWidth;
const float uvtop = 1.0f - gstate_c.vertMinV * invHeight;
const float uvbottom = 1.0f - gstate_c.vertMaxV * invHeight;
uv[0] = UV(uvleft, uvbottom);
uv[1] = UV(uvright, uvbottom);
uv[2] = UV(uvright, uvtop);
uv[3] = UV(uvleft, uvtop);
}
shaderManager_->DirtyLastShader();
glUseProgram(depal->program);
@ -1050,7 +1094,7 @@ void TextureCache::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuf
glBindTexture(GL_TEXTURE_2D, clutTexture);
glActiveTexture(GL_TEXTURE0);
framebufferManager_->BindFramebufferColor(GL_TEXTURE0, gstate.getFrameBufRawAddress(), framebuffer, true);
framebufferManager_->BindFramebufferColor(GL_TEXTURE0, gstate.getFrameBufRawAddress(), framebuffer, BINDFBCOLOR_SKIP_COPY);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@ -1073,11 +1117,11 @@ void TextureCache::ApplyTextureFramebuffer(TexCacheEntry *entry, VirtualFramebuf
fbo_bind_color_as_texture(depalFBO, 0);
glstate.Restore();
framebufferManager_->RebindFramebuffer();
} else {
framebufferManager_->BindFramebufferColor(GL_TEXTURE0, gstate.getFrameBufRawAddress(), framebuffer);
framebufferManager_->BindFramebufferColor(GL_TEXTURE0, gstate.getFrameBufRawAddress(), framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV);
}
framebufferManager_->RebindFramebuffer();
SetFramebufferSamplingParams(framebuffer->bufferWidth, framebuffer->bufferHeight);
lastBoundTexture = -1;