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