rsAllocation.cpp revision fb6b614bcea88a587a7ea4530be45ff0ffa0210e
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    memcpy(mPtr, data, size);
238    sendDirty();
239    mUploadDefered = true;
240}
241
242void Allocation::read(void *data)
243{
244    memcpy(data, mPtr, mType->getSizeBytes());
245}
246
247void Allocation::subData(uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes)
248{
249    uint32_t eSize = mType->getElementSizeBytes();
250    uint8_t * ptr = static_cast<uint8_t *>(mPtr);
251    ptr += eSize * xoff;
252    uint32_t size = count * eSize;
253
254    if (size != sizeBytes) {
255        LOGE("Allocation::subData called with mismatched size expected %i, got %i", size, sizeBytes);
256        mType->dumpLOGV("type info");
257        return;
258    }
259    memcpy(ptr, data, size);
260    sendDirty();
261    mUploadDefered = true;
262}
263
264void Allocation::subData(uint32_t xoff, uint32_t yoff,
265             uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes)
266{
267    uint32_t eSize = mType->getElementSizeBytes();
268    uint32_t lineSize = eSize * w;
269    uint32_t destW = mType->getDimX();
270
271    const uint8_t *src = static_cast<const uint8_t *>(data);
272    uint8_t *dst = static_cast<uint8_t *>(mPtr);
273    dst += eSize * (xoff + yoff * destW);
274
275    if ((lineSize * eSize * h) != sizeBytes) {
276        rsAssert(!"Allocation::subData called with mismatched size");
277        return;
278    }
279
280    for (uint32_t line=yoff; line < (yoff+h); line++) {
281        uint8_t * ptr = static_cast<uint8_t *>(mPtr);
282        memcpy(dst, src, lineSize);
283        src += lineSize;
284        dst += destW * eSize;
285    }
286    sendDirty();
287    mUploadDefered = true;
288}
289
290void Allocation::subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
291             uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes)
292{
293}
294
295void Allocation::addProgramToDirty(const Program *p)
296{
297    mToDirtyList.push(p);
298}
299
300void Allocation::removeProgramToDirty(const Program *p)
301{
302    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
303        if (mToDirtyList[ct] == p) {
304            mToDirtyList.removeAt(ct);
305            return;
306        }
307    }
308    rsAssert(0);
309}
310
311void Allocation::dumpLOGV(const char *prefix) const
312{
313    ObjectBase::dumpLOGV(prefix);
314
315    String8 s(prefix);
316    s.append(" type ");
317    if (mType.get()) {
318        mType->dumpLOGV(s.string());
319    }
320
321    LOGV("%s allocation ptr=%p mCpuWrite=%i, mCpuRead=%i, mGpuWrite=%i, mGpuRead=%i",
322          prefix, mPtr, mCpuWrite, mCpuRead, mGpuWrite, mGpuRead);
323
324    LOGV("%s allocation mIsTexture=%i mTextureID=%i, mIsVertexBuffer=%i, mBufferID=%i",
325          prefix, mIsTexture, mTextureID, mIsVertexBuffer, mBufferID);
326
327}
328
329void Allocation::serialize(OStream *stream) const
330{
331    // Need to identify ourselves
332    stream->addU32((uint32_t)getClassId());
333
334    String8 name(getName());
335    stream->addString(&name);
336
337    // First thing we need to serialize is the type object since it will be needed
338    // to initialize the class
339    mType->serialize(stream);
340
341    uint32_t dataSize = mType->getSizeBytes();
342    // Write how much data we are storing
343    stream->addU32(dataSize);
344    // Now write the data
345    stream->addByteArray(mPtr, dataSize);
346}
347
348Allocation *Allocation::createFromStream(Context *rsc, IStream *stream)
349{
350    // First make sure we are reading the correct object
351    A3DClassID classID = (A3DClassID)stream->loadU32();
352    if(classID != A3D_CLASS_ID_ALLOCATION) {
353        LOGE("allocation loading skipped due to invalid class id\n");
354        return NULL;
355    }
356
357    String8 name;
358    stream->loadString(&name);
359
360    Type *type = Type::createFromStream(rsc, stream);
361    if(!type) {
362        return NULL;
363    }
364    type->compute();
365
366    // Number of bytes we wrote out for this allocation
367    uint32_t dataSize = stream->loadU32();
368    if(dataSize != type->getSizeBytes()) {
369        LOGE("failed to read allocation because numbytes written is not the same loaded type wants\n");
370        delete type;
371        return NULL;
372    }
373
374    Allocation *alloc = new Allocation(rsc, type);
375    alloc->setName(name.string(), name.size());
376
377    // Read in all of our allocation data
378    stream->loadByteArray(alloc->getPtr(), dataSize);
379
380    return alloc;
381}
382
383void Allocation::sendDirty() const
384{
385    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
386        mToDirtyList[ct]->forceDirty();
387    }
388}
389
390/////////////////
391//
392
393
394namespace android {
395namespace renderscript {
396
397RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype)
398{
399    const Type * type = static_cast<const Type *>(vtype);
400
401    Allocation * alloc = new Allocation(rsc, type);
402    alloc->incUserRef();
403    return alloc;
404}
405
406RsAllocation rsi_AllocationCreateSized(Context *rsc, RsElement e, size_t count)
407{
408    Type * type = new Type(rsc);
409    type->setDimX(count);
410    type->setElement(static_cast<Element *>(e));
411    type->compute();
412    return rsi_AllocationCreateTyped(rsc, type);
413}
414
415void rsi_AllocationUploadToTexture(Context *rsc, RsAllocation va, bool genmip, uint32_t baseMipLevel)
416{
417    Allocation *alloc = static_cast<Allocation *>(va);
418    alloc->deferedUploadToTexture(rsc, genmip, baseMipLevel);
419}
420
421void rsi_AllocationUploadToBufferObject(Context *rsc, RsAllocation va)
422{
423    Allocation *alloc = static_cast<Allocation *>(va);
424    alloc->deferedUploadToBufferObject(rsc);
425}
426
427static void mip565(const Adapter2D &out, const Adapter2D &in)
428{
429    uint32_t w = out.getDimX();
430    uint32_t h = out.getDimY();
431
432    for (uint32_t y=0; y < h; y++) {
433        uint16_t *oPtr = static_cast<uint16_t *>(out.getElement(0, y));
434        const uint16_t *i1 = static_cast<uint16_t *>(in.getElement(0, y*2));
435        const uint16_t *i2 = static_cast<uint16_t *>(in.getElement(0, y*2+1));
436
437        for (uint32_t x=0; x < w; x++) {
438            *oPtr = rsBoxFilter565(i1[0], i1[1], i2[0], i2[1]);
439            oPtr ++;
440            i1 += 2;
441            i2 += 2;
442        }
443    }
444}
445
446static void mip8888(const Adapter2D &out, const Adapter2D &in)
447{
448    uint32_t w = out.getDimX();
449    uint32_t h = out.getDimY();
450
451    for (uint32_t y=0; y < h; y++) {
452        uint32_t *oPtr = static_cast<uint32_t *>(out.getElement(0, y));
453        const uint32_t *i1 = static_cast<uint32_t *>(in.getElement(0, y*2));
454        const uint32_t *i2 = static_cast<uint32_t *>(in.getElement(0, y*2+1));
455
456        for (uint32_t x=0; x < w; x++) {
457            *oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]);
458            oPtr ++;
459            i1 += 2;
460            i2 += 2;
461        }
462    }
463}
464
465static void mip8(const Adapter2D &out, const Adapter2D &in)
466{
467    uint32_t w = out.getDimX();
468    uint32_t h = out.getDimY();
469
470    for (uint32_t y=0; y < h; y++) {
471        uint8_t *oPtr = static_cast<uint8_t *>(out.getElement(0, y));
472        const uint8_t *i1 = static_cast<uint8_t *>(in.getElement(0, y*2));
473        const uint8_t *i2 = static_cast<uint8_t *>(in.getElement(0, y*2+1));
474
475        for (uint32_t x=0; x < w; x++) {
476            *oPtr = (uint8_t)(((uint32_t)i1[0] + i1[1] + i2[0] + i2[1]) * 0.25f);
477            oPtr ++;
478            i1 += 2;
479            i2 += 2;
480        }
481    }
482}
483
484static void mip(const Adapter2D &out, const Adapter2D &in)
485{
486    switch(out.getBaseType()->getElement()->getSizeBits()) {
487    case 32:
488        mip8888(out, in);
489        break;
490    case 16:
491        mip565(out, in);
492        break;
493    case 8:
494        mip8(out, in);
495        break;
496
497    }
498
499}
500
501typedef void (*ElementConverter_t)(void *dst, const void *src, uint32_t count);
502
503static void elementConverter_cpy_16(void *dst, const void *src, uint32_t count)
504{
505    memcpy(dst, src, count * 2);
506}
507static void elementConverter_cpy_8(void *dst, const void *src, uint32_t count)
508{
509    memcpy(dst, src, count);
510}
511static void elementConverter_cpy_32(void *dst, const void *src, uint32_t count)
512{
513    memcpy(dst, src, count * 4);
514}
515
516
517static void elementConverter_888_to_565(void *dst, const void *src, uint32_t count)
518{
519    uint16_t *d = static_cast<uint16_t *>(dst);
520    const uint8_t *s = static_cast<const uint8_t *>(src);
521
522    while(count--) {
523        *d = rs888to565(s[0], s[1], s[2]);
524        d++;
525        s+= 3;
526    }
527}
528
529static void elementConverter_8888_to_565(void *dst, const void *src, uint32_t count)
530{
531    uint16_t *d = static_cast<uint16_t *>(dst);
532    const uint8_t *s = static_cast<const uint8_t *>(src);
533
534    while(count--) {
535        *d = rs888to565(s[0], s[1], s[2]);
536        d++;
537        s+= 4;
538    }
539}
540
541static ElementConverter_t pickConverter(const Element *dst, const Element *src)
542{
543    GLenum srcGLType = src->getComponent().getGLType();
544    GLenum srcGLFmt = src->getComponent().getGLFormat();
545    GLenum dstGLType = dst->getComponent().getGLType();
546    GLenum dstGLFmt = dst->getComponent().getGLFormat();
547
548    if (srcGLFmt == dstGLFmt && srcGLType == dstGLType) {
549        switch(dst->getSizeBytes()) {
550        case 4:
551            return elementConverter_cpy_32;
552        case 2:
553            return elementConverter_cpy_16;
554        case 1:
555            return elementConverter_cpy_8;
556        }
557    }
558
559    if (srcGLType == GL_UNSIGNED_BYTE &&
560        srcGLFmt == GL_RGB &&
561        dstGLType == GL_UNSIGNED_SHORT_5_6_5 &&
562        dstGLType == GL_RGB) {
563
564        return elementConverter_888_to_565;
565    }
566
567    if (srcGLType == GL_UNSIGNED_BYTE &&
568        srcGLFmt == GL_RGBA &&
569        dstGLType == GL_UNSIGNED_SHORT_5_6_5 &&
570        dstGLType == GL_RGB) {
571
572        return elementConverter_8888_to_565;
573    }
574
575    LOGE("pickConverter, unsuported combo, src %p,  dst %p", src, dst);
576    return 0;
577}
578
579#ifndef ANDROID_RS_BUILD_FOR_HOST
580
581RsAllocation rsi_AllocationCreateBitmapRef(Context *rsc, RsType vtype,
582                                           void *bmp, void *callbackData, RsBitmapCallback_t callback)
583{
584    const Type * type = static_cast<const Type *>(vtype);
585    Allocation * alloc = new Allocation(rsc, type, bmp, callbackData, callback);
586    alloc->incUserRef();
587    return alloc;
588}
589
590RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h, RsElement _dst, RsElement _src,  bool genMips, const void *data)
591{
592    const Element *src = static_cast<const Element *>(_src);
593    const Element *dst = static_cast<const Element *>(_dst);
594
595    // Check for pow2 on pre es 2.0 versions.
596    rsAssert(rsc->checkVersion2_0() || (!(w & (w-1)) && !(h & (h-1))));
597
598    //LOGE("rsi_AllocationCreateFromBitmap %i %i %i %i %i", w, h, dstFmt, srcFmt, genMips);
599    rsi_TypeBegin(rsc, _dst);
600    rsi_TypeAdd(rsc, RS_DIMENSION_X, w);
601    rsi_TypeAdd(rsc, RS_DIMENSION_Y, h);
602    if (genMips) {
603        rsi_TypeAdd(rsc, RS_DIMENSION_LOD, 1);
604    }
605    RsType type = rsi_TypeCreate(rsc);
606
607    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, type);
608    Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
609    if (texAlloc == NULL) {
610        LOGE("Memory allocation failure");
611        return NULL;
612    }
613
614    ElementConverter_t cvt = pickConverter(dst, src);
615    cvt(texAlloc->getPtr(), data, w * h);
616
617    if (genMips) {
618        Adapter2D adapt(rsc, texAlloc);
619        Adapter2D adapt2(rsc, texAlloc);
620        for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
621            adapt.setLOD(lod);
622            adapt2.setLOD(lod + 1);
623            mip(adapt2, adapt);
624        }
625    }
626
627    return texAlloc;
628}
629
630RsAllocation rsi_AllocationCreateFromBitmapBoxed(Context *rsc, uint32_t w, uint32_t h, RsElement _dst, RsElement _src, bool genMips, const void *data)
631{
632    const Element *srcE = static_cast<const Element *>(_src);
633    const Element *dstE = static_cast<const Element *>(_dst);
634    uint32_t w2 = rsHigherPow2(w);
635    uint32_t h2 = rsHigherPow2(h);
636
637    if ((w2 == w) && (h2 == h)) {
638        return rsi_AllocationCreateFromBitmap(rsc, w, h, _dst, _src, genMips, data);
639    }
640
641    uint32_t bpp = srcE->getSizeBytes();
642    size_t size = w2 * h2 * bpp;
643    uint8_t *tmp = static_cast<uint8_t *>(malloc(size));
644    memset(tmp, 0, size);
645
646    const uint8_t * src = static_cast<const uint8_t *>(data);
647    for (uint32_t y = 0; y < h; y++) {
648        uint8_t * ydst = &tmp[(y + ((h2 - h) >> 1)) * w2 * bpp];
649        memcpy(&ydst[((w2 - w) >> 1) * bpp], src, w * bpp);
650        src += w * bpp;
651    }
652
653    RsAllocation ret = rsi_AllocationCreateFromBitmap(rsc, w2, h2, _dst, _src, genMips, tmp);
654    free(tmp);
655    return ret;
656}
657
658void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data, uint32_t sizeBytes)
659{
660    Allocation *a = static_cast<Allocation *>(va);
661    a->data(data, sizeBytes);
662}
663
664void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes)
665{
666    Allocation *a = static_cast<Allocation *>(va);
667    a->subData(xoff, count, data, sizeBytes);
668}
669
670void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes)
671{
672    Allocation *a = static_cast<Allocation *>(va);
673    a->subData(xoff, yoff, w, h, data, sizeBytes);
674}
675
676void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data)
677{
678    Allocation *a = static_cast<Allocation *>(va);
679    a->read(data);
680}
681
682#endif //ANDROID_RS_BUILD_FOR_HOST
683
684}
685}
686