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