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 namespace android;
     21 using namespace RSC;
     22 
     23 
     24 void * Allocation::getIDSafe() const {
     25     return getID();
     26 }
     27 
     28 void Allocation::updateCacheInfo(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<const Type> old = mType;
    147         sp<Type> t = new Type((void *)typeID, mRS);
    148         t->updateFromNative();
    149         updateCacheInfo(t);
    150         mType = t;
    151     }
    152 }
    153 
    154 void Allocation::syncAll(RsAllocationUsageType srcLocation) {
    155     switch (srcLocation) {
    156     case RS_ALLOCATION_USAGE_SCRIPT:
    157     case RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS:
    158     case RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE:
    159     case RS_ALLOCATION_USAGE_GRAPHICS_VERTEX:
    160     case RS_ALLOCATION_USAGE_SHARED:
    161         break;
    162     default:
    163         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Source must be exactly one usage type.");
    164         return;
    165     }
    166     tryDispatch(mRS, RS::dispatch->AllocationSyncAll(mRS->getContext(), getIDSafe(), srcLocation));
    167 }
    168 
    169 void * Allocation::getPointer(size_t *stride) {
    170     void *p = nullptr;
    171     if (!(mUsage & RS_ALLOCATION_USAGE_SHARED)) {
    172         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Allocation does not support USAGE_SHARED.");
    173         return nullptr;
    174     }
    175 
    176     // FIXME: decide if lack of getPointer should cause compat mode
    177     if (RS::dispatch->AllocationGetPointer == nullptr) {
    178         mRS->throwError(RS_ERROR_RUNTIME_ERROR, "Can't use getPointer on older APIs");
    179         return nullptr;
    180     }
    181 
    182     p = RS::dispatch->AllocationGetPointer(mRS->getContext(), getIDSafe(), 0,
    183                                            RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, 0, 0, stride, sizeof(size_t));
    184     if (mRS->getError() != RS_SUCCESS) {
    185         mRS->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation lock failed");
    186         p = nullptr;
    187     }
    188     return p;
    189 }
    190 
    191 // ---------------------------------------------------------------------------
    192 //Functions needed for autopadding & unpadding
    193 static void copyWithPadding(void* ptr, const void* srcPtr, int mSize, int count) {
    194     int sizeBytesPad = mSize * 4;
    195     int sizeBytes = mSize * 3;
    196     uint8_t *dst = static_cast<uint8_t *>(ptr);
    197     const uint8_t *src = static_cast<const uint8_t *>(srcPtr);
    198     for (int i = 0; i < count; i++) {
    199         memcpy(dst, src, sizeBytes);
    200         dst += sizeBytesPad;
    201         src += sizeBytes;
    202     }
    203 }
    204 
    205 static void copyWithUnPadding(void* ptr, const void* srcPtr, int mSize, int count) {
    206     int sizeBytesPad = mSize * 4;
    207     int sizeBytes = mSize * 3;
    208     uint8_t *dst = static_cast<uint8_t *>(ptr);
    209     const uint8_t *src = static_cast<const uint8_t *>(srcPtr);
    210     for (int i = 0; i < count; i++) {
    211         memcpy(dst, src, sizeBytes);
    212         dst += sizeBytes;
    213         src += sizeBytesPad;
    214     }
    215 }
    216 // ---------------------------------------------------------------------------
    217 
    218 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, const void *data) {
    219 
    220     if(count < 1) {
    221         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Count must be >= 1.");
    222         return;
    223     }
    224     if((off + count) > mCurrentCount) {
    225         ALOGE("Overflow, Available count %u, got %zu at offset %u.", mCurrentCount, count, off);
    226         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Invalid copy specified");
    227         return;
    228     }
    229     if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) {
    230         size_t eSize = mType->getElement()->getSizeBytes();
    231         void *ptr = malloc(eSize * count);
    232         copyWithPadding(ptr, data, eSize / 4, count);
    233         tryDispatch(mRS, RS::dispatch->Allocation1DData(mRS->getContext(), getIDSafe(), off, mSelectedLOD,
    234                                                         count, ptr, count * mType->getElement()->getSizeBytes()));
    235         free(ptr);
    236     } else {
    237         tryDispatch(mRS, RS::dispatch->Allocation1DData(mRS->getContext(), getIDSafe(), off, mSelectedLOD,
    238                                                         count, data, count * mType->getElement()->getSizeBytes()));
    239     }
    240 }
    241 
    242 void Allocation::copy1DRangeTo(uint32_t off, size_t count, void *data) {
    243     if(count < 1) {
    244         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Count must be >= 1.");
    245         return;
    246     }
    247     if((off + count) > mCurrentCount) {
    248         ALOGE("Overflow, Available count %u, got %zu at offset %u.", mCurrentCount, count, off);
    249         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Invalid copy specified");
    250         return;
    251     }
    252     if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) {
    253         size_t eSize = mType->getElement()->getSizeBytes();
    254         void *ptr = malloc(eSize * count);
    255         tryDispatch(mRS, RS::dispatch->Allocation1DRead(mRS->getContext(), getIDSafe(), off, mSelectedLOD,
    256                                                         count, ptr, count * mType->getElement()->getSizeBytes()));
    257         copyWithUnPadding(data, ptr, eSize / 4, count);
    258         free(ptr);
    259     } else {
    260         tryDispatch(mRS, RS::dispatch->Allocation1DRead(mRS->getContext(), getIDSafe(), off, mSelectedLOD,
    261                                                         count, data, count * mType->getElement()->getSizeBytes()));
    262     }
    263 }
    264 
    265 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, sp<const Allocation> data,
    266                                  uint32_t dataOff) {
    267 
    268     tryDispatch(mRS, RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), off, 0,
    269                                                          mSelectedLOD, mSelectedFace,
    270                                                          count, 1, data->getIDSafe(), dataOff, 0,
    271                                                          data->mSelectedLOD, data->mSelectedFace));
    272 }
    273 
    274 void Allocation::copy1DFrom(const void* data) {
    275     copy1DRangeFrom(0, mCurrentCount, data);
    276 }
    277 
    278 void Allocation::copy1DTo(void* data) {
    279     copy1DRangeTo(0, mCurrentCount, data);
    280 }
    281 
    282 
    283 void Allocation::validate2DRange(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h) {
    284     if (mAdaptedAllocation != nullptr) {
    285 
    286     } else {
    287         if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) {
    288             mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Updated region larger than allocation.");
    289         }
    290     }
    291 }
    292 
    293 void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
    294                                  const void *data) {
    295     validate2DRange(xoff, yoff, w, h);
    296     if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) {
    297         size_t eSize = mType->getElement()->getSizeBytes();
    298         void *ptr = malloc(eSize * w * h);
    299         copyWithPadding(ptr, data, eSize / 4, w * h);
    300         tryDispatch(mRS, RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff,
    301                                                         yoff, mSelectedLOD, mSelectedFace,
    302                                                         w, h, ptr, w * h * mType->getElement()->getSizeBytes(),
    303                                                         w * mType->getElement()->getSizeBytes()));
    304         free(ptr);
    305     } else {
    306         tryDispatch(mRS, RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff,
    307                                                         yoff, mSelectedLOD, mSelectedFace,
    308                                                         w, h, data, w * h * mType->getElement()->getSizeBytes(),
    309                                                         w * mType->getElement()->getSizeBytes()));
    310     }
    311 }
    312 
    313 void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
    314                                  sp<const Allocation> data, uint32_t dataXoff, uint32_t dataYoff) {
    315     validate2DRange(xoff, yoff, w, h);
    316     tryDispatch(mRS, RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), xoff, yoff,
    317                                                          mSelectedLOD, mSelectedFace,
    318                                                          w, h, data->getIDSafe(), dataXoff, dataYoff,
    319                                                          data->mSelectedLOD, data->mSelectedFace));
    320 }
    321 
    322 void Allocation::copy2DRangeTo(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
    323                                void* data) {
    324     validate2DRange(xoff, yoff, w, h);
    325     if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) {
    326         size_t eSize = mType->getElement()->getSizeBytes();
    327         void *ptr = malloc(eSize * w * h);
    328         tryDispatch(mRS, RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff,
    329                                                         mSelectedLOD, mSelectedFace, w, h, ptr,
    330                                                         w * h * mType->getElement()->getSizeBytes(),
    331                                                         w * mType->getElement()->getSizeBytes()));
    332         copyWithUnPadding(data, ptr, eSize / 4, w * h);
    333         free(ptr);
    334     } else {
    335         tryDispatch(mRS, RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff,
    336                                                         mSelectedLOD, mSelectedFace, w, h, data,
    337                                                         w * h * mType->getElement()->getSizeBytes(),
    338                                                         w * mType->getElement()->getSizeBytes()));
    339     }
    340 }
    341 
    342 void Allocation::copy2DStridedFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
    343                                    const void *data, size_t stride) {
    344     validate2DRange(xoff, yoff, w, h);
    345     tryDispatch(mRS, RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff, yoff,
    346                                                     mSelectedLOD, mSelectedFace, w, h, data,
    347                                                     w * h * mType->getElement()->getSizeBytes(), stride));
    348 }
    349 
    350 void Allocation::copy2DStridedFrom(const void* data, size_t stride) {
    351     copy2DStridedFrom(0, 0, mCurrentDimX, mCurrentDimY, data, stride);
    352 }
    353 
    354 void Allocation::copy2DStridedTo(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
    355                                  void *data, size_t stride) {
    356     validate2DRange(xoff, yoff, w, h);
    357     tryDispatch(mRS, RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff,
    358                                                     mSelectedLOD, mSelectedFace, w, h, data,
    359                                                     w * h * mType->getElement()->getSizeBytes(), stride));
    360 }
    361 
    362 void Allocation::copy2DStridedTo(void* data, size_t stride) {
    363     copy2DStridedTo(0, 0, mCurrentDimX, mCurrentDimY, data, stride);
    364 }
    365 
    366 void Allocation::validate3DRange(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w,
    367                                  uint32_t h, uint32_t d) {
    368     if (mAdaptedAllocation != nullptr) {
    369 
    370     } else {
    371         if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY) || ((zoff + d) > mCurrentDimZ)) {
    372             mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Updated region larger than allocation.");
    373         }
    374     }
    375 }
    376 
    377 void Allocation::copy3DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w,
    378                                  uint32_t h, uint32_t d, const void* data) {
    379     validate3DRange(xoff, yoff, zoff, w, h, d);
    380     if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) {
    381         size_t eSize = mType->getElement()->getSizeBytes();
    382         void *ptr = malloc(eSize * w * h * d);
    383         copyWithPadding(ptr, data, eSize / 4, w * h * d);
    384         tryDispatch(mRS, RS::dispatch->Allocation3DData(mRS->getContext(), getIDSafe(), xoff, yoff, zoff,
    385                                                         mSelectedLOD, w, h, d, ptr,
    386                                                         w * h * d * mType->getElement()->getSizeBytes(),
    387                                                         w * mType->getElement()->getSizeBytes()));
    388         free(ptr);
    389     } else {
    390         tryDispatch(mRS, RS::dispatch->Allocation3DData(mRS->getContext(), getIDSafe(), xoff, yoff, zoff,
    391                                                         mSelectedLOD, w, h, d, data,
    392                                                         w * h * d * mType->getElement()->getSizeBytes(),
    393                                                         w * mType->getElement()->getSizeBytes()));
    394     }
    395 }
    396 
    397 void Allocation::copy3DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w, uint32_t h, uint32_t d,
    398                                  sp<const Allocation> data, uint32_t dataXoff, uint32_t dataYoff, uint32_t dataZoff) {
    399     validate3DRange(xoff, yoff, zoff, w, h, d);
    400     tryDispatch(mRS, RS::dispatch->AllocationCopy3DRange(mRS->getContext(), getIDSafe(), xoff, yoff, zoff,
    401                                                          mSelectedLOD, w, h, d, data->getIDSafe(),
    402                                                          dataXoff, dataYoff, dataZoff, data->mSelectedLOD));
    403 }
    404 
    405 void Allocation::copy3DRangeTo(uint32_t xoff, uint32_t yoff, uint32_t zoff, uint32_t w,
    406                                  uint32_t h, uint32_t d, void* data) {
    407     validate3DRange(xoff, yoff, zoff, w, h, d);
    408     if (mAutoPadding && (mType->getElement()->getVectorSize() == 3)) {
    409         size_t eSize = mType->getElement()->getSizeBytes();
    410         void *ptr = malloc(eSize * w * h * d);
    411         tryDispatch(mRS, RS::dispatch->Allocation3DRead(mRS->getContext(), getIDSafe(), xoff, yoff, zoff,
    412                                                         mSelectedLOD, w, h, d, ptr,
    413                                                         w * h * d * mType->getElement()->getSizeBytes(),
    414                                                         w * mType->getElement()->getSizeBytes()));
    415         copyWithUnPadding(data, ptr, eSize / 4, w * h * d);
    416         free(ptr);
    417     } else {
    418         tryDispatch(mRS, RS::dispatch->Allocation3DRead(mRS->getContext(), getIDSafe(), xoff, yoff, zoff,
    419                                                         mSelectedLOD, w, h, d, data,
    420                                                         w * h * d * mType->getElement()->getSizeBytes(),
    421                                                         w * mType->getElement()->getSizeBytes()));
    422     }
    423 }
    424 
    425 sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type,
    426                                     RsAllocationMipmapControl mipmaps, uint32_t usage) {
    427     void *id = 0;
    428     if (rs->getError() == RS_SUCCESS) {
    429         id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mipmaps, usage, 0);
    430     }
    431     if (id == 0) {
    432         rs->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation creation failed");
    433         return nullptr;
    434     }
    435     return new Allocation(id, rs, type, usage);
    436 }
    437 
    438 sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type,
    439                                     RsAllocationMipmapControl mipmaps, uint32_t usage,
    440                                     void *pointer) {
    441     void *id = 0;
    442     if (rs->getError() == RS_SUCCESS) {
    443         id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mipmaps, usage,
    444                                                  (uintptr_t)pointer);
    445     }
    446     if (id == 0) {
    447         rs->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation creation failed");
    448         return nullptr;
    449     }
    450     return new Allocation(id, rs, type, usage);
    451 }
    452 
    453 sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type,
    454                                     uint32_t usage) {
    455     return createTyped(rs, type, RS_ALLOCATION_MIPMAP_NONE, usage);
    456 }
    457 
    458 sp<Allocation> Allocation::createSized(sp<RS> rs, sp<const Element> e,
    459                                     size_t count, uint32_t usage) {
    460     Type::Builder b(rs, e);
    461     b.setX(count);
    462     sp<const Type> t = b.create();
    463 
    464     return createTyped(rs, t, usage);
    465 }
    466 
    467 sp<Allocation> Allocation::createSized2D(sp<RS> rs, sp<const Element> e,
    468                                       size_t x, size_t y, uint32_t usage) {
    469     Type::Builder b(rs, e);
    470     b.setX(x);
    471     b.setY(y);
    472     sp<const Type> t = b.create();
    473 
    474     return createTyped(rs, t, usage);
    475 }
    476 
    477 void Allocation::ioSendOutput() {
    478 #ifndef RS_COMPATIBILITY_LIB
    479     if ((mUsage & RS_ALLOCATION_USAGE_IO_OUTPUT) == 0) {
    480         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only send buffer if IO_OUTPUT usage specified.");
    481         return;
    482     }
    483     tryDispatch(mRS, RS::dispatch->AllocationIoSend(mRS->getContext(), getID()));
    484 #endif
    485 }
    486 
    487 void Allocation::ioGetInput() {
    488 #ifndef RS_COMPATIBILITY_LIB
    489     if ((mUsage & RS_ALLOCATION_USAGE_IO_INPUT) == 0) {
    490         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only get buffer if IO_INPUT usage specified.");
    491         return;
    492     }
    493     tryDispatch(mRS, RS::dispatch->AllocationIoReceive(mRS->getContext(), getID()));
    494 #endif
    495 }
    496 
    497 #if !defined(RS_SERVER) && !defined(RS_COMPATIBILITY_LIB)
    498 #include <gui/Surface.h>
    499 
    500 RSC::sp<Surface> Allocation::getSurface() {
    501     if ((mUsage & RS_ALLOCATION_USAGE_IO_INPUT) == 0) {
    502         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only get Surface if IO_INPUT usage specified.");
    503         return nullptr;
    504     }
    505     IGraphicBufferProducer *v = (IGraphicBufferProducer *)RS::dispatch->AllocationGetSurface(mRS->getContext(),
    506                                                                                              getID());
    507     android::sp<IGraphicBufferProducer> bp = v;
    508     v->decStrong(nullptr);
    509 
    510     return new Surface(bp, true);;
    511 }
    512 
    513 void Allocation::setSurface(RSC::sp<Surface> s) {
    514     if ((mUsage & RS_ALLOCATION_USAGE_IO_OUTPUT) == 0) {
    515         mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only set Surface if IO_OUTPUT usage specified.");
    516         return;
    517     }
    518     tryDispatch(mRS, RS::dispatch->AllocationSetSurface(mRS->getContext(), getID(),
    519                                                         static_cast<ANativeWindow *>(s.get())));
    520 }
    521 
    522 #endif
    523 
    524