Make max number of vertex attributes be checked dynamically
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1822343002

Review URL: https://codereview.chromium.org/1822343002
diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp
index 000f90c6..784e401 100644
--- a/src/gpu/GrCaps.cpp
+++ b/src/gpu/GrCaps.cpp
@@ -106,6 +106,7 @@
 
     fMapBufferFlags = kNone_MapFlags;
 
+    fMaxVertexAttributes = 0;
     fMaxRenderTargetSize = 1;
     fMaxTextureSize = 1;
     fMaxColorSampleCount = 0;
@@ -182,6 +183,7 @@
         r.appendf("Advanced Blend Equation Blacklist  : 0x%x\n", fAdvBlendEqBlacklist);
     }
 
+    r.appendf("Max Vertex Attributes              : %d\n", fMaxVertexAttributes);
     r.appendf("Max Texture Size                   : %d\n", fMaxTextureSize);
     r.appendf("Max Render Target Size             : %d\n", fMaxRenderTargetSize);
     r.appendf("Max Color Sample Count             : %d\n", fMaxColorSampleCount);
diff --git a/src/gpu/GrGeometryProcessor.h b/src/gpu/GrGeometryProcessor.h
index 50d0bd5..05afd53 100644
--- a/src/gpu/GrGeometryProcessor.h
+++ b/src/gpu/GrGeometryProcessor.h
@@ -44,10 +44,9 @@
      * GrGeometryProcessor.
      */
     const Attribute& addVertexAttrib(const Attribute& attribute) {
-        SkASSERT(fNumAttribs < kMaxVertexAttribs);
         fVertexStride += attribute.fOffset;
-        fAttribs[fNumAttribs] = attribute;
-        return fAttribs[fNumAttribs++];
+        fAttribs.push_back(attribute);
+        return fAttribs.back();
     }
 
     void setWillUseGeoShader() { fWillUseGeoShader = true; }
diff --git a/src/gpu/GrGpu.cpp b/src/gpu/GrGpu.cpp
index f3f00f1..ce15b41 100644
--- a/src/gpu/GrGpu.cpp
+++ b/src/gpu/GrGpu.cpp
@@ -492,12 +492,16 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-void GrGpu::draw(const GrPipeline& pipeline,
+bool GrGpu::draw(const GrPipeline& pipeline,
                  const GrPrimitiveProcessor& primProc,
                  const GrMesh* meshes,
                  int meshCount) {
+    if (primProc.numAttribs() > this->caps()->maxVertexAttributes()) {
+        return false;
+    }
     this->handleDirtyContext();
 
     this->onDraw(pipeline, primProc, meshes, meshCount);
+    return true;
 }
 
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 161ca5c..082f53f 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -380,8 +380,9 @@
 
     // We pass in an array of meshCount GrMesh to the draw. The backend should loop over each
     // GrMesh object and emit a draw for it. Each draw will use the same GrPipeline and
-    // GrPrimitiveProcessor.
-    void draw(const GrPipeline&,
+    // GrPrimitiveProcessor. This may fail if the draw would exceed any resource limits (e.g.
+    // number of vertex attributes is too large).
+    bool draw(const GrPipeline&,
               const GrPrimitiveProcessor&,
               const GrMesh*,
               int meshCount);
diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h
index e5c8517..e8bb449 100644
--- a/src/gpu/GrPrimitiveProcessor.h
+++ b/src/gpu/GrPrimitiveProcessor.h
@@ -151,12 +151,6 @@
     // we put these calls on the base class to prevent having to cast
     virtual bool willUseGeoShader() const = 0;
 
-    /*
-     * This is a safeguard to prevent GrPrimitiveProcessor's from going beyond platform specific
-     * attribute limits. This number can almost certainly be raised if required.
-     */
-    static const int kMaxVertexAttribs = 8;
-
     struct Attribute {
         Attribute()
             : fName(nullptr)
@@ -174,11 +168,8 @@
         GrSLPrecision fPrecision;
     };
 
-    int numAttribs() const { return fNumAttribs; }
-    const Attribute& getAttrib(int index) const {
-        SkASSERT(index < fNumAttribs);
-        return fAttribs[index];
-    }
+    int numAttribs() const { return fAttribs.count(); }
+    const Attribute& getAttrib(int index) const { return fAttribs[index]; }
 
     // Returns the vertex stride of the GP.  A common use case is to request geometry from a
     // drawtarget based off of the stride, and to populate this memory using an implicit array of
@@ -227,12 +218,10 @@
     virtual const char* getDestColorOverride() const { return nullptr; }
     
 protected:
-    GrPrimitiveProcessor()
-        : fNumAttribs(0)
-        , fVertexStride(0) {}
+    GrPrimitiveProcessor() : fVertexStride(0) {}
 
-    Attribute fAttribs[kMaxVertexAttribs];
-    int fNumAttribs;
+    enum { kPreallocAttribCnt = 8 };
+    SkSTArray<kPreallocAttribCnt, Attribute> fAttribs;
     size_t fVertexStride;
 
 private:
diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp
index af31480..50a74fe 100644
--- a/src/gpu/gl/GrGLCaps.cpp
+++ b/src/gpu/gl/GrGLCaps.cpp
@@ -26,7 +26,6 @@
     fMapBufferType = kNone_MapBufferType;
     fTransferBufferType = kNone_TransferBufferType;
     fMaxFragmentUniformVectors = 0;
-    fMaxVertexAttributes = 0;
     fUnpackRowLengthSupport = false;
     fUnpackFlipYSupport = false;
     fPackRowLengthSupport = false;
@@ -1064,7 +1063,6 @@
     r.appendf("Invalidate FB Type: %s\n", kInvalidateFBTypeStr[fInvalidateFBType]);
     r.appendf("Map Buffer Type: %s\n", kMapBufferTypeStr[fMapBufferType]);
     r.appendf("Max FS Uniform Vectors: %d\n", fMaxFragmentUniformVectors);
-    r.appendf("Max Vertex Attributes: %d\n", fMaxVertexAttributes);
     r.appendf("Unpack Row length support: %s\n", (fUnpackRowLengthSupport ? "YES": "NO"));
     r.appendf("Unpack Flip Y support: %s\n", (fUnpackFlipYSupport ? "YES": "NO"));
     r.appendf("Pack Row length support: %s\n", (fPackRowLengthSupport ? "YES": "NO"));
diff --git a/src/gpu/gl/GrGLCaps.h b/src/gpu/gl/GrGLCaps.h
index ed673e7..bb3e231 100644
--- a/src/gpu/gl/GrGLCaps.h
+++ b/src/gpu/gl/GrGLCaps.h
@@ -248,9 +248,6 @@
     /// The maximum number of fragment uniform vectors (GLES has min. 16).
     int maxFragmentUniformVectors() const { return fMaxFragmentUniformVectors; }
 
-    /// maximum number of attribute values per vertex
-    int maxVertexAttributes() const { return fMaxVertexAttributes; }
-
     /**
      * Depending on the ES extensions present the BGRA external format may
      * correspond to either a BGRA or RGBA internalFormat. On desktop GL it is
@@ -381,7 +378,6 @@
     SkTArray<StencilFormat, true> fStencilFormats;
 
     int fMaxFragmentUniformVectors;
-    int fMaxVertexAttributes;
 
     MSFBOType           fMSFBOType;
     InvalidateFBType    fInvalidateFBType;
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 62baf79..3a29361 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -214,8 +214,6 @@
 
     fProgramCache = new ProgramCache(this);
 
-    SkASSERT(this->glCaps().maxVertexAttributes() >= GrGeometryProcessor::kMaxVertexAttribs);
-
     fHWProgramID = 0;
     fTempSrcFBOID = 0;
     fTempDstFBOID = 0;
diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp
index 9dbc40c..7cfddba 100644
--- a/src/gpu/vk/GrVkCaps.cpp
+++ b/src/gpu/vk/GrVkCaps.cpp
@@ -102,6 +102,7 @@
 void GrVkCaps::initGrCaps(const VkPhysicalDeviceProperties& properties,
                           const VkPhysicalDeviceFeatures& features,
                           const VkPhysicalDeviceMemoryProperties& memoryProperites) {
+    fMaxVertexAttributes = properties.limits.maxVertexInputAttributes;
     // We could actually query and get a max size for each config, however maxImageDimension2D will
     // give the minimum max size across all configs. So for simplicity we will use that for now.
     fMaxRenderTargetSize = properties.limits.maxImageDimension2D;