Allocation.cpp revision 69cccdf0659a193d6a75420ec745421fb5c436e6
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
27using namespace android;
28using namespace renderscriptCpp;
29
30void * Allocation::getIDSafe() const {
31    //if (mAdaptedAllocation != NULL) {
32        //return mAdaptedAllocation.getID();
33    //}
34    return getID();
35}
36
37void 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
50Allocation::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
80void 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
88void 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
96void 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
104void 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
112void 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
129void 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
142void 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
155void 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
162void 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/*
170void 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/*
187void 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
200void 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
223void Allocation::generateMipmaps() {
224    rsAllocationGenerateMipmaps(mRS->mContext, getID());
225}
226
227void 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
246void 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
251void 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
256void 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
261void Allocation::copy1DRangeFrom(uint32_t off, size_t count, const float *d, size_t dataLen) {
262    validateIsFloat32();
263    copy1DRangeFromUnchecked(off, count, d, dataLen);
264}
265
266void 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
275void 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
285void 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
292void 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
299void 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
306void 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
313void 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/*
324void copyTo(byte[] d) {
325    validateIsInt8();
326    mRS.validate();
327    mRS.nAllocationRead(getID(), d);
328}
329
330void copyTo(short[] d) {
331    validateIsInt16();
332    mRS.validate();
333    mRS.nAllocationRead(getID(), d);
334}
335
336void copyTo(int[] d) {
337    validateIsInt32();
338    mRS.validate();
339    mRS.nAllocationRead(getID(), d);
340}
341
342void copyTo(float[] d) {
343    validateIsFloat32();
344    mRS.validate();
345    mRS.nAllocationRead(getID(), d);
346}
347
348void 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
361void 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
381android::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
391android::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
400android::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
405android::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/*
422SurfaceTexture 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
432void 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
442static 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
455static 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
463static 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