rsAllocation.cpp revision 70b83c111beceaf8fbb700580833e7fec99272cf
1/*
2 * Copyright (C) 2009 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 "rsContext.h"
18#ifndef ANDROID_RS_SERIALIZE
19#include <GLES/gl.h>
20#include <GLES2/gl2.h>
21#include <GLES/glext.h>
22#endif //ANDROID_RS_SERIALIZE
23
24using namespace android;
25using namespace android::renderscript;
26
27Allocation::Allocation(Context *rsc, const Type *type, uint32_t usages,
28                       RsAllocationMipmapControl mc)
29    : ObjectBase(rsc) {
30    init(rsc, type);
31
32    mHal.state.usageFlags = usages;
33    mHal.state.mipmapControl = mc;
34
35    allocScriptMemory();
36    if (mHal.state.type->getElement()->getHasReferences()) {
37        memset(mHal.state.mallocPtr, 0, mHal.state.type->getSizeBytes());
38    }
39    if (!mHal.state.mallocPtr) {
40        LOGE("Allocation::Allocation, alloc failure");
41    }
42}
43
44
45void Allocation::init(Context *rsc, const Type *type) {
46    memset(&mHal, 0, sizeof(mHal));
47    mHal.state.mipmapControl = RS_ALLOCATION_MIPMAP_NONE;
48
49    mCpuWrite = false;
50    mCpuRead = false;
51    mGpuWrite = false;
52    mGpuRead = false;
53
54    mReadWriteRatio = 0;
55    mUpdateSize = 0;
56
57    mTextureID = 0;
58    mBufferID = 0;
59    mRenderTargetID = 0;
60    mUploadDeferred = false;
61
62    mUserBitmapCallback = NULL;
63    mUserBitmapCallbackData = NULL;
64
65    mHal.state.type.set(type);
66    updateCache();
67}
68
69void Allocation::updateCache() {
70    const Type *type = mHal.state.type.get();
71    mHal.state.dimensionX = type->getDimX();
72    mHal.state.dimensionY = type->getDimY();
73    mHal.state.dimensionZ = type->getDimZ();
74    mHal.state.hasFaces = type->getDimFaces();
75    mHal.state.hasMipmaps = type->getDimLOD();
76    mHal.state.elementSizeBytes = type->getElementSizeBytes();
77    mHal.state.hasReferences = mHal.state.type->getElement()->getHasReferences();
78}
79
80Allocation::~Allocation() {
81    if (mUserBitmapCallback != NULL) {
82        mUserBitmapCallback(mUserBitmapCallbackData);
83        mHal.state.mallocPtr = NULL;
84    }
85    freeScriptMemory();
86#ifndef ANDROID_RS_SERIALIZE
87    if (mBufferID) {
88        // Causes a SW crash....
89        //LOGV(" mBufferID %i", mBufferID);
90        //glDeleteBuffers(1, &mBufferID);
91        //mBufferID = 0;
92    }
93    if (mTextureID) {
94        glDeleteTextures(1, &mTextureID);
95        mTextureID = 0;
96    }
97    if (mRenderTargetID) {
98        glDeleteRenderbuffers(1, &mRenderTargetID);
99        mRenderTargetID = 0;
100    }
101#endif //ANDROID_RS_SERIALIZE
102}
103
104void Allocation::setCpuWritable(bool) {
105}
106
107void Allocation::setGpuWritable(bool) {
108}
109
110void Allocation::setCpuReadable(bool) {
111}
112
113void Allocation::setGpuReadable(bool) {
114}
115
116bool Allocation::fixAllocation() {
117    return false;
118}
119
120void Allocation::deferredUploadToTexture(const Context *rsc) {
121    mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE;
122    mUploadDeferred = true;
123}
124
125void Allocation::deferredAllocateRenderTarget(const Context *rsc) {
126    mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET;
127    mUploadDeferred = true;
128}
129
130uint32_t Allocation::getGLTarget() const {
131#ifndef ANDROID_RS_SERIALIZE
132    if (getIsTexture()) {
133        if (mHal.state.type->getDimFaces()) {
134            return GL_TEXTURE_CUBE_MAP;
135        } else {
136            return GL_TEXTURE_2D;
137        }
138    }
139    if (getIsBufferObject()) {
140        return GL_ARRAY_BUFFER;
141    }
142#endif //ANDROID_RS_SERIALIZE
143    return 0;
144}
145
146void Allocation::allocScriptMemory() {
147    rsAssert(!mHal.state.mallocPtr);
148    mHal.state.mallocPtr = malloc(mHal.state.type->getSizeBytes());
149}
150
151void Allocation::freeScriptMemory() {
152    if (mHal.state.mallocPtr) {
153        free(mHal.state.mallocPtr);
154        mHal.state.mallocPtr = NULL;
155    }
156}
157
158
159void Allocation::syncAll(Context *rsc, RsAllocationUsageType src) {
160    rsAssert(src == RS_ALLOCATION_USAGE_SCRIPT);
161
162    if (getIsTexture()) {
163        uploadToTexture(rsc);
164    }
165    if (getIsBufferObject()) {
166        uploadToBufferObject(rsc);
167    }
168    if (getIsRenderTarget() && !getIsTexture()) {
169        allocateRenderTarget(rsc);
170    }
171
172    mUploadDeferred = false;
173}
174
175void Allocation::uploadToTexture(const Context *rsc) {
176#ifndef ANDROID_RS_SERIALIZE
177    mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE;
178    GLenum type = mHal.state.type->getElement()->getComponent().getGLType();
179    GLenum format = mHal.state.type->getElement()->getComponent().getGLFormat();
180
181    if (!type || !format) {
182        return;
183    }
184
185    if (!mHal.state.mallocPtr) {
186        return;
187    }
188
189    bool isFirstUpload = false;
190
191    if (!mTextureID) {
192        glGenTextures(1, &mTextureID);
193
194        if (!mTextureID) {
195            // This should not happen, however, its likely the cause of the
196            // white sqare bug.
197            // Force a crash to 1: restart the app, 2: make sure we get a bugreport.
198            LOGE("Upload to texture failed to gen mTextureID");
199            rsc->dumpDebug();
200            mUploadDeferred = true;
201            return;
202        }
203        isFirstUpload = true;
204    }
205
206    upload2DTexture(isFirstUpload);
207
208    if (!(mHal.state.usageFlags & RS_ALLOCATION_USAGE_SCRIPT)) {
209        freeScriptMemory();
210    }
211
212    rsc->checkError("Allocation::uploadToTexture");
213#endif //ANDROID_RS_SERIALIZE
214}
215
216void Allocation::allocateRenderTarget(const Context *rsc) {
217#ifndef ANDROID_RS_SERIALIZE
218    mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET;
219
220    GLenum format = mHal.state.type->getElement()->getComponent().getGLFormat();
221    if (!format) {
222        return;
223    }
224
225    if (!mRenderTargetID) {
226        glGenRenderbuffers(1, &mRenderTargetID);
227
228        if (!mRenderTargetID) {
229            // This should generally not happen
230            LOGE("allocateRenderTarget failed to gen mRenderTargetID");
231            rsc->dumpDebug();
232            return;
233        }
234        glBindRenderbuffer(GL_RENDERBUFFER, mRenderTargetID);
235        glRenderbufferStorage(GL_RENDERBUFFER, format,
236                              mHal.state.type->getDimX(),
237                              mHal.state.type->getDimY());
238    }
239#endif //ANDROID_RS_SERIALIZE
240}
241
242#ifndef ANDROID_RS_SERIALIZE
243const static GLenum gFaceOrder[] = {
244    GL_TEXTURE_CUBE_MAP_POSITIVE_X,
245    GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
246    GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
247    GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
248    GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
249    GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
250};
251#endif //ANDROID_RS_SERIALIZE
252
253void Allocation::update2DTexture(const void *ptr, uint32_t xoff, uint32_t yoff,
254                                 uint32_t lod, RsAllocationCubemapFace face,
255                                 uint32_t w, uint32_t h) {
256#ifndef ANDROID_RS_SERIALIZE
257    GLenum type = mHal.state.type->getElement()->getComponent().getGLType();
258    GLenum format = mHal.state.type->getElement()->getComponent().getGLFormat();
259    GLenum target = (GLenum)getGLTarget();
260    rsAssert(mTextureID);
261    glBindTexture(target, mTextureID);
262    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
263    GLenum t = GL_TEXTURE_2D;
264    if (mHal.state.hasFaces) {
265        t = gFaceOrder[face];
266    }
267    glTexSubImage2D(t, lod, xoff, yoff, w, h, format, type, ptr);
268#endif //ANDROID_RS_SERIALIZE
269}
270
271void Allocation::upload2DTexture(bool isFirstUpload) {
272#ifndef ANDROID_RS_SERIALIZE
273    GLenum type = mHal.state.type->getElement()->getComponent().getGLType();
274    GLenum format = mHal.state.type->getElement()->getComponent().getGLFormat();
275
276    GLenum target = (GLenum)getGLTarget();
277    glBindTexture(target, mTextureID);
278    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
279
280    uint32_t faceCount = 1;
281    if (mHal.state.hasFaces) {
282        faceCount = 6;
283    }
284
285    for (uint32_t face = 0; face < faceCount; face ++) {
286        for (uint32_t lod = 0; lod < mHal.state.type->getLODCount(); lod++) {
287            const uint8_t *p = (const uint8_t *)mHal.state.mallocPtr;
288            p += mHal.state.type->getLODFaceOffset(lod, (RsAllocationCubemapFace)face, 0, 0);
289
290            GLenum t = GL_TEXTURE_2D;
291            if (mHal.state.hasFaces) {
292                t = gFaceOrder[face];
293            }
294
295            if (isFirstUpload) {
296                glTexImage2D(t, lod, format,
297                             mHal.state.type->getLODDimX(lod), mHal.state.type->getLODDimY(lod),
298                             0, format, type, p);
299            } else {
300                glTexSubImage2D(t, lod, 0, 0,
301                                mHal.state.type->getLODDimX(lod), mHal.state.type->getLODDimY(lod),
302                                format, type, p);
303            }
304        }
305    }
306
307    if (mHal.state.mipmapControl == RS_ALLOCATION_MIPMAP_ON_SYNC_TO_TEXTURE) {
308        glGenerateMipmap(target);
309    }
310#endif //ANDROID_RS_SERIALIZE
311}
312
313void Allocation::deferredUploadToBufferObject(const Context *rsc) {
314    mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX;
315    mUploadDeferred = true;
316}
317
318void Allocation::uploadToBufferObject(const Context *rsc) {
319#ifndef ANDROID_RS_SERIALIZE
320    rsAssert(!mHal.state.type->getDimY());
321    rsAssert(!mHal.state.type->getDimZ());
322
323    mHal.state.usageFlags |= RS_ALLOCATION_USAGE_GRAPHICS_VERTEX;
324
325    if (!mBufferID) {
326        glGenBuffers(1, &mBufferID);
327    }
328    if (!mBufferID) {
329        LOGE("Upload to buffer object failed");
330        mUploadDeferred = true;
331        return;
332    }
333    GLenum target = (GLenum)getGLTarget();
334    glBindBuffer(target, mBufferID);
335    glBufferData(target, mHal.state.type->getSizeBytes(), getPtr(), GL_DYNAMIC_DRAW);
336    glBindBuffer(target, 0);
337    rsc->checkError("Allocation::uploadToBufferObject");
338#endif //ANDROID_RS_SERIALIZE
339}
340
341void Allocation::uploadCheck(Context *rsc) {
342    if (mUploadDeferred) {
343        syncAll(rsc, RS_ALLOCATION_USAGE_SCRIPT);
344    }
345}
346
347void Allocation::read(void *data) {
348    memcpy(data, mHal.state.mallocPtr, mHal.state.type->getSizeBytes());
349}
350
351void Allocation::data(Context *rsc, uint32_t xoff, uint32_t lod,
352                         uint32_t count, const void *data, uint32_t sizeBytes) {
353    uint32_t eSize = mHal.state.type->getElementSizeBytes();
354    uint8_t * ptr = static_cast<uint8_t *>(mHal.state.mallocPtr);
355    ptr += eSize * xoff;
356    uint32_t size = count * eSize;
357
358    if (size != sizeBytes) {
359        LOGE("Allocation::subData called with mismatched size expected %i, got %i", size, sizeBytes);
360        mHal.state.type->dumpLOGV("type info");
361        return;
362    }
363
364    if (mHal.state.hasReferences) {
365        incRefs(data, count);
366        decRefs(ptr, count);
367    }
368
369    memcpy(ptr, data, size);
370    sendDirty();
371    mUploadDeferred = true;
372}
373
374void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
375             uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) {
376    uint32_t eSize = mHal.state.elementSizeBytes;
377    uint32_t lineSize = eSize * w;
378    uint32_t destW = mHal.state.dimensionX;
379
380    //LOGE("data2d %p,  %i %i %i %i %i %i %p %i", this, xoff, yoff, lod, face, w, h, data, sizeBytes);
381
382    if ((lineSize * h) != sizeBytes) {
383        LOGE("Allocation size mismatch, expected %i, got %i", (lineSize * h), sizeBytes);
384        rsAssert(!"Allocation::subData called with mismatched size");
385        return;
386    }
387
388    if (mHal.state.mallocPtr) {
389        const uint8_t *src = static_cast<const uint8_t *>(data);
390        uint8_t *dst = static_cast<uint8_t *>(mHal.state.mallocPtr);
391        dst += mHal.state.type->getLODFaceOffset(lod, face, xoff, yoff);
392
393        //LOGE("            %p  %p  %i  ", dst, src, eSize);
394        for (uint32_t line=yoff; line < (yoff+h); line++) {
395            if (mHal.state.hasReferences) {
396                incRefs(src, w);
397                decRefs(dst, w);
398            }
399            memcpy(dst, src, lineSize);
400            src += lineSize;
401            dst += destW * eSize;
402        }
403        sendDirty();
404        mUploadDeferred = true;
405    } else {
406        update2DTexture(data, xoff, yoff, lod, face, w, h);
407    }
408}
409
410void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff,
411                      uint32_t lod, RsAllocationCubemapFace face,
412                      uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) {
413}
414
415void Allocation::elementData(Context *rsc, uint32_t x, const void *data,
416                                uint32_t cIdx, uint32_t sizeBytes) {
417    uint32_t eSize = mHal.state.elementSizeBytes;
418    uint8_t * ptr = static_cast<uint8_t *>(mHal.state.mallocPtr);
419    ptr += eSize * x;
420
421    if (cIdx >= mHal.state.type->getElement()->getFieldCount()) {
422        LOGE("Error Allocation::subElementData component %i out of range.", cIdx);
423        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData component out of range.");
424        return;
425    }
426
427    if (x >= mHal.state.dimensionX) {
428        LOGE("Error Allocation::subElementData X offset %i out of range.", x);
429        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range.");
430        return;
431    }
432
433    const Element * e = mHal.state.type->getElement()->getField(cIdx);
434    ptr += mHal.state.type->getElement()->getFieldOffsetBytes(cIdx);
435
436    if (sizeBytes != e->getSizeBytes()) {
437        LOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes());
438        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size.");
439        return;
440    }
441
442    if (e->getHasReferences()) {
443        e->incRefs(data);
444        e->decRefs(ptr);
445    }
446
447    memcpy(ptr, data, sizeBytes);
448    sendDirty();
449    mUploadDeferred = true;
450}
451
452void Allocation::elementData(Context *rsc, uint32_t x, uint32_t y,
453                                const void *data, uint32_t cIdx, uint32_t sizeBytes) {
454    uint32_t eSize = mHal.state.elementSizeBytes;
455    uint8_t * ptr = static_cast<uint8_t *>(mHal.state.mallocPtr);
456    ptr += eSize * (x + y * mHal.state.dimensionX);
457
458    if (x >= mHal.state.dimensionX) {
459        LOGE("Error Allocation::subElementData X offset %i out of range.", x);
460        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range.");
461        return;
462    }
463
464    if (y >= mHal.state.dimensionY) {
465        LOGE("Error Allocation::subElementData X offset %i out of range.", x);
466        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range.");
467        return;
468    }
469
470    if (cIdx >= mHal.state.type->getElement()->getFieldCount()) {
471        LOGE("Error Allocation::subElementData component %i out of range.", cIdx);
472        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData component out of range.");
473        return;
474    }
475
476    const Element * e = mHal.state.type->getElement()->getField(cIdx);
477    ptr += mHal.state.type->getElement()->getFieldOffsetBytes(cIdx);
478
479    if (sizeBytes != e->getSizeBytes()) {
480        LOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes());
481        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size.");
482        return;
483    }
484
485    if (e->getHasReferences()) {
486        e->incRefs(data);
487        e->decRefs(ptr);
488    }
489
490    memcpy(ptr, data, sizeBytes);
491    sendDirty();
492    mUploadDeferred = true;
493}
494
495void Allocation::addProgramToDirty(const Program *p) {
496#ifndef ANDROID_RS_SERIALIZE
497    mToDirtyList.push(p);
498#endif //ANDROID_RS_SERIALIZE
499}
500
501void Allocation::removeProgramToDirty(const Program *p) {
502#ifndef ANDROID_RS_SERIALIZE
503    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
504        if (mToDirtyList[ct] == p) {
505            mToDirtyList.removeAt(ct);
506            return;
507        }
508    }
509    rsAssert(0);
510#endif //ANDROID_RS_SERIALIZE
511}
512
513void Allocation::dumpLOGV(const char *prefix) const {
514    ObjectBase::dumpLOGV(prefix);
515
516    String8 s(prefix);
517    s.append(" type ");
518    if (mHal.state.type.get()) {
519        mHal.state.type->dumpLOGV(s.string());
520    }
521
522    LOGV("%s allocation ptr=%p mCpuWrite=%i, mCpuRead=%i, mGpuWrite=%i, mGpuRead=%i",
523          prefix, mHal.state.mallocPtr, mCpuWrite, mCpuRead, mGpuWrite, mGpuRead);
524
525    LOGV("%s allocation mUsageFlags=0x04%x, mMipmapControl=0x%04x, mTextureID=%i, mBufferID=%i",
526          prefix, mHal.state.usageFlags, mHal.state.mipmapControl, mTextureID, mBufferID);
527}
528
529void Allocation::serialize(OStream *stream) const {
530    // Need to identify ourselves
531    stream->addU32((uint32_t)getClassId());
532
533    String8 name(getName());
534    stream->addString(&name);
535
536    // First thing we need to serialize is the type object since it will be needed
537    // to initialize the class
538    mHal.state.type->serialize(stream);
539
540    uint32_t dataSize = mHal.state.type->getSizeBytes();
541    // Write how much data we are storing
542    stream->addU32(dataSize);
543    // Now write the data
544    stream->addByteArray(mHal.state.mallocPtr, dataSize);
545}
546
547Allocation *Allocation::createFromStream(Context *rsc, IStream *stream) {
548    // First make sure we are reading the correct object
549    RsA3DClassID classID = (RsA3DClassID)stream->loadU32();
550    if (classID != RS_A3D_CLASS_ID_ALLOCATION) {
551        LOGE("allocation loading skipped due to invalid class id\n");
552        return NULL;
553    }
554
555    String8 name;
556    stream->loadString(&name);
557
558    Type *type = Type::createFromStream(rsc, stream);
559    if (!type) {
560        return NULL;
561    }
562    type->compute();
563
564    // Number of bytes we wrote out for this allocation
565    uint32_t dataSize = stream->loadU32();
566    if (dataSize != type->getSizeBytes()) {
567        LOGE("failed to read allocation because numbytes written is not the same loaded type wants\n");
568        ObjectBase::checkDelete(type);
569        return NULL;
570    }
571
572    Allocation *alloc = new Allocation(rsc, type, RS_ALLOCATION_USAGE_SCRIPT);
573    alloc->setName(name.string(), name.size());
574
575    uint32_t count = dataSize / type->getElementSizeBytes();
576
577    // Read in all of our allocation data
578    alloc->data(rsc, 0, 0, count, stream->getPtr() + stream->getPos(), dataSize);
579    stream->reset(stream->getPos() + dataSize);
580
581    return alloc;
582}
583
584void Allocation::sendDirty() const {
585#ifndef ANDROID_RS_SERIALIZE
586    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
587        mToDirtyList[ct]->forceDirty();
588    }
589#endif //ANDROID_RS_SERIALIZE
590}
591
592void Allocation::incRefs(const void *ptr, size_t ct, size_t startOff) const {
593    const uint8_t *p = static_cast<const uint8_t *>(ptr);
594    const Element *e = mHal.state.type->getElement();
595    uint32_t stride = e->getSizeBytes();
596
597    p += stride * startOff;
598    while (ct > 0) {
599        e->incRefs(p);
600        ct --;
601        p += stride;
602    }
603}
604
605void Allocation::decRefs(const void *ptr, size_t ct, size_t startOff) const {
606    const uint8_t *p = static_cast<const uint8_t *>(ptr);
607    const Element *e = mHal.state.type->getElement();
608    uint32_t stride = e->getSizeBytes();
609
610    p += stride * startOff;
611    while (ct > 0) {
612        e->decRefs(p);
613        ct --;
614        p += stride;
615    }
616}
617
618void Allocation::copyRange1D(Context *rsc, const Allocation *src, int32_t srcOff, int32_t destOff, int32_t len) {
619}
620
621void Allocation::resize1D(Context *rsc, uint32_t dimX) {
622    Type *t = mHal.state.type->cloneAndResize1D(rsc, dimX);
623
624    uint32_t oldDimX = mHal.state.dimensionX;
625    if (dimX == oldDimX) {
626        return;
627    }
628
629    if (dimX < oldDimX) {
630        decRefs(mHal.state.mallocPtr, oldDimX - dimX, dimX);
631    }
632    mHal.state.mallocPtr = realloc(mHal.state.mallocPtr, t->getSizeBytes());
633
634    if (dimX > oldDimX) {
635        const Element *e = mHal.state.type->getElement();
636        uint32_t stride = e->getSizeBytes();
637        memset(((uint8_t *)mHal.state.mallocPtr) + stride * oldDimX, 0, stride * (dimX - oldDimX));
638    }
639
640    mHal.state.type.set(t);
641    updateCache();
642}
643
644void Allocation::resize2D(Context *rsc, uint32_t dimX, uint32_t dimY) {
645    LOGE("not implemented");
646}
647
648/////////////////
649//
650#ifndef ANDROID_RS_SERIALIZE
651
652static void rsaAllocationGenerateScriptMips(RsContext con, RsAllocation va);
653
654namespace android {
655namespace renderscript {
656
657void rsi_AllocationUploadToTexture(Context *rsc, RsAllocation va, bool genmip, uint32_t baseMipLevel) {
658    Allocation *alloc = static_cast<Allocation *>(va);
659    alloc->deferredUploadToTexture(rsc);
660}
661
662void rsi_AllocationUploadToBufferObject(Context *rsc, RsAllocation va) {
663    Allocation *alloc = static_cast<Allocation *>(va);
664    alloc->deferredUploadToBufferObject(rsc);
665}
666
667static void mip565(const Adapter2D &out, const Adapter2D &in) {
668    uint32_t w = out.getDimX();
669    uint32_t h = out.getDimY();
670
671    for (uint32_t y=0; y < h; y++) {
672        uint16_t *oPtr = static_cast<uint16_t *>(out.getElement(0, y));
673        const uint16_t *i1 = static_cast<uint16_t *>(in.getElement(0, y*2));
674        const uint16_t *i2 = static_cast<uint16_t *>(in.getElement(0, y*2+1));
675
676        for (uint32_t x=0; x < w; x++) {
677            *oPtr = rsBoxFilter565(i1[0], i1[1], i2[0], i2[1]);
678            oPtr ++;
679            i1 += 2;
680            i2 += 2;
681        }
682    }
683}
684
685static void mip8888(const Adapter2D &out, const Adapter2D &in) {
686    uint32_t w = out.getDimX();
687    uint32_t h = out.getDimY();
688
689    for (uint32_t y=0; y < h; y++) {
690        uint32_t *oPtr = static_cast<uint32_t *>(out.getElement(0, y));
691        const uint32_t *i1 = static_cast<uint32_t *>(in.getElement(0, y*2));
692        const uint32_t *i2 = static_cast<uint32_t *>(in.getElement(0, y*2+1));
693
694        for (uint32_t x=0; x < w; x++) {
695            *oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]);
696            oPtr ++;
697            i1 += 2;
698            i2 += 2;
699        }
700    }
701}
702
703static void mip8(const Adapter2D &out, const Adapter2D &in) {
704    uint32_t w = out.getDimX();
705    uint32_t h = out.getDimY();
706
707    for (uint32_t y=0; y < h; y++) {
708        uint8_t *oPtr = static_cast<uint8_t *>(out.getElement(0, y));
709        const uint8_t *i1 = static_cast<uint8_t *>(in.getElement(0, y*2));
710        const uint8_t *i2 = static_cast<uint8_t *>(in.getElement(0, y*2+1));
711
712        for (uint32_t x=0; x < w; x++) {
713            *oPtr = (uint8_t)(((uint32_t)i1[0] + i1[1] + i2[0] + i2[1]) * 0.25f);
714            oPtr ++;
715            i1 += 2;
716            i2 += 2;
717        }
718    }
719}
720
721static void mip(const Adapter2D &out, const Adapter2D &in) {
722    switch (out.getBaseType()->getElement()->getSizeBits()) {
723    case 32:
724        mip8888(out, in);
725        break;
726    case 16:
727        mip565(out, in);
728        break;
729    case 8:
730        mip8(out, in);
731        break;
732    }
733}
734
735void rsi_AllocationSyncAll(Context *rsc, RsAllocation va, RsAllocationUsageType src) {
736    Allocation *a = static_cast<Allocation *>(va);
737    a->syncAll(rsc, src);
738    a->sendDirty();
739}
740
741void rsi_AllocationGenerateMipmaps(Context *rsc, RsAllocation va) {
742    Allocation *texAlloc = static_cast<Allocation *>(va);
743    rsaAllocationGenerateScriptMips(rsc, texAlloc);
744}
745
746void rsi_AllocationCopyToBitmap(Context *rsc, RsAllocation va, void *data, size_t dataLen) {
747    Allocation *texAlloc = static_cast<Allocation *>(va);
748    const Type * t = texAlloc->getType();
749
750    size_t s = t->getDimX() * t->getDimY() * t->getElementSizeBytes();
751    if (s != dataLen) {
752        rsc->setError(RS_ERROR_BAD_VALUE, "Bitmap size didn't match allocation size");
753        return;
754    }
755
756    memcpy(data, texAlloc->getPtr(), s);
757}
758
759void rsi_Allocation1DData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t lod,
760                          uint32_t count, const void *data, uint32_t sizeBytes) {
761    Allocation *a = static_cast<Allocation *>(va);
762    a->data(rsc, xoff, lod, count, data, sizeBytes);
763}
764
765void rsi_Allocation2DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t y, uint32_t lod, RsAllocationCubemapFace face,
766                                 const void *data, uint32_t eoff, uint32_t sizeBytes) {
767    Allocation *a = static_cast<Allocation *>(va);
768    a->elementData(rsc, x, y, data, eoff, sizeBytes);
769}
770
771void rsi_Allocation1DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t lod,
772                                 const void *data, uint32_t eoff, uint32_t sizeBytes) {
773    Allocation *a = static_cast<Allocation *>(va);
774    a->elementData(rsc, x, data, eoff, sizeBytes);
775}
776
777void rsi_Allocation2DData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
778                          uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) {
779    Allocation *a = static_cast<Allocation *>(va);
780    a->data(rsc, xoff, yoff, lod, face, w, h, data, sizeBytes);
781}
782
783void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data, size_t data_length) {
784    Allocation *a = static_cast<Allocation *>(va);
785    a->read(data);
786}
787
788void rsi_AllocationResize1D(Context *rsc, RsAllocation va, uint32_t dimX) {
789    Allocation *a = static_cast<Allocation *>(va);
790    a->resize1D(rsc, dimX);
791}
792
793void rsi_AllocationResize2D(Context *rsc, RsAllocation va, uint32_t dimX, uint32_t dimY) {
794    Allocation *a = static_cast<Allocation *>(va);
795    a->resize2D(rsc, dimX, dimY);
796}
797
798}
799}
800
801static void rsaAllocationGenerateScriptMips(RsContext con, RsAllocation va) {
802    Context *rsc = static_cast<Context *>(con);
803    Allocation *texAlloc = static_cast<Allocation *>(va);
804    uint32_t numFaces = texAlloc->getType()->getDimFaces() ? 6 : 1;
805    for (uint32_t face = 0; face < numFaces; face ++) {
806        Adapter2D adapt(rsc, texAlloc);
807        Adapter2D adapt2(rsc, texAlloc);
808        adapt.setFace(face);
809        adapt2.setFace(face);
810        for (uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
811            adapt.setLOD(lod);
812            adapt2.setLOD(lod + 1);
813            mip(adapt2, adapt);
814        }
815    }
816}
817
818const void * rsaAllocationGetType(RsContext con, RsAllocation va) {
819    Allocation *a = static_cast<Allocation *>(va);
820    a->getType()->incUserRef();
821
822    return a->getType();
823}
824
825RsAllocation rsaAllocationCreateTyped(RsContext con, RsType vtype,
826                                      RsAllocationMipmapControl mips,
827                                      uint32_t usages) {
828    Context *rsc = static_cast<Context *>(con);
829    Allocation * alloc = new Allocation(rsc, static_cast<Type *>(vtype), usages, mips);
830    alloc->incUserRef();
831    return alloc;
832}
833
834RsAllocation rsaAllocationCreateFromBitmap(RsContext con, RsType vtype,
835                                           RsAllocationMipmapControl mips,
836                                           const void *data, uint32_t usages) {
837    Context *rsc = static_cast<Context *>(con);
838    Type *t = static_cast<Type *>(vtype);
839
840    RsAllocation vTexAlloc = rsaAllocationCreateTyped(rsc, vtype, mips, usages);
841    Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
842    if (texAlloc == NULL) {
843        LOGE("Memory allocation failure");
844        return NULL;
845    }
846
847    memcpy(texAlloc->getPtr(), data, t->getDimX() * t->getDimY() * t->getElementSizeBytes());
848    if (mips == RS_ALLOCATION_MIPMAP_FULL) {
849        rsaAllocationGenerateScriptMips(rsc, texAlloc);
850    }
851
852    texAlloc->deferredUploadToTexture(rsc);
853    return texAlloc;
854}
855
856RsAllocation rsaAllocationCubeCreateFromBitmap(RsContext con, RsType vtype,
857                                               RsAllocationMipmapControl mips,
858                                               const void *data, uint32_t usages) {
859    Context *rsc = static_cast<Context *>(con);
860    Type *t = static_cast<Type *>(vtype);
861
862    // Cubemap allocation's faces should be Width by Width each.
863    // Source data should have 6 * Width by Width pixels
864    // Error checking is done in the java layer
865    RsAllocation vTexAlloc = rsaAllocationCreateTyped(rsc, t, mips, usages);
866    Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
867    if (texAlloc == NULL) {
868        LOGE("Memory allocation failure");
869        return NULL;
870    }
871
872    uint32_t faceSize = t->getDimX();
873    uint32_t strideBytes = faceSize * 6 * t->getElementSizeBytes();
874    uint32_t copySize = faceSize * t->getElementSizeBytes();
875
876    uint8_t *sourcePtr = (uint8_t*)data;
877    for (uint32_t face = 0; face < 6; face ++) {
878        Adapter2D faceAdapter(rsc, texAlloc);
879        faceAdapter.setFace(face);
880
881        for (uint32_t dI = 0; dI < faceSize; dI ++) {
882            memcpy(faceAdapter.getElement(0, dI), sourcePtr + strideBytes * dI, copySize);
883        }
884
885        // Move the data pointer to the next cube face
886        sourcePtr += copySize;
887    }
888
889    if (mips == RS_ALLOCATION_MIPMAP_FULL) {
890        rsaAllocationGenerateScriptMips(rsc, texAlloc);
891    }
892
893    texAlloc->deferredUploadToTexture(rsc);
894    return texAlloc;
895}
896
897#endif //ANDROID_RS_SERIALIZE
898