| Index: src/gpu/gl/GrGLGpu.cpp
 | 
| diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
 | 
| index 2bd36b640477eaf1b14a60003436553b9a344b0f..51145c89883e99836fc4c50b30fa8095bbd4755d 100644
 | 
| --- a/src/gpu/gl/GrGLGpu.cpp
 | 
| +++ b/src/gpu/gl/GrGLGpu.cpp
 | 
| @@ -233,7 +233,7 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context)
 | 
|          fPathRendering.reset(new GrGLPathRendering(this));
 | 
|      }
 | 
|  
 | 
| -    this->createCopyProgram();
 | 
| +    this->createCopyPrograms();
 | 
|  }
 | 
|  
 | 
|  GrGLGpu::~GrGLGpu() {
 | 
| @@ -253,12 +253,13 @@ GrGLGpu::~GrGLGpu() {
 | 
|          GL_CALL(DeleteFramebuffers(1, &fStencilClearFBOID));
 | 
|      }
 | 
|  
 | 
| -    if (0 != fCopyProgram.fArrayBuffer) {
 | 
| -        GL_CALL(DeleteBuffers(1, &fCopyProgram.fArrayBuffer));
 | 
| +    for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) {
 | 
| +        if (0 != fCopyPrograms[i].fProgram) {
 | 
| +            GL_CALL(DeleteProgram(fCopyPrograms[i].fProgram));
 | 
| +        }
 | 
|      }
 | 
| -
 | 
| -    if (0 != fCopyProgram.fProgram) {
 | 
| -        GL_CALL(DeleteProgram(fCopyProgram.fProgram));
 | 
| +    if (0 != fCopyProgramArrayBuffer) {
 | 
| +        GL_CALL(DeleteBuffers(1, &fCopyProgramArrayBuffer));
 | 
|      }
 | 
|  
 | 
|      delete fProgramCache;
 | 
| @@ -271,8 +272,10 @@ void GrGLGpu::contextAbandoned() {
 | 
|      fTempSrcFBOID = 0;
 | 
|      fTempDstFBOID = 0;
 | 
|      fStencilClearFBOID = 0;
 | 
| -    fCopyProgram.fArrayBuffer = 0;
 | 
| -    fCopyProgram.fProgram = 0;
 | 
| +    fCopyProgramArrayBuffer = 0;
 | 
| +    for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) {
 | 
| +        fCopyPrograms[i].fProgram = 0;
 | 
| +    }
 | 
|      if (this->glCaps().shaderCaps()->pathRenderingSupport()) {
 | 
|          this->glPathRendering()->abandonGpuResources();
 | 
|      }
 | 
| @@ -429,6 +432,9 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc,
 | 
|          return nullptr;
 | 
|      }
 | 
|  
 | 
| +    // next line relies on GrBackendTextureDesc's flags matching GrTexture's
 | 
| +    bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrBackendTextureFlag);
 | 
| +
 | 
|      GrGLTexture::IDDesc idDesc;
 | 
|      GrSurfaceDesc surfDesc;
 | 
|  
 | 
| @@ -439,6 +445,15 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc,
 | 
|  #else
 | 
|      idDesc.fInfo = *info;
 | 
|  #endif
 | 
| +    if (GR_GL_TEXTURE_EXTERNAL == idDesc.fInfo.fTarget) {
 | 
| +        if (renderTarget) {
 | 
| +            // This combination is not supported.
 | 
| +            return nullptr;
 | 
| +        }
 | 
| +        if (!this->glCaps().externalTextureSupport()) {
 | 
| +            return nullptr;
 | 
| +        }
 | 
| +    }
 | 
|  
 | 
|      switch (ownership) {
 | 
|          case kAdopt_GrWrapOwnership:
 | 
| @@ -449,13 +464,11 @@ GrTexture* GrGLGpu::onWrapBackendTexture(const GrBackendTextureDesc& desc,
 | 
|              break;
 | 
|      }    
 | 
|  
 | 
| -    // next line relies on GrBackendTextureDesc's flags matching GrTexture's
 | 
|      surfDesc.fFlags = (GrSurfaceFlags) desc.fFlags;
 | 
|      surfDesc.fWidth = desc.fWidth;
 | 
|      surfDesc.fHeight = desc.fHeight;
 | 
|      surfDesc.fConfig = desc.fConfig;
 | 
|      surfDesc.fSampleCnt = SkTMin(desc.fSampleCnt, this->caps()->maxSampleCount());
 | 
| -    bool renderTarget = SkToBool(desc.fFlags & kRenderTarget_GrBackendTextureFlag);
 | 
|      // FIXME:  this should be calling resolve_origin(), but Chrome code is currently
 | 
|      // assuming the old behaviour, which is that backend textures are always
 | 
|      // BottomLeft, even for non-RT's.  Once Chrome is fixed, change this to:
 | 
| @@ -524,6 +537,12 @@ bool GrGLGpu::onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
 | 
|      // into it. We could use glDrawPixels on GLs that have it, but we don't today.
 | 
|      if (!dstSurface->asTexture()) {
 | 
|          ElevateDrawPreference(drawPreference, kRequireDraw_DrawPreference);
 | 
| +    } else {
 | 
| +        GrGLTexture* texture = static_cast<GrGLTexture*>(dstSurface->asTexture());
 | 
| +        if (GR_GL_TEXTURE_2D != texture->target()) {
 | 
| +             // We don't currently support writing pixels to non-TEXTURE_2D textures.
 | 
| +             return false;
 | 
| +        }
 | 
|      }
 | 
|  
 | 
|      if (GrPixelConfigIsSRGB(dstSurface->config()) != GrPixelConfigIsSRGB(srcConfig)) {
 | 
| @@ -585,6 +604,11 @@ bool GrGLGpu::onWritePixels(GrSurface* surface,
 | 
|          return false;
 | 
|      }
 | 
|  
 | 
| +    // Write pixels is only implemented for TEXTURE_2D textures
 | 
| +    if (GR_GL_TEXTURE_2D != glTex->target()) {
 | 
| +        return false;
 | 
| +    }
 | 
| +
 | 
|      this->setScratchTextureUnit();
 | 
|      GL_CALL(BindTexture(glTex->target(), glTex->textureID()));
 | 
|  
 | 
| @@ -2752,11 +2776,10 @@ void GrGLGpu::setScratchTextureUnit() {
 | 
|      fHWBoundTextureUniqueIDs[lastUnitIdx] = SK_InvalidUniqueID;
 | 
|  }
 | 
|  
 | 
| -namespace {
 | 
|  // Determines whether glBlitFramebuffer could be used between src and dst.
 | 
| -inline bool can_blit_framebuffer(const GrSurface* dst,
 | 
| -                                 const GrSurface* src,
 | 
| -                                 const GrGLGpu* gpu) {
 | 
| +static inline bool can_blit_framebuffer(const GrSurface* dst,
 | 
| +                                        const GrSurface* src,
 | 
| +                                        const GrGLGpu* gpu) {
 | 
|      if (gpu->glCaps().isConfigRenderable(dst->config(), dst->desc().fSampleCnt > 0) &&
 | 
|          gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0) &&
 | 
|          gpu->glCaps().usesMSAARenderBuffers()) {
 | 
| @@ -2766,15 +2789,23 @@ inline bool can_blit_framebuffer(const GrSurface* dst,
 | 
|              (src->desc().fSampleCnt > 0 || src->config() != dst->config())) {
 | 
|             return false;
 | 
|          }
 | 
| +        const GrGLTexture* dstTex = static_cast<const GrGLTexture*>(dst->asTexture());
 | 
| +        if (dstTex && dstTex->target() != GR_GL_TEXTURE_2D) {
 | 
| +            return false;
 | 
| +        }
 | 
| +        const GrGLTexture* srcTex = static_cast<const GrGLTexture*>(dst->asTexture());
 | 
| +        if (srcTex && srcTex->target() != GR_GL_TEXTURE_2D) {
 | 
| +            return false;
 | 
| +        }
 | 
|          return true;
 | 
|      } else {
 | 
|          return false;
 | 
|      }
 | 
|  }
 | 
|  
 | 
| -inline bool can_copy_texsubimage(const GrSurface* dst,
 | 
| -                                 const GrSurface* src,
 | 
| -                                 const GrGLGpu* gpu) {
 | 
| +static inline bool can_copy_texsubimage(const GrSurface* dst,
 | 
| +                                        const GrSurface* src,
 | 
| +                                        const GrGLGpu* gpu) {
 | 
|      // 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.
 | 
| @@ -2794,18 +2825,29 @@ inline bool can_copy_texsubimage(const GrSurface* dst,
 | 
|      if (srcRT && srcRT->renderFBOID() != srcRT->textureFBOID()) {
 | 
|          return false;
 | 
|      }
 | 
| +
 | 
| +    const GrGLTexture* dstTex = static_cast<const GrGLTexture*>(dst->asTexture());
 | 
| +    // CopyTex(Sub)Image writes to a texture and we have no way of dynamically wrapping a RT in a
 | 
| +    // texture.
 | 
| +    if (!dstTex) {
 | 
| +        return false;
 | 
| +    }
 | 
| +
 | 
| +    const GrGLTexture* srcTex = static_cast<const GrGLTexture*>(src->asTexture());
 | 
| +    
 | 
| +    // Check that we could wrap the source in an FBO, that the dst is TEXTURE_2D, that no mirroring
 | 
| +    // is required.
 | 
|      if (gpu->glCaps().isConfigRenderable(src->config(), src->desc().fSampleCnt > 0) &&
 | 
| -        dst->asTexture() &&
 | 
| -        dst->origin() == src->origin() &&
 | 
| -        !GrPixelConfigIsCompressed(src->config())) {
 | 
| +        !GrPixelConfigIsCompressed(src->config()) &&
 | 
| +        (!srcTex || srcTex->target() == GR_GL_TEXTURE_2D) &&
 | 
| +        dstTex->target() == GR_GL_TEXTURE_2D &&
 | 
| +        dst->origin() == src->origin()) {
 | 
|          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.
 | 
|  void GrGLGpu::bindSurfaceFBOForCopy(GrSurface* surface, GrGLenum fboTarget, GrGLIRect* viewport,
 | 
| @@ -2863,6 +2905,12 @@ bool GrGLGpu::initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc)
 | 
|          return true;
 | 
|      }
 | 
|  
 | 
| +    const GrGLTexture* srcTexture = static_cast<const GrGLTexture*>(src->asTexture());
 | 
| +    if (srcTexture && srcTexture->target() != GR_GL_TEXTURE_2D) {
 | 
| +        // Not supported for FBO blit or CopyTexSubImage
 | 
| +        return false;
 | 
| +    }
 | 
| +
 | 
|      // We look for opportunities to use CopyTexSubImage, or fbo blit. If neither are
 | 
|      // possible and we return false to fallback to creating a render target dst for render-to-
 | 
|      // texture. This code prefers CopyTexSubImage to fbo blit and avoids triggering temporary fbo
 | 
| @@ -2927,92 +2975,109 @@ bool GrGLGpu::onCopySurface(GrSurface* dst,
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void GrGLGpu::createCopyProgram() {
 | 
| +void GrGLGpu::createCopyPrograms() {
 | 
| +    for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) {
 | 
| +        fCopyPrograms[i].fProgram = 0;
 | 
| +    }
 | 
|      const char* version = this->glCaps().glslCaps()->versionDeclString();
 | 
| -
 | 
| -    GrGLSLShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier);
 | 
| -    GrGLSLShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType,
 | 
| +    static const GrSLType kSamplerTypes[2] = { kSampler2D_GrSLType, kSamplerExternal_GrSLType };
 | 
| +    SkASSERT(2 == SK_ARRAY_COUNT(fCopyPrograms));
 | 
| +    int programCount = this->glCaps().externalTextureSupport() ? 2 : 1;
 | 
| +    for (int i = 0; i < programCount; ++i) {
 | 
| +        GrGLSLShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kAttribute_TypeModifier);
 | 
| +        GrGLSLShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType,
 | 
| +                                     GrShaderVar::kUniform_TypeModifier);
 | 
| +        GrGLSLShaderVar uPosXform("u_posXform", kVec4f_GrSLType,
 | 
| +                                  GrShaderVar::kUniform_TypeModifier);
 | 
| +        GrGLSLShaderVar uTexture("u_texture", kSamplerTypes[i],
 | 
|                                   GrShaderVar::kUniform_TypeModifier);
 | 
| -    GrGLSLShaderVar uPosXform("u_posXform", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier);
 | 
| -    GrGLSLShaderVar uTexture("u_texture", kSampler2D_GrSLType, GrShaderVar::kUniform_TypeModifier);
 | 
| -    GrGLSLShaderVar vTexCoord("v_texCoord", kVec2f_GrSLType, GrShaderVar::kVaryingOut_TypeModifier);
 | 
| -    GrGLSLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier);
 | 
| +        GrGLSLShaderVar vTexCoord("v_texCoord", kVec2f_GrSLType,
 | 
| +                                  GrShaderVar::kVaryingOut_TypeModifier);
 | 
| +        GrGLSLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType,
 | 
| +                                   GrShaderVar::kOut_TypeModifier);
 | 
|      
 | 
| -    SkString vshaderTxt(version);
 | 
| -    aVertex.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
 | 
| -    vshaderTxt.append(";");
 | 
| -    uTexCoordXform.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
 | 
| -    vshaderTxt.append(";");
 | 
| -    uPosXform.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
 | 
| -    vshaderTxt.append(";");
 | 
| -    vTexCoord.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
 | 
| -    vshaderTxt.append(";");
 | 
| +        SkString vshaderTxt(version);
 | 
| +        aVertex.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
 | 
| +        vshaderTxt.append(";");
 | 
| +        uTexCoordXform.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
 | 
| +        vshaderTxt.append(";");
 | 
| +        uPosXform.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
 | 
| +        vshaderTxt.append(";");
 | 
| +        vTexCoord.appendDecl(this->glCaps().glslCaps(), &vshaderTxt);
 | 
| +        vshaderTxt.append(";");
 | 
|      
 | 
| -    vshaderTxt.append(
 | 
| -        "// Copy Program VS\n"
 | 
| -        "void main() {"
 | 
| -        "  v_texCoord = a_vertex.xy * u_texCoordXform.xy + u_texCoordXform.zw;"
 | 
| -        "  gl_Position.xy = a_vertex * u_posXform.xy + u_posXform.zw;"
 | 
| -        "  gl_Position.zw = vec2(0, 1);"
 | 
| -        "}"
 | 
| -    );
 | 
| -
 | 
| -    SkString fshaderTxt(version);
 | 
| -    GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision,
 | 
| -                                                 *this->glCaps().glslCaps(),
 | 
| -                                                 &fshaderTxt);
 | 
| -    vTexCoord.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier);
 | 
| -    vTexCoord.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
 | 
| -    fshaderTxt.append(";");
 | 
| -    uTexture.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
 | 
| -    fshaderTxt.append(";");
 | 
| -    const char* fsOutName;
 | 
| -    if (this->glCaps().glslCaps()->mustDeclareFragmentShaderOutput()) {
 | 
| -        oFragColor.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
 | 
| +        vshaderTxt.append(
 | 
| +            "// Copy Program VS\n"
 | 
| +            "void main() {"
 | 
| +            "  v_texCoord = a_vertex.xy * u_texCoordXform.xy + u_texCoordXform.zw;"
 | 
| +            "  gl_Position.xy = a_vertex * u_posXform.xy + u_posXform.zw;"
 | 
| +            "  gl_Position.zw = vec2(0, 1);"
 | 
| +            "}"
 | 
| +        );
 | 
| +
 | 
| +        SkString fshaderTxt(version);
 | 
| +        if (kSamplerTypes[i] == kSamplerExternal_GrSLType) {
 | 
| +            fshaderTxt.appendf("#extension %s : require\n",
 | 
| +                               this->glCaps().glslCaps()->externalTextureExtensionString());
 | 
| +        }
 | 
| +        GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision,
 | 
| +                                                     *this->glCaps().glslCaps(),
 | 
| +                                                     &fshaderTxt);
 | 
| +        vTexCoord.setTypeModifier(GrShaderVar::kVaryingIn_TypeModifier);
 | 
| +        vTexCoord.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
 | 
|          fshaderTxt.append(";");
 | 
| -        fsOutName = oFragColor.c_str();
 | 
| -    } else {
 | 
| -        fsOutName = "gl_FragColor";
 | 
| -    }
 | 
| -    fshaderTxt.appendf(
 | 
| -        "// Copy Program FS\n"
 | 
| -        "void main() {"
 | 
| -        "  %s = %s(u_texture, v_texCoord);"
 | 
| -        "}",
 | 
| -        fsOutName,
 | 
| -        GrGLSLTexture2DFunctionName(kVec2f_GrSLType, this->glslGeneration())
 | 
| -    );
 | 
| +        uTexture.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
 | 
| +        fshaderTxt.append(";");
 | 
| +        const char* fsOutName;
 | 
| +        if (this->glCaps().glslCaps()->mustDeclareFragmentShaderOutput()) {
 | 
| +            oFragColor.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
 | 
| +            fshaderTxt.append(";");
 | 
| +            fsOutName = oFragColor.c_str();
 | 
| +        } else {
 | 
| +            fsOutName = "gl_FragColor";
 | 
| +        }
 | 
| +        fshaderTxt.appendf(
 | 
| +            "// Copy Program FS\n"
 | 
| +            "void main() {"
 | 
| +            "  %s = %s(u_texture, v_texCoord);"
 | 
| +            "}",
 | 
| +            fsOutName,
 | 
| +            GrGLSLTexture2DFunctionName(kVec2f_GrSLType, this->glslGeneration())
 | 
| +        );
 | 
|      
 | 
| -    GL_CALL_RET(fCopyProgram.fProgram, CreateProgram());
 | 
| -    const char* str;
 | 
| -    GrGLint length;
 | 
| +        GL_CALL_RET(fCopyPrograms[i].fProgram, CreateProgram());
 | 
| +        const char* str;
 | 
| +        GrGLint length;
 | 
|  
 | 
| -    str = vshaderTxt.c_str();
 | 
| -    length = SkToInt(vshaderTxt.size());
 | 
| -    GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fCopyProgram.fProgram,
 | 
| -                                                  GR_GL_VERTEX_SHADER, &str, &length, 1, &fStats);
 | 
| +        str = vshaderTxt.c_str();
 | 
| +        length = SkToInt(vshaderTxt.size());
 | 
| +        GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[i].fProgram,
 | 
| +                                                      GR_GL_VERTEX_SHADER, &str, &length, 1,
 | 
| +                                                      &fStats);
 | 
|  
 | 
| -    str = fshaderTxt.c_str();
 | 
| -    length = SkToInt(fshaderTxt.size());
 | 
| -    GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fCopyProgram.fProgram,
 | 
| -                                                  GR_GL_FRAGMENT_SHADER, &str, &length, 1, &fStats);
 | 
| +        str = fshaderTxt.c_str();
 | 
| +        length = SkToInt(fshaderTxt.size());
 | 
| +        GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fCopyPrograms[i].fProgram,
 | 
| +                                                      GR_GL_FRAGMENT_SHADER, &str, &length, 1,
 | 
| +                                                      &fStats);
 | 
|  
 | 
| -    GL_CALL(LinkProgram(fCopyProgram.fProgram));
 | 
| +        GL_CALL(LinkProgram(fCopyPrograms[i].fProgram));
 | 
|  
 | 
| -    GL_CALL_RET(fCopyProgram.fTextureUniform, GetUniformLocation(fCopyProgram.fProgram,
 | 
| -                                                                 "u_texture"));
 | 
| -    GL_CALL_RET(fCopyProgram.fPosXformUniform, GetUniformLocation(fCopyProgram.fProgram,
 | 
| -                                                                  "u_posXform"));
 | 
| -    GL_CALL_RET(fCopyProgram.fTexCoordXformUniform, GetUniformLocation(fCopyProgram.fProgram,
 | 
| -                                                                       "u_texCoordXform"));
 | 
| +        GL_CALL_RET(fCopyPrograms[i].fTextureUniform,
 | 
| +                    GetUniformLocation(fCopyPrograms[i].fProgram, "u_texture"));
 | 
| +        GL_CALL_RET(fCopyPrograms[i].fPosXformUniform,
 | 
| +                    GetUniformLocation(fCopyPrograms[i].fProgram, "u_posXform"));
 | 
| +        GL_CALL_RET(fCopyPrograms[i].fTexCoordXformUniform,
 | 
| +                    GetUniformLocation(fCopyPrograms[i].fProgram, "u_texCoordXform"));
 | 
|  
 | 
| -    GL_CALL(BindAttribLocation(fCopyProgram.fProgram, 0, "a_vertex"));
 | 
| +        GL_CALL(BindAttribLocation(fCopyPrograms[i].fProgram, 0, "a_vertex"));
 | 
|  
 | 
| -    GL_CALL(DeleteShader(vshader));
 | 
| -    GL_CALL(DeleteShader(fshader));
 | 
| +        GL_CALL(DeleteShader(vshader));
 | 
| +        GL_CALL(DeleteShader(fshader));
 | 
| +    }
 | 
|  
 | 
| -    GL_CALL(GenBuffers(1, &fCopyProgram.fArrayBuffer));
 | 
| -    fHWGeometryState.setVertexBufferID(this, fCopyProgram.fArrayBuffer);
 | 
| +    GL_CALL(GenBuffers(1, &fCopyProgramArrayBuffer));
 | 
| +    fHWGeometryState.setVertexBufferID(this, fCopyProgramArrayBuffer);
 | 
|      static const GrGLfloat vdata[] = {
 | 
|          0, 0,
 | 
|          0, 1,
 | 
| @@ -3041,14 +3106,16 @@ void GrGLGpu::copySurfaceAsDraw(GrSurface* dst,
 | 
|      SkIRect dstRect = SkIRect::MakeXYWH(dstPoint.fX, dstPoint.fY, w, h);
 | 
|      this->flushRenderTarget(dstRT, &dstRect);
 | 
|  
 | 
| -    GL_CALL(UseProgram(fCopyProgram.fProgram));
 | 
| -    fHWProgramID = fCopyProgram.fProgram;
 | 
| +    int progIdx = TextureTargetToCopyProgramIdx(srcTex->target());
 | 
| +
 | 
| +    GL_CALL(UseProgram(fCopyPrograms[progIdx].fProgram));
 | 
| +    fHWProgramID = fCopyPrograms[progIdx].fProgram;
 | 
|  
 | 
|      fHWGeometryState.setVertexArrayID(this, 0);
 | 
|  
 | 
|      GrGLAttribArrayState* attribs =
 | 
| -        fHWGeometryState.bindArrayAndBufferToDraw(this, fCopyProgram.fArrayBuffer);
 | 
| -    attribs->set(this, 0, fCopyProgram.fArrayBuffer, 2, GR_GL_FLOAT, false,
 | 
| +        fHWGeometryState.bindArrayAndBufferToDraw(this, fCopyProgramArrayBuffer);
 | 
| +    attribs->set(this, 0, fCopyProgramArrayBuffer, 2, GR_GL_FLOAT, false,
 | 
|                      2 * sizeof(GrGLfloat), 0);
 | 
|      attribs->disableUnusedArrays(this, 0x1);
 | 
|  
 | 
| @@ -3076,9 +3143,10 @@ void GrGLGpu::copySurfaceAsDraw(GrSurface* dst,
 | 
|          sy1 = 1.f - sy1;
 | 
|      }
 | 
|  
 | 
| -    GL_CALL(Uniform4f(fCopyProgram.fPosXformUniform, dx1 - dx0, dy1 - dy0, dx0, dy0));
 | 
| -    GL_CALL(Uniform4f(fCopyProgram.fTexCoordXformUniform, sx1 - sx0, sy1 - sy0, sx0, sy0));
 | 
| -    GL_CALL(Uniform1i(fCopyProgram.fTextureUniform, 0));
 | 
| +    GL_CALL(Uniform4f(fCopyPrograms[progIdx].fPosXformUniform, dx1 - dx0, dy1 - dy0, dx0, dy0));
 | 
| +    GL_CALL(Uniform4f(fCopyPrograms[progIdx].fTexCoordXformUniform,
 | 
| +                      sx1 - sx0, sy1 - sy0, sx0, sy0));
 | 
| +    GL_CALL(Uniform1i(fCopyPrograms[progIdx].fTextureUniform, 0));
 | 
|  
 | 
|      GrXferProcessor::BlendInfo blendInfo;
 | 
|      blendInfo.reset();
 | 
| 
 |