Add support for using glCopyTexSubImage2D when possible to copy surfaces.
Review URL: https://codereview.chromium.org/13915011 git-svn-id: http://skia.googlecode.com/svn/trunk@8675 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
ab38e560e9
commit
eb85117c05
@ -432,11 +432,9 @@ bool GrDrawTarget::setupDstReadIfNecessary(DrawInfo* info) {
|
||||
// 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;
|
||||
this->initCopySurfaceDstDesc(rt, &desc);
|
||||
desc.fWidth = copyRect.width();
|
||||
desc.fHeight = copyRect.height();
|
||||
desc.fSampleCnt = 0;
|
||||
desc.fConfig = rt->config();
|
||||
|
||||
GrAutoScratchTexture ast(fContext, desc, GrContext::kApprox_ScratchTexMatch);
|
||||
|
||||
@ -447,7 +445,7 @@ bool GrDrawTarget::setupDstReadIfNecessary(DrawInfo* info) {
|
||||
SkIPoint dstPoint = {0, 0};
|
||||
if (this->copySurface(ast.texture(), rt, copyRect, dstPoint)) {
|
||||
info->fDstCopy.setTexture(ast.texture());
|
||||
info->fDstCopy.setOffset(copyRect.fLeft, copyRect.fTop);
|
||||
info->fDstCopy.setOffset(copyRect.fLeft, copyRect.fTop);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@ -881,6 +879,13 @@ bool GrDrawTarget::onCopySurface(GrSurface* dst,
|
||||
return true;
|
||||
}
|
||||
|
||||
void GrDrawTarget::initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) {
|
||||
// Make the dst of the copy be a render target because the default copySurface draws to the dst.
|
||||
desc->fOrigin = kDefault_GrSurfaceOrigin;
|
||||
desc->fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
|
||||
desc->fConfig = src->config();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SK_DEFINE_INST_COUNT(GrDrawTargetCaps)
|
||||
|
@ -431,6 +431,14 @@ public:
|
||||
const SkIRect& srcRect,
|
||||
const SkIPoint& dstPoint);
|
||||
|
||||
/**
|
||||
* This is can be called before allocating a texture to be a dst for copySurface. It will
|
||||
* populate the origin, config, and flags fields of the desc such that copySurface is more
|
||||
* likely to succeed and be efficient.
|
||||
*/
|
||||
virtual void initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc);
|
||||
|
||||
|
||||
/**
|
||||
* Release any resources that are cached but not currently in use. This
|
||||
* is intended to give an application some recourse when resources are low.
|
||||
|
@ -540,6 +540,10 @@ bool GrInOrderDrawBuffer::onCanCopySurface(GrSurface* dst,
|
||||
return fDstGpu->canCopySurface(dst, src, srcRect, dstPoint);
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) {
|
||||
fDstGpu->initCopySurfaceDstDesc(src, desc);
|
||||
}
|
||||
|
||||
void GrInOrderDrawBuffer::willReserveVertexAndIndexSpace(
|
||||
int vertexCount,
|
||||
int indexCount) {
|
||||
|
@ -77,6 +77,9 @@ public:
|
||||
GrColor color,
|
||||
GrRenderTarget* renderTarget = NULL) SK_OVERRIDE;
|
||||
|
||||
virtual void initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) SK_OVERRIDE;
|
||||
|
||||
|
||||
protected:
|
||||
virtual void clipWillBeSet(const GrClipData* newClip) SK_OVERRIDE;
|
||||
|
||||
|
@ -2229,23 +2229,142 @@ 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());
|
||||
inline bool can_blit_framebuffer(const GrSurface* dst,
|
||||
const GrSurface* src,
|
||||
const GrGpuGL* gpu,
|
||||
bool* wouldNeedTempFBO = NULL) {
|
||||
if (gpu->isConfigRenderable(dst->config()) && gpu->isConfigRenderable(src->config()) &&
|
||||
(GrGLCaps::kDesktopEXT_MSFBOType == gpu->glCaps().msFBOType() ||
|
||||
GrGLCaps::kDesktopARB_MSFBOType == gpu->glCaps().msFBOType())) {
|
||||
if (NULL != wouldNeedTempFBO) {
|
||||
*wouldNeedTempFBO = NULL == dst->asRenderTarget() || NULL == src->asRenderTarget();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool can_copy_texsubimage(const GrSurface* dst,
|
||||
const GrSurface* src,
|
||||
const GrGpuGL* gpu,
|
||||
bool* wouldNeedTempFBO = NULL) {
|
||||
// Table 3.9 of the ES2 spec indicates the supported formats with CopyTexSubImage
|
||||
// and BGRA isn't in the spec. There doesn't appear to be any extension that adds it. Perhaps
|
||||
// many drivers would allow it to work, but ANGLE does not.
|
||||
if (kES2_GrGLBinding == gpu->glBinding() && gpu->glCaps().bgraIsInternalFormat() &&
|
||||
(kBGRA_8888_GrPixelConfig == dst->config() || kBGRA_8888_GrPixelConfig == src->config())) {
|
||||
return false;
|
||||
}
|
||||
const GrGLRenderTarget* dstRT = static_cast<const GrGLRenderTarget*>(dst->asRenderTarget());
|
||||
// If dst is multisampled (and uses an extension where there is a separate MSAA renderbuffer)
|
||||
// then we don't want to copy to the texture but to the MSAA buffer.
|
||||
if (NULL != dstRT && dstRT->renderFBOID() != dstRT->textureFBOID()) {
|
||||
return false;
|
||||
}
|
||||
if (gpu->isConfigRenderable(src->config()) && NULL != dst->asTexture() &&
|
||||
dst->origin() == src->origin() && kIndex_8_GrPixelConfig != src->config()) {
|
||||
if (NULL != wouldNeedTempFBO) {
|
||||
*wouldNeedTempFBO = NULL == src->asRenderTarget();
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If a temporary FBO was created, its non-zero ID is returned. The viewport that the copy rect is
|
||||
// relative to is output.
|
||||
inline GrGLuint bind_surface_as_fbo(const GrGLInterface* gl,
|
||||
GrSurface* surface,
|
||||
GrGLenum fboTarget,
|
||||
GrGLIRect* viewport) {
|
||||
GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
|
||||
GrGLuint tempFBOID;
|
||||
if (NULL == rt) {
|
||||
GrAssert(NULL != surface->asTexture());
|
||||
GrGLuint texID = static_cast<GrGLTexture*>(surface->asTexture())->textureID();
|
||||
GR_GL_CALL(gl, GenFramebuffers(1, &tempFBOID));
|
||||
GR_GL_CALL(gl, BindFramebuffer(fboTarget, tempFBOID));
|
||||
GR_GL_CALL(gl, FramebufferTexture2D(fboTarget,
|
||||
GR_GL_COLOR_ATTACHMENT0,
|
||||
GR_GL_TEXTURE_2D,
|
||||
texID,
|
||||
0));
|
||||
viewport->fLeft = 0;
|
||||
viewport->fBottom = 0;
|
||||
viewport->fWidth = surface->width();
|
||||
viewport->fHeight = surface->height();
|
||||
} else {
|
||||
tempFBOID = 0;
|
||||
GR_GL_CALL(gl, BindFramebuffer(fboTarget, rt->renderFBOID()));
|
||||
*viewport = rt->getViewport();
|
||||
}
|
||||
return tempFBOID;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GrGpuGL::initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) {
|
||||
// Check for format issues with glCopyTexSubImage2D
|
||||
if (kES2_GrGLBinding == this->glBinding() && this->glCaps().bgraIsInternalFormat() &&
|
||||
kBGRA_8888_GrPixelConfig == src->config()) {
|
||||
// glCopyTexSubImage2D doesn't work with this config. We'll want to make it a render target
|
||||
// to in order to call glBlitFramebuffer or to copy to it by rendering.
|
||||
INHERITED::initCopySurfaceDstDesc(src, desc);
|
||||
} else if (NULL == src->asRenderTarget()) {
|
||||
// We don't want to have to create an FBO just to use glCopyTexSubImage2D. Let the base
|
||||
// class handle it by rendering.
|
||||
INHERITED::initCopySurfaceDstDesc(src, desc);
|
||||
} else {
|
||||
desc->fConfig = src->config();
|
||||
desc->fOrigin = src->origin();
|
||||
desc->fFlags = kNone_GrTextureFlags;
|
||||
}
|
||||
}
|
||||
|
||||
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 inheritedCouldCopy = INHERITED::onCanCopySurface(dst, src, srcRect, dstPoint);
|
||||
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)) {
|
||||
bool wouldNeedTempFBO = false;
|
||||
if (can_copy_texsubimage(dst, src, this, &wouldNeedTempFBO) &&
|
||||
(!wouldNeedTempFBO || !inheritedCouldCopy)) {
|
||||
GrGLuint srcFBO;
|
||||
GrGLIRect srcVP;
|
||||
srcFBO = bind_surface_as_fbo(this->glInterface(), src, GR_GL_FRAMEBUFFER, &srcVP);
|
||||
GrGLTexture* dstTex = static_cast<GrGLTexture*>(dst->asTexture());
|
||||
GrAssert(NULL != dstTex);
|
||||
// We modified the bound FBO
|
||||
fHWBoundRenderTarget = NULL;
|
||||
GrGLIRect srcGLRect;
|
||||
srcGLRect.setRelativeTo(srcVP,
|
||||
srcRect.fLeft,
|
||||
srcRect.fTop,
|
||||
srcRect.width(),
|
||||
srcRect.height(),
|
||||
src->origin());
|
||||
|
||||
this->setSpareTextureUnit();
|
||||
GL_CALL(BindTexture(GR_GL_TEXTURE_2D, dstTex->textureID()));
|
||||
GrGLint dstY;
|
||||
if (kBottomLeft_GrSurfaceOrigin == dst->origin()) {
|
||||
dstY = dst->height() - (dstPoint.fY + srcGLRect.fHeight);
|
||||
} else {
|
||||
dstY = dstPoint.fY;
|
||||
}
|
||||
GL_CALL(CopyTexSubImage2D(GR_GL_TEXTURE_2D, 0,
|
||||
dstPoint.fX, dstY,
|
||||
srcGLRect.fLeft, srcGLRect.fBottom,
|
||||
srcGLRect.fWidth, srcGLRect.fHeight));
|
||||
copied = true;
|
||||
if (srcFBO) {
|
||||
GL_CALL(DeleteFramebuffers(1, &srcFBO));
|
||||
}
|
||||
} else if (can_blit_framebuffer(dst, src, this, &wouldNeedTempFBO) &&
|
||||
(!wouldNeedTempFBO || !inheritedCouldCopy)) {
|
||||
SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
|
||||
srcRect.width(), srcRect.height());
|
||||
bool selfOverlap = false;
|
||||
@ -2254,50 +2373,13 @@ bool GrGpuGL::onCopySurface(GrSurface* dst,
|
||||
}
|
||||
|
||||
if (!selfOverlap) {
|
||||
GrGLuint dstFBO = 0;
|
||||
GrGLuint srcFBO = 0;
|
||||
GrGLuint dstFBO;
|
||||
GrGLuint srcFBO;
|
||||
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
|
||||
dstFBO = bind_surface_as_fbo(this->glInterface(), dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP);
|
||||
srcFBO = bind_surface_as_fbo(this->glInterface(), src, GR_GL_READ_FRAMEBUFFER, &srcVP);
|
||||
// We modified the bound FBO
|
||||
fHWBoundRenderTarget = NULL;
|
||||
GrGLIRect srcGLRect;
|
||||
GrGLIRect dstGLRect;
|
||||
@ -2349,8 +2431,9 @@ bool GrGpuGL::onCopySurface(GrSurface* dst,
|
||||
copied = true;
|
||||
}
|
||||
}
|
||||
if (!copied) {
|
||||
if (!copied && inheritedCouldCopy) {
|
||||
copied = INHERITED::onCopySurface(dst, src, srcRect, dstPoint);
|
||||
GrAssert(copied);
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
@ -2360,21 +2443,21 @@ bool GrGpuGL::onCanCopySurface(GrSurface* dst,
|
||||
const SkIRect& srcRect,
|
||||
const SkIPoint& dstPoint) {
|
||||
// This mirrors the logic in onCopySurface.
|
||||
bool canBlitFramebuffer = false;
|
||||
if (can_copy_texsubimage(dst, src, this)) {
|
||||
return true;
|
||||
}
|
||||
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);
|
||||
SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY,
|
||||
srcRect.width(), srcRect.height());
|
||||
if(!SkIRect::IntersectsNoEmptyCheck(dstRect, srcRect)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
canBlitFramebuffer = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (canBlitFramebuffer) {
|
||||
return true;
|
||||
} else {
|
||||
return INHERITED::onCanCopySurface(dst, src, srcRect, dstPoint);
|
||||
}
|
||||
return INHERITED::onCanCopySurface(dst, src, srcRect, dstPoint);
|
||||
}
|
||||
|
||||
|
||||
|
@ -55,6 +55,8 @@ public:
|
||||
size_t rowBytes) const SK_OVERRIDE;
|
||||
virtual bool fullReadPixelsIsFasterThanPartial() const SK_OVERRIDE;
|
||||
|
||||
virtual void initCopySurfaceDstDesc(const GrSurface* src, GrTextureDesc* desc) SK_OVERRIDE;
|
||||
|
||||
virtual void abandonResources() SK_OVERRIDE;
|
||||
|
||||
const GrGLCaps& glCaps() const { return *fGLContext.info().caps(); }
|
||||
@ -96,7 +98,6 @@ protected:
|
||||
const SkIRect& srcRect,
|
||||
const SkIPoint& dstPoint) SK_OVERRIDE;
|
||||
|
||||
|
||||
private:
|
||||
// GrGpu overrides
|
||||
virtual void onResetContext() SK_OVERRIDE;
|
||||
|
Loading…
Reference in New Issue
Block a user