1/*
2// Copyright (c) 2014 Intel Corporation 
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#include <HwcTrace.h>
17#include <utils/String8.h>
18#include <anniedale/AnnPlaneManager.h>
19#include <anniedale/AnnRGBPlane.h>
20#include <anniedale/AnnOverlayPlane.h>
21#include <anniedale/AnnCursorPlane.h>
22#include <PlaneCapabilities.h>
23
24namespace android {
25namespace intel {
26
27
28struct PlaneDescription {
29    char nickname;
30    int type;
31    int index;
32};
33
34
35static PlaneDescription PLANE_DESC[] =
36{
37    // nickname must be continous and start with 'A',
38    // it is used to fast locate plane index and type
39    {'A', DisplayPlane::PLANE_PRIMARY, 0},
40    {'B', DisplayPlane::PLANE_PRIMARY, 1},
41    {'C', DisplayPlane::PLANE_PRIMARY, 2},
42    {'D', DisplayPlane::PLANE_SPRITE,  0},
43    {'E', DisplayPlane::PLANE_SPRITE,  1},
44    {'F', DisplayPlane::PLANE_SPRITE,  2},
45    {'G', DisplayPlane::PLANE_OVERLAY, 0},  // nickname for Overlay A
46    {'H', DisplayPlane::PLANE_OVERLAY, 1},   // nickname for Overlay C
47    {'I', DisplayPlane::PLANE_CURSOR,  0},  // nickname for cursor A
48    {'J', DisplayPlane::PLANE_CURSOR,  1},  // nickname for cursor B
49    {'K', DisplayPlane::PLANE_CURSOR,  2}   // nickname for cursor C
50};
51
52
53struct ZOrderDescription {
54    int index;  // based on overlay position
55    const char *zorder;
56};
57
58// If overlay is in the bottom of Z order, two legitimate combinations are Oa, D, E, F
59// and Oc, D, E, F. However, plane A has to be part of the blending chain as it can't
60//  be disabled [HW bug]. The only legitimate combinations including overlay and plane A is:
61// A, Oa, E, F
62// A, Oc, E, F
63// Cursor plane can be placed on top of any plane below and is intentionally ignored
64// in the zorder table.
65
66// video mode panel doesn't need the primay plane A always on hack
67static ZOrderDescription PIPE_A_ZORDER_DESC_VID[] =
68{
69    {0, "ADEF"},  // no overlay
70    {1, "GDEF"},  // overlay A at bottom (1 << 0)
71    {1, "HDEF"},  // overlay C at bottom (1 << 0)
72    {2, "AGEF"},  // overlay A at next to bottom (1 << 1)
73    {2, "AHEF"},  // overlay C at next to bottom (1 << 1)
74    {3, "GHEF"},  // overlay A, C at bottom
75    {4, "ADGF"},  // overlay A at next to top (1 << 2)
76    {4, "ADHF"},  // overlay C at next to top (1 << 2)
77    {6, "AGHF"},  // overlay A, C in between
78    {8, "ADEG"},  // overlay A at top (1 << 3)
79    {8, "ADEH"},  // overlay C at top (1 <<3)
80    {12, "ADGH"}  // overlay A, C at top
81};
82
83static ZOrderDescription PIPE_A_ZORDER_DESC_CMD[] =
84{
85    {0, "ADEF"},  // no overlay
86    {1, "GEF"},  // overlay A at bottom (1 << 0)
87    {1, "HEF"},  // overlay C at bottom (1 << 0)
88    {2, "AGEF"},  // overlay A at next to bottom (1 << 1)
89    {2, "AHEF"},  // overlay C at next to bottom (1 << 1)
90    {3, "GHF"},   // overlay A, C at bottom
91    {4, "ADGF"},  // overlay A at next to top (1 << 2)
92    {4, "ADHF"},  // overlay C at next to top (1 << 2)
93    {6, "AGHF"},  // overlay A, C in between
94    {8, "ADEG"},  // overlay A at top (1 << 3)
95    {8, "ADEH"},  // overlay C at top (1 <<3)
96    {12, "ADGH"}  // overlay A, C at top
97};
98
99// use overlay C over overlay A if possible on pipe B
100static ZOrderDescription PIPE_B_ZORDER_DESC[] =
101{
102    {0, "BD"},    // no overlay
103    {1, "HBD"},   // overlay C at bottom (1 << 0)
104//    {1, "GBD"},   // overlay A at bottom (1 << 0), overlay A don`t switch to pipeB and only overlay C on pipeB
105    {2, "BHD"},   // overlay C at middle (1 << 1)
106//   {2, "BGD"},   // overlay A at middle (1 << 1), overlay A don`t switch to pipeB and only overaly C on pipeB
107    {3, "GHBD"},  // overlay A and C at bottom ( 1 << 0 + 1 << 1)
108    {4, "BDH"},   // overlay C at top (1 << 2)
109    {4, "BDG"},   // overlay A at top (1 << 2)
110    {6, "BGHD"},  // overlay A/C at middle  1 << 1 + 1 << 2)
111    {12, "BDGH"}  // overlay A/C at top (1 << 2 + 1 << 3)
112};
113
114static ZOrderDescription *PIPE_A_ZORDER_TBL;
115static int PIPE_A_ZORDER_COMBINATIONS;
116static ZOrderDescription *PIPE_B_ZORDER_TBL;
117static int PIPE_B_ZORDER_COMBINATIONS;
118static bool OVERLAY_HW_WORKAROUND;
119
120AnnPlaneManager::AnnPlaneManager()
121    : DisplayPlaneManager()
122{
123}
124
125AnnPlaneManager::~AnnPlaneManager()
126{
127}
128
129bool AnnPlaneManager::initialize()
130{
131    mSpritePlaneCount = 3;  // Sprite D, E, F
132    mOverlayPlaneCount = 2; // Overlay A, C
133    mPrimaryPlaneCount = 3; // Primary A, B, C
134    mCursorPlaneCount = 3;
135
136    uint32_t videoMode = 0;
137    Drm *drm = Hwcomposer::getInstance().getDrm();
138    drm->readIoctl(DRM_PSB_PANEL_QUERY, &videoMode, sizeof(uint32_t));
139    if (videoMode == 1) {
140        DTRACE("video mode panel, no primay A always on hack");
141        PIPE_A_ZORDER_TBL = PIPE_A_ZORDER_DESC_VID;
142        PIPE_A_ZORDER_COMBINATIONS =
143            sizeof(PIPE_A_ZORDER_DESC_VID)/sizeof(ZOrderDescription);
144    } else {
145        DTRACE("command mode panel, need primay A always on hack");
146        PIPE_A_ZORDER_TBL = PIPE_A_ZORDER_DESC_CMD;
147        PIPE_A_ZORDER_COMBINATIONS =
148            sizeof(PIPE_A_ZORDER_DESC_CMD)/sizeof(ZOrderDescription);
149	OVERLAY_HW_WORKAROUND = true;
150    }
151
152    PIPE_B_ZORDER_TBL = PIPE_B_ZORDER_DESC;
153    PIPE_B_ZORDER_COMBINATIONS =
154        sizeof(PIPE_B_ZORDER_DESC)/sizeof(ZOrderDescription);
155
156    return DisplayPlaneManager::initialize();
157}
158
159void AnnPlaneManager::deinitialize()
160{
161    DisplayPlaneManager::deinitialize();
162}
163
164DisplayPlane* AnnPlaneManager::allocPlane(int index, int type)
165{
166    DisplayPlane *plane = NULL;
167
168    switch (type) {
169    case DisplayPlane::PLANE_PRIMARY:
170        plane = new AnnRGBPlane(index, DisplayPlane::PLANE_PRIMARY, index/*disp*/);
171        break;
172    case DisplayPlane::PLANE_SPRITE:
173        plane = new AnnRGBPlane(index, DisplayPlane::PLANE_SPRITE, 0/*disp*/);
174        break;
175    case DisplayPlane::PLANE_OVERLAY:
176        plane = new AnnOverlayPlane(index, 0/*disp*/);
177        break;
178    case DisplayPlane::PLANE_CURSOR:
179        plane = new AnnCursorPlane(index, index /*disp */);
180        break;
181    default:
182        ETRACE("unsupported type %d", type);
183        break;
184    }
185
186    if (plane && !plane->initialize(DisplayPlane::MIN_DATA_BUFFER_COUNT)) {
187        ETRACE("failed to initialize plane.");
188        DEINIT_AND_DELETE_OBJ(plane);
189    }
190
191    return plane;
192}
193
194bool AnnPlaneManager::isValidZOrder(int dsp, ZOrderConfig& config)
195{
196    int size = (int)config.size();
197    bool hasCursor = false;
198
199    for (int i = 0; i < size; i++) {
200        if (config[i]->planeType == DisplayPlane::PLANE_CURSOR) {
201            hasCursor = true;
202            break;
203        }
204    }
205
206    if (size <= 0 ||
207        (hasCursor && size > 5) ||
208        (!hasCursor && size > 4)) {
209        VTRACE("invalid z order config size %d", size);
210        return false;
211    }
212
213    if (dsp == IDisplayDevice::DEVICE_PRIMARY) {
214        int firstOverlay = -1;
215        for (int i = 0; i < size; i++) {
216            if (config[i]->planeType == DisplayPlane::PLANE_OVERLAY) {
217                firstOverlay = i;
218                break;
219            }
220        }
221
222        int sprites = 0;
223        for (int i = 0; i < size; i++) {
224            if (config[i]->planeType != DisplayPlane::PLANE_OVERLAY &&
225                config[i]->planeType != DisplayPlane::PLANE_CURSOR) {
226                sprites++;
227            }
228        }
229
230        if (firstOverlay < 0 && sprites > 4) {
231            VTRACE("not capable to support more than 4 sprite layers");
232            return false;
233        }
234
235        if (OVERLAY_HW_WORKAROUND) {
236            if (firstOverlay == 0 && size > 2) {
237                VTRACE("can not support 3 sprite layers on top of overlay");
238                return false;
239            }
240        }
241    } else if (dsp == IDisplayDevice::DEVICE_EXTERNAL) {
242        int sprites = 0;
243        for (int i = 0; i < size; i++) {
244            if (config[i]->planeType != DisplayPlane::PLANE_OVERLAY &&
245                config[i]->planeType != DisplayPlane::PLANE_CURSOR) {
246                sprites++;
247            }
248        }
249        if (sprites > 2) {
250            ETRACE("number of sprite: %d, maximum 1 sprite and 1 primary supported on pipe 1", sprites);
251            return false;
252        }
253    } else {
254        ETRACE("invalid display device %d", dsp);
255        return false;
256    }
257    return true;
258}
259
260bool AnnPlaneManager::assignPlanes(int dsp, ZOrderConfig& config)
261{
262    if (dsp < 0 || dsp > IDisplayDevice::DEVICE_EXTERNAL) {
263        ETRACE("invalid display device %d", dsp);
264        return false;
265    }
266
267    int size = (int)config.size();
268
269    // calculate index based on overlay Z order position
270    int index = 0;
271    for (int i = 0; i < size; i++) {
272        if (config[i]->planeType == DisplayPlane::PLANE_OVERLAY) {
273            index += (1 << i);
274        }
275    }
276
277    int combinations;
278    ZOrderDescription *table;
279    if (dsp == IDisplayDevice::DEVICE_PRIMARY) {
280        combinations = PIPE_A_ZORDER_COMBINATIONS;
281        table = PIPE_A_ZORDER_TBL;
282    } else {
283        combinations = PIPE_B_ZORDER_COMBINATIONS;
284        table = PIPE_B_ZORDER_TBL;
285    }
286
287    for (int i = 0; i < combinations; i++) {
288        ZOrderDescription *zorderDesc = table + i;
289
290        if (zorderDesc->index != index)
291            continue;
292
293        if (assignPlanes(dsp, config, zorderDesc->zorder)) {
294            VTRACE("zorder assigned %s", zorderDesc->zorder);
295            return true;
296        }
297    }
298    return false;
299}
300
301bool AnnPlaneManager::assignPlanes(int dsp, ZOrderConfig& config, const char *zorder)
302{
303    // zorder string does not include cursor plane, therefore cursor layer needs to be handled
304    // in a special way. Cursor layer must be on top of zorder and no more than one cursor layer.
305
306    int size = (int)config.size();
307    if (zorder == NULL || size == 0) {
308        //DTRACE("invalid zorder or ZOrder config.");
309        return false;
310    }
311
312    int zorderLen = (int)strlen(zorder);
313
314    // test if plane is avalable
315    for (int i = 0; i < size; i++) {
316        if (config[i]->planeType == DisplayPlane::PLANE_CURSOR) {
317            if (i != size - 1) {
318                ETRACE("invalid zorder of cursor layer");
319                return false;
320            }
321            PlaneDescription& desc = PLANE_DESC['I' - 'A' + dsp];
322            if (!isFreePlane(desc.type, desc.index)) {
323                ETRACE("cursor plane is not available");
324                return false;
325            }
326            continue;
327        }
328        if (i >= zorderLen) {
329            DTRACE("index of ZOrderConfig is out of bound");
330            return false;
331        }
332
333        char id = *(zorder + i);
334        PlaneDescription& desc = PLANE_DESC[id - 'A'];
335        if (!isFreePlane(desc.type, desc.index)) {
336            DTRACE("plane type %d index %d is not available", desc.type, desc.index);
337            return false;
338        }
339
340#if 0
341        // plane type check
342        if (config[i]->planeType == DisplayPlane::PLANE_OVERLAY &&
343            desc.type != DisplayPlane::PLANE_OVERLAY) {
344            ETRACE("invalid plane type %d, expected %d", desc.type, config[i]->planeType);
345            return false;
346        }
347
348        if (config[i]->planeType != DisplayPlane::PLANE_OVERLAY) {
349            if (config[i]->planeType != DisplayPlane::PLANE_PRIMARY &&
350                config[i]->planeType != DisplayPlane::PLANE_SPRITE) {
351                ETRACE("invalid plane type %d,", config[i]->planeType);
352                return false;
353            }
354            if (desc.type != DisplayPlane::PLANE_PRIMARY &&
355                desc.type != DisplayPlane::PLANE_SPRITE) {
356                ETRACE("invalid plane type %d, expected %d", desc.type, config[i]->planeType);
357                return false;
358            }
359        }
360#endif
361
362        if  (desc.type == DisplayPlane::PLANE_OVERLAY && desc.index == 1 &&
363             config[i]->hwcLayer->getTransform() != 0) {
364            DTRACE("overlay C does not support transform");
365            return false;
366        }
367    }
368
369    bool primaryPlaneActive = false;
370    // allocate planes
371    for (int i = 0; i < size; i++) {
372        if (config[i]->planeType == DisplayPlane::PLANE_CURSOR) {
373            PlaneDescription& desc = PLANE_DESC['I' - 'A' + dsp];
374            ZOrderLayer *zLayer = config.itemAt(i);
375            zLayer->plane = getPlane(desc.type, desc.index);
376            if (zLayer->plane == NULL) {
377                ETRACE("failed to get cursor plane, should never happen!");
378            }
379            continue;
380        }
381
382        char id = *(zorder + i);
383        PlaneDescription& desc = PLANE_DESC[id - 'A'];
384        ZOrderLayer *zLayer = config.itemAt(i);
385        zLayer->plane = getPlane(desc.type, desc.index);
386        if (zLayer->plane == NULL) {
387            ETRACE("failed to get plane, should never happen!");
388        }
389        // override type
390        zLayer->planeType = desc.type;
391        if (desc.type == DisplayPlane::PLANE_PRIMARY) {
392            primaryPlaneActive = true;
393        }
394    }
395
396    // setup Z order
397    int slot = 0;
398    for (int i = 0; i < size; i++) {
399        slot = i;
400
401        if (OVERLAY_HW_WORKAROUND) {
402            if (!primaryPlaneActive &&
403                config[i]->planeType == DisplayPlane::PLANE_OVERLAY) {
404                slot += 1;
405            }
406        }
407
408        config[i]->plane->setZOrderConfig(config, (void *)(unsigned long)slot);
409        config[i]->plane->enable();
410    }
411
412#if 0
413    DTRACE("config size %d, zorder %s", size, zorder);
414    for (int i = 0; i < size; i++) {
415        const ZOrderLayer *l = config.itemAt(i);
416        ITRACE("%d: plane type %d, index %d, zorder %d",
417            i, l->planeType, l->plane->getIndex(), l->zorder);
418    }
419#endif
420
421    return true;
422}
423
424void* AnnPlaneManager::getZOrderConfig() const
425{
426    return NULL;
427}
428
429int AnnPlaneManager::getFreePlanes(int dsp, int type)
430{
431    RETURN_NULL_IF_NOT_INIT();
432
433    if (type != DisplayPlane::PLANE_SPRITE) {
434        return DisplayPlaneManager::getFreePlanes(dsp, type);
435    }
436
437    if (dsp < 0 || dsp > IDisplayDevice::DEVICE_EXTERNAL) {
438        ETRACE("invalid display device %d", dsp);
439        return 0;
440    }
441
442    uint32_t freePlanes = mFreePlanes[type] | mReclaimedPlanes[type];
443    int start = 0;
444    int stop = mSpritePlaneCount;
445    if (dsp == IDisplayDevice::DEVICE_EXTERNAL) {
446        // only Sprite D (index 0) can be assigned to pipe 1
447        // Sprites E/F (index 1, 2) are fixed on pipe 0
448        stop = 1;
449    }
450    int count = 0;
451    for (int i = start; i < stop; i++) {
452        if ((1 << i) & freePlanes) {
453            count++;
454        }
455    }
456    return count;
457}
458
459} // namespace intel
460} // namespace android
461
462