rsAllocation.cpp revision 25413ecdb9359410652da7b8ef5ec0ce0fe0a640
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
29#include "utils/StopWatch.h"
30
31using namespace android;
32using namespace android::renderscript;
33
34Allocation::Allocation(Context *rsc, const Type *type) : ObjectBase(rsc) {
35    init(rsc, type);
36
37    mPtr = malloc(mType->getSizeBytes());
38    if (mType->getElement()->getHasReferences()) {
39        memset(mPtr, 0, mType->getSizeBytes());
40    }
41    if (!mPtr) {
42        LOGE("Allocation::Allocation, alloc failure");
43    }
44}
45
46Allocation::Allocation(Context *rsc, const Type *type, void *bmp,
47                       void *callbackData, RsBitmapCallback_t callback)
48                       : ObjectBase(rsc) {
49    init(rsc, type);
50
51    mPtr = bmp;
52    mUserBitmapCallback = callback;
53    mUserBitmapCallbackData = callbackData;
54}
55
56void Allocation::init(Context *rsc, const Type *type) {
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    if (mUserBitmapCallback != NULL) {
84        mUserBitmapCallback(mUserBitmapCallbackData);
85    } else {
86        free(mPtr);
87    }
88    mPtr = NULL;
89
90    if (mBufferID) {
91        // Causes a SW crash....
92        //LOGV(" mBufferID %i", mBufferID);
93        //glDeleteBuffers(1, &mBufferID);
94        //mBufferID = 0;
95    }
96    if (mTextureID) {
97        glDeleteTextures(1, &mTextureID);
98        mTextureID = 0;
99    }
100}
101
102void Allocation::setCpuWritable(bool) {
103}
104
105void Allocation::setGpuWritable(bool) {
106}
107
108void Allocation::setCpuReadable(bool) {
109}
110
111void Allocation::setGpuReadable(bool) {
112}
113
114bool Allocation::fixAllocation() {
115    return false;
116}
117
118void Allocation::deferedUploadToTexture(const Context *rsc, bool genMipmap, uint32_t lodOffset) {
119    rsAssert(lodOffset < mType->getLODCount());
120    mIsTexture = true;
121    mTextureLOD = lodOffset;
122    mUploadDefered = true;
123    mTextureGenMipmap = !mType->getDimLOD() && genMipmap;
124}
125
126uint32_t Allocation::getGLTarget() const {
127    if (mIsTexture) {
128        if (mType->getDimFaces()) {
129            return GL_TEXTURE_CUBE_MAP;
130        } else {
131            return GL_TEXTURE_2D;
132        }
133    }
134    if (mIsVertexBuffer) {
135        return GL_ARRAY_BUFFER;
136    }
137    return 0;
138}
139
140
141void Allocation::uploadToTexture(const Context *rsc) {
142
143    mIsTexture = true;
144    if (!rsc->checkDriver()) {
145        mUploadDefered = true;
146        return;
147    }
148
149    GLenum type = mType->getElement()->getComponent().getGLType();
150    GLenum format = mType->getElement()->getComponent().getGLFormat();
151
152    if (!type || !format) {
153        return;
154    }
155
156    bool isFirstUpload = false;
157
158    if (!mTextureID) {
159        glGenTextures(1, &mTextureID);
160
161        if (!mTextureID) {
162            // This should not happen, however, its likely the cause of the
163            // white sqare bug.
164            // Force a crash to 1: restart the app, 2: make sure we get a bugreport.
165            LOGE("Upload to texture failed to gen mTextureID");
166            rsc->dumpDebug();
167            mUploadDefered = true;
168            return;
169        }
170        isFirstUpload = true;
171    }
172
173    GLenum target = (GLenum)getGLTarget();
174    glBindTexture(target, mTextureID);
175    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
176
177    if (target == GL_TEXTURE_2D) {
178        upload2DTexture(isFirstUpload);
179    } else if (target == GL_TEXTURE_CUBE_MAP) {
180        uploadCubeTexture(isFirstUpload);
181    }
182
183    if (mTextureGenMipmap) {
184#ifndef ANDROID_RS_BUILD_FOR_HOST
185        glGenerateMipmap(target);
186#endif //ANDROID_RS_BUILD_FOR_HOST
187    }
188
189    rsc->checkError("Allocation::uploadToTexture");
190}
191
192void Allocation::upload2DTexture(bool isFirstUpload) {
193    GLenum type = mType->getElement()->getComponent().getGLType();
194    GLenum format = mType->getElement()->getComponent().getGLFormat();
195
196    Adapter2D adapt(getContext(), this);
197    for (uint32_t lod = 0; (lod + mTextureLOD) < mType->getLODCount(); lod++) {
198        adapt.setLOD(lod+mTextureLOD);
199
200        uint16_t * ptr = static_cast<uint16_t *>(adapt.getElement(0,0));
201        if (isFirstUpload) {
202            glTexImage2D(GL_TEXTURE_2D, lod, format,
203                         adapt.getDimX(), adapt.getDimY(),
204                         0, format, type, ptr);
205        } else {
206            glTexSubImage2D(GL_TEXTURE_2D, lod, 0, 0,
207                            adapt.getDimX(), adapt.getDimY(),
208                            format, type, ptr);
209        }
210    }
211}
212
213void Allocation::uploadCubeTexture(bool isFirstUpload) {
214    GLenum type = mType->getElement()->getComponent().getGLType();
215    GLenum format = mType->getElement()->getComponent().getGLFormat();
216
217    GLenum faceOrder[] = {
218        GL_TEXTURE_CUBE_MAP_POSITIVE_X,
219        GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
220        GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
221        GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
222        GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
223        GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
224    };
225
226    Adapter2D adapt(getContext(), this);
227    for (uint32_t face = 0; face < 6; face ++) {
228        adapt.setFace(face);
229
230        for (uint32_t lod = 0; (lod + mTextureLOD) < mType->getLODCount(); lod++) {
231            adapt.setLOD(lod+mTextureLOD);
232
233            uint16_t * ptr = static_cast<uint16_t *>(adapt.getElement(0,0));
234
235            if (isFirstUpload) {
236                glTexImage2D(faceOrder[face], lod, format,
237                             adapt.getDimX(), adapt.getDimY(),
238                             0, format, type, ptr);
239            } else {
240                glTexSubImage2D(faceOrder[face], lod, 0, 0,
241                                adapt.getDimX(), adapt.getDimY(),
242                                format, type, ptr);
243            }
244        }
245    }
246}
247
248void Allocation::deferedUploadToBufferObject(const Context *rsc) {
249    mIsVertexBuffer = true;
250    mUploadDefered = true;
251}
252
253void Allocation::uploadToBufferObject(const Context *rsc) {
254    rsAssert(!mType->getDimY());
255    rsAssert(!mType->getDimZ());
256
257    mIsVertexBuffer = true;
258    if (!rsc->checkDriver()) {
259        mUploadDefered = true;
260        return;
261    }
262
263    if (!mBufferID) {
264        glGenBuffers(1, &mBufferID);
265    }
266    if (!mBufferID) {
267        LOGE("Upload to buffer object failed");
268        mUploadDefered = true;
269        return;
270    }
271    GLenum target = (GLenum)getGLTarget();
272    glBindBuffer(target, mBufferID);
273    glBufferData(target, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW);
274    glBindBuffer(target, 0);
275    rsc->checkError("Allocation::uploadToBufferObject");
276}
277
278void Allocation::uploadCheck(const Context *rsc) {
279    if (mUploadDefered) {
280        mUploadDefered = false;
281        if (mIsVertexBuffer) {
282            uploadToBufferObject(rsc);
283        }
284        if (mIsTexture) {
285            uploadToTexture(rsc);
286        }
287    }
288}
289
290
291void Allocation::data(Context *rsc, const void *data, uint32_t sizeBytes) {
292    uint32_t size = mType->getSizeBytes();
293    if (size != sizeBytes) {
294        LOGE("Allocation::data called with mismatched size expected %i, got %i", size, sizeBytes);
295        return;
296    }
297
298    if (mType->getElement()->getHasReferences()) {
299        incRefs(data, sizeBytes / mType->getElement()->getSizeBytes());
300        decRefs(mPtr, sizeBytes / mType->getElement()->getSizeBytes());
301    }
302
303    memcpy(mPtr, data, size);
304    sendDirty();
305    mUploadDefered = true;
306}
307
308void Allocation::read(void *data) {
309    memcpy(data, mPtr, mType->getSizeBytes());
310}
311
312void Allocation::subData(Context *rsc, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes) {
313    uint32_t eSize = mType->getElementSizeBytes();
314    uint8_t * ptr = static_cast<uint8_t *>(mPtr);
315    ptr += eSize * xoff;
316    uint32_t size = count * eSize;
317
318    if (size != sizeBytes) {
319        LOGE("Allocation::subData called with mismatched size expected %i, got %i", size, sizeBytes);
320        mType->dumpLOGV("type info");
321        return;
322    }
323
324    if (mType->getElement()->getHasReferences()) {
325        incRefs(data, count);
326        decRefs(ptr, count);
327    }
328
329    memcpy(ptr, data, size);
330    sendDirty();
331    mUploadDefered = true;
332}
333
334void Allocation::subData(Context *rsc, uint32_t xoff, uint32_t yoff,
335             uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) {
336    uint32_t eSize = mType->getElementSizeBytes();
337    uint32_t lineSize = eSize * w;
338    uint32_t destW = mType->getDimX();
339
340    const uint8_t *src = static_cast<const uint8_t *>(data);
341    uint8_t *dst = static_cast<uint8_t *>(mPtr);
342    dst += eSize * (xoff + yoff * destW);
343
344    if ((lineSize * eSize * h) != sizeBytes) {
345        rsAssert(!"Allocation::subData called with mismatched size");
346        return;
347    }
348
349    for (uint32_t line=yoff; line < (yoff+h); line++) {
350        if (mType->getElement()->getHasReferences()) {
351            incRefs(src, w);
352            decRefs(dst, w);
353        }
354        memcpy(dst, src, lineSize);
355        src += lineSize;
356        dst += destW * eSize;
357    }
358    sendDirty();
359    mUploadDefered = true;
360}
361
362void Allocation::subData(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff,
363             uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) {
364}
365
366void Allocation::subElementData(Context *rsc, uint32_t x, const void *data,
367                                uint32_t cIdx, uint32_t sizeBytes) {
368    uint32_t eSize = mType->getElementSizeBytes();
369    uint8_t * ptr = static_cast<uint8_t *>(mPtr);
370    ptr += eSize * x;
371
372    if (cIdx >= mType->getElement()->getFieldCount()) {
373        LOGE("Error Allocation::subElementData component %i out of range.", cIdx);
374        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData component out of range.");
375        return;
376    }
377
378    if (x >= mType->getDimX()) {
379        LOGE("Error Allocation::subElementData X offset %i out of range.", x);
380        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range.");
381        return;
382    }
383
384    const Element * e = mType->getElement()->getField(cIdx);
385    ptr += mType->getElement()->getFieldOffsetBytes(cIdx);
386
387    if (sizeBytes != e->getSizeBytes()) {
388        LOGE("Error Allocation::subElementData data size %i does not match field size %i.", sizeBytes, e->getSizeBytes());
389        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size.");
390        return;
391    }
392
393    if (e->getHasReferences()) {
394        e->incRefs(data);
395        e->decRefs(ptr);
396    }
397
398    memcpy(ptr, data, sizeBytes);
399    sendDirty();
400    mUploadDefered = true;
401}
402
403void Allocation::subElementData(Context *rsc, uint32_t x, uint32_t y,
404                                const void *data, uint32_t cIdx, uint32_t sizeBytes) {
405    uint32_t eSize = mType->getElementSizeBytes();
406    uint8_t * ptr = static_cast<uint8_t *>(mPtr);
407    ptr += eSize * (x + y * mType->getDimX());
408
409    if (x >= mType->getDimX()) {
410        LOGE("Error Allocation::subElementData X offset %i out of range.", x);
411        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range.");
412        return;
413    }
414
415    if (y >= mType->getDimY()) {
416        LOGE("Error Allocation::subElementData X offset %i out of range.", x);
417        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range.");
418        return;
419    }
420
421    if (cIdx >= mType->getElement()->getFieldCount()) {
422        LOGE("Error Allocation::subElementData component %i out of range.", cIdx);
423        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData component out of range.");
424        return;
425    }
426
427    const Element * e = mType->getElement()->getField(cIdx);
428    ptr += mType->getElement()->getFieldOffsetBytes(cIdx);
429
430    if (sizeBytes != e->getSizeBytes()) {
431        LOGE("Error Allocation::subElementData data size %i does not match field size %i.", sizeBytes, e->getSizeBytes());
432        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size.");
433        return;
434    }
435
436    if (e->getHasReferences()) {
437        e->incRefs(data);
438        e->decRefs(ptr);
439    }
440
441    memcpy(ptr, data, sizeBytes);
442    sendDirty();
443    mUploadDefered = true;
444}
445
446void Allocation::addProgramToDirty(const Program *p) {
447    mToDirtyList.push(p);
448}
449
450void Allocation::removeProgramToDirty(const Program *p) {
451    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
452        if (mToDirtyList[ct] == p) {
453            mToDirtyList.removeAt(ct);
454            return;
455        }
456    }
457    rsAssert(0);
458}
459
460void Allocation::dumpLOGV(const char *prefix) const {
461    ObjectBase::dumpLOGV(prefix);
462
463    String8 s(prefix);
464    s.append(" type ");
465    if (mType.get()) {
466        mType->dumpLOGV(s.string());
467    }
468
469    LOGV("%s allocation ptr=%p mCpuWrite=%i, mCpuRead=%i, mGpuWrite=%i, mGpuRead=%i",
470          prefix, mPtr, mCpuWrite, mCpuRead, mGpuWrite, mGpuRead);
471
472    LOGV("%s allocation mIsTexture=%i mTextureID=%i, mIsVertexBuffer=%i, mBufferID=%i",
473          prefix, mIsTexture, mTextureID, mIsVertexBuffer, mBufferID);
474}
475
476void Allocation::serialize(OStream *stream) const {
477    // Need to identify ourselves
478    stream->addU32((uint32_t)getClassId());
479
480    String8 name(getName());
481    stream->addString(&name);
482
483    // First thing we need to serialize is the type object since it will be needed
484    // to initialize the class
485    mType->serialize(stream);
486
487    uint32_t dataSize = mType->getSizeBytes();
488    // Write how much data we are storing
489    stream->addU32(dataSize);
490    // Now write the data
491    stream->addByteArray(mPtr, dataSize);
492}
493
494Allocation *Allocation::createFromStream(Context *rsc, IStream *stream) {
495    // First make sure we are reading the correct object
496    RsA3DClassID classID = (RsA3DClassID)stream->loadU32();
497    if (classID != RS_A3D_CLASS_ID_ALLOCATION) {
498        LOGE("allocation loading skipped due to invalid class id\n");
499        return NULL;
500    }
501
502    String8 name;
503    stream->loadString(&name);
504
505    Type *type = Type::createFromStream(rsc, stream);
506    if (!type) {
507        return NULL;
508    }
509    type->compute();
510
511    // Number of bytes we wrote out for this allocation
512    uint32_t dataSize = stream->loadU32();
513    if (dataSize != type->getSizeBytes()) {
514        LOGE("failed to read allocation because numbytes written is not the same loaded type wants\n");
515        ObjectBase::checkDelete(type);
516        return NULL;
517    }
518
519    Allocation *alloc = new Allocation(rsc, type);
520    alloc->setName(name.string(), name.size());
521
522    // Read in all of our allocation data
523    alloc->data(rsc, stream->getPtr() + stream->getPos(), dataSize);
524    stream->reset(stream->getPos() + dataSize);
525
526    return alloc;
527}
528
529void Allocation::sendDirty() const {
530    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
531        mToDirtyList[ct]->forceDirty();
532    }
533}
534
535void Allocation::incRefs(const void *ptr, size_t ct, size_t startOff) const {
536    const uint8_t *p = static_cast<const uint8_t *>(ptr);
537    const Element *e = mType->getElement();
538    uint32_t stride = e->getSizeBytes();
539
540    p += stride * startOff;
541    while (ct > 0) {
542        e->incRefs(p);
543        ct --;
544        p += stride;
545    }
546}
547
548void Allocation::decRefs(const void *ptr, size_t ct, size_t startOff) const {
549    const uint8_t *p = static_cast<const uint8_t *>(ptr);
550    const Element *e = mType->getElement();
551    uint32_t stride = e->getSizeBytes();
552
553    p += stride * startOff;
554    while (ct > 0) {
555        e->decRefs(p);
556        ct --;
557        p += stride;
558    }
559}
560
561void Allocation::copyRange1D(Context *rsc, const Allocation *src, int32_t srcOff, int32_t destOff, int32_t len) {
562}
563
564void Allocation::resize1D(Context *rsc, uint32_t dimX) {
565    Type *t = mType->cloneAndResize1D(rsc, dimX);
566
567    uint32_t oldDimX = mType->getDimX();
568    if (dimX == oldDimX) {
569        return;
570    }
571
572    if (dimX < oldDimX) {
573        decRefs(mPtr, oldDimX - dimX, dimX);
574    }
575    mPtr = realloc(mPtr, t->getSizeBytes());
576
577    if (dimX > oldDimX) {
578        const Element *e = mType->getElement();
579        uint32_t stride = e->getSizeBytes();
580        memset(((uint8_t *)mPtr) + stride * oldDimX, 0, stride * (dimX - oldDimX));
581    }
582    mType.set(t);
583}
584
585void Allocation::resize2D(Context *rsc, uint32_t dimX, uint32_t dimY) {
586    LOGE("not implemented");
587}
588
589/////////////////
590//
591
592
593namespace android {
594namespace renderscript {
595
596void rsi_AllocationUploadToTexture(Context *rsc, RsAllocation va, bool genmip, uint32_t baseMipLevel) {
597    Allocation *alloc = static_cast<Allocation *>(va);
598    alloc->deferedUploadToTexture(rsc, genmip, baseMipLevel);
599}
600
601void rsi_AllocationUploadToBufferObject(Context *rsc, RsAllocation va) {
602    Allocation *alloc = static_cast<Allocation *>(va);
603    alloc->deferedUploadToBufferObject(rsc);
604}
605
606static void mip565(const Adapter2D &out, const Adapter2D &in) {
607    uint32_t w = out.getDimX();
608    uint32_t h = out.getDimY();
609
610    for (uint32_t y=0; y < h; y++) {
611        uint16_t *oPtr = static_cast<uint16_t *>(out.getElement(0, y));
612        const uint16_t *i1 = static_cast<uint16_t *>(in.getElement(0, y*2));
613        const uint16_t *i2 = static_cast<uint16_t *>(in.getElement(0, y*2+1));
614
615        for (uint32_t x=0; x < w; x++) {
616            *oPtr = rsBoxFilter565(i1[0], i1[1], i2[0], i2[1]);
617            oPtr ++;
618            i1 += 2;
619            i2 += 2;
620        }
621    }
622}
623
624static void mip8888(const Adapter2D &out, const Adapter2D &in) {
625    uint32_t w = out.getDimX();
626    uint32_t h = out.getDimY();
627
628    for (uint32_t y=0; y < h; y++) {
629        uint32_t *oPtr = static_cast<uint32_t *>(out.getElement(0, y));
630        const uint32_t *i1 = static_cast<uint32_t *>(in.getElement(0, y*2));
631        const uint32_t *i2 = static_cast<uint32_t *>(in.getElement(0, y*2+1));
632
633        for (uint32_t x=0; x < w; x++) {
634            *oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]);
635            oPtr ++;
636            i1 += 2;
637            i2 += 2;
638        }
639    }
640}
641
642static void mip8(const Adapter2D &out, const Adapter2D &in) {
643    uint32_t w = out.getDimX();
644    uint32_t h = out.getDimY();
645
646    for (uint32_t y=0; y < h; y++) {
647        uint8_t *oPtr = static_cast<uint8_t *>(out.getElement(0, y));
648        const uint8_t *i1 = static_cast<uint8_t *>(in.getElement(0, y*2));
649        const uint8_t *i2 = static_cast<uint8_t *>(in.getElement(0, y*2+1));
650
651        for (uint32_t x=0; x < w; x++) {
652            *oPtr = (uint8_t)(((uint32_t)i1[0] + i1[1] + i2[0] + i2[1]) * 0.25f);
653            oPtr ++;
654            i1 += 2;
655            i2 += 2;
656        }
657    }
658}
659
660static void mip(const Adapter2D &out, const Adapter2D &in) {
661    switch (out.getBaseType()->getElement()->getSizeBits()) {
662    case 32:
663        mip8888(out, in);
664        break;
665    case 16:
666        mip565(out, in);
667        break;
668    case 8:
669        mip8(out, in);
670        break;
671    }
672}
673
674typedef void (*ElementConverter_t)(void *dst, const void *src, uint32_t count);
675
676static void elementConverter_cpy_16(void *dst, const void *src, uint32_t count) {
677    memcpy(dst, src, count * 2);
678}
679static void elementConverter_cpy_8(void *dst, const void *src, uint32_t count) {
680    memcpy(dst, src, count);
681}
682static void elementConverter_cpy_32(void *dst, const void *src, uint32_t count) {
683    memcpy(dst, src, count * 4);
684}
685
686static void elementConverter_888_to_565(void *dst, const void *src, uint32_t count) {
687    uint16_t *d = static_cast<uint16_t *>(dst);
688    const uint8_t *s = static_cast<const uint8_t *>(src);
689
690    while (count--) {
691        *d = rs888to565(s[0], s[1], s[2]);
692        d++;
693        s+= 3;
694    }
695}
696
697static void elementConverter_8888_to_565(void *dst, const void *src, uint32_t count) {
698    uint16_t *d = static_cast<uint16_t *>(dst);
699    const uint8_t *s = static_cast<const uint8_t *>(src);
700
701    while (count--) {
702        *d = rs888to565(s[0], s[1], s[2]);
703        d++;
704        s+= 4;
705    }
706}
707
708static ElementConverter_t pickConverter(const Element *dst, const Element *src) {
709    GLenum srcGLType = src->getComponent().getGLType();
710    GLenum srcGLFmt = src->getComponent().getGLFormat();
711    GLenum dstGLType = dst->getComponent().getGLType();
712    GLenum dstGLFmt = dst->getComponent().getGLFormat();
713
714    if (srcGLFmt == dstGLFmt && srcGLType == dstGLType) {
715        switch (dst->getSizeBytes()) {
716        case 4:
717            return elementConverter_cpy_32;
718        case 2:
719            return elementConverter_cpy_16;
720        case 1:
721            return elementConverter_cpy_8;
722        }
723    }
724
725    if (srcGLType == GL_UNSIGNED_BYTE &&
726        srcGLFmt == GL_RGB &&
727        dstGLType == GL_UNSIGNED_SHORT_5_6_5 &&
728        dstGLFmt == GL_RGB) {
729
730        return elementConverter_888_to_565;
731    }
732
733    if (srcGLType == GL_UNSIGNED_BYTE &&
734        srcGLFmt == GL_RGBA &&
735        dstGLType == GL_UNSIGNED_SHORT_5_6_5 &&
736        dstGLFmt == GL_RGB) {
737
738        return elementConverter_8888_to_565;
739    }
740
741    LOGE("pickConverter, unsuported combo, src %p,  dst %p", src, dst);
742    LOGE("pickConverter, srcGLType = %x,  srcGLFmt = %x", srcGLType, srcGLFmt);
743    LOGE("pickConverter, dstGLType = %x,  dstGLFmt = %x", dstGLType, dstGLFmt);
744    src->dumpLOGV("SRC ");
745    dst->dumpLOGV("DST ");
746    return 0;
747}
748
749#ifndef ANDROID_RS_BUILD_FOR_HOST
750
751RsAllocation rsi_AllocationCreateBitmapRef(Context *rsc, RsType vtype,
752                                           void *bmp, void *callbackData,
753                                           RsBitmapCallback_t callback) {
754    const Type * type = static_cast<const Type *>(vtype);
755    Allocation * alloc = new Allocation(rsc, type, bmp, callbackData, callback);
756    alloc->incUserRef();
757    return alloc;
758}
759
760void rsi_AllocationUpdateFromBitmap(Context *rsc, RsAllocation va,
761                                    RsElement _src, const void *data) {
762    Allocation *texAlloc = static_cast<Allocation *>(va);
763    const Element *src = static_cast<const Element *>(_src);
764    const Element *dst = texAlloc->getType()->getElement();
765    uint32_t w = texAlloc->getType()->getDimX();
766    uint32_t h = texAlloc->getType()->getDimY();
767    bool genMips = texAlloc->getType()->getDimLOD();
768
769    ElementConverter_t cvt = pickConverter(dst, src);
770    if (cvt) {
771        cvt(texAlloc->getPtr(), data, w * h);
772        if (genMips) {
773            Adapter2D adapt(rsc, texAlloc);
774            Adapter2D adapt2(rsc, texAlloc);
775            for (uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
776                adapt.setLOD(lod);
777                adapt2.setLOD(lod + 1);
778                mip(adapt2, adapt);
779            }
780        }
781    } else {
782        rsc->setError(RS_ERROR_BAD_VALUE, "Unsupported bitmap format");
783    }
784}
785
786void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data, uint32_t sizeBytes) {
787    Allocation *a = static_cast<Allocation *>(va);
788    a->data(rsc, data, sizeBytes);
789}
790
791void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes) {
792    Allocation *a = static_cast<Allocation *>(va);
793    a->subData(rsc, xoff, count, data, sizeBytes);
794}
795
796void rsi_Allocation2DSubElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t y, const void *data, uint32_t eoff, uint32_t sizeBytes) {
797    Allocation *a = static_cast<Allocation *>(va);
798    a->subElementData(rsc, x, y, data, eoff, sizeBytes);
799}
800
801void rsi_Allocation1DSubElementData(Context *rsc, RsAllocation va, uint32_t x, const void *data, uint32_t eoff, uint32_t sizeBytes) {
802    Allocation *a = static_cast<Allocation *>(va);
803    a->subElementData(rsc, x, data, eoff, sizeBytes);
804}
805
806void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) {
807    Allocation *a = static_cast<Allocation *>(va);
808    a->subData(rsc, xoff, yoff, w, h, data, sizeBytes);
809}
810
811void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data) {
812    Allocation *a = static_cast<Allocation *>(va);
813    a->read(data);
814}
815
816void rsi_AllocationResize1D(Context *rsc, RsAllocation va, uint32_t dimX) {
817    Allocation *a = static_cast<Allocation *>(va);
818    a->resize1D(rsc, dimX);
819}
820
821void rsi_AllocationResize2D(Context *rsc, RsAllocation va, uint32_t dimX, uint32_t dimY) {
822    Allocation *a = static_cast<Allocation *>(va);
823    a->resize2D(rsc, dimX, dimY);
824}
825
826#endif //ANDROID_RS_BUILD_FOR_HOST
827
828}
829}
830
831const void * rsaAllocationGetType(RsContext con, RsAllocation va) {
832    Allocation *a = static_cast<Allocation *>(va);
833    a->getType()->incUserRef();
834
835    return a->getType();
836}
837
838RsAllocation rsaAllocationCreateTyped(RsContext con, RsType vtype) {
839    Context *rsc = static_cast<Context *>(con);
840    Allocation * alloc = new Allocation(rsc, static_cast<Type *>(vtype));
841    alloc->incUserRef();
842    return alloc;
843}
844
845RsAllocation rsaAllocationCreateFromBitmap(RsContext con, uint32_t w, uint32_t h, RsElement _dst, RsElement _src,  bool genMips, const void *data) {
846    Context *rsc = static_cast<Context *>(con);
847    const Element *src = static_cast<const Element *>(_src);
848    const Element *dst = static_cast<const Element *>(_dst);
849
850    //LOGE("%p rsi_AllocationCreateFromBitmap %i %i %i", rsc, w, h, genMips);
851    RsType type = rsaTypeCreate(rsc, _dst, w, h, 0, genMips, false);
852
853    RsAllocation vTexAlloc = rsaAllocationCreateTyped(rsc, type);
854    Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
855    if (texAlloc == NULL) {
856        LOGE("Memory allocation failure");
857        return NULL;
858    }
859
860    ElementConverter_t cvt = pickConverter(dst, src);
861    if (cvt) {
862        cvt(texAlloc->getPtr(), data, w * h);
863        if (genMips) {
864            Adapter2D adapt(rsc, texAlloc);
865            Adapter2D adapt2(rsc, texAlloc);
866            for (uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
867                adapt.setLOD(lod);
868                adapt2.setLOD(lod + 1);
869                mip(adapt2, adapt);
870            }
871        }
872    } else {
873        rsc->setError(RS_ERROR_BAD_VALUE, "Unsupported bitmap format");
874        delete texAlloc;
875        return NULL;
876    }
877
878    return texAlloc;
879}
880
881RsAllocation rsaAllocationCubeCreateFromBitmap(RsContext con, uint32_t w, uint32_t h, RsElement _dst, RsElement _src,  bool genMips, const void *data) {
882    Context *rsc = static_cast<Context *>(con);
883    const Element *src = static_cast<const Element *>(_src);
884    const Element *dst = static_cast<const Element *>(_dst);
885
886    // Cubemap allocation's faces should be Width by Width each.
887    // Source data should have 6 * Width by Width pixels
888    // Error checking is done in the java layer
889    RsType type = rsaTypeCreate(rsc, _dst, w, h, 0, genMips, true);
890
891    RsAllocation vTexAlloc = rsaAllocationCreateTyped(rsc, type);
892    Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
893    if (texAlloc == NULL) {
894        LOGE("Memory allocation failure");
895        return NULL;
896    }
897
898    uint8_t *sourcePtr = (uint8_t*)data;
899    ElementConverter_t cvt = pickConverter(dst, src);
900    if (cvt) {
901        for (uint32_t face = 0; face < 6; face ++) {
902            Adapter2D faceAdapter(rsc, texAlloc);
903            faceAdapter.setFace(face);
904
905            cvt(faceAdapter.getElement(0, 0), sourcePtr, w * w);
906
907            // Move the data pointer to the next cube face
908            sourcePtr += w * w * src->getSizeBytes();
909
910            if (genMips) {
911                Adapter2D adapt(rsc, texAlloc);
912                Adapter2D adapt2(rsc, texAlloc);
913                adapt.setFace(face);
914                adapt2.setFace(face);
915                for (uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
916                    adapt.setLOD(lod);
917                    adapt2.setLOD(lod + 1);
918                    mip(adapt2, adapt);
919                }
920            }
921        }
922    } else {
923        rsc->setError(RS_ERROR_BAD_VALUE, "Unsupported bitmap format");
924        delete texAlloc;
925        return NULL;
926    }
927
928    return texAlloc;
929}
930