|
|
/* |
|
|
// 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 <utils/String8.h> |
|
|
#include <anniedale/AnnPlaneManager.h> |
|
|
#include <anniedale/AnnRGBPlane.h> |
|
|
#include <anniedale/AnnOverlayPlane.h> |
|
|
#include <anniedale/AnnCursorPlane.h> |
|
|
#include <PlaneCapabilities.h> |
|
|
|
|
|
namespace android { |
|
|
namespace intel { |
|
|
|
|
|
|
|
|
struct PlaneDescription { |
|
|
char nickname; |
|
|
int type; |
|
|
int index; |
|
|
}; |
|
|
|
|
|
|
|
|
static PlaneDescription PLANE_DESC[] = |
|
|
{ |
|
|
// nickname must be continous and start with 'A', |
|
|
// it is used to fast locate plane index and type |
|
|
{'A', DisplayPlane::PLANE_PRIMARY, 0}, |
|
|
{'B', DisplayPlane::PLANE_PRIMARY, 1}, |
|
|
{'C', DisplayPlane::PLANE_PRIMARY, 2}, |
|
|
{'D', DisplayPlane::PLANE_SPRITE, 0}, |
|
|
{'E', DisplayPlane::PLANE_SPRITE, 1}, |
|
|
{'F', DisplayPlane::PLANE_SPRITE, 2}, |
|
|
{'G', DisplayPlane::PLANE_OVERLAY, 0}, // nickname for Overlay A |
|
|
{'H', DisplayPlane::PLANE_OVERLAY, 1}, // nickname for Overlay C |
|
|
{'I', DisplayPlane::PLANE_CURSOR, 0}, // nickname for cursor A |
|
|
{'J', DisplayPlane::PLANE_CURSOR, 1}, // nickname for cursor B |
|
|
{'K', DisplayPlane::PLANE_CURSOR, 2} // nickname for cursor C |
|
|
}; |
|
|
|
|
|
|
|
|
struct ZOrderDescription { |
|
|
int index; // based on overlay position |
|
|
const char *zorder; |
|
|
}; |
|
|
|
|
|
// If overlay is in the bottom of Z order, two legitimate combinations are Oa, D, E, F |
|
|
// and Oc, D, E, F. However, plane A has to be part of the blending chain as it can't |
|
|
// be disabled [HW bug]. The only legitimate combinations including overlay and plane A is: |
|
|
// A, Oa, E, F |
|
|
// A, Oc, E, F |
|
|
// Cursor plane can be placed on top of any plane below and is intentionally ignored |
|
|
// in the zorder table. |
|
|
|
|
|
// video mode panel doesn't need the primay plane A always on hack |
|
|
static ZOrderDescription PIPE_A_ZORDER_DESC_VID[] = |
|
|
{ |
|
|
{0, "ADEF"}, // no overlay |
|
|
{1, "GDEF"}, // overlay A at bottom (1 << 0) |
|
|
{1, "HDEF"}, // overlay C at bottom (1 << 0) |
|
|
{2, "AGEF"}, // overlay A at next to bottom (1 << 1) |
|
|
{2, "AHEF"}, // overlay C at next to bottom (1 << 1) |
|
|
{3, "GHEF"}, // overlay A, C at bottom |
|
|
{4, "ADGF"}, // overlay A at next to top (1 << 2) |
|
|
{4, "ADHF"}, // overlay C at next to top (1 << 2) |
|
|
{6, "AGHF"}, // overlay A, C in between |
|
|
{8, "ADEG"}, // overlay A at top (1 << 3) |
|
|
{8, "ADEH"}, // overlay C at top (1 <<3) |
|
|
{12, "ADGH"} // overlay A, C at top |
|
|
}; |
|
|
|
|
|
static ZOrderDescription PIPE_A_ZORDER_DESC_CMD[] = |
|
|
{ |
|
|
{0, "ADEF"}, // no overlay |
|
|
{1, "GEF"}, // overlay A at bottom (1 << 0) |
|
|
{1, "HEF"}, // overlay C at bottom (1 << 0) |
|
|
{2, "AGEF"}, // overlay A at next to bottom (1 << 1) |
|
|
{2, "AHEF"}, // overlay C at next to bottom (1 << 1) |
|
|
{3, "GHF"}, // overlay A, C at bottom |
|
|
{4, "ADGF"}, // overlay A at next to top (1 << 2) |
|
|
{4, "ADHF"}, // overlay C at next to top (1 << 2) |
|
|
{6, "AGHF"}, // overlay A, C in between |
|
|
{8, "ADEG"}, // overlay A at top (1 << 3) |
|
|
{8, "ADEH"}, // overlay C at top (1 <<3) |
|
|
{12, "ADGH"} // overlay A, C at top |
|
|
}; |
|
|
|
|
|
// use overlay C over overlay A if possible on pipe B |
|
|
static ZOrderDescription PIPE_B_ZORDER_DESC[] = |
|
|
{ |
|
|
{0, "BD"}, // no overlay |
|
|
{1, "HBD"}, // overlay C at bottom (1 << 0) |
|
|
// {1, "GBD"}, // overlay A at bottom (1 << 0), overlay A don`t switch to pipeB and only overlay C on pipeB |
|
|
{2, "BHD"}, // overlay C at middle (1 << 1) |
|
|
// {2, "BGD"}, // overlay A at middle (1 << 1), overlay A don`t switch to pipeB and only overaly C on pipeB |
|
|
{3, "GHBD"}, // overlay A and C at bottom ( 1 << 0 + 1 << 1) |
|
|
{4, "BDH"}, // overlay C at top (1 << 2) |
|
|
{4, "BDG"}, // overlay A at top (1 << 2) |
|
|
{6, "BGHD"}, // overlay A/C at middle 1 << 1 + 1 << 2) |
|
|
{12, "BDGH"} // overlay A/C at top (1 << 2 + 1 << 3) |
|
|
}; |
|
|
|
|
|
static ZOrderDescription *PIPE_A_ZORDER_TBL; |
|
|
static int PIPE_A_ZORDER_COMBINATIONS; |
|
|
static ZOrderDescription *PIPE_B_ZORDER_TBL; |
|
|
static int PIPE_B_ZORDER_COMBINATIONS; |
|
|
static bool OVERLAY_HW_WORKAROUND; |
|
|
|
|
|
AnnPlaneManager::AnnPlaneManager() |
|
|
: DisplayPlaneManager() |
|
|
{ |
|
|
} |
|
|
|
|
|
AnnPlaneManager::~AnnPlaneManager() |
|
|
{ |
|
|
} |
|
|
|
|
|
bool AnnPlaneManager::initialize() |
|
|
{ |
|
|
mSpritePlaneCount = 3; // Sprite D, E, F |
|
|
mOverlayPlaneCount = 2; // Overlay A, C |
|
|
mPrimaryPlaneCount = 3; // Primary A, B, C |
|
|
mCursorPlaneCount = 3; |
|
|
|
|
|
uint32_t videoMode = 0; |
|
|
Drm *drm = Hwcomposer::getInstance().getDrm(); |
|
|
drm->readIoctl(DRM_PSB_PANEL_QUERY, &videoMode, sizeof(uint32_t)); |
|
|
if (videoMode == 1) { |
|
|
DTRACE("video mode panel, no primay A always on hack"); |
|
|
PIPE_A_ZORDER_TBL = PIPE_A_ZORDER_DESC_VID; |
|
|
PIPE_A_ZORDER_COMBINATIONS = |
|
|
sizeof(PIPE_A_ZORDER_DESC_VID)/sizeof(ZOrderDescription); |
|
|
} else { |
|
|
DTRACE("command mode panel, need primay A always on hack"); |
|
|
PIPE_A_ZORDER_TBL = PIPE_A_ZORDER_DESC_CMD; |
|
|
PIPE_A_ZORDER_COMBINATIONS = |
|
|
sizeof(PIPE_A_ZORDER_DESC_CMD)/sizeof(ZOrderDescription); |
|
|
OVERLAY_HW_WORKAROUND = true; |
|
|
} |
|
|
|
|
|
PIPE_B_ZORDER_TBL = PIPE_B_ZORDER_DESC; |
|
|
PIPE_B_ZORDER_COMBINATIONS = |
|
|
sizeof(PIPE_B_ZORDER_DESC)/sizeof(ZOrderDescription); |
|
|
|
|
|
return DisplayPlaneManager::initialize(); |
|
|
} |
|
|
|
|
|
void AnnPlaneManager::deinitialize() |
|
|
{ |
|
|
DisplayPlaneManager::deinitialize(); |
|
|
} |
|
|
|
|
|
DisplayPlane* AnnPlaneManager::allocPlane(int index, int type) |
|
|
{ |
|
|
DisplayPlane *plane = NULL; |
|
|
|
|
|
switch (type) { |
|
|
case DisplayPlane::PLANE_PRIMARY: |
|
|
plane = new AnnRGBPlane(index, DisplayPlane::PLANE_PRIMARY, index/*disp*/); |
|
|
break; |
|
|
case DisplayPlane::PLANE_SPRITE: |
|
|
plane = new AnnRGBPlane(index, DisplayPlane::PLANE_SPRITE, 0/*disp*/); |
|
|
break; |
|
|
case DisplayPlane::PLANE_OVERLAY: |
|
|
plane = new AnnOverlayPlane(index, 0/*disp*/); |
|
|
break; |
|
|
case DisplayPlane::PLANE_CURSOR: |
|
|
plane = new AnnCursorPlane(index, index /*disp */); |
|
|
break; |
|
|
default: |
|
|
ETRACE("unsupported type %d", type); |
|
|
break; |
|
|
} |
|
|
|
|
|
if (plane && !plane->initialize(DisplayPlane::MIN_DATA_BUFFER_COUNT)) { |
|
|
ETRACE("failed to initialize plane."); |
|
|
DEINIT_AND_DELETE_OBJ(plane); |
|
|
} |
|
|
|
|
|
return plane; |
|
|
} |
|
|
|
|
|
bool AnnPlaneManager::isValidZOrder(int dsp, ZOrderConfig& config) |
|
|
{ |
|
|
int size = (int)config.size(); |
|
|
bool hasCursor = false; |
|
|
|
|
|
for (int i = 0; i < size; i++) { |
|
|
if (config[i]->planeType == DisplayPlane::PLANE_CURSOR) { |
|
|
hasCursor = true; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
if (size <= 0 || |
|
|
(hasCursor && size > 5) || |
|
|
(!hasCursor && size > 4)) { |
|
|
VTRACE("invalid z order config size %d", size); |
|
|
return false; |
|
|
} |
|
|
|
|
|
if (dsp == IDisplayDevice::DEVICE_PRIMARY) { |
|
|
int firstOverlay = -1; |
|
|
for (int i = 0; i < size; i++) { |
|
|
if (config[i]->planeType == DisplayPlane::PLANE_OVERLAY) { |
|
|
firstOverlay = i; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
int sprites = 0; |
|
|
for (int i = 0; i < size; i++) { |
|
|
if (config[i]->planeType != DisplayPlane::PLANE_OVERLAY && |
|
|
config[i]->planeType != DisplayPlane::PLANE_CURSOR) { |
|
|
sprites++; |
|
|
} |
|
|
} |
|
|
|
|
|
if (firstOverlay < 0 && sprites > 4) { |
|
|
VTRACE("not capable to support more than 4 sprite layers"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
if (OVERLAY_HW_WORKAROUND) { |
|
|
if (firstOverlay == 0 && size > 2) { |
|
|
VTRACE("can not support 3 sprite layers on top of overlay"); |
|
|
return false; |
|
|
} |
|
|
} |
|
|
} else if (dsp == IDisplayDevice::DEVICE_EXTERNAL) { |
|
|
int sprites = 0; |
|
|
for (int i = 0; i < size; i++) { |
|
|
if (config[i]->planeType != DisplayPlane::PLANE_OVERLAY && |
|
|
config[i]->planeType != DisplayPlane::PLANE_CURSOR) { |
|
|
sprites++; |
|
|
} |
|
|
} |
|
|
if (sprites > 2) { |
|
|
ETRACE("number of sprite: %d, maximum 1 sprite and 1 primary supported on pipe 1", sprites); |
|
|
return false; |
|
|
} |
|
|
} else { |
|
|
ETRACE("invalid display device %d", dsp); |
|
|
return false; |
|
|
} |
|
|
return true; |
|
|
} |
|
|
|
|
|
bool AnnPlaneManager::assignPlanes(int dsp, ZOrderConfig& config) |
|
|
{ |
|
|
if (dsp < 0 || dsp > IDisplayDevice::DEVICE_EXTERNAL) { |
|
|
ETRACE("invalid display device %d", dsp); |
|
|
return false; |
|
|
} |
|
|
|
|
|
int size = (int)config.size(); |
|
|
|
|
|
// calculate index based on overlay Z order position |
|
|
int index = 0; |
|
|
for (int i = 0; i < size; i++) { |
|
|
if (config[i]->planeType == DisplayPlane::PLANE_OVERLAY) { |
|
|
index += (1 << i); |
|
|
} |
|
|
} |
|
|
|
|
|
int combinations; |
|
|
ZOrderDescription *table; |
|
|
if (dsp == IDisplayDevice::DEVICE_PRIMARY) { |
|
|
combinations = PIPE_A_ZORDER_COMBINATIONS; |
|
|
table = PIPE_A_ZORDER_TBL; |
|
|
} else { |
|
|
combinations = PIPE_B_ZORDER_COMBINATIONS; |
|
|
table = PIPE_B_ZORDER_TBL; |
|
|
} |
|
|
|
|
|
for (int i = 0; i < combinations; i++) { |
|
|
ZOrderDescription *zorderDesc = table + i; |
|
|
|
|
|
if (zorderDesc->index != index) |
|
|
continue; |
|
|
|
|
|
if (assignPlanes(dsp, config, zorderDesc->zorder)) { |
|
|
VTRACE("zorder assigned %s", zorderDesc->zorder); |
|
|
return true; |
|
|
} |
|
|
} |
|
|
return false; |
|
|
} |
|
|
|
|
|
bool AnnPlaneManager::assignPlanes(int dsp, ZOrderConfig& config, const char *zorder) |
|
|
{ |
|
|
// zorder string does not include cursor plane, therefore cursor layer needs to be handled |
|
|
// in a special way. Cursor layer must be on top of zorder and no more than one cursor layer. |
|
|
|
|
|
int size = (int)config.size(); |
|
|
if (zorder == NULL || size == 0) { |
|
|
//DTRACE("invalid zorder or ZOrder config."); |
|
|
return false; |
|
|
} |
|
|
|
|
|
int zorderLen = (int)strlen(zorder); |
|
|
|
|
|
// test if plane is avalable |
|
|
for (int i = 0; i < size; i++) { |
|
|
if (config[i]->planeType == DisplayPlane::PLANE_CURSOR) { |
|
|
if (i != size - 1) { |
|
|
ETRACE("invalid zorder of cursor layer"); |
|
|
return false; |
|
|
} |
|
|
PlaneDescription& desc = PLANE_DESC['I' - 'A' + dsp]; |
|
|
if (!isFreePlane(desc.type, desc.index)) { |
|
|
ETRACE("cursor plane is not available"); |
|
|
return false; |
|
|
} |
|
|
continue; |
|
|
} |
|
|
if (i >= zorderLen) { |
|
|
DTRACE("index of ZOrderConfig is out of bound"); |
|
|
return false; |
|
|
} |
|
|
|
|
|
char id = *(zorder + i); |
|
|
PlaneDescription& desc = PLANE_DESC[id - 'A']; |
|
|
if (!isFreePlane(desc.type, desc.index)) { |
|
|
DTRACE("plane type %d index %d is not available", desc.type, desc.index); |
|
|
return false; |
|
|
} |
|
|
|
|
|
#if 0 |
|
|
// plane type check |
|
|
if (config[i]->planeType == DisplayPlane::PLANE_OVERLAY && |
|
|
desc.type != DisplayPlane::PLANE_OVERLAY) { |
|
|
ETRACE("invalid plane type %d, expected %d", desc.type, config[i]->planeType); |
|
|
return false; |
|
|
} |
|
|
|
|
|
if (config[i]->planeType != DisplayPlane::PLANE_OVERLAY) { |
|
|
if (config[i]->planeType != DisplayPlane::PLANE_PRIMARY && |
|
|
config[i]->planeType != DisplayPlane::PLANE_SPRITE) { |
|
|
ETRACE("invalid plane type %d,", config[i]->planeType); |
|
|
return false; |
|
|
} |
|
|
if (desc.type != DisplayPlane::PLANE_PRIMARY && |
|
|
desc.type != DisplayPlane::PLANE_SPRITE) { |
|
|
ETRACE("invalid plane type %d, expected %d", desc.type, config[i]->planeType); |
|
|
return false; |
|
|
} |
|
|
} |
|
|
#endif |
|
|
|
|
|
if (desc.type == DisplayPlane::PLANE_OVERLAY && desc.index == 1 && |
|
|
config[i]->hwcLayer->getTransform() != 0) { |
|
|
DTRACE("overlay C does not support transform"); |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
bool primaryPlaneActive = false; |
|
|
// allocate planes |
|
|
for (int i = 0; i < size; i++) { |
|
|
if (config[i]->planeType == DisplayPlane::PLANE_CURSOR) { |
|
|
PlaneDescription& desc = PLANE_DESC['I' - 'A' + dsp]; |
|
|
ZOrderLayer *zLayer = config.itemAt(i); |
|
|
zLayer->plane = getPlane(desc.type, desc.index); |
|
|
if (zLayer->plane == NULL) { |
|
|
ETRACE("failed to get cursor plane, should never happen!"); |
|
|
} |
|
|
continue; |
|
|
} |
|
|
|
|
|
char id = *(zorder + i); |
|
|
PlaneDescription& desc = PLANE_DESC[id - 'A']; |
|
|
ZOrderLayer *zLayer = config.itemAt(i); |
|
|
zLayer->plane = getPlane(desc.type, desc.index); |
|
|
if (zLayer->plane == NULL) { |
|
|
ETRACE("failed to get plane, should never happen!"); |
|
|
} |
|
|
// override type |
|
|
zLayer->planeType = desc.type; |
|
|
if (desc.type == DisplayPlane::PLANE_PRIMARY) { |
|
|
primaryPlaneActive = true; |
|
|
} |
|
|
} |
|
|
|
|
|
// setup Z order |
|
|
int slot = 0; |
|
|
for (int i = 0; i < size; i++) { |
|
|
slot = i; |
|
|
|
|
|
if (OVERLAY_HW_WORKAROUND) { |
|
|
if (!primaryPlaneActive && |
|
|
config[i]->planeType == DisplayPlane::PLANE_OVERLAY) { |
|
|
slot += 1; |
|
|
} |
|
|
} |
|
|
|
|
|
config[i]->plane->setZOrderConfig(config, (void *)(unsigned long)slot); |
|
|
config[i]->plane->enable(); |
|
|
} |
|
|
|
|
|
#if 0 |
|
|
DTRACE("config size %d, zorder %s", size, zorder); |
|
|
for (int i = 0; i < size; i++) { |
|
|
const ZOrderLayer *l = config.itemAt(i); |
|
|
ITRACE("%d: plane type %d, index %d, zorder %d", |
|
|
i, l->planeType, l->plane->getIndex(), l->zorder); |
|
|
} |
|
|
#endif |
|
|
|
|
|
return true; |
|
|
} |
|
|
|
|
|
void* AnnPlaneManager::getZOrderConfig() const |
|
|
{ |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
int AnnPlaneManager::getFreePlanes(int dsp, int type) |
|
|
{ |
|
|
RETURN_NULL_IF_NOT_INIT(); |
|
|
|
|
|
if (type != DisplayPlane::PLANE_SPRITE) { |
|
|
return DisplayPlaneManager::getFreePlanes(dsp, type); |
|
|
} |
|
|
|
|
|
if (dsp < 0 || dsp > IDisplayDevice::DEVICE_EXTERNAL) { |
|
|
ETRACE("invalid display device %d", dsp); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
uint32_t freePlanes = mFreePlanes[type] | mReclaimedPlanes[type]; |
|
|
int start = 0; |
|
|
int stop = mSpritePlaneCount; |
|
|
if (dsp == IDisplayDevice::DEVICE_EXTERNAL) { |
|
|
// only Sprite D (index 0) can be assigned to pipe 1 |
|
|
// Sprites E/F (index 1, 2) are fixed on pipe 0 |
|
|
stop = 1; |
|
|
} |
|
|
int count = 0; |
|
|
for (int i = start; i < stop; i++) { |
|
|
if ((1 << i) & freePlanes) { |
|
|
count++; |
|
|
} |
|
|
} |
|
|
return count; |
|
|
} |
|
|
|
|
|
} // namespace intel |
|
|
} // namespace android |
|
|
|
|
|
|