C++程序  |  462行  |  14.61 KB

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