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