/* * Copyright 2018 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 #ifndef LOG_TAG #warning "ComposerClient.h included without LOG_TAG" #endif #include #include #include #include #include #include #include #include namespace android { namespace hardware { namespace graphics { namespace composer { namespace V2_1 { namespace hal { namespace detail { // ComposerClientImpl implements V2_*::IComposerClient on top of V2_*::ComposerHal template class ComposerClientImpl : public Interface { public: static std::unique_ptr create(Hal* hal) { auto client = std::make_unique(hal); return client->init() ? std::move(client) : nullptr; } ComposerClientImpl(Hal* hal) : mHal(hal) {} virtual ~ComposerClientImpl() { // not initialized if (!mCommandEngine) { return; } ALOGD("destroying composer client"); mHal->unregisterEventCallback(); destroyResources(); if (mOnClientDestroyed) { mOnClientDestroyed(); } ALOGD("removed composer client"); } bool init() { mResources = createResources(); if (!mResources) { ALOGE("failed to create composer resources"); return false; } mCommandEngine = createCommandEngine(); return true; } void setOnClientDestroyed(std::function onClientDestroyed) { mOnClientDestroyed = onClientDestroyed; } // IComposerClient 2.1 interface class HalEventCallback : public Hal::EventCallback { public: HalEventCallback(const sp callback, ComposerResources* resources) : mCallback(callback), mResources(resources) {} void onHotplug(Display display, IComposerCallback::Connection connected) { if (connected == IComposerCallback::Connection::CONNECTED) { mResources->addPhysicalDisplay(display); } else if (connected == IComposerCallback::Connection::DISCONNECTED) { mResources->removeDisplay(display); } auto ret = mCallback->onHotplug(display, connected); ALOGE_IF(!ret.isOk(), "failed to send onHotplug: %s", ret.description().c_str()); } void onRefresh(Display display) { mResources->setDisplayMustValidateState(display, true); auto ret = mCallback->onRefresh(display); ALOGE_IF(!ret.isOk(), "failed to send onRefresh: %s", ret.description().c_str()); } void onVsync(Display display, int64_t timestamp) { auto ret = mCallback->onVsync(display, timestamp); ALOGE_IF(!ret.isOk(), "failed to send onVsync: %s", ret.description().c_str()); } protected: const sp mCallback; ComposerResources* const mResources; }; Return registerCallback(const sp& callback) override { // no locking as we require this function to be called only once mHalEventCallback = std::make_unique(callback, mResources.get()); mHal->registerEventCallback(mHalEventCallback.get()); return Void(); } Return getMaxVirtualDisplayCount() override { return mHal->getMaxVirtualDisplayCount(); } Return createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat formatHint, uint32_t outputBufferSlotCount, IComposerClient::createVirtualDisplay_cb hidl_cb) override { Display display = 0; Error err = mHal->createVirtualDisplay(width, height, &formatHint, &display); if (err == Error::NONE) { mResources->addVirtualDisplay(display, outputBufferSlotCount); } hidl_cb(err, display, formatHint); return Void(); } Return destroyVirtualDisplay(Display display) override { Error err = mHal->destroyVirtualDisplay(display); if (err == Error::NONE) { mResources->removeDisplay(display); } return err; } Return createLayer(Display display, uint32_t bufferSlotCount, IComposerClient::createLayer_cb hidl_cb) override { Layer layer = 0; Error err = mHal->createLayer(display, &layer); if (err == Error::NONE) { err = mResources->addLayer(display, layer, bufferSlotCount); if (err != Error::NONE) { // The display entry may have already been removed by onHotplug. // Note: We do not destroy the layer on this error as the hotplug // disconnect invalidates the display id. The implementation should // ensure all layers for the display are destroyed. layer = 0; } } hidl_cb(err, layer); return Void(); } Return destroyLayer(Display display, Layer layer) override { Error err = mHal->destroyLayer(display, layer); if (err == Error::NONE) { mResources->removeLayer(display, layer); } return err; } Return getActiveConfig(Display display, IComposerClient::getActiveConfig_cb hidl_cb) override { Config config = 0; Error err = mHal->getActiveConfig(display, &config); hidl_cb(err, config); return Void(); } Return getClientTargetSupport(Display display, uint32_t width, uint32_t height, PixelFormat format, Dataspace dataspace) override { Error err = mHal->getClientTargetSupport(display, width, height, format, dataspace); return err; } Return getColorModes(Display display, IComposerClient::getColorModes_cb hidl_cb) override { hidl_vec modes; Error err = mHal->getColorModes(display, &modes); hidl_cb(err, modes); return Void(); } Return getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute, IComposerClient::getDisplayAttribute_cb hidl_cb) override { int32_t value = 0; Error err = mHal->getDisplayAttribute(display, config, attribute, &value); hidl_cb(err, value); return Void(); } Return getDisplayConfigs(Display display, IComposerClient::getDisplayConfigs_cb hidl_cb) override { hidl_vec configs; Error err = mHal->getDisplayConfigs(display, &configs); hidl_cb(err, configs); return Void(); } Return getDisplayName(Display display, IComposerClient::getDisplayName_cb hidl_cb) override { hidl_string name; Error err = mHal->getDisplayName(display, &name); hidl_cb(err, name); return Void(); } Return getDisplayType(Display display, IComposerClient::getDisplayType_cb hidl_cb) override { IComposerClient::DisplayType type = IComposerClient::DisplayType::INVALID; Error err = mHal->getDisplayType(display, &type); hidl_cb(err, type); return Void(); } Return getDozeSupport(Display display, IComposerClient::getDozeSupport_cb hidl_cb) override { bool support = false; Error err = mHal->getDozeSupport(display, &support); hidl_cb(err, support); return Void(); } Return getHdrCapabilities(Display display, IComposerClient::getHdrCapabilities_cb hidl_cb) override { hidl_vec types; float max_lumi = 0.0f; float max_avg_lumi = 0.0f; float min_lumi = 0.0f; Error err = mHal->getHdrCapabilities(display, &types, &max_lumi, &max_avg_lumi, &min_lumi); hidl_cb(err, types, max_lumi, max_avg_lumi, min_lumi); return Void(); } Return setActiveConfig(Display display, Config config) override { Error err = mHal->setActiveConfig(display, config); return err; } Return setColorMode(Display display, ColorMode mode) override { Error err = mHal->setColorMode(display, mode); return err; } Return setPowerMode(Display display, IComposerClient::PowerMode mode) override { Error err = mHal->setPowerMode(display, mode); return err; } Return setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override { Error err = mHal->setVsyncEnabled(display, enabled); return err; } Return setClientTargetSlotCount(Display display, uint32_t clientTargetSlotCount) override { return mResources->setDisplayClientTargetCacheSize(display, clientTargetSlotCount); } Return setInputCommandQueue(const MQDescriptorSync& descriptor) override { std::lock_guard lock(mCommandEngineMutex); return mCommandEngine->setInputMQDescriptor(descriptor) ? Error::NONE : Error::NO_RESOURCES; } Return getOutputCommandQueue(IComposerClient::getOutputCommandQueue_cb hidl_cb) override { // no locking as we require this function to be called inside // executeCommands_cb auto outDescriptor = mCommandEngine->getOutputMQDescriptor(); if (outDescriptor) { hidl_cb(Error::NONE, *outDescriptor); } else { hidl_cb(Error::NO_RESOURCES, CommandQueueType::Descriptor()); } return Void(); } Return executeCommands(uint32_t inLength, const hidl_vec& inHandles, IComposerClient::executeCommands_cb hidl_cb) override { std::lock_guard lock(mCommandEngineMutex); bool outChanged = false; uint32_t outLength = 0; hidl_vec outHandles; Error error = mCommandEngine->execute(inLength, inHandles, &outChanged, &outLength, &outHandles); hidl_cb(error, outChanged, outLength, outHandles); mCommandEngine->reset(); return Void(); } protected: virtual std::unique_ptr createResources() { return ComposerResources::create(); } virtual std::unique_ptr createCommandEngine() { return std::make_unique(mHal, mResources.get()); } void destroyResources() { // We want to call hwc2_close here (and move hwc2_open to the // constructor), with the assumption that hwc2_close would // // - clean up all resources owned by the client // - make sure all displays are blank (since there is no layer) // // But since SF used to crash at this point, different hwcomposer2 // implementations behave differently on hwc2_close. Our only portable // choice really is to abort(). But that is not an option anymore // because we might also have VTS or VR as clients that can come and go. // // Below we manually clean all resources (layers and virtual // displays), and perform a presentDisplay afterwards. mResources->clear([this](Display display, bool isVirtual, const std::vector layers) { ALOGW("destroying client resources for display %" PRIu64, display); for (auto layer : layers) { mHal->destroyLayer(display, layer); } if (isVirtual) { mHal->destroyVirtualDisplay(display); } else { ALOGW("performing a final presentDisplay"); std::vector changedLayers; std::vector compositionTypes; uint32_t displayRequestMask = 0; std::vector requestedLayers; std::vector requestMasks; mHal->validateDisplay(display, &changedLayers, &compositionTypes, &displayRequestMask, &requestedLayers, &requestMasks); mHal->acceptDisplayChanges(display); int32_t presentFence = -1; std::vector releasedLayers; std::vector releaseFences; mHal->presentDisplay(display, &presentFence, &releasedLayers, &releaseFences); if (presentFence >= 0) { close(presentFence); } for (auto fence : releaseFences) { if (fence >= 0) { close(fence); } } } }); mResources.reset(); } Hal* const mHal; std::unique_ptr mResources; std::mutex mCommandEngineMutex; std::unique_ptr mCommandEngine; std::function mOnClientDestroyed; std::unique_ptr mHalEventCallback; }; } // namespace detail using ComposerClient = detail::ComposerClientImpl; } // namespace hal } // namespace V2_1 } // namespace composer } // namespace graphics } // namespace hardware } // namespace android