diff options
| -rw-r--r-- | include/gui/Surface.h | 18 | ||||
| -rw-r--r-- | libs/gui/Surface.cpp | 36 | 
2 files changed, 53 insertions, 1 deletions
| diff --git a/include/gui/Surface.h b/include/gui/Surface.h index 62f6cadece..88ef010368 100644 --- a/include/gui/Surface.h +++ b/include/gui/Surface.h @@ -257,10 +257,25 @@ public:      virtual int query(int what, int* value) const;      virtual int connect(int api, const sp<IProducerListener>& listener); + +    // When reportBufferRemoval is true, clients must call getAndFlushRemovedBuffers to fetch +    // GraphicBuffers removed from this surface after a dequeueBuffer, detachNextBuffer or +    // attachBuffer call. This allows clients with their own buffer caches to free up buffers no +    // longer in use by this surface. +    virtual int connect( +            int api, const sp<IProducerListener>& listener, +            bool reportBufferRemoval);      virtual int detachNextBuffer(sp<GraphicBuffer>* outBuffer,              sp<Fence>* outFence);      virtual int attachBuffer(ANativeWindowBuffer*); +    // When client connects to Surface with reportBufferRemoval set to true, any buffers removed +    // from this Surface will be collected and returned here. Once this method returns, these +    // buffers will no longer be referenced by this Surface unless they are attached to this +    // Surface later. The list of removed buffers will only be stored until the next dequeueBuffer, +    // detachNextBuffer, or attachBuffer call. +    status_t getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out); +  protected:      enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };      enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 }; @@ -414,6 +429,9 @@ protected:      // A cached copy of the FrameEventHistory maintained by the consumer.      bool mEnableFrameTimestamps = false;      std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory; + +    bool mReportRemovedBuffers = false; +    std::vector<sp<GraphicBuffer>> mRemovedBuffers;  };  } // namespace android diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 06fc31d16c..1149b8980b 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -505,7 +505,11 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) {           mFrameEventHistory->applyDelta(frameTimestamps);      } -    if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == 0) { +    if ((result & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) || gbuf == nullptr) { +        if (mReportRemovedBuffers && (gbuf != nullptr)) { +            mRemovedBuffers.clear(); +            mRemovedBuffers.push_back(gbuf); +        }          result = mGraphicBufferProducer->requestBuffer(buf, &gbuf);          if (result != NO_ERROR) {              ALOGE("dequeueBuffer: IGraphicBufferProducer::requestBuffer failed: %d", result); @@ -1075,10 +1079,16 @@ int Surface::connect(int api) {  }  int Surface::connect(int api, const sp<IProducerListener>& listener) { +    return connect(api, listener, false); +} + +int Surface::connect( +        int api, const sp<IProducerListener>& listener, bool reportBufferRemoval) {      ATRACE_CALL();      ALOGV("Surface::connect");      Mutex::Autolock lock(mMutex);      IGraphicBufferProducer::QueueBufferOutput output; +    mReportRemovedBuffers = reportBufferRemoval;      int err = mGraphicBufferProducer->connect(listener, api, mProducerControlledByApp, &output);      if (err == NO_ERROR) {          mDefaultWidth = output.width; @@ -1109,6 +1119,7 @@ int Surface::disconnect(int api, IGraphicBufferProducer::DisconnectMode mode) {      ATRACE_CALL();      ALOGV("Surface::disconnect");      Mutex::Autolock lock(mMutex); +    mRemovedBuffers.clear();      mSharedBufferSlot = BufferItem::INVALID_BUFFER_SLOT;      mSharedBufferHasBeenQueued = false;      freeAllBuffers(); @@ -1156,9 +1167,16 @@ int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer,          *outFence = Fence::NO_FENCE;      } +    if (mReportRemovedBuffers) { +        mRemovedBuffers.clear(); +    } +      for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {          if (mSlots[i].buffer != NULL &&                  mSlots[i].buffer->handle == buffer->handle) { +            if (mReportRemovedBuffers) { +                mRemovedBuffers.push_back(mSlots[i].buffer); +            }              mSlots[i].buffer = NULL;          }      } @@ -1184,6 +1202,10 @@ int Surface::attachBuffer(ANativeWindowBuffer* buffer)          graphicBuffer->mGenerationNumber = priorGeneration;          return result;      } +    if (mReportRemovedBuffers && (mSlots[attachedSlot].buffer != nullptr)) { +        mRemovedBuffers.clear(); +        mRemovedBuffers.push_back(mSlots[attachedSlot].buffer); +    }      mSlots[attachedSlot].buffer = graphicBuffer;      return NO_ERROR; @@ -1617,4 +1639,16 @@ status_t Surface::getUniqueId(uint64_t* outId) const {      return mGraphicBufferProducer->getUniqueId(outId);  } +status_t Surface::getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out) { +    if (out == nullptr) { +        ALOGE("%s: out must not be null!", __FUNCTION__); +        return BAD_VALUE; +    } + +    Mutex::Autolock lock(mMutex); +    *out = mRemovedBuffers; +    mRemovedBuffers.clear(); +    return OK; +} +  }; // namespace android |