Cache CPU memory buffers used for client side arrays.

Use same cache for CPU-side copy of data when using GPU buffers.

Change-Id: I09f2837211a30aabc50e9897c090f5fbc6d90492
Reviewed-on: https://skia-review.googlesource.com/c/189484
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
diff --git a/src/gpu/GrBufferAllocPool.h b/src/gpu/GrBufferAllocPool.h
index d0fda19..b499e80 100644
--- a/src/gpu/GrBufferAllocPool.h
+++ b/src/gpu/GrBufferAllocPool.h
@@ -8,14 +8,14 @@
 #ifndef GrBufferAllocPool_DEFINED
 #define GrBufferAllocPool_DEFINED
 
-#include "GrGpuBuffer.h"
+#include "GrCpuBuffer.h"
+#include "GrNonAtomicRef.h"
 #include "GrTypesPriv.h"
 #include "SkNoncopyable.h"
 #include "SkTArray.h"
 #include "SkTDArray.h"
 #include "SkTypes.h"
 
-
 class GrGpu;
 
 /**
@@ -35,6 +35,28 @@
     static constexpr size_t kDefaultBufferSize = 1 << 15;
 
     /**
+     * A cache object that can be shared by multiple GrBufferAllocPool instances. It caches
+     * cpu buffer allocations to avoid reallocating them.
+     */
+    class CpuBufferCache : public GrNonAtomicRef<CpuBufferCache> {
+    public:
+        static sk_sp<CpuBufferCache> Make(int maxBuffersToCache);
+
+        sk_sp<GrCpuBuffer> makeBuffer(size_t size, bool mustBeInitialized);
+        void releaseAll();
+
+    private:
+        CpuBufferCache(int maxBuffersToCache);
+
+        struct Buffer {
+            sk_sp<GrCpuBuffer> fBuffer;
+            bool fCleared = false;
+        };
+        std::unique_ptr<Buffer[]> fBuffers;
+        int fMaxBuffersToCache = 0;
+    };
+
+    /**
      * Ensures all buffers are unmapped and have all data written to them.
      * Call before drawing using buffers from the pool.
      */
@@ -56,11 +78,11 @@
      *
      * @param gpu                   The GrGpu used to create the buffers.
      * @param bufferType            The type of buffers to create.
-     * @param initialBuffer         If non-null this should be a kDefaultBufferSize byte allocation.
-     *                              This parameter can be used to avoid malloc/free when all
-     *                              usages can be satisfied with default-sized buffers.
+     * @param cpuBufferCache        If non-null a cache for client side array buffers
+     *                              or staging buffers used before data is uploaded to
+     *                              GPU buffer objects.
      */
-    GrBufferAllocPool(GrGpu* gpu, GrGpuBufferType bufferType, void* initialBuffer);
+    GrBufferAllocPool(GrGpu* gpu, GrGpuBufferType bufferType, sk_sp<CpuBufferCache> cpuBufferCache);
 
     virtual ~GrBufferAllocPool();
 
@@ -129,18 +151,17 @@
     void destroyBlock();
     void deleteBlocks();
     void flushCpuData(const BufferBlock& block, size_t flushSize);
-    void* resetCpuData(size_t newSize);
+    void resetCpuData(size_t newSize);
 #ifdef SK_DEBUG
     void validate(bool unusedBlockAllowed = false) const;
 #endif
     size_t fBytesInUse = 0;
 
     SkTArray<BufferBlock> fBlocks;
+    sk_sp<CpuBufferCache> fCpuBufferCache;
+    sk_sp<GrCpuBuffer> fCpuStagingBuffer;
     GrGpu* fGpu;
     GrGpuBufferType fBufferType;
-    void* fInitialCpuData = nullptr;
-    void* fCpuData = nullptr;
-    size_t fCpuDataSize = 0;
     void* fBufferPtr = nullptr;
 };
 
@@ -153,11 +174,11 @@
      * Constructor
      *
      * @param gpu                   The GrGpu used to create the vertex buffers.
-     * @param initialBuffer         If non-null this should be a kDefaultBufferSize byte allocation.
-     *                              This parameter can be used to avoid malloc/free when all
-     *                              usages can be satisfied with default-sized buffers.
+     * @param cpuBufferCache        If non-null a cache for client side array buffers
+     *                              or staging buffers used before data is uploaded to
+     *                              GPU buffer objects.
      */
-    GrVertexBufferAllocPool(GrGpu* gpu, void* initialBuffer);
+    GrVertexBufferAllocPool(GrGpu* gpu, sk_sp<CpuBufferCache> cpuBufferCache);
 
     /**
      * Returns a block of memory to hold vertices. A buffer designated to hold
@@ -232,11 +253,11 @@
      * Constructor
      *
      * @param gpu                   The GrGpu used to create the index buffers.
-     * @param initialBuffer         If non-null this should be a kDefaultBufferSize byte allocation.
-     *                              This parameter can be used to avoid malloc/free when all
-     *                              usages can be satisfied with default-sized buffers.
+     * @param cpuBufferCache        If non-null a cache for client side array buffers
+     *                              or staging buffers used before data is uploaded to
+     *                              GPU buffer objects.
      */
-    GrIndexBufferAllocPool(GrGpu* gpu, void* initialBuffer);
+    GrIndexBufferAllocPool(GrGpu* gpu, sk_sp<CpuBufferCache> cpuBufferCache);
 
     /**
      * Returns a block of memory to hold indices. A buffer designated to hold