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