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