Use blitframebuffer to implement copySurface.
Author: bsalomon@google.com Reviewed By: robertphillips@google.com Review URL: https://chromiumcodereview.appspot.com/13910009 git-svn-id: http://skia.googlecode.com/svn/trunk@8633 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
5a6324e314
commit
63150afcc0
@ -45,12 +45,6 @@ protected:
|
||||
}
|
||||
|
||||
virtual void onDraw(SkCanvas* canvas) {
|
||||
// FIXME: Currently necessary for GPU to be able to make dst-copy in SampleApp because
|
||||
// main layer is not a texture.
|
||||
SkPaint layerPaint;
|
||||
layerPaint.setXfermodeMode(SkXfermode::kSrc_Mode);
|
||||
canvas->saveLayer(NULL, &layerPaint);
|
||||
|
||||
SkPaint bgPaint;
|
||||
bgPaint.setShader(fBG.get());
|
||||
canvas->drawPaint(bgPaint);
|
||||
@ -86,8 +80,6 @@ protected:
|
||||
areaSqrt/50,
|
||||
SkIntToScalar(size.fHeight / 2),
|
||||
txtPaint);
|
||||
|
||||
canvas->restore();
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -411,12 +411,6 @@ bool GrDrawTarget::setupDstReadIfNecessary(DrawInfo* info) {
|
||||
return true;
|
||||
}
|
||||
GrRenderTarget* rt = this->drawState()->getRenderTarget();
|
||||
// If the dst is not a texture then we don't currently have a way of copying the
|
||||
// texture. TODO: API-specific impl of onCopySurface that can handle more cases.
|
||||
if (NULL == rt->asTexture()) {
|
||||
GrPrintf("Reading Dst of non-texture render target is not currently supported.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
const GrClipData* clip = this->getClip();
|
||||
GrIRect copyRect;
|
||||
@ -435,11 +429,8 @@ bool GrDrawTarget::setupDstReadIfNecessary(DrawInfo* info) {
|
||||
#endif
|
||||
}
|
||||
|
||||
// The draw will resolve dst if it has MSAA. Two things to consider in the future:
|
||||
// 1) to make the dst values be pre-resolve we'd need to be able to copy to MSAA
|
||||
// texture and sample it correctly in the shader. 2) If 1 isn't available then we
|
||||
// should just resolve and use the resolved texture directly rather than making a
|
||||
// copy of it.
|
||||
// MSAA consideration: When there is support for reading MSAA samples in the shader we could
|
||||
// have per-sample dst values by making the copy multisampled.
|
||||
GrTextureDesc desc;
|
||||
desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
|
||||
desc.fWidth = copyRect.width();
|
||||
|
@ -36,7 +36,7 @@ struct GrGLIRect {
|
||||
GR_GL_GetIntegerv(gl, GR_GL_VIEWPORT, (GrGLint*) this);
|
||||
}
|
||||
|
||||
// sometimes we have a GrIRect from the client that we
|
||||
// sometimes we have a SkIRect from the client that we
|
||||
// want to simultaneously make relative to GL's viewport
|
||||
// and (optionally) convert from top-down to bottom-up.
|
||||
void setRelativeTo(const GrGLIRect& glRect,
|
||||
|
@ -2227,6 +2227,157 @@ void GrGpuGL::setSpareTextureUnit() {
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Determines whether glBlitFramebuffer could be used between src and dst.
|
||||
inline bool can_blit_framebuffer(const GrSurface* dst, const GrSurface* src, const GrGpuGL* gpu) {
|
||||
return gpu->isConfigRenderable(dst->config()) && gpu->isConfigRenderable(src->config()) &&
|
||||
(GrGLCaps::kDesktopEXT_MSFBOType == gpu->glCaps().msFBOType() ||
|
||||
GrGLCaps::kDesktopARB_MSFBOType == gpu->glCaps().msFBOType());
|
||||
}
|
||||
}
|
||||
|
||||
bool GrGpuGL::onCopySurface(GrSurface* dst,
|
||||
GrSurface* src,
|
||||
const SkIRect& srcRect,
|
||||
const SkIPoint& dstPoint) {
|
||||
// TODO: Add support for glCopyTexSubImage for cases when src is an FBO and dst is not
|
||||
// renderable or we don't have glBlitFramebuffer.
|
||||
bool copied = false;
|
||||
// Check whether both src and dst could be attached to an FBO and we're on a GL that supports
|
||||
// glBlitFramebuffer.
|
||||
if (can_blit_framebuffer(dst, src, this)) {
|
||||
SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
|
||||
srcRect.width(), srcRect.height());
|
||||
bool selfOverlap = false;
|
||||
if (dst->isSameAs(src)) {
|
||||
selfOverlap = SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect);
|
||||
}
|
||||
|
||||
if (!selfOverlap) {
|
||||
GrGLuint dstFBO = 0;
|
||||
GrGLuint srcFBO = 0;
|
||||
GrGLIRect dstVP;
|
||||
GrGLIRect srcVP;
|
||||
GrGLRenderTarget* dstRT = static_cast<GrGLRenderTarget*>(dst->asRenderTarget());
|
||||
GrGLRenderTarget* srcRT = static_cast<GrGLRenderTarget*>(src->asRenderTarget());
|
||||
if (NULL == dstRT) {
|
||||
GrAssert(NULL != dst->asTexture());
|
||||
GrGLuint texID = static_cast<GrGLTexture*>(dst->asTexture())->textureID();
|
||||
GL_CALL(GenFramebuffers(1, &dstFBO));
|
||||
GL_CALL(BindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, dstFBO));
|
||||
GL_CALL(FramebufferTexture2D(GR_GL_DRAW_FRAMEBUFFER,
|
||||
GR_GL_COLOR_ATTACHMENT0,
|
||||
GR_GL_TEXTURE_2D,
|
||||
texID,
|
||||
0));
|
||||
dstVP.fLeft = 0;
|
||||
dstVP.fBottom = 0;
|
||||
dstVP.fWidth = dst->width();
|
||||
dstVP.fHeight = dst->height();
|
||||
} else {
|
||||
GL_CALL(BindFramebuffer(GR_GL_DRAW_FRAMEBUFFER, dstRT->renderFBOID()));
|
||||
dstVP = dstRT->getViewport();
|
||||
}
|
||||
if (NULL == srcRT) {
|
||||
GrAssert(NULL != src->asTexture());
|
||||
GrGLuint texID = static_cast<GrGLTexture*>(src->asTexture())->textureID();
|
||||
GL_CALL(GenFramebuffers(1, &srcFBO));
|
||||
GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, srcFBO));
|
||||
GL_CALL(FramebufferTexture2D(GR_GL_READ_FRAMEBUFFER,
|
||||
GR_GL_COLOR_ATTACHMENT0,
|
||||
GR_GL_TEXTURE_2D,
|
||||
texID,
|
||||
0));
|
||||
srcVP.fLeft = 0;
|
||||
srcVP.fBottom = 0;
|
||||
srcVP.fWidth = src->width();
|
||||
srcVP.fHeight = src->height();
|
||||
} else {
|
||||
GL_CALL(BindFramebuffer(GR_GL_READ_FRAMEBUFFER, srcRT->renderFBOID()));
|
||||
srcVP = srcRT->getViewport();
|
||||
}
|
||||
|
||||
// We modified the bound FB
|
||||
fHWBoundRenderTarget = NULL;
|
||||
GrGLIRect srcGLRect;
|
||||
GrGLIRect dstGLRect;
|
||||
srcGLRect.setRelativeTo(srcVP,
|
||||
srcRect.fLeft,
|
||||
srcRect.fTop,
|
||||
srcRect.width(),
|
||||
srcRect.height(),
|
||||
src->origin());
|
||||
dstGLRect.setRelativeTo(dstVP,
|
||||
dstRect.fLeft,
|
||||
dstRect.fTop,
|
||||
dstRect.width(),
|
||||
dstRect.height(),
|
||||
dst->origin());
|
||||
|
||||
GrAutoTRestore<ScissorState> asr;
|
||||
if (GrGLCaps::kDesktopEXT_MSFBOType == this->glCaps().msFBOType()) {
|
||||
// The EXT version applies the scissor during the blit, so disable it.
|
||||
asr.reset(&fScissorState);
|
||||
fScissorState.fEnabled = false;
|
||||
this->flushScissor();
|
||||
}
|
||||
GrGLint srcY0;
|
||||
GrGLint srcY1;
|
||||
// Does the blit need to y-mirror or not?
|
||||
if (src->origin() == dst->origin()) {
|
||||
srcY0 = srcGLRect.fBottom;
|
||||
srcY1 = srcGLRect.fBottom + srcGLRect.fHeight;
|
||||
} else {
|
||||
srcY0 = srcGLRect.fBottom + srcGLRect.fHeight;
|
||||
srcY1 = srcGLRect.fBottom;
|
||||
}
|
||||
GL_CALL(BlitFramebuffer(srcGLRect.fLeft,
|
||||
srcY0,
|
||||
srcGLRect.fLeft + srcGLRect.fWidth,
|
||||
srcY1,
|
||||
dstGLRect.fLeft,
|
||||
dstGLRect.fBottom,
|
||||
dstGLRect.fLeft + dstGLRect.fWidth,
|
||||
dstGLRect.fBottom + dstGLRect.fHeight,
|
||||
GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
|
||||
if (dstFBO) {
|
||||
GL_CALL(DeleteFramebuffers(1, &dstFBO));
|
||||
}
|
||||
if (srcFBO) {
|
||||
GL_CALL(DeleteFramebuffers(1, &srcFBO));
|
||||
}
|
||||
copied = true;
|
||||
}
|
||||
}
|
||||
if (!copied) {
|
||||
copied = INHERITED::onCopySurface(dst, src, srcRect, dstPoint);
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
|
||||
bool GrGpuGL::onCanCopySurface(GrSurface* dst,
|
||||
GrSurface* src,
|
||||
const SkIRect& srcRect,
|
||||
const SkIPoint& dstPoint) {
|
||||
// This mirrors the logic in onCopySurface.
|
||||
bool canBlitFramebuffer = false;
|
||||
if (can_blit_framebuffer(dst, src, this)) {
|
||||
SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
|
||||
srcRect.width(), srcRect.height());
|
||||
if (dst->isSameAs(src)) {
|
||||
canBlitFramebuffer = !SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect);
|
||||
} else {
|
||||
canBlitFramebuffer = true;
|
||||
}
|
||||
}
|
||||
if (canBlitFramebuffer) {
|
||||
return true;
|
||||
} else {
|
||||
return INHERITED::onCanCopySurface(dst, src, srcRect, dstPoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrGLAttribArrayState* GrGpuGL::HWGeometryState::bindArrayAndBuffersToDraw(
|
||||
|
@ -85,6 +85,18 @@ public:
|
||||
void notifyTextureDelete(GrGLTexture* texture);
|
||||
void notifyRenderTargetDelete(GrRenderTarget* renderTarget);
|
||||
|
||||
protected:
|
||||
virtual bool onCopySurface(GrSurface* dst,
|
||||
GrSurface* src,
|
||||
const SkIRect& srcRect,
|
||||
const SkIPoint& dstPoint) SK_OVERRIDE;
|
||||
|
||||
virtual bool onCanCopySurface(GrSurface* dst,
|
||||
GrSurface* src,
|
||||
const SkIRect& srcRect,
|
||||
const SkIPoint& dstPoint) SK_OVERRIDE;
|
||||
|
||||
|
||||
private:
|
||||
// GrGpu overrides
|
||||
virtual void onResetContext() SK_OVERRIDE;
|
||||
|
Loading…
Reference in New Issue
Block a user