Home | History | Annotate | Download | only in driver
      1 /*
      2  * Copyright (C) 2011 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 
     18 #include "rsdCore.h"
     19 #include "rsdBcc.h"
     20 #include "rsdRuntime.h"
     21 #include "rsdAllocation.h"
     22 #include "rsdFrameBufferObj.h"
     23 
     24 #include "rsAllocation.h"
     25 
     26 #include <GLES/gl.h>
     27 #include <GLES2/gl2.h>
     28 #include <GLES/glext.h>
     29 
     30 using namespace android;
     31 using namespace android::renderscript;
     32 
     33 
     34 
     35 const static GLenum gFaceOrder[] = {
     36     GL_TEXTURE_CUBE_MAP_POSITIVE_X,
     37     GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
     38     GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
     39     GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
     40     GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
     41     GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
     42 };
     43 
     44 
     45 GLenum rsdTypeToGLType(RsDataType t) {
     46     switch (t) {
     47     case RS_TYPE_UNSIGNED_5_6_5:    return GL_UNSIGNED_SHORT_5_6_5;
     48     case RS_TYPE_UNSIGNED_5_5_5_1:  return GL_UNSIGNED_SHORT_5_5_5_1;
     49     case RS_TYPE_UNSIGNED_4_4_4_4:  return GL_UNSIGNED_SHORT_4_4_4_4;
     50 
     51     //case RS_TYPE_FLOAT_16:      return GL_HALF_FLOAT;
     52     case RS_TYPE_FLOAT_32:      return GL_FLOAT;
     53     case RS_TYPE_UNSIGNED_8:    return GL_UNSIGNED_BYTE;
     54     case RS_TYPE_UNSIGNED_16:   return GL_UNSIGNED_SHORT;
     55     case RS_TYPE_SIGNED_8:      return GL_BYTE;
     56     case RS_TYPE_SIGNED_16:     return GL_SHORT;
     57     default:    break;
     58     }
     59     return 0;
     60 }
     61 
     62 GLenum rsdKindToGLFormat(RsDataKind k) {
     63     switch (k) {
     64     case RS_KIND_PIXEL_L: return GL_LUMINANCE;
     65     case RS_KIND_PIXEL_A: return GL_ALPHA;
     66     case RS_KIND_PIXEL_LA: return GL_LUMINANCE_ALPHA;
     67     case RS_KIND_PIXEL_RGB: return GL_RGB;
     68     case RS_KIND_PIXEL_RGBA: return GL_RGBA;
     69     case RS_KIND_PIXEL_DEPTH: return GL_DEPTH_COMPONENT16;
     70     default: break;
     71     }
     72     return 0;
     73 }
     74 
     75 
     76 static void Update2DTexture(const Context *rsc, const Allocation *alloc, const void *ptr,
     77                             uint32_t xoff, uint32_t yoff, uint32_t lod,
     78                             RsAllocationCubemapFace face, uint32_t w, uint32_t h) {
     79     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
     80 
     81     rsAssert(drv->textureID);
     82     RSD_CALL_GL(glBindTexture, drv->glTarget, drv->textureID);
     83     RSD_CALL_GL(glPixelStorei, GL_UNPACK_ALIGNMENT, 1);
     84     GLenum t = GL_TEXTURE_2D;
     85     if (alloc->mHal.state.hasFaces) {
     86         t = gFaceOrder[face];
     87     }
     88     RSD_CALL_GL(glTexSubImage2D, t, lod, xoff, yoff, w, h, drv->glFormat, drv->glType, ptr);
     89 }
     90 
     91 
     92 static void Upload2DTexture(const Context *rsc, const Allocation *alloc, bool isFirstUpload) {
     93     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
     94 
     95     RSD_CALL_GL(glBindTexture, drv->glTarget, drv->textureID);
     96     RSD_CALL_GL(glPixelStorei, GL_UNPACK_ALIGNMENT, 1);
     97 
     98     uint32_t faceCount = 1;
     99     if (alloc->mHal.state.hasFaces) {
    100         faceCount = 6;
    101     }
    102 
    103     rsdGLCheckError(rsc, "Upload2DTexture 1 ");
    104     for (uint32_t face = 0; face < faceCount; face ++) {
    105         for (uint32_t lod = 0; lod < alloc->mHal.state.type->getLODCount(); lod++) {
    106             const uint8_t *p = (const uint8_t *)drv->mallocPtr;
    107             p += alloc->mHal.state.type->getLODFaceOffset(lod, (RsAllocationCubemapFace)face, 0, 0);
    108 
    109             GLenum t = GL_TEXTURE_2D;
    110             if (alloc->mHal.state.hasFaces) {
    111                 t = gFaceOrder[face];
    112             }
    113 
    114             if (isFirstUpload) {
    115                 RSD_CALL_GL(glTexImage2D, t, lod, drv->glFormat,
    116                              alloc->mHal.state.type->getLODDimX(lod),
    117                              alloc->mHal.state.type->getLODDimY(lod),
    118                              0, drv->glFormat, drv->glType, p);
    119             } else {
    120                 RSD_CALL_GL(glTexSubImage2D, t, lod, 0, 0,
    121                                 alloc->mHal.state.type->getLODDimX(lod),
    122                                 alloc->mHal.state.type->getLODDimY(lod),
    123                                 drv->glFormat, drv->glType, p);
    124             }
    125         }
    126     }
    127 
    128     if (alloc->mHal.state.mipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) {
    129         RSD_CALL_GL(glGenerateMipmap, drv->glTarget);
    130     }
    131     rsdGLCheckError(rsc, "Upload2DTexture");
    132 }
    133 
    134 static void UploadToTexture(const Context *rsc, const Allocation *alloc) {
    135     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
    136 
    137     if (!drv->glType || !drv->glFormat) {
    138         return;
    139     }
    140 
    141     if (!alloc->getPtr()) {
    142         return;
    143     }
    144 
    145     bool isFirstUpload = false;
    146 
    147     if (!drv->textureID) {
    148         RSD_CALL_GL(glGenTextures, 1, &drv->textureID);
    149         isFirstUpload = true;
    150     }
    151 
    152     Upload2DTexture(rsc, alloc, isFirstUpload);
    153 
    154     if (!(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) {
    155         if (drv->mallocPtr) {
    156             free(drv->mallocPtr);
    157             drv->mallocPtr = NULL;
    158         }
    159     }
    160     rsdGLCheckError(rsc, "UploadToTexture");
    161 }
    162 
    163 static void AllocateRenderTarget(const Context *rsc, const Allocation *alloc) {
    164     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
    165 
    166     if (!drv->glFormat) {
    167         return;
    168     }
    169 
    170     if (!drv->renderTargetID) {
    171         RSD_CALL_GL(glGenRenderbuffers, 1, &drv->renderTargetID);
    172 
    173         if (!drv->renderTargetID) {
    174             // This should generally not happen
    175             LOGE("allocateRenderTarget failed to gen mRenderTargetID");
    176             rsc->dumpDebug();
    177             return;
    178         }
    179         RSD_CALL_GL(glBindRenderbuffer, GL_RENDERBUFFER, drv->renderTargetID);
    180         RSD_CALL_GL(glRenderbufferStorage, GL_RENDERBUFFER, drv->glFormat,
    181                               alloc->mHal.state.dimensionX, alloc->mHal.state.dimensionY);
    182     }
    183     rsdGLCheckError(rsc, "AllocateRenderTarget");
    184 }
    185 
    186 static void UploadToBufferObject(const Context *rsc, const Allocation *alloc) {
    187     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
    188 
    189     rsAssert(!alloc->mHal.state.type->getDimY());
    190     rsAssert(!alloc->mHal.state.type->getDimZ());
    191 
    192     //alloc->mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX;
    193 
    194     if (!drv->bufferID) {
    195         RSD_CALL_GL(glGenBuffers, 1, &drv->bufferID);
    196     }
    197     if (!drv->bufferID) {
    198         LOGE("Upload to buffer object failed");
    199         drv->uploadDeferred = true;
    200         return;
    201     }
    202     RSD_CALL_GL(glBindBuffer, drv->glTarget, drv->bufferID);
    203     RSD_CALL_GL(glBufferData, drv->glTarget, alloc->mHal.state.type->getSizeBytes(),
    204                  drv->mallocPtr, GL_DYNAMIC_DRAW);
    205     RSD_CALL_GL(glBindBuffer, drv->glTarget, 0);
    206     rsdGLCheckError(rsc, "UploadToBufferObject");
    207 }
    208 
    209 bool rsdAllocationInit(const Context *rsc, Allocation *alloc, bool forceZero) {
    210     DrvAllocation *drv = (DrvAllocation *)calloc(1, sizeof(DrvAllocation));
    211     if (!drv) {
    212         return false;
    213     }
    214 
    215     void * ptr = malloc(alloc->mHal.state.type->getSizeBytes());
    216     if (!ptr) {
    217         free(drv);
    218         return false;
    219     }
    220 
    221     drv->glTarget = GL_NONE;
    222     if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) {
    223         if (alloc->mHal.state.hasFaces) {
    224             drv->glTarget = GL_TEXTURE_CUBE_MAP;
    225         } else {
    226             drv->glTarget = GL_TEXTURE_2D;
    227         }
    228     } else {
    229         if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) {
    230             drv->glTarget = GL_ARRAY_BUFFER;
    231         }
    232     }
    233 
    234     drv->glType = rsdTypeToGLType(alloc->mHal.state.type->getElement()->getComponent().getType());
    235     drv->glFormat = rsdKindToGLFormat(alloc->mHal.state.type->getElement()->getComponent().getKind());
    236 
    237 
    238     alloc->mHal.drvState.mallocPtr = ptr;
    239     drv->mallocPtr = (uint8_t *)ptr;
    240     alloc->mHal.drv = drv;
    241     if (forceZero) {
    242         memset(ptr, 0, alloc->mHal.state.type->getSizeBytes());
    243     }
    244 
    245     if (alloc->mHal.state.usageFlags & ~RS_ALLOCATION_USAGE_SCRIPT) {
    246         drv->uploadDeferred = true;
    247     }
    248 
    249     drv->readBackFBO = NULL;
    250 
    251     return true;
    252 }
    253 
    254 void rsdAllocationDestroy(const Context *rsc, Allocation *alloc) {
    255     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
    256 
    257     if (drv->bufferID) {
    258         // Causes a SW crash....
    259         //LOGV(" mBufferID %i", mBufferID);
    260         //glDeleteBuffers(1, &mBufferID);
    261         //mBufferID = 0;
    262     }
    263     if (drv->textureID) {
    264         RSD_CALL_GL(glDeleteTextures, 1, &drv->textureID);
    265         drv->textureID = 0;
    266     }
    267     if (drv->renderTargetID) {
    268         RSD_CALL_GL(glDeleteRenderbuffers, 1, &drv->renderTargetID);
    269         drv->renderTargetID = 0;
    270     }
    271 
    272     if (drv->mallocPtr) {
    273         free(drv->mallocPtr);
    274         drv->mallocPtr = NULL;
    275     }
    276     if (drv->readBackFBO != NULL) {
    277         delete drv->readBackFBO;
    278         drv->readBackFBO = NULL;
    279     }
    280     free(drv);
    281     alloc->mHal.drv = NULL;
    282 }
    283 
    284 void rsdAllocationResize(const Context *rsc, const Allocation *alloc,
    285                          const Type *newType, bool zeroNew) {
    286     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
    287 
    288     drv->mallocPtr = (uint8_t *)realloc(drv->mallocPtr, newType->getSizeBytes());
    289 
    290     // fixme
    291     ((Allocation *)alloc)->mHal.drvState.mallocPtr = drv->mallocPtr;
    292 
    293     const uint32_t oldDimX = alloc->mHal.state.dimensionX;
    294     const uint32_t dimX = newType->getDimX();
    295 
    296     if (dimX > oldDimX) {
    297         const Element *e = alloc->mHal.state.type->getElement();
    298         uint32_t stride = e->getSizeBytes();
    299         memset(((uint8_t *)drv->mallocPtr) + stride * oldDimX, 0, stride * (dimX - oldDimX));
    300     }
    301 }
    302 
    303 static void rsdAllocationSyncFromFBO(const Context *rsc, const Allocation *alloc) {
    304     if (!alloc->getIsScript()) {
    305         return; // nothing to sync
    306     }
    307 
    308     RsdHal *dc = (RsdHal *)rsc->mHal.drv;
    309     RsdFrameBufferObj *lastFbo = dc->gl.currentFrameBuffer;
    310 
    311     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
    312     if (!drv->textureID && !drv->renderTargetID) {
    313         return; // nothing was rendered here yet, so nothing to sync
    314     }
    315     if (drv->readBackFBO == NULL) {
    316         drv->readBackFBO = new RsdFrameBufferObj();
    317         drv->readBackFBO->setColorTarget(drv, 0);
    318         drv->readBackFBO->setDimensions(alloc->getType()->getDimX(),
    319                                         alloc->getType()->getDimY());
    320     }
    321 
    322     // Bind the framebuffer object so we can read back from it
    323     drv->readBackFBO->setActive(rsc);
    324 
    325     // Do the readback
    326     RSD_CALL_GL(glReadPixels, 0, 0, alloc->getType()->getDimX(), alloc->getType()->getDimY(),
    327                  drv->glFormat, drv->glType, alloc->getPtr());
    328 
    329     // Revert framebuffer to its original
    330     lastFbo->setActive(rsc);
    331 }
    332 
    333 
    334 void rsdAllocationSyncAll(const Context *rsc, const Allocation *alloc,
    335                          RsAllocationUsageType src) {
    336     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
    337 
    338     if (src == RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
    339         if(!alloc->getIsRenderTarget()) {
    340             rsc->setError(RS_ERROR_FATAL_DRIVER,
    341                           "Attempting to sync allocation from render target, "
    342                           "for non-render target allocation");
    343         } else if (alloc->getType()->getElement()->getKind() != RS_KIND_PIXEL_RGBA) {
    344             rsc->setError(RS_ERROR_FATAL_DRIVER, "Cannot only sync from RGBA"
    345                                                  "render target");
    346         } else {
    347             rsdAllocationSyncFromFBO(rsc, alloc);
    348         }
    349         return;
    350     }
    351 
    352     rsAssert(src == RS_ALLOCATION_USAGE_SCRIPT);
    353 
    354     if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) {
    355         UploadToTexture(rsc, alloc);
    356     } else {
    357         if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
    358             AllocateRenderTarget(rsc, alloc);
    359         }
    360     }
    361     if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) {
    362         UploadToBufferObject(rsc, alloc);
    363     }
    364 
    365     drv->uploadDeferred = false;
    366 }
    367 
    368 void rsdAllocationMarkDirty(const Context *rsc, const Allocation *alloc) {
    369     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
    370     drv->uploadDeferred = true;
    371 }
    372 
    373 void rsdAllocationData1D(const Context *rsc, const Allocation *alloc,
    374                          uint32_t xoff, uint32_t lod, uint32_t count,
    375                          const void *data, uint32_t sizeBytes) {
    376     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
    377 
    378     const uint32_t eSize = alloc->mHal.state.type->getElementSizeBytes();
    379     uint8_t * ptr = drv->mallocPtr;
    380     ptr += eSize * xoff;
    381     uint32_t size = count * eSize;
    382 
    383     if (alloc->mHal.state.hasReferences) {
    384         alloc->incRefs(data, count);
    385         alloc->decRefs(ptr, count);
    386     }
    387 
    388     memcpy(ptr, data, size);
    389     drv->uploadDeferred = true;
    390 }
    391 
    392 void rsdAllocationData2D(const Context *rsc, const Allocation *alloc,
    393                          uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
    394                          uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) {
    395     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
    396 
    397     uint32_t eSize = alloc->mHal.state.elementSizeBytes;
    398     uint32_t lineSize = eSize * w;
    399     uint32_t destW = alloc->mHal.state.dimensionX;
    400 
    401     if (drv->mallocPtr) {
    402         const uint8_t *src = static_cast<const uint8_t *>(data);
    403         uint8_t *dst = drv->mallocPtr;
    404         dst += alloc->mHal.state.type->getLODFaceOffset(lod, face, xoff, yoff);
    405 
    406         for (uint32_t line=yoff; line < (yoff+h); line++) {
    407             if (alloc->mHal.state.hasReferences) {
    408                 alloc->incRefs(src, w);
    409                 alloc->decRefs(dst, w);
    410             }
    411             memcpy(dst, src, lineSize);
    412             src += lineSize;
    413             dst += destW * eSize;
    414         }
    415         drv->uploadDeferred = true;
    416     } else {
    417         Update2DTexture(rsc, alloc, data, xoff, yoff, lod, face, w, h);
    418     }
    419 }
    420 
    421 void rsdAllocationData3D(const Context *rsc, const Allocation *alloc,
    422                          uint32_t xoff, uint32_t yoff, uint32_t zoff,
    423                          uint32_t lod, RsAllocationCubemapFace face,
    424                          uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) {
    425 
    426 }
    427 
    428 void rsdAllocationData1D_alloc(const android::renderscript::Context *rsc,
    429                                const android::renderscript::Allocation *dstAlloc,
    430                                uint32_t dstXoff, uint32_t dstLod, uint32_t count,
    431                                const android::renderscript::Allocation *srcAlloc,
    432                                uint32_t srcXoff, uint32_t srcLod) {
    433 }
    434 
    435 uint8_t *getOffsetPtr(const android::renderscript::Allocation *alloc,
    436                       uint32_t xoff, uint32_t yoff, uint32_t lod,
    437                       RsAllocationCubemapFace face) {
    438     uint8_t *ptr = static_cast<uint8_t *>(alloc->getPtr());
    439     ptr += alloc->getType()->getLODOffset(lod, xoff, yoff);
    440 
    441     if (face != 0) {
    442         uint32_t totalSizeBytes = alloc->getType()->getSizeBytes();
    443         uint32_t faceOffset = totalSizeBytes / 6;
    444         ptr += faceOffset * (uint32_t)face;
    445     }
    446     return ptr;
    447 }
    448 
    449 
    450 void rsdAllocationData2D_alloc_script(const android::renderscript::Context *rsc,
    451                                       const android::renderscript::Allocation *dstAlloc,
    452                                       uint32_t dstXoff, uint32_t dstYoff, uint32_t dstLod,
    453                                       RsAllocationCubemapFace dstFace, uint32_t w, uint32_t h,
    454                                       const android::renderscript::Allocation *srcAlloc,
    455                                       uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod,
    456                                       RsAllocationCubemapFace srcFace) {
    457     uint32_t elementSize = dstAlloc->getType()->getElementSizeBytes();
    458     for (uint32_t i = 0; i < h; i ++) {
    459         uint8_t *dstPtr = getOffsetPtr(dstAlloc, dstXoff, dstYoff + i, dstLod, dstFace);
    460         uint8_t *srcPtr = getOffsetPtr(srcAlloc, srcXoff, srcYoff + i, srcLod, srcFace);
    461         memcpy(dstPtr, srcPtr, w * elementSize);
    462 
    463         //LOGE("COPIED dstXoff(%u), dstYoff(%u), dstLod(%u), dstFace(%u), w(%u), h(%u), srcXoff(%u), srcYoff(%u), srcLod(%u), srcFace(%u)",
    464         //     dstXoff, dstYoff, dstLod, dstFace, w, h, srcXoff, srcYoff, srcLod, srcFace);
    465     }
    466 }
    467 
    468 void rsdAllocationData2D_alloc(const android::renderscript::Context *rsc,
    469                                const android::renderscript::Allocation *dstAlloc,
    470                                uint32_t dstXoff, uint32_t dstYoff, uint32_t dstLod,
    471                                RsAllocationCubemapFace dstFace, uint32_t w, uint32_t h,
    472                                const android::renderscript::Allocation *srcAlloc,
    473                                uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod,
    474                                RsAllocationCubemapFace srcFace) {
    475     if (!dstAlloc->getIsScript() && !srcAlloc->getIsScript()) {
    476         rsc->setError(RS_ERROR_FATAL_DRIVER, "Non-script allocation copies not "
    477                                              "yet implemented.");
    478         return;
    479     }
    480     rsdAllocationData2D_alloc_script(rsc, dstAlloc, dstXoff, dstYoff,
    481                                      dstLod, dstFace, w, h, srcAlloc,
    482                                      srcXoff, srcYoff, srcLod, srcFace);
    483 }
    484 
    485 void rsdAllocationData3D_alloc(const android::renderscript::Context *rsc,
    486                                const android::renderscript::Allocation *dstAlloc,
    487                                uint32_t dstXoff, uint32_t dstYoff, uint32_t dstZoff,
    488                                uint32_t dstLod, RsAllocationCubemapFace dstFace,
    489                                uint32_t w, uint32_t h, uint32_t d,
    490                                const android::renderscript::Allocation *srcAlloc,
    491                                uint32_t srcXoff, uint32_t srcYoff, uint32_t srcZoff,
    492                                uint32_t srcLod, RsAllocationCubemapFace srcFace) {
    493 }
    494 
    495 void rsdAllocationElementData1D(const Context *rsc, const Allocation *alloc,
    496                                 uint32_t x,
    497                                 const void *data, uint32_t cIdx, uint32_t sizeBytes) {
    498     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
    499 
    500     uint32_t eSize = alloc->mHal.state.elementSizeBytes;
    501     uint8_t * ptr = drv->mallocPtr;
    502     ptr += eSize * x;
    503 
    504     const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx);
    505     ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx);
    506 
    507     if (alloc->mHal.state.hasReferences) {
    508         e->incRefs(data);
    509         e->decRefs(ptr);
    510     }
    511 
    512     memcpy(ptr, data, sizeBytes);
    513     drv->uploadDeferred = true;
    514 }
    515 
    516 void rsdAllocationElementData2D(const Context *rsc, const Allocation *alloc,
    517                                 uint32_t x, uint32_t y,
    518                                 const void *data, uint32_t cIdx, uint32_t sizeBytes) {
    519     DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
    520 
    521     uint32_t eSize = alloc->mHal.state.elementSizeBytes;
    522     uint8_t * ptr = drv->mallocPtr;
    523     ptr += eSize * (x + y * alloc->mHal.state.dimensionX);
    524 
    525     const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx);
    526     ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx);
    527 
    528     if (alloc->mHal.state.hasReferences) {
    529         e->incRefs(data);
    530         e->decRefs(ptr);
    531     }
    532 
    533     memcpy(ptr, data, sizeBytes);
    534     drv->uploadDeferred = true;
    535 }
    536 
    537 
    538