Store texture target on GrGLTexture. This is in preparation for using texture targets other than 2D.

Review URL: https://codereview.chromium.org/1403123002
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index cd6bf39..80f0171 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -426,7 +426,9 @@
     GrSurfaceDesc surfDesc;
 
     idDesc.fTextureID = static_cast<GrGLuint>(desc.fTextureHandle);
-    
+    // We only support GL_TEXTURE_2D at the moment.
+    idDesc.fTarget = GR_GL_TEXTURE_2D;
+
     switch (ownership) {
         case kAdopt_GrWrapOwnership:
             idDesc.fLifeCycle = GrGpuResource::kAdopted_LifeCycle;
@@ -457,7 +459,7 @@
     if (renderTarget) {
         GrGLRenderTarget::IDDesc rtIDDesc;
         if (!this->createRenderTargetObjects(surfDesc, GrGpuResource::kUncached_LifeCycle,
-                                             idDesc.fTextureID, &rtIDDesc)) {
+                                             idDesc.fTextureID, idDesc.fTarget, &rtIDDesc)) {
             return nullptr;
         }
         texture = new GrGLTextureRenderTarget(this, surfDesc, idDesc, rtIDDesc);
@@ -573,17 +575,17 @@
     }
 
     this->setScratchTextureUnit();
-    GL_CALL(BindTexture(GR_GL_TEXTURE_2D, glTex->textureID()));
+    GL_CALL(BindTexture(glTex->target(), glTex->textureID()));
 
     bool success = false;
     if (GrPixelConfigIsCompressed(glTex->desc().fConfig)) {
         // We check that config == desc.fConfig in GrGLGpu::canWriteTexturePixels()
         SkASSERT(config == glTex->desc().fConfig);
-        success = this->uploadCompressedTexData(glTex->desc(), buffer, false, left, top, width,
-                                                height);
+        success = this->uploadCompressedTexData(glTex->desc(), glTex->target(), buffer, false, left,
+                                                top, width, height);
     } else {
-        success = this->uploadTexData(glTex->desc(), false, left, top, width, height, config,
-                                      buffer, rowBytes);
+        success = this->uploadTexData(glTex->desc(), glTex->target(), false, left, top, width,
+                                      height, config, buffer, rowBytes);
     }
 
     if (success) {
@@ -604,6 +606,7 @@
 }
 
 bool GrGLGpu::uploadTexData(const GrSurfaceDesc& desc,
+                            GrGLenum target,
                             bool isNewTexture,
                             int left, int top, int width, int height,
                             GrPixelConfig dataConfig,
@@ -719,13 +722,13 @@
         if (useTexStorage) {
             // We never resize  or change formats of textures.
             GL_ALLOC_CALL(this->glInterface(),
-                          TexStorage2D(GR_GL_TEXTURE_2D,
+                          TexStorage2D(target,
                                        1, // levels
                                        internalFormat,
                                        desc.fWidth, desc.fHeight));
         } else {
             GL_ALLOC_CALL(this->glInterface(),
-                          TexImage2D(GR_GL_TEXTURE_2D,
+                          TexImage2D(target,
                                      0, // level
                                      internalFormat,
                                      desc.fWidth, desc.fHeight,
@@ -740,7 +743,7 @@
             // if we have data and we used TexStorage to create the texture, we
             // now upload with TexSubImage.
             if (data && useTexStorage) {
-                GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D,
+                GL_CALL(TexSubImage2D(target,
                                       0, // level
                                       left, top,
                                       width, height,
@@ -752,7 +755,7 @@
         if (swFlipY || glFlipY) {
             top = desc.fHeight - (top + height);
         }
-        GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D,
+        GL_CALL(TexSubImage2D(target,
                               0, // level
                               left, top,
                               width, height,
@@ -775,6 +778,7 @@
 // the proper upload semantics. Then users can construct this function how they
 // see fit if they want to go against the "standard" way to do it.
 bool GrGLGpu::uploadCompressedTexData(const GrSurfaceDesc& desc,
+                                      GrGLenum target,
                                       const void* data,
                                       bool isNewTexture,
                                       int left, int top, int width, int height) {
@@ -814,7 +818,7 @@
     if (isNewTexture) {
         CLEAR_ERROR_BEFORE_ALLOC(this->glInterface());
         GL_ALLOC_CALL(this->glInterface(),
-                      CompressedTexImage2D(GR_GL_TEXTURE_2D,
+                      CompressedTexImage2D(target,
                                            0, // level
                                            internalFormat,
                                            width, height,
@@ -830,7 +834,7 @@
         if (GR_GL_PALETTE8_RGBA8 == internalFormat) {
             return false;
         }
-        GL_CALL(CompressedTexSubImage2D(GR_GL_TEXTURE_2D,
+        GL_CALL(CompressedTexSubImage2D(target,
                                         0, // level
                                         left, top,
                                         width, height,
@@ -884,6 +888,7 @@
 bool GrGLGpu::createRenderTargetObjects(const GrSurfaceDesc& desc,
                                         GrGpuResource::LifeCycle lifeCycle,
                                         GrGLuint texID,
+                                        GrGLenum textureTarget,
                                         GrGLRenderTarget::IDDesc* idDesc) {
     idDesc->fMSColorRenderbufferID = 0;
     idDesc->fRTFBOID = 0;
@@ -942,9 +947,9 @@
         fStats.incRenderTargetBinds();
         GL_CALL(BindFramebuffer(GR_GL_FRAMEBUFFER, idDesc->fRTFBOID));
         GL_CALL(FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
-                                      GR_GL_COLOR_ATTACHMENT0,
-                                      GR_GL_RENDERBUFFER,
-                                      idDesc->fMSColorRenderbufferID));
+                                        GR_GL_COLOR_ATTACHMENT0,
+                                        GR_GL_RENDERBUFFER,
+                                        idDesc->fMSColorRenderbufferID));
         if ((desc.fFlags & kCheckAllocation_GrSurfaceFlag) ||
             !this->glCaps().isConfigVerifiedColorAttachment(desc.fConfig)) {
             GL_CALL_RET(status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
@@ -960,12 +965,12 @@
     if (this->glCaps().usesImplicitMSAAResolve() && desc.fSampleCnt > 0) {
         GL_CALL(FramebufferTexture2DMultisample(GR_GL_FRAMEBUFFER,
                                                 GR_GL_COLOR_ATTACHMENT0,
-                                                GR_GL_TEXTURE_2D,
+                                                textureTarget,
                                                 texID, 0, desc.fSampleCnt));
     } else {
         GL_CALL(FramebufferTexture2D(GR_GL_FRAMEBUFFER,
                                      GR_GL_COLOR_ATTACHMENT0,
-                                     GR_GL_TEXTURE_2D,
+                                     textureTarget,
                                      texID, 0));
     }
     if ((desc.fFlags & kCheckAllocation_GrSurfaceFlag) ||
@@ -1018,17 +1023,19 @@
     GrGLTexture::IDDesc idDesc;
     GL_CALL(GenTextures(1, &idDesc.fTextureID));
     idDesc.fLifeCycle = lifeCycle;
+    // We only support GL_TEXTURE_2D at the moment.
+    idDesc.fTarget = GR_GL_TEXTURE_2D;
 
     if (!idDesc.fTextureID) {
         return return_null_texture();
     }
 
     this->setScratchTextureUnit();
-    GL_CALL(BindTexture(GR_GL_TEXTURE_2D, idDesc.fTextureID));
+    GL_CALL(BindTexture(idDesc.fTarget, idDesc.fTextureID));
 
     if (renderTarget && this->glCaps().textureUsageSupport()) {
         // provides a hint about how this texture will be used
-        GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+        GL_CALL(TexParameteri(idDesc.fTarget,
                               GR_GL_TEXTURE_USAGE,
                               GR_GL_FRAMEBUFFER_ATTACHMENT));
     }
@@ -1043,19 +1050,19 @@
     initialTexParams.fMagFilter = GR_GL_NEAREST;
     initialTexParams.fWrapS = GR_GL_CLAMP_TO_EDGE;
     initialTexParams.fWrapT = GR_GL_CLAMP_TO_EDGE;
-    GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+    GL_CALL(TexParameteri(idDesc.fTarget,
                           GR_GL_TEXTURE_MAG_FILTER,
                           initialTexParams.fMagFilter));
-    GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+    GL_CALL(TexParameteri(idDesc.fTarget,
                           GR_GL_TEXTURE_MIN_FILTER,
                           initialTexParams.fMinFilter));
-    GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+    GL_CALL(TexParameteri(idDesc.fTarget,
                           GR_GL_TEXTURE_WRAP_S,
                           initialTexParams.fWrapS));
-    GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+    GL_CALL(TexParameteri(idDesc.fTarget,
                           GR_GL_TEXTURE_WRAP_T,
                           initialTexParams.fWrapT));
-    if (!this->uploadTexData(desc, true, 0, 0,
+    if (!this->uploadTexData(desc, idDesc.fTarget, true, 0, 0,
                              desc.fWidth, desc.fHeight,
                              desc.fConfig, srcData, rowBytes)) {
         GL_CALL(DeleteTextures(1, &idDesc.fTextureID));
@@ -1065,10 +1072,11 @@
     GrGLTexture* tex;
     if (renderTarget) {
         // unbind the texture from the texture unit before binding it to the frame buffer
-        GL_CALL(BindTexture(GR_GL_TEXTURE_2D, 0));
+        GL_CALL(BindTexture(idDesc.fTarget, 0));
         GrGLRenderTarget::IDDesc rtIDDesc;
 
-        if (!this->createRenderTargetObjects(desc, lifeCycle, idDesc.fTextureID, &rtIDDesc)) {
+        if (!this->createRenderTargetObjects(desc, lifeCycle, idDesc.fTextureID, idDesc.fTarget,
+                                             &rtIDDesc)) {
             GL_CALL(DeleteTextures(1, &idDesc.fTextureID));
             return return_null_texture();
         }
@@ -1095,13 +1103,15 @@
     GrGLTexture::IDDesc idDesc;
     GL_CALL(GenTextures(1, &idDesc.fTextureID));
     idDesc.fLifeCycle = lifeCycle;
+    // We only support GL_TEXTURE_2D at the moment.
+    idDesc.fTarget = GR_GL_TEXTURE_2D;
 
     if (!idDesc.fTextureID) {
         return return_null_texture();
     }
 
     this->setScratchTextureUnit();
-    GL_CALL(BindTexture(GR_GL_TEXTURE_2D, idDesc.fTextureID));
+    GL_CALL(BindTexture(idDesc.fTarget, idDesc.fTextureID));
 
     // Some drivers like to know filter/wrap before seeing glTexImage2D. Some
     // drivers have a bug where an FBO won't be complete if it includes a
@@ -1113,20 +1123,20 @@
     initialTexParams.fMagFilter = GR_GL_NEAREST;
     initialTexParams.fWrapS = GR_GL_CLAMP_TO_EDGE;
     initialTexParams.fWrapT = GR_GL_CLAMP_TO_EDGE;
-    GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+    GL_CALL(TexParameteri(idDesc.fTarget,
                           GR_GL_TEXTURE_MAG_FILTER,
                           initialTexParams.fMagFilter));
-    GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+    GL_CALL(TexParameteri(idDesc.fTarget,
                           GR_GL_TEXTURE_MIN_FILTER,
                           initialTexParams.fMinFilter));
-    GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+    GL_CALL(TexParameteri(idDesc.fTarget,
                           GR_GL_TEXTURE_WRAP_S,
                           initialTexParams.fWrapS));
-    GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
+    GL_CALL(TexParameteri(idDesc.fTarget,
                           GR_GL_TEXTURE_WRAP_T,
                           initialTexParams.fWrapT));
 
-    if (!this->uploadCompressedTexData(desc, srcData)) {
+    if (!this->uploadCompressedTexData(desc, idDesc.fTarget, srcData)) {
         GL_CALL(DeleteTextures(1, &idDesc.fTextureID));
         return return_null_texture();
     }
@@ -2293,9 +2303,10 @@
     }
 
     uint32_t textureID = texture->getUniqueID();
+    GrGLenum target = texture->target();
     if (fHWBoundTextureUniqueIDs[unitIdx] != textureID) {
         this->setTextureUnit(unitIdx);
-        GL_CALL(BindTexture(GR_GL_TEXTURE_2D, texture->textureID()));
+        GL_CALL(BindTexture(target, texture->textureID()));
         fHWBoundTextureUniqueIDs[unitIdx] = textureID;
     }
 
@@ -2327,7 +2338,7 @@
 
     if (GrTextureParams::kMipMap_FilterMode == filterMode &&
         texture->texturePriv().mipMapsAreDirty()) {
-        GL_CALL(GenerateMipmap(GR_GL_TEXTURE_2D));
+        GL_CALL(GenerateMipmap(target));
         texture->texturePriv().dirtyMipMaps(false);
     }
 
@@ -2338,27 +2349,19 @@
            sizeof(newTexParams.fSwizzleRGBA));
     if (setAll || newTexParams.fMagFilter != oldTexParams.fMagFilter) {
         this->setTextureUnit(unitIdx);
-        GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
-                              GR_GL_TEXTURE_MAG_FILTER,
-                              newTexParams.fMagFilter));
+        GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MAG_FILTER, newTexParams.fMagFilter));
     }
     if (setAll || newTexParams.fMinFilter != oldTexParams.fMinFilter) {
         this->setTextureUnit(unitIdx);
-        GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
-                              GR_GL_TEXTURE_MIN_FILTER,
-                              newTexParams.fMinFilter));
+        GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MIN_FILTER, newTexParams.fMinFilter));
     }
     if (setAll || newTexParams.fWrapS != oldTexParams.fWrapS) {
         this->setTextureUnit(unitIdx);
-        GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
-                              GR_GL_TEXTURE_WRAP_S,
-                              newTexParams.fWrapS));
+        GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_S, newTexParams.fWrapS));
     }
     if (setAll || newTexParams.fWrapT != oldTexParams.fWrapT) {
         this->setTextureUnit(unitIdx);
-        GL_CALL(TexParameteri(GR_GL_TEXTURE_2D,
-                              GR_GL_TEXTURE_WRAP_T,
-                              newTexParams.fWrapT));
+        GL_CALL(TexParameteri(target, GR_GL_TEXTURE_WRAP_T, newTexParams.fWrapT));
     }
     if (this->glCaps().textureSwizzleSupport() &&
         (setAll || memcmp(newTexParams.fSwizzleRGBA,
@@ -2368,14 +2371,14 @@
         if (this->glStandard() == kGLES_GrGLStandard) {
             // ES3 added swizzle support but not GL_TEXTURE_SWIZZLE_RGBA.
             const GrGLenum* swizzle = newTexParams.fSwizzleRGBA;
-            GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_SWIZZLE_R, swizzle[0]));
-            GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_SWIZZLE_G, swizzle[1]));
-            GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_SWIZZLE_B, swizzle[2]));
-            GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_SWIZZLE_A, swizzle[3]));
+            GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_R, swizzle[0]));
+            GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_G, swizzle[1]));
+            GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_B, swizzle[2]));
+            GL_CALL(TexParameteri(target, GR_GL_TEXTURE_SWIZZLE_A, swizzle[3]));
         } else {
             GR_STATIC_ASSERT(sizeof(newTexParams.fSwizzleRGBA[0]) == sizeof(GrGLint));
             const GrGLint* swizzle = reinterpret_cast<const GrGLint*>(newTexParams.fSwizzleRGBA);
-            GL_CALL(TexParameteriv(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_SWIZZLE_RGBA, swizzle));
+            GL_CALL(TexParameteriv(target, GR_GL_TEXTURE_SWIZZLE_RGBA, swizzle));
         }
     }
     texture->setCachedTexParams(newTexParams, this->getResetTimestamp());
@@ -2681,12 +2684,13 @@
 
 // If a temporary FBO was created, its non-zero ID is returned. The viewport that the copy rect is
 // relative to is output.
-GrGLuint GrGLGpu::bindSurfaceAsFBO(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport,
-                                   TempFBOTarget tempFBOTarget) {
+void GrGLGpu::bindSurfaceFBOForCopy(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport,
+                                    TempFBOTarget tempFBOTarget) {
     GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(surface->asRenderTarget());
     if (nullptr == rt) {
         SkASSERT(surface->asTexture());
         GrGLuint texID = static_cast<GrGLTexture*>(surface->asTexture())->textureID();
+        GrGLenum target = static_cast<GrGLTexture*>(surface->asTexture())->target();
         GrGLuint* tempFBOID;
         tempFBOID = kSrc_TempFBOTarget == tempFBOTarget ? &fTempSrcFBOID : &fTempDstFBOID;
 
@@ -2698,29 +2702,31 @@
         GR_GL_CALL(this->glInterface(), BindFramebuffer(fboTarget, *tempFBOID));
         GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget,
                                                              GR_GL_COLOR_ATTACHMENT0,
-                                                             GR_GL_TEXTURE_2D,
+                                                             target,
                                                              texID,
                                                              0));
         viewport->fLeft = 0;
         viewport->fBottom = 0;
         viewport->fWidth = surface->width();
         viewport->fHeight = surface->height();
-        return *tempFBOID;
     } else {
-        GrGLuint tempFBOID = 0;
         fStats.incRenderTargetBinds();
         GR_GL_CALL(this->glInterface(), BindFramebuffer(fboTarget, rt->renderFBOID()));
         *viewport = rt->getViewport();
-        return tempFBOID;
     }
 }
 
-void GrGLGpu::unbindTextureFromFBO(GrGLenum fboTarget) {
-    GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget,
-                                                         GR_GL_COLOR_ATTACHMENT0,
-                                                         GR_GL_TEXTURE_2D,
-                                                         0,
-                                                         0));
+void GrGLGpu::unbindTextureFBOForCopy(GrGLenum fboTarget, GrSurface* surface) {
+    // bindSurfaceFBOForCopy temporarily binds textures that are not render targets to 
+    if (!surface->asRenderTarget()) {
+        SkASSERT(surface->asTexture());
+        GrGLenum textureTarget = static_cast<GrGLTexture*>(surface->asTexture())->target();
+        GR_GL_CALL(this->glInterface(), FramebufferTexture2D(fboTarget,
+                                                             GR_GL_COLOR_ATTACHMENT0,
+                                                             textureTarget,
+                                                             0,
+                                                             0));
+    }
 }
 
 bool GrGLGpu::initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const {
@@ -2968,9 +2974,8 @@
                                            const SkIRect& srcRect,
                                            const SkIPoint& dstPoint) {
     SkASSERT(can_copy_texsubimage(dst, src, this));
-    GrGLuint srcFBO;
     GrGLIRect srcVP;
-    srcFBO = this->bindSurfaceAsFBO(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget);
+    this->bindSurfaceFBOForCopy(src, GR_GL_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget);
     GrGLTexture* dstTex = static_cast<GrGLTexture*>(dst->asTexture());
     SkASSERT(dstTex);
     // We modified the bound FBO
@@ -2984,20 +2989,18 @@
                             src->origin());
 
     this->setScratchTextureUnit();
-    GL_CALL(BindTexture(GR_GL_TEXTURE_2D, dstTex->textureID()));
+    GL_CALL(BindTexture(dstTex->target(), 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,
+    GL_CALL(CopyTexSubImage2D(dstTex->target(), 0,
                                 dstPoint.fX, dstY,
                                 srcGLRect.fLeft, srcGLRect.fBottom,
                                 srcGLRect.fWidth, srcGLRect.fHeight));
-    if (srcFBO) {
-        this->unbindTextureFromFBO(GR_GL_FRAMEBUFFER);
-    }
+    this->unbindTextureFBOForCopy(GR_GL_FRAMEBUFFER, src);
 }
 
 bool GrGLGpu::copySurfaceAsBlitFramebuffer(GrSurface* dst,
@@ -3013,14 +3016,10 @@
         }
     }
 
-    GrGLuint dstFBO;
-    GrGLuint srcFBO;
     GrGLIRect dstVP;
     GrGLIRect srcVP;
-    dstFBO = this->bindSurfaceAsFBO(dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP,
-                                    kDst_TempFBOTarget);
-    srcFBO = this->bindSurfaceAsFBO(src, GR_GL_READ_FRAMEBUFFER, &srcVP,
-                                    kSrc_TempFBOTarget);
+    this->bindSurfaceFBOForCopy(dst, GR_GL_DRAW_FRAMEBUFFER, &dstVP, kDst_TempFBOTarget);
+    this->bindSurfaceFBOForCopy(src, GR_GL_READ_FRAMEBUFFER, &srcVP, kSrc_TempFBOTarget);
     // We modified the bound FBO
     fHWBoundRenderTargetUniqueID = SK_InvalidUniqueID;
     GrGLIRect srcGLRect;
@@ -3060,12 +3059,8 @@
                             dstGLRect.fLeft + dstGLRect.fWidth,
                             dstGLRect.fBottom + dstGLRect.fHeight,
                             GR_GL_COLOR_BUFFER_BIT, GR_GL_NEAREST));
-    if (dstFBO) {
-        this->unbindTextureFromFBO(GR_GL_DRAW_FRAMEBUFFER);
-    }
-    if (srcFBO) {
-        this->unbindTextureFromFBO(GR_GL_READ_FRAMEBUFFER);
-    }
+    this->unbindTextureFBOForCopy(GR_GL_DRAW_FRAMEBUFFER, dst);
+    this->unbindTextureFBOForCopy(GR_GL_READ_FRAMEBUFFER, src);
     return true;
 }
 
diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h
index dee2012..3fa498c 100644
--- a/src/gpu/gl/GrGLGpu.h
+++ b/src/gpu/gl/GrGLGpu.h
@@ -273,6 +273,7 @@
                            GrGLenum* externalType) const;
     // helper for onCreateTexture and writeTexturePixels
     bool uploadTexData(const GrSurfaceDesc& desc,
+                       GrGLenum target,
                        bool isNewTexture,
                        int left, int top, int width, int height,
                        GrPixelConfig dataConfig,
@@ -286,23 +287,29 @@
     // the texture is already in GPU memory and that it's going to be updated
     // with new data.
     bool uploadCompressedTexData(const GrSurfaceDesc& desc,
+                                 GrGLenum target,
                                  const void* data,
                                  bool isNewTexture = true,
                                  int left = 0, int top = 0,
                                  int width = -1, int height = -1);
 
     bool createRenderTargetObjects(const GrSurfaceDesc&, GrGpuResource::LifeCycle lifeCycle,
-                                   GrGLuint texID, GrGLRenderTarget::IDDesc*);
+                                   GrGLenum textureTarget, GrGLuint texID,
+                                   GrGLRenderTarget::IDDesc*);
 
     enum TempFBOTarget {
         kSrc_TempFBOTarget,
         kDst_TempFBOTarget
     };
 
-    GrGLuint bindSurfaceAsFBO(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport,
+    // Binds a surface as a FBO for a copy operation. If the surface already owns an FBO ID then
+    // that ID is bound. If not the surface is temporarily bound to a FBO and that FBO is bound.
+    // This must be paired with a call to unbindSurfaceFBOForCopy().
+    void bindSurfaceFBOForCopy(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport,
                               TempFBOTarget tempFBOTarget);
 
-    void unbindTextureFromFBO(GrGLenum fboTarget);
+    // Must be called if bindSurfaceFBOForCopy was used to bind a surface for copying.
+    void unbindTextureFBOForCopy(GrGLenum fboTarget, GrSurface* surface);
 
     SkAutoTUnref<GrGLContext>  fGLContext;
 
diff --git a/src/gpu/gl/GrGLTexture.cpp b/src/gpu/gl/GrGLTexture.cpp
index 6f70d51..29f7423 100644
--- a/src/gpu/gl/GrGLTexture.cpp
+++ b/src/gpu/gl/GrGLTexture.cpp
@@ -30,6 +30,7 @@
     SkASSERT(0 != idDesc.fTextureID);
     fTexParams.invalidate();
     fTexParamsTimestamp = GrGpu::kExpiredTimestamp;
+    fTarget = idDesc.fTarget;
     fTextureID = idDesc.fTextureID;
     fTextureIDLifecycle = idDesc.fLifeCycle;
 }
diff --git a/src/gpu/gl/GrGLTexture.h b/src/gpu/gl/GrGLTexture.h
index cffc64a..40a68eb 100644
--- a/src/gpu/gl/GrGLTexture.h
+++ b/src/gpu/gl/GrGLTexture.h
@@ -28,6 +28,7 @@
     };
 
     struct IDDesc {
+        GrGLenum                    fTarget;
         GrGLuint                    fTextureID;
         GrGpuResource::LifeCycle    fLifeCycle;
     };
@@ -52,6 +53,8 @@
 
     GrGLuint textureID() const { return fTextureID; }
 
+    GrGLenum target() const { return fTarget; }
+
 protected:
     // The public constructor registers this object with the cache. However, only the most derived
     // class should register with the cache. This constructor does not do the registration and
@@ -69,6 +72,7 @@
 private:
     TexParams                       fTexParams;
     GrGpu::ResetTimestamp           fTexParamsTimestamp;
+    GrGLenum                        fTarget;
     GrGLuint                        fTextureID;
 
     // We track this separately from GrGpuResource because this may be both a texture and a render