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