rsAllocation.cpp revision cf4c7c9b2f513be77a5b9853319ca82ac2b128ed
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()->getGLType();
110    GLenum format = mType->getElement()->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 mip(const Adapter2D &out, const Adapter2D &in)
370{
371    switch(out.getBaseType()->getElement()->getSizeBits()) {
372    case 32:
373        mip8888(out, in);
374        break;
375    case 16:
376        mip565(out, in);
377        break;
378
379    }
380
381}
382
383typedef void (*ElementConverter_t)(void *dst, const void *src, uint32_t count);
384
385static void elementConverter_cpy_16(void *dst, const void *src, uint32_t count)
386{
387    memcpy(dst, src, count * 2);
388}
389static void elementConverter_cpy_8(void *dst, const void *src, uint32_t count)
390{
391    memcpy(dst, src, count);
392}
393static void elementConverter_cpy_32(void *dst, const void *src, uint32_t count)
394{
395    memcpy(dst, src, count * 4);
396}
397
398
399static void elementConverter_888_to_565(void *dst, const void *src, uint32_t count)
400{
401    uint16_t *d = static_cast<uint16_t *>(dst);
402    const uint8_t *s = static_cast<const uint8_t *>(src);
403
404    while(count--) {
405        *d = rs888to565(s[0], s[1], s[2]);
406        d++;
407        s+= 3;
408    }
409}
410
411static void elementConverter_8888_to_565(void *dst, const void *src, uint32_t count)
412{
413    uint16_t *d = static_cast<uint16_t *>(dst);
414    const uint8_t *s = static_cast<const uint8_t *>(src);
415
416    while(count--) {
417        *d = rs888to565(s[0], s[1], s[2]);
418        d++;
419        s+= 4;
420    }
421}
422
423static ElementConverter_t pickConverter(const Element *dst, const Element *src)
424{
425    GLenum srcGLType = src->getGLType();
426    GLenum srcGLFmt = src->getGLFormat();
427    GLenum dstGLType = dst->getGLType();
428    GLenum dstGLFmt = dst->getGLFormat();
429
430    if (srcGLFmt == dstGLFmt && srcGLType == dstGLType) {
431        switch(dst->getSizeBytes()) {
432        case 4:
433            return elementConverter_cpy_32;
434        case 2:
435            return elementConverter_cpy_16;
436        case 1:
437            return elementConverter_cpy_8;
438        }
439    }
440
441    if (srcGLType == GL_UNSIGNED_BYTE &&
442        srcGLFmt == GL_RGB &&
443        dstGLType == GL_UNSIGNED_SHORT_5_6_5 &&
444        dstGLType == GL_RGB) {
445
446        return elementConverter_888_to_565;
447    }
448
449    if (srcGLType == GL_UNSIGNED_BYTE &&
450        srcGLFmt == GL_RGBA &&
451        dstGLType == GL_UNSIGNED_SHORT_5_6_5 &&
452        dstGLType == GL_RGB) {
453
454        return elementConverter_8888_to_565;
455    }
456
457    LOGE("pickConverter, unsuported combo, src %p,  dst %p", src, dst);
458    return 0;
459}
460
461
462RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h, RsElement _dst, RsElement _src,  bool genMips, const void *data)
463{
464    const Element *src = static_cast<const Element *>(_src);
465    const Element *dst = static_cast<const Element *>(_dst);
466    rsAssert(!(w & (w-1)));
467    rsAssert(!(h & (h-1)));
468
469    //LOGE("rsi_AllocationCreateFromBitmap %i %i %i %i %i", w, h, dstFmt, srcFmt, genMips);
470    rsi_TypeBegin(rsc, _dst);
471    rsi_TypeAdd(rsc, RS_DIMENSION_X, w);
472    rsi_TypeAdd(rsc, RS_DIMENSION_Y, h);
473    if (genMips) {
474        rsi_TypeAdd(rsc, RS_DIMENSION_LOD, 1);
475    }
476    RsType type = rsi_TypeCreate(rsc);
477
478    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, type);
479    Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
480    if (texAlloc == NULL) {
481        LOGE("Memory allocation failure");
482        return NULL;
483    }
484
485    ElementConverter_t cvt = pickConverter(dst, src);
486    cvt(texAlloc->getPtr(), data, w * h);
487
488    if (genMips) {
489        Adapter2D adapt(rsc, texAlloc);
490        Adapter2D adapt2(rsc, texAlloc);
491        for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
492            adapt.setLOD(lod);
493            adapt2.setLOD(lod + 1);
494            mip(adapt2, adapt);
495        }
496    }
497
498    return texAlloc;
499}
500
501RsAllocation rsi_AllocationCreateFromBitmapBoxed(Context *rsc, uint32_t w, uint32_t h, RsElement _dst, RsElement _src, bool genMips, const void *data)
502{
503    const Element *srcE = static_cast<const Element *>(_src);
504    const Element *dstE = static_cast<const Element *>(_dst);
505    uint32_t w2 = rsHigherPow2(w);
506    uint32_t h2 = rsHigherPow2(h);
507
508    if ((w2 == w) && (h2 == h)) {
509        return rsi_AllocationCreateFromBitmap(rsc, w, h, _dst, _src, genMips, data);
510    }
511
512    uint32_t bpp = srcE->getSizeBytes();
513    size_t size = w2 * h2 * bpp;
514    uint8_t *tmp = static_cast<uint8_t *>(malloc(size));
515    memset(tmp, 0, size);
516
517    const uint8_t * src = static_cast<const uint8_t *>(data);
518    for (uint32_t y = 0; y < h; y++) {
519        uint8_t * ydst = &tmp[(y + ((h2 - h) >> 1)) * w2 * bpp];
520        memcpy(&ydst[((w2 - w) >> 1) * bpp], src, w * bpp);
521        src += w * bpp;
522    }
523
524    RsAllocation ret = rsi_AllocationCreateFromBitmap(rsc, w2, h2, _dst, _src, genMips, tmp);
525    free(tmp);
526    return ret;
527}
528
529void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data, uint32_t sizeBytes)
530{
531    Allocation *a = static_cast<Allocation *>(va);
532    a->data(data, sizeBytes);
533}
534
535void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes)
536{
537    Allocation *a = static_cast<Allocation *>(va);
538    a->subData(xoff, count, data, sizeBytes);
539}
540
541void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes)
542{
543    Allocation *a = static_cast<Allocation *>(va);
544    a->subData(xoff, yoff, w, h, data, sizeBytes);
545}
546
547void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data)
548{
549    Allocation *a = static_cast<Allocation *>(va);
550    a->read(data);
551}
552
553
554}
555}
556