rsdAllocation.cpp revision af12ac6a08651464f8d823add667c706f993b587
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            ALOGE("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        ALOGE("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 = malloc(alloc->mHal.state.type->getSizeBytes());
216    if (!ptr) {
217        free(drv);
218        return false;
219    }
220
221    drv->glTarget = GL_NONE;
222    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) {
223        if (alloc->mHal.state.hasFaces) {
224            drv->glTarget = GL_TEXTURE_CUBE_MAP;
225        } else {
226            drv->glTarget = GL_TEXTURE_2D;
227        }
228    } else {
229        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) {
230            drv->glTarget = GL_ARRAY_BUFFER;
231        }
232    }
233
234    drv->glType = rsdTypeToGLType(alloc->mHal.state.type->getElement()->getComponent().getType());
235    drv->glFormat = rsdKindToGLFormat(alloc->mHal.state.type->getElement()->getComponent().getKind());
236
237
238    alloc->mHal.drvState.mallocPtr = ptr;
239    drv->mallocPtr = (uint8_t *)ptr;
240    alloc->mHal.drv = drv;
241    if (forceZero) {
242        memset(ptr, 0, alloc->mHal.state.type->getSizeBytes());
243    }
244
245    if (alloc->mHal.state.usageFlags & ~RS_ALLOCATION_USAGE_SCRIPT) {
246        drv->uploadDeferred = true;
247    }
248
249    drv->readBackFBO = NULL;
250
251    return true;
252}
253
254void rsdAllocationDestroy(const Context *rsc, Allocation *alloc) {
255    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
256
257    if (drv->bufferID) {
258        // Causes a SW crash....
259        //ALOGV(" mBufferID %i", mBufferID);
260        //glDeleteBuffers(1, &mBufferID);
261        //mBufferID = 0;
262    }
263    if (drv->textureID) {
264        RSD_CALL_GL(glDeleteTextures, 1, &drv->textureID);
265        drv->textureID = 0;
266    }
267    if (drv->renderTargetID) {
268        RSD_CALL_GL(glDeleteRenderbuffers, 1, &drv->renderTargetID);
269        drv->renderTargetID = 0;
270    }
271
272    if (drv->mallocPtr) {
273        free(drv->mallocPtr);
274        drv->mallocPtr = NULL;
275    }
276    if (drv->readBackFBO != NULL) {
277        delete drv->readBackFBO;
278        drv->readBackFBO = NULL;
279    }
280    free(drv);
281    alloc->mHal.drv = NULL;
282}
283
284void rsdAllocationResize(const Context *rsc, const Allocation *alloc,
285                         const Type *newType, bool zeroNew) {
286    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
287
288    drv->mallocPtr = (uint8_t *)realloc(drv->mallocPtr, newType->getSizeBytes());
289
290    // fixme
291    ((Allocation *)alloc)->mHal.drvState.mallocPtr = drv->mallocPtr;
292
293    const uint32_t oldDimX = alloc->mHal.state.dimensionX;
294    const uint32_t dimX = newType->getDimX();
295
296    if (dimX > oldDimX) {
297        const Element *e = alloc->mHal.state.type->getElement();
298        uint32_t stride = e->getSizeBytes();
299        memset(((uint8_t *)drv->mallocPtr) + stride * oldDimX, 0, stride * (dimX - oldDimX));
300    }
301}
302
303static void rsdAllocationSyncFromFBO(const Context *rsc, const Allocation *alloc) {
304    if (!alloc->getIsScript()) {
305        return; // nothing to sync
306    }
307
308    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
309    RsdFrameBufferObj *lastFbo = dc->gl.currentFrameBuffer;
310
311    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
312    if (!drv->textureID && !drv->renderTargetID) {
313        return; // nothing was rendered here yet, so nothing to sync
314    }
315    if (drv->readBackFBO == NULL) {
316        drv->readBackFBO = new RsdFrameBufferObj();
317        drv->readBackFBO->setColorTarget(drv, 0);
318        drv->readBackFBO->setDimensions(alloc->getType()->getDimX(),
319                                        alloc->getType()->getDimY());
320    }
321
322    // Bind the framebuffer object so we can read back from it
323    drv->readBackFBO->setActive(rsc);
324
325    // Do the readback
326    RSD_CALL_GL(glReadPixels, 0, 0, alloc->getType()->getDimX(), alloc->getType()->getDimY(),
327                 drv->glFormat, drv->glType, alloc->getPtr());
328
329    // Revert framebuffer to its original
330    lastFbo->setActive(rsc);
331}
332
333
334void rsdAllocationSyncAll(const Context *rsc, const Allocation *alloc,
335                         RsAllocationUsageType src) {
336    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
337
338    if (src == RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
339        if(!alloc->getIsRenderTarget()) {
340            rsc->setError(RS_ERROR_FATAL_DRIVER,
341                          "Attempting to sync allocation from render target, "
342                          "for non-render target allocation");
343        } else if (alloc->getType()->getElement()->getKind() != RS_KIND_PIXEL_RGBA) {
344            rsc->setError(RS_ERROR_FATAL_DRIVER, "Cannot only sync from RGBA"
345                                                 "render target");
346        } else {
347            rsdAllocationSyncFromFBO(rsc, alloc);
348        }
349        return;
350    }
351
352    rsAssert(src == RS_ALLOCATION_USAGE_SCRIPT);
353
354    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE) {
355        UploadToTexture(rsc, alloc);
356    } else {
357        if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET) {
358            AllocateRenderTarget(rsc, alloc);
359        }
360    }
361    if (alloc->mHal.state.usageFlags & RS_ALLOCATION_USAGE_GRAPHICS_VERTEX) {
362        UploadToBufferObject(rsc, alloc);
363    }
364
365    drv->uploadDeferred = false;
366}
367
368void rsdAllocationMarkDirty(const Context *rsc, const Allocation *alloc) {
369    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
370    drv->uploadDeferred = true;
371}
372
373void rsdAllocationData1D(const Context *rsc, const Allocation *alloc,
374                         uint32_t xoff, uint32_t lod, uint32_t count,
375                         const void *data, uint32_t sizeBytes) {
376    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
377
378    const uint32_t eSize = alloc->mHal.state.type->getElementSizeBytes();
379    uint8_t * ptr = drv->mallocPtr;
380    ptr += eSize * xoff;
381    uint32_t size = count * eSize;
382
383    if (alloc->mHal.state.hasReferences) {
384        alloc->incRefs(data, count);
385        alloc->decRefs(ptr, count);
386    }
387
388    memcpy(ptr, data, size);
389    drv->uploadDeferred = true;
390}
391
392void rsdAllocationData2D(const Context *rsc, const Allocation *alloc,
393                         uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
394                         uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) {
395    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
396
397    uint32_t eSize = alloc->mHal.state.elementSizeBytes;
398    uint32_t lineSize = eSize * w;
399    uint32_t destW = alloc->mHal.state.dimensionX;
400
401    if (drv->mallocPtr) {
402        const uint8_t *src = static_cast<const uint8_t *>(data);
403        uint8_t *dst = drv->mallocPtr;
404        dst += alloc->mHal.state.type->getLODFaceOffset(lod, face, xoff, yoff);
405
406        for (uint32_t line=yoff; line < (yoff+h); line++) {
407            if (alloc->mHal.state.hasReferences) {
408                alloc->incRefs(src, w);
409                alloc->decRefs(dst, w);
410            }
411            memcpy(dst, src, lineSize);
412            src += lineSize;
413            dst += destW * eSize;
414        }
415        drv->uploadDeferred = true;
416    } else {
417        Update2DTexture(rsc, alloc, data, xoff, yoff, lod, face, w, h);
418    }
419}
420
421void rsdAllocationData3D(const Context *rsc, const Allocation *alloc,
422                         uint32_t xoff, uint32_t yoff, uint32_t zoff,
423                         uint32_t lod, RsAllocationCubemapFace face,
424                         uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) {
425
426}
427
428void rsdAllocationData1D_alloc(const android::renderscript::Context *rsc,
429                               const android::renderscript::Allocation *dstAlloc,
430                               uint32_t dstXoff, uint32_t dstLod, uint32_t count,
431                               const android::renderscript::Allocation *srcAlloc,
432                               uint32_t srcXoff, uint32_t srcLod) {
433}
434
435uint8_t *getOffsetPtr(const android::renderscript::Allocation *alloc,
436                      uint32_t xoff, uint32_t yoff, uint32_t lod,
437                      RsAllocationCubemapFace face) {
438    uint8_t *ptr = static_cast<uint8_t *>(alloc->getPtr());
439    ptr += alloc->getType()->getLODOffset(lod, xoff, yoff);
440
441    if (face != 0) {
442        uint32_t totalSizeBytes = alloc->getType()->getSizeBytes();
443        uint32_t faceOffset = totalSizeBytes / 6;
444        ptr += faceOffset * (uint32_t)face;
445    }
446    return ptr;
447}
448
449
450void rsdAllocationData2D_alloc_script(const android::renderscript::Context *rsc,
451                                      const android::renderscript::Allocation *dstAlloc,
452                                      uint32_t dstXoff, uint32_t dstYoff, uint32_t dstLod,
453                                      RsAllocationCubemapFace dstFace, uint32_t w, uint32_t h,
454                                      const android::renderscript::Allocation *srcAlloc,
455                                      uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod,
456                                      RsAllocationCubemapFace srcFace) {
457    uint32_t elementSize = dstAlloc->getType()->getElementSizeBytes();
458    for (uint32_t i = 0; i < h; i ++) {
459        uint8_t *dstPtr = getOffsetPtr(dstAlloc, dstXoff, dstYoff + i, dstLod, dstFace);
460        uint8_t *srcPtr = getOffsetPtr(srcAlloc, srcXoff, srcYoff + i, srcLod, srcFace);
461        memcpy(dstPtr, srcPtr, w * elementSize);
462
463        //ALOGE("COPIED dstXoff(%u), dstYoff(%u), dstLod(%u), dstFace(%u), w(%u), h(%u), srcXoff(%u), srcYoff(%u), srcLod(%u), srcFace(%u)",
464        //     dstXoff, dstYoff, dstLod, dstFace, w, h, srcXoff, srcYoff, srcLod, srcFace);
465    }
466}
467
468void rsdAllocationData2D_alloc(const android::renderscript::Context *rsc,
469                               const android::renderscript::Allocation *dstAlloc,
470                               uint32_t dstXoff, uint32_t dstYoff, uint32_t dstLod,
471                               RsAllocationCubemapFace dstFace, uint32_t w, uint32_t h,
472                               const android::renderscript::Allocation *srcAlloc,
473                               uint32_t srcXoff, uint32_t srcYoff, uint32_t srcLod,
474                               RsAllocationCubemapFace srcFace) {
475    if (!dstAlloc->getIsScript() && !srcAlloc->getIsScript()) {
476        rsc->setError(RS_ERROR_FATAL_DRIVER, "Non-script allocation copies not "
477                                             "yet implemented.");
478        return;
479    }
480    rsdAllocationData2D_alloc_script(rsc, dstAlloc, dstXoff, dstYoff,
481                                     dstLod, dstFace, w, h, srcAlloc,
482                                     srcXoff, srcYoff, srcLod, srcFace);
483}
484
485void rsdAllocationData3D_alloc(const android::renderscript::Context *rsc,
486                               const android::renderscript::Allocation *dstAlloc,
487                               uint32_t dstXoff, uint32_t dstYoff, uint32_t dstZoff,
488                               uint32_t dstLod, RsAllocationCubemapFace dstFace,
489                               uint32_t w, uint32_t h, uint32_t d,
490                               const android::renderscript::Allocation *srcAlloc,
491                               uint32_t srcXoff, uint32_t srcYoff, uint32_t srcZoff,
492                               uint32_t srcLod, RsAllocationCubemapFace srcFace) {
493}
494
495void rsdAllocationElementData1D(const Context *rsc, const Allocation *alloc,
496                                uint32_t x,
497                                const void *data, uint32_t cIdx, uint32_t sizeBytes) {
498    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
499
500    uint32_t eSize = alloc->mHal.state.elementSizeBytes;
501    uint8_t * ptr = drv->mallocPtr;
502    ptr += eSize * x;
503
504    const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx);
505    ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx);
506
507    if (alloc->mHal.state.hasReferences) {
508        e->incRefs(data);
509        e->decRefs(ptr);
510    }
511
512    memcpy(ptr, data, sizeBytes);
513    drv->uploadDeferred = true;
514}
515
516void rsdAllocationElementData2D(const Context *rsc, const Allocation *alloc,
517                                uint32_t x, uint32_t y,
518                                const void *data, uint32_t cIdx, uint32_t sizeBytes) {
519    DrvAllocation *drv = (DrvAllocation *)alloc->mHal.drv;
520
521    uint32_t eSize = alloc->mHal.state.elementSizeBytes;
522    uint8_t * ptr = drv->mallocPtr;
523    ptr += eSize * (x + y * alloc->mHal.state.dimensionX);
524
525    const Element * e = alloc->mHal.state.type->getElement()->getField(cIdx);
526    ptr += alloc->mHal.state.type->getElement()->getFieldOffsetBytes(cIdx);
527
528    if (alloc->mHal.state.hasReferences) {
529        e->incRefs(data);
530        e->decRefs(ptr);
531    }
532
533    memcpy(ptr, data, sizeBytes);
534    drv->uploadDeferred = true;
535}
536
537
538