diff options
author | Guilhem IMBERTON <guilhem.imberton@intel.com> | 2015-04-10 09:45:39 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2015-04-10 09:45:39 +0000 |
commit | 3f021f9136639ae37de057ac74e5bc74b37e0fd6 (patch) | |
tree | a5d415fbd762c72f5075adf4d9596292c9314004 /moorefield_hdmi/common/base | |
parent | b6cd081e90a23a60aa6488f40c07f86fac5a48d6 (diff) | |
parent | 5094bbf4cbe9b244d79ce5ec52a9285978fff311 (diff) | |
download | hwcomposer-3f021f9136639ae37de057ac74e5bc74b37e0fd6.tar.gz |
am 5094bbf4: Moving Moorefield HWComposer in dedicated directory
* commit '5094bbf4cbe9b244d79ce5ec52a9285978fff311':
Moving Moorefield HWComposer in dedicated directory
Diffstat (limited to 'moorefield_hdmi/common/base')
-rwxr-xr-x | moorefield_hdmi/common/base/DisplayAnalyzer.cpp | 141 | ||||
-rwxr-xr-x | moorefield_hdmi/common/base/DisplayAnalyzer.h | 72 | ||||
-rwxr-xr-x | moorefield_hdmi/common/base/Drm.cpp | 755 | ||||
-rwxr-xr-x | moorefield_hdmi/common/base/Drm.h | 107 | ||||
-rwxr-xr-x | moorefield_hdmi/common/base/HwcLayer.cpp | 347 | ||||
-rw-r--r-- | moorefield_hdmi/common/base/HwcLayer.h | 122 | ||||
-rwxr-xr-x | moorefield_hdmi/common/base/HwcLayerList.cpp | 1044 | ||||
-rwxr-xr-x | moorefield_hdmi/common/base/HwcLayerList.h | 109 | ||||
-rw-r--r-- | moorefield_hdmi/common/base/HwcModule.cpp | 313 | ||||
-rwxr-xr-x | moorefield_hdmi/common/base/Hwcomposer.cpp | 519 | ||||
-rw-r--r-- | moorefield_hdmi/common/base/SimpleThread.h | 38 |
11 files changed, 3567 insertions, 0 deletions
diff --git a/moorefield_hdmi/common/base/DisplayAnalyzer.cpp b/moorefield_hdmi/common/base/DisplayAnalyzer.cpp new file mode 100755 index 0000000..7e5737f --- /dev/null +++ b/moorefield_hdmi/common/base/DisplayAnalyzer.cpp @@ -0,0 +1,141 @@ +/* +// 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 <common/utils/HwcTrace.h> +#include <Hwcomposer.h> +#include <common/base/DisplayAnalyzer.h> + +namespace android { +namespace intel { + +DisplayAnalyzer::DisplayAnalyzer() + : mInitialized(false), + mCachedNumDisplays(0), + mCachedDisplays(0), + mPendingEvents(), + mEventMutex() +{ +} + +DisplayAnalyzer::~DisplayAnalyzer() +{ +} + +bool DisplayAnalyzer::initialize() +{ + mCachedNumDisplays = 0; + mCachedDisplays = 0; + mPendingEvents.clear(); + mInitialized = true; + + return true; +} + +void DisplayAnalyzer::deinitialize() +{ + mPendingEvents.clear(); + mInitialized = false; +} + +void DisplayAnalyzer::analyzeContents( + size_t numDisplays, hwc_display_contents_1_t** displays) +{ + // cache and use them only in this context during analysis + mCachedNumDisplays = numDisplays; + mCachedDisplays = displays; + + handlePendingEvents(); +} + +void DisplayAnalyzer::postHotplugEvent(bool connected) +{ + // handle hotplug event (vsync switch) asynchronously + Event e; + e.type = HOTPLUG_EVENT; + e.bValue = connected; + postEvent(e); + Hwcomposer::getInstance().invalidate(); +} + +void DisplayAnalyzer::postEvent(Event& e) +{ + Mutex::Autolock lock(mEventMutex); + mPendingEvents.add(e); +} + +bool DisplayAnalyzer::getEvent(Event& e) +{ + Mutex::Autolock lock(mEventMutex); + if (mPendingEvents.size() == 0) { + return false; + } + e = mPendingEvents[0]; + mPendingEvents.removeAt(0); + return true; +} + +void DisplayAnalyzer::handlePendingEvents() +{ + // handle one event per analysis to avoid blocking surface flinger + // some event may take lengthy time to process + Event e; + if (!getEvent(e)) { + return; + } + + switch (e.type) { + case HOTPLUG_EVENT: + handleHotplugEvent(e.bValue); + break; + } +} + +void DisplayAnalyzer::handleHotplugEvent(bool connected) +{ + if (connected) { + for (int i = 0; i < mCachedNumDisplays; i++) { + setCompositionType(i, HWC_FRAMEBUFFER, true); + } + } +} + +void DisplayAnalyzer::setCompositionType(hwc_display_contents_1_t *display, int type) +{ + for (size_t i = 0; i < display->numHwLayers - 1; i++) { + hwc_layer_1_t *layer = &display->hwLayers[i]; + if (layer) layer->compositionType = type; + } +} + +void DisplayAnalyzer::setCompositionType(int device, int type, bool reset) +{ + hwc_display_contents_1_t *content = mCachedDisplays[device]; + if (content == NULL) { + ELOGTRACE("Invalid device %d", device); + return; + } + + // don't need to set geometry changed if layers are just needed to be marked + if (reset) { + content->flags |= HWC_GEOMETRY_CHANGED; + } + + setCompositionType(content, type); +} + +} // namespace intel +} // namespace android + diff --git a/moorefield_hdmi/common/base/DisplayAnalyzer.h b/moorefield_hdmi/common/base/DisplayAnalyzer.h new file mode 100755 index 0000000..239cd0a --- /dev/null +++ b/moorefield_hdmi/common/base/DisplayAnalyzer.h @@ -0,0 +1,72 @@ +/* +// 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. +*/ +#ifndef DISPLAY_ANALYZER_H +#define DISPLAY_ANALYZER_H + +#include <utils/threads.h> +#include <utils/Vector.h> + + +namespace android { +namespace intel { + + +class DisplayAnalyzer { +public: + DisplayAnalyzer(); + virtual ~DisplayAnalyzer(); + +public: + bool initialize(); + void deinitialize(); + void analyzeContents(size_t numDisplays, hwc_display_contents_1_t** displays); + void postHotplugEvent(bool connected); + +private: + enum DisplayEventType { + HOTPLUG_EVENT, + }; + + struct Event { + int type; + + union { + bool bValue; + int nValue; + }; + }; + inline void postEvent(Event& e); + inline bool getEvent(Event& e); + void handlePendingEvents(); + void handleHotplugEvent(bool connected); + inline void setCompositionType(hwc_display_contents_1_t *content, int type); + inline void setCompositionType(int device, int type, bool reset); + + +private: + bool mInitialized; + int mCachedNumDisplays; + hwc_display_contents_1_t** mCachedDisplays; + Vector<Event> mPendingEvents; + Mutex mEventMutex; +}; + +} // namespace intel +} // namespace android + + + +#endif /* DISPLAY_ANALYZER_H */ diff --git a/moorefield_hdmi/common/base/Drm.cpp b/moorefield_hdmi/common/base/Drm.cpp new file mode 100755 index 0000000..007d308 --- /dev/null +++ b/moorefield_hdmi/common/base/Drm.cpp @@ -0,0 +1,755 @@ +/* +// 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 <fcntl.h> +#include <errno.h> +#include <common/utils/HwcTrace.h> +#include <IDisplayDevice.h> +#include <DrmConfig.h> +#include <common/base/Drm.h> +#include <Hwcomposer.h> + +namespace android { +namespace intel { + +Drm::Drm() + : mDrmFd(0), + mLock(), + mInitialized(false) +{ + memset(&mOutputs, 0, sizeof(mOutputs)); +} + +Drm::~Drm() +{ + WARN_IF_NOT_DEINIT(); +} + +bool Drm::initialize() +{ + if (mInitialized) { + WLOGTRACE("Drm object has been initialized"); + return true; + } + + const char *path = DrmConfig::getDrmPath(); + mDrmFd = open(path, O_RDWR, 0); + if (mDrmFd < 0) { + ELOGTRACE("failed to open Drm, error: %s", strerror(errno)); + return false; + } + DLOGTRACE("mDrmFd = %d", mDrmFd); + + memset(&mOutputs, 0, sizeof(mOutputs)); + mInitialized = true; + return true; +} + +void Drm::deinitialize() +{ + for (int i = 0; i < OUTPUT_MAX; i++) { + resetOutput(i); + } + + if (mDrmFd) { + close(mDrmFd); + mDrmFd = 0; + } + mInitialized = false; +} + +bool Drm::detect(int device) +{ + RETURN_FALSE_IF_NOT_INIT(); + + Mutex::Autolock _l(mLock); + int outputIndex = getOutputIndex(device); + if (outputIndex < 0 ) { + return false; + } + + resetOutput(outputIndex); + + // get drm resources + drmModeResPtr resources = drmModeGetResources(mDrmFd); + if (!resources) { + ELOGTRACE("fail to get drm resources, error: %s", strerror(errno)); + return false; + } + + drmModeConnectorPtr connector = NULL; + DrmOutput *output = &mOutputs[outputIndex]; + bool ret = false; + + // find connector for the given device + for (int i = 0; i < resources->count_connectors; i++) { + if (!resources->connectors || !resources->connectors[i]) { + ELOGTRACE("fail to get drm resources connectors, error: %s", strerror(errno)); + continue; + } + + connector = drmModeGetConnector(mDrmFd, resources->connectors[i]); + if (!connector) { + ELOGTRACE("drmModeGetConnector failed"); + continue; + } + + if (connector->connector_type != DrmConfig::getDrmConnector(device)) { + drmModeFreeConnector(connector); + continue; + } + + if (connector->connection != DRM_MODE_CONNECTED) { + ILOGTRACE("device %d is not connected", device); + drmModeFreeConnector(connector); + ret = true; + break; + } + + output->connector = connector; + output->connected = true; + + // get proper encoder for the given connector + if (connector->encoder_id) { + ILOGTRACE("Drm connector has encoder attached on device %d", device); + output->encoder = drmModeGetEncoder(mDrmFd, connector->encoder_id); + if (!output->encoder) { + ELOGTRACE("failed to get encoder from a known encoder id"); + // fall through to get an encoder + } + } + if (!output->encoder) { + ILOGTRACE("getting encoder for device %d", device); + drmModeEncoderPtr encoder; + for (int j = 0; j < resources->count_encoders; j++) { + if (!resources->encoders || !resources->encoders[j]) { + ELOGTRACE("fail to get drm resources encoders, error: %s", strerror(errno)); + continue; + } + + encoder = drmModeGetEncoder(mDrmFd, resources->encoders[i]); + if (!encoder) { + ELOGTRACE("drmModeGetEncoder failed"); + continue; + } + if (encoder->encoder_type == DrmConfig::getDrmEncoder(device)) { + output->encoder = encoder; + break; + } + drmModeFreeEncoder(encoder); + encoder = NULL; + } + } + if (!output->encoder) { + ELOGTRACE("failed to get drm encoder"); + break; + } + + // get an attached crtc or spare crtc + if (output->encoder->crtc_id) { + ILOGTRACE("Drm encoder has crtc attached on device %d", device); + output->crtc = drmModeGetCrtc(mDrmFd, output->encoder->crtc_id); + if (!output->crtc) { + ELOGTRACE("failed to get crtc from a known crtc id"); + // fall through to get a spare crtc + } + } + if (!output->crtc) { + ILOGTRACE("getting crtc for device %d", device); + drmModeCrtcPtr crtc; + for (int j = 0; j < resources->count_crtcs; j++) { + if (!resources->crtcs || !resources->crtcs[j]) { + ELOGTRACE("fail to get drm resources crtcs, error: %s", strerror(errno)); + continue; + } + + crtc = drmModeGetCrtc(mDrmFd, resources->crtcs[j]); + if (!crtc) { + ELOGTRACE("drmModeGetCrtc failed"); + continue; + } + // check if legal crtc to the encoder + if (output->encoder->possible_crtcs & (1<<j)) { + if (crtc->buffer_id == 0) { + output->crtc = crtc; + break; + } + } + drmModeFreeCrtc(crtc); + } + } + if (!output->crtc) { + ELOGTRACE("failed to get drm crtc"); + break; + } + + // current mode + if (output->crtc->mode_valid) { + ILOGTRACE("mode is valid, kernel mode settings"); + memcpy(&output->mode, &output->crtc->mode, sizeof(drmModeModeInfo)); + ret = true; + } else { + ELOGTRACE("mode is invalid. Kernel mode setting is not completed"); + ret = false; + } + + if (outputIndex == OUTPUT_PRIMARY) { + if (!readIoctl(DRM_PSB_PANEL_ORIENTATION, &output->panelOrientation, sizeof(int))) { + ELOGTRACE("failed to get device %d orientation", device); + output->panelOrientation = PANEL_ORIENTATION_0; + } + } else { + output->panelOrientation = PANEL_ORIENTATION_0; + } + break; + } + + if (!ret) { + if (output->connector == NULL && outputIndex != OUTPUT_PRIMARY) { + // a fatal failure on primary device + // non fatal on secondary device + WLOGTRACE("device %d is disabled?", device); + ret = true; + } + resetOutput(outputIndex); + } else if (output->connected) { + ILOGTRACE("mode is: %dx%d@%dHz", output->mode.hdisplay, output->mode.vdisplay, output->mode.vrefresh); + } + + drmModeFreeResources(resources); + return ret; +} + +bool Drm::isSameDrmMode(drmModeModeInfoPtr value, + drmModeModeInfoPtr base) const +{ + if (base->hdisplay == value->hdisplay && + base->vdisplay == value->vdisplay && + base->vrefresh == value->vrefresh && + (base->flags & value->flags) == value->flags) { + VLOGTRACE("Drm mode is not changed"); + return true; + } + + return false; +} + +bool Drm::setDrmMode(int device, drmModeModeInfo& value) +{ + RETURN_FALSE_IF_NOT_INIT(); + Mutex::Autolock _l(mLock); + + if (device != IDisplayDevice::DEVICE_EXTERNAL) { + WLOGTRACE("Setting mode on invalid device %d", device); + return false; + } + + int outputIndex = getOutputIndex(device); + if (outputIndex < 0 ) { + ELOGTRACE("invalid device"); + return false; + } + + DrmOutput *output= &mOutputs[outputIndex]; + if (!output->connected) { + ELOGTRACE("device is not connected"); + return false; + } + + if (output->connector->count_modes <= 0) { + ELOGTRACE("invalid count of modes"); + return false; + } + + drmModeModeInfoPtr mode; + int index = 0; + for (int i = 0; i < output->connector->count_modes; i++) { + mode = &output->connector->modes[i]; + if (mode->type & DRM_MODE_TYPE_PREFERRED) { + index = i; + } + if (isSameDrmMode(&value, mode)) { + index = i; + break; + } + } + + mode = &output->connector->modes[index]; + return setDrmMode(outputIndex, mode); +} + +bool Drm::setRefreshRate(int device, int hz) +{ + RETURN_FALSE_IF_NOT_INIT(); + Mutex::Autolock _l(mLock); + + if (device != IDisplayDevice::DEVICE_EXTERNAL) { + WLOGTRACE("Setting mode on invalid device %d", device); + return false; + } + + int outputIndex = getOutputIndex(device); + if (outputIndex < 0 ) { + ELOGTRACE("invalid device"); + return false; + } + + DrmOutput *output= &mOutputs[outputIndex]; + if (!output->connected) { + ELOGTRACE("device is not connected"); + return false; + } + + if (output->connector->count_modes <= 0) { + ELOGTRACE("invalid count of modes"); + return false; + } + + drmModeModeInfoPtr mode; + int index = 0; + for (int i = 0; i < output->connector->count_modes; i++) { + mode = &output->connector->modes[i]; + if (mode->type & DRM_MODE_TYPE_PREFERRED) { + index = i; + } + if (mode->hdisplay == output->mode.hdisplay && + mode->vdisplay == output->mode.vdisplay && + mode->vrefresh == (uint32_t)hz) { + index = i; + break; + } + } + + mode = &output->connector->modes[index]; + return setDrmMode(outputIndex, mode); +} + +bool Drm::writeReadIoctl(unsigned long cmd, void *data, + unsigned long size) +{ + int err; + + if (mDrmFd <= 0) { + ELOGTRACE("drm is not initialized"); + return false; + } + + if (!data || !size) { + ELOGTRACE("invalid parameters"); + return false; + } + + err = drmCommandWriteRead(mDrmFd, cmd, data, size); + if (err) { + WLOGTRACE("failed to call %ld ioctl with failure %d", cmd, err); + return false; + } + + return true; +} + +bool Drm::writeIoctl(unsigned long cmd, void *data, + unsigned long size) +{ + int err; + + if (mDrmFd <= 0) { + ELOGTRACE("drm is not initialized"); + return false; + } + + if (!data || !size) { + ELOGTRACE("invalid parameters"); + return false; + } + + err = drmCommandWrite(mDrmFd, cmd, data, size); + if (err) { + WLOGTRACE("failed to call %ld ioctl with failure %d", cmd, err); + return false; + } + + return true; +} + + +bool Drm::readIoctl(unsigned long cmd, void *data, + unsigned long size) +{ + int err; + + if (mDrmFd <= 0) { + ELOGTRACE("drm is not initialized"); + return false; + } + + if (!data || !size) { + ELOGTRACE("invalid parameters"); + return false; + } + + err = drmCommandRead(mDrmFd, cmd, data, size); + if (err) { + WLOGTRACE("failed to call %ld ioctl with failure %d", cmd, err); + return false; + } + + return true; +} + + +int Drm::getDrmFd() const +{ + return mDrmFd; +} + +bool Drm::getModeInfo(int device, drmModeModeInfo& mode) +{ + Mutex::Autolock _l(mLock); + + int outputIndex = getOutputIndex(device); + if (outputIndex < 0 ) { + return false; + } + + DrmOutput *output= &mOutputs[outputIndex]; + if (output->connected == false) { + ELOGTRACE("device is not connected"); + return false; + } + + if (output->mode.hdisplay == 0 || output->mode.vdisplay == 0) { + ELOGTRACE("invalid width or height"); + return false; + } + + memcpy(&mode, &output->mode, sizeof(drmModeModeInfo)); + +#ifdef INTEL_SUPPORT_HDMI_PRIMARY + // FIXME: use default fb size instead of hdmi mode, because to + // support hdmi primary, we cannot report dynamic mode to SF. + mode.hdisplay = DEFAULT_DRM_FB_WIDTH; + mode.vdisplay = DEFAULT_DRM_FB_HEIGHT; +#endif + + return true; +} + +bool Drm::getPhysicalSize(int device, uint32_t& width, uint32_t& height) +{ + Mutex::Autolock _l(mLock); + + int outputIndex = getOutputIndex(device); + if (outputIndex < 0 ) { + return false; + } + + DrmOutput *output= &mOutputs[outputIndex]; + if (output->connected == false) { + ELOGTRACE("device is not connected"); + return false; + } + + width = output->connector->mmWidth; + height = output->connector->mmHeight; + return true; +} + +bool Drm::getDisplayResolution(int device, uint32_t& width, uint32_t& height) +{ + Mutex::Autolock _l(mLock); + + int outputIndex = getOutputIndex(device); + if (outputIndex < 0) { + return false; + } + + DrmOutput *output= &mOutputs[outputIndex]; + if (output->connected == false) { + ELOGTRACE("device is not connected"); + return false; + } + + width = output->mode.hdisplay; + height = output->mode.vdisplay; + + if (!width || !height) { + ELOGTRACE("invalid width or height"); + return false; + } + return true; +} + +bool Drm::isConnected(int device) +{ + Mutex::Autolock _l(mLock); + + int output = getOutputIndex(device); + if (output < 0 ) { + return false; + } + + return mOutputs[output].connected; +} + +bool Drm::setDpmsMode(int device, int mode) +{ + Mutex::Autolock _l(mLock); + + int output = getOutputIndex(device); + if (output < 0 ) { + return false; + } + + if (mode != IDisplayDevice::DEVICE_DISPLAY_OFF && + mode != IDisplayDevice::DEVICE_DISPLAY_STANDBY && + mode != IDisplayDevice::DEVICE_DISPLAY_ON) { + ELOGTRACE("invalid mode %d", mode); + return false; + } + + DrmOutput *out = &mOutputs[output]; + if (!out->connected) { + ELOGTRACE("device is not connected"); + return false; + } + + drmModePropertyPtr props; + for (int i = 0; i < out->connector->count_props; i++) { + props = drmModeGetProperty(mDrmFd, out->connector->props[i]); + if (!props) { + continue; + } + + if (strcmp(props->name, "DPMS") == 0) { + int ret = drmModeConnectorSetProperty( + mDrmFd, + out->connector->connector_id, + props->prop_id, + (mode == IDisplayDevice::DEVICE_DISPLAY_ON) ? DRM_MODE_DPMS_ON : + IDisplayDevice::DEVICE_DISPLAY_STANDBY == mode ? + DRM_MODE_DPMS_STANDBY : DRM_MODE_DPMS_OFF); + drmModeFreeProperty(props); + if (ret != 0) { + ELOGTRACE("unable to set DPMS %d", mode); + return false; + } else { + return true; + } + } + drmModeFreeProperty(props); + } + return false; +} + +void Drm::resetOutput(int index) +{ + DrmOutput *output = &mOutputs[index]; + + output->connected = false; + memset(&output->mode, 0, sizeof(drmModeModeInfo)); + + if (output->connector) { + drmModeFreeConnector(output->connector); + output->connector = 0; + } + if (output->encoder) { + drmModeFreeEncoder(output->encoder); + output->encoder = 0; + } + if (output->crtc) { + drmModeFreeCrtc(output->crtc); + output->crtc = 0; + } + if (output->fbId) { + drmModeRmFB(mDrmFd, output->fbId); + output->fbId = 0; + } + if (output->fbHandle) { + Hwcomposer::getInstance().getBufferManager()->freeFrameBuffer(output->fbHandle); + output->fbHandle = 0; + } +} + +bool Drm::initDrmMode(int outputIndex) +{ + DrmOutput *output= &mOutputs[outputIndex]; + if (output->connector->count_modes <= 0) { + ELOGTRACE("invalid count of modes"); + return false; + } + + drmModeModeInfoPtr mode; + int index = 0; + for (int i = 0; i < output->connector->count_modes; i++) { + mode = &output->connector->modes[i]; + if (mode->type & DRM_MODE_TYPE_PREFERRED) { + index = i; + break; + } + } + + return setDrmMode(outputIndex, &output->connector->modes[index]); +} + +bool Drm::setDrmMode(int index, drmModeModeInfoPtr mode) +{ + DrmOutput *output = &mOutputs[index]; + + int oldFbId =0; + int oldFbHandle = 0; + + drmModeModeInfo currentMode; + memcpy(¤tMode, &output->mode, sizeof(drmModeModeInfo)); + + if (isSameDrmMode(mode, ¤tMode)) + return true; + + + if (output->fbId) { + oldFbId = output->fbId ; + output->fbId = 0; + } + + if (output->fbHandle) { + oldFbHandle = output->fbHandle; + output->fbHandle = 0; + } + + // allocate frame buffer + int stride = 0; +#ifdef INTEL_SUPPORT_HDMI_PRIMARY + output->fbHandle = Hwcomposer::getInstance().getBufferManager()->allocFrameBuffer( + DEFAULT_DRM_FB_WIDTH, DEFAULT_DRM_FB_HEIGHT, &stride); +#else + output->fbHandle = Hwcomposer::getInstance().getBufferManager()->allocFrameBuffer( + mode->hdisplay, mode->vdisplay, &stride); +#endif + if (output->fbHandle == 0) { + ELOGTRACE("failed to allocate frame buffer"); + return false; + } + + int ret = 0; + ret = drmModeAddFB( + mDrmFd, +#ifdef INTEL_SUPPORT_HDMI_PRIMARY + DEFAULT_DRM_FB_WIDTH, + DEFAULT_DRM_FB_HEIGHT, +#else + mode->hdisplay, + mode->vdisplay, +#endif + DrmConfig::getFrameBufferDepth(), + DrmConfig::getFrameBufferBpp(), + stride, + output->fbHandle, + &output->fbId); + if (ret != 0) { + ELOGTRACE("drmModeAddFB failed, error: %d", ret); + return false; + } + + ILOGTRACE("mode set: %dx%d@%dHz", mode->hdisplay, mode->vdisplay, mode->vrefresh); + + ret = drmModeSetCrtc(mDrmFd, output->crtc->crtc_id, output->fbId, 0, 0, + &output->connector->connector_id, 1, mode); + if (ret == 0) { + //save mode + memcpy(&output->mode, mode, sizeof(drmModeModeInfo)); + } else { + ELOGTRACE("drmModeSetCrtc failed. error: %d", ret); + } + + if (oldFbId) { + drmModeRmFB(mDrmFd, oldFbId); + } + + if (oldFbHandle) { + Hwcomposer::getInstance().getBufferManager()->freeFrameBuffer(oldFbHandle); + } + + return ret == 0; +} + +int Drm::getOutputIndex(int device) +{ + switch (device) { + case IDisplayDevice::DEVICE_PRIMARY: + return OUTPUT_PRIMARY; + case IDisplayDevice::DEVICE_EXTERNAL: + return OUTPUT_EXTERNAL; + default: + ELOGTRACE("invalid display device"); + break; + } + + return -1; +} + +int Drm::getPanelOrientation(int device) +{ + int outputIndex = getOutputIndex(device); + if (outputIndex < 0) { + ELOGTRACE("invalid device"); + return PANEL_ORIENTATION_0; + } + + DrmOutput *output= &mOutputs[outputIndex]; + if (output->connected == false) { + ELOGTRACE("device is not connected"); + return PANEL_ORIENTATION_0; + } + + return output->panelOrientation; +} + +// HWC 1.4 requires that we return all of the compatible configs in getDisplayConfigs +// this is needed so getActiveConfig/setActiveConfig work correctly. It is up to the +// user space to decide what speed to send. +drmModeModeInfoPtr Drm::detectAllConfigs(int device, int *modeCount) +{ + RETURN_NULL_IF_NOT_INIT(); + Mutex::Autolock _l(mLock); + + if (modeCount != NULL) + *modeCount = 0; + else + return NULL; + + int outputIndex = getOutputIndex(device); + if (outputIndex < 0) { + ELOGTRACE("invalid device"); + return NULL; + } + + DrmOutput *output= &mOutputs[outputIndex]; + if (!output->connected) { + ELOGTRACE("device is not connected"); + return NULL; + } + + if (output->connector->count_modes <= 0) { + ELOGTRACE("invalid count of modes"); + return NULL; + } + + *modeCount = output->connector->count_modes; + return output->connector->modes; +} + +} // namespace intel +} // namespace android + diff --git a/moorefield_hdmi/common/base/Drm.h b/moorefield_hdmi/common/base/Drm.h new file mode 100755 index 0000000..ff77ffd --- /dev/null +++ b/moorefield_hdmi/common/base/Drm.h @@ -0,0 +1,107 @@ +/* +// 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. +*/ +#ifndef __DRM_H__ +#define __DRM_H__ + +#include <utils/Mutex.h> +#include <linux/psb_drm.h> + +extern "C" { +#include "xf86drm.h" +#include "xf86drmMode.h" +} + +namespace android { +namespace intel { + +enum { + PANEL_ORIENTATION_0 = 0, + PANEL_ORIENTATION_180 +}; + +#ifdef INTEL_SUPPORT_HDMI_PRIMARY +enum { + DEFAULT_DRM_FB_WIDTH = 1920, + DEFAULT_DRM_FB_HEIGHT = 1080, +}; +#endif + +class Drm { +public: + Drm(); + virtual ~Drm(); +public: + bool initialize(); + void deinitialize(); + bool detect(int device); + bool setDrmMode(int device, drmModeModeInfo& value); + bool setRefreshRate(int device, int hz); + bool writeReadIoctl(unsigned long cmd, void *data, + unsigned long size); + bool writeIoctl(unsigned long cmd, void *data, + unsigned long size); + bool readIoctl(unsigned long cmd, void *data, + unsigned long size); + + bool isConnected(int device); + bool setDpmsMode(int device, int mode); + int getDrmFd() const; + bool getModeInfo(int device, drmModeModeInfo& mode); + bool getPhysicalSize(int device, uint32_t& width, uint32_t& height); + bool getDisplayResolution(int device, uint32_t& width, uint32_t& height); + bool isSameDrmMode(drmModeModeInfoPtr mode, drmModeModeInfoPtr base) const; + int getPanelOrientation(int device); + + drmModeModeInfoPtr detectAllConfigs(int device, int *modeCount); + +private: + bool initDrmMode(int index); + bool setDrmMode(int index, drmModeModeInfoPtr mode); + void resetOutput(int index); + + // map device type to output index, return -1 if not mapped + inline int getOutputIndex(int device); + +private: + // DRM object index + enum { + OUTPUT_PRIMARY = 0, + OUTPUT_EXTERNAL, + OUTPUT_MAX, + }; + + struct DrmOutput { + drmModeConnectorPtr connector; + drmModeEncoderPtr encoder; + drmModeCrtcPtr crtc; + drmModeModeInfo mode; + uint32_t fbHandle; + uint32_t fbId; + int connected; + int panelOrientation; + } mOutputs[OUTPUT_MAX]; + + int mDrmFd; + Mutex mLock; + bool mInitialized; +}; + +} // namespace intel +} // namespace android + + + +#endif /* __DRM_H__ */ diff --git a/moorefield_hdmi/common/base/HwcLayer.cpp b/moorefield_hdmi/common/base/HwcLayer.cpp new file mode 100755 index 0000000..554fb93 --- /dev/null +++ b/moorefield_hdmi/common/base/HwcLayer.cpp @@ -0,0 +1,347 @@ +/* +// 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 <common/utils/HwcTrace.h> +#include <common/base/Drm.h> +#include <common/base/HwcLayer.h> +#include <Hwcomposer.h> +#include <GraphicBuffer.h> +#include <IDisplayDevice.h> +#include <DisplayQuery.h> +#include <PlaneCapabilities.h> + + +namespace android { +namespace intel { + +inline bool operator==(const hwc_rect_t& x, const hwc_rect_t& y) +{ + return (x.top == y.top && + x.bottom == y.bottom && + x.left == y.left && + x.right == y.right); +} + +inline bool operator !=(const hwc_rect_t& x, const hwc_rect_t& y) +{ + return !operator==(x, y); +} + +inline bool operator ==(const hwc_frect_t& x, const hwc_frect_t& y) +{ + return (x.top == y.top && + x.bottom == y.bottom && + x.left == y.left && + x.right == y.right); +} + +inline bool operator !=(const hwc_frect_t& x, const hwc_frect_t& y) +{ + return !operator==(x, y); +} + +HwcLayer::HwcLayer(int index, hwc_layer_1_t *layer) + : mIndex(index), + mZOrder(index + 1), // 0 is reserved for frame buffer target + mDevice(0), + mLayer(layer), + mPlane(0), + mFormat(DataBuffer::FORMAT_INVALID), + mWidth(0), + mHeight(0), + mUsage(0), + mHandle(0), + mIsProtected(false), + mType(LAYER_FB), + mPriority(0), + mTransform(0), + mUpdated(false) +{ + memset(&mSourceCropf, 0, sizeof(mSourceCropf)); + memset(&mDisplayFrame, 0, sizeof(mDisplayFrame)); + memset(&mStride, 0, sizeof(mStride)); + + mPlaneCandidate = false; + setupAttributes(); +} + +HwcLayer::~HwcLayer() +{ + if (mPlane) { + WLOGTRACE("HwcLayer is not cleaned up"); + } + + mLayer = NULL; + mPlane = NULL; +} + +bool HwcLayer::attachPlane(DisplayPlane* plane, int device) +{ + if (mPlane) { + ELOGTRACE("failed to attach plane, plane exists"); + return false; + } + + if (!plane) { + ELOGTRACE("Invalid plane"); + return false; + } + + mDevice = device; + //plane->setZOrder(mIndex); + plane->assignToDevice(device); + mPlane = plane; + return true; +} + +DisplayPlane* HwcLayer::detachPlane() +{ + // reset plane's z order + if (mPlane) + mPlane->setZOrder(-1); + DisplayPlane *plane = mPlane; + mPlane = 0; + mDevice = 0; + return plane; +} + +void HwcLayer::setType(uint32_t type) +{ + if (!mLayer) + return; + + switch (type) { + case LAYER_OVERLAY: + case LAYER_SKIPPED: + mLayer->compositionType = HWC_OVERLAY; + mLayer->hints |= HWC_HINT_CLEAR_FB; + break; + // NOTE: set compositionType to HWC_FRAMEBUFFER here so that we have + // a chance to submit the primary changes to HW. + // Upper layer HWComposer will reset the compositionType automatically. + case LAYER_FB: + case LAYER_FORCE_FB: + mLayer->compositionType = HWC_FRAMEBUFFER; + break; + case LAYER_SIDEBAND: + mLayer->compositionType = HWC_SIDEBAND; + break; + case LAYER_CURSOR_OVERLAY: + mLayer->compositionType = HWC_CURSOR_OVERLAY; + break; + default: + break; + } + + mType = type; +} + +uint32_t HwcLayer::getType() const +{ + return mType; +} + +void HwcLayer::setCompositionType(int32_t type) +{ + mLayer->compositionType = type; +} + +int32_t HwcLayer::getCompositionType() const +{ + return mLayer->compositionType; +} + +int HwcLayer::getIndex() const +{ + return mIndex; +} + +int HwcLayer::getZOrder() const +{ + return mZOrder; +} + +uint32_t HwcLayer::getFormat() const +{ + return mFormat; +} + +uint32_t HwcLayer::getBufferWidth() const +{ + return mWidth; +} + +uint32_t HwcLayer::getBufferHeight() const +{ + return mHeight; +} + +const stride_t& HwcLayer::getBufferStride() const +{ + return mStride; +} + +uint32_t HwcLayer::getUsage() const +{ + return mUsage; +} + +uint32_t HwcLayer::getHandle() const +{ + return mHandle; +} + +uint32_t HwcLayer::getTransform() const +{ + return mTransform; +} + +bool HwcLayer::isProtected() const +{ + return mIsProtected; +} + +hwc_layer_1_t* HwcLayer::getLayer() const +{ + return mLayer; +} + +DisplayPlane* HwcLayer::getPlane() const +{ + return mPlane; +} + +void HwcLayer::setPriority(uint32_t priority) +{ + mPriority = priority; +} + +uint32_t HwcLayer::getPriority() const +{ + return mPriority; +} + +bool HwcLayer::update(hwc_layer_1_t *layer) +{ + // update layer + mLayer = layer; + setupAttributes(); + + // if not a FB layer & a plane was attached update plane's data buffer + if (mPlane) { + mPlane->setPosition(layer->displayFrame.left, + layer->displayFrame.top, + layer->displayFrame.right - layer->displayFrame.left, + layer->displayFrame.bottom - layer->displayFrame.top); + mPlane->setSourceCrop(layer->sourceCropf.left, + layer->sourceCropf.top, + layer->sourceCropf.right - layer->sourceCropf.left, + layer->sourceCropf.bottom - layer->sourceCropf.top); + mPlane->setTransform(layer->transform); + mPlane->setPlaneAlpha(layer->planeAlpha, layer->blending); + bool ret = mPlane->setDataBuffer((uint32_t)layer->handle); + if (ret == true) { + return true; + } + DLOGTRACE("failed to set data buffer, reset handle to 0!!"); + mHandle = 0; + if (!mIsProtected) { + // typical case: rotated buffer is not ready or handle is null + return false; + } else { + // protected video has to be rendered using overlay. + // if buffer is not ready overlay will still be attached to this layer + // but rendering needs to be skipped. + WLOGTRACE("ignoring result of data buffer setting for protected video"); + return true; + } + } + + return true; +} + +bool HwcLayer::isUpdated() +{ + return mUpdated; +} + +void HwcLayer::postFlip() +{ + mUpdated = false; + if (mPlane) { + mPlane->postFlip(); + } +} + +void HwcLayer::setupAttributes() +{ + if ((mLayer->flags & HWC_SKIP_LAYER) || + mTransform != mLayer->transform || + mSourceCropf != mLayer->sourceCropf || + mDisplayFrame != mLayer->displayFrame || + mHandle != (uint32_t)mLayer->handle || + DisplayQuery::isVideoFormat(mFormat)) { + // TODO: same handle does not mean there is always no update + mUpdated = true; + } + + // update handle always as it can become "NULL" + // if the given layer is not ready + mTransform = mLayer->transform; + mSourceCropf = mLayer->sourceCropf; + mDisplayFrame = mLayer->displayFrame; + mHandle = (uint32_t)mLayer->handle; + + if (mFormat != DataBuffer::FORMAT_INVALID) { + // other attributes have been set. + return; + } + + if (mLayer->handle == NULL) { + VLOGTRACE("invalid handle"); + return; + } + + BufferManager *bm = Hwcomposer::getInstance().getBufferManager(); + if (bm == NULL) { + // TODO: this check is redundant + return; + } + + DataBuffer *buffer = bm->lockDataBuffer((uint32_t)mLayer->handle); + if (!buffer) { + ELOGTRACE("failed to get buffer"); + } else { + mFormat = buffer->getFormat(); + mWidth = buffer->getWidth(); + mHeight = buffer->getHeight(); + mStride = buffer->getStride(); + mPriority = (mSourceCropf.right - mSourceCropf.left) * (mSourceCropf.bottom - mSourceCropf.top); + mPriority <<= LAYER_PRIORITY_SIZE_OFFSET; + mPriority |= mIndex; + GraphicBuffer *gBuffer = (GraphicBuffer*)buffer; + mUsage = gBuffer->getUsage(); + mIsProtected = GraphicBuffer::isProtectedBuffer((GraphicBuffer*)buffer); + if (mIsProtected) { + mPriority |= LAYER_PRIORITY_PROTECTED; + } else if (PlaneCapabilities::isFormatSupported(DisplayPlane::PLANE_OVERLAY, this)) { + mPriority |= LAYER_PRIORITY_OVERLAY; + } + bm->unlockDataBuffer(buffer); + } +} + +} // namespace intel +} // namespace android diff --git a/moorefield_hdmi/common/base/HwcLayer.h b/moorefield_hdmi/common/base/HwcLayer.h new file mode 100644 index 0000000..95dbf34 --- /dev/null +++ b/moorefield_hdmi/common/base/HwcLayer.h @@ -0,0 +1,122 @@ +/* +// 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. +*/ +#ifndef HWC_LAYER_H +#define HWC_LAYER_H + +#include <hardware/hwcomposer.h> +#include <DisplayPlane.h> + + +namespace android { +namespace intel { + +class HwcLayer { +public: + enum { + // LAYER_FB layers are marked as HWC_FRAMEBUFFER. + // And a LAYER_FB can become HWC_OVERLAY layers during + // revisiting layer list. + LAYER_FB = 0, + // LAYER_FORCE_FB layers are marked as HWC_FRAMEBUFFER. + // And a LAYER_FORCE_FB can never become HWC_OVERLAY layers during + // revisiting layer list. + LAYER_FORCE_FB, + // LAYER_OVERLAY layers are marked as HWC_OVERLAY + LAYER_OVERLAY, + // LAYER_SKIPPED layers are marked as HWC_OVERLAY with no plane attached + LAYER_SKIPPED, + // LAYER_FRAMEBUFFER_TARGET layers are marked as HWC_FRAMEBUFFER_TARGET + LAYER_FRAMEBUFFER_TARGET, + // LAYER_SIDEBAND layers have alternate path bypassing HWC after setup + LAYER_SIDEBAND, + // LAYER_CURSOR_OVERLAY layers support hardware cursor planes + LAYER_CURSOR_OVERLAY, + }; + + enum { + LAYER_PRIORITY_OVERLAY = 0x60000000UL, + LAYER_PRIORITY_PROTECTED = 0x70000000UL, + LAYER_PRIORITY_SIZE_OFFSET = 4, + }; +public: + HwcLayer(int index, hwc_layer_1_t *layer); + virtual ~HwcLayer(); + + // plane operations + bool attachPlane(DisplayPlane *plane, int device); + DisplayPlane* detachPlane(); + + void setType(uint32_t type); + uint32_t getType() const; + int32_t getCompositionType() const; + void setCompositionType(int32_t type); + + int getIndex() const; + int getZOrder() const; + uint32_t getFormat() const; + uint32_t getBufferWidth() const; + uint32_t getBufferHeight() const; + const stride_t& getBufferStride() const; + uint32_t getUsage() const; + uint32_t getHandle() const; + uint32_t getTransform() const; + bool isProtected() const; + hwc_layer_1_t* getLayer() const; + DisplayPlane* getPlane() const; + + void setPriority(uint32_t priority); + uint32_t getPriority() const; + + bool update(hwc_layer_1_t *layer); + void postFlip(); + bool isUpdated(); + +public: + // temporary solution for plane assignment + bool mPlaneCandidate; + +private: + void setupAttributes(); + +private: + const int mIndex; + int mZOrder; + int mDevice; + hwc_layer_1_t *mLayer; + DisplayPlane *mPlane; + uint32_t mFormat; + uint32_t mWidth; + uint32_t mHeight; + stride_t mStride; + uint32_t mUsage; + uint32_t mHandle; + bool mIsProtected; + uint32_t mType; + uint32_t mPriority; + uint32_t mTransform; + + // for smart composition + hwc_frect_t mSourceCropf; + hwc_rect_t mDisplayFrame; + bool mUpdated; +}; + + +} // namespace intel +} // namespace android + + +#endif /* HWC_LAYER_H */ diff --git a/moorefield_hdmi/common/base/HwcLayerList.cpp b/moorefield_hdmi/common/base/HwcLayerList.cpp new file mode 100755 index 0000000..171cf85 --- /dev/null +++ b/moorefield_hdmi/common/base/HwcLayerList.cpp @@ -0,0 +1,1044 @@ +/* +// 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 <common/utils/HwcTrace.h> +#include <common/base/Drm.h> +#include <common/base/HwcLayerList.h> +#include <Hwcomposer.h> +#include <GraphicBuffer.h> +#include <IDisplayDevice.h> +#include <PlaneCapabilities.h> +#include <DisplayQuery.h> +#include <hal_public.h> + +namespace android { +namespace intel { + +HwcLayerList::HwcLayerList(hwc_display_contents_1_t *list, int disp) + : mList(list), + mLayerCount(0), + mLayers(), + mFBLayers(), + mSpriteCandidates(), + mOverlayCandidates(), + mZOrderConfig(), + mFrameBufferTarget(NULL), + mDisplayIndex(disp) +{ + initialize(); +} + +HwcLayerList::~HwcLayerList() +{ + deinitialize(); +} + +bool HwcLayerList::checkSupported(int planeType, HwcLayer *hwcLayer) +{ + bool valid = false; + hwc_layer_1_t& layer = *(hwcLayer->getLayer()); + + // if layer was forced to use FB + if (hwcLayer->getType() == HwcLayer::LAYER_FORCE_FB) { + VLOGTRACE("layer was forced to use HWC_FRAMEBUFFER"); + return false; + } + + // check layer flags + if (layer.flags & HWC_SKIP_LAYER) { + VLOGTRACE("plane type %d: (skip layer flag was set)", planeType); + return false; + } + + if (layer.handle == 0) { + WLOGTRACE("invalid buffer handle"); + return false; + } + + // check usage + if (!hwcLayer->getUsage() & GRALLOC_USAGE_HW_COMPOSER) { + WLOGTRACE("not a composer layer"); + return false; + } + + // check layer transform + valid = PlaneCapabilities::isTransformSupported(planeType, hwcLayer); + if (!valid) { + VLOGTRACE("plane type %d: (bad transform)", planeType); + return false; + } + + // check buffer format + valid = PlaneCapabilities::isFormatSupported(planeType, hwcLayer); + if (!valid) { + VLOGTRACE("plane type %d: (bad buffer format)", planeType); + return false; + } + + // check buffer size + valid = PlaneCapabilities::isSizeSupported(planeType, hwcLayer); + if (!valid) { + VLOGTRACE("plane type %d: (bad buffer size)", planeType); + return false; + } + + // check layer blending + valid = PlaneCapabilities::isBlendingSupported(planeType, hwcLayer); + if (!valid) { + VLOGTRACE("plane type %d: (bad blending)", planeType); + return false; + } + + // check layer scaling + valid = PlaneCapabilities::isScalingSupported(planeType, hwcLayer); + if (!valid) { + VLOGTRACE("plane type %d: (bad scaling)", planeType); + return false; + } + + // TODO: check visible region? + return true; +} + +bool HwcLayerList::checkRgbOverlaySupported(HwcLayer *hwcLayer) +{ + bool valid = false; + hwc_layer_1_t& layer = *(hwcLayer->getLayer()); + + // if layer was forced to use FB + if (hwcLayer->getType() == HwcLayer::LAYER_FORCE_FB) { + VLOGTRACE("layer was forced to use HWC_FRAMEBUFFER"); + return false; + } + + // check layer flags + if (layer.flags & HWC_SKIP_LAYER) { + VLOGTRACE("skip layer flag was set"); + return false; + } + + if (layer.handle == 0) { + WLOGTRACE("invalid buffer handle"); + return false; + } + + // check usage + if (!hwcLayer->getUsage() & GRALLOC_USAGE_HW_COMPOSER) { + WLOGTRACE("not a composer layer"); + return false; + } + + uint32_t format = hwcLayer->getFormat(); + if (format != HAL_PIXEL_FORMAT_BGRA_8888 && + format != HAL_PIXEL_FORMAT_BGRX_8888) { + return false; + } + + uint32_t h = hwcLayer->getBufferHeight(); + const stride_t& stride = hwcLayer->getBufferStride(); + if (stride.rgb.stride > 4096) { + return false; + } + + uint32_t blending = (uint32_t)hwcLayer->getLayer()->blending; + if (blending != HWC_BLENDING_NONE) { + return false; + } + + uint32_t trans = hwcLayer->getLayer()->transform; + if (trans != 0) { + return false; + } + + hwc_frect_t& src = hwcLayer->getLayer()->sourceCropf; + hwc_rect_t& dest = hwcLayer->getLayer()->displayFrame; + int srcW = (int)src.right - (int)src.left; + int srcH = (int)src.bottom - (int)src.top; + int dstW = dest.right - dest.left; + int dstH = dest.bottom - dest.top; + if (srcW != dstW || srcH != dstH) { + return false; + } + return true; +} + +bool HwcLayerList::checkCursorSupported(HwcLayer *hwcLayer) +{ + bool valid = false; + hwc_layer_1_t& layer = *(hwcLayer->getLayer()); + + // if layer was forced to use FB + if (hwcLayer->getType() == HwcLayer::LAYER_FORCE_FB) { + VLOGTRACE("layer was forced to use HWC_FRAMEBUFFER"); + return false; + } + + // check layer flags + if (layer.flags & HWC_SKIP_LAYER) { + VLOGTRACE("skip layer flag was set"); + return false; + } + + if (!(layer.flags & HWC_IS_CURSOR_LAYER)) { + VLOGTRACE("not a cursor layer"); + return false; + } + + if (hwcLayer->getIndex() != mLayerCount - 2) { + WLOGTRACE("cursor layer is not on top of zorder"); + return false; + } + + if (layer.handle == 0) { + WLOGTRACE("invalid buffer handle"); + return false; + } + + // check usage + if (!hwcLayer->getUsage() & GRALLOC_USAGE_HW_COMPOSER) { + WLOGTRACE("not a composer layer"); + return false; + } + + uint32_t format = hwcLayer->getFormat(); + if (format != HAL_PIXEL_FORMAT_BGRA_8888 && + format != HAL_PIXEL_FORMAT_RGBA_8888) { + WLOGTRACE("unexpected color format %u for cursor", format); + return false; + } + + uint32_t trans = hwcLayer->getLayer()->transform; + if (trans != 0) { + WLOGTRACE("unexpected transform %u for cursor", trans); + return false; + } + + hwc_frect_t& src = hwcLayer->getLayer()->sourceCropf; + hwc_rect_t& dest = hwcLayer->getLayer()->displayFrame; + int srcW = (int)src.right - (int)src.left; + int srcH = (int)src.bottom - (int)src.top; + int dstW = dest.right - dest.left; + int dstH = dest.bottom - dest.top; + if (srcW != dstW || srcH != dstH) { + WLOGTRACE("unexpected scaling for cursor: %dx%d => %dx%d", + srcW, srcH, dstW, dstH); + //return false; + } + + if (srcW > 256 || srcH > 256) { + WLOGTRACE("unexpected size %dx%d for cursor", srcW, srcH); + return false; + } + + return true; +} + + +bool HwcLayerList::initialize() +{ + if (!mList || mList->numHwLayers == 0) { + ELOGTRACE("invalid hwc list"); + return false; + } + + mLayerCount = (int)mList->numHwLayers; + mLayers.setCapacity(mLayerCount); + mFBLayers.setCapacity(mLayerCount); + mSpriteCandidates.setCapacity(mLayerCount); + mOverlayCandidates.setCapacity(mLayerCount); + mCursorCandidates.setCapacity(mLayerCount); + mZOrderConfig.setCapacity(mLayerCount); + Hwcomposer& hwc = Hwcomposer::getInstance(); + + PriorityVector rgbOverlayLayers; + rgbOverlayLayers.setCapacity(mLayerCount); + + for (int i = 0; i < mLayerCount; i++) { + hwc_layer_1_t *layer = &mList->hwLayers[i]; + if (!layer) { + DEINIT_AND_RETURN_FALSE("layer %d is null", i); + } + + HwcLayer *hwcLayer = new HwcLayer(i, layer); + if (!hwcLayer) { + DEINIT_AND_RETURN_FALSE("failed to allocate hwc layer %d", i); + } + + if (layer->compositionType == HWC_FRAMEBUFFER_TARGET) { + hwcLayer->setType(HwcLayer::LAYER_FRAMEBUFFER_TARGET); + mFrameBufferTarget = hwcLayer; + } else if (layer->compositionType == HWC_OVERLAY){ + // skipped layer, filtered by Display Analyzer + hwcLayer->setType(HwcLayer::LAYER_SKIPPED); + } else if (layer->compositionType == HWC_FORCE_FRAMEBUFFER) { + layer->compositionType = HWC_FRAMEBUFFER; + hwcLayer->setType(HwcLayer::LAYER_FORCE_FB); + // add layer to FB layer list for zorder check during plane assignment + mFBLayers.add(hwcLayer); + } else if (layer->compositionType == HWC_FRAMEBUFFER) { + // by default use GPU composition + hwcLayer->setType(HwcLayer::LAYER_FB); + mFBLayers.add(hwcLayer); + if (!DisplayQuery::forceFbScaling(mDisplayIndex)) { + if (checkCursorSupported(hwcLayer)) { + mCursorCandidates.add(hwcLayer); + } else if (checkRgbOverlaySupported(hwcLayer)) { + rgbOverlayLayers.add(hwcLayer); + } else if (checkSupported(DisplayPlane::PLANE_SPRITE, hwcLayer)) { + mSpriteCandidates.add(hwcLayer); + } else if (checkSupported(DisplayPlane::PLANE_OVERLAY, hwcLayer)) { + mOverlayCandidates.add(hwcLayer); + } else { + // noncandidate layer + } + } else { + if (checkSupported(DisplayPlane::PLANE_SPRITE, hwcLayer) && + mLayerCount == 2) { + // if fb scaling, support only one RGB layer on HWC + mSpriteCandidates.add(hwcLayer); + } else if (checkSupported(DisplayPlane::PLANE_OVERLAY, hwcLayer)) { + mOverlayCandidates.add(hwcLayer); + } else { + // noncandidate layer + } + } + } else if (layer->compositionType == HWC_SIDEBAND){ + hwcLayer->setType(HwcLayer::LAYER_SIDEBAND); + } else { + DEINIT_AND_RETURN_FALSE("invalid composition type %d", layer->compositionType); + } + // add layer to layer list + mLayers.add(hwcLayer); + } + + if (mFrameBufferTarget == NULL) { + ELOGTRACE("no frame buffer target?"); + return false; + } + + // If has layer besides of FB_Target, but no FBLayers, skip plane allocation + // Note: There is case that SF passes down a layerlist with only FB_Target + // layer; we need to have this FB_Target to be flipped as well, otherwise it + // will have the buffer queue blocked. (The buffer hold by driver cannot be + // released if new buffers' flip is skipped). + if ((mFBLayers.size() == 0) && (mLayers.size() > 1)) { + VLOGTRACE("no FB layers, skip plane allocation"); + return true; + } + + bool hasOverlay = mOverlayCandidates.size() != 0; + while (rgbOverlayLayers.size()) { + HwcLayer *hwcLayer = rgbOverlayLayers.top(); + if (hasOverlay) { + mSpriteCandidates.add(hwcLayer); + } else { + mOverlayCandidates.add(hwcLayer); + } + rgbOverlayLayers.removeItemsAt(0); + } + + allocatePlanes(); + //dump(); + return true; +} + +void HwcLayerList::deinitialize() +{ + if (mLayerCount == 0) { + return; + } + + DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager(); + for (int i = 0; i < mLayerCount; i++) { + HwcLayer *hwcLayer = mLayers.itemAt(i); + if (hwcLayer) { + DisplayPlane *plane = hwcLayer->detachPlane(); + if (plane) { + planeManager->reclaimPlane(mDisplayIndex, *plane); + } + } + delete hwcLayer; + } + + mLayers.clear(); + mFBLayers.clear(); + mOverlayCandidates.clear(); + mSpriteCandidates.clear(); + mCursorCandidates.clear(); + mZOrderConfig.clear(); + mFrameBufferTarget = NULL; + mLayerCount = 0; +} + + +bool HwcLayerList::allocatePlanes() +{ + return assignCursorPlanes(); +} + +bool HwcLayerList::assignCursorPlanes() +{ + int cursorCandidates = (int)mCursorCandidates.size(); + if (cursorCandidates == 0) { + return assignOverlayPlanes(); + } + + DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager(); + int planeNumber = planeManager->getFreePlanes(mDisplayIndex, DisplayPlane::PLANE_CURSOR); + if (planeNumber == 0) { + DLOGTRACE("no cursor plane available. candidates %d", cursorCandidates); + return assignOverlayPlanes(); + } + + if (planeNumber > cursorCandidates) { + // assuming all cursor planes have the same capabilities, just + // need up to number of candidates for plane assignment + planeNumber = cursorCandidates; + } + + for (int i = planeNumber; i >= 0; i--) { + // assign as many cursor planes as possible + if (assignCursorPlanes(0, i)) { + return true; + } + if (mZOrderConfig.size() != 0) { + ELOGTRACE("ZOrder config is not cleaned up!"); + } + } + return false; +} + + +bool HwcLayerList::assignCursorPlanes(int index, int planeNumber) +{ + // index indicates position in mCursorCandidates to start plane assignment + if (planeNumber == 0) { + return assignOverlayPlanes(); + } + + int cursorCandidates = (int)mCursorCandidates.size(); + for (int i = index; i <= cursorCandidates - planeNumber; i++) { + ZOrderLayer *zlayer = addZOrderLayer(DisplayPlane::PLANE_CURSOR, mCursorCandidates[i]); + if (assignCursorPlanes(i + 1, planeNumber - 1)) { + return true; + } + removeZOrderLayer(zlayer); + } + return false; +} + +bool HwcLayerList::assignOverlayPlanes() +{ + int overlayCandidates = (int)mOverlayCandidates.size(); + if (overlayCandidates == 0) { + return assignSpritePlanes(); + } + + DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager(); + int planeNumber = planeManager->getFreePlanes(mDisplayIndex, DisplayPlane::PLANE_OVERLAY); + if (planeNumber == 0) { + DLOGTRACE("no overlay plane available. candidates %d", overlayCandidates); + return assignSpritePlanes(); + } + + if (planeNumber > overlayCandidates) { + // assuming all overlay planes have the same capabilities, just + // need up to number of candidates for plane assignment + planeNumber = overlayCandidates; + } + + for (int i = planeNumber; i >= 0; i--) { + // assign as many overlay planes as possible + if (assignOverlayPlanes(0, i)) { + return true; + } + if (mZOrderConfig.size() != 0) { + ELOGTRACE("ZOrder config is not cleaned up!"); + } + } + return false; +} + + +bool HwcLayerList::assignOverlayPlanes(int index, int planeNumber) +{ + // index indicates position in mOverlayCandidates to start plane assignment + if (planeNumber == 0) { + return assignSpritePlanes(); + } + + int overlayCandidates = (int)mOverlayCandidates.size(); + for (int i = index; i <= overlayCandidates - planeNumber; i++) { + ZOrderLayer *zlayer = addZOrderLayer(DisplayPlane::PLANE_OVERLAY, mOverlayCandidates[i]); + if (assignOverlayPlanes(i + 1, planeNumber - 1)) { + return true; + } + removeZOrderLayer(zlayer); + } + return false; +} + +bool HwcLayerList::assignSpritePlanes() +{ + int spriteCandidates = (int)mSpriteCandidates.size(); + if (spriteCandidates == 0) { + return assignPrimaryPlane(); + } + + // number does not include primary plane + DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager(); + int planeNumber = planeManager->getFreePlanes(mDisplayIndex, DisplayPlane::PLANE_SPRITE); + if (planeNumber == 0) { + VLOGTRACE("no sprite plane available, candidates %d", spriteCandidates); + return assignPrimaryPlane(); + } + + if (planeNumber > spriteCandidates) { + // assuming all sprite planes have the same capabilities, just + // need up to number of candidates for plane assignment + planeNumber = spriteCandidates; + } + + for (int i = planeNumber; i >= 0; i--) { + // assign as many sprite planes as possible + if (assignSpritePlanes(0, i)) { + return true; + } + + if (mOverlayCandidates.size() == 0 && mZOrderConfig.size() != 0) { + ELOGTRACE("ZOrder config is not cleaned up!"); + } + } + return false; +} + + +bool HwcLayerList::assignSpritePlanes(int index, int planeNumber) +{ + if (planeNumber == 0) { + return assignPrimaryPlane(); + } + + int spriteCandidates = (int)mSpriteCandidates.size(); + for (int i = index; i <= spriteCandidates - planeNumber; i++) { + ZOrderLayer *zlayer = addZOrderLayer(DisplayPlane::PLANE_SPRITE, mSpriteCandidates[i]); + if (assignSpritePlanes(i + 1, planeNumber - 1)) { + return true; + } + removeZOrderLayer(zlayer); + } + return false; +} + +bool HwcLayerList::assignPrimaryPlane() +{ + // find a sprit layer that is not candidate but has lower priority than candidates. + HwcLayer *spriteLayer = NULL; + for (int i = (int)mSpriteCandidates.size() - 1; i >= 0; i--) { + if (mSpriteCandidates[i]->mPlaneCandidate) + break; + + spriteLayer = mSpriteCandidates[i]; + } + + int candidates = (int)mZOrderConfig.size(); + int layers = (int)mFBLayers.size(); + bool ok = false; + + if (candidates == layers - 1 && spriteLayer != NULL) { + // primary plane is configured as sprite, all sprite candidates are offloaded to display planes + ok = assignPrimaryPlaneHelper(spriteLayer); + if (!ok) { + VLOGTRACE("failed to use primary as sprite plane"); + } + } else if (candidates == 0) { + // none assigned, use primary plane for frame buffer target and set zorder to 0 + ok = assignPrimaryPlaneHelper(mFrameBufferTarget, 0); + if (!ok) { + ELOGTRACE("failed to compose all layers to primary plane, should never happen"); + } + } else if (candidates == layers) { + // all assigned, primary plane may be used during ZOrder config. + ok = attachPlanes(); + if (!ok) { + VLOGTRACE("failed to assign layers without primary"); + } + } else { + // check if the remaining planes can be composed to frame buffer target (FBT) + // look up a legitimate Z order position to place FBT. + for (int i = 0; i < layers && !ok; i++) { + if (mFBLayers[i]->mPlaneCandidate) { + continue; + } + if (useAsFrameBufferTarget(mFBLayers[i])) { + ok = assignPrimaryPlaneHelper(mFrameBufferTarget, mFBLayers[i]->getZOrder()); + if (!ok) { + VLOGTRACE("failed to use zorder %d for frame buffer target", + mFBLayers[i]->getZOrder()); + } + } + } + if (!ok) { + VLOGTRACE("no possible zorder for frame buffer target"); + } + + } + return ok; +} + +bool HwcLayerList::assignPrimaryPlaneHelper(HwcLayer *hwcLayer, int zorder) +{ + int type = DisplayPlane::PLANE_PRIMARY; + + ZOrderLayer *zlayer = addZOrderLayer(type, hwcLayer, zorder); + bool ok = attachPlanes(); + if (!ok) { + removeZOrderLayer(zlayer); + } + return ok; +} + +bool HwcLayerList::attachPlanes() +{ + DisplayPlaneManager *planeManager = Hwcomposer::getInstance().getPlaneManager(); + if (!planeManager->isValidZOrder(mDisplayIndex, mZOrderConfig)) { + VLOGTRACE("invalid z order, size of config %d", mZOrderConfig.size()); + return false; + } + + if (!planeManager->assignPlanes(mDisplayIndex, mZOrderConfig)) { + WLOGTRACE("failed to assign planes"); + return false; + } + + VLOGTRACE("============= plane assignment==================="); + for (int i = 0; i < (int)mZOrderConfig.size(); i++) { + ZOrderLayer *zlayer = mZOrderConfig.itemAt(i); + if (zlayer->plane == NULL || zlayer->hwcLayer == NULL) { + ELOGTRACE("invalid ZOrderLayer, should never happen!!"); + return false; + } + + zlayer->plane->setZOrder(i); + + if (zlayer->plane->getType() == DisplayPlane::PLANE_CURSOR) { + zlayer->hwcLayer->setType(HwcLayer::LAYER_CURSOR_OVERLAY); + mFBLayers.remove(zlayer->hwcLayer); + } else if (zlayer->hwcLayer != mFrameBufferTarget) { + zlayer->hwcLayer->setType(HwcLayer::LAYER_OVERLAY); + // update FB layers for smart composition + mFBLayers.remove(zlayer->hwcLayer); + } + + zlayer->hwcLayer->attachPlane(zlayer->plane, mDisplayIndex); + + VLOGTRACE("total %d, layer %d, type %d, index %d, zorder %d", + mLayerCount - 1, + zlayer->hwcLayer->getIndex(), + zlayer->plane->getType(), + zlayer->plane->getIndex(), + zlayer->zorder); + + delete zlayer; + } + + mZOrderConfig.clear(); + return true; +} + +bool HwcLayerList::useAsFrameBufferTarget(HwcLayer *target) +{ + // check if zorder of target can be used as zorder of frame buffer target + // eligible only when all noncandidate layers can be merged to the target layer: + // 1) noncandidate layer and candidate layer below the target layer can't overlap + // if candidate layer is on top of non candidate layer, as "noncandidate layer" needs + // to be moved up to target layer in z order; + // 2) noncandidate layer and candidate layers above the target layer can't overlap + // if candidate layer is below noncandidate layer, as "noncandidate layer" needs + // to be moved down to target layer in z order. + + int targetLayerIndex = target->getIndex(); + + // check candidate and noncandidate layers below this candidate does not overlap + for (int below = 0; below < targetLayerIndex; below++) { + if (mFBLayers[below]->mPlaneCandidate) { + continue; + } else { + // check candidate layer above this noncandidate layer does not overlap + for (int above = below + 1; above < targetLayerIndex; above++) { + if (mFBLayers[above]->mPlaneCandidate == false) { + continue; + } + if (hasIntersection(mFBLayers[above], mFBLayers[below])) { + return false; + } + } + } + } + + // check candidate and noncandidate layers above this candidate does not overlap + for (unsigned int above = targetLayerIndex + 1; above < mFBLayers.size(); above++) { + if (mFBLayers[above]->mPlaneCandidate) { + continue; + } else { + // check candidate layer below this noncandidate layer does not overlap + for (unsigned int below = targetLayerIndex + 1; below < above; below++) { + if (mFBLayers[below]->mPlaneCandidate == false) { + continue; + } + if (hasIntersection(mFBLayers[above], mFBLayers[below])) { + return false; + } + } + } + } + + return true; +} + +bool HwcLayerList::hasIntersection(HwcLayer *la, HwcLayer *lb) +{ + hwc_layer_1_t *a = la->getLayer(); + hwc_layer_1_t *b = lb->getLayer(); + hwc_rect_t *aRect = &a->displayFrame; + hwc_rect_t *bRect = &b->displayFrame; + + if (bRect->right <= aRect->left || + bRect->left >= aRect->right || + bRect->top >= aRect->bottom || + bRect->bottom <= aRect->top) + return false; + + return true; +} + +ZOrderLayer* HwcLayerList::addZOrderLayer(int type, HwcLayer *hwcLayer, int zorder) +{ + ZOrderLayer *layer = new ZOrderLayer; + layer->planeType = type; + layer->hwcLayer = hwcLayer; + layer->zorder = (zorder != -1) ? zorder : hwcLayer->getZOrder(); + layer->plane = NULL; + + if (hwcLayer->mPlaneCandidate) { + ELOGTRACE("plane is candidate!, order = %d", zorder); + } + + hwcLayer->mPlaneCandidate = true; + + if ((int)mZOrderConfig.indexOf(layer) >= 0) { + ELOGTRACE("layer exists!"); + } + + mZOrderConfig.add(layer); + return layer; +} + +void HwcLayerList::removeZOrderLayer(ZOrderLayer *layer) +{ + if ((int)mZOrderConfig.indexOf(layer) < 0) { + ELOGTRACE("layer does not exist!"); + } + + mZOrderConfig.remove(layer); + + if (layer->hwcLayer->mPlaneCandidate == false) { + ELOGTRACE("plane is not candidate!, order %d", layer->zorder); + } + layer->hwcLayer->mPlaneCandidate = false; + delete layer; +} + +void HwcLayerList::setupSmartComposition() +{ + uint32_t compositionType = HWC_OVERLAY; + HwcLayer *hwcLayer = NULL; + + // setup smart composition only there's no update on all FB layers + for (size_t i = 0; i < mFBLayers.size(); i++) { + hwcLayer = mFBLayers.itemAt(i); + if (hwcLayer->isUpdated()) { + compositionType = HWC_FRAMEBUFFER; + } + } + + VLOGTRACE("smart composition enabled %s", + (compositionType == HWC_OVERLAY) ? "TRUE" : "FALSE"); + for (size_t i = 0; i < mFBLayers.size(); i++) { + hwcLayer = mFBLayers.itemAt(i); + switch (hwcLayer->getType()) { + case HwcLayer::LAYER_FB: + case HwcLayer::LAYER_FORCE_FB: + hwcLayer->setCompositionType(compositionType); + break; + default: + ELOGTRACE("Invalid layer type %d", hwcLayer->getType()); + break; + } + } +} + +#if 1 // support overlay fallback to GLES + +bool HwcLayerList::update(hwc_display_contents_1_t *list) +{ + bool ret; + + // basic check to make sure the consistance + if (!list) { + ELOGTRACE("null layer list"); + return false; + } + + if ((int)list->numHwLayers != mLayerCount) { + ELOGTRACE("layer count doesn't match (%d, %d)", list->numHwLayers, mLayerCount); + return false; + } + + // update list + mList = list; + + bool ok = true; + // update all layers, call each layer's update() + for (int i = 0; i < mLayerCount; i++) { + HwcLayer *hwcLayer = mLayers.itemAt(i); + if (!hwcLayer) { + ELOGTRACE("no HWC layer for layer %d", i); + continue; + } + + if (!hwcLayer->update(&list->hwLayers[i])) { + ok = false; + hwcLayer->setCompositionType(HWC_FORCE_FRAMEBUFFER); + } + } + + if (!ok) { + ILOGTRACE("overlay fallback to GLES. flags: %#x", list->flags); + for (int i = 0; i < mLayerCount - 1; i++) { + HwcLayer *hwcLayer = mLayers.itemAt(i); + if (hwcLayer->getPlane() && + (hwcLayer->getCompositionType() == HWC_OVERLAY || + hwcLayer->getCompositionType() == HWC_CURSOR_OVERLAY)) { + hwcLayer->setCompositionType(HWC_FRAMEBUFFER); + } + } + mLayers.itemAt(mLayerCount - 1)->setCompositionType(HWC_FRAMEBUFFER_TARGET); + deinitialize(); + mList = list; + initialize(); + + // update all layers again after plane re-allocation + for (int i = 0; i < mLayerCount; i++) { + HwcLayer *hwcLayer = mLayers.itemAt(i); + if (!hwcLayer) { + ELOGTRACE("no HWC layer for layer %d", i); + continue; + } + + if (!hwcLayer->update(&list->hwLayers[i])) { + DLOGTRACE("fallback to GLES update failed on layer[%d]!\n", i); + } + } + } + + setupSmartComposition(); + return true; +} + +#else + +bool HwcLayerList::update(hwc_display_contents_1_t *list) +{ + bool ret; + + // basic check to make sure the consistance + if (!list) { + ELOGTRACE("null layer list"); + return false; + } + + if ((int)list->numHwLayers != mLayerCount) { + ELOGTRACE("layer count doesn't match (%d, %d)", list->numHwLayers, mLayerCount); + return false; + } + + // update list + mList = list; + + // update all layers, call each layer's update() + for (int i = 0; i < mLayerCount; i++) { + HwcLayer *hwcLayer = mLayers.itemAt(i); + if (!hwcLayer) { + ELOGTRACE("no HWC layer for layer %d", i); + continue; + } + + hwcLayer->update(&list->hwLayers[i]); + } + + setupSmartComposition(); + return true; +} + +#endif + +DisplayPlane* HwcLayerList::getPlane(uint32_t index) const +{ + HwcLayer *hwcLayer; + + if (index >= mLayers.size()) { + ELOGTRACE("invalid layer index %d", index); + return 0; + } + + hwcLayer = mLayers.itemAt(index); + if ((hwcLayer->getType() == HwcLayer::LAYER_FB) || + (hwcLayer->getType() == HwcLayer::LAYER_FORCE_FB) || + (hwcLayer->getType() == HwcLayer::LAYER_SKIPPED)) { + return 0; + } + + if (hwcLayer->getHandle() == 0) { + DLOGTRACE("plane is attached with invalid handle"); + return 0; + } + + return hwcLayer->getPlane(); +} + +void HwcLayerList::postFlip() +{ + for (size_t i = 0; i < mLayers.size(); i++) { + HwcLayer *hwcLayer = mLayers.itemAt(i); + hwcLayer->postFlip(); + } +} + +void HwcLayerList::dump(Dump& d) +{ + d.append("Layer list: (number of layers %d):\n", mLayers.size()); + d.append(" LAYER | TYPE | PLANE | INDEX | Z Order \n"); + d.append("-------+------------------------+----------------------------\n"); + for (size_t i = 0; i < mLayers.size(); i++) { + HwcLayer *hwcLayer = mLayers.itemAt(i); + DisplayPlane *plane; + int planeIndex = -1; + int zorder = -1; + const char *type = "HWC_FB"; + const char *planeType = "N/A"; + + if (hwcLayer) { + switch (hwcLayer->getType()) { + case HwcLayer::LAYER_FB: + case HwcLayer::LAYER_FORCE_FB: + type = "HWC_FB"; + break; + case HwcLayer::LAYER_OVERLAY: + case HwcLayer::LAYER_SKIPPED: + type = "HWC_OVERLAY"; + break; + case HwcLayer::LAYER_FRAMEBUFFER_TARGET: + type = "HWC_FRAMEBUFFER_TARGET"; + break; + case HwcLayer::LAYER_SIDEBAND: + type = "HWC_SIDEBAND"; + break; + case HwcLayer::LAYER_CURSOR_OVERLAY: + type = "HWC_CURSOR_OVERLAY"; + break; + default: + type = "Unknown"; + } + + plane = hwcLayer->getPlane(); + if (plane) { + planeIndex = plane->getIndex(); + zorder = plane->getZOrder(); + switch (plane->getType()) { + case DisplayPlane::PLANE_OVERLAY: + planeType = "OVERLAY"; + break; + case DisplayPlane::PLANE_SPRITE: + planeType = "SPRITE"; + break; + case DisplayPlane::PLANE_PRIMARY: + planeType = "PRIMARY"; + break; + case DisplayPlane::PLANE_CURSOR: + planeType = "CURSOR"; + break; + default: + planeType = "Unknown"; + } + } + + d.append(" %2d | %22s | %8s | %3D | %3D \n", + i, type, planeType, planeIndex, zorder); + } + } +} + + +void HwcLayerList::dump() +{ + static char const* compositionTypeName[] = { + "GLES", + "HWC", + "BG", + "FBT", + "SB", + "CUR", + "N/A"}; + + static char const* planeTypeName[] = { + "SPRITE", + "OVERLAY", + "PRIMARY", + "CURSOR", + "UNKNOWN"}; + + DLOGTRACE(" numHwLayers = %u, flags = %08x", mList->numHwLayers, mList->flags); + + DLOGTRACE(" type | handle | hints | flags | tr | blend | alpha | format | source crop | frame | index | zorder | plane "); + DLOGTRACE("------+----------+-------+-------+----+-------+-------+----------+-----------------------------------+---------------------------+-------+--------+---------"); + + + for (int i = 0 ; i < mLayerCount ; i++) { + const hwc_layer_1_t&l = mList->hwLayers[i]; + DisplayPlane *plane = mLayers[i]->getPlane(); + int planeIndex = -1; + int zorder = -1; + const char *planeType = "N/A"; + if (plane) { + planeIndex = plane->getIndex(); + zorder = plane->getZOrder(); + planeType = planeTypeName[plane->getType()]; + } + + DLOGTRACE( + " %4s | %8x | %5x | %5x | %2x | %5x | %5x | %8x | [%7.1f,%7.1f,%7.1f,%7.1f] | [%5d,%5d,%5d,%5d] | %5d | %6d | %7s ", + compositionTypeName[l.compositionType], + mLayers[i]->getHandle(), l.hints, l.flags, l.transform, l.blending, l.planeAlpha, mLayers[i]->getFormat(), + l.sourceCropf.left, l.sourceCropf.top, l.sourceCropf.right, l.sourceCropf.bottom, + l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom, + planeIndex, zorder, planeType); + } + +} + + +} // namespace intel +} // namespace android diff --git a/moorefield_hdmi/common/base/HwcLayerList.h b/moorefield_hdmi/common/base/HwcLayerList.h new file mode 100755 index 0000000..f933e7a --- /dev/null +++ b/moorefield_hdmi/common/base/HwcLayerList.h @@ -0,0 +1,109 @@ +/* +// 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. +*/ +#ifndef HWC_LAYER_LIST_H +#define HWC_LAYER_LIST_H + +#include <common/utils/Dump.h> +#include <hardware/hwcomposer.h> +#include <utils/SortedVector.h> +#include <DataBuffer.h> +#include <DisplayPlane.h> +#include <DisplayPlaneManager.h> +#include <common/base/HwcLayer.h> + +namespace android { +namespace intel { + + +class HwcLayerList { +public: + HwcLayerList(hwc_display_contents_1_t *list, int disp); + virtual ~HwcLayerList(); + +public: + virtual bool initialize(); + virtual void deinitialize(); + + virtual bool update(hwc_display_contents_1_t *list); + virtual DisplayPlane* getPlane(uint32_t index) const; + + void postFlip(); + + // dump interface + virtual void dump(Dump& d); + + +private: + bool checkSupported(int planeType, HwcLayer *hwcLayer); + bool checkRgbOverlaySupported(HwcLayer *hwcLayer); + bool checkCursorSupported(HwcLayer *hwcLayer); + bool allocatePlanes(); + bool assignCursorPlanes(); + bool assignCursorPlanes(int index, int planeNumber); + bool assignOverlayPlanes(); + bool assignOverlayPlanes(int index, int planeNumber); + bool assignSpritePlanes(); + bool assignSpritePlanes(int index, int planeNumber); + bool assignPrimaryPlane(); + bool assignPrimaryPlaneHelper(HwcLayer *hwcLayer, int zorder = -1); + bool attachPlanes(); + bool useAsFrameBufferTarget(HwcLayer *target); + bool hasIntersection(HwcLayer *la, HwcLayer *lb); + ZOrderLayer* addZOrderLayer(int type, HwcLayer *hwcLayer, int zorder = -1); + void removeZOrderLayer(ZOrderLayer *layer); + void setupSmartComposition(); + void dump(); + +private: + class HwcLayerVector : public SortedVector<HwcLayer*> { + public: + HwcLayerVector() {} + virtual int do_compare(const void* lhs, const void* rhs) const { + const HwcLayer* l = *(HwcLayer**)lhs; + const HwcLayer* r = *(HwcLayer**)rhs; + // sorted from index 0 to n + return l->getIndex() - r->getIndex(); + } + }; + + class PriorityVector : public SortedVector<HwcLayer*> { + public: + PriorityVector() {} + virtual int do_compare(const void* lhs, const void* rhs) const { + const HwcLayer* l = *(HwcLayer**)lhs; + const HwcLayer* r = *(HwcLayer**)rhs; + return r->getPriority() - l->getPriority(); + } + }; + + hwc_display_contents_1_t *mList; + int mLayerCount; + + HwcLayerVector mLayers; + HwcLayerVector mFBLayers; + PriorityVector mSpriteCandidates; + PriorityVector mOverlayCandidates; + PriorityVector mCursorCandidates; + ZOrderConfig mZOrderConfig; + HwcLayer *mFrameBufferTarget; + int mDisplayIndex; +}; + +} // namespace intel +} // namespace android + + +#endif /* HWC_LAYER_LIST_H */ diff --git a/moorefield_hdmi/common/base/HwcModule.cpp b/moorefield_hdmi/common/base/HwcModule.cpp new file mode 100644 index 0000000..ce8d478 --- /dev/null +++ b/moorefield_hdmi/common/base/HwcModule.cpp @@ -0,0 +1,313 @@ +/* +// 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. +*/ + +#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL) + +#include <hardware/hardware.h> +#include <string.h> +#include <stdio.h> +#include <fcntl.h> +#include <errno.h> +#include <common/utils/HwcTrace.h> +#include <Hwcomposer.h> +#include <utils/Trace.h> + +#define GET_HWC_RETURN_X_IF_NULL(X) \ + CTRACE(); \ + Hwcomposer *hwc = static_cast<Hwcomposer*>(dev); \ + do {\ + if (!hwc) { \ + ELOGTRACE("invalid HWC device."); \ + return X; \ + } \ + } while (0) + + +#define GET_HWC_RETURN_ERROR_IF_NULL() GET_HWC_RETURN_X_IF_NULL(-EINVAL) +#define GET_HWC_RETURN_VOID_IF_NULL() GET_HWC_RETURN_X_IF_NULL() + + +namespace android { +namespace intel { + +static int hwc_prepare(struct hwc_composer_device_1 *dev, + size_t numDisplays, + hwc_display_contents_1_t** displays) +{ + ATRACE_CALL(); + GET_HWC_RETURN_ERROR_IF_NULL(); + if (!hwc->prepare(numDisplays, displays)) { + ELOGTRACE("failed to prepare"); + return -EINVAL; + } + return 0; +} + +static int hwc_set(struct hwc_composer_device_1 *dev, + size_t numDisplays, + hwc_display_contents_1_t **displays) +{ + ATRACE_CALL(); + GET_HWC_RETURN_ERROR_IF_NULL(); + if (!hwc->commit(numDisplays, displays)) { + ELOGTRACE("failed to commit"); + return -EINVAL; + } + return 0; +} + +static void hwc_dump(struct hwc_composer_device_1 *dev, + char *buff, + int buff_len) +{ + GET_HWC_RETURN_VOID_IF_NULL(); + hwc->dump(buff, buff_len, 0); +} + +void hwc_registerProcs(struct hwc_composer_device_1 *dev, + hwc_procs_t const *procs) +{ + GET_HWC_RETURN_VOID_IF_NULL(); + hwc->registerProcs(procs); +} + +static int hwc_device_close(struct hw_device_t * /* dev */) +{ + CTRACE(); + Hwcomposer::releaseInstance(); + return 0; +} + +static int hwc_query(struct hwc_composer_device_1 * /* dev */, + int what, int* /* value */) +{ + (void) what; + ALOGTRACE("what = %d", what); + return -EINVAL; +} + +static int hwc_eventControl(struct hwc_composer_device_1 *dev, + int disp, + int event, + int enabled) +{ + bool ret; + ATRACE_CALL(); + GET_HWC_RETURN_ERROR_IF_NULL(); + + switch (event) { + case HWC_EVENT_VSYNC: + ret = hwc->vsyncControl(disp, enabled); + if (ret == false) { + ELOGTRACE("failed to control vsync"); + return -EINVAL; + } + break; + default: + WLOGTRACE("unsupported event %d", event); + break; + } + + return 0; +} + +static int hwc_blank(hwc_composer_device_1_t *dev, int disp, int blank) +{ + ATRACE_CALL(); + GET_HWC_RETURN_ERROR_IF_NULL(); + bool ret = hwc->blank(disp, blank); + if (ret == false) { + ELOGTRACE("failed to blank disp %d, blank %d", disp, blank); + return -EINVAL; + } + + return 0; +} + +static int hwc_getDisplayConfigs(hwc_composer_device_1_t *dev, + int disp, + uint32_t *configs, + size_t *numConfigs) +{ + ATRACE_CALL(); + GET_HWC_RETURN_ERROR_IF_NULL(); + bool ret = hwc->getDisplayConfigs(disp, configs, numConfigs); + if (ret == false) { + WLOGTRACE("failed to get configs of disp %d", disp); + return -EINVAL; + } + + return 0; +} + +static int hwc_getDisplayAttributes(hwc_composer_device_1_t *dev, + int disp, + uint32_t config, + const uint32_t *attributes, + int32_t *values) +{ + ATRACE_CALL(); + GET_HWC_RETURN_ERROR_IF_NULL(); + bool ret = hwc->getDisplayAttributes(disp, config, attributes, values); + if (ret == false) { + WLOGTRACE("failed to get attributes of disp %d", disp); + return -EINVAL; + } + + return 0; +} + +static int hwc_compositionComplete(hwc_composer_device_1_t *dev, int disp) +{ + ATRACE_CALL(); + GET_HWC_RETURN_ERROR_IF_NULL(); + bool ret = hwc->compositionComplete(disp); + if (ret == false) { + ELOGTRACE("failed for disp %d", disp); + return -EINVAL; + } + + return 0; +} + +static int hwc_setPowerMode(hwc_composer_device_1_t *dev, int disp, int mode) +{ + ATRACE_CALL(); + GET_HWC_RETURN_ERROR_IF_NULL(); + bool ret = hwc->setPowerMode(disp, mode); + if (ret == false) { + WLOGTRACE("failed to set power mode of disp %d", disp); + return -EINVAL; + } + + return 0; +} + +static int hwc_getActiveConfig(hwc_composer_device_1_t *dev, int disp) +{ + ATRACE_CALL(); + GET_HWC_RETURN_ERROR_IF_NULL(); + int ret = hwc->getActiveConfig(disp); + if (ret == -1) { + WLOGTRACE("failed to get active config of disp %d", disp); + return -EINVAL; + } + + return ret; +} + +static int hwc_setActiveConfig(hwc_composer_device_1_t *dev, int disp, int index) +{ + ATRACE_CALL(); + GET_HWC_RETURN_ERROR_IF_NULL(); + bool ret = hwc->setActiveConfig(disp, index); + if (ret == false) { + WLOGTRACE("failed to set active config of disp %d", disp); + return -EINVAL; + } + + return 0; +} + +static int hwc_setCursorPositionAsync(hwc_composer_device_1_t *dev, int disp, int x, int y) +{ + ATRACE_CALL(); + GET_HWC_RETURN_ERROR_IF_NULL(); + bool ret = hwc->setCursorPositionAsync(disp, x, y); + if (ret == false) { + WLOGTRACE("failed to set cursor position of disp %d", disp); + return -EINVAL; + } + + return 0; +} + +//------------------------------------------------------------------------------ + +static int hwc_device_open(const struct hw_module_t* module, + const char* name, + struct hw_device_t** device) +{ + if (!name) { + ELOGTRACE("invalid name."); + return -EINVAL; + } + + ALOGTRACE("open device %s", name); + + if (strcmp(name, HWC_HARDWARE_COMPOSER) != 0) { + ELOGTRACE("try to open unknown HWComposer %s", name); + return -EINVAL; + } + + Hwcomposer& hwc = Hwcomposer::getInstance(); + // initialize our state here + if (hwc.initialize() == false) { + ELOGTRACE("failed to intialize HWComposer"); + Hwcomposer::releaseInstance(); + return -EINVAL; + } + + // initialize the procs + hwc.hwc_composer_device_1_t::common.tag = HARDWARE_DEVICE_TAG; + hwc.hwc_composer_device_1_t::common.module = + const_cast<hw_module_t*>(module); + hwc.hwc_composer_device_1_t::common.close = hwc_device_close; + + hwc.hwc_composer_device_1_t::prepare = hwc_prepare; + hwc.hwc_composer_device_1_t::set = hwc_set; + hwc.hwc_composer_device_1_t::dump = hwc_dump; + hwc.hwc_composer_device_1_t::registerProcs = hwc_registerProcs; + hwc.hwc_composer_device_1_t::query = hwc_query; + + hwc.hwc_composer_device_1_t::eventControl = hwc_eventControl; + hwc.hwc_composer_device_1_t::getDisplayConfigs = hwc_getDisplayConfigs; + hwc.hwc_composer_device_1_t::getDisplayAttributes = hwc_getDisplayAttributes; + + // This is used to hack FBO switch flush issue in SurfaceFlinger. + hwc.hwc_composer_device_1_t::reserved_proc[0] = (void*)hwc_compositionComplete; + hwc.hwc_composer_device_1_t::common.version = HWC_DEVICE_API_VERSION_1_4; + hwc.hwc_composer_device_1_t::setPowerMode = hwc_setPowerMode; + hwc.hwc_composer_device_1_t::getActiveConfig = hwc_getActiveConfig; + hwc.hwc_composer_device_1_t::setActiveConfig = hwc_setActiveConfig; + // Todo: add hwc_setCursorPositionAsync after supporting patches + hwc.hwc_composer_device_1_t::setCursorPositionAsync = NULL; + + *device = &hwc.hwc_composer_device_1_t::common; + + return 0; +} + +} // namespace intel +} // namespace android + +static struct hw_module_methods_t hwc_module_methods = { + open: android::intel::hwc_device_open +}; + +hwc_module_t HAL_MODULE_INFO_SYM = { + common: { + tag: HARDWARE_MODULE_TAG, + version_major: 1, + version_minor: 4, + id: HWC_HARDWARE_MODULE_ID, + name: "Intel Hardware Composer", + author: "Intel", + methods: &hwc_module_methods, + dso: 0, + reserved: { 0 }, + } +}; diff --git a/moorefield_hdmi/common/base/Hwcomposer.cpp b/moorefield_hdmi/common/base/Hwcomposer.cpp new file mode 100755 index 0000000..eac1448 --- /dev/null +++ b/moorefield_hdmi/common/base/Hwcomposer.cpp @@ -0,0 +1,519 @@ +/* +// 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 <common/utils/HwcTrace.h> +#include <Hwcomposer.h> +#include <common/utils/Dump.h> +#include <UeventObserver.h> + +namespace android { +namespace intel { + +Hwcomposer* Hwcomposer::sInstance(0); + +Hwcomposer::Hwcomposer() + : mProcs(0), + mDrm(0), + mPlaneManager(0), + mBufferManager(0), + mDisplayAnalyzer(0), + mDisplayContext(0), + mUeventObserver(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(); + ALOGTRACE("display count = %d", numDisplays); + + if (!numDisplays || !displays) { + ELOGTRACE("invalid parameters"); + return false; + } + + mDisplayAnalyzer->analyzeContents(numDisplays, displays); + + // disable reclaimed planes + mPlaneManager->disableReclaimedPlanes(); + + // reclaim all allocated planes if possible + for (size_t i = 0; i < numDisplays; i++) { + if (i >= mDisplayDevices.size()) { + continue; + } + IDisplayDevice *device = mDisplayDevices.itemAt(i); + if (!device) { + VLOGTRACE("device %d doesn't exist", i); + continue; + } + device->prePrepare(displays[i]); + } + + for (size_t i = 0; i < numDisplays; i++) { + if (i >= mDisplayDevices.size()) { + continue; + } + IDisplayDevice *device = mDisplayDevices.itemAt(i); + if (!device) { + VLOGTRACE("device %d doesn't exist", i); + continue; + } + ret = device->prepare(displays[i]); + if (ret == false) { + ELOGTRACE("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(); + ALOGTRACE("display count = %d", numDisplays); + + if (!numDisplays || !displays) { + ELOGTRACE("invalid parameters"); + return false; + } + + mDisplayContext->commitBegin(numDisplays, displays); + + for (size_t i = 0; i < numDisplays; i++) { + if (i >= mDisplayDevices.size()) { + continue; + } + IDisplayDevice *device = mDisplayDevices.itemAt(i); + if (!device) { + VLOGTRACE("device %d doesn't exist", i); + continue; + } + + if (!device->isConnected()) { + VLOGTRACE("device %d is disconnected", i); + continue; + } + + ret = device->commit(displays[i], mDisplayContext); + if (ret == false) { + ELOGTRACE("failed to do commit for device %d", i); + continue; + } + } + + mDisplayContext->commitEnd(numDisplays, displays); + // return true always + return true; +} + +bool Hwcomposer::vsyncControl(int disp, int enabled) +{ + RETURN_FALSE_IF_NOT_INIT(); + ALOGTRACE("disp = %d, enabled = %d", disp, enabled); + + if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) { + ELOGTRACE("invalid disp %d", disp); + return false; + } + if (disp >= (int) mDisplayDevices.size()) { + return false; + } + IDisplayDevice *device = mDisplayDevices.itemAt(disp); + if (!device) { + ELOGTRACE("no device found"); + return false; + } + + return device->vsyncControl(enabled ? true : false); +} + +bool Hwcomposer::blank(int disp, int blank) +{ + RETURN_FALSE_IF_NOT_INIT(); + ALOGTRACE("disp = %d, blank = %d", disp, blank); + + if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) { + ELOGTRACE("invalid disp %d", disp); + return false; + } + if (disp >= (int) mDisplayDevices.size()) { + return false; + } + IDisplayDevice *device = mDisplayDevices.itemAt(disp); + if (!device) { + ELOGTRACE("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) { + ELOGTRACE("invalid disp %d", disp); + return false; + } + if (disp >= (int) mDisplayDevices.size()) { + return false; + } + IDisplayDevice *device = mDisplayDevices.itemAt(disp); + if (!device) { + ELOGTRACE("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) { + ELOGTRACE("invalid disp %d", disp); + return false; + } + if (disp >= (int) mDisplayDevices.size()) { + return false; + } + IDisplayDevice *device = mDisplayDevices.itemAt(disp); + if (!device) { + ELOGTRACE("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) { + ELOGTRACE("invalid disp %d", disp); + return false; + } + + mDisplayContext->compositionComplete(); + if (disp >= (int) mDisplayDevices.size()) { + return false; + } + + IDisplayDevice *device = mDisplayDevices.itemAt(disp); + if (!device) { + ELOGTRACE("no device found"); + return false; + } + + return device->compositionComplete(); +} + +bool Hwcomposer::setPowerMode(int disp, int mode) +{ + RETURN_FALSE_IF_NOT_INIT(); + + if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) { + ELOGTRACE("invalid disp %d", disp); + return false; + } + + IDisplayDevice *device = mDisplayDevices.itemAt(disp); + if (!device) { + ELOGTRACE("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) { + ELOGTRACE("invalid disp %d", disp); + return -1; + } + + IDisplayDevice *device = mDisplayDevices.itemAt(disp); + if (!device) { + ELOGTRACE("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) { + ELOGTRACE("invalid disp %d", disp); + return false; + } + + IDisplayDevice *device = mDisplayDevices.itemAt(disp); + if (!device) { + ELOGTRACE("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) { + ELOGTRACE("invalid disp %d", disp); + return false; + } + + return mDisplayContext->setCursorPosition(disp, x, y); +} + +void Hwcomposer::vsync(int disp, int64_t timestamp) +{ + RETURN_VOID_IF_NOT_INIT(); + + if (mProcs && mProcs->vsync) { + VLOGTRACE("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(__attribute__((unused))int disp, bool connected) +{ + RETURN_VOID_IF_NOT_INIT(); + +#ifndef INTEL_SUPPORT_HDMI_PRIMARY + if (mProcs && mProcs->hotplug) { + DLOGTRACE("report hotplug on disp %d, connected %d", disp, connected); + mProcs->hotplug(const_cast<hwc_procs_t*>(mProcs), disp, connected); + DLOGTRACE("hotplug callback processed and returned!"); + } +#endif + + mDisplayAnalyzer->postHotplugEvent(connected); +} + +void Hwcomposer::invalidate() +{ + RETURN_VOID_IF_NOT_INIT(); + + if (mProcs && mProcs->invalidate) { + DLOGTRACE("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) { + WLOGTRACE("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"); + } + + // create buffer manager + mBufferManager = createBufferManager(); + if (!mBufferManager || !mBufferManager->initialize()) { + DEINIT_AND_RETURN_FALSE("failed to create buffer manager"); + } + + // create display plane manager + mPlaneManager = createDisplayPlaneManager(); + if (!mPlaneManager || !mPlaneManager->initialize()) { + DEINIT_AND_RETURN_FALSE("failed to create display plane manager"); + } + + mDisplayContext = 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 + for (int i = 0; i < IDisplayDevice::DEVICE_COUNT; i++) { + IDisplayDevice *device = createDisplayDevice(i, *mPlaneManager); + if (!device || !device->initialize()) { + DEINIT_AND_DELETE_OBJ(device); + DEINIT_AND_RETURN_FALSE("failed to create device %d", i); + } + // add this device + mDisplayDevices.insertAt(device, i, 1); + } + + mDisplayAnalyzer = new DisplayAnalyzer(); + if (!mDisplayAnalyzer || !mDisplayAnalyzer->initialize()) { + DEINIT_AND_RETURN_FALSE("failed to initialize display analyzer"); + } + + // all initialized, starting uevent observer + mUeventObserver->start(); + + mInitialized = true; + return true; +} + +void Hwcomposer::deinitialize() +{ + DEINIT_AND_DELETE_OBJ(mDisplayAnalyzer); + + 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(); + + 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; +} + +IDisplayDevice* Hwcomposer::getDisplayDevice(int disp) +{ + if (disp < 0 || disp >= IDisplayDevice::DEVICE_COUNT) { + ELOGTRACE("invalid disp %d", disp); + return NULL; + } + if (disp >= (int) mDisplayDevices.size()) { + return NULL; + } + return mDisplayDevices.itemAt(disp); +} + +UeventObserver* Hwcomposer::getUeventObserver() +{ + return mUeventObserver; +} + + +} // namespace intel +} // namespace android diff --git a/moorefield_hdmi/common/base/SimpleThread.h b/moorefield_hdmi/common/base/SimpleThread.h new file mode 100644 index 0000000..ade0e84 --- /dev/null +++ b/moorefield_hdmi/common/base/SimpleThread.h @@ -0,0 +1,38 @@ +/* +// 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. +*/ + +#ifndef SIMPLE_THREAD_H +#define SIMPLE_THREAD_H + +#include <utils/threads.h> + +#define DECLARE_THREAD(THREADNAME, THREADOWNER) \ + class THREADNAME: public Thread { \ + public: \ + THREADNAME(THREADOWNER *owner) { mOwner = owner; } \ + THREADNAME() { mOwner = NULL; } \ + private: \ + virtual bool threadLoop() { return mOwner->threadLoop(); } \ + private: \ + THREADOWNER *mOwner; \ + }; \ + friend class THREADNAME; \ + bool threadLoop(); \ + sp<THREADNAME> mThread; + + +#endif /* SIMPLE_THREAD_H */ + |