rsdAllocation.cpp revision 099bc262f862cdeb547cf8a78fe9e0e92560f437
1/*
2 * Copyright (C) 2013 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 "rsdCore.h"
18#include "rsdAllocation.h"
19
20#include "rsAllocation.h"
21
22#ifndef RS_SERVER
23#include "system/window.h"
24#include "ui/Rect.h"
25#include "ui/GraphicBufferMapper.h"
26#endif
27
28#ifndef RS_COMPATIBILITY_LIB
29#include "rsdFrameBufferObj.h"
30#include "gui/GLConsumer.h"
31#include "gui/CpuConsumer.h"
32#include "gui/Surface.h"
33#include "hardware/gralloc.h"
34
35#include <GLES/gl.h>
36#include <GLES2/gl2.h>
37#include <GLES/glext.h>
38#endif
39
40#ifdef RS_SERVER
41// server requires malloc.h for memalign
42#include <malloc.h>
43#endif
44
45using namespace android;
46using namespace android::renderscript;
47
48
49#ifndef RS_COMPATIBILITY_LIB
50const static GLenum gFaceOrder[] = {
51    GL_TEXTURE_CUBE_MAP_POSITIVE_X,
52    GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
53    GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
54    GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
55    GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
56    GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
57};
58
59GLenum rsdTypeToGLType(RsDataType t) {
60    switch (t) {
61    case RS_TYPE_UNSIGNED_5_6_5:    return GL_UNSIGNED_SHORT_5_6_5;
62    case RS_TYPE_UNSIGNED_5_5_5_1:  return GL_UNSIGNED_SHORT_5_5_5_1;
63    case RS_TYPE_UNSIGNED_4_4_4_4:  return GL_UNSIGNED_SHORT_4_4_4_4;
64
65    //case RS_TYPE_FLOAT_16:      return GL_HALF_FLOAT;
66    case RS_TYPE_FLOAT_32:      return GL_FLOAT;
67    case RS_TYPE_UNSIGNED_8:    return GL_UNSIGNED_BYTE;
68    case RS_TYPE_UNSIGNED_16:   return GL_UNSIGNED_SHORT;
69    case RS_TYPE_SIGNED_8:      return GL_BYTE;
70    case RS_TYPE_SIGNED_16:     return GL_SHORT;
71    default:    break;
72    }
73    return 0;
74}
75
76GLenum rsdKindToGLFormat(RsDataKind k) {
77    switch (k) {
78    case RS_KIND_PIXEL_L: return GL_LUMINANCE;
79    case RS_KIND_PIXEL_A: return GL_ALPHA;
80    case RS_KIND_PIXEL_LA: return GL_LUMINANCE_ALPHA;
81    case RS_KIND_PIXEL_RGB: return GL_RGB;
82    case RS_KIND_PIXEL_RGBA: return GL_RGBA;
83    case RS_KIND_PIXEL_DEPTH: return GL_DEPTH_COMPONENT16;
84    default: break;
85    }
86    return 0;
87}
88#endif
89
90uint8_t *GetOffsetPtr(const android::renderscript::Allocation *alloc,
91                      uint32_t xoff, uint32_t yoff, uint32_t lod,
92                      RsAllocationCubemapFace face) {
93    uint8_t *ptr = (uint8_t *)alloc->mHal.drvState.lod[lod].mallocPtr;
94    ptr += face * alloc->mHal.drvState.faceOffset;
95    ptr += yoff * alloc->mHal.drvState.lod[lod].stride;
96    ptr += xoff * alloc->mHal.state.elementSizeBytes;
97    return ptr;
98}
99
100
101static void Update2DTexture(const Context *rsc, const Allocation *alloc, const void *ptr,
102                            uint32_t xoff, uint32_t yoff, uint32_t lod,
103                            RsAllocationCubemapFace face, uint32_t w, uint32_t h) {
104#ifndef RS_COMPATIBILITY_LIB
105    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
106
107    rsAssert(drv->textureID);
108    RSD_CALL_GL(glBindTexture, drv->glTarget, drv->textureID);
109    RSD_CALL_GL(glPixelStorei, GL_UNPACK_ALIGNMENT, 1);
110    GLenum t = GL_TEXTURE_2D;
111    if (alloc->mHal.state.hasFaces) {
112        t = gFaceOrder[face];
113    }
114    RSD_CALL_GL(glTexSubImage2D, t, lod, xoff, yoff, w, h, drv->glFormat, drv->glType, ptr);
115#endif
116}
117
118
119#ifndef RS_COMPATIBILITY_LIB
120static void Upload2DTexture(const Context *rsc, const Allocation *alloc, bool isFirstUpload) {
121    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
122
123    RSD_CALL_GL(glBindTexture, drv->glTarget, drv->textureID);
124    RSD_CALL_GL(glPixelStorei, GL_UNPACK_ALIGNMENT, 1);
125
126    uint32_t faceCount = 1;
127    if (alloc->mHal.state.hasFaces) {
128        faceCount = 6;
129    }
130
131    rsdGLCheckError(rsc, "Upload2DTexture 1 ");
132    for (uint32_t face = 0; face < faceCount; face ++) {
133        for (uint32_t lod = 0; lod < alloc->mHal.state.type->getLODCount(); lod++) {
134            const uint8_t *p = GetOffsetPtr(alloc, 0, 0, lod, (RsAllocationCubemapFace)face);
135
136            GLenum t = GL_TEXTURE_2D;
137            if (alloc->mHal.state.hasFaces) {
138                t = gFaceOrder[face];
139            }
140
141            if (isFirstUpload) {
142                RSD_CALL_GL(glTexImage2D, t, lod, drv->glFormat,
143                             alloc->mHal.state.type->getLODDimX(lod),
144                             alloc->mHal.state.type->getLODDimY(lod),
145                             0, drv->glFormat, drv->glType, p);
146            } else {
147                RSD_CALL_GL(glTexSubImage2D, t, lod, 0, 0,
148                                alloc->mHal.state.type->getLODDimX(lod),
149                                alloc->mHal.state.type->getLODDimY(lod),
150                                drv->glFormat, drv->glType, p);
151            }
152        }
153    }
154
155    if (alloc->mHal.state.mipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) {
156        RSD_CALL_GL(glGenerateMipmap, drv->glTarget);
157    }
158    rsdGLCheckError(rsc, "Upload2DTexture");
159}
160#endif
161
162static void UploadToTexture(const Context *rsc, const Allocation *alloc) {
163#ifndef RS_COMPATIBILITY_LIB
164    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
165
166    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_INPUT) {
167        if (!drv->textureID) {
168            RSD_CALL_GL(glGenTextures, 1, &drv->textureID);
169        }
170        return;
171    }
172
173    if (!drv->glType || !drv->glFormat) {
174        return;
175    }
176
177    if (!alloc->mHal.drvState.lod[0].mallocPtr) {
178        return;
179    }
180
181    bool isFirstUpload = false;
182
183    if (!drv->textureID) {
184        RSD_CALL_GL(glGenTextures, 1, &drv->textureID);
185        isFirstUpload = true;
186    }
187
188    Upload2DTexture(rsc, alloc, isFirstUpload);
189
190    if (!(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) {
191        if (alloc->mHal.drvState.lod[0].mallocPtr) {
192            free(alloc->mHal.drvState.lod[0].mallocPtr);
193            alloc->mHal.drvState.lod[0].mallocPtr = NULL;
194        }
195    }
196    rsdGLCheckError(rsc, "UploadToTexture");
197#endif
198}
199
200static void AllocateRenderTarget(const Context *rsc, const Allocation *alloc) {
201#ifndef RS_COMPATIBILITY_LIB
202    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
203
204    if (!drv->glFormat) {
205        return;
206    }
207
208    if (!drv->renderTargetID) {
209        RSD_CALL_GL(glGenRenderbuffers, 1, &drv->renderTargetID);
210
211        if (!drv->renderTargetID) {
212            // This should generally not happen
213            ALOGE("allocateRenderTarget failed to gen mRenderTargetID");
214            rsc->dumpDebug();
215            return;
216        }
217        RSD_CALL_GL(glBindRenderbuffer, GL_RENDERBUFFER, drv->renderTargetID);
218        RSD_CALL_GL(glRenderbufferStorage, GL_RENDERBUFFER, drv->glFormat,
219                    alloc->mHal.drvState.lod[0].dimX, alloc->mHal.drvState.lod[0].dimY);
220    }
221    rsdGLCheckError(rsc, "AllocateRenderTarget");
222#endif
223}
224
225static void UploadToBufferObject(const Context *rsc, const Allocation *alloc) {
226#ifndef RS_COMPATIBILITY_LIB
227    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
228
229    rsAssert(!alloc->mHal.state.type->getDimY());
230    rsAssert(!alloc->mHal.state.type->getDimZ());
231
232    //alloc->mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX;
233
234    if (!drv->bufferID) {
235        RSD_CALL_GL(glGenBuffers, 1, &drv->bufferID);
236    }
237    if (!drv->bufferID) {
238        ALOGE("Upload to buffer object failed");
239        drv->uploadDeferred = true;
240        return;
241    }
242    RSD_CALL_GL(glBindBuffer, drv->glTarget, drv->bufferID);
243    RSD_CALL_GL(glBufferData, drv->glTarget, alloc->mHal.state.type->getSizeBytes(),
244                 alloc->mHal.drvState.lod[0].mallocPtr, GL_DYNAMIC_DRAW);
245    RSD_CALL_GL(glBindBuffer, drv->glTarget, 0);
246    rsdGLCheckError(rsc, "UploadToBufferObject");
247#endif
248}
249
250
251static size_t DeriveYUVLayout(int yuv, Allocation::Hal::DrvState *state) {
252    // YUV only supports basic 2d
253    // so we can stash the plane pointers in the mipmap levels.
254    size_t uvSize = 0;
255#ifndef RS_SERVER
256    switch(yuv) {
257    case HAL_PIXEL_FORMAT_YV12:
258        state->lod[1].dimX = state->lod[0].dimX / 2;
259        state->lod[1].dimY = state->lod[0].dimY / 2;
260        state->lod[1].stride = rsRound(state->lod[0].stride >> 1, 16);
261        state->lod[1].mallocPtr = ((uint8_t *)state->lod[0].mallocPtr) +
262                (state->lod[0].stride * state->lod[0].dimY);
263        uvSize += state->lod[1].stride * state->lod[1].dimY;
264
265        state->lod[2].dimX = state->lod[1].dimX;
266        state->lod[2].dimY = state->lod[1].dimY;
267        state->lod[2].stride = state->lod[1].stride;
268        state->lod[2].mallocPtr = ((uint8_t *)state->lod[1].mallocPtr) +
269                (state->lod[1].stride * state->lod[1].dimY);
270        uvSize += state->lod[2].stride * state->lod[2].dimY;
271
272        state->lodCount = 3;
273        break;
274    case HAL_PIXEL_FORMAT_YCrCb_420_SP:  // NV21
275        state->lod[1].dimX = state->lod[0].dimX;
276        state->lod[1].dimY = state->lod[0].dimY / 2;
277        state->lod[1].stride = state->lod[0].stride;
278        state->lod[1].mallocPtr = ((uint8_t *)state->lod[0].mallocPtr) +
279                (state->lod[0].stride * state->lod[0].dimY);
280        uvSize += state->lod[1].stride * state->lod[1].dimY;
281        state->lodCount = 2;
282        break;
283    default:
284        rsAssert(0);
285    }
286#endif
287    return uvSize;
288}
289
290
291static size_t AllocationBuildPointerTable(const Context *rsc, const Allocation *alloc,
292        const Type *type, uint8_t *ptr) {
293    alloc->mHal.drvState.lod[0].dimX = type->getDimX();
294    alloc->mHal.drvState.lod[0].dimY = type->getDimY();
295    alloc->mHal.drvState.lod[0].dimZ = type->getDimZ();
296    alloc->mHal.drvState.lod[0].mallocPtr = 0;
297    // Stride needs to be 16-byte aligned too!
298    size_t stride = alloc->mHal.drvState.lod[0].dimX * type->getElementSizeBytes();
299    alloc->mHal.drvState.lod[0].stride = rsRound(stride, 16);
300    alloc->mHal.drvState.lodCount = type->getLODCount();
301    alloc->mHal.drvState.faceCount = type->getDimFaces();
302
303    size_t offsets[Allocation::MAX_LOD];
304    memset(offsets, 0, sizeof(offsets));
305
306    size_t o = alloc->mHal.drvState.lod[0].stride * rsMax(alloc->mHal.drvState.lod[0].dimY, 1u) *
307            rsMax(alloc->mHal.drvState.lod[0].dimZ, 1u);
308    if(alloc->mHal.drvState.lodCount > 1) {
309        uint32_t tx = alloc->mHal.drvState.lod[0].dimX;
310        uint32_t ty = alloc->mHal.drvState.lod[0].dimY;
311        uint32_t tz = alloc->mHal.drvState.lod[0].dimZ;
312        for (uint32_t lod=1; lod < alloc->mHal.drvState.lodCount; lod++) {
313            alloc->mHal.drvState.lod[lod].dimX = tx;
314            alloc->mHal.drvState.lod[lod].dimY = ty;
315            alloc->mHal.drvState.lod[lod].dimZ = tz;
316            alloc->mHal.drvState.lod[lod].stride =
317                    rsRound(tx * type->getElementSizeBytes(), 16);
318            offsets[lod] = o;
319            o += alloc->mHal.drvState.lod[lod].stride * rsMax(ty, 1u) * rsMax(tz, 1u);
320            if (tx > 1) tx >>= 1;
321            if (ty > 1) ty >>= 1;
322            if (tz > 1) tz >>= 1;
323        }
324    } else if (alloc->mHal.state.yuv) {
325        o += DeriveYUVLayout(alloc->mHal.state.yuv, &alloc->mHal.drvState);
326
327        for (uint32_t ct = 1; ct < alloc->mHal.drvState.lodCount; ct++) {
328            offsets[ct] = (size_t)alloc->mHal.drvState.lod[ct].mallocPtr;
329        }
330    }
331
332    alloc->mHal.drvState.faceOffset = o;
333
334    alloc->mHal.drvState.lod[0].mallocPtr = ptr;
335    for (uint32_t lod=1; lod < alloc->mHal.drvState.lodCount; lod++) {
336        alloc->mHal.drvState.lod[lod].mallocPtr = ptr + offsets[lod];
337    }
338
339    size_t allocSize = alloc->mHal.drvState.faceOffset;
340    if(alloc->mHal.drvState.faceCount) {
341        allocSize *= 6;
342    }
343
344    return allocSize;
345}
346
347static uint8_t* allocAlignedMemory(size_t allocSize, bool forceZero) {
348    // We align all allocations to a 16-byte boundary.
349    uint8_t* ptr = (uint8_t *)memalign(16, allocSize);
350    if (!ptr) {
351        return NULL;
352    }
353    if (forceZero) {
354        memset(ptr, 0, allocSize);
355    }
356    return ptr;
357}
358
359bool rsdAllocationInit(const Context *rsc, Allocation *alloc, bool forceZero) {
360    DrvAllocation *drv = (DrvAllocation *)calloc(1, sizeof(DrvAllocation));
361    if (!drv) {
362        return false;
363    }
364    alloc->mHal.drv = drv;
365
366    // Calculate the object size.
367    size_t allocSize = AllocationBuildPointerTable(rsc, alloc, alloc->getType(), NULL);
368
369    uint8_t * ptr = NULL;
370    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_OUTPUT) {
371
372    } else if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_INPUT) {
373        // Allocation is allocated when the surface is created
374        // in getSurface
375    } else if (alloc->mHal.state.userProvidedPtr != NULL) {
376        // user-provided allocation
377        // limitations: no faces, no LOD, USAGE_SCRIPT only
378        if (alloc->mHal.state.usageFlags != (RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED)) {
379            ALOGE("Can't use user-allocated buffers if usage is not USAGE_SCRIPT and USAGE_SHARED");
380            return false;
381        }
382        if (alloc->getType()->getDimLOD() || alloc->getType()->getDimFaces()) {
383            ALOGE("User-allocated buffers must not have multiple faces or LODs");
384            return false;
385        }
386
387        // rows must be 16-byte aligned
388        // validate that here, otherwise fall back to not use the user-backed allocation
389        if (((alloc->getType()->getDimX() * alloc->getType()->getElement()->getSizeBytes()) % 16) != 0) {
390            ALOGV("User-backed allocation failed stride requirement, falling back to separate allocation");
391            drv->useUserProvidedPtr = false;
392
393            ptr = allocAlignedMemory(allocSize, forceZero);
394            if (!ptr) {
395                alloc->mHal.drv = NULL;
396                free(drv);
397                return false;
398            }
399
400        } else {
401            drv->useUserProvidedPtr = true;
402            ptr = (uint8_t*)alloc->mHal.state.userProvidedPtr;
403        }
404    } else {
405        ptr = allocAlignedMemory(allocSize, forceZero);
406        if (!ptr) {
407            alloc->mHal.drv = NULL;
408            free(drv);
409            return false;
410        }
411    }
412    // Build the pointer tables
413    size_t verifySize = AllocationBuildPointerTable(rsc, alloc, alloc->getType(), ptr);
414    if(allocSize != verifySize) {
415        rsAssert(!"Size mismatch");
416    }
417
418#ifndef RS_SERVER
419    drv->glTarget = GL_NONE;
420    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) {
421        if (alloc->mHal.state.hasFaces) {
422            drv->glTarget = GL_TEXTURE_CUBE_MAP;
423        } else {
424            drv->glTarget = GL_TEXTURE_2D;
425        }
426    } else {
427        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) {
428            drv->glTarget = GL_ARRAY_BUFFER;
429        }
430    }
431#endif
432
433#ifndef RS_COMPATIBILITY_LIB
434    drv->glType = rsdTypeToGLType(alloc->mHal.state.type->getElement()->getComponent().getType());
435    drv->glFormat = rsdKindToGLFormat(alloc->mHal.state.type->getElement()->getComponent().getKind());
436#else
437    drv->glType = 0;
438    drv->glFormat = 0;
439#endif
440
441    if (alloc->mHal.state.usageFlags & ~RS_ALLOCATION_USAGE_SCRIPT) {
442        drv->uploadDeferred = true;
443    }
444
445
446    drv->readBackFBO = NULL;
447
448    // fill out the initial state of the buffer if we couldn't use the user-provided ptr and USAGE_SHARED was accepted
449    if ((alloc->mHal.state.userProvidedPtr != 0) && (drv->useUserProvidedPtr == false)) {
450        rsdAllocationData2D(rsc, alloc, 0, 0, 0, RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, alloc->getType()->getDimX(), alloc->getType()->getDimY(), alloc->mHal.state.userProvidedPtr, allocSize, 0);
451    }
452
453    return true;
454}
455
456void rsdAllocationDestroy(const Context *rsc, Allocation *alloc) {
457    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
458
459#ifndef RS_COMPATIBILITY_LIB
460    if (drv->bufferID) {
461        // Causes a SW crash....
462        //ALOGV(" mBufferID %i", mBufferID);
463        //glDeleteBuffers(1, &mBufferID);
464        //mBufferID = 0;
465    }
466    if (drv->textureID) {
467        RSD_CALL_GL(glDeleteTextures, 1, &drv->textureID);
468        drv->textureID = 0;
469    }
470    if (drv->renderTargetID) {
471        RSD_CALL_GL(glDeleteRenderbuffers, 1, &drv->renderTargetID);
472        drv->renderTargetID = 0;
473    }
474#endif
475
476    if (alloc->mHal.drvState.lod[0].mallocPtr) {
477        // don't free user-allocated ptrs
478        if (!(drv->useUserProvidedPtr)) {
479            free(alloc->mHal.drvState.lod[0].mallocPtr);
480        }
481        alloc->mHal.drvState.lod[0].mallocPtr = NULL;
482    }
483
484#ifndef RS_COMPATIBILITY_LIB
485    if (drv->readBackFBO != NULL) {
486        delete drv->readBackFBO;
487        drv->readBackFBO = NULL;
488    }
489
490    if ((alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_OUTPUT) &&
491        (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) {
492
493        DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
494        ANativeWindow *nw = drv->wndSurface;
495        if (nw) {
496            GraphicBufferMapper &mapper = GraphicBufferMapper::get();
497            mapper.unlock(drv->wndBuffer->handle);
498            int32_t r = nw->queueBuffer(nw, drv->wndBuffer, -1);
499        }
500    }
501#endif
502
503    free(drv);
504    alloc->mHal.drv = NULL;
505}
506
507void rsdAllocationResize(const Context *rsc, const Allocation *alloc,
508                         const Type *newType, bool zeroNew) {
509    const uint32_t oldDimX = alloc->mHal.drvState.lod[0].dimX;
510    const uint32_t dimX = newType->getDimX();
511
512    // can't resize Allocations with user-allocated buffers
513    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SHARED) {
514        ALOGE("Resize cannot be called on a USAGE_SHARED allocation");
515        return;
516    }
517    void * oldPtr = alloc->mHal.drvState.lod[0].mallocPtr;
518    // Calculate the object size
519    size_t s = AllocationBuildPointerTable(rsc, alloc, newType, NULL);
520    uint8_t *ptr = (uint8_t *)realloc(oldPtr, s);
521    // Build the relative pointer tables.
522    size_t verifySize = AllocationBuildPointerTable(rsc, alloc, newType, ptr);
523    if(s != verifySize) {
524        rsAssert(!"Size mismatch");
525    }
526
527
528    if (dimX > oldDimX) {
529        size_t stride = alloc->mHal.state.elementSizeBytes;
530        memset(((uint8_t *)alloc->mHal.drvState.lod[0].mallocPtr) + stride * oldDimX,
531                 0, stride * (dimX - oldDimX));
532    }
533}
534
535static void rsdAllocationSyncFromFBO(const Context *rsc, const Allocation *alloc) {
536#ifndef RS_COMPATIBILITY_LIB
537    if (!alloc->getIsScript()) {
538        return; // nothing to sync
539    }
540
541    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
542    RsdFrameBufferObj *lastFbo = dc->gl.currentFrameBuffer;
543
544    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
545    if (!drv->textureID && !drv->renderTargetID) {
546        return; // nothing was rendered here yet, so nothing to sync
547    }
548    if (drv->readBackFBO == NULL) {
549        drv->readBackFBO = new RsdFrameBufferObj();
550        drv->readBackFBO->setColorTarget(drv, 0);
551        drv->readBackFBO->setDimensions(alloc->getType()->getDimX(),
552                                        alloc->getType()->getDimY());
553    }
554
555    // Bind the framebuffer object so we can read back from it
556    drv->readBackFBO->setActive(rsc);
557
558    // Do the readback
559    RSD_CALL_GL(glReadPixels, 0, 0, alloc->mHal.drvState.lod[0].dimX,
560                alloc->mHal.drvState.lod[0].dimY,
561                drv->glFormat, drv->glType, alloc->mHal.drvState.lod[0].mallocPtr);
562
563    // Revert framebuffer to its original
564    lastFbo->setActive(rsc);
565#endif
566}
567
568
569void rsdAllocationSyncAll(const Context *rsc, const Allocation *alloc,
570                         RsAllocationUsageType src) {
571    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
572
573    if (src == RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
574        if(!alloc->getIsRenderTarget()) {
575            rsc->setError(RS_ERROR_FATAL_DRIVER,
576                          "Attempting to sync allocation from render target, "
577                          "for non-render target allocation");
578        } else if (alloc->getType()->getElement()->getKind() != RS_KIND_PIXEL_RGBA) {
579            rsc->setError(RS_ERROR_FATAL_DRIVER, "Cannot only sync from RGBA"
580                                                 "render target");
581        } else {
582            rsdAllocationSyncFromFBO(rsc, alloc);
583        }
584        return;
585    }
586
587    rsAssert(src == RS_ALLOCATION_USAGE_SCRIPT);
588
589    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) {
590        UploadToTexture(rsc, alloc);
591    } else {
592        if ((alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) &&
593            !(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_IO_OUTPUT)) {
594            AllocateRenderTarget(rsc, alloc);
595        }
596    }
597    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) {
598        UploadToBufferObject(rsc, alloc);
599    }
600
601    drv->uploadDeferred = false;
602}
603
604void rsdAllocationMarkDirty(const Context *rsc, const Allocation *alloc) {
605    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
606    drv->uploadDeferred = true;
607}
608
609void* rsdAllocationGetSurface(const Context *rsc, const Allocation *alloc) {
610#ifndef RS_COMPATIBILITY_LIB
611    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
612
613    drv->cpuConsumer = new CpuConsumer(2);
614    sp<IGraphicBufferProducer> bp = drv->cpuConsumer->getProducerInterface();
615    bp->incStrong(NULL);
616    return bp.get();
617#else
618    return NULL;
619#endif
620}
621
622#ifndef RS_COMPATIBILITY_LIB
623static bool IoGetBuffer(const Context *rsc, Allocation *alloc, ANativeWindow *nw) {
624    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
625
626    int32_t r = native_window_dequeue_buffer_and_wait(nw, &drv->wndBuffer);
627    if (r) {
628        rsc->setError(RS_ERROR_DRIVER, "Error getting next IO output buffer.");
629        return false;
630    }
631
632    // Must lock the whole surface
633    GraphicBufferMapper &mapper = GraphicBufferMapper::get();
634    Rect bounds(drv->wndBuffer->width, drv->wndBuffer->height);
635
636    void *dst = NULL;
637    mapper.lock(drv->wndBuffer->handle,
638            GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN,
639            bounds, &dst);
640    alloc->mHal.drvState.lod[0].mallocPtr = dst;
641    alloc->mHal.drvState.lod[0].stride = drv->wndBuffer->stride * alloc->mHal.state.elementSizeBytes;
642    rsAssert((alloc->mHal.drvState.lod[0].stride & 0xf) == 0);
643
644    return true;
645}
646#endif
647
648void rsdAllocationSetSurface(const Context *rsc, Allocation *alloc, ANativeWindow *nw) {
649#ifndef RS_COMPATIBILITY_LIB
650    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
651    ANativeWindow *old = drv->wndSurface;
652
653    if (nw) {
654        nw->incStrong(NULL);
655    }
656
657    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
658        //TODO finish support for render target + script
659        drv->wnd = nw;
660        return;
661    }
662
663    // Cleanup old surface if there is one.
664    if (drv->wndSurface) {
665        ANativeWindow *old = drv->wndSurface;
666        GraphicBufferMapper &mapper = GraphicBufferMapper::get();
667        mapper.unlock(drv->wndBuffer->handle);
668        old->cancelBuffer(old, drv->wndBuffer, -1);
669        drv->wndSurface = NULL;
670        old->decStrong(NULL);
671    }
672
673    if (nw != NULL) {
674        int32_t r;
675        uint32_t flags = 0;
676        r = native_window_set_buffer_count(nw, 3);
677        if (r) {
678            rsc->setError(RS_ERROR_DRIVER, "Error setting IO output buffer count.");
679            goto error;
680        }
681
682        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT) {
683            flags |= GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_OFTEN;
684        }
685        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
686            flags |= GRALLOC_USAGE_HW_RENDER;
687        }
688
689        r = native_window_set_usage(nw, flags);
690        if (r) {
691            rsc->setError(RS_ERROR_DRIVER, "Error setting IO output buffer usage.");
692            goto error;
693        }
694
695        r = native_window_set_buffers_dimensions(nw, alloc->mHal.drvState.lod[0].dimX,
696                                                 alloc->mHal.drvState.lod[0].dimY);
697        if (r) {
698            rsc->setError(RS_ERROR_DRIVER, "Error setting IO output buffer dimensions.");
699            goto error;
700        }
701
702        int format = 0;
703        const Element *e = alloc->mHal.state.type->getElement();
704        switch(e->getType()) {
705        case RS_TYPE_UNSIGNED_8:
706            switch (e->getVectorSize()) {
707            case 1:
708                rsAssert(e->getKind() == RS_KIND_PIXEL_A);
709                format = PIXEL_FORMAT_A_8;
710                break;
711            case 4:
712                rsAssert(e->getKind() == RS_KIND_PIXEL_RGBA);
713                format = PIXEL_FORMAT_RGBA_8888;
714                break;
715            default:
716                rsAssert(0);
717            }
718            break;
719        default:
720            rsAssert(0);
721        }
722
723        r = native_window_set_buffers_format(nw, format);
724        if (r) {
725            rsc->setError(RS_ERROR_DRIVER, "Error setting IO output buffer format.");
726            goto error;
727        }
728
729        IoGetBuffer(rsc, alloc, nw);
730        drv->wndSurface = nw;
731    }
732
733    return;
734
735 error:
736
737    if (nw) {
738        nw->decStrong(NULL);
739    }
740
741
742#endif
743}
744
745void rsdAllocationIoSend(const Context *rsc, Allocation *alloc) {
746#ifndef RS_COMPATIBILITY_LIB
747    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
748    ANativeWindow *nw = drv->wndSurface;
749    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
750        RsdHal *dc = (RsdHal *)rsc->mHal.drv;
751        RSD_CALL_GL(eglSwapBuffers, dc->gl.egl.display, dc->gl.egl.surface);
752        return;
753    }
754    if (nw) {
755        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT) {
756            GraphicBufferMapper &mapper = GraphicBufferMapper::get();
757            mapper.unlock(drv->wndBuffer->handle);
758            int32_t r = nw->queueBuffer(nw, drv->wndBuffer, -1);
759            if (r) {
760                rsc->setError(RS_ERROR_DRIVER, "Error sending IO output buffer.");
761                return;
762            }
763
764            IoGetBuffer(rsc, alloc, nw);
765        }
766    } else {
767        rsc->setError(RS_ERROR_DRIVER, "Sent IO buffer with no attached surface.");
768        return;
769    }
770#endif
771}
772
773void rsdAllocationIoReceive(const Context *rsc, Allocation *alloc) {
774#ifndef RS_COMPATIBILITY_LIB
775    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
776
777    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT) {
778        if (drv->lb.data != NULL) {
779            drv->cpuConsumer->unlockBuffer(drv->lb);
780        }
781
782        status_t ret = drv->cpuConsumer->lockNextBuffer(&drv->lb);
783        alloc->mHal.drvState.lod[0].mallocPtr = drv->lb.data;
784        alloc->mHal.drvState.lod[0].stride = drv->lb.stride * alloc->mHal.state.elementSizeBytes;
785
786        if (alloc->mHal.state.yuv) {
787            DeriveYUVLayout(alloc->mHal.state.yuv, &alloc->mHal.drvState);
788        }
789
790    } else {
791        drv->surfaceTexture->updateTexImage();
792    }
793
794
795#endif
796}
797
798
799void rsdAllocationData1D(const Context *rsc, const Allocation *alloc,
800                         uint32_t xoff, uint32_t lod, size_t count,
801                         const void *data, size_t sizeBytes) {
802    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
803
804    const size_t eSize = alloc->mHal.state.type->getElementSizeBytes();
805    uint8_t * ptr = GetOffsetPtr(alloc, xoff, 0, 0, RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X);
806    size_t size = count * eSize;
807
808    if (ptr != data) {
809        // Skip the copy if we are the same allocation. This can arise from
810        // our Bitmap optimization, where we share the same storage.
811        if (alloc->mHal.state.hasReferences) {
812            alloc->incRefs(data, count);
813            alloc->decRefs(ptr, count);
814        }
815        memcpy(ptr, data, size);
816    }
817    drv->uploadDeferred = true;
818}
819
820void rsdAllocationData2D(const Context *rsc, const Allocation *alloc,
821                         uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
822                         uint32_t w, uint32_t h, const void *data, size_t sizeBytes, size_t stride) {
823    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
824
825    size_t eSize = alloc->mHal.state.elementSizeBytes;
826    size_t lineSize = eSize * w;
827    if (!stride) {
828        stride = lineSize;
829    }
830
831    if (alloc->mHal.drvState.lod[0].mallocPtr) {
832        const uint8_t *src = static_cast<const uint8_t *>(data);
833        uint8_t *dst = GetOffsetPtr(alloc, xoff, yoff, lod, face);
834        if (dst == src) {
835            // Skip the copy if we are the same allocation. This can arise from
836            // our Bitmap optimization, where we share the same storage.
837            drv->uploadDeferred = true;
838            return;
839        }
840
841        for (uint32_t line=yoff; line < (yoff+h); line++) {
842            if (alloc->mHal.state.hasReferences) {
843                alloc->incRefs(src, w);
844                alloc->decRefs(dst, w);
845            }
846            memcpy(dst, src, lineSize);
847            src += stride;
848            dst += alloc->mHal.drvState.lod[lod].stride;
849        }
850        if (alloc->mHal.state.yuv) {
851            int lod = 1;
852            while (alloc->mHal.drvState.lod[lod].mallocPtr) {
853                size_t lineSize = alloc->mHal.drvState.lod[lod].dimX;
854                uint8_t *dst = GetOffsetPtr(alloc, xoff, yoff, lod, face);
855
856                for (uint32_t line=(yoff >> 1); line < ((yoff+h)>>1); line++) {
857                    memcpy(dst, src, lineSize);
858                    src += lineSize;
859                    dst += alloc->mHal.drvState.lod[lod].stride;
860                }
861                lod++;
862            }
863
864        }
865        drv->uploadDeferred = true;
866    } else {
867        Update2DTexture(rsc, alloc, data, xoff, yoff, lod, face, w, h);
868    }
869}
870
871void rsdAllocationData3D(const Context *rsc, const Allocation *alloc,
872                         uint32_t xoff, uint32_t yoff, uint32_t zoff,
873                         uint32_t lod, RsAllocationCubemapFace face,
874                         uint32_t w, uint32_t h, uint32_t d, const void *data, size_t sizeBytes) {
875
876}
877
878void rsdAllocationRead1D(const Context *rsc, const Allocation *alloc,
879                         uint32_t xoff, uint32_t lod, size_t count,
880                         void *data, size_t sizeBytes) {
881    const size_t eSize = alloc->mHal.state.type->getElementSizeBytes();
882    const uint8_t * ptr = GetOffsetPtr(alloc, xoff, 0, 0, RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X);
883    if (data != ptr) {
884        // Skip the copy if we are the same allocation. This can arise from
885        // our Bitmap optimization, where we share the same storage.
886        memcpy(data, ptr, count * eSize);
887    }
888}
889
890void rsdAllocationRead2D(const Context *rsc, const Allocation *alloc,
891                                uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
892                                uint32_t w, uint32_t h, void *data, size_t sizeBytes, size_t stride) {
893    size_t eSize = alloc->mHal.state.elementSizeBytes;
894    size_t lineSize = eSize * w;
895    if (!stride) {
896        stride = lineSize;
897    }
898
899    if (alloc->mHal.drvState.lod[0].mallocPtr) {
900        uint8_t *dst = static_cast<uint8_t *>(data);
901        const uint8_t *src = GetOffsetPtr(alloc, xoff, yoff, lod, face);
902        if (dst == src) {
903            // Skip the copy if we are the same allocation. This can arise from
904            // our Bitmap optimization, where we share the same storage.
905            return;
906        }
907
908        for (uint32_t line=yoff; line < (yoff+h); line++) {
909            memcpy(dst, src, lineSize);
910            dst += stride;
911            src += alloc->mHal.drvState.lod[lod].stride;
912        }
913    } else {
914        ALOGE("Add code to readback from non-script memory");
915    }
916}
917
918
919void rsdAllocationRead3D(const Context *rsc, const Allocation *alloc,
920                         uint32_t xoff, uint32_t yoff, uint32_t zoff,
921                         uint32_t lod, RsAllocationCubemapFace face,
922                         uint32_t w, uint32_t h, uint32_t d, void *data, size_t sizeBytes) {
923
924}
925
926void * rsdAllocationLock1D(const android::renderscript::Context *rsc,
927                          const android::renderscript::Allocation *alloc) {
928    return alloc->mHal.drvState.lod[0].mallocPtr;
929}
930
931void rsdAllocationUnlock1D(const android::renderscript::Context *rsc,
932                          const android::renderscript::Allocation *alloc) {
933
934}
935
936void rsdAllocationData1D_alloc(const android::renderscript::Context *rsc,
937                               const android::renderscript::Allocation *dstAlloc,
938                               uint32_t dstXoff, uint32_t dstLod, size_t count,
939                               const android::renderscript::Allocation *srcAlloc,
940                               uint32_t srcXoff, uint32_t srcLod) {
941}
942
943
944void rsdAllocationData2D_alloc_script(const android::renderscript::Context *rsc,
945                                      const android::renderscript::Allocation *dstAlloc,
946                                      uint32_t dstXoff, uint32_t dstYoff, uint32_t dstLod,
947                                      RsAllocationCubemapFace dstFace, uint32_t w, uint32_t h,
948                                      const android::renderscript::Allocation *srcAlloc,
949                                      uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod,
950                                      RsAllocationCubemapFace srcFace) {
951    size_t elementSize = dstAlloc->getType()->getElementSizeBytes();
952    for (uint32_t i = 0; i < h; i ++) {
953        uint8_t *dstPtr = GetOffsetPtr(dstAlloc, dstXoff, dstYoff + i, dstLod, dstFace);
954        uint8_t *srcPtr = GetOffsetPtr(srcAlloc, srcXoff, srcYoff + i, srcLod, srcFace);
955        memcpy(dstPtr, srcPtr, w * elementSize);
956
957        //ALOGE("COPIED dstXoff(%u), dstYoff(%u), dstLod(%u), dstFace(%u), w(%u), h(%u), srcXoff(%u), srcYoff(%u), srcLod(%u), srcFace(%u)",
958        //     dstXoff, dstYoff, dstLod, dstFace, w, h, srcXoff, srcYoff, srcLod, srcFace);
959    }
960}
961
962void rsdAllocationData2D_alloc(const android::renderscript::Context *rsc,
963                               const android::renderscript::Allocation *dstAlloc,
964                               uint32_t dstXoff, uint32_t dstYoff, uint32_t dstLod,
965                               RsAllocationCubemapFace dstFace, uint32_t w, uint32_t h,
966                               const android::renderscript::Allocation *srcAlloc,
967                               uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod,
968                               RsAllocationCubemapFace srcFace) {
969    if (!dstAlloc->getIsScript() && !srcAlloc->getIsScript()) {
970        rsc->setError(RS_ERROR_FATAL_DRIVER, "Non-script allocation copies not "
971                                             "yet implemented.");
972        return;
973    }
974    rsdAllocationData2D_alloc_script(rsc, dstAlloc, dstXoff, dstYoff,
975                                     dstLod, dstFace, w, h, srcAlloc,
976                                     srcXoff, srcYoff, srcLod, srcFace);
977}
978
979void rsdAllocationData3D_alloc(const android::renderscript::Context *rsc,
980                               const android::renderscript::Allocation *dstAlloc,
981                               uint32_t dstXoff, uint32_t dstYoff, uint32_t dstZoff,
982                               uint32_t dstLod, RsAllocationCubemapFace dstFace,
983                               uint32_t w, uint32_t h, uint32_t d,
984                               const android::renderscript::Allocation *srcAlloc,
985                               uint32_t srcXoff, uint32_t srcYoff, uint32_t srcZoff,
986                               uint32_t srcLod, RsAllocationCubemapFace srcFace) {
987}
988
989void rsdAllocationElementData1D(const Context *rsc, const Allocation *alloc,
990                                uint32_t x,
991                                const void *data, uint32_t cIdx, size_t sizeBytes) {
992    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
993
994    size_t eSize = alloc->mHal.state.elementSizeBytes;
995    uint8_t * ptr = GetOffsetPtr(alloc, x, 0, 0, RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X);
996
997    const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx);
998    ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx);
999
1000    if (alloc->mHal.state.hasReferences) {
1001        e->incRefs(data);
1002        e->decRefs(ptr);
1003    }
1004
1005    memcpy(ptr, data, sizeBytes);
1006    drv->uploadDeferred = true;
1007}
1008
1009void rsdAllocationElementData2D(const Context *rsc, const Allocation *alloc,
1010                                uint32_t x, uint32_t y,
1011                                const void *data, uint32_t cIdx, size_t sizeBytes) {
1012    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
1013
1014    size_t eSize = alloc->mHal.state.elementSizeBytes;
1015    uint8_t * ptr = GetOffsetPtr(alloc, x, y, 0, RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X);
1016
1017    const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx);
1018    ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx);
1019
1020    if (alloc->mHal.state.hasReferences) {
1021        e->incRefs(data);
1022        e->decRefs(ptr);
1023    }
1024
1025    memcpy(ptr, data, sizeBytes);
1026    drv->uploadDeferred = true;
1027}
1028
1029static void mip565(const Allocation *alloc, int lod, RsAllocationCubemapFace face) {
1030    uint32_t w = alloc->mHal.drvState.lod[lod + 1].dimX;
1031    uint32_t h = alloc->mHal.drvState.lod[lod + 1].dimY;
1032
1033    for (uint32_t y=0; y < h; y++) {
1034        uint16_t *oPtr = (uint16_t *)GetOffsetPtr(alloc, 0, y, lod + 1, face);
1035        const uint16_t *i1 = (uint16_t *)GetOffsetPtr(alloc, 0, y*2, lod, face);
1036        const uint16_t *i2 = (uint16_t *)GetOffsetPtr(alloc, 0, y*2+1, lod, face);
1037
1038        for (uint32_t x=0; x < w; x++) {
1039            *oPtr = rsBoxFilter565(i1[0], i1[1], i2[0], i2[1]);
1040            oPtr ++;
1041            i1 += 2;
1042            i2 += 2;
1043        }
1044    }
1045}
1046
1047static void mip8888(const Allocation *alloc, int lod, RsAllocationCubemapFace face) {
1048    uint32_t w = alloc->mHal.drvState.lod[lod + 1].dimX;
1049    uint32_t h = alloc->mHal.drvState.lod[lod + 1].dimY;
1050
1051    for (uint32_t y=0; y < h; y++) {
1052        uint32_t *oPtr = (uint32_t *)GetOffsetPtr(alloc, 0, y, lod + 1, face);
1053        const uint32_t *i1 = (uint32_t *)GetOffsetPtr(alloc, 0, y*2, lod, face);
1054        const uint32_t *i2 = (uint32_t *)GetOffsetPtr(alloc, 0, y*2+1, lod, face);
1055
1056        for (uint32_t x=0; x < w; x++) {
1057            *oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]);
1058            oPtr ++;
1059            i1 += 2;
1060            i2 += 2;
1061        }
1062    }
1063}
1064
1065static void mip8(const Allocation *alloc, int lod, RsAllocationCubemapFace face) {
1066    uint32_t w = alloc->mHal.drvState.lod[lod + 1].dimX;
1067    uint32_t h = alloc->mHal.drvState.lod[lod + 1].dimY;
1068
1069    for (uint32_t y=0; y < h; y++) {
1070        uint8_t *oPtr = GetOffsetPtr(alloc, 0, y, lod + 1, face);
1071        const uint8_t *i1 = GetOffsetPtr(alloc, 0, y*2, lod, face);
1072        const uint8_t *i2 = GetOffsetPtr(alloc, 0, y*2+1, lod, face);
1073
1074        for (uint32_t x=0; x < w; x++) {
1075            *oPtr = (uint8_t)(((uint32_t)i1[0] + i1[1] + i2[0] + i2[1]) * 0.25f);
1076            oPtr ++;
1077            i1 += 2;
1078            i2 += 2;
1079        }
1080    }
1081}
1082
1083void rsdAllocationGenerateMipmaps(const Context *rsc, const Allocation *alloc) {
1084    if(!alloc->mHal.drvState.lod[0].mallocPtr) {
1085        return;
1086    }
1087    uint32_t numFaces = alloc->getType()->getDimFaces() ? 6 : 1;
1088    for (uint32_t face = 0; face < numFaces; face ++) {
1089        for (uint32_t lod=0; lod < (alloc->getType()->getLODCount() -1); lod++) {
1090            switch (alloc->getType()->getElement()->getSizeBits()) {
1091            case 32:
1092                mip8888(alloc, lod, (RsAllocationCubemapFace)face);
1093                break;
1094            case 16:
1095                mip565(alloc, lod, (RsAllocationCubemapFace)face);
1096                break;
1097            case 8:
1098                mip8(alloc, lod, (RsAllocationCubemapFace)face);
1099                break;
1100            }
1101        }
1102    }
1103}
1104
1105
1106