/* // Copyright (c) 2014 Intel Corporation // // 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 <HwcTrace.h> #include <Hwcomposer.h> #include <Dump.h> #include <UeventObserver.h> namespace android { namespace intel { Hwcomposer* Hwcomposer::sInstance(0); Hwcomposer::Hwcomposer(IPlatFactory *factory) : mProcs(0), mDrm(0), mPlatFactory(factory), mVsyncManager(0), mDisplayAnalyzer(0), mMultiDisplayObserver(0), mUeventObserver(0), mPlaneManager(0), mBufferManager(0), mDisplayContext(0), mInitialized(false) { CTRACE(); mDisplayDevices.setCapacity(IDisplayDevice::DEVICE_COUNT); mDisplayDevices.clear(); } Hwcomposer::~Hwcomposer() { CTRACE(); deinitialize(); } bool Hwcomposer::initCheck() const { return mInitialized; } bool Hwcomposer::prepare(size_t numDisplays, hwc_display_contents_1_t** displays) { bool ret = true; RETURN_FALSE_IF_NOT_INIT(); ATRACE("display count = %d", numDisplays); if (!numDisplays || !displays) { ETRACE("invalid parameters"); return false; } mDisplayAnalyzer->analyzeContents(numDisplays, displays); // disable reclaimed planes mPlaneManager->disableReclaimedPlanes(); if(numDisplays > mDisplayDevices.size()) numDisplays = mDisplayDevices.size(); // reclaim all allocated planes if possible for (size_t i = 0; i < numDisplays; i++) { IDisplayDevice *device = mDisplayDevices.itemAt(i); if (!device) { VTRACE("device %d doesn't exist", i); continue; } if (device->getType() == IDisplayDevice::DEVICE_VIRTUAL) continue; device->prePrepare(displays[i]); } for (size_t i = 0; i < numDisplays; i++) { IDisplayDevice *device = mDisplayDevices.itemAt(i); if (!device) { VTRACE("device %d doesn't exist", i); continue; } if (device->getType() == IDisplayDevice::DEVICE_VIRTUAL) continue; ret = device->prepare(displays[i]); if (ret == false) { ETRACE("failed to do prepare for device %d", i); continue; } } return ret; } bool Hwcomposer::commit(size_t numDisplays, hwc_display_contents_1_t **displays) { bool ret = true; RETURN_FALSE_IF_NOT_INIT(); ATRACE("display count = %d", numDisplays); if (!numDisplays || !displays) { ETRACE("invalid parameters"); return false; } if(numDisplays > mDisplayDevices.size()) numDisplays = mDisplayDevices.size(); mDisplayContext->commitBegin(numDisplays, displays); for (size_t i = 0; i < numDisplays; i++) { IDisplayDevice *device = mDisplayDevices.itemAt(i); if (!device) { VTRACE("device %d doesn't exist", i); continue; } if (!device->isConnected()) { VTRACE("device %d is disconnected", i); continue; } if (device->getType() == IDisplayDevice::DEVICE_VIRTUAL) continue; ret = device->commit(displays[i], mDisplayContext); if (ret == false) { ETRACE("failed to do commit for device %d", i); continue; } } mDisplayContext->commitEnd(numDisplays, displays); // return true always return true; } bool Hwcomposer::setPowerMode(int disp, int mode) { RETURN_FALSE_IF_NOT_INIT(); if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) { ETRACE("invalid disp %d", disp); return false; } if(disp >= mDisplayDevices.size()){ ETRACE("no device found"); return false; } IDisplayDevice *device = mDisplayDevices.itemAt(disp); if (!device) { ETRACE("no device found"); return false; } return device->setPowerMode(mode); } int Hwcomposer::getActiveConfig(int disp) { RETURN_NULL_IF_NOT_INIT(); if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) { ETRACE("invalid disp %d", disp); return -1; } IDisplayDevice *device = mDisplayDevices.itemAt(disp); if (!device) { ETRACE("no device found"); return -1; } return device->getActiveConfig(); } bool Hwcomposer::setActiveConfig(int disp, int index) { RETURN_FALSE_IF_NOT_INIT(); if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) { ETRACE("invalid disp %d", disp); return false; } IDisplayDevice *device = mDisplayDevices.itemAt(disp); if (!device) { ETRACE("no device found"); return false; } return device->setActiveConfig(index); } bool Hwcomposer::setCursorPositionAsync(int disp, int x, int y) { RETURN_FALSE_IF_NOT_INIT(); if (disp != HWC_DISPLAY_PRIMARY && disp != HWC_DISPLAY_EXTERNAL) { ETRACE("invalid disp %d", disp); return false; } return mDisplayContext->setCursorPosition(disp, x, y); } bool Hwcomposer::vsyncControl(int disp, int enabled) { RETURN_FALSE_IF_NOT_INIT(); ATRACE("disp = %d, enabled = %d", disp, enabled); return mVsyncManager->handleVsyncControl(disp, enabled ? true : false); } bool Hwcomposer::blank(int disp, int blank) { RETURN_FALSE_IF_NOT_INIT(); ATRACE("disp = %d, blank = %d", disp, blank); if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) { ETRACE("invalid disp %d", disp); return false; } IDisplayDevice *device = mDisplayDevices.itemAt(disp); if (!device) { ETRACE("no device found"); return false; } return device->blank(blank ? true : false); } bool Hwcomposer::getDisplayConfigs(int disp, uint32_t *configs, size_t *numConfigs) { RETURN_FALSE_IF_NOT_INIT(); if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) { ETRACE("invalid disp %d", disp); return false; } if(disp >= mDisplayDevices.size()){ ETRACE("no device found"); return false; } IDisplayDevice *device = mDisplayDevices.itemAt(disp); if (!device) { ETRACE("no device %d found", disp); return false; } return device->getDisplayConfigs(configs, numConfigs); } bool Hwcomposer::getDisplayAttributes(int disp, uint32_t config, const uint32_t *attributes, int32_t *values) { RETURN_FALSE_IF_NOT_INIT(); if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) { ETRACE("invalid disp %d", disp); return false; } if(disp >= mDisplayDevices.size()){ ETRACE("no device found"); return false; } IDisplayDevice *device = mDisplayDevices.itemAt(disp); if (!device) { ETRACE("no device found"); return false; } return device->getDisplayAttributes(config, attributes, values); } bool Hwcomposer::compositionComplete(int disp) { RETURN_FALSE_IF_NOT_INIT(); if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) { ETRACE("invalid disp %d", disp); return false; } mDisplayContext->compositionComplete(); if(disp >= mDisplayDevices.size()){ ETRACE("no device found"); return false; } IDisplayDevice *device = mDisplayDevices.itemAt(disp); if (!device) { ETRACE("no device found"); return false; } return device->compositionComplete(); } void Hwcomposer::vsync(int disp, int64_t timestamp) { RETURN_VOID_IF_NOT_INIT(); if (mProcs && mProcs->vsync) { VTRACE("report vsync on disp %d, timestamp %llu", disp, timestamp); // workaround to pretend vsync is from primary display // Display will freeze if vsync is from external display. mProcs->vsync(const_cast<hwc_procs_t*>(mProcs), IDisplayDevice::DEVICE_PRIMARY, timestamp); } } void Hwcomposer::hotplug(int disp, bool connected) { RETURN_VOID_IF_NOT_INIT(); // TODO: Two fake hotplug events are sent during mode setting. To avoid // unnecessary audio switch, real connection status should be sent to MDS mMultiDisplayObserver->notifyHotPlug(mDrm->isConnected(disp)); if (mProcs && mProcs->hotplug) { DTRACE("report hotplug on disp %d, connected %d", disp, connected); mProcs->hotplug(const_cast<hwc_procs_t*>(mProcs), disp, connected); DTRACE("hotplug callback processed and returned!"); } mDisplayAnalyzer->postHotplugEvent(connected); } void Hwcomposer::invalidate() { RETURN_VOID_IF_NOT_INIT(); if (mProcs && mProcs->invalidate) { DTRACE("invalidating screen..."); mProcs->invalidate(const_cast<hwc_procs_t*>(mProcs)); } } bool Hwcomposer::release() { RETURN_FALSE_IF_NOT_INIT(); return true; } bool Hwcomposer::dump(char *buff, int buff_len, int *cur_len) { RETURN_FALSE_IF_NOT_INIT(); Dump d(buff, buff_len); // dump composer status d.append("Hardware Composer state:"); // dump device status for (size_t i= 0; i < mDisplayDevices.size(); i++) { IDisplayDevice *device = mDisplayDevices.itemAt(i); if (device) device->dump(d); } // dump plane manager status if (mPlaneManager) mPlaneManager->dump(d); // dump buffer manager status if (mBufferManager) mBufferManager->dump(d); return true; } void Hwcomposer::registerProcs(hwc_procs_t const *procs) { CTRACE(); if (!procs) { WTRACE("procs is NULL"); } mProcs = procs; } bool Hwcomposer::initialize() { CTRACE(); // create drm mDrm = new Drm(); if (!mDrm || !mDrm->initialize()) { DEINIT_AND_RETURN_FALSE("failed to create DRM"); } if (!mPlatFactory){ DEINIT_AND_RETURN_FALSE("failed to provide a PlatFactory"); } // create buffer manager mBufferManager = mPlatFactory->createBufferManager(); if (!mBufferManager || !mBufferManager->initialize()) { DEINIT_AND_RETURN_FALSE("failed to create buffer manager"); } // create display plane manager mPlaneManager = mPlatFactory->createDisplayPlaneManager(); if (!mPlaneManager || !mPlaneManager->initialize()) { DEINIT_AND_RETURN_FALSE("failed to create display plane manager"); } mDisplayContext = mPlatFactory->createDisplayContext(); if (!mDisplayContext || !mDisplayContext->initialize()) { DEINIT_AND_RETURN_FALSE("failed to create display context"); } mUeventObserver = new UeventObserver(); if (!mUeventObserver || !mUeventObserver->initialize()) { DEINIT_AND_RETURN_FALSE("failed to initialize uevent observer"); } // create display device mDisplayDevices.clear(); for (int i = 0; i < IDisplayDevice::DEVICE_COUNT; i++) { IDisplayDevice *device = mPlatFactory->createDisplayDevice(i); if (!device || !device->initialize()) { DEINIT_AND_DELETE_OBJ(device); DEINIT_AND_RETURN_FALSE("failed to create device %d", i); } // add this device ETRACE("HWC devices initialize device is %p at %d", device, i); mDisplayDevices.insertAt(device, i, 1); } mVsyncManager = new VsyncManager(*this); if (!mVsyncManager || !mVsyncManager->initialize()) { DEINIT_AND_RETURN_FALSE("failed to create Vsync Manager"); } mDisplayAnalyzer = new DisplayAnalyzer(); if (!mDisplayAnalyzer || !mDisplayAnalyzer->initialize()) { DEINIT_AND_RETURN_FALSE("failed to initialize display analyzer"); } mMultiDisplayObserver = new MultiDisplayObserver(); if (!mMultiDisplayObserver || !mMultiDisplayObserver->initialize()) { DEINIT_AND_RETURN_FALSE("failed to initialize display observer"); } // all initialized, starting uevent observer mUeventObserver->start(); mInitialized = true; return true; } void Hwcomposer::deinitialize() { DEINIT_AND_DELETE_OBJ(mMultiDisplayObserver); DEINIT_AND_DELETE_OBJ(mDisplayAnalyzer); // delete mVsyncManager first as it holds reference to display devices. DEINIT_AND_DELETE_OBJ(mVsyncManager); DEINIT_AND_DELETE_OBJ(mUeventObserver); // destroy display devices for (size_t i = 0; i < mDisplayDevices.size(); i++) { IDisplayDevice *device = mDisplayDevices.itemAt(i); DEINIT_AND_DELETE_OBJ(device); } mDisplayDevices.clear(); if (mPlatFactory) { delete mPlatFactory; mPlatFactory = 0; } DEINIT_AND_DELETE_OBJ(mDisplayContext); DEINIT_AND_DELETE_OBJ(mPlaneManager); DEINIT_AND_DELETE_OBJ(mBufferManager); DEINIT_AND_DELETE_OBJ(mDrm); mInitialized = false; } Drm* Hwcomposer::getDrm() { return mDrm; } DisplayPlaneManager* Hwcomposer::getPlaneManager() { return mPlaneManager; } BufferManager* Hwcomposer::getBufferManager() { return mBufferManager; } IDisplayContext* Hwcomposer::getDisplayContext() { return mDisplayContext; } DisplayAnalyzer* Hwcomposer::getDisplayAnalyzer() { return mDisplayAnalyzer; } MultiDisplayObserver* Hwcomposer::getMultiDisplayObserver() { return mMultiDisplayObserver; } IDisplayDevice* Hwcomposer::getDisplayDevice(int disp) { if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) { ETRACE("invalid disp %d", disp); return NULL; } return mDisplayDevices.itemAt(disp); } VsyncManager* Hwcomposer::getVsyncManager() { return mVsyncManager; } UeventObserver* Hwcomposer::getUeventObserver() { return mUeventObserver; } } // namespace intel } // namespace android