/* * Copyright 2021 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. */ #include "Device.h" #include #include "ClientComposer.h" #include "DisplayFinder.h" #include "GuestComposer.h" #include "HostComposer.h" #include "NoOpComposer.h" namespace android { namespace { static bool isMinigbmFromProperty() { static constexpr const auto kGrallocProp = "ro.hardware.gralloc"; const auto grallocProp = android::base::GetProperty(kGrallocProp, ""); DEBUG_LOG("%s: prop value is: %s", __FUNCTION__, grallocProp.c_str()); if (grallocProp == "minigbm") { ALOGD("%s: Using minigbm, in minigbm mode.\n", __FUNCTION__); return true; } else { ALOGD("%s: Is not using minigbm, in goldfish mode.\n", __FUNCTION__); return false; } } template static hwc2_function_pointer_t asFP(T function) { static_assert(std::is_same::value, "Incompatible function pointer"); return reinterpret_cast(function); } static int CloseHook(hw_device_t* dev) { Device* device = Device::fromDevice(dev); delete device; return 0; } bool ShouldUseGuestComposer() { return android::base::GetProperty("ro.hardware.vulkan", "") == "pastel"; } } // namespace Device::Device() { DEBUG_LOG("%s", __FUNCTION__); common.tag = HARDWARE_DEVICE_TAG; common.version = HWC_DEVICE_API_VERSION_2_0; common.close = CloseHook; hwc2_device_t::getCapabilities = getCapabilitiesHook; hwc2_device_t::getFunction = getFunctionHook; mDrmPresenter = std::make_unique(); } HWC2::Error Device::init() { DEBUG_LOG("%s", __FUNCTION__); bool isMinigbm = isMinigbmFromProperty(); if (IsNoOpMode()) { DEBUG_LOG("%s: using NoOpComposer", __FUNCTION__); mComposer = std::make_unique(); } else if (IsClientCompositionMode()) { DEBUG_LOG("%s: using ClientComposer", __FUNCTION__); mComposer = std::make_unique(mDrmPresenter.get()); } else if (ShouldUseGuestComposer()) { DEBUG_LOG("%s: using GuestComposer", __FUNCTION__); mComposer = std::make_unique(mDrmPresenter.get()); } else { DEBUG_LOG("%s: using HostComposer", __FUNCTION__); mComposer = std::make_unique(mDrmPresenter.get(), isMinigbm); } if (!IsNoOpMode() && (ShouldUseGuestComposer() || isMinigbm)) { bool success = mDrmPresenter->init( [this](bool connected, uint32_t id, uint32_t width, uint32_t height, uint32_t dpiX, uint32_t dpiY, uint32_t refreshRate) { handleHotplug(connected, id, width, height, dpiX, dpiY, refreshRate); }); if (!success) { ALOGE("%s: failed to initialize DrmPresenter", __FUNCTION__); return HWC2::Error::NoResources; } } HWC2::Error error = mComposer->init(); if (error != HWC2::Error::None) { ALOGE("%s failed to initialize Composer", __FUNCTION__); return HWC2::Error::NoResources; } return HWC2::Error::None; } Device::~Device() { DEBUG_LOG("%s", __FUNCTION__); HWC2::Error error = HWC2::Error::None; error = destroyDisplays(); if (error != HWC2::Error::None) { ALOGE("%s failed to destroy displays", __FUNCTION__); } } HWC2::Error Device::createDisplays() { DEBUG_LOG("%s", __FUNCTION__); std::unique_lock lock(mStateMutex); if (!mComposer) { ALOGE("%s composer not initialized!", __FUNCTION__); return HWC2::Error::NoResources; } std::vector displays; HWC2::Error error = findDisplays(mDrmPresenter.get(), displays); if (error != HWC2::Error::None) { ALOGE("%s failed to find display configs", __FUNCTION__); return error; } for (const auto& iter : displays) { error = createDisplay(iter.displayId, iter.activeConfigId, iter.configs); if (error != HWC2::Error::None) { ALOGE("%s failed to create display from config", __FUNCTION__); return error; } } return HWC2::Error::None; } HWC2::Error Device::createDisplay(hwc2_display_t displayId, hwc2_config_t activeConfigId, const std::vector& configs) { DEBUG_LOG("%s", __FUNCTION__); if (!mComposer) { ALOGE("%s composer not initialized!", __FUNCTION__); return HWC2::Error::NoResources; } auto display = std::make_unique(mComposer.get(), displayId); if (display == nullptr) { ALOGE("%s failed to allocate display", __FUNCTION__); return HWC2::Error::NoResources; } HWC2::Error error = display->init(configs, activeConfigId); if (error != HWC2::Error::None) { ALOGE("%s failed to initialize display:%" PRIu64, __FUNCTION__, displayId); return error; } error = mComposer->onDisplayCreate(display.get()); if (error != HWC2::Error::None) { ALOGE("%s failed to register display:%" PRIu64 " with composer", __FUNCTION__, displayId); return error; } DEBUG_LOG("%s: adding display:%" PRIu64, __FUNCTION__, displayId); mDisplays.emplace(displayId, std::move(display)); return HWC2::Error::None; } HWC2::Error Device::destroyDisplays() { DEBUG_LOG("%s", __FUNCTION__); std::unique_lock lock(mStateMutex); if (!mComposer) { ALOGE("%s composer not initialized!", __FUNCTION__); return HWC2::Error::NoResources; } for (auto& [displayId, displayPtr] : mDisplays) { HWC2::Error error = mComposer->onDisplayDestroy(displayPtr.get()); if (error != HWC2::Error::None) { ALOGE("%s composer failed to destroy displays", __FUNCTION__); return error; } displayPtr.reset(); } mDisplays.clear(); return HWC2::Error::None; } void Device::getCapabilities(uint32_t* outCount, int32_t* outCapabilities) { DEBUG_LOG("%s", __FUNCTION__); if (outCapabilities == nullptr) { *outCount = mCapabilities.size(); return; } auto capabilityIter = mCapabilities.cbegin(); for (size_t i = 0; i < *outCount; ++i) { if (capabilityIter == mCapabilities.cend()) { return; } outCapabilities[i] = static_cast(*capabilityIter); ++capabilityIter; } } /*static*/ void Device::getCapabilitiesHook(hwc2_device_t* dev, uint32_t* outCount, int32_t* outCapabilities) { DEBUG_LOG("%s", __FUNCTION__); Device* device = Device::fromDevice(dev); device->getCapabilities(outCount, outCapabilities); } hwc2_function_pointer_t Device::getFunction(int32_t desc) { const auto func = static_cast(desc); const auto funcString = to_string(func); DEBUG_LOG("%s(%s)", __FUNCTION__, funcString.c_str()); switch (func) { // Device functions. case HWC2::FunctionDescriptor::CreateVirtualDisplay: return asFP( DeviceHook); case HWC2::FunctionDescriptor::DestroyVirtualDisplay: return asFP( DeviceHook); case HWC2::FunctionDescriptor::Dump: return asFP(DeviceHook); case HWC2::FunctionDescriptor::GetMaxVirtualDisplayCount: return asFP( DeviceHook); case HWC2::FunctionDescriptor::RegisterCallback: return asFP( DeviceHook); // Display functions case HWC2::FunctionDescriptor::AcceptDisplayChanges: return asFP( displayHook); case HWC2::FunctionDescriptor::CreateLayer: return asFP( displayHook); case HWC2::FunctionDescriptor::DestroyLayer: return asFP( displayHook); case HWC2::FunctionDescriptor::GetActiveConfig: return asFP( displayHook); case HWC2::FunctionDescriptor::GetChangedCompositionTypes: return asFP( displayHook); case HWC2::FunctionDescriptor::GetColorModes: return asFP( displayHook); case HWC2::FunctionDescriptor::GetDisplayAttribute: return asFP( displayHook); case HWC2::FunctionDescriptor::GetDisplayConfigs: return asFP( displayHook); case HWC2::FunctionDescriptor::GetDisplayName: return asFP( displayHook); case HWC2::FunctionDescriptor::GetDisplayRequests: return asFP( displayHook); case HWC2::FunctionDescriptor::GetDisplayType: return asFP( displayHook); case HWC2::FunctionDescriptor::GetDozeSupport: return asFP( displayHook); case HWC2::FunctionDescriptor::GetHdrCapabilities: return asFP( displayHook); case HWC2::FunctionDescriptor::GetReleaseFences: return asFP( displayHook); case HWC2::FunctionDescriptor::PresentDisplay: return asFP( displayHook); case HWC2::FunctionDescriptor::SetActiveConfig: return asFP( displayHook); case HWC2::FunctionDescriptor::SetClientTarget: return asFP( displayHook); case HWC2::FunctionDescriptor::SetColorMode: return asFP( displayHook); case HWC2::FunctionDescriptor::SetColorTransform: return asFP( displayHook); case HWC2::FunctionDescriptor::SetOutputBuffer: return asFP( displayHook); case HWC2::FunctionDescriptor::SetPowerMode: return asFP( displayHook); case HWC2::FunctionDescriptor::SetVsyncEnabled: return asFP( displayHook); case HWC2::FunctionDescriptor::ValidateDisplay: return asFP( displayHook); case HWC2::FunctionDescriptor::GetClientTargetSupport: return asFP( displayHook); case HWC2::FunctionDescriptor::GetDisplayIdentificationData: return asFP( displayHook); case HWC2::FunctionDescriptor::GetDisplayCapabilities: return asFP( displayHook); case HWC2::FunctionDescriptor::GetDisplayBrightnessSupport: return asFP( displayHook); case HWC2::FunctionDescriptor::SetDisplayBrightness: return asFP( displayHook); case HWC2::FunctionDescriptor::GetDisplayVsyncPeriod: return asFP( displayHook); case HWC2::FunctionDescriptor::SetActiveConfigWithConstraints: return asFP( displayHook); case HWC2::FunctionDescriptor::GetDisplayConnectionType: return asFP( displayHook); case HWC2::FunctionDescriptor::SetAutoLowLatencyMode: return asFP( displayHook); case HWC2::FunctionDescriptor::GetSupportedContentTypes: return asFP( displayHook); case HWC2::FunctionDescriptor::SetContentType: return asFP( displayHook); // Layer functions case HWC2::FunctionDescriptor::SetCursorPosition: return asFP( layerHook); case HWC2::FunctionDescriptor::SetLayerBuffer: return asFP( layerHook); case HWC2::FunctionDescriptor::SetLayerSurfaceDamage: return asFP( layerHook); case HWC2::FunctionDescriptor::SetLayerBlendMode: return asFP( layerHook); case HWC2::FunctionDescriptor::SetLayerColor: return asFP( layerHook); case HWC2::FunctionDescriptor::SetLayerCompositionType: return asFP( layerHook); case HWC2::FunctionDescriptor::SetLayerDataspace: return asFP( layerHook); case HWC2::FunctionDescriptor::SetLayerDisplayFrame: return asFP( layerHook); case HWC2::FunctionDescriptor::SetLayerPlaneAlpha: return asFP( layerHook); case HWC2::FunctionDescriptor::SetLayerSidebandStream: return asFP( layerHook); case HWC2::FunctionDescriptor::SetLayerSourceCrop: return asFP( layerHook); case HWC2::FunctionDescriptor::SetLayerTransform: return asFP( layerHook); case HWC2::FunctionDescriptor::SetLayerVisibleRegion: return asFP( layerHook); case HWC2::FunctionDescriptor::SetLayerZOrder: return asFP( displayHook); default: ALOGE("GetFunction: Unknown function descriptor: %d", static_cast(desc)); return nullptr; } } /*static*/ hwc2_function_pointer_t Device::getFunctionHook(hwc2_device_t* dev, int32_t desc) { Device* device = Device::fromDevice(dev); return device->getFunction(desc); } // Device functions HWC2::Error Device::createVirtualDisplay(uint32_t /*width*/, uint32_t /*height*/, int32_t* /*format*/, hwc2_display_t* /*outDisplay*/) { DEBUG_LOG("%s", __FUNCTION__); // TODO: VirtualDisplay support return HWC2::Error::None; } HWC2::Error Device::destroyVirtualDisplay(hwc2_display_t /*displayId*/) { DEBUG_LOG("%s", __FUNCTION__); // TODO: VirtualDisplay support return HWC2::Error::None; } void Device::dump(uint32_t* /*outSize*/, char* /*outBuffer*/) { DEBUG_LOG("%s", __FUNCTION__); // TODO: return; } uint32_t Device::getMaxVirtualDisplayCount() { DEBUG_LOG("%s", __FUNCTION__); // TODO: VirtualDisplay support return 0; } HWC2::Error Device::registerCallback(int32_t desc, hwc2_callback_data_t callbackData, hwc2_function_pointer_t callbackPointer) { const auto callbackType = static_cast(desc); const auto callbackTypeString = to_string(callbackType); DEBUG_LOG("%s callback %s", __FUNCTION__, callbackTypeString.c_str()); std::unique_lock lock(mStateMutex); if (callbackPointer != nullptr) { mCallbacks[callbackType] = {callbackData, callbackPointer}; } else { mCallbacks.erase(callbackType); } if (callbackType == HWC2::Callback::Vsync) { auto callback = reinterpret_cast(callbackPointer); for (const auto& [displayId, display] : mDisplays) { display->setVsyncCallback(callback, callbackData); } } else if (callbackType == HWC2::Callback::Vsync_2_4) { auto callback = reinterpret_cast(callbackPointer); for (const auto& [displayId, display] : mDisplays) { display->setVsync24Callback(callback, callbackData); } } else if (callbackType == HWC2::Callback::Hotplug) { if (callbackPointer == nullptr) { return HWC2::Error::None; } // Callback without the state lock held lock.unlock(); auto hotplug = reinterpret_cast(callbackPointer); auto hotplugConnect = static_cast(HWC2::Connection::Connected); for (const auto& [displayId, display] : mDisplays) { ALOGI("%s hotplug connecting display:%" PRIu64, __FUNCTION__, displayId); hotplug(callbackData, displayId, hotplugConnect); } } else if (callbackType == HWC2::Callback::Refresh) { // Not used } else { ALOGE("%s unhandled callback: %s", __FUNCTION__, callbackTypeString.c_str()); return HWC2::Error::BadParameter; } return HWC2::Error::None; } bool Device::handleHotplug(bool connected, uint32_t id, uint32_t width, uint32_t height, uint32_t dpiX, uint32_t dpiY, uint32_t refreshRate) { std::unique_lock lock(mStateMutex); if (mCallbacks[HWC2::Callback::Hotplug].pointer == nullptr) { return false; } auto hotplug = reinterpret_cast( mCallbacks[HWC2::Callback::Hotplug].pointer); auto hotplugConnect = static_cast(HWC2::Connection::Connected); auto hotplugDisconnect = static_cast(HWC2::Connection::Disconnected); Display* display = getDisplay(id); if (display) { // if existed, disconnect first ALOGD("callback hotplugDisconnect display %" PRIu32, id); hotplug(mCallbacks[HWC2::Callback::Hotplug].data, id, hotplugDisconnect); display->lock(); mComposer->onDisplayDestroy(display); display->unlock(); } if (connected) { hwc2_display_t displayId = static_cast(id); hwc2_config_t configId = static_cast(id); std::vector configs = { DisplayConfig(configId, static_cast(width), static_cast(height), static_cast(dpiX), static_cast(dpiY), static_cast(refreshRate))}; createDisplay(displayId, configId, configs); ALOGD("callback hotplugConnect display %" PRIu32 " width %" PRIu32 " height %" PRIu32 " dpiX %" PRIu32 " dpiY %" PRIu32 "fps %" PRIu32, id, width, height, dpiX, dpiY, refreshRate); hotplug(mCallbacks[HWC2::Callback::Hotplug].data, id, hotplugConnect); }; return true; } Display* Device::getDisplay(hwc2_display_t id) { auto display = mDisplays.find(id); if (display == mDisplays.end()) { ALOGW("Failed to get display for id=%d", (uint32_t)id); return nullptr; } return display->second.get(); } static int OpenDevice(const struct hw_module_t* module, const char* name, struct hw_device_t** dev) { DEBUG_LOG("%s ", __FUNCTION__); if (strcmp(name, HWC_HARDWARE_COMPOSER)) { ALOGE("Invalid module name- %s", name); return -EINVAL; } std::unique_ptr device = std::make_unique(); HWC2::Error error = device->init(); if (error != HWC2::Error::None) { ALOGE("%s: failed to initialize device", __FUNCTION__); return -EINVAL; } error = device->createDisplays(); if (error != HWC2::Error::None) { ALOGE("%s: failed to initialize device displays.", __FUNCTION__); return -EINVAL; } device->common.module = const_cast(module); *dev = &device.release()->common; return 0; } } // namespace android static struct hw_module_methods_t hwc2_module_methods = { .open = android::OpenDevice, }; hw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG, .version_major = 2, .version_minor = 4, .id = HWC_HARDWARE_MODULE_ID, .name = "goldfish HWC2 module", .author = "The Android Open Source Project", .methods = &hwc2_module_methods, .dso = NULL, .reserved = {0}, };