From eaa35b1de1138a7913e8d4f86ced0b7a6e5c3a3d Mon Sep 17 00:00:00 2001 From: ZhaoPengyuan Date: Sat, 1 Aug 2020 11:01:06 +0800 Subject: [PATCH] memory:delay the deletion of ColorBuffers delete the ColorBuffers which not used within 2 seconds --- src/anbox/graphics/emugl/ColorBuffer.cpp | 13 ++- src/anbox/graphics/emugl/ColorBuffer.h | 9 +- src/anbox/graphics/emugl/RenderThreadInfo.h | 1 - src/anbox/graphics/emugl/Renderer.cpp | 93 +++++++++++++++++---- src/anbox/graphics/emugl/Renderer.h | 27 +++++- 5 files changed, 120 insertions(+), 23 deletions(-) diff --git a/src/anbox/graphics/emugl/ColorBuffer.cpp b/src/anbox/graphics/emugl/ColorBuffer.cpp index f336c83..76eb4e8 100644 --- a/src/anbox/graphics/emugl/ColorBuffer.cpp +++ b/src/anbox/graphics/emugl/ColorBuffer.cpp @@ -102,7 +102,7 @@ class ScopedHelperContext { // static ColorBuffer* ColorBuffer::create(EGLDisplay p_display, int p_width, int p_height, GLenum p_internalFormat, - bool has_eglimage_texture_2d, Helper* helper) { + bool has_eglimage_texture_2d, Helper* helper, HandleType hndl) { GLenum texInternalFormat = 0; switch (p_internalFormat) { @@ -127,7 +127,7 @@ ColorBuffer* ColorBuffer::create(EGLDisplay p_display, int p_width, return NULL; } - ColorBuffer* cb = new ColorBuffer(p_display, helper); + ColorBuffer* cb = new ColorBuffer(p_display, helper, hndl); s_gles2.glGenTextures(1, &cb->m_tex); s_gles2.glBindTexture(GL_TEXTURE_2D, cb->m_tex); @@ -176,7 +176,7 @@ ColorBuffer* ColorBuffer::create(EGLDisplay p_display, int p_width, return cb; } -ColorBuffer::ColorBuffer(EGLDisplay display, Helper* helper) +ColorBuffer::ColorBuffer(EGLDisplay display, Helper* helper, HandleType hndl) : m_tex(0), m_blitTex(0), m_eglImage(NULL), @@ -184,7 +184,8 @@ ColorBuffer::ColorBuffer(EGLDisplay display, Helper* helper) m_fbo(0), m_internalFormat(0), m_display(display), - m_helper(helper) {} + m_helper(helper), + mHndl(hndl) {} ColorBuffer::~ColorBuffer() { ScopedHelperContext context(m_helper); @@ -206,6 +207,10 @@ ColorBuffer::~ColorBuffer() { delete m_resizer; } +HandleType ColorBuffer::getHndl() const { + return mHndl; +} + void ColorBuffer::readPixels(int x, int y, int width, int height, GLenum p_format, GLenum p_type, void* pixels) { ScopedHelperContext context(m_helper); diff --git a/src/anbox/graphics/emugl/ColorBuffer.h b/src/anbox/graphics/emugl/ColorBuffer.h index 19bf44c..bcf3835 100644 --- a/src/anbox/graphics/emugl/ColorBuffer.h +++ b/src/anbox/graphics/emugl/ColorBuffer.h @@ -22,6 +22,8 @@ #include +typedef uint32_t HandleType; + class TextureDraw; class TextureResize; @@ -77,7 +79,7 @@ class ColorBuffer { // Returns NULL on failure. static ColorBuffer* create(EGLDisplay p_display, int p_width, int p_height, GLenum p_internalFormat, - bool has_eglimage_texture_2d, Helper* helper); + bool has_eglimage_texture_2d, Helper* helper, HandleType hndl); // Destructor. ~ColorBuffer(); @@ -115,10 +117,12 @@ class ColorBuffer { void bind(); + HandleType getHndl() const; + private: ColorBuffer(); // no default constructor. - explicit ColorBuffer(EGLDisplay display, Helper* helper); + explicit ColorBuffer(EGLDisplay display, Helper* helper, HandleType hndl); private: GLuint m_tex; @@ -132,6 +136,7 @@ class ColorBuffer { EGLDisplay m_display; Helper* m_helper; TextureResize* m_resizer; + HandleType mHndl; }; typedef std::shared_ptr ColorBufferPtr; diff --git a/src/anbox/graphics/emugl/RenderThreadInfo.h b/src/anbox/graphics/emugl/RenderThreadInfo.h index 10516a6..968c445 100644 --- a/src/anbox/graphics/emugl/RenderThreadInfo.h +++ b/src/anbox/graphics/emugl/RenderThreadInfo.h @@ -28,7 +28,6 @@ #include -typedef uint32_t HandleType; typedef std::set ThreadContextSet; typedef std::set WindowSurfaceSet; diff --git a/src/anbox/graphics/emugl/Renderer.cpp b/src/anbox/graphics/emugl/Renderer.cpp index cd17ab4..9f5b881 100644 --- a/src/anbox/graphics/emugl/Renderer.cpp +++ b/src/anbox/graphics/emugl/Renderer.cpp @@ -27,6 +27,8 @@ #include "gles2_dec.h" #include +#include +#include #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wold-style-cast" @@ -35,6 +37,12 @@ #include #pragma GCC diagnostic pop +int64_t getCurrentLocalTimeStamp() +{ + return std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(); +} + + namespace { // Helper class to call the bind_locked() / unbind_locked() properly. @@ -84,10 +92,16 @@ class ColorBufferHelper : public ColorBuffer::Helper { }; } // namespace +void Renderer::saveColorBuffer(ColorBufferRef* cbRef) { + eraseDelayedCloseColorBufferLocked(cbRef->cb->getHndl(), cbRef->closedTs); + cbRef->closedTs = 0; +} + HandleType Renderer::s_nextHandle = 0; void Renderer::finalize() { m_colorbuffers.clear(); + m_colorBufferDelayedCloseList.clear(); m_windows.clear(); m_contexts.clear(); s_egl.eglMakeCurrent(m_eglDisplay, NULL, NULL, NULL); @@ -366,14 +380,15 @@ HandleType Renderer::createColorBuffer(int p_width, int p_height, std::unique_lock l(m_lock); HandleType ret = 0; + ret = genHandle(); ColorBufferPtr cb(ColorBuffer::create( getDisplay(), p_width, p_height, p_internalFormat, - getCaps().has_eglimage_texture_2d, m_colorBufferHelper)); + getCaps().has_eglimage_texture_2d, m_colorBufferHelper, ret)); if (cb) { - ret = genHandle(); m_colorbuffers[ret].cb = cb; m_colorbuffers[ret].refcount = 1; + m_colorbuffers[ret].closedTs= 0; RenderThreadInfo *tInfo = RenderThreadInfo::get(); if (!tInfo) { @@ -475,12 +490,7 @@ void Renderer::drainWindowSurface() { if (m_windows.find(windowHandle) != m_windows.end()) { HandleType oldColorBufferHandle = m_windows[windowHandle].second; if (oldColorBufferHandle) { - ColorBufferMap::iterator cit(m_colorbuffers.find(oldColorBufferHandle)); - if (cit != m_colorbuffers.end()) { - if (--(*cit).second.refcount == 0) { - m_colorbuffers.erase(cit); - } - } + closeColorBufferLocked(oldColorBufferHandle); } m_windows.erase(windowHandle); } @@ -511,11 +521,12 @@ void Renderer::DestroyRenderContext(HandleType p_context) { void Renderer::DestroyWindowSurface(HandleType p_surface) { std::unique_lock l(m_lock); - if (m_windows.find(p_surface) != m_windows.end()) { - m_windows.erase(p_surface); - RenderThreadInfo *tinfo = RenderThreadInfo::get(); - if (tinfo->m_windowSet.empty()) return; - tinfo->m_windowSet.erase(p_surface); + const auto w = m_windows.find(p_surface); + if (w != m_windows.end()) { + closeColorBufferLocked(w->second.second); + m_windows.erase(w); + RenderThreadInfo* tinfo = RenderThreadInfo::get(); + tinfo->m_windowSet.erase(p_surface); } } @@ -530,6 +541,7 @@ int Renderer::openColorBuffer(HandleType p_colorbuffer) { return -1; } (*c).second.refcount++; + saveColorBuffer(&c->second); int tid = tInfo->m_tid; if (tid > 0) { m_procOwnedColorBuffers[tid].insert(p_colorbuffer); @@ -537,6 +549,51 @@ int Renderer::openColorBuffer(HandleType p_colorbuffer) { return 0; } +void Renderer::eraseDelayedCloseColorBufferLocked(HandleType cb, int64_t ts) { + // Find the first delayed buffer with a timestamp <= |ts| + auto it = std::lower_bound( + m_colorBufferDelayedCloseList.begin(), + m_colorBufferDelayedCloseList.end(), ts, + [](const ColorBufferCloseInfo& ci, int64_t ts) { + return ci.ts < ts; + }); + while (it != m_colorBufferDelayedCloseList.end() && + it->ts == ts) { + // if this is the one we need - clear it out. + if (it->cbHandle == cb) { + it->cbHandle = 0; + break; + } + ++it; + } +} + +void Renderer::performDelayedColorBufferCloseLocked() { + // Let's wait just long enough to make sure it's not because of instant + // timestamp change (end of previous second -> beginning of a next one), + // but not for long - this is a workaround for race conditions, and they + // are quick. + static constexpr int64_t kColorBufferClosingDelayMS = 2000; + + const auto now = getCurrentLocalTimeStamp(); + auto it = m_colorBufferDelayedCloseList.begin(); + while (it != m_colorBufferDelayedCloseList.end() && + (it->ts + kColorBufferClosingDelayMS <= now)) { + if (it->cbHandle != 0) { + for (auto& ite : m_procOwnedColorBuffers) { + if (ite.second.find(it->cbHandle) != ite.second.end()) { + ite.second.erase(it->cbHandle); + } + } + const auto& cb = m_colorbuffers.find(it->cbHandle); + m_colorbuffers.erase(cb); + } + ++it; + } + m_colorBufferDelayedCloseList.erase( + m_colorBufferDelayedCloseList.begin(), it); +} + void Renderer::closeColorBufferLocked(HandleType p_colorbuffer) { ColorBufferMap::iterator c(m_colorbuffers.find(p_colorbuffer)); if (c == m_colorbuffers.end()) { @@ -547,8 +604,11 @@ void Renderer::closeColorBufferLocked(HandleType p_colorbuffer) { return; } if (--(*c).second.refcount == 0) { - m_colorbuffers.erase(c); + c->second.closedTs = getCurrentLocalTimeStamp(); + m_colorBufferDelayedCloseList.push_back( + {c->second.closedTs, p_colorbuffer}); } + performDelayedColorBufferCloseLocked(); } void Renderer::closeColorBuffer(HandleType p_colorbuffer) @@ -649,6 +709,11 @@ bool Renderer::setWindowSurfaceColorBuffer(HandleType p_surface, } (*w).second.first->setColorBuffer((*c).second.cb); + saveColorBuffer(&c->second); + if (w->second.second) { + closeColorBufferLocked(w->second.second); + } + c->second.refcount++; (*w).second.second = p_colorbuffer; return true; } diff --git a/src/anbox/graphics/emugl/Renderer.h b/src/anbox/graphics/emugl/Renderer.h index 01dd928..6fe1219 100644 --- a/src/anbox/graphics/emugl/Renderer.h +++ b/src/anbox/graphics/emugl/Renderer.h @@ -44,6 +44,7 @@ typedef uint32_t HandleType; struct ColorBufferRef { ColorBufferPtr cb; uint32_t refcount; // number of client-side references + int64_t closedTs; }; typedef std::map RenderContextMap; typedef std::unordered_set RenderContextSet; @@ -87,6 +88,12 @@ class Renderer : public anbox::graphics::Renderer { Renderer(); virtual ~Renderer(); + void saveColorBuffer(ColorBufferRef* cbRef); + + void eraseDelayedCloseColorBufferLocked(HandleType cb, int64_t ts); + + void performDelayedColorBufferCloseLocked(); + // Initialize the global instance. // |width| and |height| are the dimensions of the emulator GPU display // in pixels. |useSubWindow| is true to indicate that the caller @@ -171,9 +178,9 @@ class Renderer : public anbox::graphics::Renderer { // createColorBuffer(). Note that if the reference count reaches 0, // the instance is destroyed automatically. void closeColorBuffer(HandleType p_colorbuffer); - void closeColorBufferLocked(HandleType p_colorbuffer); + void closeColorBufferLocked(HandleType p_colorbuffer); - void cleanupProcGLObjects(int tid); + void cleanupProcGLObjects(int tid); // Equivalent for eglMakeCurrent() for the current display. // |p_context|, |p_drawSurface| and |p_readSurface| are the handle values // of the context, the draw surface and the read surface, respectively. @@ -326,5 +333,21 @@ class Renderer : public anbox::graphics::Renderer { ProcOwnedColorBuffers m_procOwnedColorBuffers; ProcOwnedEGLImages m_procOwnedEGLImages; ProcOwnedRenderContexts m_procOwnedRenderContext; + + // A collection of color buffers that were closed without any usages + // + // If a buffer reached |refcount| == 0 while not being |opened|, instead of + // deleting it we remember the timestamp when this happened. Later, we + // check if the buffer stayed unopened long enough and if it did, we delete + // it permanently. On the other hand, if the color buffer was used then + // we don't care about timestamps anymore. + // + // Note: this collection is ordered by |ts| field. + struct ColorBufferCloseInfo { + int64_t ts; // when we got the close request. + HandleType cbHandle; // 0 == already closed, do nothing + }; + using ColorBufferDelayedClose = std::vector; + ColorBufferDelayedClose m_colorBufferDelayedCloseList; }; #endif -- Gitee