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
17#include <math.h>
18#include <common/utils/HwcTrace.h>
19#include <common/base/Drm.h>
20#include <Hwcomposer.h>
21#include <PhysicalDevice.h>
22#include <ips/common/OverlayPlaneBase.h>
23#include <ips/common/TTMBufferMapper.h>
24#include <ips/common/GrallocSubBuffer.h>
25#include <DisplayQuery.h>
26#include <khronos/openmax/OMX_IntelVideoExt.h>
27#include <hal_public.h>
28
29namespace android {
30namespace intel {
31
32OverlayPlaneBase::OverlayPlaneBase(int index, int disp)
33    : DisplayPlane(index, PLANE_OVERLAY, disp),
34      mTTMBuffers(),
35      mActiveTTMBuffers(),
36      mCurrent(0),
37      mWsbm(0),
38      mPipeConfig(0),
39      mBobDeinterlace(0)
40{
41    CTRACE();
42    for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) {
43        mBackBuffer[i] = 0;
44    }
45}
46
47OverlayPlaneBase::~OverlayPlaneBase()
48{
49    CTRACE();
50}
51
52bool OverlayPlaneBase::initialize(uint32_t bufferCount)
53{
54    Drm *drm = Hwcomposer::getInstance().getDrm();
55    CTRACE();
56
57    // NOTE: use overlay's data buffer count for the overlay plane
58    if (bufferCount < OVERLAY_DATA_BUFFER_COUNT) {
59        ILOGTRACE("override overlay buffer count from %d to %d",
60             bufferCount, OVERLAY_DATA_BUFFER_COUNT);
61        bufferCount = OVERLAY_DATA_BUFFER_COUNT;
62    }
63    if (!DisplayPlane::initialize(bufferCount)) {
64        DEINIT_AND_RETURN_FALSE("failed to initialize display plane");
65    }
66
67    mTTMBuffers.setCapacity(bufferCount);
68    mActiveTTMBuffers.setCapacity(MIN_DATA_BUFFER_COUNT);
69
70    // init wsbm
71    mWsbm = new Wsbm(drm->getDrmFd());
72    if (!mWsbm || !mWsbm->initialize()) {
73        DEINIT_AND_RETURN_FALSE("failed to create wsbm");
74    }
75
76    // create overlay back buffer
77    for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) {
78        mBackBuffer[i] = createBackBuffer();
79        if (!mBackBuffer[i]) {
80            DEINIT_AND_RETURN_FALSE("failed to create overlay back buffer");
81        }
82        // reset back buffer
83        resetBackBuffer(i);
84    }
85
86    // disable overlay when created
87    flush(PLANE_DISABLE);
88
89    return true;
90}
91
92bool OverlayPlaneBase::isDisabled()
93{
94    RETURN_FALSE_IF_NOT_INIT();
95
96    struct drm_psb_register_rw_arg arg;
97    memset(&arg, 0, sizeof(struct drm_psb_register_rw_arg));
98
99    arg.get_plane_state_mask = 1;
100    arg.plane.type = DC_OVERLAY_PLANE;
101    arg.plane.index = mIndex;
102    // pass the pipe index to check its enabled status
103    // now we can pass the device id directly since
104    // their values are just equal
105    arg.plane.ctx = mDevice; // not used in kernel
106
107    Drm *drm = Hwcomposer::getInstance().getDrm();
108    bool ret = drm->writeReadIoctl(DRM_PSB_REGISTER_RW, &arg, sizeof(arg));
109    if (ret == false) {
110        WLOGTRACE("overlay plane query failed with error code %d", ret);
111        return false;
112    }
113
114    DLOGTRACE("overlay %d status %s on device %d, current device %d",
115        mIndex, arg.plane.ctx ? "DISABLED" : "ENABLED", mDevice, mDevice);
116
117    return arg.plane.ctx == PSB_DC_PLANE_DISABLED;
118}
119
120void OverlayPlaneBase::deinitialize()
121{
122    if (mTTMBuffers.size()) {
123        invalidateBufferCache();
124    }
125
126    if (mActiveTTMBuffers.size() > 0) {
127        invalidateActiveTTMBuffers();
128    }
129
130    // delete back buffer
131    for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) {
132        if (mBackBuffer[i]) {
133            deleteBackBuffer(i);
134            mBackBuffer[i] = NULL;
135        }
136    }
137    DEINIT_AND_DELETE_OBJ(mWsbm);
138
139    DisplayPlane::deinitialize();
140}
141
142void OverlayPlaneBase::invalidateBufferCache()
143{
144    // clear plane buffer cache
145    DisplayPlane::invalidateBufferCache();
146    invalidateTTMBuffers();
147}
148
149bool OverlayPlaneBase::assignToDevice(int disp)
150{
151    uint32_t pipeConfig = 0;
152
153    RETURN_FALSE_IF_NOT_INIT();
154    VLOGTRACE("overlay %d assigned to disp %d", mIndex, disp);
155
156    switch (disp) {
157    case IDisplayDevice::DEVICE_EXTERNAL:
158        pipeConfig = (0x2 << 6);
159        break;
160    case IDisplayDevice::DEVICE_PRIMARY:
161    default:
162        pipeConfig = 0;
163        break;
164    }
165
166    // if pipe switching happened, then disable overlay first
167    if (mPipeConfig != pipeConfig) {
168        DLOGTRACE("overlay %d switched from %d to %d", mIndex, mDevice, disp);
169        disable();
170    }
171
172    mPipeConfig = pipeConfig;
173    DisplayPlane::assignToDevice(disp);
174
175    enable();
176
177    return true;
178}
179
180void OverlayPlaneBase::setZOrderConfig(ZOrderConfig& zorderConfig,
181        void * /*nativeConfig*/)
182{
183    CTRACE();
184
185    // setup overlay z order
186    int ovaZOrder = -1;
187    int ovcZOrder = -1;
188    for (size_t i = 0; i < zorderConfig.size(); i++) {
189        DisplayPlane *plane = zorderConfig[i]->plane;
190        if (plane->getType() == DisplayPlane::PLANE_OVERLAY) {
191            if (plane->getIndex() == 0) {
192                ovaZOrder = i;
193            } else if (plane->getIndex() == 1) {
194                ovcZOrder = i;
195            }
196        }
197    }
198
199    for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) {
200        OverlayBackBufferBlk *backBuffer = mBackBuffer[i]->buf;
201        if (!backBuffer)
202            return;
203
204        // force overlay c above overlay a
205        if ((ovaZOrder >= 0) && (ovaZOrder < ovcZOrder)) {
206            backBuffer->OCONFIG |= (1 << 15);
207        } else {
208            backBuffer->OCONFIG &= ~(1 << 15);
209        }
210    }
211}
212
213bool OverlayPlaneBase::reset()
214{
215    RETURN_FALSE_IF_NOT_INIT();
216
217    DisplayPlane::reset();
218
219    // invalidate active TTM buffers
220    if (mActiveTTMBuffers.size() > 0) {
221        invalidateActiveTTMBuffers();
222    }
223
224    // reset back buffers
225    for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) {
226        resetBackBuffer(i);
227    }
228    return true;
229}
230
231bool OverlayPlaneBase::enable()
232{
233    RETURN_FALSE_IF_NOT_INIT();
234    for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) {
235        OverlayBackBufferBlk *backBuffer = mBackBuffer[i]->buf;
236        if (!backBuffer)
237            return false;
238
239        if (backBuffer->OCMD & 0x1)
240            return true;
241
242        backBuffer->OCMD |= 0x1;
243    }
244
245    // flush
246    flush(PLANE_ENABLE);
247    return true;
248}
249
250bool OverlayPlaneBase::disable()
251{
252    RETURN_FALSE_IF_NOT_INIT();
253    for (int i = 0; i < OVERLAY_BACK_BUFFER_COUNT; i++) {
254        OverlayBackBufferBlk *backBuffer = mBackBuffer[i]->buf;
255        if (!backBuffer)
256            return false;
257
258        if (!(backBuffer->OCMD & 0x1))
259            return true;
260
261        backBuffer->OCMD &= ~0x1;
262    }
263
264    // flush
265    flush(PLANE_DISABLE);
266    return true;
267}
268
269OverlayBackBuffer* OverlayPlaneBase::createBackBuffer()
270{
271    CTRACE();
272
273    // create back buffer
274    OverlayBackBuffer *backBuffer = (OverlayBackBuffer *)malloc(sizeof(OverlayBackBuffer));
275    if (!backBuffer) {
276        ELOGTRACE("failed to allocate back buffer");
277        return 0;
278    }
279
280
281    int size = sizeof(OverlayBackBufferBlk);
282    int alignment = 64 * 1024;
283    void *wsbmBufferObject = 0;
284    bool ret = mWsbm->allocateTTMBuffer(size, alignment, &wsbmBufferObject);
285    if (ret == false) {
286        ELOGTRACE("failed to allocate TTM buffer");
287        return 0;
288    }
289
290    void *virtAddr = mWsbm->getCPUAddress(wsbmBufferObject);
291    uint32_t gttOffsetInPage = mWsbm->getGttOffset(wsbmBufferObject);
292
293    backBuffer->buf = (OverlayBackBufferBlk *)virtAddr;
294    backBuffer->gttOffsetInPage = gttOffsetInPage;
295    backBuffer->bufObject = (uint32_t)wsbmBufferObject;
296
297    VLOGTRACE("cpu %p, gtt %d", virtAddr, gttOffsetInPage);
298
299    return backBuffer;
300}
301
302void OverlayPlaneBase::deleteBackBuffer(int buf)
303{
304    if (!mBackBuffer[buf])
305        return;
306
307    void *wsbmBufferObject = (void *)mBackBuffer[buf]->bufObject;
308    bool ret = mWsbm->destroyTTMBuffer(wsbmBufferObject);
309    if (ret == false) {
310        WLOGTRACE("failed to destroy TTM buffer");
311    }
312    // free back buffer
313    free(mBackBuffer[buf]);
314    mBackBuffer[buf] = 0;
315}
316
317void OverlayPlaneBase::resetBackBuffer(int buf)
318{
319    CTRACE();
320
321    if (!mBackBuffer[buf] || !mBackBuffer[buf]->buf)
322        return;
323
324    OverlayBackBufferBlk *backBuffer = mBackBuffer[buf]->buf;
325
326    memset(backBuffer, 0, sizeof(OverlayBackBufferBlk));
327
328    // reset overlay
329    backBuffer->OCLRC0 = (OVERLAY_INIT_CONTRAST << 18) |
330                         (OVERLAY_INIT_BRIGHTNESS & 0xff);
331    backBuffer->OCLRC1 = OVERLAY_INIT_SATURATION;
332    backBuffer->DCLRKV = OVERLAY_INIT_COLORKEY;
333    backBuffer->DCLRKM = OVERLAY_INIT_COLORKEYMASK;
334    backBuffer->OCONFIG = 0;
335    backBuffer->OCONFIG |= (0x1 << 3);
336    backBuffer->OCONFIG |= (0x1 << 27);
337    backBuffer->SCHRKEN &= ~(0x7 << 24);
338    backBuffer->SCHRKEN |= 0xff;
339}
340
341BufferMapper* OverlayPlaneBase::getTTMMapper(BufferMapper& grallocMapper, struct VideoPayloadBuffer *payload)
342{
343    uint32_t khandle;
344    uint32_t w, h;
345    uint32_t yStride, uvStride;
346    stride_t stride;
347    int srcX, srcY, srcW, srcH;
348
349    ssize_t index;
350    TTMBufferMapper *mapper;
351    bool ret;
352
353    if (!payload) {
354        ELOGTRACE("invalid payload buffer");
355        return 0;
356    }
357
358    srcX = grallocMapper.getCrop().x;
359    srcY = grallocMapper.getCrop().y;
360    srcW = grallocMapper.getCrop().w;
361    srcH = grallocMapper.getCrop().h;
362
363    // init ttm buffer
364    khandle = payload->rotated_buffer_handle;
365    index = mTTMBuffers.indexOfKey(khandle);
366    if (index < 0) {
367        VLOGTRACE("unmapped TTM buffer, will map it");
368
369        w = payload->rotated_width;
370        h = payload->rotated_height;
371        checkCrop(srcX, srcY, srcW, srcH, payload->coded_width, payload->coded_height);
372
373        uint32_t format = grallocMapper.getFormat();
374        // this is for sw decode with tiled buffer in landscape mode
375        if (payload->tiling)
376            format = OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled;
377
378        // calculate stride
379        switch (format) {
380        case HAL_PIXEL_FORMAT_YV12:
381        case HAL_PIXEL_FORMAT_INTEL_YV12:
382        case HAL_PIXEL_FORMAT_I420:
383            uint32_t yStride_align;
384            yStride_align = DisplayQuery::getOverlayLumaStrideAlignment(grallocMapper.getFormat());
385            if (yStride_align > 0)
386            {
387                yStride = align_to(align_to(w, 32), yStride_align);
388            }
389            else
390            {
391                yStride = align_to(align_to(w, 32), 64);
392            }
393            uvStride = align_to(yStride >> 1, 64);
394            stride.yuv.yStride = yStride;
395            stride.yuv.uvStride = uvStride;
396            break;
397        case HAL_PIXEL_FORMAT_NV12:
398            yStride = align_to(align_to(w, 32), 64);
399            uvStride = yStride;
400            stride.yuv.yStride = yStride;
401            stride.yuv.uvStride = uvStride;
402            break;
403        case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar:
404        case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled:
405            yStride = align_to(align_to(w, 32), 64);
406            uvStride = yStride;
407            stride.yuv.yStride = yStride;
408            stride.yuv.uvStride = uvStride;
409            break;
410        case HAL_PIXEL_FORMAT_YUY2:
411        case HAL_PIXEL_FORMAT_UYVY:
412            yStride = align_to((align_to(w, 32) << 1), 64);
413            uvStride = 0;
414            stride.yuv.yStride = yStride;
415            stride.yuv.uvStride = uvStride;
416            break;
417        }
418
419        DataBuffer buf(khandle);
420        // update buffer
421        buf.setStride(stride);
422        buf.setWidth(w);
423        buf.setHeight(h);
424        buf.setCrop(srcX, srcY, srcW, srcH);
425        buf.setFormat(format);
426
427        // create buffer mapper
428        bool res = false;
429        do {
430            mapper = new TTMBufferMapper(*mWsbm, buf);
431            if (!mapper) {
432                ELOGTRACE("failed to allocate mapper");
433                break;
434            }
435            // map ttm buffer
436            ret = mapper->map();
437            if (!ret) {
438                ELOGTRACE("failed to map");
439                invalidateTTMBuffers();
440                ret = mapper->map();
441                if (!ret) {
442                    ELOGTRACE("failed to remap");
443                    break;
444                }
445            }
446
447            if (mTTMBuffers.size() >= OVERLAY_DATA_BUFFER_COUNT) {
448                invalidateTTMBuffers();
449            }
450
451            // add mapper
452            index = mTTMBuffers.add(khandle, mapper);
453            if (index < 0) {
454                ELOGTRACE("failed to add TTMMapper");
455                break;
456            }
457
458            // increase mapper refCount since it is added to mTTMBuffers
459            mapper->incRef();
460            res = true;
461        } while (0);
462
463        if (!res) {
464            // error handling
465            if (mapper) {
466                mapper->unmap();
467                delete mapper;
468                mapper = NULL;
469            }
470            return 0;
471        }
472    } else {
473        VLOGTRACE("got mapper in saved ttm buffers");
474        mapper = reinterpret_cast<TTMBufferMapper *>(mTTMBuffers.valueAt(index));
475        if (mapper->getCrop().x != srcX || mapper->getCrop().y != srcY ||
476            mapper->getCrop().w != srcW || mapper->getCrop().h != srcH) {
477            checkCrop(srcX, srcY, srcW, srcH, payload->coded_width, payload->coded_height);
478            mapper->setCrop(srcX, srcY, srcW, srcH);
479        }
480    }
481
482    XLOGTRACE();
483    return mapper;
484}
485
486void OverlayPlaneBase::putTTMMapper(BufferMapper* mapper)
487{
488    if (!mapper)
489        return;
490
491    if (!mapper->decRef()) {
492        // unmap it
493        mapper->unmap();
494
495        // destroy this mapper
496        delete mapper;
497    }
498}
499
500bool OverlayPlaneBase::isActiveTTMBuffer(BufferMapper *mapper)
501{
502    for (size_t i = 0; i < mActiveTTMBuffers.size(); i++) {
503        BufferMapper *activeMapper = mActiveTTMBuffers.itemAt(i);
504        if (!activeMapper)
505            continue;
506        if (activeMapper->getKey() == mapper->getKey())
507            return true;
508    }
509
510    return false;
511}
512
513void OverlayPlaneBase::updateActiveTTMBuffers(BufferMapper *mapper)
514{
515    // unmap the first entry (oldest buffer)
516    if (mActiveTTMBuffers.size() >= MAX_ACTIVE_TTM_BUFFERS) {
517        BufferMapper *oldest = mActiveTTMBuffers.itemAt(0);
518        putTTMMapper(oldest);
519        mActiveTTMBuffers.removeAt(0);
520    }
521
522    // queue it to cached buffers
523    if (!isActiveTTMBuffer(mapper)) {
524        mapper->incRef();
525        mActiveTTMBuffers.push_back(mapper);
526    }
527}
528
529void OverlayPlaneBase::invalidateActiveTTMBuffers()
530{
531    BufferMapper* mapper;
532
533    RETURN_VOID_IF_NOT_INIT();
534
535    for (size_t i = 0; i < mActiveTTMBuffers.size(); i++) {
536        mapper = mActiveTTMBuffers.itemAt(i);
537        // unmap it
538        putTTMMapper(mapper);
539    }
540
541    // clear recorded data buffers
542    mActiveTTMBuffers.clear();
543}
544
545void OverlayPlaneBase::invalidateTTMBuffers()
546{
547    BufferMapper* mapper;
548    for (size_t i = 0; i < mTTMBuffers.size(); i++) {
549        mapper = mTTMBuffers.valueAt(i);
550        // putTTMMapper removes mapper from cache
551        putTTMMapper(mapper);
552    }
553    mTTMBuffers.clear();
554}
555
556
557bool OverlayPlaneBase::rotatedBufferReady(BufferMapper& mapper, BufferMapper* &rotatedMapper)
558{
559    struct VideoPayloadBuffer *payload;
560    uint32_t format;
561
562    // only NV12_VED has rotated buffer
563    format = mapper.getFormat();
564    if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar &&
565        format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled)
566        return false;
567
568    payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1);
569    // check payload
570    if (!payload) {
571        ELOGTRACE("no payload found");
572        return false;
573    }
574
575    if (payload->force_output_method == FORCE_OUTPUT_GPU)
576        return false;
577
578    if (payload->client_transform != mTransform) {
579        if (payload->surface_protected) {
580            payload->hwc_timestamp = systemTime();
581            payload->layer_transform = mTransform;
582        }
583        WLOGTRACE("client is not ready");
584        return false;
585    }
586
587    rotatedMapper = getTTMMapper(mapper, payload);
588    return true;
589}
590
591
592bool OverlayPlaneBase::useOverlayRotation(BufferMapper& /* mapper */)
593{
594    // by default overlay plane does not support rotation.
595    return false;
596}
597
598void OverlayPlaneBase::checkPosition(int& x, int& y, int& w, int& h)
599{
600    drmModeModeInfoPtr mode = &mModeInfo;
601
602    if (mode->hdisplay == 0 || mode->vdisplay == 0)
603        return;
604
605    if (x < 0)
606        x = 0;
607    if (y < 0)
608        y = 0;
609    if ((x + w) > mode->hdisplay)
610        w = mode->hdisplay - x;
611    if ((y + h) > mode->vdisplay)
612        h = mode->vdisplay - y;
613}
614
615void OverlayPlaneBase::checkCrop(int& srcX, int& srcY, int& srcW, int& srcH,
616                               int coded_width, int coded_height)
617{
618    int tmp;
619
620    if (mTransform)
621        srcH >>= mBobDeinterlace;
622
623    if (mTransform == HWC_TRANSFORM_ROT_90 || mTransform == HWC_TRANSFORM_ROT_270) {
624        tmp = srcH;
625        srcH = srcW;
626        srcW = tmp;
627
628        tmp = srcX;
629        srcX = srcY;
630        srcY = tmp;
631
632        tmp = coded_width;
633        coded_width = coded_height;
634        coded_height = tmp;
635    }
636
637    // skip pading bytes in rotate buffer
638    switch(mTransform) {
639    case HWC_TRANSFORM_ROT_90:
640        srcX = (coded_width >> mBobDeinterlace) - srcW - srcX;
641        break;
642    case HWC_TRANSFORM_ROT_180:
643        srcX = coded_width - srcW - srcX;
644        srcY = (coded_height >> mBobDeinterlace) - srcH - srcY;
645        break;
646    case HWC_TRANSFORM_ROT_270:
647        srcY = coded_height - srcH - srcY;
648        break;
649    default:
650        break;
651    }
652}
653
654
655bool OverlayPlaneBase::bufferOffsetSetup(BufferMapper& mapper)
656{
657    CTRACE();
658
659    OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf;
660    if (!backBuffer) {
661        ELOGTRACE("invalid back buffer");
662        return false;
663    }
664
665    uint32_t format = mapper.getFormat();
666    uint32_t gttOffsetInBytes = (mapper.getGttOffsetInPage(0) << 12);
667    uint32_t yStride = mapper.getStride().yuv.yStride;
668    uint32_t uvStride = mapper.getStride().yuv.uvStride;
669    uint32_t h = mapper.getHeight();
670    uint32_t srcX= mapper.getCrop().x;
671    uint32_t srcY= mapper.getCrop().y;
672
673    // clear original format setting
674    backBuffer->OCMD &= ~(0xf << 10);
675    backBuffer->OCMD &= ~OVERLAY_MEMORY_LAYOUT_TILED;
676
677    // Y/U/V plane must be 4k bytes aligned.
678    backBuffer->OSTART_0Y = gttOffsetInBytes;
679    if (mIsProtectedBuffer) {
680        // temporary workaround until vsync event logic is corrected.
681        // it seems that overlay buffer update and renderring can be overlapped,
682        // as such encryption bit may be cleared during HW rendering
683        backBuffer->OSTART_0Y |= 0x01;
684    }
685
686    backBuffer->OSTART_0U = gttOffsetInBytes;
687    backBuffer->OSTART_0V = gttOffsetInBytes;
688
689    backBuffer->OSTART_1Y = backBuffer->OSTART_0Y;
690    backBuffer->OSTART_1U = backBuffer->OSTART_0U;
691    backBuffer->OSTART_1V = backBuffer->OSTART_0V;
692
693    switch(format) {
694    case HAL_PIXEL_FORMAT_YV12:    // YV12
695        backBuffer->OBUF_0Y = 0;
696        backBuffer->OBUF_0V = yStride * h;
697        backBuffer->OBUF_0U = backBuffer->OBUF_0V + (uvStride * (h / 2));
698        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420;
699        break;
700    case HAL_PIXEL_FORMAT_INTEL_YV12:    // INTEL_YV12
701        backBuffer->OBUF_0Y = 0;
702        backBuffer->OBUF_0V = yStride * align_to(h, 32);
703        backBuffer->OBUF_0U = backBuffer->OBUF_0V + (uvStride * (align_to(h, 32) / 2));
704        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420;
705        break;
706    case HAL_PIXEL_FORMAT_I420:    // I420
707        backBuffer->OBUF_0Y = 0;
708        backBuffer->OBUF_0U = yStride * h;
709        backBuffer->OBUF_0V = backBuffer->OBUF_0U + (uvStride * (h / 2));
710        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_YUV420;
711        break;
712    case HAL_PIXEL_FORMAT_NV12:    // NV12
713        backBuffer->OBUF_0Y = 0;
714        backBuffer->OBUF_0U = yStride * h;
715        backBuffer->OBUF_0V = 0;
716        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2;
717        break;
718    // NOTE: this is the decoded video format, align the height to 32B
719    //as it's defined by video driver
720    case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar:    // Intel codec NV12
721        backBuffer->OBUF_0Y = 0;
722        backBuffer->OBUF_0U = yStride * align_to(h, 32);
723        backBuffer->OBUF_0V = 0;
724        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2;
725        break;
726    case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled:  //NV12_tiled
727        backBuffer->OBUF_0Y = 0;
728        backBuffer->OBUF_0U = yStride * align_to(h, 32);
729        backBuffer->OBUF_0V = 0;
730        backBuffer->OSTART_0U += yStride * align_to(h, 32);
731        backBuffer->OSTART_0V += yStride * align_to(h, 32);
732        backBuffer->OSTART_1U = backBuffer->OSTART_0U;
733        backBuffer->OSTART_1V = backBuffer->OSTART_0V;
734        backBuffer->OTILEOFF_0Y = srcX + (srcY << 16);
735        backBuffer->OTILEOFF_1Y = backBuffer->OTILEOFF_0Y;
736        backBuffer->OTILEOFF_0U = srcX + ((srcY / 2) << 16);
737        backBuffer->OTILEOFF_1U = backBuffer->OTILEOFF_0U;
738        backBuffer->OTILEOFF_0V = backBuffer->OTILEOFF_0U;
739        backBuffer->OTILEOFF_1V = backBuffer->OTILEOFF_0U;
740        backBuffer->OCMD |= OVERLAY_FORMAT_PLANAR_NV12_2;
741        backBuffer->OCMD |= OVERLAY_MEMORY_LAYOUT_TILED;
742        break;
743    case HAL_PIXEL_FORMAT_YUY2:    // YUY2
744        backBuffer->OBUF_0Y = 0;
745        backBuffer->OBUF_0U = 0;
746        backBuffer->OBUF_0V = 0;
747        backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422;
748        backBuffer->OCMD |= OVERLAY_PACKED_ORDER_YUY2;
749        break;
750    case HAL_PIXEL_FORMAT_UYVY:    // UYVY
751        backBuffer->OBUF_0Y = 0;
752        backBuffer->OBUF_0U = 0;
753        backBuffer->OBUF_0V = 0;
754        backBuffer->OCMD |= OVERLAY_FORMAT_PACKED_YUV422;
755        backBuffer->OCMD |= OVERLAY_PACKED_ORDER_UYVY;
756        break;
757    default:
758        ELOGTRACE("unsupported format %d", format);
759        return false;
760    }
761
762    backBuffer->OBUF_0Y += srcY * yStride + srcX;
763    backBuffer->OBUF_0V += (srcY / 2) * uvStride + srcX;
764    backBuffer->OBUF_0U += (srcY / 2) * uvStride + srcX;
765    backBuffer->OBUF_1Y = backBuffer->OBUF_0Y;
766    backBuffer->OBUF_1U = backBuffer->OBUF_0U;
767    backBuffer->OBUF_1V = backBuffer->OBUF_0V;
768
769    VLOGTRACE("done. offset (%d, %d, %d)",
770          backBuffer->OBUF_0Y,
771          backBuffer->OBUF_0U,
772          backBuffer->OBUF_0V);
773    return true;
774}
775
776uint32_t OverlayPlaneBase::calculateSWidthSW(uint32_t offset, uint32_t width)
777{
778    ALOGTRACE("offset = %d, width = %d", offset, width);
779
780    uint32_t swidth = ((offset + width + 0x3F) >> 6) - (offset >> 6);
781
782    swidth <<= 1;
783    swidth -= 1;
784
785    return swidth;
786}
787
788bool OverlayPlaneBase::coordinateSetup(BufferMapper& mapper)
789{
790    CTRACE();
791
792    OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf;
793    if (!backBuffer) {
794        ELOGTRACE("invalid back buffer");
795        return false;
796    }
797
798    uint32_t swidthy = 0;
799    uint32_t swidthuv = 0;
800    uint32_t format = mapper.getFormat();
801    uint32_t width = mapper.getCrop().w;
802    uint32_t height = mapper.getCrop().h;
803    uint32_t yStride = mapper.getStride().yuv.yStride;
804    uint32_t uvStride = mapper.getStride().yuv.uvStride;
805    uint32_t offsety = backBuffer->OBUF_0Y;
806    uint32_t offsetu = backBuffer->OBUF_0U;
807
808    switch (format) {
809    case HAL_PIXEL_FORMAT_YV12:              // YV12
810    case HAL_PIXEL_FORMAT_INTEL_YV12:        // INTEL_YV12
811    case HAL_PIXEL_FORMAT_I420:              // I420
812    case HAL_PIXEL_FORMAT_NV12:              // NV12
813    case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar:          // NV12
814    case OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled:    // NV12_tiled
815        break;
816    case HAL_PIXEL_FORMAT_YUY2:              // YUY2
817    case HAL_PIXEL_FORMAT_UYVY:              // UYVY
818        width <<= 1;
819        break;
820    default:
821        ELOGTRACE("unsupported format %d", format);
822        return false;
823    }
824
825    if (width <= 0 || height <= 0) {
826        ELOGTRACE("invalid src dim");
827        return false;
828    }
829
830    if (yStride <=0 && uvStride <= 0) {
831        ELOGTRACE("invalid source stride");
832        return false;
833    }
834
835    backBuffer->SWIDTH = width | ((width / 2) << 16);
836    swidthy = calculateSWidthSW(offsety, width);
837    swidthuv = calculateSWidthSW(offsetu, width / 2);
838    backBuffer->SWIDTHSW = (swidthy << 2) | (swidthuv << 18);
839    backBuffer->SHEIGHT = height | ((height / 2) << 16);
840    backBuffer->OSTRIDE = (yStride & (~0x3f)) | ((uvStride & (~0x3f)) << 16);
841
842    XLOGTRACE();
843
844    return true;
845}
846
847bool OverlayPlaneBase::setCoeffRegs(double *coeff, int mantSize,
848                                  coeffPtr pCoeff, int pos)
849{
850    int maxVal, icoeff, res;
851    int sign;
852    double c;
853
854    sign = 0;
855    maxVal = 1 << mantSize;
856    c = *coeff;
857    if (c < 0.0) {
858        sign = 1;
859        c = -c;
860    }
861
862    res = 12 - mantSize;
863    if ((icoeff = (int)(c * 4 * maxVal + 0.5)) < maxVal) {
864        pCoeff[pos].exponent = 3;
865        pCoeff[pos].mantissa = icoeff << res;
866        *coeff = (double)icoeff / (double)(4 * maxVal);
867    } else if ((icoeff = (int)(c * 2 * maxVal + 0.5)) < maxVal) {
868        pCoeff[pos].exponent = 2;
869        pCoeff[pos].mantissa = icoeff << res;
870        *coeff = (double)icoeff / (double)(2 * maxVal);
871    } else if ((icoeff = (int)(c * maxVal + 0.5)) < maxVal) {
872        pCoeff[pos].exponent = 1;
873        pCoeff[pos].mantissa = icoeff << res;
874        *coeff = (double)icoeff / (double)(maxVal);
875    } else if ((icoeff = (int)(c * maxVal * 0.5 + 0.5)) < maxVal) {
876        pCoeff[pos].exponent = 0;
877        pCoeff[pos].mantissa = icoeff << res;
878        *coeff = (double)icoeff / (double)(maxVal / 2);
879    } else {
880        // Coeff out of range
881        return false;
882    }
883
884    pCoeff[pos].sign = sign;
885    if (sign)
886        *coeff = -(*coeff);
887    return true;
888}
889
890void OverlayPlaneBase::updateCoeff(int taps, double fCutoff,
891                                 bool isHoriz, bool isY,
892                                 coeffPtr pCoeff)
893{
894    int i, j, j1, num, pos, mantSize;
895    double pi = 3.1415926535, val, sinc, window, sum;
896    double rawCoeff[MAX_TAPS * 32], coeffs[N_PHASES][MAX_TAPS];
897    double diff;
898    int tapAdjust[MAX_TAPS], tap2Fix;
899    bool isVertAndUV;
900
901    if (isHoriz)
902        mantSize = 7;
903    else
904        mantSize = 6;
905
906    isVertAndUV = !isHoriz && !isY;
907    num = taps * 16;
908    for (i = 0; i < num  * 2; i++) {
909        val = (1.0 / fCutoff) * taps * pi * (i - num) / (2 * num);
910        if (val == 0.0)
911            sinc = 1.0;
912        else
913            sinc = sin(val) / val;
914
915        // Hamming window
916        window = (0.54 - 0.46 * cos(2 * i * pi / (2 * num - 1)));
917        rawCoeff[i] = sinc * window;
918    }
919
920    for (i = 0; i < N_PHASES; i++) {
921        // Normalise the coefficients
922        sum = 0.0;
923        for (j = 0; j < taps; j++) {
924            pos = i + j * 32;
925            sum += rawCoeff[pos];
926        }
927        for (j = 0; j < taps; j++) {
928            pos = i + j * 32;
929            coeffs[i][j] = rawCoeff[pos] / sum;
930        }
931
932        // Set the register values
933        for (j = 0; j < taps; j++) {
934            pos = j + i * taps;
935            if ((j == (taps - 1) / 2) && !isVertAndUV)
936                setCoeffRegs(&coeffs[i][j], mantSize + 2, pCoeff, pos);
937            else
938                setCoeffRegs(&coeffs[i][j], mantSize, pCoeff, pos);
939        }
940
941        tapAdjust[0] = (taps - 1) / 2;
942        for (j = 1, j1 = 1; j <= tapAdjust[0]; j++, j1++) {
943            tapAdjust[j1] = tapAdjust[0] - j;
944            tapAdjust[++j1] = tapAdjust[0] + j;
945        }
946
947        // Adjust the coefficients
948        sum = 0.0;
949        for (j = 0; j < taps; j++)
950            sum += coeffs[i][j];
951        if (sum != 1.0) {
952            for (j1 = 0; j1 < taps; j1++) {
953                tap2Fix = tapAdjust[j1];
954                diff = 1.0 - sum;
955                coeffs[i][tap2Fix] += diff;
956                pos = tap2Fix + i * taps;
957                if ((tap2Fix == (taps - 1) / 2) && !isVertAndUV)
958                    setCoeffRegs(&coeffs[i][tap2Fix], mantSize + 2, pCoeff, pos);
959                else
960                    setCoeffRegs(&coeffs[i][tap2Fix], mantSize, pCoeff, pos);
961
962                sum = 0.0;
963                for (j = 0; j < taps; j++)
964                    sum += coeffs[i][j];
965                if (sum == 1.0)
966                    break;
967            }
968        }
969    }
970}
971
972bool OverlayPlaneBase::scalingSetup(BufferMapper& mapper)
973{
974    int xscaleInt, xscaleFract, yscaleInt, yscaleFract;
975    int xscaleIntUV, xscaleFractUV;
976    int yscaleIntUV, yscaleFractUV;
977    int deinterlace_factor = 1;
978    // UV is half the size of Y -- YUV420
979    int uvratio = 2;
980    uint32_t newval;
981    coeffRec xcoeffY[N_HORIZ_Y_TAPS * N_PHASES];
982    coeffRec xcoeffUV[N_HORIZ_UV_TAPS * N_PHASES];
983    int i, j, pos;
984    bool scaleChanged = false;
985    int x, y, w, h;
986
987    OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf;
988    if (!backBuffer) {
989        ELOGTRACE("invalid back buffer");
990        return false;
991    }
992
993    x = mPosition.x;
994    y = mPosition.y;
995    w = mPosition.w;
996    h = mPosition.h;
997
998    // check position
999    checkPosition(x, y, w, h);
1000    VLOGTRACE("final position (%d, %d, %d, %d)", x, y, w, h);
1001
1002    if ((w <= 0) || (h <= 0)) {
1003         ELOGTRACE("invalid dst width/height");
1004         return false;
1005    }
1006
1007    // setup dst position
1008    backBuffer->DWINPOS = (y << 16) | x;
1009    backBuffer->DWINSZ = (h << 16) | w;
1010
1011    uint32_t srcWidth = mapper.getCrop().w;
1012    uint32_t srcHeight = mapper.getCrop().h;
1013    uint32_t dstWidth = w;
1014    uint32_t dstHeight = h;
1015
1016    VLOGTRACE("src (%dx%d), dst (%dx%d)",
1017          srcWidth, srcHeight,
1018          dstWidth, dstHeight);
1019
1020     // Y down-scale factor as a multiple of 4096
1021    if (srcWidth == dstWidth && srcHeight == dstHeight) {
1022        xscaleFract = (1 << 12);
1023        yscaleFract = (1 << 12)/deinterlace_factor;
1024    } else {
1025        xscaleFract = ((srcWidth - 1) << 12) / dstWidth;
1026        yscaleFract = ((srcHeight - 1) << 12) / (dstHeight * deinterlace_factor);
1027    }
1028
1029    // Calculate the UV scaling factor
1030    xscaleFractUV = xscaleFract / uvratio;
1031    yscaleFractUV = yscaleFract / uvratio;
1032
1033    // To keep the relative Y and UV ratios exact, round the Y scales
1034    // to a multiple of the Y/UV ratio.
1035    xscaleFract = xscaleFractUV * uvratio;
1036    yscaleFract = yscaleFractUV * uvratio;
1037
1038    // Integer (un-multiplied) values
1039    xscaleInt = xscaleFract >> 12;
1040    yscaleInt = yscaleFract >> 12;
1041
1042    xscaleIntUV = xscaleFractUV >> 12;
1043    yscaleIntUV = yscaleFractUV >> 12;
1044
1045    // Check scaling ratio
1046    if (xscaleInt > INTEL_OVERLAY_MAX_SCALING_RATIO) {
1047        ELOGTRACE("xscaleInt > %d", INTEL_OVERLAY_MAX_SCALING_RATIO);
1048        return false;
1049    }
1050
1051    // shouldn't get here
1052    if (xscaleIntUV > INTEL_OVERLAY_MAX_SCALING_RATIO) {
1053        ELOGTRACE("xscaleIntUV > %d", INTEL_OVERLAY_MAX_SCALING_RATIO);
1054        return false;
1055    }
1056
1057    newval = (xscaleInt << 15) |
1058    ((xscaleFract & 0xFFF) << 3) | ((yscaleFract & 0xFFF) << 20);
1059    if (newval != backBuffer->YRGBSCALE) {
1060        scaleChanged = true;
1061        backBuffer->YRGBSCALE = newval;
1062    }
1063
1064    newval = (xscaleIntUV << 15) | ((xscaleFractUV & 0xFFF) << 3) |
1065    ((yscaleFractUV & 0xFFF) << 20);
1066    if (newval != backBuffer->UVSCALE) {
1067        scaleChanged = true;
1068        backBuffer->UVSCALE = newval;
1069    }
1070
1071    newval = yscaleInt << 16 | yscaleIntUV;
1072    if (newval != backBuffer->UVSCALEV) {
1073        scaleChanged = true;
1074        backBuffer->UVSCALEV = newval;
1075    }
1076
1077    // Recalculate coefficients if the scaling changed
1078    // Only Horizontal coefficients so far.
1079    if (scaleChanged) {
1080        double fCutoffY;
1081        double fCutoffUV;
1082
1083        fCutoffY = xscaleFract / 4096.0;
1084        fCutoffUV = xscaleFractUV / 4096.0;
1085
1086        // Limit to between 1.0 and 3.0
1087        if (fCutoffY < MIN_CUTOFF_FREQ)
1088            fCutoffY = MIN_CUTOFF_FREQ;
1089        if (fCutoffY > MAX_CUTOFF_FREQ)
1090            fCutoffY = MAX_CUTOFF_FREQ;
1091        if (fCutoffUV < MIN_CUTOFF_FREQ)
1092            fCutoffUV = MIN_CUTOFF_FREQ;
1093        if (fCutoffUV > MAX_CUTOFF_FREQ)
1094            fCutoffUV = MAX_CUTOFF_FREQ;
1095
1096        updateCoeff(N_HORIZ_Y_TAPS, fCutoffY, true, true, xcoeffY);
1097        updateCoeff(N_HORIZ_UV_TAPS, fCutoffUV, true, false, xcoeffUV);
1098
1099        for (i = 0; i < N_PHASES; i++) {
1100            for (j = 0; j < N_HORIZ_Y_TAPS; j++) {
1101                pos = i * N_HORIZ_Y_TAPS + j;
1102                backBuffer->Y_HCOEFS[pos] =
1103                        (xcoeffY[pos].sign << 15 |
1104                         xcoeffY[pos].exponent << 12 |
1105                         xcoeffY[pos].mantissa);
1106            }
1107        }
1108        for (i = 0; i < N_PHASES; i++) {
1109            for (j = 0; j < N_HORIZ_UV_TAPS; j++) {
1110                pos = i * N_HORIZ_UV_TAPS + j;
1111                backBuffer->UV_HCOEFS[pos] =
1112                         (xcoeffUV[pos].sign << 15 |
1113                          xcoeffUV[pos].exponent << 12 |
1114                          xcoeffUV[pos].mantissa);
1115            }
1116        }
1117    }
1118
1119    XLOGTRACE();
1120    return true;
1121}
1122
1123bool OverlayPlaneBase::colorSetup(BufferMapper& mapper)
1124{
1125    CTRACE();
1126
1127    OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf;
1128    if (!backBuffer) {
1129        ELOGTRACE("invalid back buffer");
1130        return false;
1131    }
1132
1133    if (mPipeConfig == (0x2 << 6))
1134        return true;
1135
1136    uint32_t format = mapper.getFormat();
1137    if (format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar &&
1138        format != OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) {
1139
1140        VLOGTRACE("Not video layer, use default color setting");
1141        backBuffer->OCLRC0 = (OVERLAY_INIT_CONTRAST << 18) |
1142                         (OVERLAY_INIT_BRIGHTNESS & 0xff);
1143        backBuffer->OCLRC1 = OVERLAY_INIT_SATURATION;
1144        backBuffer->OCONFIG &= ~(1 << 5);
1145
1146        return true;
1147    }
1148
1149    struct VideoPayloadBuffer *payload;
1150    payload = (struct VideoPayloadBuffer *)mapper.getCpuAddress(SUB_BUFFER1);
1151    // check payload
1152    if (!payload) {
1153        ELOGTRACE("no payload found");
1154        return false;
1155    }
1156
1157    // BT.601 or BT.709
1158    backBuffer->OCONFIG &= ~(1 << 5);
1159    backBuffer->OCONFIG |= (payload->csc_mode << 5);
1160
1161    if  (payload->video_range) {
1162        // full range, no need to do level expansion
1163        backBuffer->OCLRC0 = 0x1000000;
1164        backBuffer->OCLRC1 = 0x80;
1165    } else {
1166        // level expansion for limited range
1167        backBuffer->OCLRC0 = (OVERLAY_INIT_CONTRAST << 18) |
1168                         (OVERLAY_INIT_BRIGHTNESS & 0xff);
1169        backBuffer->OCLRC1 = OVERLAY_INIT_SATURATION;
1170    }
1171
1172    return true;
1173}
1174
1175bool OverlayPlaneBase::setDataBuffer(BufferMapper& grallocMapper)
1176{
1177    BufferMapper *mapper;
1178    BufferMapper *rotatedMapper = 0;
1179    bool ret;
1180    uint32_t format;
1181
1182    RETURN_FALSE_IF_NOT_INIT();
1183
1184    // get gralloc mapper
1185    mapper = &grallocMapper;
1186    format = grallocMapper.getFormat();
1187    if (format == OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar ||
1188        format == OMX_INTEL_COLOR_FormatYUV420PackedSemiPlanar_Tiled) {
1189        struct VideoPayloadBuffer *payload;
1190        payload = (struct VideoPayloadBuffer *)grallocMapper.getCpuAddress(SUB_BUFFER1);
1191        if (!payload) {
1192            ELOGTRACE("invalid payload buffer");
1193            return 0;
1194        }
1195
1196        mBobDeinterlace = payload->bob_deinterlace;
1197    }
1198
1199    if (mTransform && !useOverlayRotation(grallocMapper)) {
1200        if (!rotatedBufferReady(grallocMapper, rotatedMapper)) {
1201            DLOGTRACE("rotated buffer is not ready");
1202            return false;
1203        }
1204
1205        if (!rotatedMapper) {
1206            ELOGTRACE("failed to get rotated buffer");
1207            return false;
1208        }
1209        mapper = rotatedMapper;
1210    }
1211
1212    OverlayBackBufferBlk *backBuffer = mBackBuffer[mCurrent]->buf;
1213    if (!backBuffer) {
1214        ELOGTRACE("invalid back buffer");
1215        return false;
1216    }
1217
1218    ret = bufferOffsetSetup(*mapper);
1219    if (ret == false) {
1220        ELOGTRACE("failed to set up buffer offsets");
1221        return false;
1222    }
1223
1224    ret = coordinateSetup(*mapper);
1225    if (ret == false) {
1226        ELOGTRACE("failed to set up overlay coordinates");
1227        return false;
1228    }
1229
1230    ret = scalingSetup(*mapper);
1231    if (ret == false) {
1232        ELOGTRACE("failed to set up scaling parameters");
1233        return false;
1234    }
1235
1236    backBuffer->OCMD |= 0x1;
1237
1238    if (mBobDeinterlace && !mTransform) {
1239        backBuffer->OCMD |= BUF_TYPE_FIELD;
1240        backBuffer->OCMD &= ~FIELD_SELECT;
1241        backBuffer->OCMD |= FIELD0;
1242        backBuffer->OCMD &= ~(BUFFER_SELECT);
1243        backBuffer->OCMD |= BUFFER0;
1244    } else {
1245        backBuffer->OCMD &= ~BUF_TYPE;
1246        backBuffer->OCMD &= ~FIELD_SELECT;
1247        backBuffer->OCMD &= ~(BUFFER_SELECT);
1248    }
1249
1250    ret = colorSetup(*mapper);
1251    if (ret == false) {
1252        ELOGTRACE("failed to set up color parameters");
1253        return false;
1254    }
1255
1256    // add to active ttm buffers if it's a rotated buffer
1257    if (rotatedMapper) {
1258        updateActiveTTMBuffers(mapper);
1259    }
1260
1261    return true;
1262}
1263
1264} // namespace intel
1265} // namespace android
1266
1267