Commit aa6dd50d by Geoff Lang Committed by Commit Bot

Share scratch buffers between contexts.

The Display now owns scratch buffers and loans them out to contexts while they are current. This allows us to to only allocate one scratch buffer in a single-threaded use case. Tick the scratch buffers every time a new context is made current. Lower the lifetime from 1000 to 64 to ensure that in the worst case, the buffers are cleared after not being used for ~1 second. BUG=chromium:1030835 BUG=angleproject:4363 Change-Id: I83552424e2beac62b9e41152876b04fc84f53692 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2031698 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarZhenyao Mo <zmo@chromium.org>
parent 4546c5ce
...@@ -76,12 +76,32 @@ MemoryBuffer &MemoryBuffer::operator=(MemoryBuffer &&other) ...@@ -76,12 +76,32 @@ MemoryBuffer &MemoryBuffer::operator=(MemoryBuffer &&other)
return *this; return *this;
} }
namespace
{
static constexpr uint32_t kDefaultScratchBufferLifetime = 1000u;
} // anonymous namespace
// ScratchBuffer implementation. // ScratchBuffer implementation.
ScratchBuffer::ScratchBuffer() : ScratchBuffer(kDefaultScratchBufferLifetime) {}
ScratchBuffer::ScratchBuffer(uint32_t lifetime) : mLifetime(lifetime), mResetCounter(lifetime) {} ScratchBuffer::ScratchBuffer(uint32_t lifetime) : mLifetime(lifetime), mResetCounter(lifetime) {}
ScratchBuffer::~ScratchBuffer() {} ScratchBuffer::~ScratchBuffer() {}
ScratchBuffer::ScratchBuffer(ScratchBuffer &&other)
{
*this = std::move(other);
}
ScratchBuffer &ScratchBuffer::operator=(ScratchBuffer &&other)
{
std::swap(mLifetime, other.mLifetime);
std::swap(mResetCounter, other.mResetCounter);
std::swap(mScratchMemory, other.mScratchMemory);
return *this;
}
bool ScratchBuffer::get(size_t requestedSize, MemoryBuffer **memoryBufferOut) bool ScratchBuffer::get(size_t requestedSize, MemoryBuffer **memoryBufferOut)
{ {
return getImpl(requestedSize, memoryBufferOut, Optional<uint8_t>::Invalid()); return getImpl(requestedSize, memoryBufferOut, Optional<uint8_t>::Invalid());
...@@ -110,9 +130,8 @@ bool ScratchBuffer::getImpl(size_t requestedSize, ...@@ -110,9 +130,8 @@ bool ScratchBuffer::getImpl(size_t requestedSize,
tick(); tick();
} }
if (mResetCounter == 0 || mScratchMemory.size() < requestedSize) if (mScratchMemory.size() < requestedSize)
{ {
clear();
if (!mScratchMemory.resize(requestedSize)) if (!mScratchMemory.resize(requestedSize))
{ {
return false; return false;
...@@ -135,13 +154,20 @@ void ScratchBuffer::tick() ...@@ -135,13 +154,20 @@ void ScratchBuffer::tick()
if (mResetCounter > 0) if (mResetCounter > 0)
{ {
--mResetCounter; --mResetCounter;
if (mResetCounter == 0)
{
clear();
}
} }
} }
void ScratchBuffer::clear() void ScratchBuffer::clear()
{ {
mResetCounter = mLifetime; mResetCounter = mLifetime;
mScratchMemory.clear(); if (mScratchMemory.size() > 0)
{
mScratchMemory.clear();
}
} }
} // namespace angle } // namespace angle
...@@ -62,9 +62,13 @@ class ScratchBuffer final : NonCopyable ...@@ -62,9 +62,13 @@ class ScratchBuffer final : NonCopyable
// If we request a scratch buffer requesting a smaller size this many times, release and // 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 // recreate the scratch buffer. This ensures we don't have a degenerate case where we are stuck
// hogging memory. // hogging memory.
ScratchBuffer();
ScratchBuffer(uint32_t lifetime); ScratchBuffer(uint32_t lifetime);
~ScratchBuffer(); ~ScratchBuffer();
ScratchBuffer(ScratchBuffer &&other);
ScratchBuffer &operator=(ScratchBuffer &&other);
// Returns true with a memory buffer of the requested size, or false on failure. // Returns true with a memory buffer of the requested size, or false on failure.
bool get(size_t requestedSize, MemoryBuffer **memoryBufferOut); bool get(size_t requestedSize, MemoryBuffer **memoryBufferOut);
...@@ -79,7 +83,7 @@ class ScratchBuffer final : NonCopyable ...@@ -79,7 +83,7 @@ class ScratchBuffer final : NonCopyable
private: private:
bool getImpl(size_t requestedSize, MemoryBuffer **memoryBufferOut, Optional<uint8_t> initValue); bool getImpl(size_t requestedSize, MemoryBuffer **memoryBufferOut, Optional<uint8_t> initValue);
const uint32_t mLifetime; uint32_t mLifetime;
uint32_t mResetCounter; uint32_t mResetCounter;
MemoryBuffer mScratchMemory; MemoryBuffer mScratchMemory;
}; };
......
...@@ -43,10 +43,16 @@ struct Optional ...@@ -43,10 +43,16 @@ struct Optional
} }
void reset() { mValid = false; } void reset() { mValid = false; }
T &&release()
{
mValid = false;
return std::move(mValue);
}
static Optional Invalid() { return Optional(); } static Optional Invalid() { return Optional(); }
bool valid() const { return mValid; } bool valid() const { return mValid; }
T &value() { return mValue; }
const T &value() const { return mValue; } const T &value() const { return mValue; }
bool operator==(const Optional &other) const bool operator==(const Optional &other) const
......
...@@ -347,8 +347,6 @@ Context::Context(egl::Display *display, ...@@ -347,8 +347,6 @@ Context::Context(egl::Display *display,
mVertexArrayObserverBinding(this, kVertexArraySubjectIndex), mVertexArrayObserverBinding(this, kVertexArraySubjectIndex),
mDrawFramebufferObserverBinding(this, kDrawFramebufferSubjectIndex), mDrawFramebufferObserverBinding(this, kDrawFramebufferSubjectIndex),
mReadFramebufferObserverBinding(this, kReadFramebufferSubjectIndex), mReadFramebufferObserverBinding(this, kReadFramebufferSubjectIndex),
mScratchBuffer(1000u),
mZeroFilledBuffer(1000u),
mThreadPool(nullptr), mThreadPool(nullptr),
mFrameCapture(new angle::FrameCapture), mFrameCapture(new angle::FrameCapture),
mOverlay(mImplementation.get()) mOverlay(mImplementation.get())
...@@ -706,7 +704,20 @@ egl::Error Context::unMakeCurrent(const egl::Display *display) ...@@ -706,7 +704,20 @@ egl::Error Context::unMakeCurrent(const egl::Display *display)
{ {
ANGLE_TRY(unsetDefaultFramebuffer()); ANGLE_TRY(unsetDefaultFramebuffer());
return angle::ResultToEGL(mImplementation->onUnMakeCurrent(this)); ANGLE_TRY(angle::ResultToEGL(mImplementation->onUnMakeCurrent(this)));
// Return the scratch buffers to the display so they can be shared with other contexts while
// this one is not current.
if (mScratchBuffer.valid())
{
mDisplay->returnScratchBuffer(mScratchBuffer.release());
}
if (mZeroFilledBuffer.valid())
{
mDisplay->returnZeroFilledBuffer(mZeroFilledBuffer.release());
}
return egl::NoError();
} }
BufferID Context::createBuffer() BufferID Context::createBuffer()
...@@ -5757,13 +5768,36 @@ void Context::framebufferParameteri(GLenum target, GLenum pname, GLint param) ...@@ -5757,13 +5768,36 @@ void Context::framebufferParameteri(GLenum target, GLenum pname, GLint param)
bool Context::getScratchBuffer(size_t requstedSizeBytes, bool Context::getScratchBuffer(size_t requstedSizeBytes,
angle::MemoryBuffer **scratchBufferOut) const angle::MemoryBuffer **scratchBufferOut) const
{ {
return mScratchBuffer.get(requstedSizeBytes, scratchBufferOut); if (!mScratchBuffer.valid())
{
mScratchBuffer = mDisplay->requestScratchBuffer();
}
ASSERT(mScratchBuffer.valid());
return mScratchBuffer.value().get(requstedSizeBytes, scratchBufferOut);
}
angle::ScratchBuffer *Context::getScratchBuffer() const
{
if (!mScratchBuffer.valid())
{
mScratchBuffer = mDisplay->requestScratchBuffer();
}
ASSERT(mScratchBuffer.valid());
return &mScratchBuffer.value();
} }
bool Context::getZeroFilledBuffer(size_t requstedSizeBytes, bool Context::getZeroFilledBuffer(size_t requstedSizeBytes,
angle::MemoryBuffer **zeroBufferOut) const angle::MemoryBuffer **zeroBufferOut) const
{ {
return mZeroFilledBuffer.getInitialized(requstedSizeBytes, zeroBufferOut, 0); if (!mZeroFilledBuffer.valid())
{
mZeroFilledBuffer = mDisplay->requestZeroFilledBuffer();
}
ASSERT(mZeroFilledBuffer.valid());
return mZeroFilledBuffer.value().getInitialized(requstedSizeBytes, zeroBufferOut, 0);
} }
void Context::dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ) void Context::dispatchCompute(GLuint numGroupsX, GLuint numGroupsY, GLuint numGroupsZ)
......
...@@ -480,7 +480,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl ...@@ -480,7 +480,7 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
angle::MemoryBuffer **scratchBufferOut) const; angle::MemoryBuffer **scratchBufferOut) const;
ANGLE_NO_DISCARD bool getZeroFilledBuffer(size_t requstedSizeBytes, ANGLE_NO_DISCARD bool getZeroFilledBuffer(size_t requstedSizeBytes,
angle::MemoryBuffer **zeroBufferOut) const; angle::MemoryBuffer **zeroBufferOut) const;
angle::ScratchBuffer *getScratchBuffer() const { return &mScratchBuffer; } angle::ScratchBuffer *getScratchBuffer() const;
angle::Result prepareForCopyImage(); angle::Result prepareForCopyImage();
angle::Result prepareForDispatch(); angle::Result prepareForDispatch();
...@@ -731,8 +731,8 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl ...@@ -731,8 +731,8 @@ class Context final : public egl::LabeledObject, angle::NonCopyable, public angl
std::vector<angle::ObserverBinding> mImageObserverBindings; std::vector<angle::ObserverBinding> mImageObserverBindings;
// Not really a property of context state. The size and contexts change per-api-call. // Not really a property of context state. The size and contexts change per-api-call.
mutable angle::ScratchBuffer mScratchBuffer; mutable Optional<angle::ScratchBuffer> mScratchBuffer;
mutable angle::ScratchBuffer mZeroFilledBuffer; mutable Optional<angle::ScratchBuffer> mZeroFilledBuffer;
std::shared_ptr<angle::WorkerThreadPool> mThreadPool; std::shared_ptr<angle::WorkerThreadPool> mThreadPool;
......
...@@ -388,6 +388,8 @@ void ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display) ...@@ -388,6 +388,8 @@ void ANGLESetDefaultDisplayPlatform(angle::EGLDisplayType display)
platformMethods->logInfo = Display_logInfo; platformMethods->logInfo = Display_logInfo;
} }
static constexpr uint32_t kScratchBufferLifetime = 64u;
} // anonymous namespace } // anonymous namespace
DisplayState::DisplayState() : label(nullptr), featuresAllDisabled(false) {} DisplayState::DisplayState() : label(nullptr), featuresAllDisabled(false) {}
...@@ -1071,6 +1073,21 @@ Error Display::makeCurrent(const Thread *thread, ...@@ -1071,6 +1073,21 @@ Error Display::makeCurrent(const Thread *thread,
ANGLE_TRY(context->makeCurrent(this, drawSurface, readSurface)); ANGLE_TRY(context->makeCurrent(this, drawSurface, readSurface));
} }
// Tick all the scratch buffers to make sure they get cleaned up eventually if they stop being
// used.
{
std::lock_guard<std::mutex> lock(mScratchBufferMutex);
for (angle::ScratchBuffer &scatchBuffer : mScratchBuffers)
{
scatchBuffer.tick();
}
for (angle::ScratchBuffer &zeroFilledBuffer : mZeroFilledBuffers)
{
zeroFilledBuffer.tick();
}
}
return NoError(); return NoError();
} }
...@@ -1663,4 +1680,46 @@ EGLAttrib Display::queryAttrib(const EGLint attribute) ...@@ -1663,4 +1680,46 @@ EGLAttrib Display::queryAttrib(const EGLint attribute)
} }
return value; return value;
} }
angle::ScratchBuffer Display::requestScratchBuffer()
{
return requestScratchBufferImpl(&mScratchBuffers);
}
void Display::returnScratchBuffer(angle::ScratchBuffer scratchBuffer)
{
returnScratchBufferImpl(std::move(scratchBuffer), &mScratchBuffers);
}
angle::ScratchBuffer Display::requestZeroFilledBuffer()
{
return requestScratchBufferImpl(&mZeroFilledBuffers);
}
void Display::returnZeroFilledBuffer(angle::ScratchBuffer zeroFilledBuffer)
{
returnScratchBufferImpl(std::move(zeroFilledBuffer), &mZeroFilledBuffers);
}
angle::ScratchBuffer Display::requestScratchBufferImpl(
std::vector<angle::ScratchBuffer> *bufferVector)
{
std::lock_guard<std::mutex> lock(mScratchBufferMutex);
if (!bufferVector->empty())
{
angle::ScratchBuffer buffer = std::move(bufferVector->back());
bufferVector->pop_back();
return buffer;
}
return angle::ScratchBuffer(kScratchBufferLifetime);
}
void Display::returnScratchBufferImpl(angle::ScratchBuffer scratchBuffer,
std::vector<angle::ScratchBuffer> *bufferVector)
{
std::lock_guard<std::mutex> lock(mScratchBufferMutex);
bufferVector->push_back(std::move(scratchBuffer));
}
} // namespace egl } // namespace egl
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#ifndef LIBANGLE_DISPLAY_H_ #ifndef LIBANGLE_DISPLAY_H_
#define LIBANGLE_DISPLAY_H_ #define LIBANGLE_DISPLAY_H_
#include <mutex>
#include <set> #include <set>
#include <vector> #include <vector>
...@@ -208,6 +209,12 @@ class Display final : public LabeledObject, angle::NonCopyable ...@@ -208,6 +209,12 @@ class Display final : public LabeledObject, angle::NonCopyable
EGLAttrib queryAttrib(const EGLint attribute); EGLAttrib queryAttrib(const EGLint attribute);
angle::ScratchBuffer requestScratchBuffer();
void returnScratchBuffer(angle::ScratchBuffer scratchBuffer);
angle::ScratchBuffer requestZeroFilledBuffer();
void returnZeroFilledBuffer(angle::ScratchBuffer zeroFilledBuffer);
private: private:
Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice); Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDevice);
...@@ -223,6 +230,10 @@ class Display final : public LabeledObject, angle::NonCopyable ...@@ -223,6 +230,10 @@ class Display final : public LabeledObject, angle::NonCopyable
void initVendorString(); void initVendorString();
void initializeFrontendFeatures(); void initializeFrontendFeatures();
angle::ScratchBuffer requestScratchBufferImpl(std::vector<angle::ScratchBuffer> *bufferVector);
void returnScratchBufferImpl(angle::ScratchBuffer scratchBuffer,
std::vector<angle::ScratchBuffer> *bufferVector);
DisplayState mState; DisplayState mState;
rx::DisplayImpl *mImplementation; rx::DisplayImpl *mImplementation;
...@@ -265,6 +276,10 @@ class Display final : public LabeledObject, angle::NonCopyable ...@@ -265,6 +276,10 @@ class Display final : public LabeledObject, angle::NonCopyable
angle::FrontendFeatures mFrontendFeatures; angle::FrontendFeatures mFrontendFeatures;
angle::FeatureList mFeatures; angle::FeatureList mFeatures;
std::mutex mScratchBufferMutex;
std::vector<angle::ScratchBuffer> mScratchBuffers;
std::vector<angle::ScratchBuffer> mZeroFilledBuffers;
}; };
} // namespace egl } // namespace egl
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment