Allocation.cpp revision 94280f817b502caf0b4e40cbcbe300f5178b7473
1/*
2 * Copyright (C) 2013 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 "RenderScript.h"
18#include "rsCppInternal.h"
19
20using namespace android;
21using namespace RSC;
22
23void * Allocation::getIDSafe() const {
24    return getID();
25}
26
27void Allocation::updateCacheInfo(sp<const Type> t) {
28    mCurrentDimX = t->getX();
29    mCurrentDimY = t->getY();
30    mCurrentDimZ = t->getZ();
31    mCurrentCount = mCurrentDimX;
32    if (mCurrentDimY > 1) {
33        mCurrentCount *= mCurrentDimY;
34    }
35    if (mCurrentDimZ > 1) {
36        mCurrentCount *= mCurrentDimZ;
37    }
38}
39
40Allocation::Allocation(void *id, sp<RS> rs, sp<const Type> t, uint32_t usage) :
41    BaseObj(id, rs), mSelectedY(0), mSelectedZ(0), mSelectedLOD(0),
42    mSelectedFace(RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X) {
43
44    if ((usage & ~(RS_ALLOCATION_USAGE_SCRIPT |
45                   RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE |
46                   RS_ALLOCATION_USAGE_GRAPHICS_VERTEX |
47                   RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS |
48                   RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET |
49                   RS_ALLOCATION_USAGE_IO_INPUT |
50                   RS_ALLOCATION_USAGE_IO_OUTPUT |
51                   RS_ALLOCATION_USAGE_SHARED)) != 0) {
52        ALOGE("Unknown usage specified.");
53    }
54
55    if ((usage & RS_ALLOCATION_USAGE_IO_INPUT) != 0) {
56        mWriteAllowed = false;
57        if ((usage & ~(RS_ALLOCATION_USAGE_IO_INPUT |
58                       RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE |
59                       RS_ALLOCATION_USAGE_SCRIPT)) != 0) {
60            ALOGE("Invalid usage combination.");
61        }
62    }
63
64    mType = t;
65    mUsage = usage;
66
67    if (t != nullptr) {
68        updateCacheInfo(t);
69    }
70
71}
72
73
74
75void Allocation::validateIsInt32() {
76    RsDataType dt = mType->getElement()->getDataType();
77    if ((dt == RS_TYPE_SIGNED_32) || (dt == RS_TYPE_UNSIGNED_32)) {
78        return;
79    }
80    ALOGE("32 bit integer source does not match allocation type %i", dt);
81}
82
83void Allocation::validateIsInt16() {
84    RsDataType dt = mType->getElement()->getDataType();
85    if ((dt == RS_TYPE_SIGNED_16) || (dt == RS_TYPE_UNSIGNED_16)) {
86        return;
87    }
88    ALOGE("16 bit integer source does not match allocation type %i", dt);
89}
90
91void Allocation::validateIsInt8() {
92    RsDataType dt = mType->getElement()->getDataType();
93    if ((dt == RS_TYPE_SIGNED_8) || (dt == RS_TYPE_UNSIGNED_8)) {
94        return;
95    }
96    ALOGE("8 bit integer source does not match allocation type %i", dt);
97}
98
99void Allocation::validateIsFloat32() {
100    RsDataType dt = mType->getElement()->getDataType();
101    if (dt == RS_TYPE_FLOAT_32) {
102        return;
103    }
104    ALOGE("32 bit float source does not match allocation type %i", dt);
105}
106
107void Allocation::validateIsObject() {
108    RsDataType dt = mType->getElement()->getDataType();
109    if ((dt == RS_TYPE_ELEMENT) ||
110        (dt == RS_TYPE_TYPE) ||
111        (dt == RS_TYPE_ALLOCATION) ||
112        (dt == RS_TYPE_SAMPLER) ||
113        (dt == RS_TYPE_SCRIPT) ||
114        (dt == RS_TYPE_MESH) ||
115        (dt == RS_TYPE_PROGRAM_FRAGMENT) ||
116        (dt == RS_TYPE_PROGRAM_VERTEX) ||
117        (dt == RS_TYPE_PROGRAM_RASTER) ||
118        (dt == RS_TYPE_PROGRAM_STORE)) {
119        return;
120    }
121    ALOGE("Object source does not match allocation type %i", dt);
122}
123
124void Allocation::updateFromNative() {
125    BaseObj::updateFromNative();
126
127    const void *typeID = RS::dispatch->AllocationGetType(mRS->getContext(), getID());
128    if(typeID != nullptr) {
129        sp<const Type> old = mType;
130        sp<Type> t = new Type((void *)typeID, mRS);
131        t->updateFromNative();
132        updateCacheInfo(t);
133        mType = t;
134    }
135}
136
137void Allocation::syncAll(RsAllocationUsageType srcLocation) {
138    switch (srcLocation) {
139    case RS_ALLOCATION_USAGE_SCRIPT:
140    case RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS:
141    case RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE:
142    case RS_ALLOCATION_USAGE_GRAPHICS_VERTEX:
143    case RS_ALLOCATION_USAGE_SHARED:
144        break;
145    default:
146        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Source must be exactly one usage type.");
147        return;
148    }
149    tryDispatch(mRS, RS::dispatch->AllocationSyncAll(mRS->getContext(), getIDSafe(), srcLocation));
150}
151
152void Allocation::ioSendOutput() {
153#ifndef RS_COMPATIBILITY_LIB
154    if ((mUsage & RS_ALLOCATION_USAGE_IO_OUTPUT) == 0) {
155        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only send buffer if IO_OUTPUT usage specified.");
156        return;
157    }
158    tryDispatch(mRS, RS::dispatch->AllocationIoSend(mRS->getContext(), getID()));
159#endif
160}
161
162void Allocation::ioGetInput() {
163#ifndef RS_COMPATIBILITY_LIB
164    if ((mUsage & RS_ALLOCATION_USAGE_IO_INPUT) == 0) {
165        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only send buffer if IO_OUTPUT usage specified.");
166        return;
167    }
168    tryDispatch(mRS, RS::dispatch->AllocationIoReceive(mRS->getContext(), getID()));
169#endif
170}
171
172void * Allocation::getPointer(size_t *stride) {
173    void *p = nullptr;
174    if (!(mUsage & RS_ALLOCATION_USAGE_SHARED)) {
175        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Allocation does not support USAGE_SHARED.");
176        return nullptr;
177    }
178
179    // FIXME: decide if lack of getPointer should cause compat mode
180    if (RS::dispatch->AllocationGetPointer == nullptr) {
181        mRS->throwError(RS_ERROR_RUNTIME_ERROR, "Can't use getPointer on older APIs");
182        return nullptr;
183    }
184
185    p = RS::dispatch->AllocationGetPointer(mRS->getContext(), getIDSafe(), 0,
186                                           RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, 0, 0, stride, sizeof(size_t));
187    if (mRS->getError() != RS_SUCCESS) {
188        mRS->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation lock failed");
189        p = nullptr;
190    }
191    return p;
192}
193
194void Allocation::copy1DRangeFrom(uint32_t off, size_t count, const void *data) {
195
196    if(count < 1) {
197        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Count must be >= 1.");
198        return;
199    }
200    if((off + count) > mCurrentCount) {
201        ALOGE("Overflow, Available count %u, got %zu at offset %u.", mCurrentCount, count, off);
202        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Invalid copy specified");
203        return;
204    }
205
206    tryDispatch(mRS, RS::dispatch->Allocation1DData(mRS->getContext(), getIDSafe(), off, mSelectedLOD,
207                                                    count, data, count * mType->getElement()->getSizeBytes()));
208}
209
210void Allocation::copy1DRangeTo(uint32_t off, size_t count, void *data) {
211    if(count < 1) {
212        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Count must be >= 1.");
213        return;
214    }
215    if((off + count) > mCurrentCount) {
216        ALOGE("Overflow, Available count %u, got %zu at offset %u.", mCurrentCount, count, off);
217        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Invalid copy specified");
218        return;
219    }
220
221    tryDispatch(mRS, RS::dispatch->Allocation1DRead(mRS->getContext(), getIDSafe(), off, mSelectedLOD,
222                                                    count, data, count * mType->getElement()->getSizeBytes()));
223}
224
225void Allocation::copy1DRangeFrom(uint32_t off, size_t count, sp<const Allocation> data,
226                                 uint32_t dataOff) {
227
228    tryDispatch(mRS, RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), off, 0,
229                                                         mSelectedLOD, mSelectedFace,
230                                                         count, 1, data->getIDSafe(), dataOff, 0,
231                                                         data->mSelectedLOD, data->mSelectedFace));
232}
233
234void Allocation::copy1DFrom(const void* data) {
235    copy1DRangeFrom(0, mCurrentCount, data);
236}
237
238void Allocation::copy1DTo(void* data) {
239    copy1DRangeTo(0, mCurrentCount, data);
240}
241
242
243void Allocation::validate2DRange(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h) {
244    if (mAdaptedAllocation != nullptr) {
245
246    } else {
247        if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) {
248            mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Updated region larger than allocation.");
249        }
250    }
251}
252
253void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
254                                 const void *data) {
255    validate2DRange(xoff, yoff, w, h);
256    tryDispatch(mRS, RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff,
257                                                    yoff, mSelectedLOD, mSelectedFace,
258                                                    w, h, data, w * h * mType->getElement()->getSizeBytes(),
259                                                    w * mType->getElement()->getSizeBytes()));
260}
261
262void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
263                                 sp<const Allocation> data, uint32_t dataXoff, uint32_t dataYoff) {
264    validate2DRange(xoff, yoff, w, h);
265    tryDispatch(mRS, RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), xoff, yoff,
266                                                         mSelectedLOD, mSelectedFace,
267                                                         w, h, data->getIDSafe(), dataXoff, dataYoff,
268                                                         data->mSelectedLOD, data->mSelectedFace));
269}
270
271void Allocation::copy2DRangeTo(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
272                               void* data) {
273    validate2DRange(xoff, yoff, w, h);
274    tryDispatch(mRS, RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff,
275                                                    mSelectedLOD, mSelectedFace, w, h, data,
276                                                    w * h * mType->getElement()->getSizeBytes(),
277                                                    w * mType->getElement()->getSizeBytes()));
278}
279
280void Allocation::copy2DStridedFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
281                                   const void *data, size_t stride) {
282    validate2DRange(xoff, yoff, w, h);
283    tryDispatch(mRS, RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff, yoff,
284                                                    mSelectedLOD, mSelectedFace, w, h, data,
285                                                    w * h * mType->getElement()->getSizeBytes(), stride));
286}
287
288void Allocation::copy2DStridedFrom(const void* data, size_t stride) {
289    copy2DStridedFrom(0, 0, mCurrentDimX, mCurrentDimY, data, stride);
290}
291
292void Allocation::copy2DStridedTo(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
293                                 void *data, size_t stride) {
294    validate2DRange(xoff, yoff, w, h);
295    tryDispatch(mRS, RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff,
296                                                    mSelectedLOD, mSelectedFace, w, h, data,
297                                                    w * h * mType->getElement()->getSizeBytes(), stride));
298}
299
300void Allocation::copy2DStridedTo(void* data, size_t stride) {
301    copy2DStridedTo(0, 0, mCurrentDimX, mCurrentDimY, data, stride);
302}
303
304void Allocation::validate3DRange(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w,
305                                 uint32_t h, uint32_t d) {
306    if (mAdaptedAllocation != nullptr) {
307
308    } else {
309        if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY) || ((zoff + d) > mCurrentDimZ)) {
310            mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Updated region larger than allocation.");
311        }
312    }
313}
314
315void Allocation::copy3DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w,
316                                 uint32_t h, uint32_t d, const void* data) {
317    validate3DRange(xoff, yoff, zoff, w, h, d);
318    tryDispatch(mRS, RS::dispatch->Allocation3DData(mRS->getContext(), getIDSafe(), xoff, yoff, zoff,
319                                                    mSelectedLOD, w, h, d, data,
320                                                    w * h * d * mType->getElement()->getSizeBytes(),
321                                                    w * mType->getElement()->getSizeBytes()));
322}
323
324void Allocation::copy3DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w, uint32_t h, uint32_t d,
325                                 sp<const Allocation> data, uint32_t dataXoff, uint32_t dataYoff, uint32_t dataZoff) {
326    validate3DRange(xoff, yoff, zoff, dataXoff, dataYoff, dataZoff);
327    tryDispatch(mRS, RS::dispatch->AllocationCopy3DRange(mRS->getContext(), getIDSafe(), xoff, yoff, zoff,
328                                                         mSelectedLOD, w, h, d, data->getIDSafe(),
329                                                         dataXoff, dataYoff, dataZoff, data->mSelectedLOD));
330}
331
332
333sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type,
334                                    RsAllocationMipmapControl mipmaps, uint32_t usage) {
335    void *id = 0;
336    if (rs->getError() == RS_SUCCESS) {
337        id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mipmaps, usage, 0);
338    }
339    if (id == 0) {
340        rs->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation creation failed");
341        return nullptr;
342    }
343    return new Allocation(id, rs, type, usage);
344}
345
346sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type,
347                                    RsAllocationMipmapControl mipmaps, uint32_t usage,
348                                    void *pointer) {
349    void *id = 0;
350    if (rs->getError() == RS_SUCCESS) {
351        id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mipmaps, usage,
352                                                 (uintptr_t)pointer);
353    }
354    if (id == 0) {
355        rs->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation creation failed");
356        return nullptr;
357    }
358    return new Allocation(id, rs, type, usage);
359}
360
361sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type,
362                                    uint32_t usage) {
363    return createTyped(rs, type, RS_ALLOCATION_MIPMAP_NONE, usage);
364}
365
366sp<Allocation> Allocation::createSized(sp<RS> rs, sp<const Element> e,
367                                    size_t count, uint32_t usage) {
368    Type::Builder b(rs, e);
369    b.setX(count);
370    sp<const Type> t = b.create();
371
372    return createTyped(rs, t, usage);
373}
374
375sp<Allocation> Allocation::createSized2D(sp<RS> rs, sp<const Element> e,
376                                      size_t x, size_t y, uint32_t usage) {
377    Type::Builder b(rs, e);
378    b.setX(x);
379    b.setY(y);
380    sp<const Type> t = b.create();
381
382    return createTyped(rs, t, usage);
383}
384