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 #define LOG_TAG "libRS_cpp"
18
19 #include <utils/Log.h>
20 #include <malloc.h>
21
22 #include "RenderScript.h"
23 #include "Element.h"
24 #include "Type.h"
25 #include "Allocation.h"
26
27 using namespace android;
28 using namespace renderscriptCpp;
29
getIDSafe() const30 void * Allocation::getIDSafe() const {
31 //if (mAdaptedAllocation != NULL) {
32 //return mAdaptedAllocation.getID();
33 //}
34 return getID();
35 }
36
updateCacheInfo(sp<const Type> t)37 void Allocation::updateCacheInfo(sp<const Type> t) {
38 mCurrentDimX = t->getX();
39 mCurrentDimY = t->getY();
40 mCurrentDimZ = t->getZ();
41 mCurrentCount = mCurrentDimX;
42 if (mCurrentDimY > 1) {
43 mCurrentCount *= mCurrentDimY;
44 }
45 if (mCurrentDimZ > 1) {
46 mCurrentCount *= mCurrentDimZ;
47 }
48 }
49
Allocation(void * id,RenderScript * rs,sp<const Type> t,uint32_t usage)50 Allocation::Allocation(void *id, RenderScript *rs, sp<const Type> t, uint32_t usage) :
51 BaseObj(id, rs) {
52
53 if ((usage & ~(RS_ALLOCATION_USAGE_SCRIPT |
54 RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE |
55 RS_ALLOCATION_USAGE_GRAPHICS_VERTEX |
56 RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS |
57 RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET |
58 RS_ALLOCATION_USAGE_IO_INPUT |
59 RS_ALLOCATION_USAGE_IO_OUTPUT)) != 0) {
60 ALOGE("Unknown usage specified.");
61 }
62
63 if ((usage & RS_ALLOCATION_USAGE_IO_INPUT) != 0) {
64 mWriteAllowed = false;
65 if ((usage & ~(RS_ALLOCATION_USAGE_IO_INPUT |
66 RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE |
67 RS_ALLOCATION_USAGE_SCRIPT)) != 0) {
68 ALOGE("Invalid usage combination.");
69 }
70 }
71
72 mType = t;
73 mUsage = usage;
74
75 if (t.get() != NULL) {
76 updateCacheInfo(t);
77 }
78 }
79
validateIsInt32()80 void Allocation::validateIsInt32() {
81 RsDataType dt = mType->getElement()->getDataType();
82 if ((dt == RS_TYPE_SIGNED_32) || (dt == RS_TYPE_UNSIGNED_32)) {
83 return;
84 }
85 ALOGE("32 bit integer source does not match allocation type %i", dt);
86 }
87
validateIsInt16()88 void Allocation::validateIsInt16() {
89 RsDataType dt = mType->getElement()->getDataType();
90 if ((dt == RS_TYPE_SIGNED_16) || (dt == RS_TYPE_UNSIGNED_16)) {
91 return;
92 }
93 ALOGE("16 bit integer source does not match allocation type %i", dt);
94 }
95
validateIsInt8()96 void Allocation::validateIsInt8() {
97 RsDataType dt = mType->getElement()->getDataType();
98 if ((dt == RS_TYPE_SIGNED_8) || (dt == RS_TYPE_UNSIGNED_8)) {
99 return;
100 }
101 ALOGE("8 bit integer source does not match allocation type %i", dt);
102 }
103
validateIsFloat32()104 void Allocation::validateIsFloat32() {
105 RsDataType dt = mType->getElement()->getDataType();
106 if (dt == RS_TYPE_FLOAT_32) {
107 return;
108 }
109 ALOGE("32 bit float source does not match allocation type %i", dt);
110 }
111
validateIsObject()112 void Allocation::validateIsObject() {
113 RsDataType dt = mType->getElement()->getDataType();
114 if ((dt == RS_TYPE_ELEMENT) ||
115 (dt == RS_TYPE_TYPE) ||
116 (dt == RS_TYPE_ALLOCATION) ||
117 (dt == RS_TYPE_SAMPLER) ||
118 (dt == RS_TYPE_SCRIPT) ||
119 (dt == RS_TYPE_MESH) ||
120 (dt == RS_TYPE_PROGRAM_FRAGMENT) ||
121 (dt == RS_TYPE_PROGRAM_VERTEX) ||
122 (dt == RS_TYPE_PROGRAM_RASTER) ||
123 (dt == RS_TYPE_PROGRAM_STORE)) {
124 return;
125 }
126 ALOGE("Object source does not match allocation type %i", dt);
127 }
128
updateFromNative()129 void Allocation::updateFromNative() {
130 BaseObj::updateFromNative();
131
132 const void *typeID = rsaAllocationGetType(mRS->mContext, getID());
133 if(typeID != NULL) {
134 sp<const Type> old = mType;
135 sp<Type> t = new Type((void *)typeID, mRS);
136 t->updateFromNative();
137 updateCacheInfo(t);
138 mType = t;
139 }
140 }
141
syncAll(RsAllocationUsageType srcLocation)142 void Allocation::syncAll(RsAllocationUsageType srcLocation) {
143 switch (srcLocation) {
144 case RS_ALLOCATION_USAGE_SCRIPT:
145 case RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS:
146 case RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE:
147 case RS_ALLOCATION_USAGE_GRAPHICS_VERTEX:
148 break;
149 default:
150 ALOGE("Source must be exactly one usage type.");
151 }
152 rsAllocationSyncAll(mRS->mContext, getIDSafe(), srcLocation);
153 }
154
ioSendOutput()155 void Allocation::ioSendOutput() {
156 if ((mUsage & RS_ALLOCATION_USAGE_IO_OUTPUT) == 0) {
157 ALOGE("Can only send buffer if IO_OUTPUT usage specified.");
158 }
159 rsAllocationIoSend(mRS->mContext, getID());
160 }
161
ioGetInput()162 void Allocation::ioGetInput() {
163 if ((mUsage & RS_ALLOCATION_USAGE_IO_INPUT) == 0) {
164 ALOGE("Can only send buffer if IO_OUTPUT usage specified.");
165 }
166 rsAllocationIoReceive(mRS->mContext, getID());
167 }
168
169 /*
170 void copyFrom(BaseObj[] d) {
171 mRS.validate();
172 validateIsObject();
173 if (d.length != mCurrentCount) {
174 ALOGE("Array size mismatch, allocation sizeX = " +
175 mCurrentCount + ", array length = " + d.length);
176 }
177 int i[] = new int[d.length];
178 for (int ct=0; ct < d.length; ct++) {
179 i[ct] = d[ct].getID();
180 }
181 copy1DRangeFromUnchecked(0, mCurrentCount, i);
182 }
183 */
184
185
186 /*
187 void Allocation::setFromFieldPacker(int xoff, FieldPacker fp) {
188 mRS.validate();
189 int eSize = mType.mElement.getSizeBytes();
190 final byte[] data = fp.getData();
191
192 int count = data.length / eSize;
193 if ((eSize * count) != data.length) {
194 ALOGE("Field packer length " + data.length +
195 " not divisible by element size " + eSize + ".");
196 }
197 copy1DRangeFromUnchecked(xoff, count, data);
198 }
199
200 void setFromFieldPacker(int xoff, int component_number, FieldPacker fp) {
201 mRS.validate();
202 if (component_number >= mType.mElement.mElements.length) {
203 ALOGE("Component_number " + component_number + " out of range.");
204 }
205 if(xoff < 0) {
206 ALOGE("Offset must be >= 0.");
207 }
208
209 final byte[] data = fp.getData();
210 int eSize = mType.mElement.mElements[component_number].getSizeBytes();
211 eSize *= mType.mElement.mArraySizes[component_number];
212
213 if (data.length != eSize) {
214 ALOGE("Field packer sizelength " + data.length +
215 " does not match component size " + eSize + ".");
216 }
217
218 mRS.nAllocationElementData1D(getIDSafe(), xoff, mSelectedLOD,
219 component_number, data, data.length);
220 }
221 */
222
generateMipmaps()223 void Allocation::generateMipmaps() {
224 rsAllocationGenerateMipmaps(mRS->mContext, getID());
225 }
226
copy1DRangeFromUnchecked(uint32_t off,size_t count,const void * data,size_t dataLen)227 void Allocation::copy1DRangeFromUnchecked(uint32_t off, size_t count, const void *data,
228 size_t dataLen) {
229
230 if(count < 1) {
231 ALOGE("Count must be >= 1.");
232 return;
233 }
234 if((off + count) > mCurrentCount) {
235 ALOGE("Overflow, Available count %zu, got %zu at offset %zu.", mCurrentCount, count, off);
236 return;
237 }
238 if((count * mType->getElement()->getSizeBytes()) > dataLen) {
239 ALOGE("Array too small for allocation type.");
240 return;
241 }
242
243 rsAllocation1DData(mRS->mContext, getIDSafe(), off, mSelectedLOD, count, data, dataLen);
244 }
245
copy1DRangeFrom(uint32_t off,size_t count,const int32_t * d,size_t dataLen)246 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, const int32_t *d, size_t dataLen) {
247 validateIsInt32();
248 copy1DRangeFromUnchecked(off, count, d, dataLen);
249 }
250
copy1DRangeFrom(uint32_t off,size_t count,const int16_t * d,size_t dataLen)251 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, const int16_t *d, size_t dataLen) {
252 validateIsInt16();
253 copy1DRangeFromUnchecked(off, count, d, dataLen);
254 }
255
copy1DRangeFrom(uint32_t off,size_t count,const int8_t * d,size_t dataLen)256 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, const int8_t *d, size_t dataLen) {
257 validateIsInt8();
258 copy1DRangeFromUnchecked(off, count, d, dataLen);
259 }
260
copy1DRangeFrom(uint32_t off,size_t count,const float * d,size_t dataLen)261 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, const float *d, size_t dataLen) {
262 validateIsFloat32();
263 copy1DRangeFromUnchecked(off, count, d, dataLen);
264 }
265
copy1DRangeFrom(uint32_t off,size_t count,const Allocation * data,uint32_t dataOff)266 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, const Allocation *data,
267 uint32_t dataOff) {
268
269 rsAllocationCopy2DRange(mRS->mContext, getIDSafe(), off, 0,
270 mSelectedLOD, mSelectedFace,
271 count, 1, data->getIDSafe(), dataOff, 0,
272 data->mSelectedLOD, data->mSelectedFace);
273 }
274
validate2DRange(uint32_t xoff,uint32_t yoff,uint32_t w,uint32_t h)275 void Allocation::validate2DRange(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h) {
276 if (mAdaptedAllocation != NULL) {
277
278 } else {
279 if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) {
280 ALOGE("Updated region larger than allocation.");
281 }
282 }
283 }
284
copy2DRangeFrom(uint32_t xoff,uint32_t yoff,uint32_t w,uint32_t h,const int8_t * data,size_t dataLen)285 void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
286 const int8_t *data, size_t dataLen) {
287 validate2DRange(xoff, yoff, w, h);
288 rsAllocation2DData(mRS->mContext, getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
289 w, h, data, dataLen);
290 }
291
copy2DRangeFrom(uint32_t xoff,uint32_t yoff,uint32_t w,uint32_t h,const int16_t * data,size_t dataLen)292 void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
293 const int16_t *data, size_t dataLen) {
294 validate2DRange(xoff, yoff, w, h);
295 rsAllocation2DData(mRS->mContext, getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
296 w, h, data, dataLen);
297 }
298
copy2DRangeFrom(uint32_t xoff,uint32_t yoff,uint32_t w,uint32_t h,const int32_t * data,size_t dataLen)299 void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
300 const int32_t *data, size_t dataLen) {
301 validate2DRange(xoff, yoff, w, h);
302 rsAllocation2DData(mRS->mContext, getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
303 w, h, data, dataLen);
304 }
305
copy2DRangeFrom(uint32_t xoff,uint32_t yoff,uint32_t w,uint32_t h,const float * data,size_t dataLen)306 void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
307 const float *data, size_t dataLen) {
308 validate2DRange(xoff, yoff, w, h);
309 rsAllocation2DData(mRS->mContext, getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
310 w, h, data, dataLen);
311 }
312
copy2DRangeFrom(uint32_t xoff,uint32_t yoff,uint32_t w,uint32_t h,const Allocation * data,size_t dataLen,uint32_t dataXoff,uint32_t dataYoff)313 void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
314 const Allocation *data, size_t dataLen,
315 uint32_t dataXoff, uint32_t dataYoff) {
316 validate2DRange(xoff, yoff, w, h);
317 rsAllocationCopy2DRange(mRS->mContext, getIDSafe(), xoff, yoff,
318 mSelectedLOD, mSelectedFace,
319 w, h, data->getIDSafe(), dataXoff, dataYoff,
320 data->mSelectedLOD, data->mSelectedFace);
321 }
322
323 /*
324 void copyTo(byte[] d) {
325 validateIsInt8();
326 mRS.validate();
327 mRS.nAllocationRead(getID(), d);
328 }
329
330 void copyTo(short[] d) {
331 validateIsInt16();
332 mRS.validate();
333 mRS.nAllocationRead(getID(), d);
334 }
335
336 void copyTo(int[] d) {
337 validateIsInt32();
338 mRS.validate();
339 mRS.nAllocationRead(getID(), d);
340 }
341
342 void copyTo(float[] d) {
343 validateIsFloat32();
344 mRS.validate();
345 mRS.nAllocationRead(getID(), d);
346 }
347
348 void resize(int dimX) {
349 if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) {
350 throw new RSInvalidStateException("Resize only support for 1D allocations at this time.");
351 }
352 mRS.nAllocationResize1D(getID(), dimX);
353 mRS.finish(); // Necessary because resize is fifoed and update is async.
354
355 int typeID = mRS.nAllocationGetType(getID());
356 mType = new Type(typeID, mRS);
357 mType.updateFromNative();
358 updateCacheInfo(mType);
359 }
360
361 void resize(int dimX, int dimY) {
362 if ((mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) {
363 throw new RSInvalidStateException(
364 "Resize only support for 2D allocations at this time.");
365 }
366 if (mType.getY() == 0) {
367 throw new RSInvalidStateException(
368 "Resize only support for 2D allocations at this time.");
369 }
370 mRS.nAllocationResize2D(getID(), dimX, dimY);
371 mRS.finish(); // Necessary because resize is fifoed and update is async.
372
373 int typeID = mRS.nAllocationGetType(getID());
374 mType = new Type(typeID, mRS);
375 mType.updateFromNative();
376 updateCacheInfo(mType);
377 }
378 */
379
380
createTyped(RenderScript * rs,sp<const Type> type,RsAllocationMipmapControl mips,uint32_t usage)381 android::sp<Allocation> Allocation::createTyped(RenderScript *rs, sp<const Type> type,
382 RsAllocationMipmapControl mips, uint32_t usage) {
383 void *id = rsAllocationCreateTyped(rs->mContext, type->getID(), mips, usage, 0);
384 if (id == 0) {
385 ALOGE("Allocation creation failed.");
386 return NULL;
387 }
388 return new Allocation(id, rs, type, usage);
389 }
390
createTyped(RenderScript * rs,sp<const Type> type,RsAllocationMipmapControl mips,uint32_t usage,void * pointer)391 android::sp<Allocation> Allocation::createTyped(RenderScript *rs, sp<const Type> type,
392 RsAllocationMipmapControl mips, uint32_t usage, void *pointer) {
393 void *id = rsAllocationCreateTyped(rs->mContext, type->getID(), mips, usage, (uint32_t)pointer);
394 if (id == 0) {
395 ALOGE("Allocation creation failed.");
396 }
397 return new Allocation(id, rs, type, usage);
398 }
399
createTyped(RenderScript * rs,sp<const Type> type,uint32_t usage)400 android::sp<Allocation> Allocation::createTyped(RenderScript *rs, sp<const Type> type,
401 uint32_t usage) {
402 return createTyped(rs, type, RS_ALLOCATION_MIPMAP_NONE, usage);
403 }
404
createSized(RenderScript * rs,sp<const Element> e,size_t count,uint32_t usage)405 android::sp<Allocation> Allocation::createSized(RenderScript *rs, sp<const Element> e,
406 size_t count, uint32_t usage) {
407
408 Type::Builder b(rs, e);
409 b.setX(count);
410 sp<const Type> t = b.create();
411
412 void *id = rsAllocationCreateTyped(rs->mContext, t->getID(),
413 RS_ALLOCATION_MIPMAP_NONE, usage, 0);
414 if (id == 0) {
415 ALOGE("Allocation creation failed.");
416 }
417 return new Allocation(id, rs, t, usage);
418 }
419
420
421 /*
422 SurfaceTexture getSurfaceTexture() {
423 if ((mUsage & USAGE_GRAPHICS_SURFACE_TEXTURE_INPUT_OPAQUE) == 0) {
424 throw new RSInvalidStateException("Allocation is not a surface texture.");
425 }
426
427 int id = mRS.nAllocationGetSurfaceTextureID(getID());
428 return new SurfaceTexture(id);
429
430 }
431
432 void setSurfaceTexture(SurfaceTexture sur) {
433 if ((mUsage & USAGE_IO_OUTPUT) == 0) {
434 throw new RSInvalidStateException("Allocation is not USAGE_IO_OUTPUT.");
435 }
436
437 mRS.validate();
438 mRS.nAllocationSetSurfaceTexture(getID(), sur);
439 }
440
441
442 static Allocation createFromBitmapResource(RenderScript rs,
443 Resources res,
444 int id,
445 MipmapControl mips,
446 int usage) {
447
448 rs.validate();
449 Bitmap b = BitmapFactory.decodeResource(res, id);
450 Allocation alloc = createFromBitmap(rs, b, mips, usage);
451 b.recycle();
452 return alloc;
453 }
454
455 static Allocation createFromBitmapResource(RenderScript rs,
456 Resources res,
457 int id) {
458 return createFromBitmapResource(rs, res, id,
459 MipmapControl.MIPMAP_NONE,
460 USAGE_GRAPHICS_TEXTURE);
461 }
462
463 static Allocation createFromString(RenderScript rs,
464 String str,
465 int usage) {
466 rs.validate();
467 byte[] allocArray = NULL;
468 try {
469 allocArray = str.getBytes("UTF-8");
470 Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage);
471 alloc.copyFrom(allocArray);
472 return alloc;
473 }
474 catch (Exception e) {
475 throw new RSRuntimeException("Could not convert string to utf-8.");
476 }
477 }
478 */
479
480