1 /*
2  * Copyright (C) 2011 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 "rsContext.h"
18 #include "rsMesh.h"
19 #include "rs.h"
20 
21 using namespace android;
22 using namespace android::renderscript;
23 
Mesh(Context * rsc)24 Mesh::Mesh(Context *rsc) : ObjectBase(rsc) {
25     mHal.drv = nullptr;
26     mHal.state.primitives = nullptr;
27     mHal.state.primitivesCount = 0;
28     mHal.state.indexBuffers = nullptr;
29     mHal.state.indexBuffersCount = 0;
30     mHal.state.vertexBuffers = nullptr;
31     mHal.state.vertexBuffersCount = 0;
32     mInitialized = false;
33 
34     mVertexBuffers = nullptr;
35     mIndexBuffers = nullptr;
36 }
37 
Mesh(Context * rsc,uint32_t vertexBuffersCount,uint32_t primitivesCount)38 Mesh::Mesh(Context *rsc,
39            uint32_t vertexBuffersCount,
40            uint32_t primitivesCount) : ObjectBase(rsc) {
41     mHal.drv = nullptr;
42     mHal.state.primitivesCount = primitivesCount;
43     mHal.state.indexBuffersCount = primitivesCount;
44     mHal.state.primitives = new RsPrimitive[mHal.state.primitivesCount];
45     mHal.state.indexBuffers = new Allocation *[mHal.state.indexBuffersCount];
46     for (uint32_t i = 0; i < mHal.state.primitivesCount; i ++) {
47         mHal.state.primitives[i] = RS_PRIMITIVE_POINT;
48     }
49     for (uint32_t i = 0; i < mHal.state.indexBuffersCount; i ++) {
50         mHal.state.indexBuffers[i] = nullptr;
51     }
52     mHal.state.vertexBuffersCount = vertexBuffersCount;
53     mHal.state.vertexBuffers = new Allocation *[mHal.state.vertexBuffersCount];
54     for (uint32_t i = 0; i < mHal.state.vertexBuffersCount; i ++) {
55         mHal.state.vertexBuffers[i] = nullptr;
56     }
57 
58     mVertexBuffers = new ObjectBaseRef<Allocation>[mHal.state.vertexBuffersCount];
59     mIndexBuffers = new ObjectBaseRef<Allocation>[mHal.state.primitivesCount];
60 }
61 
~Mesh()62 Mesh::~Mesh() {
63 #ifndef ANDROID_RS_SERIALIZE
64     mRSC->mHal.funcs.mesh.destroy(mRSC, this);
65 #endif
66 
67     delete[] mHal.state.vertexBuffers;
68     delete[] mHal.state.primitives;
69     delete[] mHal.state.indexBuffers;
70 
71     delete[] mVertexBuffers;
72     delete[] mIndexBuffers;
73 }
74 
init()75 void Mesh::init() {
76 #ifndef ANDROID_RS_SERIALIZE
77     mRSC->mHal.funcs.mesh.init(mRSC, this);
78 #endif
79 }
80 
serialize(Context * rsc,OStream * stream) const81 void Mesh::serialize(Context *rsc, OStream *stream) const {
82     // Need to identify ourselves
83     stream->addU32((uint32_t)getClassId());
84     stream->addString(getName());
85 
86     // Store number of vertex streams
87     stream->addU32(mHal.state.vertexBuffersCount);
88     for (uint32_t vCount = 0; vCount < mHal.state.vertexBuffersCount; vCount ++) {
89         mHal.state.vertexBuffers[vCount]->serialize(rsc, stream);
90     }
91 
92     stream->addU32(mHal.state.primitivesCount);
93     // Store the primitives
94     for (uint32_t pCount = 0; pCount < mHal.state.primitivesCount; pCount ++) {
95         stream->addU8((uint8_t)mHal.state.primitives[pCount]);
96 
97         if (mHal.state.indexBuffers[pCount]) {
98             stream->addU32(1);
99             mHal.state.indexBuffers[pCount]->serialize(rsc, stream);
100         } else {
101             stream->addU32(0);
102         }
103     }
104 }
105 
createFromStream(Context * rsc,IStream * stream)106 Mesh *Mesh::createFromStream(Context *rsc, IStream *stream) {
107     // First make sure we are reading the correct object
108     RsA3DClassID classID = (RsA3DClassID)stream->loadU32();
109     if (classID != RS_A3D_CLASS_ID_MESH) {
110         ALOGE("mesh loading skipped due to invalid class id");
111         return nullptr;
112     }
113 
114     const char *name = stream->loadString();
115 
116     uint32_t vertexBuffersCount = stream->loadU32();
117     ObjectBaseRef<Allocation> *vertexBuffers = nullptr;
118     if (vertexBuffersCount) {
119         vertexBuffers = new ObjectBaseRef<Allocation>[vertexBuffersCount];
120 
121         for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) {
122             Allocation *vertexAlloc = Allocation::createFromStream(rsc, stream);
123             vertexBuffers[vCount].set(vertexAlloc);
124         }
125     }
126 
127     uint32_t primitivesCount = stream->loadU32();
128     ObjectBaseRef<Allocation> *indexBuffers = nullptr;
129     RsPrimitive *primitives = nullptr;
130     if (primitivesCount) {
131         indexBuffers = new ObjectBaseRef<Allocation>[primitivesCount];
132         primitives = new RsPrimitive[primitivesCount];
133 
134         // load all primitives
135         for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) {
136             primitives[pCount] = (RsPrimitive)stream->loadU8();
137 
138             // Check to see if the index buffer was stored
139             uint32_t isIndexPresent = stream->loadU32();
140             if (isIndexPresent) {
141                 Allocation *indexAlloc = Allocation::createFromStream(rsc, stream);
142                 indexBuffers[pCount].set(indexAlloc);
143             }
144         }
145     }
146 
147     Mesh *mesh = new Mesh(rsc, vertexBuffersCount, primitivesCount);
148     mesh->assignName(name);
149     for (uint32_t vCount = 0; vCount < vertexBuffersCount; vCount ++) {
150         mesh->setVertexBuffer(vertexBuffers[vCount].get(), vCount);
151     }
152     for (uint32_t pCount = 0; pCount < primitivesCount; pCount ++) {
153         mesh->setPrimitive(indexBuffers[pCount].get(), primitives[pCount], pCount);
154     }
155 
156     // Cleanup
157     if (vertexBuffersCount) {
158         delete[] vertexBuffers;
159     }
160     if (primitivesCount) {
161         delete[] indexBuffers;
162         delete[] primitives;
163     }
164 
165 #ifndef ANDROID_RS_SERIALIZE
166     mesh->init();
167     mesh->uploadAll(rsc);
168 #endif
169     return mesh;
170 }
171 
render(Context * rsc) const172 void Mesh::render(Context *rsc) const {
173     for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) {
174         renderPrimitive(rsc, ct);
175     }
176 }
177 
renderPrimitive(Context * rsc,uint32_t primIndex) const178 void Mesh::renderPrimitive(Context *rsc, uint32_t primIndex) const {
179     if (primIndex >= mHal.state.primitivesCount) {
180         ALOGE("Invalid primitive index");
181         return;
182     }
183 
184     if (mHal.state.indexBuffers[primIndex]) {
185         renderPrimitiveRange(rsc, primIndex, 0, mHal.state.indexBuffers[primIndex]->getType()->getDimX());
186         return;
187     }
188 
189     renderPrimitiveRange(rsc, primIndex, 0, mHal.state.vertexBuffers[0]->getType()->getDimX());
190 }
191 
renderPrimitiveRange(Context * rsc,uint32_t primIndex,uint32_t start,uint32_t len) const192 void Mesh::renderPrimitiveRange(Context *rsc, uint32_t primIndex, uint32_t start, uint32_t len) const {
193     if (len < 1 || primIndex >= mHal.state.primitivesCount) {
194         ALOGE("Invalid mesh or parameters");
195         return;
196     }
197 
198     mRSC->mHal.funcs.mesh.draw(mRSC, this, primIndex, start, len);
199 }
200 
uploadAll(Context * rsc)201 void Mesh::uploadAll(Context *rsc) {
202     for (uint32_t ct = 0; ct < mHal.state.vertexBuffersCount; ct ++) {
203         if (mHal.state.vertexBuffers[ct]) {
204             rsc->mHal.funcs.allocation.markDirty(rsc, mHal.state.vertexBuffers[ct]);
205         }
206     }
207 
208     for (uint32_t ct = 0; ct < mHal.state.primitivesCount; ct ++) {
209         if (mHal.state.indexBuffers[ct]) {
210             rsc->mHal.funcs.allocation.markDirty(rsc, mHal.state.indexBuffers[ct]);
211         }
212     }
213 }
214 
computeBBox(Context * rsc)215 void Mesh::computeBBox(Context *rsc) {
216     float *posPtr = nullptr;
217     uint32_t vectorSize = 0;
218     uint32_t stride = 0;
219     uint32_t numVerts = 0;
220     Allocation *posAlloc = nullptr;
221     // First we need to find the position ptr and stride
222     for (uint32_t ct=0; ct < mHal.state.vertexBuffersCount; ct++) {
223         const Type *bufferType = mHal.state.vertexBuffers[ct]->getType();
224         const Element *bufferElem = bufferType->getElement();
225 
226         for (uint32_t ct=0; ct < bufferElem->getFieldCount(); ct++) {
227             if (strcmp(bufferElem->getFieldName(ct), "position") == 0) {
228                 vectorSize = bufferElem->getField(ct)->getComponent().getVectorSize();
229                 stride = bufferElem->getSizeBytes() / sizeof(float);
230                 uint32_t offset = bufferElem->getFieldOffsetBytes(ct);
231                 posAlloc = mHal.state.vertexBuffers[ct];
232                 const uint8_t *bp = (const uint8_t *)rsc->mHal.funcs.allocation.lock1D(
233                         rsc, posAlloc);
234                 posPtr = (float*)(bp + offset);
235                 numVerts = bufferType->getDimX();
236                 break;
237             }
238         }
239         if (posPtr) {
240             break;
241         }
242     }
243 
244     mBBoxMin[0] = mBBoxMin[1] = mBBoxMin[2] = 1e6;
245     mBBoxMax[0] = mBBoxMax[1] = mBBoxMax[2] = -1e6;
246     if (!posPtr) {
247         ALOGE("Unable to compute bounding box");
248         mBBoxMin[0] = mBBoxMin[1] = mBBoxMin[2] = 0.0f;
249         mBBoxMax[0] = mBBoxMax[1] = mBBoxMax[2] = 0.0f;
250         return;
251     }
252 
253     for (uint32_t i = 0; i < numVerts; i ++) {
254         for (uint32_t v = 0; v < vectorSize; v ++) {
255             mBBoxMin[v] = rsMin(mBBoxMin[v], posPtr[v]);
256             mBBoxMax[v] = rsMax(mBBoxMax[v], posPtr[v]);
257         }
258         posPtr += stride;
259     }
260 
261     if (posAlloc) {
262         rsc->mHal.funcs.allocation.unlock1D(rsc, posAlloc);
263     }
264 }
265 
266 namespace android {
267 namespace renderscript {
268 
rsi_MeshCreate(Context * rsc,RsAllocation * vtx,size_t vtxCount,RsAllocation * idx,size_t idxCount,uint32_t * primType,size_t primTypeCount)269 RsMesh rsi_MeshCreate(Context *rsc,
270                       RsAllocation * vtx, size_t vtxCount,
271                       RsAllocation * idx, size_t idxCount,
272                       uint32_t * primType, size_t primTypeCount) {
273     rsAssert(idxCount == primTypeCount);
274     Mesh *sm = new Mesh(rsc, vtxCount, idxCount);
275     sm->incUserRef();
276 
277     for (uint32_t i = 0; i < vtxCount; i ++) {
278         sm->setVertexBuffer((Allocation*)vtx[i], i);
279     }
280 
281     for (uint32_t i = 0; i < idxCount; i ++) {
282         sm->setPrimitive((Allocation*)idx[i], (RsPrimitive)primType[i], i);
283     }
284 
285     sm->init();
286 
287     return sm;
288 }
289 
290 }}
291