1/*
2 * Copyright (C) 2009 The Android Open Source Project
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//#define LOG_NDEBUG 0
18#define LOG_TAG "QComHardwareRenderer"
19#include <utils/Log.h>
20
21#include "QComHardwareRenderer.h"
22
23#include <binder/MemoryHeapBase.h>
24#include <binder/MemoryHeapPmem.h>
25#include <media/stagefright/MediaDebug.h>
26#include <surfaceflinger/ISurface.h>
27
28namespace android {
29
30////////////////////////////////////////////////////////////////////////////////
31
32typedef struct PLATFORM_PRIVATE_ENTRY
33{
34    /* Entry type */
35    uint32_t type;
36
37    /* Pointer to platform specific entry */
38    void *entry;
39
40} PLATFORM_PRIVATE_ENTRY;
41
42typedef struct PLATFORM_PRIVATE_LIST
43{
44    /* Number of entries */
45    uint32_t nEntries;
46
47    /* Pointer to array of platform specific entries *
48     * Contiguous block of PLATFORM_PRIVATE_ENTRY elements */
49    PLATFORM_PRIVATE_ENTRY *entryList;
50
51} PLATFORM_PRIVATE_LIST;
52
53// data structures for tunneling buffers
54typedef struct PLATFORM_PRIVATE_PMEM_INFO
55{
56    /* pmem file descriptor */
57    uint32_t pmem_fd;
58    uint32_t offset;
59
60} PLATFORM_PRIVATE_PMEM_INFO;
61
62#define PLATFORM_PRIVATE_PMEM   1
63
64QComHardwareRenderer::QComHardwareRenderer(
65        const sp<ISurface> &surface,
66        size_t displayWidth, size_t displayHeight,
67        size_t decodedWidth, size_t decodedHeight,
68        int32_t rotationDegrees)
69    : mISurface(surface),
70      mDisplayWidth(displayWidth),
71      mDisplayHeight(displayHeight),
72      mDecodedWidth(decodedWidth),
73      mDecodedHeight(decodedHeight),
74      mFrameSize((mDecodedWidth * mDecodedHeight * 3) / 2),
75      mRotationDegrees(rotationDegrees) {
76    CHECK(mISurface.get() != NULL);
77    CHECK(mDecodedWidth > 0);
78    CHECK(mDecodedHeight > 0);
79}
80
81QComHardwareRenderer::~QComHardwareRenderer() {
82    mISurface->unregisterBuffers();
83}
84
85void QComHardwareRenderer::render(
86        const void *data, size_t size, void *platformPrivate) {
87    size_t offset;
88    if (!getOffset(platformPrivate, &offset)) {
89        return;
90    }
91
92    mISurface->postBuffer(offset);
93}
94
95bool QComHardwareRenderer::getOffset(void *platformPrivate, size_t *offset) {
96    *offset = 0;
97
98    PLATFORM_PRIVATE_LIST *list = (PLATFORM_PRIVATE_LIST *)platformPrivate;
99    for (uint32_t i = 0; i < list->nEntries; ++i) {
100        if (list->entryList[i].type != PLATFORM_PRIVATE_PMEM) {
101            continue;
102        }
103
104        PLATFORM_PRIVATE_PMEM_INFO *info =
105            (PLATFORM_PRIVATE_PMEM_INFO *)list->entryList[i].entry;
106
107        if (info != NULL) {
108            if (mMemoryHeap.get() == NULL) {
109                publishBuffers(info->pmem_fd);
110            }
111
112            if (mMemoryHeap.get() == NULL) {
113                return false;
114            }
115
116            *offset = info->offset;
117
118            return true;
119        }
120    }
121
122    return false;
123}
124
125void QComHardwareRenderer::publishBuffers(uint32_t pmem_fd) {
126    sp<MemoryHeapBase> master =
127        reinterpret_cast<MemoryHeapBase *>(pmem_fd);
128
129    master->setDevice("/dev/pmem");
130
131    uint32_t heap_flags = master->getFlags() & MemoryHeapBase::NO_CACHING;
132    mMemoryHeap = new MemoryHeapPmem(master, heap_flags);
133    mMemoryHeap->slap();
134
135    uint32_t orientation;
136    switch (mRotationDegrees) {
137        case 0: orientation = ISurface::BufferHeap::ROT_0; break;
138        case 90: orientation = ISurface::BufferHeap::ROT_90; break;
139        case 180: orientation = ISurface::BufferHeap::ROT_180; break;
140        case 270: orientation = ISurface::BufferHeap::ROT_270; break;
141        default: orientation = ISurface::BufferHeap::ROT_0; break;
142    }
143
144    ISurface::BufferHeap bufferHeap(
145            mDisplayWidth, mDisplayHeight,
146            mDecodedWidth, mDecodedHeight,
147            HAL_PIXEL_FORMAT_YCrCb_420_SP,
148            orientation, 0,
149            mMemoryHeap);
150
151    status_t err = mISurface->registerBuffers(bufferHeap);
152    if (err != OK) {
153        LOGE("ISurface::registerBuffers failed (err = %d)", err);
154    }
155}
156
157}  // namespace android
158