| /* |
| // 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 |