rsdAllocation.cpp revision a614ae175bbf97201b5e18984d814a1d3e86faa8
1/*
2 * Copyright (C) 2011 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
18#include "rsdCore.h"
19#include "rsdBcc.h"
20#include "rsdRuntime.h"
21#include "rsdAllocation.h"
22
23#include "rsAllocation.h"
24
25#include <GLES/gl.h>
26#include <GLES2/gl2.h>
27#include <GLES/glext.h>
28
29using namespace android;
30using namespace android::renderscript;
31
32
33
34const static GLenum gFaceOrder[] = {
35    GL_TEXTURE_CUBE_MAP_POSITIVE_X,
36    GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
37    GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
38    GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
39    GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
40    GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
41};
42
43
44GLenum rsdTypeToGLType(RsDataType t) {
45    switch (t) {
46    case RS_TYPE_UNSIGNED_5_6_5:    return GL_UNSIGNED_SHORT_5_6_5;
47    case RS_TYPE_UNSIGNED_5_5_5_1:  return GL_UNSIGNED_SHORT_5_5_5_1;
48    case RS_TYPE_UNSIGNED_4_4_4_4:  return GL_UNSIGNED_SHORT_4_4_4_4;
49
50    //case RS_TYPE_FLOAT_16:      return GL_HALF_FLOAT;
51    case RS_TYPE_FLOAT_32:      return GL_FLOAT;
52    case RS_TYPE_UNSIGNED_8:    return GL_UNSIGNED_BYTE;
53    case RS_TYPE_UNSIGNED_16:   return GL_UNSIGNED_SHORT;
54    case RS_TYPE_SIGNED_8:      return GL_BYTE;
55    case RS_TYPE_SIGNED_16:     return GL_SHORT;
56    default:    break;
57    }
58    return 0;
59}
60
61GLenum rsdKindToGLFormat(RsDataKind k) {
62    switch (k) {
63    case RS_KIND_PIXEL_L: return GL_LUMINANCE;
64    case RS_KIND_PIXEL_A: return GL_ALPHA;
65    case RS_KIND_PIXEL_LA: return GL_LUMINANCE_ALPHA;
66    case RS_KIND_PIXEL_RGB: return GL_RGB;
67    case RS_KIND_PIXEL_RGBA: return GL_RGBA;
68    case RS_KIND_PIXEL_DEPTH: return GL_DEPTH_COMPONENT16;
69    default: break;
70    }
71    return 0;
72}
73
74
75static void Update2DTexture(const Allocation *alloc, const void *ptr, uint32_t xoff, uint32_t yoff,
76                     uint32_t lod, RsAllocationCubemapFace face,
77                     uint32_t w, uint32_t h) {
78    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
79
80    rsAssert(drv->textureID);
81    glBindTexture(drv->glTarget, drv->textureID);
82    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
83    GLenum t = GL_TEXTURE_2D;
84    if (alloc->mHal.state.hasFaces) {
85        t = gFaceOrder[face];
86    }
87    glTexSubImage2D(t, lod, xoff, yoff, w, h, drv->glFormat, drv->glType, ptr);
88}
89
90
91static void Upload2DTexture(const Context *rsc, const Allocation *alloc, bool isFirstUpload) {
92    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
93
94    glBindTexture(drv->glTarget, drv->textureID);
95    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
96
97    uint32_t faceCount = 1;
98    if (alloc->mHal.state.hasFaces) {
99        faceCount = 6;
100    }
101
102    rsdGLCheckError(rsc, "Upload2DTexture 1 ");
103    for (uint32_t face = 0; face < faceCount; face ++) {
104        for (uint32_t lod = 0; lod < alloc->mHal.state.type->getLODCount(); lod++) {
105            const uint8_t *p = (const uint8_t *)drv->mallocPtr;
106            p += alloc->mHal.state.type->getLODFaceOffset(lod, (RsAllocationCubemapFace)face, 0, 0);
107
108            GLenum t = GL_TEXTURE_2D;
109            if (alloc->mHal.state.hasFaces) {
110                t = gFaceOrder[face];
111            }
112
113            if (isFirstUpload) {
114                glTexImage2D(t, lod, drv->glFormat,
115                             alloc->mHal.state.type->getLODDimX(lod),
116                             alloc->mHal.state.type->getLODDimY(lod),
117                             0, drv->glFormat, drv->glType, p);
118            } else {
119                glTexSubImage2D(t, lod, 0, 0,
120                                alloc->mHal.state.type->getLODDimX(lod),
121                                alloc->mHal.state.type->getLODDimY(lod),
122                                drv->glFormat, drv->glType, p);
123            }
124        }
125    }
126
127    if (alloc->mHal.state.mipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) {
128        glGenerateMipmap(drv->glTarget);
129    }
130    rsdGLCheckError(rsc, "Upload2DTexture");
131}
132
133static void UploadToTexture(const Context *rsc, const Allocation *alloc) {
134    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
135
136    if (!drv->glType || !drv->glFormat) {
137        return;
138    }
139
140    if (!alloc->getPtr()) {
141        return;
142    }
143
144    bool isFirstUpload = false;
145
146    if (!drv->textureID) {
147        glGenTextures(1, &drv->textureID);
148        isFirstUpload = true;
149    }
150
151    Upload2DTexture(rsc, alloc, isFirstUpload);
152
153    if (!(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) {
154        if (drv->mallocPtr) {
155            free(drv->mallocPtr);
156            drv->mallocPtr = NULL;
157        }
158    }
159    rsdGLCheckError(rsc, "UploadToTexture");
160}
161
162static void AllocateRenderTarget(const Context *rsc, const Allocation *alloc) {
163    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
164
165    if (!drv->glFormat) {
166        return;
167    }
168
169    if (!drv->renderTargetID) {
170        glGenRenderbuffers(1, &drv->renderTargetID);
171
172        if (!drv->renderTargetID) {
173            // This should generally not happen
174            LOGE("allocateRenderTarget failed to gen mRenderTargetID");
175            rsc->dumpDebug();
176            return;
177        }
178        glBindRenderbuffer(GL_RENDERBUFFER, drv->renderTargetID);
179        glRenderbufferStorage(GL_RENDERBUFFER, drv->glFormat,
180                              alloc->mHal.state.dimensionX, alloc->mHal.state.dimensionY);
181    }
182    rsdGLCheckError(rsc, "AllocateRenderTarget");
183}
184
185static void UploadToBufferObject(const Context *rsc, const Allocation *alloc) {
186    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
187
188    rsAssert(!alloc->mHal.state.type->getDimY());
189    rsAssert(!alloc->mHal.state.type->getDimZ());
190
191    //alloc->mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX;
192
193    if (!drv->bufferID) {
194        glGenBuffers(1, &drv->bufferID);
195    }
196    if (!drv->bufferID) {
197        LOGE("Upload to buffer object failed");
198        drv->uploadDeferred = true;
199        return;
200    }
201    glBindBuffer(drv->glTarget, drv->bufferID);
202    glBufferData(drv->glTarget, alloc->mHal.state.type->getSizeBytes(),
203                 drv->mallocPtr, GL_DYNAMIC_DRAW);
204    glBindBuffer(drv->glTarget, 0);
205    rsdGLCheckError(rsc, "UploadToBufferObject");
206}
207
208bool rsdAllocationInit(const Context *rsc, Allocation *alloc, bool forceZero) {
209    DrvAllocation *drv = (DrvAllocation *)calloc(1, sizeof(DrvAllocation));
210    if (!drv) {
211        return false;
212    }
213
214    void * ptr = malloc(alloc->mHal.state.type->getSizeBytes());
215    if (!ptr) {
216        free(drv);
217        return false;
218    }
219
220    drv->glTarget = GL_NONE;
221    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) {
222        if (alloc->mHal.state.hasFaces) {
223            drv->glTarget = GL_TEXTURE_CUBE_MAP;
224        } else {
225            drv->glTarget = GL_TEXTURE_2D;
226        }
227    } else {
228        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) {
229            drv->glTarget = GL_ARRAY_BUFFER;
230        }
231    }
232
233    drv->glType = rsdTypeToGLType(alloc->mHal.state.type->getElement()->getComponent().getType());
234    drv->glFormat = rsdKindToGLFormat(alloc->mHal.state.type->getElement()->getComponent().getKind());
235
236
237    alloc->mHal.drvState.mallocPtr = ptr;
238    drv->mallocPtr = (uint8_t *)ptr;
239    alloc->mHal.drv = drv;
240    if (forceZero) {
241        memset(ptr, 0, alloc->mHal.state.type->getSizeBytes());
242    }
243
244    if (alloc->mHal.state.usageFlags & ~RS_ALLOCATION_USAGE_SCRIPT) {
245        drv->uploadDeferred = true;
246    }
247    return true;
248}
249
250void rsdAllocationDestroy(const Context *rsc, Allocation *alloc) {
251    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
252
253    if (drv->bufferID) {
254        // Causes a SW crash....
255        //LOGV(" mBufferID %i", mBufferID);
256        //glDeleteBuffers(1, &mBufferID);
257        //mBufferID = 0;
258    }
259    if (drv->textureID) {
260        glDeleteTextures(1, &drv->textureID);
261        drv->textureID = 0;
262    }
263    if (drv->renderTargetID) {
264        glDeleteRenderbuffers(1, &drv->renderTargetID);
265        drv->renderTargetID = 0;
266    }
267
268    if (drv->mallocPtr) {
269        free(drv->mallocPtr);
270        drv->mallocPtr = NULL;
271    }
272    free(drv);
273    alloc->mHal.drv = NULL;
274}
275
276void rsdAllocationResize(const Context *rsc, const Allocation *alloc,
277                         const Type *newType, bool zeroNew) {
278    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
279
280    drv->mallocPtr = (uint8_t *)realloc(drv->mallocPtr, newType->getSizeBytes());
281
282    // fixme
283    ((Allocation *)alloc)->mHal.drvState.mallocPtr = drv->mallocPtr;
284
285    const uint32_t oldDimX = alloc->mHal.state.dimensionX;
286    const uint32_t dimX = newType->getDimX();
287
288    if (dimX > oldDimX) {
289        const Element *e = alloc->mHal.state.type->getElement();
290        uint32_t stride = e->getSizeBytes();
291        memset(((uint8_t *)drv->mallocPtr) + stride * oldDimX, 0, stride * (dimX - oldDimX));
292    }
293}
294
295
296
297void rsdAllocationSyncAll(const Context *rsc, const Allocation *alloc,
298                         RsAllocationUsageType src) {
299    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
300
301    if (!drv->uploadDeferred) {
302        return;
303    }
304
305    rsAssert(src == RS_ALLOCATION_USAGE_SCRIPT);
306
307    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) {
308        UploadToTexture(rsc, alloc);
309    } else {
310        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
311            AllocateRenderTarget(rsc, alloc);
312        }
313    }
314    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) {
315        UploadToBufferObject(rsc, alloc);
316    }
317
318    drv->uploadDeferred = false;
319}
320
321void rsdAllocationMarkDirty(const Context *rsc, const Allocation *alloc) {
322    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
323    drv->uploadDeferred = true;
324}
325
326void rsdAllocationData1D(const Context *rsc, const Allocation *alloc,
327                         uint32_t xoff, uint32_t lod, uint32_t count,
328                         const void *data, uint32_t sizeBytes) {
329    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
330
331    const uint32_t eSize = alloc->mHal.state.type->getElementSizeBytes();
332    uint8_t * ptr = drv->mallocPtr;
333    ptr += eSize * xoff;
334    uint32_t size = count * eSize;
335
336    if (alloc->mHal.state.hasReferences) {
337        alloc->incRefs(data, count);
338        alloc->decRefs(ptr, count);
339    }
340
341    memcpy(ptr, data, size);
342    drv->uploadDeferred = true;
343}
344
345void rsdAllocationData2D(const Context *rsc, const Allocation *alloc,
346                         uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
347                         uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) {
348    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
349
350    uint32_t eSize = alloc->mHal.state.elementSizeBytes;
351    uint32_t lineSize = eSize * w;
352    uint32_t destW = alloc->mHal.state.dimensionX;
353
354    if (drv->mallocPtr) {
355        const uint8_t *src = static_cast<const uint8_t *>(data);
356        uint8_t *dst = drv->mallocPtr;
357        dst += alloc->mHal.state.type->getLODFaceOffset(lod, face, xoff, yoff);
358
359        for (uint32_t line=yoff; line < (yoff+h); line++) {
360            if (alloc->mHal.state.hasReferences) {
361                alloc->incRefs(src, w);
362                alloc->decRefs(dst, w);
363            }
364            memcpy(dst, src, lineSize);
365            src += lineSize;
366            dst += destW * eSize;
367        }
368        drv->uploadDeferred = true;
369    } else {
370        Update2DTexture(alloc, data, xoff, yoff, lod, face, w, h);
371    }
372}
373
374void rsdAllocationData3D(const Context *rsc, const Allocation *alloc,
375                         uint32_t xoff, uint32_t yoff, uint32_t zoff,
376                         uint32_t lod, RsAllocationCubemapFace face,
377                         uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) {
378
379}
380
381void rsdAllocationElementData1D(const Context *rsc, const Allocation *alloc,
382                                uint32_t x,
383                                const void *data, uint32_t cIdx, uint32_t sizeBytes) {
384    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
385
386    uint32_t eSize = alloc->mHal.state.elementSizeBytes;
387    uint8_t * ptr = drv->mallocPtr;
388    ptr += eSize * x;
389
390    const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx);
391    ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx);
392
393    if (alloc->mHal.state.hasReferences) {
394        e->incRefs(data);
395        e->decRefs(ptr);
396    }
397
398    memcpy(ptr, data, sizeBytes);
399    drv->uploadDeferred = true;
400}
401
402void rsdAllocationElementData2D(const Context *rsc, const Allocation *alloc,
403                                uint32_t x, uint32_t y,
404                                const void *data, uint32_t cIdx, uint32_t sizeBytes) {
405    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
406
407    uint32_t eSize = alloc->mHal.state.elementSizeBytes;
408    uint8_t * ptr = drv->mallocPtr;
409    ptr += eSize * (x + y * alloc->mHal.state.dimensionX);
410
411    const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx);
412    ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx);
413
414    if (alloc->mHal.state.hasReferences) {
415        e->incRefs(data);
416        e->decRefs(ptr);
417    }
418
419    memcpy(ptr, data, sizeBytes);
420    drv->uploadDeferred = true;
421}
422
423
424