Home | History | Annotate | Download | only in cpp
      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 
     20 using android::RSC::Allocation;
     21 using android::RSC::sp;
     22 using android::Surface;
     23 
     24 void * Allocation::getIDSafe() const {
     25     return getID();
     26 }
     27 
     28 void Allocation::updateCacheInfo(const sp<const Type>& t) {
     29     mCurrentDimX = t->getX();
     30     mCurrentDimY = t->getY();
     31     mCurrentDimZ = t->getZ();
     32     mCurrentCount = mCurrentDimX;
     33     if (mCurrentDimY > 1) {
     34         mCurrentCount *= mCurrentDimY;
     35     }
     36     if (mCurrentDimZ > 1) {
     37         mCurrentCount *= mCurrentDimZ;
     38     }
     39 }
     40 
     41 Allocation::Allocation(void *id, sp<RS> rs, sp<const Type> t, uint32_t usage) :
     42     BaseObj(id, rs), mSelectedY(0), mSelectedZ(0), mSelectedLOD(0),
     43     mSelectedFace(RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X) {
     44 
     45     if ((usage & ~(RS_ALLOCATION_USAGE_SCRIPT |
     46                    RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE |
     47                    RS_ALLOCATION_USAGE_GRAPHICS_VERTEX |
     48                    RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS |
     49                    RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET |
     50                    RS_ALLOCATION_USAGE_IO_INPUT |
     51                    RS_ALLOCATION_USAGE_IO_OUTPUT |
     52                    RS_ALLOCATION_USAGE_OEM |
     53                    RS_ALLOCATION_USAGE_SHARED)) != 0) {
     54         ALOGE("Unknown usage specified.");
     55     }
     56 
     57     if ((usage & RS_ALLOCATION_USAGE_IO_INPUT) != 0) {
     58         mWriteAllowed = false;
     59         if ((usage & ~(RS_ALLOCATION_USAGE_IO_INPUT |
     60                        RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE |
     61                        RS_ALLOCATION_USAGE_SCRIPT)) != 0) {
     62             ALOGE("Invalid usage combination.");
     63         }
     64     }
     65 
     66     mType = t;
     67     mUsage = usage;
     68     mAutoPadding = false;
     69     if (t != nullptr) {
     70         updateCacheInfo(t);
     71     }
     72 
     73 }
     74 
     75 
     76 void Allocation::validateIsInt64() {
     77     RsDataType dt = mType->getElement()->getDataType();
     78     if ((dt == RS_TYPE_SIGNED_64) || (dt == RS_TYPE_UNSIGNED_64)) {
     79         return;
     80     }
     81     ALOGE("64 bit integer source does not match allocation type %i", dt);
     82 }
     83 
     84 void Allocation::validateIsInt32() {
     85     RsDataType dt = mType->getElement()->getDataType();
     86     if ((dt == RS_TYPE_SIGNED_32) || (dt == RS_TYPE_UNSIGNED_32)) {
     87         return;
     88     }
     89     ALOGE("32 bit integer source does not match allocation type %i", dt);
     90 }
     91 
     92 void Allocation::validateIsInt16() {
     93     RsDataType dt = mType->getElement()->getDataType();
     94     if ((dt == RS_TYPE_SIGNED_16) || (dt == RS_TYPE_UNSIGNED_16)) {
     95         return;
     96     }
     97     ALOGE("16 bit integer source does not match allocation type %i", dt);
     98 }
     99 
    100 void Allocation::validateIsInt8() {
    101     RsDataType dt = mType->getElement()->getDataType();
    102     if ((dt == RS_TYPE_SIGNED_8) || (dt == RS_TYPE_UNSIGNED_8)) {
    103         return;
    104     }
    105     ALOGE("8 bit integer source does not match allocation type %i", dt);
    106 }
    107 
    108 void Allocation::validateIsFloat32() {
    109     RsDataType dt = mType->getElement()->getDataType();
    110     if (dt == RS_TYPE_FLOAT_32) {
    111         return;
    112     }
    113     ALOGE("32 bit float source does not match allocation type %i", dt);
    114 }
    115 
    116 void Allocation::validateIsFloat64() {
    117     RsDataType dt = mType->getElement()->getDataType();
    118     if (dt == RS_TYPE_FLOAT_64) {
    119         return;
    120     }
    121     ALOGE("64 bit float source does not match allocation type %i", dt);
    122 }
    123 
    124 void Allocation::validateIsObject() {
    125     RsDataType dt = mType->getElement()->getDataType();
    126     if ((dt == RS_TYPE_ELEMENT) ||
    127         (dt == RS_TYPE_TYPE) ||
    128         (dt == RS_TYPE_ALLOCATION) ||
    129         (dt == RS_TYPE_SAMPLER) ||
    130         (dt == RS_TYPE_SCRIPT) ||
    131         (dt == RS_TYPE_MESH) ||
    132         (dt == RS_TYPE_PROGRAM_FRAGMENT) ||
    133         (dt == RS_TYPE_PROGRAM_VERTEX) ||
    134         (dt == RS_TYPE_PROGRAM_RASTER) ||
    135         (dt == RS_TYPE_PROGRAM_STORE)) {
    136         return;
    137     }
    138     ALOGE("Object source does not match allocation type %i", dt);
    139 }
    140 
    141 void Allocation::updateFromNative() {
    142     BaseObj::updateFromNative();
    143 
    144     const void *typeID = RS::dispatch->AllocationGetType(mRS->getContext(), getID());
    145     if(typeID != nullptr) {
    146         sp<Type> t = new Type((void *)typeID, mRS);
    147         t->updateFromNative();
    148         updateCacheInfo(t);
    149         mType = t;
    150     }
    151 }
    152 
    153 void Allocation::syncAll(RsAllocationUsageType srcLocation) {
    154     switch (srcLocation) {
    155     case RS_ALLOCATION_USAGE_SCRIPT:
    156     case RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS:
    157     case RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE:
    158     case RS_ALLOCATION_USAGE_GRAPHICS_VERTEX:
    159     case RS_ALLOCATION_USAGE_SHARED:
    160         break;
    161     default:
    162         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Source must be exactly one usage type.");
    163         return;
    164     }
    165     tryDispatch(mRS, RS::dispatch->AllocationSyncAll(mRS->getContext(), getIDSafe(), srcLocation));
    166 }
    167 
    168 void * Allocation::getPointer(size_t *stride) {
    169     void *p = nullptr;
    170     if (!(mUsage & RS_ALLOCATION_USAGE_SHARED)) {
    171         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Allocation does not support USAGE_SHARED.");
    172         return nullptr;
    173     }
    174 
    175     // FIXME: decide if lack of getPointer should cause compat mode
    176     if (RS::dispatch->AllocationGetPointer == nullptr) {
    177         mRS->throwError(RS_ERROR_RUNTIME_ERROR, "Can't use getPointer on older APIs");
    178         return nullptr;
    179     }
    180 
    181     p = RS::dispatch->AllocationGetPointer(mRS->getContext(), getIDSafe(), 0,
    182                                            RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, 0, 0, stride, sizeof(size_t));
    183     if (mRS->getError() != RS_SUCCESS) {
    184         mRS->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation lock failed");
    185         p = nullptr;
    186     }
    187     return p;
    188 }
    189 
    190 // ---------------------------------------------------------------------------
    191 //Functions needed for autopadding & unpadding
    192 static void copyWithPadding(void* ptr, const void* srcPtr, int mSize, int count) {
    193     int sizeBytesPad = mSize * 4;
    194     int sizeBytes = mSize * 3;
    195     uint8_t *dst = static_cast<uint8_t *>(ptr);
    196     const uint8_t *src = static_cast<const uint8_t *>(srcPtr);
    197     for (int i = 0; i < count; i++) {
    198         memcpy(dst, src, sizeBytes);
    199         dst += sizeBytesPad;
    200         src += sizeBytes;
    201     }
    202 }
    203 
    204 static void copyWithUnPadding(void* ptr, const void* srcPtr, int mSize, int count) {
    205     int sizeBytesPad = mSize * 4;
    206     int sizeBytes = mSize * 3;
    207     uint8_t *dst = static_cast<uint8_t *>(ptr);
    208     const uint8_t *src = static_cast<const uint8_t *>(srcPtr);
    209     for (int i = 0; i < count; i++) {
    210         memcpy(dst, src, sizeBytes);
    211         dst += sizeBytes;
    212         src += sizeBytesPad;
    213     }
    214 }
    215 // ---------------------------------------------------------------------------
    216 
    217 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, const void *data) {
    218 
    219     if(count < 1) {
    220         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Count must be >= 1.");
    221         return;
    222     }
    223     if((off + count) > mCurrentCount) {
    224         ALOGE("Overflow, Available count %u, got %zu at offset %u.", mCurrentCount, count, off);
    225         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Invalid copy specified");
    226         return;
    227     }
    228     if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) {
    229         size_t eSize = mType->getElement()->getSizeBytes();
    230         void *ptr = malloc(eSize * count);
    231         copyWithPadding(ptr, data, eSize / 4, count);
    232         tryDispatch(mRS, RS::dispatch->Allocation1DData(mRS->getContext(), getIDSafe(), off, mSelectedLOD,
    233                                                         count, ptr, count * mType->getElement()->getSizeBytes()));
    234         free(ptr);
    235     } else {
    236         tryDispatch(mRS, RS::dispatch->Allocation1DData(mRS->getContext(), getIDSafe(), off, mSelectedLOD,
    237                                                         count, data, count * mType->getElement()->getSizeBytes()));
    238     }
    239 }
    240 
    241 void Allocation::copy1DRangeTo(uint32_t off, size_t count, void *data) {
    242     if(count < 1) {
    243         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Count must be >= 1.");
    244         return;
    245     }
    246     if((off + count) > mCurrentCount) {
    247         ALOGE("Overflow, Available count %u, got %zu at offset %u.", mCurrentCount, count, off);
    248         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Invalid copy specified");
    249         return;
    250     }
    251     if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) {
    252         size_t eSize = mType->getElement()->getSizeBytes();
    253         void *ptr = malloc(eSize * count);
    254         tryDispatch(mRS, RS::dispatch->Allocation1DRead(mRS->getContext(), getIDSafe(), off, mSelectedLOD,
    255                                                         count, ptr, count * mType->getElement()->getSizeBytes()));
    256         copyWithUnPadding(data, ptr, eSize / 4, count);
    257         free(ptr);
    258     } else {
    259         tryDispatch(mRS, RS::dispatch->Allocation1DRead(mRS->getContext(), getIDSafe(), off, mSelectedLOD,
    260                                                         count, data, count * mType->getElement()->getSizeBytes()));
    261     }
    262 }
    263 
    264 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, const sp<const Allocation>& data,
    265                                  uint32_t dataOff) {
    266 
    267     tryDispatch(mRS, RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), off, 0,
    268                                                          mSelectedLOD, mSelectedFace,
    269                                                          count, 1, data->getIDSafe(), dataOff, 0,
    270                                                          data->mSelectedLOD, data->mSelectedFace));
    271 }
    272 
    273 void Allocation::copy1DFrom(const void* data) {
    274     copy1DRangeFrom(0, mCurrentCount, data);
    275 }
    276 
    277 void Allocation::copy1DTo(void* data) {
    278     copy1DRangeTo(0, mCurrentCount, data);
    279 }
    280 
    281 
    282 void Allocation::validate2DRange(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h) {
    283     if (mAdaptedAllocation != nullptr) {
    284 
    285     } else {
    286         if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) {
    287             mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Updated region larger than allocation.");
    288         }
    289     }
    290 }
    291 
    292 void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
    293                                  const void *data) {
    294     validate2DRange(xoff, yoff, w, h);
    295     if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) {
    296         size_t eSize = mType->getElement()->getSizeBytes();
    297         void *ptr = malloc(eSize * w * h);
    298         copyWithPadding(ptr, data, eSize / 4, w * h);
    299         tryDispatch(mRS, RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff,
    300                                                         yoff, mSelectedLOD, mSelectedFace,
    301                                                         w, h, ptr, w * h * mType->getElement()->getSizeBytes(),
    302                                                         w * mType->getElement()->getSizeBytes()));
    303         free(ptr);
    304     } else {
    305         tryDispatch(mRS, RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff,
    306                                                         yoff, mSelectedLOD, mSelectedFace,
    307                                                         w, h, data, w * h * mType->getElement()->getSizeBytes(),
    308                                                         w * mType->getElement()->getSizeBytes()));
    309     }
    310 }
    311 
    312 void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
    313                                  const sp<const Allocation>& data, uint32_t dataXoff, uint32_t dataYoff) {
    314     validate2DRange(xoff, yoff, w, h);
    315     tryDispatch(mRS, RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), xoff, yoff,
    316                                                          mSelectedLOD, mSelectedFace,
    317                                                          w, h, data->getIDSafe(), dataXoff, dataYoff,
    318                                                          data->mSelectedLOD, data->mSelectedFace));
    319 }
    320 
    321 void Allocation::copy2DRangeTo(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
    322                                void* data) {
    323     validate2DRange(xoff, yoff, w, h);
    324     if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) {
    325         size_t eSize = mType->getElement()->getSizeBytes();
    326         void *ptr = malloc(eSize * w * h);
    327         tryDispatch(mRS, RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff,
    328                                                         mSelectedLOD, mSelectedFace, w, h, ptr,
    329                                                         w * h * mType->getElement()->getSizeBytes(),
    330                                                         w * mType->getElement()->getSizeBytes()));
    331         copyWithUnPadding(data, ptr, eSize / 4, w * h);
    332         free(ptr);
    333     } else {
    334         tryDispatch(mRS, RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff,
    335                                                         mSelectedLOD, mSelectedFace, w, h, data,
    336                                                         w * h * mType->getElement()->getSizeBytes(),
    337                                                         w * mType->getElement()->getSizeBytes()));
    338     }
    339 }
    340 
    341 void Allocation::copy2DStridedFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
    342                                    const void *data, size_t stride) {
    343     validate2DRange(xoff, yoff, w, h);
    344     tryDispatch(mRS, RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff, yoff,
    345                                                     mSelectedLOD, mSelectedFace, w, h, data,
    346                                                     w * h * mType->getElement()->getSizeBytes(), stride));
    347 }
    348 
    349 void Allocation::copy2DStridedFrom(const void* data, size_t stride) {
    350     copy2DStridedFrom(0, 0, mCurrentDimX, mCurrentDimY, data, stride);
    351 }
    352 
    353 void Allocation::copy2DStridedTo(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
    354                                  void *data, size_t stride) {
    355     validate2DRange(xoff, yoff, w, h);
    356     tryDispatch(mRS, RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff,
    357                                                     mSelectedLOD, mSelectedFace, w, h, data,
    358                                                     w * h * mType->getElement()->getSizeBytes(), stride));
    359 }
    360 
    361 void Allocation::copy2DStridedTo(void* data, size_t stride) {
    362     copy2DStridedTo(0, 0, mCurrentDimX, mCurrentDimY, data, stride);
    363 }
    364 
    365 void Allocation::validate3DRange(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w,
    366                                  uint32_t h, uint32_t d) {
    367     if (mAdaptedAllocation != nullptr) {
    368 
    369     } else {
    370         if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY) || ((zoff + d) > mCurrentDimZ)) {
    371             mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Updated region larger than allocation.");
    372         }
    373     }
    374 }
    375 
    376 void Allocation::copy3DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w,
    377                                  uint32_t h, uint32_t d, const void* data) {
    378     validate3DRange(xoff, yoff, zoff, w, h, d);
    379     if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) {
    380         size_t eSize = mType->getElement()->getSizeBytes();
    381         void *ptr = malloc(eSize * w * h * d);
    382         copyWithPadding(ptr, data, eSize / 4, w * h * d);
    383         tryDispatch(mRS, RS::dispatch->Allocation3DData(mRS->getContext(), getIDSafe(), xoff, yoff, zoff,
    384                                                         mSelectedLOD, w, h, d, ptr,
    385                                                         w * h * d * mType->getElement()->getSizeBytes(),
    386                                                         w * mType->getElement()->getSizeBytes()));
    387         free(ptr);
    388     } else {
    389         tryDispatch(mRS, RS::dispatch->Allocation3DData(mRS->getContext(), getIDSafe(), xoff, yoff, zoff,
    390                                                         mSelectedLOD, w, h, d, data,
    391                                                         w * h * d * mType->getElement()->getSizeBytes(),
    392                                                         w * mType->getElement()->getSizeBytes()));
    393     }
    394 }
    395 
    396 void Allocation::copy3DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w, uint32_t h, uint32_t d,
    397                                  const sp<const Allocation>& data, uint32_t dataXoff, uint32_t dataYoff, uint32_t dataZoff) {
    398     validate3DRange(xoff, yoff, zoff, w, h, d);
    399     tryDispatch(mRS, RS::dispatch->AllocationCopy3DRange(mRS->getContext(), getIDSafe(), xoff, yoff, zoff,
    400                                                          mSelectedLOD, w, h, d, data->getIDSafe(),
    401                                                          dataXoff, dataYoff, dataZoff, data->mSelectedLOD));
    402 }
    403 
    404 void Allocation::copy3DRangeTo(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w,
    405                                  uint32_t h, uint32_t d, void* data) {
    406     validate3DRange(xoff, yoff, zoff, w, h, d);
    407     if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) {
    408         size_t eSize = mType->getElement()->getSizeBytes();
    409         void *ptr = malloc(eSize * w * h * d);
    410         tryDispatch(mRS, RS::dispatch->Allocation3DRead(mRS->getContext(), getIDSafe(), xoff, yoff, zoff,
    411                                                         mSelectedLOD, w, h, d, ptr,
    412                                                         w * h * d * mType->getElement()->getSizeBytes(),
    413                                                         w * mType->getElement()->getSizeBytes()));
    414         copyWithUnPadding(data, ptr, eSize / 4, w * h * d);
    415         free(ptr);
    416     } else {
    417         tryDispatch(mRS, RS::dispatch->Allocation3DRead(mRS->getContext(), getIDSafe(), xoff, yoff, zoff,
    418                                                         mSelectedLOD, w, h, d, data,
    419                                                         w * h * d * mType->getElement()->getSizeBytes(),
    420                                                         w * mType->getElement()->getSizeBytes()));
    421     }
    422 }
    423 
    424 sp<Allocation> Allocation::createTyped(const sp<RS>& rs, const sp<const Type>& type,
    425                                     RsAllocationMipmapControl mipmaps, uint32_t usage) {
    426     void *id = 0;
    427     if (rs->getError() == RS_SUCCESS) {
    428         id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mipmaps, usage, 0);
    429     }
    430     if (id == 0) {
    431         rs->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation creation failed");
    432         return nullptr;
    433     }
    434     return new Allocation(id, rs, type, usage);
    435 }
    436 
    437 sp<Allocation> Allocation::createTyped(const sp<RS>& rs, const sp<const Type>& type,
    438                                     RsAllocationMipmapControl mipmaps, uint32_t usage,
    439                                     void *pointer) {
    440     void *id = 0;
    441     if (rs->getError() == RS_SUCCESS) {
    442         id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mipmaps, usage,
    443                                                  (uintptr_t)pointer);
    444     }
    445     if (id == 0) {
    446         rs->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation creation failed");
    447         return nullptr;
    448     }
    449     return new Allocation(id, rs, type, usage);
    450 }
    451 
    452 sp<Allocation> Allocation::createTyped(const sp<RS>& rs, const sp<const Type>& type,
    453                                     uint32_t usage) {
    454     return createTyped(rs, type, RS_ALLOCATION_MIPMAP_NONE, usage);
    455 }
    456 
    457 sp<Allocation> Allocation::createSized(const sp<RS>& rs, const sp<const Element>& e,
    458                                     size_t count, uint32_t usage) {
    459     Type::Builder b(rs, e);
    460     b.setX(count);
    461     sp<const Type> t = b.create();
    462 
    463     return createTyped(rs, t, usage);
    464 }
    465 
    466 sp<Allocation> Allocation::createSized2D(const sp<RS>& rs, const sp<const Element>& e,
    467                                       size_t x, size_t y, uint32_t usage) {
    468     Type::Builder b(rs, e);
    469     b.setX(x);
    470     b.setY(y);
    471     sp<const Type> t = b.create();
    472 
    473     return createTyped(rs, t, usage);
    474 }
    475 
    476 void Allocation::ioSendOutput() {
    477 #ifndef RS_COMPATIBILITY_LIB
    478     if ((mUsage & RS_ALLOCATION_USAGE_IO_OUTPUT) == 0) {
    479         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only send buffer if IO_OUTPUT usage specified.");
    480         return;
    481     }
    482     tryDispatch(mRS, RS::dispatch->AllocationIoSend(mRS->getContext(), getID()));
    483 #endif
    484 }
    485 
    486 void Allocation::ioGetInput() {
    487 #ifndef RS_COMPATIBILITY_LIB
    488     if ((mUsage & RS_ALLOCATION_USAGE_IO_INPUT) == 0) {
    489         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only get buffer if IO_INPUT usage specified.");
    490         return;
    491     }
    492     tryDispatch(mRS, RS::dispatch->AllocationIoReceive(mRS->getContext(), getID()));
    493 #endif
    494 }
    495 
    496 #ifndef RS_COMPATIBILITY_LIB
    497 #include <gui/Surface.h>
    498 
    499 sp<Surface> Allocation::getSurface() {
    500     if ((mUsage & RS_ALLOCATION_USAGE_IO_INPUT) == 0) {
    501         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only get Surface if IO_INPUT usage specified.");
    502         return nullptr;
    503     }
    504     ANativeWindow *anw = (ANativeWindow *)RS::dispatch->AllocationGetSurface(mRS->getContext(),
    505                                                                              getID());
    506     sp<Surface> surface(static_cast<Surface*>(anw));
    507     return surface;
    508 }
    509 
    510 void Allocation::setSurface(const sp<Surface>& s) {
    511     if ((mUsage & RS_ALLOCATION_USAGE_IO_OUTPUT) == 0) {
    512         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only set Surface if IO_OUTPUT usage specified.");
    513         return;
    514     }
    515     tryDispatch(mRS, RS::dispatch->AllocationSetSurface(mRS->getContext(), getID(),
    516                                                         static_cast<ANativeWindow *>(s.get())));
    517 }
    518 
    519 #endif
    520 
    521