Skip to content

Commit

Permalink
Merge pull request #9566 from unknownbrackets/gpu-blit
Browse files Browse the repository at this point in the history
Fix out-of-bounds framebuffer blit on color bind
  • Loading branch information
hrydgard authored Apr 7, 2017
2 parents 19bf222 + ff14495 commit 706714e
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 66 deletions.
26 changes: 26 additions & 0 deletions GPU/Common/FramebufferCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,32 @@ void FramebufferManagerCommon::DrawPixels(VirtualFramebuffer *vfb, int dstX, int
DrawActiveTexture(dstX, dstY, width, height, vfb->bufferWidth, vfb->bufferHeight, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, linearFilter);
}

void FramebufferManagerCommon::CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags) {
int x = 0;
int y = 0;
int w = src->drawnWidth;
int h = src->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) == BINDFBCOLOR_MAY_COPY_WITH_UV && gstate_c.vertBounds.maxU > gstate_c.vertBounds.minU) {
x = std::max(gstate_c.vertBounds.minU, (u16)0);
y = std::max(gstate_c.vertBounds.minV, (u16)0);
w = std::min(gstate_c.vertBounds.maxU, src->drawnWidth) - x;
h = std::min(gstate_c.vertBounds.maxV, src->drawnHeight) - y;

// If we bound a framebuffer, apply the byte offset as pixels to the copy too.
if (flags & BINDFBCOLOR_APPLY_TEX_OFFSET) {
x += gstate_c.curTextureXOffset;
y += gstate_c.curTextureYOffset;
}
}

if (x < src->drawnWidth && y < src->drawnHeight && w > 0 && h > 0) {
BlitFramebuffer(dst, x, y, src, x, y, w, h, 0);
}
}

void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, bool applyPostShader) {
textureCache_->ForgetLastTexture();
shaderManager_->DirtyLastShader();
Expand Down
1 change: 1 addition & 0 deletions GPU/Common/FramebufferCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ class FramebufferManagerCommon {

// Used by ReadFramebufferToMemory and later framebuffer block copies
virtual void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) = 0;
void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags);

void EstimateDrawingSize(u32 fb_address, GEBufferFormat fb_format, int viewport_width, int viewport_height, int region_width, int region_height, int scissor_width, int scissor_height, int fb_stride, int &drawing_width, int &drawing_height);
u32 FramebufferByteSize(const VirtualFramebuffer *vfb) const;
Expand Down
23 changes: 1 addition & 22 deletions GPU/D3D11/FramebufferManagerD3D11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,28 +572,7 @@ void FramebufferManagerD3D11::BindFramebufferAsColorTexture(int stage, VirtualFr
VirtualFramebuffer copyInfo = *framebuffer;
copyInfo.fbo = renderCopy;

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) == BINDFBCOLOR_MAY_COPY_WITH_UV && gstate_c.vertBounds.maxU > gstate_c.vertBounds.minU) {
x = gstate_c.vertBounds.minU;
y = gstate_c.vertBounds.minV;
w = gstate_c.vertBounds.maxU - x;
h = gstate_c.vertBounds.maxV - y;

// If we bound a framebuffer, apply the byte offset as pixels to the copy too.
if (flags & BINDFBCOLOR_APPLY_TEX_OFFSET) {
x += gstate_c.curTextureXOffset;
y += gstate_c.curTextureYOffset;
}
}

BlitFramebuffer(&copyInfo, x, y, framebuffer, x, y, w, h, 0);

CopyFramebufferForColorTexture(&copyInfo, framebuffer, flags);
RebindFramebuffer();
draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, 0);
} else {
Expand Down
23 changes: 1 addition & 22 deletions GPU/Directx9/FramebufferDX9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,28 +481,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
VirtualFramebuffer copyInfo = *framebuffer;
copyInfo.fbo = renderCopy;

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) == BINDFBCOLOR_MAY_COPY_WITH_UV && gstate_c.vertBounds.maxU > gstate_c.vertBounds.minU) {
x = gstate_c.vertBounds.minU;
y = gstate_c.vertBounds.minV;
w = gstate_c.vertBounds.maxU - x;
h = gstate_c.vertBounds.maxV - y;

// If we bound a framebuffer, apply the byte offset as pixels to the copy too.
if (flags & BINDFBCOLOR_APPLY_TEX_OFFSET) {
x += gstate_c.curTextureXOffset;
y += gstate_c.curTextureYOffset;
}
}

BlitFramebuffer(&copyInfo, x, y, framebuffer, x, y, w, h, 0);

CopyFramebufferForColorTexture(&copyInfo, framebuffer, flags);
RebindFramebuffer();
draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, 0);
} else {
Expand Down
23 changes: 1 addition & 22 deletions GPU/GLES/FramebufferManagerGLES.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -547,28 +547,7 @@ void FramebufferManagerGLES::BindFramebufferAsColorTexture(int stage, VirtualFra
VirtualFramebuffer copyInfo = *framebuffer;
copyInfo.fbo = renderCopy;

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) == BINDFBCOLOR_MAY_COPY_WITH_UV && gstate_c.vertBounds.maxU > gstate_c.vertBounds.minU) {
x = gstate_c.vertBounds.minU;
y = gstate_c.vertBounds.minV;
w = gstate_c.vertBounds.maxU - x;
h = gstate_c.vertBounds.maxV - y;

// If we bound a framebuffer, apply the byte offset as pixels to the copy too.
if (flags & BINDFBCOLOR_APPLY_TEX_OFFSET) {
x += gstate_c.curTextureXOffset;
y += gstate_c.curTextureYOffset;
}
}

BlitFramebuffer(&copyInfo, x, y, framebuffer, x, y, w, h, 0);

CopyFramebufferForColorTexture(&copyInfo, framebuffer, flags);
draw_->BindFramebufferAsTexture(renderCopy, stage, Draw::FB_COLOR_BIT, 0);
} else {
draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0);
Expand Down

0 comments on commit 706714e

Please sign in to comment.