/* * Copyright 2019 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. */ #define LOG_TAG "ComposerResources" #include "composer-resources/2.1/ComposerResources.h" namespace android { namespace hardware { namespace graphics { namespace composer { namespace V2_1 { namespace hal { bool ComposerHandleImporter::init() { mMapper4 = mapper::V4_0::IMapper::getService(); if (mMapper4) { return true; } ALOGI_IF(!mMapper4, "failed to get mapper 4.0 service, falling back to mapper 3.0"); mMapper3 = mapper::V3_0::IMapper::getService(); if (mMapper3) { return true; } ALOGI_IF(!mMapper3, "failed to get mapper 3.0 service, falling back to mapper 2.0"); mMapper2 = mapper::V2_0::IMapper::getService(); ALOGE_IF(!mMapper2, "failed to get mapper 2.0 service"); return mMapper2 != nullptr; } Error ComposerHandleImporter::importBuffer(const native_handle_t* rawHandle, const native_handle_t** outBufferHandle) { if (!rawHandle || (!rawHandle->numFds && !rawHandle->numInts)) { *outBufferHandle = nullptr; return Error::NONE; } const native_handle_t* bufferHandle; if (mMapper2) { mapper::V2_0::Error error; mMapper2->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) { error = tmpError; bufferHandle = static_cast(tmpBufferHandle); }); if (error != mapper::V2_0::Error::NONE) { return Error::NO_RESOURCES; } } if (mMapper3) { mapper::V3_0::Error error; mMapper3->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) { error = tmpError; bufferHandle = static_cast(tmpBufferHandle); }); if (error != mapper::V3_0::Error::NONE) { return Error::NO_RESOURCES; } } if (mMapper4) { mapper::V4_0::Error error; mMapper4->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBufferHandle) { error = tmpError; bufferHandle = static_cast(tmpBufferHandle); }); if (error != mapper::V4_0::Error::NONE) { return Error::NO_RESOURCES; } } *outBufferHandle = bufferHandle; return Error::NONE; } void ComposerHandleImporter::freeBuffer(const native_handle_t* bufferHandle) { if (bufferHandle) { if (mMapper2) { mMapper2->freeBuffer(static_cast(const_cast(bufferHandle))); } else if (mMapper3) { mMapper3->freeBuffer(static_cast(const_cast(bufferHandle))); } else if (mMapper4) { mMapper4->freeBuffer(static_cast(const_cast(bufferHandle))); } } } Error ComposerHandleImporter::importStream(const native_handle_t* rawHandle, const native_handle_t** outStreamHandle) { const native_handle_t* streamHandle = nullptr; if (rawHandle) { streamHandle = native_handle_clone(rawHandle); if (!streamHandle) { return Error::NO_RESOURCES; } } *outStreamHandle = streamHandle; return Error::NONE; } void ComposerHandleImporter::freeStream(const native_handle_t* streamHandle) { if (streamHandle) { native_handle_close(streamHandle); native_handle_delete(const_cast(streamHandle)); } } ComposerHandleCache::ComposerHandleCache(ComposerHandleImporter& importer, HandleType type, uint32_t cacheSize) : mImporter(importer), mHandleType(type), mHandles(cacheSize, nullptr) {} // must be initialized later with initCache ComposerHandleCache::ComposerHandleCache(ComposerHandleImporter& importer) : mImporter(importer) {} ComposerHandleCache::~ComposerHandleCache() { switch (mHandleType) { case HandleType::BUFFER: for (auto handle : mHandles) { mImporter.freeBuffer(handle); } break; case HandleType::STREAM: for (auto handle : mHandles) { mImporter.freeStream(handle); } break; default: break; } } size_t ComposerHandleCache::getCacheSize() const { return mHandles.size(); } bool ComposerHandleCache::initCache(HandleType type, uint32_t cacheSize) { // already initialized if (mHandleType != HandleType::INVALID) { return false; } mHandleType = type; mHandles.resize(cacheSize, nullptr); return true; } Error ComposerHandleCache::lookupCache(uint32_t slot, const native_handle_t** outHandle) { if (slot >= 0 && slot < mHandles.size()) { *outHandle = mHandles[slot]; return Error::NONE; } else { return Error::BAD_PARAMETER; } } Error ComposerHandleCache::updateCache(uint32_t slot, const native_handle_t* handle, const native_handle** outReplacedHandle) { if (slot >= 0 && slot < mHandles.size()) { auto& cachedHandle = mHandles[slot]; *outReplacedHandle = cachedHandle; cachedHandle = handle; return Error::NONE; } else { return Error::BAD_PARAMETER; } } // when fromCache is true, look up in the cache; otherwise, update the cache Error ComposerHandleCache::getHandle(uint32_t slot, bool fromCache, const native_handle_t* inHandle, const native_handle_t** outHandle, const native_handle** outReplacedHandle) { if (fromCache) { *outReplacedHandle = nullptr; return lookupCache(slot, outHandle); } else { *outHandle = inHandle; return updateCache(slot, inHandle, outReplacedHandle); } } ComposerLayerResource::ComposerLayerResource(ComposerHandleImporter& importer, uint32_t bufferCacheSize) : mBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, bufferCacheSize), mSidebandStreamCache(importer, ComposerHandleCache::HandleType::STREAM, 1) {} Error ComposerLayerResource::getBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle, const native_handle_t** outHandle, const native_handle** outReplacedHandle) { return mBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle); } Error ComposerLayerResource::getSidebandStream(uint32_t slot, bool fromCache, const native_handle_t* inHandle, const native_handle_t** outHandle, const native_handle** outReplacedHandle) { return mSidebandStreamCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle); } ComposerDisplayResource::ComposerDisplayResource(DisplayType type, ComposerHandleImporter& importer, uint32_t outputBufferCacheSize) : mType(type), mClientTargetCache(importer), mOutputBufferCache(importer, ComposerHandleCache::HandleType::BUFFER, outputBufferCacheSize), mMustValidate(true) {} bool ComposerDisplayResource::initClientTargetCache(uint32_t cacheSize) { return mClientTargetCache.initCache(ComposerHandleCache::HandleType::BUFFER, cacheSize); } size_t ComposerDisplayResource::getClientTargetCacheSize() const { return mClientTargetCache.getCacheSize(); } size_t ComposerDisplayResource::getOutputBufferCacheSize() const { return mOutputBufferCache.getCacheSize(); } bool ComposerDisplayResource::isVirtual() const { return mType == DisplayType::VIRTUAL; } Error ComposerDisplayResource::getClientTarget(uint32_t slot, bool fromCache, const native_handle_t* inHandle, const native_handle_t** outHandle, const native_handle** outReplacedHandle) { return mClientTargetCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle); } Error ComposerDisplayResource::getOutputBuffer(uint32_t slot, bool fromCache, const native_handle_t* inHandle, const native_handle_t** outHandle, const native_handle** outReplacedHandle) { return mOutputBufferCache.getHandle(slot, fromCache, inHandle, outHandle, outReplacedHandle); } bool ComposerDisplayResource::addLayer(Layer layer, std::unique_ptr layerResource) { auto result = mLayerResources.emplace(layer, std::move(layerResource)); return result.second; } bool ComposerDisplayResource::removeLayer(Layer layer) { return mLayerResources.erase(layer) > 0; } ComposerLayerResource* ComposerDisplayResource::findLayerResource(Layer layer) { auto layerIter = mLayerResources.find(layer); if (layerIter == mLayerResources.end()) { return nullptr; } return layerIter->second.get(); } std::vector ComposerDisplayResource::getLayers() const { std::vector layers; layers.reserve(mLayerResources.size()); for (const auto& layerKey : mLayerResources) { layers.push_back(layerKey.first); } return layers; } void ComposerDisplayResource::setMustValidateState(bool mustValidate) { mMustValidate = mustValidate; } bool ComposerDisplayResource::mustValidate() const { return mMustValidate; } std::unique_ptr ComposerResources::create() { auto resources = std::make_unique(); return resources->init() ? std::move(resources) : nullptr; } bool ComposerResources::init() { return mImporter.init(); } void ComposerResources::clear(RemoveDisplay removeDisplay) { std::lock_guard lock(mDisplayResourcesMutex); for (const auto& displayKey : mDisplayResources) { Display display = displayKey.first; const ComposerDisplayResource& displayResource = *displayKey.second; removeDisplay(display, displayResource.isVirtual(), displayResource.getLayers()); } mDisplayResources.clear(); } bool ComposerResources::hasDisplay(Display display) { return mDisplayResources.count(display) > 0; } Error ComposerResources::addPhysicalDisplay(Display display) { auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::PHYSICAL, 0); std::lock_guard lock(mDisplayResourcesMutex); auto result = mDisplayResources.emplace(display, std::move(displayResource)); return result.second ? Error::NONE : Error::BAD_DISPLAY; } Error ComposerResources::addVirtualDisplay(Display display, uint32_t outputBufferCacheSize) { auto displayResource = createDisplayResource(ComposerDisplayResource::DisplayType::VIRTUAL, outputBufferCacheSize); std::lock_guard lock(mDisplayResourcesMutex); auto result = mDisplayResources.emplace(display, std::move(displayResource)); return result.second ? Error::NONE : Error::BAD_DISPLAY; } Error ComposerResources::removeDisplay(Display display) { std::lock_guard lock(mDisplayResourcesMutex); return mDisplayResources.erase(display) > 0 ? Error::NONE : Error::BAD_DISPLAY; } Error ComposerResources::setDisplayClientTargetCacheSize(Display display, uint32_t clientTargetCacheSize) { std::lock_guard lock(mDisplayResourcesMutex); ComposerDisplayResource* displayResource = findDisplayResourceLocked(display); if (!displayResource) { return Error::BAD_DISPLAY; } return displayResource->initClientTargetCache(clientTargetCacheSize) ? Error::NONE : Error::BAD_PARAMETER; } Error ComposerResources::getDisplayClientTargetCacheSize(Display display, size_t* outCacheSize) { std::lock_guard lock(mDisplayResourcesMutex); ComposerDisplayResource* displayResource = findDisplayResourceLocked(display); if (!displayResource) { return Error::BAD_DISPLAY; } *outCacheSize = displayResource->getClientTargetCacheSize(); return Error::NONE; } Error ComposerResources::getDisplayOutputBufferCacheSize(Display display, size_t* outCacheSize) { std::lock_guard lock(mDisplayResourcesMutex); ComposerDisplayResource* displayResource = findDisplayResourceLocked(display); if (!displayResource) { return Error::BAD_DISPLAY; } *outCacheSize = displayResource->getOutputBufferCacheSize(); return Error::NONE; } Error ComposerResources::addLayer(Display display, Layer layer, uint32_t bufferCacheSize) { auto layerResource = createLayerResource(bufferCacheSize); std::lock_guard lock(mDisplayResourcesMutex); ComposerDisplayResource* displayResource = findDisplayResourceLocked(display); if (!displayResource) { return Error::BAD_DISPLAY; } return displayResource->addLayer(layer, std::move(layerResource)) ? Error::NONE : Error::BAD_LAYER; } Error ComposerResources::removeLayer(Display display, Layer layer) { std::lock_guard lock(mDisplayResourcesMutex); ComposerDisplayResource* displayResource = findDisplayResourceLocked(display); if (!displayResource) { return Error::BAD_DISPLAY; } return displayResource->removeLayer(layer) ? Error::NONE : Error::BAD_LAYER; } Error ComposerResources::getDisplayClientTarget(Display display, uint32_t slot, bool fromCache, const native_handle_t* rawHandle, const native_handle_t** outBufferHandle, ReplacedHandle* outReplacedBuffer) { return getHandle(display, 0, slot, Cache::CLIENT_TARGET, fromCache, rawHandle, outBufferHandle, outReplacedBuffer); } Error ComposerResources::getDisplayOutputBuffer(Display display, uint32_t slot, bool fromCache, const native_handle_t* rawHandle, const native_handle_t** outBufferHandle, ReplacedHandle* outReplacedBuffer) { return getHandle(display, 0, slot, Cache::OUTPUT_BUFFER, fromCache, rawHandle, outBufferHandle, outReplacedBuffer); } Error ComposerResources::getLayerBuffer(Display display, Layer layer, uint32_t slot, bool fromCache, const native_handle_t* rawHandle, const native_handle_t** outBufferHandle, ReplacedHandle* outReplacedBuffer) { return getHandle(display, layer, slot, Cache::LAYER_BUFFER, fromCache, rawHandle, outBufferHandle, outReplacedBuffer); } Error ComposerResources::getLayerSidebandStream(Display display, Layer layer, const native_handle_t* rawHandle, const native_handle_t** outStreamHandle, ReplacedHandle* outReplacedStream) { return getHandle(display, layer, 0, Cache::LAYER_SIDEBAND_STREAM, false, rawHandle, outStreamHandle, outReplacedStream); } void ComposerResources::setDisplayMustValidateState(Display display, bool mustValidate) { std::lock_guard lock(mDisplayResourcesMutex); auto* displayResource = findDisplayResourceLocked(display); if (displayResource) { displayResource->setMustValidateState(mustValidate); } } bool ComposerResources::mustValidateDisplay(Display display) { std::lock_guard lock(mDisplayResourcesMutex); auto* displayResource = findDisplayResourceLocked(display); if (displayResource) { return displayResource->mustValidate(); } return false; } std::unique_ptr ComposerResources::createDisplayResource( ComposerDisplayResource::DisplayType type, uint32_t outputBufferCacheSize) { return std::make_unique(type, mImporter, outputBufferCacheSize); } std::unique_ptr ComposerResources::createLayerResource( uint32_t bufferCacheSize) { return std::make_unique(mImporter, bufferCacheSize); } ComposerDisplayResource* ComposerResources::findDisplayResourceLocked(Display display) { auto iter = mDisplayResources.find(display); if (iter == mDisplayResources.end()) { return nullptr; } return iter->second.get(); } Error ComposerResources::getHandle(Display display, Layer layer, uint32_t slot, Cache cache, bool fromCache, const native_handle_t* rawHandle, const native_handle_t** outHandle, ReplacedHandle* outReplacedHandle) { Error error; // import the raw handle (or ignore raw handle when fromCache is true) const native_handle_t* importedHandle = nullptr; if (!fromCache) { error = (outReplacedHandle->isBuffer()) ? mImporter.importBuffer(rawHandle, &importedHandle) : mImporter.importStream(rawHandle, &importedHandle); if (error != Error::NONE) { return error; } } std::lock_guard lock(mDisplayResourcesMutex); // find display/layer resource const bool needLayerResource = (cache == ComposerResources::Cache::LAYER_BUFFER || cache == ComposerResources::Cache::LAYER_SIDEBAND_STREAM); ComposerDisplayResource* displayResource = findDisplayResourceLocked(display); ComposerLayerResource* layerResource = (displayResource && needLayerResource) ? displayResource->findLayerResource(layer) : nullptr; // lookup or update cache const native_handle_t* replacedHandle = nullptr; if (displayResource && (!needLayerResource || layerResource)) { switch (cache) { case ComposerResources::Cache::CLIENT_TARGET: error = displayResource->getClientTarget(slot, fromCache, importedHandle, outHandle, &replacedHandle); break; case ComposerResources::Cache::OUTPUT_BUFFER: error = displayResource->getOutputBuffer(slot, fromCache, importedHandle, outHandle, &replacedHandle); break; case ComposerResources::Cache::LAYER_BUFFER: error = layerResource->getBuffer(slot, fromCache, importedHandle, outHandle, &replacedHandle); break; case ComposerResources::Cache::LAYER_SIDEBAND_STREAM: error = layerResource->getSidebandStream(slot, fromCache, importedHandle, outHandle, &replacedHandle); break; default: error = Error::BAD_PARAMETER; break; } if (error != Error::NONE) { ALOGW("invalid cache %d slot %d", int(cache), int(slot)); } } else if (!displayResource) { error = Error::BAD_DISPLAY; } else { error = Error::BAD_LAYER; } // clean up on errors if (error != Error::NONE) { if (!fromCache) { if (outReplacedHandle->isBuffer()) { mImporter.freeBuffer(importedHandle); } else { mImporter.freeStream(importedHandle); } } return error; } outReplacedHandle->reset(&mImporter, replacedHandle); return Error::NONE; } } // namespace hal } // namespace V2_1 } // namespace composer } // namespace graphics } // namespace hardware } // namespace android