rsAllocation.cpp revision e6d9fbc31bef01219cc812e819c505ff01673c6f
1/*
2 * Copyright (C) 2009 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#ifndef ANDROID_RS_BUILD_FOR_HOST
17#include "rsContext.h"
18
19#include <GLES/gl.h>
20#include <GLES2/gl2.h>
21#include <GLES/glext.h>
22#else
23#include "rsContextHostStub.h"
24
25#include <OpenGL/gl.h>
26#include <OpenGl/glext.h>
27#endif
28
29using namespace android;
30using namespace android::renderscript;
31
32Allocation::Allocation(Context *rsc, const Type *type) : ObjectBase(rsc)
33{
34    init(rsc, type);
35
36    mPtr = malloc(mType->getSizeBytes());
37    if (!mPtr) {
38        LOGE("Allocation::Allocation, alloc failure");
39    }
40}
41
42Allocation::Allocation(Context *rsc, const Type *type, void *bmp,
43                       void *callbackData, RsBitmapCallback_t callback)
44: ObjectBase(rsc)
45{
46    init(rsc, type);
47
48    mPtr = bmp;
49    mUserBitmapCallback = callback;
50    mUserBitmapCallbackData = callbackData;
51}
52
53void Allocation::init(Context *rsc, const Type *type)
54{
55    mAllocFile = __FILE__;
56    mAllocLine = __LINE__;
57    mPtr = NULL;
58
59    mCpuWrite = false;
60    mCpuRead = false;
61    mGpuWrite = false;
62    mGpuRead = false;
63
64    mReadWriteRatio = 0;
65    mUpdateSize = 0;
66
67    mIsTexture = false;
68    mTextureID = 0;
69    mIsVertexBuffer = false;
70    mBufferID = 0;
71    mUploadDefered = false;
72
73    mUserBitmapCallback = NULL;
74    mUserBitmapCallbackData = NULL;
75
76    mType.set(type);
77    rsAssert(type);
78
79    mPtr = NULL;
80}
81
82Allocation::~Allocation()
83{
84    if (mUserBitmapCallback != NULL) {
85        mUserBitmapCallback(mUserBitmapCallbackData);
86    } else {
87        free(mPtr);
88    }
89    mPtr = NULL;
90
91    if (mBufferID) {
92        // Causes a SW crash....
93        //LOGV(" mBufferID %i", mBufferID);
94        //glDeleteBuffers(1, &mBufferID);
95        //mBufferID = 0;
96    }
97    if (mTextureID) {
98        glDeleteTextures(1, &mTextureID);
99        mTextureID = 0;
100    }
101}
102
103void Allocation::setCpuWritable(bool)
104{
105}
106
107void Allocation::setGpuWritable(bool)
108{
109}
110
111void Allocation::setCpuReadable(bool)
112{
113}
114
115void Allocation::setGpuReadable(bool)
116{
117}
118
119bool Allocation::fixAllocation()
120{
121    return false;
122}
123
124void Allocation::deferedUploadToTexture(const Context *rsc, bool genMipmap, uint32_t lodOffset)
125{
126    rsAssert(lodOffset < mType->getLODCount());
127    mIsTexture = true;
128    mTextureLOD = lodOffset;
129    mUploadDefered = true;
130    mTextureGenMipmap = !mType->getDimLOD() && genMipmap;
131}
132
133void Allocation::uploadToTexture(const Context *rsc)
134{
135    //rsAssert(!mTextureId);
136
137    mIsTexture = true;
138    if (!rsc->checkDriver()) {
139        mUploadDefered = true;
140        return;
141    }
142
143    GLenum type = mType->getElement()->getComponent().getGLType();
144    GLenum format = mType->getElement()->getComponent().getGLFormat();
145
146    if (!type || !format) {
147        return;
148    }
149
150    if (!mTextureID) {
151        glGenTextures(1, &mTextureID);
152
153        if (!mTextureID) {
154            // This should not happen, however, its likely the cause of the
155            // white sqare bug.
156            // Force a crash to 1: restart the app, 2: make sure we get a bugreport.
157            LOGE("Upload to texture failed to gen mTextureID");
158            rsc->dumpDebug();
159            mUploadDefered = true;
160            return;
161        }
162    }
163    glBindTexture(GL_TEXTURE_2D, mTextureID);
164    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
165
166    Adapter2D adapt(getContext(), this);
167    for(uint32_t lod = 0; (lod + mTextureLOD) < mType->getLODCount(); lod++) {
168        adapt.setLOD(lod+mTextureLOD);
169
170        uint16_t * ptr = static_cast<uint16_t *>(adapt.getElement(0,0));
171        glTexImage2D(GL_TEXTURE_2D, lod, format,
172                     adapt.getDimX(), adapt.getDimY(),
173                     0, format, type, ptr);
174    }
175    if (mTextureGenMipmap) {
176#ifndef ANDROID_RS_BUILD_FOR_HOST
177        glGenerateMipmap(GL_TEXTURE_2D);
178#endif //ANDROID_RS_BUILD_FOR_HOST
179    }
180
181    rsc->checkError("Allocation::uploadToTexture");
182}
183
184void Allocation::deferedUploadToBufferObject(const Context *rsc)
185{
186    mIsVertexBuffer = true;
187    mUploadDefered = true;
188}
189
190void Allocation::uploadToBufferObject(const Context *rsc)
191{
192    rsAssert(!mType->getDimY());
193    rsAssert(!mType->getDimZ());
194
195    mIsVertexBuffer = true;
196    if (!rsc->checkDriver()) {
197        mUploadDefered = true;
198        return;
199    }
200
201    if (!mBufferID) {
202        glGenBuffers(1, &mBufferID);
203    }
204    if (!mBufferID) {
205        LOGE("Upload to buffer object failed");
206        mUploadDefered = true;
207        return;
208    }
209
210    glBindBuffer(GL_ARRAY_BUFFER, mBufferID);
211    glBufferData(GL_ARRAY_BUFFER, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW);
212    glBindBuffer(GL_ARRAY_BUFFER, 0);
213    rsc->checkError("Allocation::uploadToBufferObject");
214}
215
216void Allocation::uploadCheck(const Context *rsc)
217{
218    if (mUploadDefered) {
219        mUploadDefered = false;
220        if (mIsVertexBuffer) {
221            uploadToBufferObject(rsc);
222        }
223        if (mIsTexture) {
224            uploadToTexture(rsc);
225        }
226    }
227}
228
229
230void Allocation::data(const void *data, uint32_t sizeBytes)
231{
232    uint32_t size = mType->getSizeBytes();
233    if (size != sizeBytes) {
234        LOGE("Allocation::data called with mismatched size expected %i, got %i", size, sizeBytes);
235        return;
236    }
237
238    if (mType->getElement()->getHasReferences()) {
239        incRefs(data, sizeBytes / mType->getElement()->getSizeBytes());
240        decRefs(mPtr, sizeBytes / mType->getElement()->getSizeBytes());
241    }
242
243    memcpy(mPtr, data, size);
244    sendDirty();
245    mUploadDefered = true;
246}
247
248void Allocation::read(void *data)
249{
250    memcpy(data, mPtr, mType->getSizeBytes());
251}
252
253void Allocation::subData(uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes)
254{
255    uint32_t eSize = mType->getElementSizeBytes();
256    uint8_t * ptr = static_cast<uint8_t *>(mPtr);
257    ptr += eSize * xoff;
258    uint32_t size = count * eSize;
259
260    if (size != sizeBytes) {
261        LOGE("Allocation::subData called with mismatched size expected %i, got %i", size, sizeBytes);
262        mType->dumpLOGV("type info");
263        return;
264    }
265
266    if (mType->getElement()->getHasReferences()) {
267        incRefs(data, count);
268        decRefs(ptr, count);
269    }
270
271    memcpy(ptr, data, size);
272    sendDirty();
273    mUploadDefered = true;
274}
275
276void Allocation::subData(uint32_t xoff, uint32_t yoff,
277             uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes)
278{
279    uint32_t eSize = mType->getElementSizeBytes();
280    uint32_t lineSize = eSize * w;
281    uint32_t destW = mType->getDimX();
282
283    const uint8_t *src = static_cast<const uint8_t *>(data);
284    uint8_t *dst = static_cast<uint8_t *>(mPtr);
285    dst += eSize * (xoff + yoff * destW);
286
287    if ((lineSize * eSize * h) != sizeBytes) {
288        rsAssert(!"Allocation::subData called with mismatched size");
289        return;
290    }
291
292    for (uint32_t line=yoff; line < (yoff+h); line++) {
293        uint8_t * ptr = static_cast<uint8_t *>(mPtr);
294        if (mType->getElement()->getHasReferences()) {
295            incRefs(src, w);
296            decRefs(dst, w);
297        }
298        memcpy(dst, src, lineSize);
299        src += lineSize;
300        dst += destW * eSize;
301    }
302    sendDirty();
303    mUploadDefered = true;
304}
305
306void Allocation::subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
307             uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes)
308{
309}
310
311void Allocation::addProgramToDirty(const Program *p)
312{
313    mToDirtyList.push(p);
314}
315
316void Allocation::removeProgramToDirty(const Program *p)
317{
318    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
319        if (mToDirtyList[ct] == p) {
320            mToDirtyList.removeAt(ct);
321            return;
322        }
323    }
324    rsAssert(0);
325}
326
327void Allocation::dumpLOGV(const char *prefix) const
328{
329    ObjectBase::dumpLOGV(prefix);
330
331    String8 s(prefix);
332    s.append(" type ");
333    if (mType.get()) {
334        mType->dumpLOGV(s.string());
335    }
336
337    LOGV("%s allocation ptr=%p mCpuWrite=%i, mCpuRead=%i, mGpuWrite=%i, mGpuRead=%i",
338          prefix, mPtr, mCpuWrite, mCpuRead, mGpuWrite, mGpuRead);
339
340    LOGV("%s allocation mIsTexture=%i mTextureID=%i, mIsVertexBuffer=%i, mBufferID=%i",
341          prefix, mIsTexture, mTextureID, mIsVertexBuffer, mBufferID);
342
343}
344
345void Allocation::serialize(OStream *stream) const
346{
347    // Need to identify ourselves
348    stream->addU32((uint32_t)getClassId());
349
350    String8 name(getName());
351    stream->addString(&name);
352
353    // First thing we need to serialize is the type object since it will be needed
354    // to initialize the class
355    mType->serialize(stream);
356
357    uint32_t dataSize = mType->getSizeBytes();
358    // Write how much data we are storing
359    stream->addU32(dataSize);
360    // Now write the data
361    stream->addByteArray(mPtr, dataSize);
362}
363
364Allocation *Allocation::createFromStream(Context *rsc, IStream *stream)
365{
366    // First make sure we are reading the correct object
367    RsA3DClassID classID = (RsA3DClassID)stream->loadU32();
368    if(classID != RS_A3D_CLASS_ID_ALLOCATION) {
369        LOGE("allocation loading skipped due to invalid class id\n");
370        return NULL;
371    }
372
373    String8 name;
374    stream->loadString(&name);
375
376    Type *type = Type::createFromStream(rsc, stream);
377    if(!type) {
378        return NULL;
379    }
380    type->compute();
381
382    // Number of bytes we wrote out for this allocation
383    uint32_t dataSize = stream->loadU32();
384    if(dataSize != type->getSizeBytes()) {
385        LOGE("failed to read allocation because numbytes written is not the same loaded type wants\n");
386        delete type;
387        return NULL;
388    }
389
390    Allocation *alloc = new Allocation(rsc, type);
391    alloc->setName(name.string(), name.size());
392
393    // Read in all of our allocation data
394    alloc->data(stream->getPtr() + stream->getPos(), dataSize);
395    stream->reset(stream->getPos() + dataSize);
396
397    return alloc;
398}
399
400void Allocation::sendDirty() const
401{
402    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
403        mToDirtyList[ct]->forceDirty();
404    }
405}
406
407void Allocation::incRefs(const void *ptr, size_t ct) const
408{
409    const uint8_t *p = static_cast<const uint8_t *>(ptr);
410    const Element *e = mType->getElement();
411    uint32_t stride = e->getSizeBytes();
412
413    while (ct > 0) {
414        e->incRefs(p);
415        ct --;
416        p += stride;
417    }
418}
419
420void Allocation::decRefs(const void *ptr, size_t ct) const
421{
422    const uint8_t *p = static_cast<const uint8_t *>(ptr);
423    const Element *e = mType->getElement();
424    uint32_t stride = e->getSizeBytes();
425
426    while (ct > 0) {
427        e->decRefs(p);
428        ct --;
429        p += stride;
430    }
431}
432
433/////////////////
434//
435
436
437namespace android {
438namespace renderscript {
439
440RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype)
441{
442    const Type * type = static_cast<const Type *>(vtype);
443
444    Allocation * alloc = new Allocation(rsc, type);
445    alloc->incUserRef();
446    return alloc;
447}
448
449RsAllocation rsi_AllocationCreateSized(Context *rsc, RsElement e, size_t count)
450{
451    Type * type = new Type(rsc);
452    type->setDimX(count);
453    type->setElement(static_cast<Element *>(e));
454    type->compute();
455    return rsi_AllocationCreateTyped(rsc, type);
456}
457
458void rsi_AllocationUploadToTexture(Context *rsc, RsAllocation va, bool genmip, uint32_t baseMipLevel)
459{
460    Allocation *alloc = static_cast<Allocation *>(va);
461    alloc->deferedUploadToTexture(rsc, genmip, baseMipLevel);
462}
463
464void rsi_AllocationUploadToBufferObject(Context *rsc, RsAllocation va)
465{
466    Allocation *alloc = static_cast<Allocation *>(va);
467    alloc->deferedUploadToBufferObject(rsc);
468}
469
470static void mip565(const Adapter2D &out, const Adapter2D &in)
471{
472    uint32_t w = out.getDimX();
473    uint32_t h = out.getDimY();
474
475    for (uint32_t y=0; y < h; y++) {
476        uint16_t *oPtr = static_cast<uint16_t *>(out.getElement(0, y));
477        const uint16_t *i1 = static_cast<uint16_t *>(in.getElement(0, y*2));
478        const uint16_t *i2 = static_cast<uint16_t *>(in.getElement(0, y*2+1));
479
480        for (uint32_t x=0; x < w; x++) {
481            *oPtr = rsBoxFilter565(i1[0], i1[1], i2[0], i2[1]);
482            oPtr ++;
483            i1 += 2;
484            i2 += 2;
485        }
486    }
487}
488
489static void mip8888(const Adapter2D &out, const Adapter2D &in)
490{
491    uint32_t w = out.getDimX();
492    uint32_t h = out.getDimY();
493
494    for (uint32_t y=0; y < h; y++) {
495        uint32_t *oPtr = static_cast<uint32_t *>(out.getElement(0, y));
496        const uint32_t *i1 = static_cast<uint32_t *>(in.getElement(0, y*2));
497        const uint32_t *i2 = static_cast<uint32_t *>(in.getElement(0, y*2+1));
498
499        for (uint32_t x=0; x < w; x++) {
500            *oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]);
501            oPtr ++;
502            i1 += 2;
503            i2 += 2;
504        }
505    }
506}
507
508static void mip8(const Adapter2D &out, const Adapter2D &in)
509{
510    uint32_t w = out.getDimX();
511    uint32_t h = out.getDimY();
512
513    for (uint32_t y=0; y < h; y++) {
514        uint8_t *oPtr = static_cast<uint8_t *>(out.getElement(0, y));
515        const uint8_t *i1 = static_cast<uint8_t *>(in.getElement(0, y*2));
516        const uint8_t *i2 = static_cast<uint8_t *>(in.getElement(0, y*2+1));
517
518        for (uint32_t x=0; x < w; x++) {
519            *oPtr = (uint8_t)(((uint32_t)i1[0] + i1[1] + i2[0] + i2[1]) * 0.25f);
520            oPtr ++;
521            i1 += 2;
522            i2 += 2;
523        }
524    }
525}
526
527static void mip(const Adapter2D &out, const Adapter2D &in)
528{
529    switch(out.getBaseType()->getElement()->getSizeBits()) {
530    case 32:
531        mip8888(out, in);
532        break;
533    case 16:
534        mip565(out, in);
535        break;
536    case 8:
537        mip8(out, in);
538        break;
539
540    }
541
542}
543
544typedef void (*ElementConverter_t)(void *dst, const void *src, uint32_t count);
545
546static void elementConverter_cpy_16(void *dst, const void *src, uint32_t count)
547{
548    memcpy(dst, src, count * 2);
549}
550static void elementConverter_cpy_8(void *dst, const void *src, uint32_t count)
551{
552    memcpy(dst, src, count);
553}
554static void elementConverter_cpy_32(void *dst, const void *src, uint32_t count)
555{
556    memcpy(dst, src, count * 4);
557}
558
559
560static void elementConverter_888_to_565(void *dst, const void *src, uint32_t count)
561{
562    uint16_t *d = static_cast<uint16_t *>(dst);
563    const uint8_t *s = static_cast<const uint8_t *>(src);
564
565    while(count--) {
566        *d = rs888to565(s[0], s[1], s[2]);
567        d++;
568        s+= 3;
569    }
570}
571
572static void elementConverter_8888_to_565(void *dst, const void *src, uint32_t count)
573{
574    uint16_t *d = static_cast<uint16_t *>(dst);
575    const uint8_t *s = static_cast<const uint8_t *>(src);
576
577    while(count--) {
578        *d = rs888to565(s[0], s[1], s[2]);
579        d++;
580        s+= 4;
581    }
582}
583
584static ElementConverter_t pickConverter(const Element *dst, const Element *src)
585{
586    GLenum srcGLType = src->getComponent().getGLType();
587    GLenum srcGLFmt = src->getComponent().getGLFormat();
588    GLenum dstGLType = dst->getComponent().getGLType();
589    GLenum dstGLFmt = dst->getComponent().getGLFormat();
590
591    if (srcGLFmt == dstGLFmt && srcGLType == dstGLType) {
592        switch(dst->getSizeBytes()) {
593        case 4:
594            return elementConverter_cpy_32;
595        case 2:
596            return elementConverter_cpy_16;
597        case 1:
598            return elementConverter_cpy_8;
599        }
600    }
601
602    if (srcGLType == GL_UNSIGNED_BYTE &&
603        srcGLFmt == GL_RGB &&
604        dstGLType == GL_UNSIGNED_SHORT_5_6_5 &&
605        dstGLFmt == GL_RGB) {
606
607        return elementConverter_888_to_565;
608    }
609
610    if (srcGLType == GL_UNSIGNED_BYTE &&
611        srcGLFmt == GL_RGBA &&
612        dstGLType == GL_UNSIGNED_SHORT_5_6_5 &&
613        dstGLFmt == GL_RGB) {
614
615        return elementConverter_8888_to_565;
616    }
617
618    LOGE("pickConverter, unsuported combo, src %p,  dst %p", src, dst);
619    LOGE("pickConverter, srcGLType = %x,  srcGLFmt = %x", srcGLType, srcGLFmt);
620    LOGE("pickConverter, dstGLType = %x,  dstGLFmt = %x", dstGLType, dstGLFmt);
621    src->dumpLOGV("SRC ");
622    dst->dumpLOGV("DST ");
623    return 0;
624}
625
626#ifndef ANDROID_RS_BUILD_FOR_HOST
627
628RsAllocation rsi_AllocationCreateBitmapRef(Context *rsc, RsType vtype,
629                                           void *bmp, void *callbackData, RsBitmapCallback_t callback)
630{
631    const Type * type = static_cast<const Type *>(vtype);
632    Allocation * alloc = new Allocation(rsc, type, bmp, callbackData, callback);
633    alloc->incUserRef();
634    return alloc;
635}
636
637RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h, RsElement _dst, RsElement _src,  bool genMips, const void *data)
638{
639    const Element *src = static_cast<const Element *>(_src);
640    const Element *dst = static_cast<const Element *>(_dst);
641
642    // Check for pow2 on pre es 2.0 versions.
643    rsAssert(rsc->checkVersion2_0() || (!(w & (w-1)) && !(h & (h-1))));
644
645    //LOGE("rsi_AllocationCreateFromBitmap %i %i %i %i %i", w, h, dstFmt, srcFmt, genMips);
646    rsi_TypeBegin(rsc, _dst);
647    rsi_TypeAdd(rsc, RS_DIMENSION_X, w);
648    rsi_TypeAdd(rsc, RS_DIMENSION_Y, h);
649    if (genMips) {
650        rsi_TypeAdd(rsc, RS_DIMENSION_LOD, 1);
651    }
652    RsType type = rsi_TypeCreate(rsc);
653
654    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, type);
655    Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
656    if (texAlloc == NULL) {
657        LOGE("Memory allocation failure");
658        return NULL;
659    }
660
661    ElementConverter_t cvt = pickConverter(dst, src);
662    cvt(texAlloc->getPtr(), data, w * h);
663
664    if (genMips) {
665        Adapter2D adapt(rsc, texAlloc);
666        Adapter2D adapt2(rsc, texAlloc);
667        for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
668            adapt.setLOD(lod);
669            adapt2.setLOD(lod + 1);
670            mip(adapt2, adapt);
671        }
672    }
673
674    return texAlloc;
675}
676
677RsAllocation rsi_AllocationCreateFromBitmapBoxed(Context *rsc, uint32_t w, uint32_t h, RsElement _dst, RsElement _src, bool genMips, const void *data)
678{
679    const Element *srcE = static_cast<const Element *>(_src);
680    const Element *dstE = static_cast<const Element *>(_dst);
681    uint32_t w2 = rsHigherPow2(w);
682    uint32_t h2 = rsHigherPow2(h);
683
684    if ((w2 == w) && (h2 == h)) {
685        return rsi_AllocationCreateFromBitmap(rsc, w, h, _dst, _src, genMips, data);
686    }
687
688    uint32_t bpp = srcE->getSizeBytes();
689    size_t size = w2 * h2 * bpp;
690    uint8_t *tmp = static_cast<uint8_t *>(malloc(size));
691    memset(tmp, 0, size);
692
693    const uint8_t * src = static_cast<const uint8_t *>(data);
694    for (uint32_t y = 0; y < h; y++) {
695        uint8_t * ydst = &tmp[(y + ((h2 - h) >> 1)) * w2 * bpp];
696        memcpy(&ydst[((w2 - w) >> 1) * bpp], src, w * bpp);
697        src += w * bpp;
698    }
699
700    RsAllocation ret = rsi_AllocationCreateFromBitmap(rsc, w2, h2, _dst, _src, genMips, tmp);
701    free(tmp);
702    return ret;
703}
704
705void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data, uint32_t sizeBytes)
706{
707    Allocation *a = static_cast<Allocation *>(va);
708    a->data(data, sizeBytes);
709}
710
711void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes)
712{
713    Allocation *a = static_cast<Allocation *>(va);
714    a->subData(xoff, count, data, sizeBytes);
715}
716
717void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes)
718{
719    Allocation *a = static_cast<Allocation *>(va);
720    a->subData(xoff, yoff, w, h, data, sizeBytes);
721}
722
723void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data)
724{
725    Allocation *a = static_cast<Allocation *>(va);
726    a->read(data);
727}
728
729const void* rsi_AllocationGetType(Context *rsc, RsAllocation va)
730{
731    Allocation *a = static_cast<Allocation *>(va);
732    a->getType()->incUserRef();
733
734    return a->getType();
735}
736
737#endif //ANDROID_RS_BUILD_FOR_HOST
738
739}
740}
741