| Index: src/gpu/gl/GrGpuGL.cpp | 
| diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp | 
| index 0c47060e4f5033454caf5b1748762a57a4c6eb47..2f218a0c86e543f42f5393cc629709fb7fa3aa24 100644 | 
| --- a/src/gpu/gl/GrGpuGL.cpp | 
| +++ b/src/gpu/gl/GrGpuGL.cpp | 
| @@ -20,9 +20,6 @@ static const GrGLint  GR_INVAL_GLINT = ~0; | 
| #define GL_CALL(X) GR_GL_CALL(this->glInterface(), X) | 
| #define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->glInterface(), RET, X) | 
|  | 
| -// we use a spare texture unit to avoid | 
| -// mucking with the state of any of the stages. | 
| -static const int SPARE_TEX_UNIT = GrDrawState::kNumStages; | 
|  | 
| #define SKIP_CACHE_CHECK    true | 
|  | 
| @@ -118,35 +115,6 @@ bool GrGpuGL::BlendCoeffReferencesConstant(GrBlendCoeff coeff) { | 
|  | 
| static bool gPrintStartupSpew; | 
|  | 
| -static bool fbo_test(const GrGLInterface* gl, int w, int h) { | 
| - | 
| -    GR_GL_CALL(gl, ActiveTexture(GR_GL_TEXTURE0 + SPARE_TEX_UNIT)); | 
| - | 
| -    GrGLuint testFBO; | 
| -    GR_GL_CALL(gl, GenFramebuffers(1, &testFBO)); | 
| -    GR_GL_CALL(gl, BindFramebuffer(GR_GL_FRAMEBUFFER, testFBO)); | 
| -    GrGLuint testRTTex; | 
| -    GR_GL_CALL(gl, GenTextures(1, &testRTTex)); | 
| -    GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, testRTTex)); | 
| -    // some implementations require texture to be mip-map complete before | 
| -    // FBO with level 0 bound as color attachment will be framebuffer complete. | 
| -    GR_GL_CALL(gl, TexParameteri(GR_GL_TEXTURE_2D, | 
| -                                 GR_GL_TEXTURE_MIN_FILTER, | 
| -                                 GR_GL_NEAREST)); | 
| -    GR_GL_CALL(gl, TexImage2D(GR_GL_TEXTURE_2D, 0, GR_GL_RGBA, w, h, | 
| -                              0, GR_GL_RGBA, GR_GL_UNSIGNED_BYTE, NULL)); | 
| -    GR_GL_CALL(gl, BindTexture(GR_GL_TEXTURE_2D, 0)); | 
| -    GR_GL_CALL(gl, FramebufferTexture2D(GR_GL_FRAMEBUFFER, | 
| -                                        GR_GL_COLOR_ATTACHMENT0, | 
| -                                        GR_GL_TEXTURE_2D, testRTTex, 0)); | 
| -    GrGLenum status; | 
| -    GR_GL_CALL_RET(gl, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER)); | 
| -    GR_GL_CALL(gl, DeleteFramebuffers(1, &testFBO)); | 
| -    GR_GL_CALL(gl, DeleteTextures(1, &testRTTex)); | 
| - | 
| -    return status == GR_GL_FRAMEBUFFER_COMPLETE; | 
| -} | 
| - | 
| GrGpuGL::GrGpuGL(const GrGLContext& ctx, GrContext* context) | 
| : GrGpu(context) | 
| , fGLContext(ctx) { | 
| @@ -155,6 +123,8 @@ GrGpuGL::GrGpuGL(const GrGLContext& ctx, GrContext* context) | 
|  | 
| fCaps.reset(SkRef(ctx.info().caps())); | 
|  | 
| +    fHWBoundTextures.reset(ctx.info().caps()->maxFragmentTextureUnits()); | 
| + | 
| fillInConfigRenderableTable(); | 
|  | 
|  | 
| @@ -183,9 +153,6 @@ GrGpuGL::GrGpuGL(const GrGLContext& ctx, GrContext* context) | 
| GrAssert(this->glCaps().maxVertexAttributes() >= GrDrawState::kMaxVertexAttribCnt); | 
|  | 
| fLastSuccessfulStencilFmtIdx = 0; | 
| -    if (false) { // avoid bit rot, suppress warning | 
| -        fbo_test(this->glInterface(), 0, 0); | 
| -    } | 
| } | 
|  | 
| GrGpuGL::~GrGpuGL() { | 
| @@ -361,7 +328,7 @@ void GrGpuGL::onResetContext() { | 
|  | 
| fHWBlendState.invalidate(); | 
|  | 
| -    for (int s = 0; s < GrDrawState::kNumStages; ++s) { | 
| +    for (int s = 0; s < fHWBoundTextures.count(); ++s) { | 
| fHWBoundTextures[s] = NULL; | 
| } | 
|  | 
| @@ -473,7 +440,6 @@ GrTexture* GrGpuGL::onWrapBackendTexture(const GrBackendTextureDesc& desc) { | 
| return NULL; | 
| } | 
|  | 
| -    this->setSpareTextureUnit(); | 
| return texture; | 
| } | 
|  | 
| @@ -527,7 +493,7 @@ bool GrGpuGL::onWriteTexturePixels(GrTexture* texture, | 
| } | 
| GrGLTexture* glTex = static_cast<GrGLTexture*>(texture); | 
|  | 
| -    this->setSpareTextureUnit(); | 
| +    this->setScratchTextureUnit(); | 
| GL_CALL(BindTexture(GR_GL_TEXTURE_2D, glTex->textureID())); | 
| GrGLTexture::Desc desc; | 
| desc.fFlags = glTex->desc().fFlags; | 
| @@ -952,7 +918,7 @@ GrTexture* GrGpuGL::onCreateTexture(const GrTextureDesc& desc, | 
| return return_null_texture(); | 
| } | 
|  | 
| -    this->setSpareTextureUnit(); | 
| +    this->setScratchTextureUnit(); | 
| GL_CALL(BindTexture(GR_GL_TEXTURE_2D, glTexDesc.fTextureID)); | 
|  | 
| // Some drivers like to know filter/wrap before seeing glTexImage2D. Some | 
| @@ -2102,7 +2068,7 @@ void GrGpuGL::notifyRenderTargetDelete(GrRenderTarget* renderTarget) { | 
| } | 
|  | 
| void GrGpuGL::notifyTextureDelete(GrGLTexture* texture) { | 
| -    for (int s = 0; s < GrDrawState::kNumStages; ++s) { | 
| +    for (int s = 0; s < fHWBoundTextures.count(); ++s) { | 
| if (fHWBoundTextures[s] == texture) { | 
| // deleting bound texture does implied bind to 0 | 
| fHWBoundTextures[s] = NULL; | 
| @@ -2222,18 +2188,23 @@ bool GrGpuGL::configToGLFormats(GrPixelConfig config, | 
| } | 
|  | 
| void GrGpuGL::setTextureUnit(int unit) { | 
| -    GrAssert(unit >= 0 && unit < GrDrawState::kNumStages); | 
| -    if (fHWActiveTextureUnitIdx != unit) { | 
| +    GrAssert(unit >= 0 && unit < fHWBoundTextures.count()); | 
| +    if (unit != fHWActiveTextureUnitIdx) { | 
| GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + unit)); | 
| fHWActiveTextureUnitIdx = unit; | 
| } | 
| } | 
|  | 
| -void GrGpuGL::setSpareTextureUnit() { | 
| -    if (fHWActiveTextureUnitIdx != (GR_GL_TEXTURE0 + SPARE_TEX_UNIT)) { | 
| -        GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + SPARE_TEX_UNIT)); | 
| -        fHWActiveTextureUnitIdx = SPARE_TEX_UNIT; | 
| +void GrGpuGL::setScratchTextureUnit() { | 
| +    // Bind the last texture unit since it is the least likely to be used by GrGLProgram. | 
| +    int lastUnitIdx = fHWBoundTextures.count() - 1; | 
| +    if (lastUnitIdx != fHWActiveTextureUnitIdx) { | 
| +        GL_CALL(ActiveTexture(GR_GL_TEXTURE0 + lastUnitIdx)); | 
| +        fHWActiveTextureUnitIdx = lastUnitIdx; | 
| } | 
| +    // clear out the this field so that if a program does use this unit it will rebind the correct | 
| +    // texture. | 
| +    fHWBoundTextures[lastUnitIdx] = NULL; | 
| } | 
|  | 
| namespace { | 
| @@ -2370,7 +2341,7 @@ bool GrGpuGL::onCopySurface(GrSurface* dst, | 
| srcRect.height(), | 
| src->origin()); | 
|  | 
| -        this->setSpareTextureUnit(); | 
| +        this->setScratchTextureUnit(); | 
| GL_CALL(BindTexture(GR_GL_TEXTURE_2D, dstTex->textureID())); | 
| GrGLint dstY; | 
| if (kBottomLeft_GrSurfaceOrigin == dst->origin()) { | 
|  |