1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <compositionengine/impl/HwcBufferCache.h>
18 
19 #include <gui/BufferQueue.h>
20 #include <ui/GraphicBuffer.h>
21 
22 namespace android::compositionengine::impl {
23 
HwcBufferCache()24 HwcBufferCache::HwcBufferCache() {
25     for (uint32_t i = kMaxLayerBufferCount; i-- > 0;) {
26         mFreeSlots.push(i);
27     }
28 }
29 
getHwcSlotAndBuffer(const sp<GraphicBuffer> & buffer)30 HwcSlotAndBuffer HwcBufferCache::getHwcSlotAndBuffer(const sp<GraphicBuffer>& buffer) {
31     if (auto i = mCacheByBufferId.find(buffer->getId()); i != mCacheByBufferId.end()) {
32         Cache& cache = i->second;
33         // mark this cache slot as more recently used so it won't get evicted anytime soon
34         cache.lruCounter = mLeastRecentlyUsedCounter++;
35         return {cache.slot, nullptr};
36     }
37     return {cache(buffer), buffer};
38 }
39 
getOverrideHwcSlotAndBuffer(const sp<GraphicBuffer> & buffer)40 HwcSlotAndBuffer HwcBufferCache::getOverrideHwcSlotAndBuffer(const sp<GraphicBuffer>& buffer) {
41     if (buffer == mLastOverrideBuffer) {
42         return {kOverrideBufferSlot, nullptr};
43     }
44     mLastOverrideBuffer = buffer;
45     return {kOverrideBufferSlot, buffer};
46 }
47 
uncache(uint64_t bufferId)48 uint32_t HwcBufferCache::uncache(uint64_t bufferId) {
49     if (auto i = mCacheByBufferId.find(bufferId); i != mCacheByBufferId.end()) {
50         uint32_t slot = i->second.slot;
51         mCacheByBufferId.erase(i);
52         mFreeSlots.push(slot);
53         return slot;
54     }
55     if (mLastOverrideBuffer && bufferId == mLastOverrideBuffer->getId()) {
56         mLastOverrideBuffer = nullptr;
57         return kOverrideBufferSlot;
58     }
59     return UINT32_MAX;
60 }
61 
cache(const sp<GraphicBuffer> & buffer)62 uint32_t HwcBufferCache::cache(const sp<GraphicBuffer>& buffer) {
63     Cache cache;
64     cache.slot = getLeastRecentlyUsedSlot();
65     cache.lruCounter = mLeastRecentlyUsedCounter++;
66     cache.buffer = buffer;
67     mCacheByBufferId.emplace(buffer->getId(), cache);
68     return cache.slot;
69 }
70 
getLeastRecentlyUsedSlot()71 uint32_t HwcBufferCache::getLeastRecentlyUsedSlot() {
72     if (mFreeSlots.empty()) {
73         assert(!mCacheByBufferId.empty());
74         // evict the least recently used cache entry
75         auto cacheToErase = mCacheByBufferId.begin();
76         for (auto i = cacheToErase; i != mCacheByBufferId.end(); ++i) {
77             if (i->second.lruCounter < cacheToErase->second.lruCounter) {
78                 cacheToErase = i;
79             }
80         }
81         uint32_t slot = cacheToErase->second.slot;
82         mCacheByBufferId.erase(cacheToErase);
83         mFreeSlots.push(slot);
84     }
85     uint32_t slot = mFreeSlots.top();
86     mFreeSlots.pop();
87     return slot;
88 }
89 
90 } // namespace android::compositionengine::impl
91