rsAllocation.cpp revision 2f6d8617769b5fd6287404a31d4e10140ebdcf7e
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
17#include "rsContext.h"
18
19#include <GLES/gl.h>
20#include <GLES/glext.h>
21
22using namespace android;
23using namespace android::renderscript;
24
25Allocation::Allocation(Context *rsc, const Type *type) : ObjectBase(rsc)
26{
27    mAllocFile = __FILE__;
28    mAllocLine = __LINE__;
29    mPtr = NULL;
30
31    mCpuWrite = false;
32    mCpuRead = false;
33    mGpuWrite = false;
34    mGpuRead = false;
35
36    mReadWriteRatio = 0;
37    mUpdateSize = 0;
38
39    mIsTexture = false;
40    mTextureID = 0;
41    mIsVertexBuffer = false;
42    mBufferID = 0;
43    mUploadDefered = false;
44
45    mType.set(type);
46    rsAssert(type);
47    mPtr = malloc(mType->getSizeBytes());
48    if (!mPtr) {
49        LOGE("Allocation::Allocation, alloc failure");
50    }
51}
52
53Allocation::~Allocation()
54{
55    free(mPtr);
56    mPtr = NULL;
57
58    if (mBufferID) {
59        // Causes a SW crash....
60        //LOGV(" mBufferID %i", mBufferID);
61        //glDeleteBuffers(1, &mBufferID);
62        //mBufferID = 0;
63    }
64    if (mTextureID) {
65        glDeleteTextures(1, &mTextureID);
66        mTextureID = 0;
67    }
68}
69
70void Allocation::setCpuWritable(bool)
71{
72}
73
74void Allocation::setGpuWritable(bool)
75{
76}
77
78void Allocation::setCpuReadable(bool)
79{
80}
81
82void Allocation::setGpuReadable(bool)
83{
84}
85
86bool Allocation::fixAllocation()
87{
88    return false;
89}
90
91void Allocation::deferedUploadToTexture(const Context *rsc, uint32_t lodOffset)
92{
93    rsAssert(lodOffset < mType->getLODCount());
94    mIsTexture = true;
95    mTextureLOD = lodOffset;
96    mUploadDefered = true;
97}
98
99void Allocation::uploadToTexture(const Context *rsc)
100{
101    //rsAssert(!mTextureId);
102
103    mIsTexture = true;
104    if (!rsc->checkDriver()) {
105        mUploadDefered = true;
106        return;
107    }
108
109    GLenum type = mType->getElement()->getComponent().getGLType();
110    GLenum format = mType->getElement()->getComponent().getGLFormat();
111
112    if (!type || !format) {
113        return;
114    }
115
116    if (!mTextureID) {
117        glGenTextures(1, &mTextureID);
118
119        if (!mTextureID) {
120            // This should not happen, however, its likely the cause of the
121            // white sqare bug.
122            // Force a crash to 1: restart the app, 2: make sure we get a bugreport.
123            LOGE("Upload to texture failed to gen mTextureID");
124            rsc->dumpDebug();
125            mUploadDefered = true;
126            return;
127        }
128    }
129    glBindTexture(GL_TEXTURE_2D, mTextureID);
130    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
131
132    Adapter2D adapt(getContext(), this);
133    for(uint32_t lod = 0; (lod + mTextureLOD) < mType->getLODCount(); lod++) {
134        adapt.setLOD(lod+mTextureLOD);
135
136        uint16_t * ptr = static_cast<uint16_t *>(adapt.getElement(0,0));
137        glTexImage2D(GL_TEXTURE_2D, lod, format,
138                     adapt.getDimX(), adapt.getDimY(),
139                     0, format, type, ptr);
140    }
141}
142
143void Allocation::deferedUploadToBufferObject(const Context *rsc)
144{
145    mIsVertexBuffer = true;
146    mUploadDefered = true;
147}
148
149void Allocation::uploadToBufferObject(const Context *rsc)
150{
151    rsAssert(!mType->getDimY());
152    rsAssert(!mType->getDimZ());
153
154    mIsVertexBuffer = true;
155    if (!rsc->checkDriver()) {
156        mUploadDefered = true;
157        return;
158    }
159
160    if (!mBufferID) {
161        glGenBuffers(1, &mBufferID);
162    }
163    if (!mBufferID) {
164        LOGE("Upload to buffer object failed");
165        mUploadDefered = true;
166        return;
167    }
168
169    glBindBuffer(GL_ARRAY_BUFFER, mBufferID);
170    glBufferData(GL_ARRAY_BUFFER, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW);
171    glBindBuffer(GL_ARRAY_BUFFER, 0);
172}
173
174void Allocation::uploadCheck(const Context *rsc)
175{
176    if (mUploadDefered) {
177        mUploadDefered = false;
178        if (mIsVertexBuffer) {
179            uploadToBufferObject(rsc);
180        }
181        if (mIsTexture) {
182            uploadToTexture(rsc);
183        }
184    }
185}
186
187
188void Allocation::data(const void *data, uint32_t sizeBytes)
189{
190    uint32_t size = mType->getSizeBytes();
191    if (size != sizeBytes) {
192        LOGE("Allocation::data called with mismatched size expected %i, got %i", size, sizeBytes);
193        return;
194    }
195    memcpy(mPtr, data, size);
196    sendDirty();
197    mUploadDefered = true;
198}
199
200void Allocation::read(void *data)
201{
202    memcpy(data, mPtr, mType->getSizeBytes());
203}
204
205void Allocation::subData(uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes)
206{
207    uint32_t eSize = mType->getElementSizeBytes();
208    uint8_t * ptr = static_cast<uint8_t *>(mPtr);
209    ptr += eSize * xoff;
210    uint32_t size = count * eSize;
211
212    if (size != sizeBytes) {
213        LOGE("Allocation::subData called with mismatched size expected %i, got %i", size, sizeBytes);
214        mType->dumpLOGV("type info");
215        return;
216    }
217    memcpy(ptr, data, size);
218    sendDirty();
219    mUploadDefered = true;
220}
221
222void Allocation::subData(uint32_t xoff, uint32_t yoff,
223             uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes)
224{
225    uint32_t eSize = mType->getElementSizeBytes();
226    uint32_t lineSize = eSize * w;
227    uint32_t destW = mType->getDimX();
228
229    const uint8_t *src = static_cast<const uint8_t *>(data);
230    uint8_t *dst = static_cast<uint8_t *>(mPtr);
231    dst += eSize * (xoff + yoff * destW);
232
233    if ((lineSize * eSize * h) != sizeBytes) {
234        rsAssert(!"Allocation::subData called with mismatched size");
235        return;
236    }
237
238    for (uint32_t line=yoff; line < (yoff+h); line++) {
239        uint8_t * ptr = static_cast<uint8_t *>(mPtr);
240        memcpy(dst, src, lineSize);
241        src += lineSize;
242        dst += destW * eSize;
243    }
244    sendDirty();
245    mUploadDefered = true;
246}
247
248void Allocation::subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
249             uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes)
250{
251}
252
253void Allocation::addProgramToDirty(const Program *p)
254{
255    mToDirtyList.add(p);
256}
257
258void Allocation::removeProgramToDirty(const Program *p)
259{
260    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
261        if (mToDirtyList[ct] == p) {
262            mToDirtyList.removeAt(ct);
263            return;
264        }
265    }
266    rsAssert(0);
267}
268
269void Allocation::dumpLOGV(const char *prefix) const
270{
271    ObjectBase::dumpLOGV(prefix);
272
273    String8 s(prefix);
274    s.append(" type ");
275    if (mType.get()) {
276        mType->dumpLOGV(s.string());
277    }
278
279    LOGV("%s allocation ptr=%p mCpuWrite=%i, mCpuRead=%i, mGpuWrite=%i, mGpuRead=%i",
280          prefix, mPtr, mCpuWrite, mCpuRead, mGpuWrite, mGpuRead);
281
282    LOGV("%s allocation mIsTexture=%i mTextureID=%i, mIsVertexBuffer=%i, mBufferID=%i",
283          prefix, mIsTexture, mTextureID, mIsVertexBuffer, mBufferID);
284
285}
286
287void Allocation::sendDirty() const
288{
289    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
290        mToDirtyList[ct]->forceDirty();
291    }
292}
293
294/////////////////
295//
296
297
298namespace android {
299namespace renderscript {
300
301RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype)
302{
303    const Type * type = static_cast<const Type *>(vtype);
304
305    Allocation * alloc = new Allocation(rsc, type);
306    alloc->incUserRef();
307    return alloc;
308}
309
310RsAllocation rsi_AllocationCreateSized(Context *rsc, RsElement e, size_t count)
311{
312    Type * type = new Type(rsc);
313    type->setDimX(count);
314    type->setElement(static_cast<Element *>(e));
315    type->compute();
316    return rsi_AllocationCreateTyped(rsc, type);
317}
318
319void rsi_AllocationUploadToTexture(Context *rsc, RsAllocation va, uint32_t baseMipLevel)
320{
321    Allocation *alloc = static_cast<Allocation *>(va);
322    alloc->deferedUploadToTexture(rsc, baseMipLevel);
323}
324
325void rsi_AllocationUploadToBufferObject(Context *rsc, RsAllocation va)
326{
327    Allocation *alloc = static_cast<Allocation *>(va);
328    alloc->deferedUploadToBufferObject(rsc);
329}
330
331static void mip565(const Adapter2D &out, const Adapter2D &in)
332{
333    uint32_t w = out.getDimX();
334    uint32_t h = out.getDimY();
335
336    for (uint32_t y=0; y < h; y++) {
337        uint16_t *oPtr = static_cast<uint16_t *>(out.getElement(0, y));
338        const uint16_t *i1 = static_cast<uint16_t *>(in.getElement(0, y*2));
339        const uint16_t *i2 = static_cast<uint16_t *>(in.getElement(0, y*2+1));
340
341        for (uint32_t x=0; x < w; x++) {
342            *oPtr = rsBoxFilter565(i1[0], i1[1], i2[0], i2[1]);
343            oPtr ++;
344            i1 += 2;
345            i2 += 2;
346        }
347    }
348}
349
350static void mip8888(const Adapter2D &out, const Adapter2D &in)
351{
352    uint32_t w = out.getDimX();
353    uint32_t h = out.getDimY();
354
355    for (uint32_t y=0; y < h; y++) {
356        uint32_t *oPtr = static_cast<uint32_t *>(out.getElement(0, y));
357        const uint32_t *i1 = static_cast<uint32_t *>(in.getElement(0, y*2));
358        const uint32_t *i2 = static_cast<uint32_t *>(in.getElement(0, y*2+1));
359
360        for (uint32_t x=0; x < w; x++) {
361            *oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]);
362            oPtr ++;
363            i1 += 2;
364            i2 += 2;
365        }
366    }
367}
368
369static void mip8(const Adapter2D &out, const Adapter2D &in)
370{
371    uint32_t w = out.getDimX();
372    uint32_t h = out.getDimY();
373
374    for (uint32_t y=0; y < h; y++) {
375        uint8_t *oPtr = static_cast<uint8_t *>(out.getElement(0, y));
376        const uint8_t *i1 = static_cast<uint8_t *>(in.getElement(0, y*2));
377        const uint8_t *i2 = static_cast<uint8_t *>(in.getElement(0, y*2+1));
378
379        for (uint32_t x=0; x < w; x++) {
380            *oPtr = (uint8_t)(((uint32_t)i1[0] + i1[1] + i2[0] + i2[1]) * 0.25f);
381            oPtr ++;
382            i1 += 2;
383            i2 += 2;
384        }
385    }
386}
387
388static void mip(const Adapter2D &out, const Adapter2D &in)
389{
390    switch(out.getBaseType()->getElement()->getSizeBits()) {
391    case 32:
392        mip8888(out, in);
393        break;
394    case 16:
395        mip565(out, in);
396        break;
397    case 8:
398        mip8(out, in);
399        break;
400
401    }
402
403}
404
405typedef void (*ElementConverter_t)(void *dst, const void *src, uint32_t count);
406
407static void elementConverter_cpy_16(void *dst, const void *src, uint32_t count)
408{
409    memcpy(dst, src, count * 2);
410}
411static void elementConverter_cpy_8(void *dst, const void *src, uint32_t count)
412{
413    memcpy(dst, src, count);
414}
415static void elementConverter_cpy_32(void *dst, const void *src, uint32_t count)
416{
417    memcpy(dst, src, count * 4);
418}
419
420
421static void elementConverter_888_to_565(void *dst, const void *src, uint32_t count)
422{
423    uint16_t *d = static_cast<uint16_t *>(dst);
424    const uint8_t *s = static_cast<const uint8_t *>(src);
425
426    while(count--) {
427        *d = rs888to565(s[0], s[1], s[2]);
428        d++;
429        s+= 3;
430    }
431}
432
433static void elementConverter_8888_to_565(void *dst, const void *src, uint32_t count)
434{
435    uint16_t *d = static_cast<uint16_t *>(dst);
436    const uint8_t *s = static_cast<const uint8_t *>(src);
437
438    while(count--) {
439        *d = rs888to565(s[0], s[1], s[2]);
440        d++;
441        s+= 4;
442    }
443}
444
445static ElementConverter_t pickConverter(const Element *dst, const Element *src)
446{
447    GLenum srcGLType = src->getComponent().getGLType();
448    GLenum srcGLFmt = src->getComponent().getGLFormat();
449    GLenum dstGLType = dst->getComponent().getGLType();
450    GLenum dstGLFmt = dst->getComponent().getGLFormat();
451
452    if (srcGLFmt == dstGLFmt && srcGLType == dstGLType) {
453        switch(dst->getSizeBytes()) {
454        case 4:
455            return elementConverter_cpy_32;
456        case 2:
457            return elementConverter_cpy_16;
458        case 1:
459            return elementConverter_cpy_8;
460        }
461    }
462
463    if (srcGLType == GL_UNSIGNED_BYTE &&
464        srcGLFmt == GL_RGB &&
465        dstGLType == GL_UNSIGNED_SHORT_5_6_5 &&
466        dstGLType == GL_RGB) {
467
468        return elementConverter_888_to_565;
469    }
470
471    if (srcGLType == GL_UNSIGNED_BYTE &&
472        srcGLFmt == GL_RGBA &&
473        dstGLType == GL_UNSIGNED_SHORT_5_6_5 &&
474        dstGLType == GL_RGB) {
475
476        return elementConverter_8888_to_565;
477    }
478
479    LOGE("pickConverter, unsuported combo, src %p,  dst %p", src, dst);
480    return 0;
481}
482
483
484RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h, RsElement _dst, RsElement _src,  bool genMips, const void *data)
485{
486    const Element *src = static_cast<const Element *>(_src);
487    const Element *dst = static_cast<const Element *>(_dst);
488
489    // Check for pow2 on pre es 2.0 versions.
490    rsAssert(rsc->checkVersion2_0() || (!(w & (w-1)) && !(h & (h-1))));
491
492    //LOGE("rsi_AllocationCreateFromBitmap %i %i %i %i %i", w, h, dstFmt, srcFmt, genMips);
493    rsi_TypeBegin(rsc, _dst);
494    rsi_TypeAdd(rsc, RS_DIMENSION_X, w);
495    rsi_TypeAdd(rsc, RS_DIMENSION_Y, h);
496    if (genMips) {
497        rsi_TypeAdd(rsc, RS_DIMENSION_LOD, 1);
498    }
499    RsType type = rsi_TypeCreate(rsc);
500
501    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, type);
502    Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
503    if (texAlloc == NULL) {
504        LOGE("Memory allocation failure");
505        return NULL;
506    }
507
508    ElementConverter_t cvt = pickConverter(dst, src);
509    cvt(texAlloc->getPtr(), data, w * h);
510
511    if (genMips) {
512        Adapter2D adapt(rsc, texAlloc);
513        Adapter2D adapt2(rsc, texAlloc);
514        for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
515            adapt.setLOD(lod);
516            adapt2.setLOD(lod + 1);
517            mip(adapt2, adapt);
518        }
519    }
520
521    return texAlloc;
522}
523
524RsAllocation rsi_AllocationCreateFromBitmapBoxed(Context *rsc, uint32_t w, uint32_t h, RsElement _dst, RsElement _src, bool genMips, const void *data)
525{
526    const Element *srcE = static_cast<const Element *>(_src);
527    const Element *dstE = static_cast<const Element *>(_dst);
528    uint32_t w2 = rsHigherPow2(w);
529    uint32_t h2 = rsHigherPow2(h);
530
531    if ((w2 == w) && (h2 == h)) {
532        return rsi_AllocationCreateFromBitmap(rsc, w, h, _dst, _src, genMips, data);
533    }
534
535    uint32_t bpp = srcE->getSizeBytes();
536    size_t size = w2 * h2 * bpp;
537    uint8_t *tmp = static_cast<uint8_t *>(malloc(size));
538    memset(tmp, 0, size);
539
540    const uint8_t * src = static_cast<const uint8_t *>(data);
541    for (uint32_t y = 0; y < h; y++) {
542        uint8_t * ydst = &tmp[(y + ((h2 - h) >> 1)) * w2 * bpp];
543        memcpy(&ydst[((w2 - w) >> 1) * bpp], src, w * bpp);
544        src += w * bpp;
545    }
546
547    RsAllocation ret = rsi_AllocationCreateFromBitmap(rsc, w2, h2, _dst, _src, genMips, tmp);
548    free(tmp);
549    return ret;
550}
551
552void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data, uint32_t sizeBytes)
553{
554    Allocation *a = static_cast<Allocation *>(va);
555    a->data(data, sizeBytes);
556}
557
558void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes)
559{
560    Allocation *a = static_cast<Allocation *>(va);
561    a->subData(xoff, count, data, sizeBytes);
562}
563
564void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes)
565{
566    Allocation *a = static_cast<Allocation *>(va);
567    a->subData(xoff, yoff, w, h, data, sizeBytes);
568}
569
570void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data)
571{
572    Allocation *a = static_cast<Allocation *>(va);
573    a->read(data);
574}
575
576
577}
578}
579