rsdAllocation.cpp revision 179e9a457095fea4c9e6d366c269754b882d05dd
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#include "rsdFrameBufferObj.h"
23
24#include "rsAllocation.h"
25
26#include <GLES/gl.h>
27#include <GLES2/gl2.h>
28#include <GLES/glext.h>
29
30using namespace android;
31using namespace android::renderscript;
32
33
34
35const static GLenum gFaceOrder[] = {
36    GL_TEXTURE_CUBE_MAP_POSITIVE_X,
37    GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
38    GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
39    GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
40    GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
41    GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
42};
43
44
45GLenum rsdTypeToGLType(RsDataType t) {
46    switch (t) {
47    case RS_TYPE_UNSIGNED_5_6_5:    return GL_UNSIGNED_SHORT_5_6_5;
48    case RS_TYPE_UNSIGNED_5_5_5_1:  return GL_UNSIGNED_SHORT_5_5_5_1;
49    case RS_TYPE_UNSIGNED_4_4_4_4:  return GL_UNSIGNED_SHORT_4_4_4_4;
50
51    //case RS_TYPE_FLOAT_16:      return GL_HALF_FLOAT;
52    case RS_TYPE_FLOAT_32:      return GL_FLOAT;
53    case RS_TYPE_UNSIGNED_8:    return GL_UNSIGNED_BYTE;
54    case RS_TYPE_UNSIGNED_16:   return GL_UNSIGNED_SHORT;
55    case RS_TYPE_SIGNED_8:      return GL_BYTE;
56    case RS_TYPE_SIGNED_16:     return GL_SHORT;
57    default:    break;
58    }
59    return 0;
60}
61
62GLenum rsdKindToGLFormat(RsDataKind k) {
63    switch (k) {
64    case RS_KIND_PIXEL_L: return GL_LUMINANCE;
65    case RS_KIND_PIXEL_A: return GL_ALPHA;
66    case RS_KIND_PIXEL_LA: return GL_LUMINANCE_ALPHA;
67    case RS_KIND_PIXEL_RGB: return GL_RGB;
68    case RS_KIND_PIXEL_RGBA: return GL_RGBA;
69    case RS_KIND_PIXEL_DEPTH: return GL_DEPTH_COMPONENT16;
70    default: break;
71    }
72    return 0;
73}
74
75
76static void Update2DTexture(const Context *rsc, const Allocation *alloc, const void *ptr,
77                            uint32_t xoff, uint32_t yoff, uint32_t lod,
78                            RsAllocationCubemapFace face, uint32_t w, uint32_t h) {
79    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
80
81    rsAssert(drv->textureID);
82    RSD_CALL_GL(glBindTexture, drv->glTarget, drv->textureID);
83    RSD_CALL_GL(glPixelStorei, GL_UNPACK_ALIGNMENT, 1);
84    GLenum t = GL_TEXTURE_2D;
85    if (alloc->mHal.state.hasFaces) {
86        t = gFaceOrder[face];
87    }
88    RSD_CALL_GL(glTexSubImage2D, t, lod, xoff, yoff, w, h, drv->glFormat, drv->glType, ptr);
89}
90
91
92static void Upload2DTexture(const Context *rsc, const Allocation *alloc, bool isFirstUpload) {
93    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
94
95    RSD_CALL_GL(glBindTexture, drv->glTarget, drv->textureID);
96    RSD_CALL_GL(glPixelStorei, GL_UNPACK_ALIGNMENT, 1);
97
98    uint32_t faceCount = 1;
99    if (alloc->mHal.state.hasFaces) {
100        faceCount = 6;
101    }
102
103    rsdGLCheckError(rsc, "Upload2DTexture 1 ");
104    for (uint32_t face = 0; face < faceCount; face ++) {
105        for (uint32_t lod = 0; lod < alloc->mHal.state.type->getLODCount(); lod++) {
106            const uint8_t *p = (const uint8_t *)drv->mallocPtr;
107            p += alloc->mHal.state.type->getLODFaceOffset(lod, (RsAllocationCubemapFace)face, 0, 0);
108
109            GLenum t = GL_TEXTURE_2D;
110            if (alloc->mHal.state.hasFaces) {
111                t = gFaceOrder[face];
112            }
113
114            if (isFirstUpload) {
115                RSD_CALL_GL(glTexImage2D, t, lod, drv->glFormat,
116                             alloc->mHal.state.type->getLODDimX(lod),
117                             alloc->mHal.state.type->getLODDimY(lod),
118                             0, drv->glFormat, drv->glType, p);
119            } else {
120                RSD_CALL_GL(glTexSubImage2D, t, lod, 0, 0,
121                                alloc->mHal.state.type->getLODDimX(lod),
122                                alloc->mHal.state.type->getLODDimY(lod),
123                                drv->glFormat, drv->glType, p);
124            }
125        }
126    }
127
128    if (alloc->mHal.state.mipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) {
129        RSD_CALL_GL(glGenerateMipmap, drv->glTarget);
130    }
131    rsdGLCheckError(rsc, "Upload2DTexture");
132}
133
134static void UploadToTexture(const Context *rsc, const Allocation *alloc) {
135    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
136
137    if (!drv->glType || !drv->glFormat) {
138        return;
139    }
140
141    if (!alloc->getPtr()) {
142        return;
143    }
144
145    bool isFirstUpload = false;
146
147    if (!drv->textureID) {
148        RSD_CALL_GL(glGenTextures, 1, &drv->textureID);
149        isFirstUpload = true;
150    }
151
152    Upload2DTexture(rsc, alloc, isFirstUpload);
153
154    if (!(alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) {
155        if (drv->mallocPtr) {
156            free(drv->mallocPtr);
157            drv->mallocPtr = NULL;
158        }
159    }
160    rsdGLCheckError(rsc, "UploadToTexture");
161}
162
163static void AllocateRenderTarget(const Context *rsc, const Allocation *alloc) {
164    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
165
166    if (!drv->glFormat) {
167        return;
168    }
169
170    if (!drv->renderTargetID) {
171        RSD_CALL_GL(glGenRenderbuffers, 1, &drv->renderTargetID);
172
173        if (!drv->renderTargetID) {
174            // This should generally not happen
175            LOGE("allocateRenderTarget failed to gen mRenderTargetID");
176            rsc->dumpDebug();
177            return;
178        }
179        RSD_CALL_GL(glBindRenderbuffer, GL_RENDERBUFFER, drv->renderTargetID);
180        RSD_CALL_GL(glRenderbufferStorage, GL_RENDERBUFFER, drv->glFormat,
181                              alloc->mHal.state.dimensionX, alloc->mHal.state.dimensionY);
182    }
183    rsdGLCheckError(rsc, "AllocateRenderTarget");
184}
185
186static void UploadToBufferObject(const Context *rsc, const Allocation *alloc) {
187    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
188
189    rsAssert(!alloc->mHal.state.type->getDimY());
190    rsAssert(!alloc->mHal.state.type->getDimZ());
191
192    //alloc->mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX;
193
194    if (!drv->bufferID) {
195        RSD_CALL_GL(glGenBuffers, 1, &drv->bufferID);
196    }
197    if (!drv->bufferID) {
198        LOGE("Upload to buffer object failed");
199        drv->uploadDeferred = true;
200        return;
201    }
202    RSD_CALL_GL(glBindBuffer, drv->glTarget, drv->bufferID);
203    RSD_CALL_GL(glBufferData, drv->glTarget, alloc->mHal.state.type->getSizeBytes(),
204                 drv->mallocPtr, GL_DYNAMIC_DRAW);
205    RSD_CALL_GL(glBindBuffer, drv->glTarget, 0);
206    rsdGLCheckError(rsc, "UploadToBufferObject");
207}
208
209bool rsdAllocationInit(const Context *rsc, Allocation *alloc, bool forceZero) {
210    DrvAllocation *drv = (DrvAllocation *)calloc(1, sizeof(DrvAllocation));
211    if (!drv) {
212        return false;
213    }
214
215    void * ptr = alloc->mHal.state.usrPtr;
216    if (!ptr) {
217        ptr = malloc(alloc->mHal.state.type->getSizeBytes());
218        if (!ptr) {
219            free(drv);
220            return false;
221        }
222    }
223
224    drv->glTarget = GL_NONE;
225    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) {
226        if (alloc->mHal.state.hasFaces) {
227            drv->glTarget = GL_TEXTURE_CUBE_MAP;
228        } else {
229            drv->glTarget = GL_TEXTURE_2D;
230        }
231    } else {
232        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) {
233            drv->glTarget = GL_ARRAY_BUFFER;
234        }
235    }
236
237    drv->glType = rsdTypeToGLType(alloc->mHal.state.type->getElement()->getComponent().getType());
238    drv->glFormat = rsdKindToGLFormat(alloc->mHal.state.type->getElement()->getComponent().getKind());
239
240
241    alloc->mHal.drvState.mallocPtr = ptr;
242    drv->mallocPtr = (uint8_t *)ptr;
243    alloc->mHal.drv = drv;
244    if (forceZero) {
245        memset(ptr, 0, alloc->mHal.state.type->getSizeBytes());
246    }
247
248    if (alloc->mHal.state.usageFlags & ~RS_ALLOCATION_USAGE_SCRIPT) {
249        drv->uploadDeferred = true;
250    }
251
252    drv->readBackFBO = NULL;
253
254    return true;
255}
256
257void rsdAllocationDestroy(const Context *rsc, Allocation *alloc) {
258    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
259
260    if (drv->bufferID) {
261        // Causes a SW crash....
262        //ALOGV(" mBufferID %i", mBufferID);
263        //glDeleteBuffers(1, &mBufferID);
264        //mBufferID = 0;
265    }
266    if (drv->textureID) {
267        RSD_CALL_GL(glDeleteTextures, 1, &drv->textureID);
268        drv->textureID = 0;
269    }
270    if (drv->renderTargetID) {
271        RSD_CALL_GL(glDeleteRenderbuffers, 1, &drv->renderTargetID);
272        drv->renderTargetID = 0;
273    }
274
275    if (drv->mallocPtr && !alloc->mHal.state.usrPtr) {
276        free(drv->mallocPtr);
277        drv->mallocPtr = NULL;
278    }
279    if (drv->readBackFBO != NULL) {
280        delete drv->readBackFBO;
281        drv->readBackFBO = NULL;
282    }
283    free(drv);
284    alloc->mHal.drv = NULL;
285}
286
287void rsdAllocationResize(const Context *rsc, const Allocation *alloc,
288                         const Type *newType, bool zeroNew) {
289    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
290
291    drv->mallocPtr = (uint8_t *)realloc(drv->mallocPtr, newType->getSizeBytes());
292
293    // fixme
294    ((Allocation *)alloc)->mHal.drvState.mallocPtr = drv->mallocPtr;
295
296    const uint32_t oldDimX = alloc->mHal.state.dimensionX;
297    const uint32_t dimX = newType->getDimX();
298
299    if (dimX > oldDimX) {
300        const Element *e = alloc->mHal.state.type->getElement();
301        uint32_t stride = e->getSizeBytes();
302        memset(((uint8_t *)drv->mallocPtr) + stride * oldDimX, 0, stride * (dimX - oldDimX));
303    }
304}
305
306static void rsdAllocationSyncFromFBO(const Context *rsc, const Allocation *alloc) {
307    if (!alloc->getIsScript()) {
308        return; // nothing to sync
309    }
310
311    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
312    RsdFrameBufferObj *lastFbo = dc->gl.currentFrameBuffer;
313
314    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
315    if (!drv->textureID && !drv->renderTargetID) {
316        return; // nothing was rendered here yet, so nothing to sync
317    }
318    if (drv->readBackFBO == NULL) {
319        drv->readBackFBO = new RsdFrameBufferObj();
320        drv->readBackFBO->setColorTarget(drv, 0);
321        drv->readBackFBO->setDimensions(alloc->getType()->getDimX(),
322                                        alloc->getType()->getDimY());
323    }
324
325    // Bind the framebuffer object so we can read back from it
326    drv->readBackFBO->setActive(rsc);
327
328    // Do the readback
329    RSD_CALL_GL(glReadPixels, 0, 0, alloc->getType()->getDimX(), alloc->getType()->getDimY(),
330                 drv->glFormat, drv->glType, alloc->getPtr());
331
332    // Revert framebuffer to its original
333    lastFbo->setActive(rsc);
334}
335
336
337void rsdAllocationSyncAll(const Context *rsc, const Allocation *alloc,
338                         RsAllocationUsageType src) {
339    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
340
341    if (src == RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
342        if(!alloc->getIsRenderTarget()) {
343            rsc->setError(RS_ERROR_FATAL_DRIVER,
344                          "Attempting to sync allocation from render target, "
345                          "for non-render target allocation");
346        } else if (alloc->getType()->getElement()->getKind() != RS_KIND_PIXEL_RGBA) {
347            rsc->setError(RS_ERROR_FATAL_DRIVER, "Cannot only sync from RGBA"
348                                                 "render target");
349        } else {
350            rsdAllocationSyncFromFBO(rsc, alloc);
351        }
352        return;
353    }
354
355    rsAssert(src == RS_ALLOCATION_USAGE_SCRIPT);
356
357    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) {
358        UploadToTexture(rsc, alloc);
359    } else {
360        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
361            AllocateRenderTarget(rsc, alloc);
362        }
363    }
364    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) {
365        UploadToBufferObject(rsc, alloc);
366    }
367
368    drv->uploadDeferred = false;
369}
370
371void rsdAllocationMarkDirty(const Context *rsc, const Allocation *alloc) {
372    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
373    drv->uploadDeferred = true;
374}
375
376void rsdAllocationData1D(const Context *rsc, const Allocation *alloc,
377                         uint32_t xoff, uint32_t lod, uint32_t count,
378                         const void *data, uint32_t sizeBytes) {
379    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
380
381    const uint32_t eSize = alloc->mHal.state.type->getElementSizeBytes();
382    uint8_t * ptr = drv->mallocPtr;
383    ptr += eSize * xoff;
384    uint32_t size = count * eSize;
385
386    if (alloc->mHal.state.hasReferences) {
387        alloc->incRefs(data, count);
388        alloc->decRefs(ptr, count);
389    }
390
391    memcpy(ptr, data, size);
392    drv->uploadDeferred = true;
393}
394
395void rsdAllocationData2D(const Context *rsc, const Allocation *alloc,
396                         uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
397                         uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) {
398    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
399
400    uint32_t eSize = alloc->mHal.state.elementSizeBytes;
401    uint32_t lineSize = eSize * w;
402    uint32_t destW = alloc->mHal.state.dimensionX;
403
404    if (drv->mallocPtr) {
405        const uint8_t *src = static_cast<const uint8_t *>(data);
406        uint8_t *dst = drv->mallocPtr;
407        dst += alloc->mHal.state.type->getLODFaceOffset(lod, face, xoff, yoff);
408
409        for (uint32_t line=yoff; line < (yoff+h); line++) {
410            if (alloc->mHal.state.hasReferences) {
411                alloc->incRefs(src, w);
412                alloc->decRefs(dst, w);
413            }
414            memcpy(dst, src, lineSize);
415            src += lineSize;
416            dst += destW * eSize;
417        }
418        drv->uploadDeferred = true;
419    } else {
420        Update2DTexture(rsc, alloc, data, xoff, yoff, lod, face, w, h);
421    }
422}
423
424void rsdAllocationData3D(const Context *rsc, const Allocation *alloc,
425                         uint32_t xoff, uint32_t yoff, uint32_t zoff,
426                         uint32_t lod, RsAllocationCubemapFace face,
427                         uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) {
428
429}
430
431void rsdAllocationData1D_alloc(const android::renderscript::Context *rsc,
432                               const android::renderscript::Allocation *dstAlloc,
433                               uint32_t dstXoff, uint32_t dstLod, uint32_t count,
434                               const android::renderscript::Allocation *srcAlloc,
435                               uint32_t srcXoff, uint32_t srcLod) {
436}
437
438uint8_t *getOffsetPtr(const android::renderscript::Allocation *alloc,
439                      uint32_t xoff, uint32_t yoff, uint32_t lod,
440                      RsAllocationCubemapFace face) {
441    uint8_t *ptr = static_cast<uint8_t *>(alloc->getPtr());
442    ptr += alloc->getType()->getLODOffset(lod, xoff, yoff);
443
444    if (face != 0) {
445        uint32_t totalSizeBytes = alloc->getType()->getSizeBytes();
446        uint32_t faceOffset = totalSizeBytes / 6;
447        ptr += faceOffset * (uint32_t)face;
448    }
449    return ptr;
450}
451
452
453void rsdAllocationData2D_alloc_script(const android::renderscript::Context *rsc,
454                                      const android::renderscript::Allocation *dstAlloc,
455                                      uint32_t dstXoff, uint32_t dstYoff, uint32_t dstLod,
456                                      RsAllocationCubemapFace dstFace, uint32_t w, uint32_t h,
457                                      const android::renderscript::Allocation *srcAlloc,
458                                      uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod,
459                                      RsAllocationCubemapFace srcFace) {
460    uint32_t elementSize = dstAlloc->getType()->getElementSizeBytes();
461    for (uint32_t i = 0; i < h; i ++) {
462        uint8_t *dstPtr = getOffsetPtr(dstAlloc, dstXoff, dstYoff + i, dstLod, dstFace);
463        uint8_t *srcPtr = getOffsetPtr(srcAlloc, srcXoff, srcYoff + i, srcLod, srcFace);
464        memcpy(dstPtr, srcPtr, w * elementSize);
465
466        //LOGE("COPIED dstXoff(%u), dstYoff(%u), dstLod(%u), dstFace(%u), w(%u), h(%u), srcXoff(%u), srcYoff(%u), srcLod(%u), srcFace(%u)",
467        //     dstXoff, dstYoff, dstLod, dstFace, w, h, srcXoff, srcYoff, srcLod, srcFace);
468    }
469}
470
471void rsdAllocationData2D_alloc(const android::renderscript::Context *rsc,
472                               const android::renderscript::Allocation *dstAlloc,
473                               uint32_t dstXoff, uint32_t dstYoff, uint32_t dstLod,
474                               RsAllocationCubemapFace dstFace, uint32_t w, uint32_t h,
475                               const android::renderscript::Allocation *srcAlloc,
476                               uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod,
477                               RsAllocationCubemapFace srcFace) {
478    if (!dstAlloc->getIsScript() && !srcAlloc->getIsScript()) {
479        rsc->setError(RS_ERROR_FATAL_DRIVER, "Non-script allocation copies not "
480                                             "yet implemented.");
481        return;
482    }
483    rsdAllocationData2D_alloc_script(rsc, dstAlloc, dstXoff, dstYoff,
484                                     dstLod, dstFace, w, h, srcAlloc,
485                                     srcXoff, srcYoff, srcLod, srcFace);
486}
487
488void rsdAllocationData3D_alloc(const android::renderscript::Context *rsc,
489                               const android::renderscript::Allocation *dstAlloc,
490                               uint32_t dstXoff, uint32_t dstYoff, uint32_t dstZoff,
491                               uint32_t dstLod, RsAllocationCubemapFace dstFace,
492                               uint32_t w, uint32_t h, uint32_t d,
493                               const android::renderscript::Allocation *srcAlloc,
494                               uint32_t srcXoff, uint32_t srcYoff, uint32_t srcZoff,
495                               uint32_t srcLod, RsAllocationCubemapFace srcFace) {
496}
497
498void rsdAllocationElementData1D(const Context *rsc, const Allocation *alloc,
499                                uint32_t x,
500                                const void *data, uint32_t cIdx, uint32_t sizeBytes) {
501    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
502
503    uint32_t eSize = alloc->mHal.state.elementSizeBytes;
504    uint8_t * ptr = drv->mallocPtr;
505    ptr += eSize * x;
506
507    const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx);
508    ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx);
509
510    if (alloc->mHal.state.hasReferences) {
511        e->incRefs(data);
512        e->decRefs(ptr);
513    }
514
515    memcpy(ptr, data, sizeBytes);
516    drv->uploadDeferred = true;
517}
518
519void rsdAllocationElementData2D(const Context *rsc, const Allocation *alloc,
520                                uint32_t x, uint32_t y,
521                                const void *data, uint32_t cIdx, uint32_t sizeBytes) {
522    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
523
524    uint32_t eSize = alloc->mHal.state.elementSizeBytes;
525    uint8_t * ptr = drv->mallocPtr;
526    ptr += eSize * (x + y * alloc->mHal.state.dimensionX);
527
528    const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx);
529    ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx);
530
531    if (alloc->mHal.state.hasReferences) {
532        e->incRefs(data);
533        e->decRefs(ptr);
534    }
535
536    memcpy(ptr, data, sizeBytes);
537    drv->uploadDeferred = true;
538}
539
540
541