SoftwareRenderer.cpp revision c726bd8b7b9929fd917b01e5551a66ad5fe2c04e
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_TAG "SoftwareRenderer"
18#include <utils/Log.h>
19
20#include "../include/SoftwareRenderer.h"
21
22#include <binder/MemoryHeapBase.h>
23#include <binder/MemoryHeapPmem.h>
24#include <media/stagefright/MediaDebug.h>
25#include <surfaceflinger/Surface.h>
26#include <ui/android_native_buffer.h>
27#include <ui/GraphicBufferMapper.h>
28
29// XXX: Temporary hack to allow referencing the _ADRENO pixel format here.
30#include <libgralloc-qsd8k/gralloc_priv.h>
31
32namespace android {
33
34SoftwareRenderer::SoftwareRenderer(
35        OMX_COLOR_FORMATTYPE colorFormat,
36        const sp<Surface> &surface,
37        size_t displayWidth, size_t displayHeight,
38        size_t decodedWidth, size_t decodedHeight,
39        int32_t rotationDegrees)
40    : mColorFormat(colorFormat),
41      mConverter(NULL),
42      mYUVMode(None),
43      mSurface(surface),
44      mDisplayWidth(displayWidth),
45      mDisplayHeight(displayHeight),
46      mDecodedWidth(decodedWidth),
47      mDecodedHeight(decodedHeight) {
48    LOGI("input format = %d", mColorFormat);
49    LOGI("display = %d x %d, decoded = %d x %d",
50            mDisplayWidth, mDisplayHeight, mDecodedWidth, mDecodedHeight);
51
52    mDecodedWidth = mDisplayWidth;
53    mDecodedHeight = mDisplayHeight;
54
55    int halFormat;
56    switch (mColorFormat) {
57#if HAS_YCBCR420_SP_ADRENO
58        case OMX_COLOR_FormatYUV420Planar:
59        {
60            halFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO;
61            mYUVMode = YUV420ToYUV420sp;
62            break;
63        }
64
65        case 0x7fa30c00:
66        {
67            halFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO;
68            mYUVMode = YUV420spToYUV420sp;
69            break;
70        }
71#endif
72
73        default:
74            halFormat = HAL_PIXEL_FORMAT_RGB_565;
75
76            mConverter = new ColorConverter(
77                    mColorFormat, OMX_COLOR_Format16bitRGB565);
78            CHECK(mConverter->isValid());
79            break;
80    }
81
82    CHECK(mSurface.get() != NULL);
83    CHECK(mDecodedWidth > 0);
84    CHECK(mDecodedHeight > 0);
85    CHECK(mConverter == NULL || mConverter->isValid());
86
87    CHECK_EQ(0,
88            native_window_set_usage(
89            mSurface.get(),
90            GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN
91            | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP));
92
93    CHECK_EQ(0, native_window_set_buffer_count(mSurface.get(), 2));
94
95    // Width must be multiple of 32???
96    CHECK_EQ(0, native_window_set_buffers_geometry(
97                mSurface.get(), mDecodedWidth, mDecodedHeight,
98                halFormat));
99
100    uint32_t transform;
101    switch (rotationDegrees) {
102        case 0: transform = 0; break;
103        case 90: transform = HAL_TRANSFORM_ROT_90; break;
104        case 180: transform = HAL_TRANSFORM_ROT_180; break;
105        case 270: transform = HAL_TRANSFORM_ROT_270; break;
106        default: transform = 0; break;
107    }
108
109    if (transform) {
110        CHECK_EQ(0, native_window_set_buffers_transform(
111                    mSurface.get(), transform));
112    }
113}
114
115SoftwareRenderer::~SoftwareRenderer() {
116    delete mConverter;
117    mConverter = NULL;
118}
119
120static inline size_t ALIGN(size_t x, size_t alignment) {
121    return (x + alignment - 1) & ~(alignment - 1);
122}
123
124void SoftwareRenderer::render(
125        const void *data, size_t size, void *platformPrivate) {
126    android_native_buffer_t *buf;
127    int err;
128    if ((err = mSurface->dequeueBuffer(mSurface.get(), &buf)) != 0) {
129        LOGW("Surface::dequeueBuffer returned error %d", err);
130        return;
131    }
132
133    CHECK_EQ(0, mSurface->lockBuffer(mSurface.get(), buf));
134
135    GraphicBufferMapper &mapper = GraphicBufferMapper::get();
136
137    Rect bounds(mDecodedWidth, mDecodedHeight);
138
139    void *dst;
140    CHECK_EQ(0, mapper.lock(
141                buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));
142
143    if (mConverter) {
144        mConverter->convert(
145                mDecodedWidth, mDecodedHeight,
146                data, 0, dst, buf->stride * 2);
147    } else if (mYUVMode == YUV420spToYUV420sp) {
148        // Input and output are both YUV420sp, but the alignment requirements
149        // are different.
150        size_t srcYStride = mDecodedWidth;
151        const uint8_t *srcY = (const uint8_t *)data;
152        uint8_t *dstY = (uint8_t *)dst;
153        for (size_t i = 0; i < mDecodedHeight; ++i) {
154            memcpy(dstY, srcY, mDecodedWidth);
155            srcY += srcYStride;
156            dstY += buf->stride;
157        }
158
159        size_t srcUVStride = (mDecodedWidth + 1) & ~1;
160        size_t dstUVStride = ALIGN(mDecodedWidth / 2, 32) * 2;
161
162        const uint8_t *srcUV = (const uint8_t *)data
163            + mDecodedHeight * mDecodedWidth;
164
165        size_t dstUVOffset = ALIGN(ALIGN(mDecodedHeight, 32) * buf->stride, 4096);
166        uint8_t *dstUV = (uint8_t *)dst + dstUVOffset;
167
168        for (size_t i = 0; i < (mDecodedHeight + 1) / 2; ++i) {
169            memcpy(dstUV, srcUV, (mDecodedWidth + 1) & ~1);
170            srcUV += srcUVStride;
171            dstUV += dstUVStride;
172        }
173    } else if (mYUVMode == YUV420ToYUV420sp) {
174        // Input is YUV420 planar, output is YUV420sp, adhere to proper
175        // alignment requirements.
176        size_t srcYStride = mDecodedWidth;
177        const uint8_t *srcY = (const uint8_t *)data;
178        uint8_t *dstY = (uint8_t *)dst;
179        for (size_t i = 0; i < mDecodedHeight; ++i) {
180            memcpy(dstY, srcY, mDecodedWidth);
181            srcY += srcYStride;
182            dstY += buf->stride;
183        }
184
185        size_t srcUVStride = (mDecodedWidth + 1) / 2;
186        size_t dstUVStride = ALIGN(mDecodedWidth / 2, 32) * 2;
187
188        const uint8_t *srcU = (const uint8_t *)data
189            + mDecodedHeight * mDecodedWidth;
190
191        const uint8_t *srcV =
192            srcU + ((mDecodedWidth + 1) / 2) * ((mDecodedHeight + 1) / 2);
193
194        size_t dstUVOffset = ALIGN(ALIGN(mDecodedHeight, 32) * buf->stride, 4096);
195        uint8_t *dstUV = (uint8_t *)dst + dstUVOffset;
196
197        for (size_t i = 0; i < (mDecodedHeight + 1) / 2; ++i) {
198            for (size_t j = 0; j < (mDecodedWidth + 1) / 2; ++j) {
199                dstUV[2 * j + 1] = srcU[j];
200                dstUV[2 * j] = srcV[j];
201            }
202            srcU += srcUVStride;
203            srcV += srcUVStride;
204            dstUV += dstUVStride;
205        }
206    } else {
207        memcpy(dst, data, size);
208    }
209
210    CHECK_EQ(0, mapper.unlock(buf->handle));
211
212    if ((err = mSurface->queueBuffer(mSurface.get(), buf)) != 0) {
213        LOGW("Surface::queueBuffer returned error %d", err);
214    }
215    buf = NULL;
216}
217
218}  // namespace android
219