blob: b6a4240b4be576430ef866d4b83c1479e88f0480 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <cstdint>
#include <stack>
#include <unordered_map>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wextra"
#include <gui/BufferQueue.h>
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
#include <utils/StrongPointer.h>
namespace android {
class GraphicBuffer;
namespace compositionengine::impl {
// The buffer cache returns both a slot and the buffer that should be sent to HWC. In cases
// where the buffer is already cached, the buffer is a nullptr and will not be sent to HWC as
// an optimization.
struct HwcSlotAndBuffer {
uint32_t slot;
sp<GraphicBuffer> buffer;
};
//
// Manages the slot assignments for a buffers stored in Composer HAL's cache.
//
// Cache slots are an optimization when communicating buffer handles to Composer
// HAL. When updating a layer's buffer, we can either send a new buffer handle
// along with it's slot assignment or request the HAL to reuse a buffer handle
// that we've already sent by using the slot assignment. The latter is cheaper
// since it eliminates the overhead to transfer the buffer handle over IPC and
// the overhead for the HAL to clone the handle.
//
class HwcBufferCache {
private:
static const constexpr size_t kMaxLayerBufferCount = BufferQueue::NUM_BUFFER_SLOTS;
public:
// public for testing
// Override buffers don't use the normal cache slots because we don't want them to evict client
// buffers from the cache. We add an extra slot at the end for the override buffers.
static const constexpr size_t kOverrideBufferSlot = kMaxLayerBufferCount;
HwcBufferCache();
//
// Given a buffer, return the HWC cache slot and buffer to send to HWC.
//
// If the buffer is already in the cache, the buffer is null to optimize away sending HWC the
// buffer handle.
//
HwcSlotAndBuffer getHwcSlotAndBuffer(const sp<GraphicBuffer>& buffer);
//
// Given a buffer, return the HWC cache slot and buffer to send to HWC.
//
// A special slot number is used for override buffers.
//
// If the buffer is already in the cache, the buffer is null to optimize away sending HWC the
// buffer handle.
//
HwcSlotAndBuffer getOverrideHwcSlotAndBuffer(const sp<GraphicBuffer>& buffer);
//
// When a client process discards a buffer, it needs to be purged from the HWC cache.
//
// Returns the slot number of the buffer, or UINT32_MAX if it wasn't found in the cache.
//
uint32_t uncache(uint64_t graphicBufferId);
private:
uint32_t cache(const sp<GraphicBuffer>& buffer);
uint32_t getLeastRecentlyUsedSlot();
struct Cache {
sp<GraphicBuffer> buffer;
uint32_t slot;
// Cache entries are evicted according to least-recently-used when more than
// kMaxLayerBufferCount unique buffers have been sent to a layer.
uint64_t lruCounter;
};
std::unordered_map<uint64_t, Cache> mCacheByBufferId;
sp<GraphicBuffer> mLastOverrideBuffer;
std::stack<uint32_t> mFreeSlots;
uint64_t mLeastRecentlyUsedCounter;
};
} // namespace compositionengine::impl
} // namespace android