Make ScratchBuffer its own type.

This helper tool in Renderer11 can be useful in other back-ends,
or even in the front end.

BUG=angleproject:1635

Change-Id: I18ec19a891a9bdfa7b80dea1b8e308abf206906b
Reviewed-on: https://chromium-review.googlesource.com/450919
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/common/MemoryBuffer.cpp b/src/common/MemoryBuffer.cpp
index e7a3fb4..e720edc 100644
--- a/src/common/MemoryBuffer.cpp
+++ b/src/common/MemoryBuffer.cpp
@@ -11,19 +11,18 @@
 
 #include "common/debug.h"
 
-namespace rx
+namespace angle
 {
 
-MemoryBuffer::MemoryBuffer()
-    : mSize(0),
-      mData(NULL)
+// MemoryBuffer implementation.
+MemoryBuffer::MemoryBuffer() : mSize(0), mData(nullptr)
 {
 }
 
 MemoryBuffer::~MemoryBuffer()
 {
     free(mData);
-    mData = NULL;
+    mData = nullptr;
 }
 
 bool MemoryBuffer::resize(size_t size)
@@ -31,7 +30,7 @@
     if (size == 0)
     {
         free(mData);
-        mData = NULL;
+        mData = nullptr;
         mSize = 0;
         return true;
     }
@@ -43,7 +42,7 @@
 
     // Only reallocate if the size has changed.
     uint8_t *newMemory = reinterpret_cast<uint8_t*>(malloc(sizeof(uint8_t) * size));
-    if (newMemory == NULL)
+    if (newMemory == nullptr)
     {
         return false;
     }
@@ -77,4 +76,58 @@
     return mData;
 }
 
+// ScratchBuffer implementation.
+
+ScratchBuffer::ScratchBuffer(uint32_t lifetime) : mLifetime(lifetime), mResetCounter(lifetime)
+{
 }
+
+ScratchBuffer::~ScratchBuffer()
+{
+}
+
+bool ScratchBuffer::get(size_t requestedSize, MemoryBuffer **memoryBufferOut)
+{
+    if (mScratchMemory.size() == requestedSize)
+    {
+        mResetCounter    = mLifetime;
+        *memoryBufferOut = &mScratchMemory;
+        return true;
+    }
+
+    if (mScratchMemory.size() > requestedSize)
+    {
+        tick();
+    }
+
+    if (mResetCounter == 0 || mScratchMemory.size() < requestedSize)
+    {
+        mScratchMemory.resize(0);
+        if (!mScratchMemory.resize(requestedSize))
+        {
+            return false;
+        }
+        mResetCounter = mLifetime;
+    }
+
+    ASSERT(mScratchMemory.size() >= requestedSize);
+
+    *memoryBufferOut = &mScratchMemory;
+    return true;
+}
+
+void ScratchBuffer::tick()
+{
+    if (mResetCounter > 0)
+    {
+        --mResetCounter;
+    }
+}
+
+void ScratchBuffer::clear()
+{
+    mResetCounter = mLifetime;
+    mScratchMemory.resize(0);
+}
+
+}  // namespace angle
diff --git a/src/common/MemoryBuffer.h b/src/common/MemoryBuffer.h
index ec621cb..b30f737 100644
--- a/src/common/MemoryBuffer.h
+++ b/src/common/MemoryBuffer.h
@@ -12,10 +12,10 @@
 #include <cstddef>
 #include <stdint.h>
 
-namespace rx
+namespace angle
 {
 
-class MemoryBuffer : angle::NonCopyable
+class MemoryBuffer final : NonCopyable
 {
   public:
     MemoryBuffer();
@@ -33,6 +33,29 @@
     uint8_t *mData;
 };
 
-}
+class ScratchBuffer final : NonCopyable
+{
+  public:
+    // If we request a scratch buffer requesting a smaller size this many times, release and
+    // recreate the scratch buffer. This ensures we don't have a degenerate case where we are stuck
+    // hogging memory.
+    ScratchBuffer(uint32_t lifetime);
+    ~ScratchBuffer();
+
+    // Returns true with a memory buffer of the requested size, or false on failure.
+    bool get(size_t requestedSize, MemoryBuffer **memoryBufferOut);
+
+    // Ticks the release counter for the scratch buffer. Also done implicitly in get().
+    void tick();
+
+    void clear();
+
+  private:
+    const uint32_t mLifetime;
+    uint32_t mResetCounter;
+    MemoryBuffer mScratchMemory;
+};
+
+}  // namespace angle
 
 #endif // COMMON_MEMORYBUFFER_H_
diff --git a/src/libANGLE/Uniform.h b/src/libANGLE/Uniform.h
index 42edb89..b21cd23 100644
--- a/src/libANGLE/Uniform.h
+++ b/src/libANGLE/Uniform.h
@@ -45,7 +45,7 @@
     sh::BlockMemberInfo blockInfo;
 
   private:
-    mutable rx::MemoryBuffer mLazyData;
+    mutable angle::MemoryBuffer mLazyData;
 };
 
 // Helper struct representing a single shader uniform block
diff --git a/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp
index eab6c35..c2f9d3e 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Buffer11.cpp
@@ -205,8 +205,8 @@
 
   private:
     ID3D11Buffer *mNativeStorage;       // contains expanded data for use by D3D
-    MemoryBuffer mMemoryBuffer;         // original data (not expanded)
-    MemoryBuffer mIndicesMemoryBuffer;  // indices data
+    angle::MemoryBuffer mMemoryBuffer;  // original data (not expanded)
+    angle::MemoryBuffer mIndicesMemoryBuffer;  // indices data
 };
 
 // Pack storage represents internal storage for pack buffers. We implement pack buffers
@@ -237,7 +237,7 @@
     gl::Error flushQueuedPackCommand();
 
     TextureHelper11 mStagingTexture;
-    MemoryBuffer mMemoryBuffer;
+    angle::MemoryBuffer mMemoryBuffer;
     std::unique_ptr<PackPixelsParams> mQueuedPackCommand;
     PackPixelsParams mPackParams;
     bool mDataModified;
@@ -265,10 +265,10 @@
                   uint8_t **mapPointerOut) override;
     void unmap() override;
 
-    MemoryBuffer *getSystemCopy() { return &mSystemCopy; }
+    angle::MemoryBuffer *getSystemCopy() { return &mSystemCopy; }
 
   protected:
-    MemoryBuffer mSystemCopy;
+    angle::MemoryBuffer mSystemCopy;
 };
 
 Buffer11::Buffer11(const gl::BufferState &state, Renderer11 *renderer)
@@ -1274,7 +1274,7 @@
         // Expand the memory storage upon request and cache the results.
         unsigned int expandedDataSize =
             static_cast<unsigned int>((indexInfo->srcCount * attribute.stride) + offset);
-        MemoryBuffer expandedData;
+        angle::MemoryBuffer expandedData;
         if (!expandedData.resize(expandedDataSize))
         {
             return gl::Error(
diff --git a/src/libANGLE/renderer/d3d/d3d11/Image11.cpp b/src/libANGLE/renderer/d3d/d3d11/Image11.cpp
index 1e58ef0..2657b1e 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Image11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Image11.cpp
@@ -370,7 +370,7 @@
     if (loadFunction.requiresConversion)
     {
         size_t bufferSize = destFormatInfo.pixelBytes * sourceArea.width * sourceArea.height;
-        MemoryBuffer *memoryBuffer = nullptr;
+        angle::MemoryBuffer *memoryBuffer = nullptr;
         mRenderer->getScratchMemoryBuffer(bufferSize, &memoryBuffer);
         GLuint memoryBufferRowPitch = destFormatInfo.pixelBytes * sourceArea.width;
 
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
index d6e7b44..a53fc41 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.cpp
@@ -376,10 +376,7 @@
     }
 }
 
-// If we request a scratch buffer requesting a smaller size this many times,
-// release and recreate the scratch buffer. This ensures we don't have a
-// degenerate case where we are stuck hogging memory.
-const int ScratchMemoryBufferLifetime = 1000;
+const uint32_t ScratchMemoryBufferLifetime = 1000;
 
 }  // anonymous namespace
 
@@ -390,7 +387,7 @@
       mLastHistogramUpdateTime(
           ANGLEPlatformCurrent()->monotonicallyIncreasingTime(ANGLEPlatformCurrent())),
       mDebug(nullptr),
-      mScratchMemoryBufferResetCounter(0),
+      mScratchMemoryBuffer(ScratchMemoryBufferLifetime),
       mAnnotator(nullptr)
 {
     mVertexDataManager = NULL;
@@ -2717,7 +2714,7 @@
 {
     RendererD3D::cleanup();
 
-    mScratchMemoryBuffer.resize(0);
+    mScratchMemoryBuffer.clear();
 
     if (mAnnotator != nullptr)
     {
@@ -4589,33 +4586,12 @@
     return new Framebuffer11(state, this);
 }
 
-gl::Error Renderer11::getScratchMemoryBuffer(size_t requestedSize, MemoryBuffer **bufferOut)
+gl::Error Renderer11::getScratchMemoryBuffer(size_t requestedSize, angle::MemoryBuffer **bufferOut)
 {
-    if (mScratchMemoryBuffer.size() == requestedSize)
+    if (!mScratchMemoryBuffer.get(requestedSize, bufferOut))
     {
-        mScratchMemoryBufferResetCounter = ScratchMemoryBufferLifetime;
-        *bufferOut                       = &mScratchMemoryBuffer;
-        return gl::NoError();
+        return gl::OutOfMemory() << "Failed to allocate internal buffer.";
     }
-
-    if (mScratchMemoryBuffer.size() > requestedSize)
-    {
-        mScratchMemoryBufferResetCounter--;
-    }
-
-    if (mScratchMemoryBufferResetCounter <= 0 || mScratchMemoryBuffer.size() < requestedSize)
-    {
-        mScratchMemoryBuffer.resize(0);
-        if (!mScratchMemoryBuffer.resize(requestedSize))
-        {
-            return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal buffer.");
-        }
-        mScratchMemoryBufferResetCounter = ScratchMemoryBufferLifetime;
-    }
-
-    ASSERT(mScratchMemoryBuffer.size() >= requestedSize);
-
-    *bufferOut = &mScratchMemoryBuffer;
     return gl::NoError();
 }
 
diff --git a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
index 6d9fe0f..e27eedd 100644
--- a/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
+++ b/src/libANGLE/renderer/d3d/d3d11/Renderer11.h
@@ -377,7 +377,7 @@
     // Necessary hack for default framebuffers in D3D.
     FramebufferImpl *createDefaultFramebuffer(const gl::FramebufferState &state) override;
 
-    gl::Error getScratchMemoryBuffer(size_t requestedSize, MemoryBuffer **bufferOut);
+    gl::Error getScratchMemoryBuffer(size_t requestedSize, angle::MemoryBuffer **bufferOut);
 
     gl::Version getMaxSupportedESVersion() const override;
 
@@ -574,8 +574,7 @@
 
     std::vector<GLuint> mScratchIndexDataBuffer;
 
-    MemoryBuffer mScratchMemoryBuffer;
-    unsigned int mScratchMemoryBufferResetCounter;
+    angle::ScratchBuffer mScratchMemoryBuffer;
 
     gl::DebugAnnotator *mAnnotator;
 
diff --git a/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp b/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp
index 3afa02e..2a4906d 100644
--- a/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp
+++ b/src/libANGLE/renderer/d3d/d3d11/TextureStorage11.cpp
@@ -654,7 +654,7 @@
     UINT bufferDepthPitch = bufferRowPitch * height;
 
     const size_t neededSize        = bufferDepthPitch * depth;
-    MemoryBuffer *conversionBuffer = nullptr;
+    angle::MemoryBuffer *conversionBuffer = nullptr;
     const uint8_t *data            = nullptr;
 
     LoadImageFunctionInfo loadFunctionInfo = d3d11Format.getLoadFunctions()(type);
diff --git a/src/libANGLE/renderer/d3d/d3d9/Buffer9.h b/src/libANGLE/renderer/d3d/d3d9/Buffer9.h
index ddb0d7b..a8c0cb2 100644
--- a/src/libANGLE/renderer/d3d/d3d9/Buffer9.h
+++ b/src/libANGLE/renderer/d3d/d3d9/Buffer9.h
@@ -54,7 +54,7 @@
     gl::Error markTransformFeedbackUsage() override;
 
   private:
-    MemoryBuffer mMemory;
+    angle::MemoryBuffer mMemory;
     size_t mSize;
 };
 
diff --git a/src/libANGLE/renderer/gl/BufferGL.h b/src/libANGLE/renderer/gl/BufferGL.h
index 2651ff1..5bc62bc 100644
--- a/src/libANGLE/renderer/gl/BufferGL.h
+++ b/src/libANGLE/renderer/gl/BufferGL.h
@@ -63,7 +63,7 @@
     size_t mMapSize;
 
     bool mShadowBufferData;
-    MemoryBuffer mShadowCopy;
+    angle::MemoryBuffer mShadowCopy;
 
     size_t mBufferSize;
 
@@ -73,6 +73,6 @@
     GLuint mBufferID;
 };
 
-}
+}  // namespace rx
 
 #endif // LIBANGLE_RENDERER_GL_BUFFERGL_H_