Allow TextureSamplers to have null GrTexture pointer

Bug: 715488

Change-Id: I69775cbb50d334d81872e236e59368fe65e698ff
Reviewed-on: https://skia-review.googlesource.com/14605
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrFragmentProcessor.cpp b/src/gpu/GrFragmentProcessor.cpp
index 462766a..b0a36fc 100644
--- a/src/gpu/GrFragmentProcessor.cpp
+++ b/src/gpu/GrFragmentProcessor.cpp
@@ -62,6 +62,10 @@
 }
 
 int GrFragmentProcessor::registerChildProcessor(sk_sp<GrFragmentProcessor> child) {
+    if (child->isBad()) {
+        this->markAsBad();
+    }
+
     this->combineRequiredFeatures(*child);
 
     if (child->usesLocalCoords()) {
diff --git a/src/gpu/GrGpuCommandBuffer.cpp b/src/gpu/GrGpuCommandBuffer.cpp
index 4eb9843..b51d3ea 100644
--- a/src/gpu/GrGpuCommandBuffer.cpp
+++ b/src/gpu/GrGpuCommandBuffer.cpp
@@ -39,6 +39,10 @@
                               const GrMesh* mesh,
                               int meshCount,
                               const SkRect& bounds) {
+    if (pipeline.isBad() || primProc.isBad()) {
+        return false;
+    }
+
     SkASSERT(pipeline.isInitialized());
     if (primProc.numAttribs() > this->gpu()->caps()->maxVertexAttributes()) {
         this->gpu()->stats()->incNumFailedDraws();
diff --git a/src/gpu/GrGpuResourceRef.cpp b/src/gpu/GrGpuResourceRef.cpp
index 405679d..532e065 100644
--- a/src/gpu/GrGpuResourceRef.cpp
+++ b/src/gpu/GrGpuResourceRef.cpp
@@ -66,10 +66,13 @@
 }
 
 void GrGpuResourceRef::markPendingIO() const {
+    if (!fResource) {
+        return;
+    }
+
     // This should only be called when the owning GrProgramElement gets its first
     // pendingExecution ref.
     SkASSERT(!fPendingIO);
-    SkASSERT(fResource);
     fPendingIO = true;
     switch (fIOType) {
         case kRead_GrIOType:
@@ -86,6 +89,10 @@
 }
 
 void GrGpuResourceRef::pendingIOComplete() const {
+    if (!fResource) {
+        return;
+    }
+
     // This should only be called when the owner's pending executions have ocurred but it is still
     // reffed.
     SkASSERT(fOwnRef);
@@ -107,11 +114,14 @@
 }
 
 void GrGpuResourceRef::removeRef() const {
+    if (!fResource) {
+        return;
+    }
+
     // This should only be called once, when the owners last ref goes away and
     // there is a pending execution.
     SkASSERT(fOwnRef);
     SkASSERT(fPendingIO);
-    SkASSERT(fResource);
     fResource->unref();
     fOwnRef = false;
 }
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index 1471b57..78fb759 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -64,15 +64,24 @@
     for (int i = 0; i < args.fProcessors->numColorFragmentProcessors(); ++i, ++currFPIdx) {
         const GrFragmentProcessor* fp = args.fProcessors->colorFragmentProcessor(i);
         fFragmentProcessors[currFPIdx].reset(fp);
+        if (fp->isBad()) {
+            this->markAsBad();
+        }
     }
 
     for (int i = 0; i < args.fProcessors->numCoverageFragmentProcessors(); ++i, ++currFPIdx) {
         const GrFragmentProcessor* fp = args.fProcessors->coverageFragmentProcessor(i);
         fFragmentProcessors[currFPIdx].reset(fp);
+        if (fp->isBad()) {
+            this->markAsBad();
+        }
     }
     if (args.fAppliedClip) {
         if (const GrFragmentProcessor* fp = args.fAppliedClip->clipCoverageFragmentProcessor()) {
             fFragmentProcessors[currFPIdx].reset(fp);
+            if (fp->isBad()) {
+                this->markAsBad();
+            }
         }
     }
 }
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index 01d375e..3bac5f7 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -213,6 +213,7 @@
     bool isStencilEnabled() const {
         return SkToBool(fFlags & kStencilEnabled_Flag);
     }
+    bool isBad() const { return SkToBool(fFlags & kIsBad_Flag); }
 
     GrXferBarrierType xferBarrierType(const GrCaps& caps) const {
         if (fDstTexture.get() && fDstTexture.get() == fRenderTarget.get()->asTexture()) {
@@ -229,11 +230,14 @@
     GrDrawFace getDrawFace() const { return static_cast<GrDrawFace>(fDrawFace); }
 
 private:
+    void markAsBad() { fFlags |= kIsBad_Flag; }
+
     /** This is a continuation of the public "Flags" enum. */
     enum PrivateFlags {
         kUsesDistanceVectorField_Flag = 0x10,
         kHasStencilClip_Flag = 0x20,
         kStencilEnabled_Flag = 0x40,
+        kIsBad_Flag = 0x80,
     };
 
     using RenderTarget = GrPendingIOResource<GrRenderTarget, kWrite_GrIOType>;
diff --git a/src/gpu/GrProcessor.cpp b/src/gpu/GrProcessor.cpp
index 4856c42..c5ccc3f 100644
--- a/src/gpu/GrProcessor.cpp
+++ b/src/gpu/GrProcessor.cpp
@@ -129,6 +129,10 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void GrResourceIOProcessor::addTextureSampler(const TextureSampler* access) {
+    if (access->isBad()) {
+        this->markAsBad();
+    }
+
     fTextureSamplers.push_back(access);
 }
 
@@ -234,13 +238,17 @@
                                                   sk_sp<GrTextureProxy> proxy,
                                                   const GrSamplerParams& params,
                                                   GrShaderFlags visibility) {
+    fParams = params;
+
     // For now, end the deferral at this time. Once all the TextureSamplers are swapped over
     // to taking a GrSurfaceProxy just use the IORefs on the proxy
     GrTexture* texture = proxy->instantiate(resourceProvider);
-    SkASSERT(texture);
-    fTexture.set(SkRef(texture), kRead_GrIOType);
-    fParams = params;
-    fParams.setFilterMode(SkTMin(params.filterMode(), texture->texturePriv().highestFilterMode()));
+    if (texture) {
+        fTexture.set(SkRef(texture), kRead_GrIOType);
+        fParams.setFilterMode(SkTMin(params.filterMode(),
+                                     texture->texturePriv().highestFilterMode()));
+    }
+
     fVisibility = visibility;
 }
 
@@ -252,9 +260,11 @@
     // For now, end the deferral at this time. Once all the TextureSamplers are swapped over
     // to taking a GrSurfaceProxy just use the IORefs on the proxy
     GrTexture* texture = proxy->instantiate(resourceProvider);
-    SkASSERT(texture);
-    fTexture.set(SkRef(texture), kRead_GrIOType);
-    filterMode = SkTMin(filterMode, texture->texturePriv().highestFilterMode());
+    if (texture) {
+        fTexture.set(SkRef(texture), kRead_GrIOType);
+        filterMode = SkTMin(filterMode, texture->texturePriv().highestFilterMode());
+    }
+
     fParams.reset(tileXAndY, filterMode);
     fVisibility = visibility;
 }
diff --git a/src/gpu/GrProcessor.h b/src/gpu/GrProcessor.h
index 1816db2..7011267 100644
--- a/src/gpu/GrProcessor.h
+++ b/src/gpu/GrProcessor.h
@@ -176,8 +176,10 @@
         return *fImageStorageAccesses[index];
     }
 
+    bool isBad() const { return fIsBad; }
+
 protected:
-    GrResourceIOProcessor() = default;
+    GrResourceIOProcessor() : fIsBad(false) {}
 
     /**
      * Subclasses call these from their constructor to register sampler/image sources. The processor
@@ -196,10 +198,13 @@
     void removeRefs() const;
     void pendingIOComplete() const;
 
+    void markAsBad() { fIsBad = true; }
+
 private:
     SkSTArray<4, const TextureSampler*, true> fTextureSamplers;
     SkSTArray<1, const BufferAccess*, true> fBufferAccesses;
     SkSTArray<1, const ImageStorageAccess*, true> fImageStorageAccesses;
+    bool fIsBad;
 
     typedef GrProcessor INHERITED;
 };
@@ -252,6 +257,8 @@
      */
     const GrGpuResourceRef* programTexture() const { return &fTexture; }
 
+    bool isBad() const { return !fTexture.get(); }
+
 private:
 
     typedef GrTGpuResourceRef<GrTexture> ProgramTexture;
diff --git a/src/gpu/effects/GrBitmapTextGeoProc.cpp b/src/gpu/effects/GrBitmapTextGeoProc.cpp
index 527d5ce..470af46 100644
--- a/src/gpu/effects/GrBitmapTextGeoProc.cpp
+++ b/src/gpu/effects/GrBitmapTextGeoProc.cpp
@@ -105,9 +105,10 @@
         // Currently we hardcode numbers to convert atlas coordinates to normalized floating point
         SkASSERT(gp.numTextureSamplers() == 1);
         GrTexture* atlas = gp.textureSampler(0).texture();
-        SkASSERT(atlas);
-        b->add32(atlas->width());
-        b->add32(atlas->height());
+        if (atlas) {
+            b->add32(atlas->width());
+            b->add32(atlas->height());
+        }
     }
 
 private:
diff --git a/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
index 82f8880..5ad2ef2 100644
--- a/src/gpu/effects/GrDistanceFieldGeoProc.cpp
+++ b/src/gpu/effects/GrDistanceFieldGeoProc.cpp
@@ -203,9 +203,10 @@
         // Currently we hardcode numbers to convert atlas coordinates to normalized floating point
         SkASSERT(gp.numTextureSamplers() == 1);
         GrTexture* atlas = gp.textureSampler(0).texture();
-        SkASSERT(atlas);
-        b->add32(atlas->width());
-        b->add32(atlas->height());
+        if (atlas) {
+            b->add32(atlas->width());
+            b->add32(atlas->height());
+        }
     }
 
 private:
@@ -759,9 +760,10 @@
         // Currently we hardcode numbers to convert atlas coordinates to normalized floating point
         SkASSERT(gp.numTextureSamplers() == 1);
         GrTexture* atlas = gp.textureSampler(0).texture();
-        SkASSERT(atlas);
-        b->add32(atlas->width());
-        b->add32(atlas->height());
+        if (atlas) {
+            b->add32(atlas->width());
+            b->add32(atlas->height());
+        }
     }
 
 private:
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index 0351819..8e6901d 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -33,6 +33,8 @@
                                                const GrPrimitiveProcessor& primProc,
                                                GrProgramDesc* desc,
                                                GrGLGpu* gpu) {
+    SkASSERT(!pipeline.isBad() && !primProc.isBad());
+
     ATRACE_ANDROID_FRAMEWORK("Shader Compile");
     GrAutoLocaleSetter als("C");