1/*
2 * Copyright (C) 2012 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#include <malloc.h>
18#include <string.h>
19
20#include "RenderScript.h"
21#include "rsCppInternal.h"
22
23// From system/graphics.h
24enum {
25    HAL_PIXEL_FORMAT_YV12               = 0x32315659, // YCrCb 4:2:0 Planar
26    HAL_PIXEL_FORMAT_YCrCb_420_SP       = 0x11,       // NV21
27};
28
29using namespace android;
30using namespace RSC;
31
32void Type::calcElementCount() {
33    bool hasLod = hasMipmaps();
34    uint32_t x = getX();
35    uint32_t y = getY();
36    uint32_t z = getZ();
37    uint32_t faces = 1;
38    if (hasFaces()) {
39        faces = 6;
40    }
41    if (x == 0) {
42        x = 1;
43    }
44    if (y == 0) {
45        y = 1;
46    }
47    if (z == 0) {
48        z = 1;
49    }
50
51    uint32_t count = x * y * z * faces;
52    while (hasLod && ((x > 1) || (y > 1) || (z > 1))) {
53        if(x > 1) {
54            x >>= 1;
55        }
56        if(y > 1) {
57            y >>= 1;
58        }
59        if(z > 1) {
60            z >>= 1;
61        }
62
63        count += x * y * z * faces;
64    }
65    mElementCount = count;
66}
67
68
69Type::Type(void *id, sp<RS> rs) : BaseObj(id, rs) {
70    mDimX = 0;
71    mDimY = 0;
72    mDimZ = 0;
73    mDimMipmaps = false;
74    mDimFaces = false;
75    mElement = nullptr;
76    mYuvFormat = RS_YUV_NONE;
77}
78
79void Type::updateFromNative() {
80    BaseObj::updateFromNative();
81
82    /*
83     * We have 6 integers / pointers (uintptr_t) to obtain from the return buffer:
84     * mDimX     (buffer[0]);
85     * mDimY     (buffer[1]);
86     * mDimZ     (buffer[2]);
87     * mDimLOD   (buffer[3]);
88     * mDimFaces (buffer[4]);
89     * mElement  (buffer[5]);
90     */
91    uintptr_t dataBuffer[6];
92    RS::dispatch->TypeGetNativeData(mRS->getContext(), getID(), dataBuffer, 6);
93
94    mDimX = (uint32_t)dataBuffer[0];
95    mDimY = (uint32_t)dataBuffer[1];
96    mDimZ = (uint32_t)dataBuffer[2];
97    mDimMipmaps = dataBuffer[3] == 1 ? true : false;
98    mDimFaces = dataBuffer[4] == 1 ? true : false;
99
100    uintptr_t elementID = dataBuffer[5];
101    if(elementID != 0) {
102        // Just create a new Element and update it from native.
103        sp<Element> e = new Element((void *)elementID, mRS);
104        e->updateFromNative();
105        mElement = e;
106    }
107    calcElementCount();
108}
109
110sp<const Type> Type::create(sp<RS> rs, sp<const Element> e, uint32_t dimX, uint32_t dimY, uint32_t dimZ) {
111    void * id = RS::dispatch->TypeCreate(rs->getContext(), e->getID(), dimX, dimY, dimZ, false, false, 0);
112    Type *t = new Type(id, rs);
113
114    t->mElement = e;
115    t->mDimX = dimX;
116    t->mDimY = dimY;
117    t->mDimZ = dimZ;
118    t->mDimMipmaps = false;
119    t->mDimFaces = false;
120    t->mYuvFormat = RS_YUV_NONE;
121
122    t->calcElementCount();
123
124    return t;
125}
126
127Type::Builder::Builder(sp<RS> rs, sp<const Element> e) {
128    mRS = rs.get();
129    mElement = e;
130    mDimX = 0;
131    mDimY = 0;
132    mDimZ = 0;
133    mDimMipmaps = false;
134    mDimFaces = false;
135    mYuvFormat = RS_YUV_NONE;
136}
137
138void Type::Builder::setX(uint32_t value) {
139    if(value < 1) {
140        ALOGE("Values of less than 1 for Dimension X are not valid.");
141    }
142    mDimX = value;
143}
144
145void Type::Builder::setY(uint32_t value) {
146    if(value < 1) {
147        ALOGE("Values of less than 1 for Dimension Y are not valid.");
148    }
149    mDimY = value;
150}
151
152void Type::Builder::setZ(uint32_t value) {
153    if(value < 1) {
154        ALOGE("Values of less than 1 for Dimension Z are not valid.");
155    }
156    mDimZ = value;
157}
158
159void Type::Builder::setYuvFormat(RsYuvFormat format) {
160    if (format != RS_YUV_NONE && !(mElement->isCompatible(Element::YUV(mRS)))) {
161        ALOGE("Invalid element for use with YUV.");
162        return;
163    }
164
165    if (format != RS_YUV_NONE &&
166        format != RS_YUV_YV12 &&
167        format != RS_YUV_NV21 &&
168        format != RS_YUV_420_888) {
169        ALOGE("Invalid YUV format.");
170        return;
171    }
172    mYuvFormat = format;
173}
174
175
176void Type::Builder::setMipmaps(bool value) {
177    mDimMipmaps = value;
178}
179
180void Type::Builder::setFaces(bool value) {
181    mDimFaces = value;
182}
183
184sp<const Type> Type::Builder::create() {
185    if (mDimZ > 0) {
186        if ((mDimX < 1) || (mDimY < 1)) {
187            ALOGE("Both X and Y dimension required when Z is present.");
188            return nullptr;
189        }
190        if (mDimFaces) {
191            ALOGE("Cube maps not supported with 3D types.");
192            return nullptr;
193        }
194    }
195    if (mDimY > 0) {
196        if (mDimX < 1) {
197            ALOGE("X dimension required when Y is present.");
198            return nullptr;
199        }
200    }
201    if (mDimFaces) {
202        if (mDimY < 1) {
203            ALOGE("Cube maps require 2D Types.");
204            return nullptr;
205        }
206    }
207
208    if (mYuvFormat != RS_YUV_NONE) {
209        if (mDimZ || mDimFaces || mDimMipmaps) {
210            ALOGE("YUV only supports basic 2D.");
211            return nullptr;
212        }
213    }
214
215    if (mYuvFormat == RS_YUV_420_888) {
216        ALOGE("YUV_420_888 not supported.");
217        return nullptr;
218    }
219
220    void * id = RS::dispatch->TypeCreate(mRS->getContext(), mElement->getID(), mDimX, mDimY, mDimZ,
221                                         mDimMipmaps, mDimFaces, mYuvFormat);
222    Type *t = new Type(id, mRS);
223    t->mElement = mElement;
224    t->mDimX = mDimX;
225    t->mDimY = mDimY;
226    t->mDimZ = mDimZ;
227    t->mDimMipmaps = mDimMipmaps;
228    t->mDimFaces = mDimFaces;
229    t->mYuvFormat = mYuvFormat;
230
231    t->calcElementCount();
232    return t;
233}
234
235