/*
// Copyright (c) 2014 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/
#include <HwcTrace.h>
#include <Hwcomposer.h>
#include <Drm.h>
#include <DisplayPlane.h>
#include <IDisplayDevice.h>
#include <HwcLayerList.h>
#include <tangier/TngDisplayContext.h>
namespace android {
namespace intel {
TngDisplayContext::TngDisplayContext()
: mIMGDisplayDevice(0),
mInitialized(false),
mCount(0)
{
CTRACE();
}
TngDisplayContext::~TngDisplayContext()
{
WARN_IF_NOT_DEINIT();
}
bool TngDisplayContext::initialize()
{
CTRACE();
// open frame buffer device
gralloc_module_t const* module;
int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err) {
ETRACE("failed to load gralloc module, error = %d", err);
return false;
}
// init IMG display device
err = module->perform(module, GRALLOC_MODULE_GET_DISPLAY_DEVICE_IMG, (void **)&mIMGDisplayDevice);
if (err) {
ETRACE("failed to get display device, error = %d", err);
return false;
}
mCount = 0;
mInitialized = true;
return true;
}
bool TngDisplayContext::commitBegin(size_t numDisplays, hwc_display_contents_1_t **displays)
{
RETURN_FALSE_IF_NOT_INIT();
mCount = 0;
return true;
}
bool TngDisplayContext::commitContents(hwc_display_contents_1_t *display, HwcLayerList *layerList)
{
bool ret;
RETURN_FALSE_IF_NOT_INIT();
if (!display || !layerList) {
ETRACE("invalid parameters");
return false;
}
IMG_hwc_layer_t *imgLayerList = (IMG_hwc_layer_t*)mImgLayers;
for (size_t i = 0; i < display->numHwLayers; i++) {
if (mCount >= MAXIMUM_LAYER_NUMBER) {
ETRACE("layer count exceeds the limit");
return false;
}
// check layer parameters
if (!display->hwLayers[i].handle) {
continue;
}
DisplayPlane* plane = layerList->getPlane(i);
if (!plane) {
continue;
}
ret = plane->flip(NULL);
if (ret == false) {
VTRACE("failed to flip plane %d", i);
continue;
}
IMG_hwc_layer_t *imgLayer = &imgLayerList[mCount++];
// update IMG layer
imgLayer->psLayer = &display->hwLayers[i];
imgLayer->custom = (unsigned long)plane->getContext();
struct intel_dc_plane_ctx *ctx =
(struct intel_dc_plane_ctx *)imgLayer->custom;
// update z order
Hwcomposer& hwc = Hwcomposer::getInstance();
DisplayPlaneManager *pm = hwc.getPlaneManager();
void *config = pm->getZOrderConfig();
if (config) {
memcpy(&ctx->zorder, config, sizeof(ctx->zorder));
} else {
memset(&ctx->zorder, 0, sizeof(ctx->zorder));
}
VTRACE("count %p, handle %#x, trans %#x, blending %#x"
" sourceCrop %f,%f - %fx%f, dst %d,%d - %dx%d, custom %#x",
mCount,
imgLayer->psLayer->handle,
imgLayer->psLayer->transform,
imgLayer->psLayer->blending,
imgLayer->psLayer->sourceCropf.left,
imgLayer->psLayer->sourceCropf.top,
imgLayer->psLayer->sourceCropf.right - imgLayer->psLayer->sourceCropf.left,
imgLayer->psLayer->sourceCropf.bottom - imgLayer->psLayer->sourceCropf.top,
imgLayer->psLayer->displayFrame.left,
imgLayer->psLayer->displayFrame.top,
imgLayer->psLayer->displayFrame.right - imgLayer->psLayer->displayFrame.left,
imgLayer->psLayer->displayFrame.bottom - imgLayer->psLayer->displayFrame.top,
imgLayer->custom);
}
layerList->postFlip();
return true;
}
bool TngDisplayContext::commitEnd(size_t numDisplays, hwc_display_contents_1_t **displays)
{
int releaseFenceFd = -1;
VTRACE("count = %d", mCount);
if (mIMGDisplayDevice && mCount) {
int err = mIMGDisplayDevice->post(mIMGDisplayDevice,
mImgLayers,
mCount,
&releaseFenceFd);
if (err) {
ETRACE("post failed, err = %d", err);
return false;
}
}
// close acquire fence
for (size_t i = 0; i < numDisplays; i++) {
// Wait and close HWC_OVERLAY typed layer's acquire fence
hwc_display_contents_1_t* display = displays[i];
if (!display) {
continue;
}
for (size_t j = 0; j < display->numHwLayers-1; j++) {
hwc_layer_1_t& layer = display->hwLayers[j];
if (layer.compositionType == HWC_OVERLAY) {
if (layer.acquireFenceFd != -1) {
// sync_wait(layer.acquireFenceFd, 16ms);
close(layer.acquireFenceFd);
layer.acquireFenceFd = -1;
}
}
}
// Wait and close framebuffer target layer's acquire fence
hwc_layer_1_t& fbt = display->hwLayers[display->numHwLayers-1];
if (fbt.acquireFenceFd != -1) {
// sync_wait(fbt.acquireFencdFd, 16ms);
close(fbt.acquireFenceFd);
fbt.acquireFenceFd = -1;
}
// Wait and close outbuf's acquire fence
if (display->outbufAcquireFenceFd != -1) {
// sync_wait(display->outbufAcquireFenceFd, 16ms);
close(display->outbufAcquireFenceFd);
display->outbufAcquireFenceFd = -1;
}
}
// update release fence and retire fence
if (mCount > 0) {
// For physical displays, dup the releaseFenceFd only for
// HWC layers which successfully flipped to display planes
IMG_hwc_layer_t *imgLayerList = (IMG_hwc_layer_t*)mImgLayers;
for (unsigned int i = 0; i < mCount; i++) {
IMG_hwc_layer_t *imgLayer = &imgLayerList[i];
imgLayer->psLayer->releaseFenceFd =
(releaseFenceFd != -1) ? dup(releaseFenceFd) : -1;
}
}
for (size_t i = 0; i < numDisplays; i++) {
if (!displays[i]) {
continue;
}
// log for layer fence status
for (size_t j = 0; j < displays[i]->numHwLayers; j++) {
VTRACE("handle %#p, acquiredFD %d, releaseFD %d",
displays[i]->hwLayers[j].handle,
displays[i]->hwLayers[j].acquireFenceFd,
displays[i]->hwLayers[j].releaseFenceFd);
}
// retireFence is used for SurfaceFlinger to do DispSync;
// dup releaseFenceFd for physical displays and ignore virtual
// display; we don't distinguish between release and retire, and all
// physical displays are using a single releaseFence; for virtual
// display, fencing is handled by the VirtualDisplay class
if (i < IDisplayDevice::DEVICE_VIRTUAL) {
displays[i]->retireFenceFd =
(releaseFenceFd != -1) ? dup(releaseFenceFd) : -1;
}
}
// close original release fence fd
if (releaseFenceFd != -1) {
close(releaseFenceFd);
}
return true;
}
bool TngDisplayContext::compositionComplete()
{
return true;
}
bool TngDisplayContext::setCursorPosition(int disp, int x, int y)
{
DTRACE("setCursorPosition");
struct intel_dc_cursor_ctx ctx;
memset(&ctx, 0, sizeof(ctx));
ctx.pipe = disp;
if (x < 0) {
ctx.pos |= 1 << 15;
x = -x;
}
if (y < 0) {
ctx.pos |= 1 << 31;
y = -y;
}
ctx.pos |= (y & 0xfff) << 16 | (x & 0xfff);
Drm *drm = Hwcomposer::getInstance().getDrm();
return drm->writeIoctl(DRM_PSB_UPDATE_CURSOR_POS, &ctx, sizeof(ctx));
}
void TngDisplayContext::deinitialize()
{
mIMGDisplayDevice = 0;
mCount = 0;
mInitialized = false;
}
} // namespace intel
} // namespace android