rsAllocation.cpp revision e6c6078f301a197f310b0ae0c12031188e7c1b6b
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
42    mIsVertexBuffer = false;
43    mBufferID = 0;
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::uploadToTexture(Context *rsc, uint32_t lodOffset)
92{
93    //rsAssert(!mTextureId);
94    rsAssert(lodOffset < mType->getLODCount());
95
96    GLenum type = mType->getElement()->getGLType();
97    GLenum format = mType->getElement()->getGLFormat();
98
99    if (!type || !format) {
100        return;
101    }
102
103    if (!mTextureID) {
104        glGenTextures(1, &mTextureID);
105
106        if (!mTextureID) {
107            // This should not happen, however, its likely the cause of the
108            // white sqare bug.
109            // Force a crash to 1: restart the app, 2: make sure we get a bugreport.
110            LOGE("Upload to texture failed to gen mTextureID");
111            rsc->dumpDebug();
112            ((char *)0)[0] = 0;
113        }
114    }
115    glBindTexture(GL_TEXTURE_2D, mTextureID);
116    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
117
118    Adapter2D adapt(getContext(), this);
119    for(uint32_t lod = 0; (lod + lodOffset) < mType->getLODCount(); lod++) {
120        adapt.setLOD(lod+lodOffset);
121
122        uint16_t * ptr = static_cast<uint16_t *>(adapt.getElement(0,0));
123        glTexImage2D(GL_TEXTURE_2D, lod, format,
124                     adapt.getDimX(), adapt.getDimY(),
125                     0, format, type, ptr);
126    }
127}
128
129void Allocation::uploadToBufferObject()
130{
131    rsAssert(!mType->getDimY());
132    rsAssert(!mType->getDimZ());
133
134    if (!mBufferID) {
135        glGenBuffers(1, &mBufferID);
136    }
137    glBindBuffer(GL_ARRAY_BUFFER, mBufferID);
138    glBufferData(GL_ARRAY_BUFFER, mType->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW);
139    glBindBuffer(GL_ARRAY_BUFFER, 0);
140}
141
142
143void Allocation::data(const void *data, uint32_t sizeBytes)
144{
145    uint32_t size = mType->getSizeBytes();
146    if (size != sizeBytes) {
147        LOGE("Allocation::data called with mismatched size expected %i, got %i", size, sizeBytes);
148        return;
149    }
150    memcpy(mPtr, data, size);
151    sendDirty();
152}
153
154void Allocation::read(void *data)
155{
156    memcpy(data, mPtr, mType->getSizeBytes());
157}
158
159void Allocation::subData(uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes)
160{
161    uint32_t eSize = mType->getElementSizeBytes();
162    uint8_t * ptr = static_cast<uint8_t *>(mPtr);
163    ptr += eSize * xoff;
164    uint32_t size = count * eSize;
165
166    if (size != sizeBytes) {
167        LOGE("Allocation::subData called with mismatched size expected %i, got %i", size, sizeBytes);
168        mType->dumpLOGV("type info");
169        return;
170    }
171    memcpy(ptr, data, size);
172    sendDirty();
173}
174
175void Allocation::subData(uint32_t xoff, uint32_t yoff,
176             uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes)
177{
178    uint32_t eSize = mType->getElementSizeBytes();
179    uint32_t lineSize = eSize * w;
180    uint32_t destW = mType->getDimX();
181
182    const uint8_t *src = static_cast<const uint8_t *>(data);
183    uint8_t *dst = static_cast<uint8_t *>(mPtr);
184    dst += eSize * (xoff + yoff * destW);
185
186    if ((lineSize * eSize * h) != sizeBytes) {
187        rsAssert(!"Allocation::subData called with mismatched size");
188        return;
189    }
190
191    for (uint32_t line=yoff; line < (yoff+h); line++) {
192        uint8_t * ptr = static_cast<uint8_t *>(mPtr);
193        memcpy(dst, src, lineSize);
194        src += lineSize;
195        dst += destW * eSize;
196    }
197    sendDirty();
198}
199
200void Allocation::subData(uint32_t xoff, uint32_t yoff, uint32_t zoff,
201             uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes)
202{
203}
204
205void Allocation::addProgramToDirty(const Program *p)
206{
207    mToDirtyList.add(p);
208}
209
210void Allocation::removeProgramToDirty(const Program *p)
211{
212    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
213        if (mToDirtyList[ct] == p) {
214            mToDirtyList.removeAt(ct);
215            return;
216        }
217    }
218    rsAssert(0);
219}
220
221void Allocation::dumpLOGV(const char *prefix) const
222{
223    ObjectBase::dumpLOGV(prefix);
224
225    String8 s(prefix);
226    s.append(" type ");
227    if (mType.get()) {
228        mType->dumpLOGV(s.string());
229    }
230
231    LOGV("%s allocation ptr=%p mCpuWrite=%i, mCpuRead=%i, mGpuWrite=%i, mGpuRead=%i",
232          prefix, mPtr, mCpuWrite, mCpuRead, mGpuWrite, mGpuRead);
233
234    LOGV("%s allocation mIsTexture=%i mTextureID=%i, mIsVertexBuffer=%i, mBufferID=%i",
235          prefix, mIsTexture, mTextureID, mIsVertexBuffer, mBufferID);
236
237}
238
239void Allocation::sendDirty() const
240{
241    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
242        mToDirtyList[ct]->forceDirty();
243    }
244}
245
246/////////////////
247//
248
249
250namespace android {
251namespace renderscript {
252
253RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype)
254{
255    const Type * type = static_cast<const Type *>(vtype);
256
257    Allocation * alloc = new Allocation(rsc, type);
258    alloc->incUserRef();
259    return alloc;
260}
261
262RsAllocation rsi_AllocationCreateSized(Context *rsc, RsElement e, size_t count)
263{
264    Type * type = new Type(rsc);
265    type->setDimX(count);
266    type->setElement(static_cast<Element *>(e));
267    type->compute();
268    return rsi_AllocationCreateTyped(rsc, type);
269}
270
271void rsi_AllocationUploadToTexture(Context *rsc, RsAllocation va, uint32_t baseMipLevel)
272{
273    Allocation *alloc = static_cast<Allocation *>(va);
274    alloc->uploadToTexture(rsc, baseMipLevel);
275}
276
277void rsi_AllocationUploadToBufferObject(Context *rsc, RsAllocation va)
278{
279    Allocation *alloc = static_cast<Allocation *>(va);
280    alloc->uploadToBufferObject();
281}
282
283static void mip565(const Adapter2D &out, const Adapter2D &in)
284{
285    uint32_t w = out.getDimX();
286    uint32_t h = out.getDimY();
287
288    for (uint32_t y=0; y < h; y++) {
289        uint16_t *oPtr = static_cast<uint16_t *>(out.getElement(0, y));
290        const uint16_t *i1 = static_cast<uint16_t *>(in.getElement(0, y*2));
291        const uint16_t *i2 = static_cast<uint16_t *>(in.getElement(0, y*2+1));
292
293        for (uint32_t x=0; x < w; x++) {
294            *oPtr = rsBoxFilter565(i1[0], i1[1], i2[0], i2[1]);
295            oPtr ++;
296            i1 += 2;
297            i2 += 2;
298        }
299    }
300}
301
302static void mip8888(const Adapter2D &out, const Adapter2D &in)
303{
304    uint32_t w = out.getDimX();
305    uint32_t h = out.getDimY();
306
307    for (uint32_t y=0; y < h; y++) {
308        uint32_t *oPtr = static_cast<uint32_t *>(out.getElement(0, y));
309        const uint32_t *i1 = static_cast<uint32_t *>(in.getElement(0, y*2));
310        const uint32_t *i2 = static_cast<uint32_t *>(in.getElement(0, y*2+1));
311
312        for (uint32_t x=0; x < w; x++) {
313            *oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]);
314            oPtr ++;
315            i1 += 2;
316            i2 += 2;
317        }
318    }
319}
320
321static void mip(const Adapter2D &out, const Adapter2D &in)
322{
323    switch(out.getBaseType()->getElement()->getSizeBits()) {
324    case 32:
325        mip8888(out, in);
326        break;
327    case 16:
328        mip565(out, in);
329        break;
330
331    }
332
333}
334
335typedef void (*ElementConverter_t)(void *dst, const void *src, uint32_t count);
336
337static void elementConverter_cpy_16(void *dst, const void *src, uint32_t count)
338{
339    memcpy(dst, src, count * 2);
340}
341static void elementConverter_cpy_8(void *dst, const void *src, uint32_t count)
342{
343    memcpy(dst, src, count);
344}
345static void elementConverter_cpy_32(void *dst, const void *src, uint32_t count)
346{
347    memcpy(dst, src, count * 4);
348}
349
350
351static void elementConverter_888_to_565(void *dst, const void *src, uint32_t count)
352{
353    uint16_t *d = static_cast<uint16_t *>(dst);
354    const uint8_t *s = static_cast<const uint8_t *>(src);
355
356    while(count--) {
357        *d = rs888to565(s[0], s[1], s[2]);
358        d++;
359        s+= 3;
360    }
361}
362
363static void elementConverter_8888_to_565(void *dst, const void *src, uint32_t count)
364{
365    uint16_t *d = static_cast<uint16_t *>(dst);
366    const uint8_t *s = static_cast<const uint8_t *>(src);
367
368    while(count--) {
369        *d = rs888to565(s[0], s[1], s[2]);
370        d++;
371        s+= 4;
372    }
373}
374
375static ElementConverter_t pickConverter(const Element *dst, const Element *src)
376{
377    GLenum srcGLType = src->getGLType();
378    GLenum srcGLFmt = src->getGLFormat();
379    GLenum dstGLType = dst->getGLType();
380    GLenum dstGLFmt = dst->getGLFormat();
381
382    if (srcGLFmt == dstGLFmt && srcGLType == dstGLType) {
383        switch(dst->getSizeBytes()) {
384        case 4:
385            return elementConverter_cpy_32;
386        case 2:
387            return elementConverter_cpy_16;
388        case 1:
389            return elementConverter_cpy_8;
390        }
391    }
392
393    if (srcGLType == GL_UNSIGNED_BYTE &&
394        srcGLFmt == GL_RGB &&
395        dstGLType == GL_UNSIGNED_SHORT_5_6_5 &&
396        dstGLType == GL_RGB) {
397
398        return elementConverter_888_to_565;
399    }
400
401    if (srcGLType == GL_UNSIGNED_BYTE &&
402        srcGLFmt == GL_RGBA &&
403        dstGLType == GL_UNSIGNED_SHORT_5_6_5 &&
404        dstGLType == GL_RGB) {
405
406        return elementConverter_8888_to_565;
407    }
408
409    LOGE("pickConverter, unsuported combo, src %p,  dst %p", src, dst);
410    return 0;
411}
412
413
414RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, uint32_t w, uint32_t h, RsElement _dst, RsElement _src,  bool genMips, const void *data)
415{
416    const Element *src = static_cast<const Element *>(_src);
417    const Element *dst = static_cast<const Element *>(_dst);
418    rsAssert(!(w & (w-1)));
419    rsAssert(!(h & (h-1)));
420
421    //LOGE("rsi_AllocationCreateFromBitmap %i %i %i %i %i", w, h, dstFmt, srcFmt, genMips);
422    rsi_TypeBegin(rsc, _dst);
423    rsi_TypeAdd(rsc, RS_DIMENSION_X, w);
424    rsi_TypeAdd(rsc, RS_DIMENSION_Y, h);
425    if (genMips) {
426        rsi_TypeAdd(rsc, RS_DIMENSION_LOD, 1);
427    }
428    RsType type = rsi_TypeCreate(rsc);
429
430    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, type);
431    Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
432    if (texAlloc == NULL) {
433        LOGE("Memory allocation failure");
434        return NULL;
435    }
436
437    ElementConverter_t cvt = pickConverter(dst, src);
438    cvt(texAlloc->getPtr(), data, w * h);
439
440    if (genMips) {
441        Adapter2D adapt(rsc, texAlloc);
442        Adapter2D adapt2(rsc, texAlloc);
443        for(uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
444            adapt.setLOD(lod);
445            adapt2.setLOD(lod + 1);
446            mip(adapt2, adapt);
447        }
448    }
449
450    return texAlloc;
451}
452
453RsAllocation rsi_AllocationCreateFromBitmapBoxed(Context *rsc, uint32_t w, uint32_t h, RsElement _dst, RsElement _src, bool genMips, const void *data)
454{
455    const Element *srcE = static_cast<const Element *>(_src);
456    const Element *dstE = static_cast<const Element *>(_dst);
457    uint32_t w2 = rsHigherPow2(w);
458    uint32_t h2 = rsHigherPow2(h);
459
460    if ((w2 == w) && (h2 == h)) {
461        return rsi_AllocationCreateFromBitmap(rsc, w, h, _dst, _src, genMips, data);
462    }
463
464    uint32_t bpp = srcE->getSizeBytes();
465    size_t size = w2 * h2 * bpp;
466    uint8_t *tmp = static_cast<uint8_t *>(malloc(size));
467    memset(tmp, 0, size);
468
469    const uint8_t * src = static_cast<const uint8_t *>(data);
470    for (uint32_t y = 0; y < h; y++) {
471        uint8_t * ydst = &tmp[(y + ((h2 - h) >> 1)) * w2 * bpp];
472        memcpy(&ydst[((w2 - w) >> 1) * bpp], src, w * bpp);
473        src += w * bpp;
474    }
475
476    RsAllocation ret = rsi_AllocationCreateFromBitmap(rsc, w2, h2, _dst, _src, genMips, tmp);
477    free(tmp);
478    return ret;
479}
480
481void rsi_AllocationData(Context *rsc, RsAllocation va, const void *data, uint32_t sizeBytes)
482{
483    Allocation *a = static_cast<Allocation *>(va);
484    a->data(data, sizeBytes);
485}
486
487void rsi_Allocation1DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t count, const void *data, uint32_t sizeBytes)
488{
489    Allocation *a = static_cast<Allocation *>(va);
490    a->subData(xoff, count, data, sizeBytes);
491}
492
493void rsi_Allocation2DSubData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes)
494{
495    Allocation *a = static_cast<Allocation *>(va);
496    a->subData(xoff, yoff, w, h, data, sizeBytes);
497}
498
499void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data)
500{
501    Allocation *a = static_cast<Allocation *>(va);
502    a->read(data);
503}
504
505
506}
507}
508