rsAllocation.cpp revision b81a0eb8180791e4eaab1253b59fa8bd562b046b
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#include "rs_hal.h"
19
20
21using namespace android;
22using namespace android::renderscript;
23
24Allocation::Allocation(Context *rsc, const Type *type, uint32_t usages,
25                       RsAllocationMipmapControl mc)
26    : ObjectBase(rsc) {
27
28    memset(&mHal, 0, sizeof(mHal));
29    mHal.state.mipmapControl = RS_ALLOCATION_MIPMAP_NONE;
30    mHal.state.usageFlags = usages;
31    mHal.state.mipmapControl = mc;
32
33    mHal.state.type.set(type);
34    updateCache();
35}
36
37Allocation * Allocation::createAllocation(Context *rsc, const Type *type, uint32_t usages,
38                              RsAllocationMipmapControl mc) {
39    Allocation *a = new Allocation(rsc, type, usages, mc);
40
41    if (!rsc->mHal.funcs.allocation.init(rsc, a, type->getElement()->getHasReferences())) {
42        rsc->setError(RS_ERROR_FATAL_DRIVER, "Allocation::Allocation, alloc failure");
43        delete a;
44        return NULL;
45    }
46    return a;
47}
48
49void Allocation::updateCache() {
50    const Type *type = mHal.state.type.get();
51    mHal.state.dimensionX = type->getDimX();
52    mHal.state.dimensionY = type->getDimY();
53    mHal.state.dimensionZ = type->getDimZ();
54    mHal.state.hasFaces = type->getDimFaces();
55    mHal.state.hasMipmaps = type->getDimLOD();
56    mHal.state.elementSizeBytes = type->getElementSizeBytes();
57    mHal.state.hasReferences = mHal.state.type->getElement()->getHasReferences();
58}
59
60Allocation::~Allocation() {
61    mRSC->mHal.funcs.allocation.destroy(mRSC, this);
62}
63
64void Allocation::syncAll(Context *rsc, RsAllocationUsageType src) {
65    rsc->mHal.funcs.allocation.syncAll(rsc, this, src);
66}
67
68void Allocation::read(void *data) {
69    memcpy(data, getPtr(), mHal.state.type->getSizeBytes());
70}
71
72void Allocation::data(Context *rsc, uint32_t xoff, uint32_t lod,
73                         uint32_t count, const void *data, uint32_t sizeBytes) {
74    const uint32_t eSize = mHal.state.type->getElementSizeBytes();
75
76    if ((count * eSize) != sizeBytes) {
77        LOGE("Allocation::subData called with mismatched size expected %i, got %i",
78             (count * eSize), sizeBytes);
79        mHal.state.type->dumpLOGV("type info");
80        return;
81    }
82
83    rsc->mHal.funcs.allocation.data1D(rsc, this, xoff, lod, count, data, sizeBytes);
84    sendDirty(rsc);
85}
86
87void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
88             uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) {
89    const uint32_t eSize = mHal.state.elementSizeBytes;
90    const uint32_t lineSize = eSize * w;
91
92    //LOGE("data2d %p,  %i %i %i %i %i %i %p %i", this, xoff, yoff, lod, face, w, h, data, sizeBytes);
93
94    if ((lineSize * h) != sizeBytes) {
95        LOGE("Allocation size mismatch, expected %i, got %i", (lineSize * h), sizeBytes);
96        rsAssert(!"Allocation::subData called with mismatched size");
97        return;
98    }
99
100    rsc->mHal.funcs.allocation.data2D(rsc, this, xoff, yoff, lod, face, w, h, data, sizeBytes);
101    sendDirty(rsc);
102}
103
104void Allocation::data(Context *rsc, uint32_t xoff, uint32_t yoff, uint32_t zoff,
105                      uint32_t lod, RsAllocationCubemapFace face,
106                      uint32_t w, uint32_t h, uint32_t d, const void *data, uint32_t sizeBytes) {
107}
108
109void Allocation::elementData(Context *rsc, uint32_t x, const void *data,
110                                uint32_t cIdx, uint32_t sizeBytes) {
111    uint32_t eSize = mHal.state.elementSizeBytes;
112
113    if (cIdx >= mHal.state.type->getElement()->getFieldCount()) {
114        LOGE("Error Allocation::subElementData component %i out of range.", cIdx);
115        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData component out of range.");
116        return;
117    }
118
119    if (x >= mHal.state.dimensionX) {
120        LOGE("Error Allocation::subElementData X offset %i out of range.", x);
121        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range.");
122        return;
123    }
124
125    const Element * e = mHal.state.type->getElement()->getField(cIdx);
126    if (sizeBytes != e->getSizeBytes()) {
127        LOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes());
128        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size.");
129        return;
130    }
131
132    rsc->mHal.funcs.allocation.elementData1D(rsc, this, x, data, cIdx, sizeBytes);
133    sendDirty(rsc);
134}
135
136void Allocation::elementData(Context *rsc, uint32_t x, uint32_t y,
137                                const void *data, uint32_t cIdx, uint32_t sizeBytes) {
138    uint32_t eSize = mHal.state.elementSizeBytes;
139
140    if (x >= mHal.state.dimensionX) {
141        LOGE("Error Allocation::subElementData X offset %i out of range.", x);
142        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range.");
143        return;
144    }
145
146    if (y >= mHal.state.dimensionY) {
147        LOGE("Error Allocation::subElementData X offset %i out of range.", x);
148        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData X offset out of range.");
149        return;
150    }
151
152    if (cIdx >= mHal.state.type->getElement()->getFieldCount()) {
153        LOGE("Error Allocation::subElementData component %i out of range.", cIdx);
154        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData component out of range.");
155        return;
156    }
157
158    const Element * e = mHal.state.type->getElement()->getField(cIdx);
159
160    if (sizeBytes != e->getSizeBytes()) {
161        LOGE("Error Allocation::subElementData data size %i does not match field size %zu.", sizeBytes, e->getSizeBytes());
162        rsc->setError(RS_ERROR_BAD_VALUE, "subElementData bad size.");
163        return;
164    }
165
166    rsc->mHal.funcs.allocation.elementData2D(rsc, this, x, y, data, cIdx, sizeBytes);
167    sendDirty(rsc);
168}
169
170void Allocation::addProgramToDirty(const Program *p) {
171    mToDirtyList.push(p);
172}
173
174void Allocation::removeProgramToDirty(const Program *p) {
175    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
176        if (mToDirtyList[ct] == p) {
177            mToDirtyList.removeAt(ct);
178            return;
179        }
180    }
181    rsAssert(0);
182}
183
184void Allocation::dumpLOGV(const char *prefix) const {
185    ObjectBase::dumpLOGV(prefix);
186
187    String8 s(prefix);
188    s.append(" type ");
189    if (mHal.state.type.get()) {
190        mHal.state.type->dumpLOGV(s.string());
191    }
192
193    LOGV("%s allocation ptr=%p  mUsageFlags=0x04%x, mMipmapControl=0x%04x",
194         prefix, getPtr(), mHal.state.usageFlags, mHal.state.mipmapControl);
195}
196
197void Allocation::serialize(OStream *stream) const {
198    // Need to identify ourselves
199    stream->addU32((uint32_t)getClassId());
200
201    String8 name(getName());
202    stream->addString(&name);
203
204    // First thing we need to serialize is the type object since it will be needed
205    // to initialize the class
206    mHal.state.type->serialize(stream);
207
208    uint32_t dataSize = mHal.state.type->getSizeBytes();
209    // Write how much data we are storing
210    stream->addU32(dataSize);
211    // Now write the data
212    stream->addByteArray(getPtr(), dataSize);
213}
214
215Allocation *Allocation::createFromStream(Context *rsc, IStream *stream) {
216    // First make sure we are reading the correct object
217    RsA3DClassID classID = (RsA3DClassID)stream->loadU32();
218    if (classID != RS_A3D_CLASS_ID_ALLOCATION) {
219        LOGE("allocation loading skipped due to invalid class id\n");
220        return NULL;
221    }
222
223    String8 name;
224    stream->loadString(&name);
225
226    Type *type = Type::createFromStream(rsc, stream);
227    if (!type) {
228        return NULL;
229    }
230    type->compute();
231
232    // Number of bytes we wrote out for this allocation
233    uint32_t dataSize = stream->loadU32();
234    if (dataSize != type->getSizeBytes()) {
235        LOGE("failed to read allocation because numbytes written is not the same loaded type wants\n");
236        ObjectBase::checkDelete(type);
237        return NULL;
238    }
239
240    Allocation *alloc = Allocation::createAllocation(rsc, type, RS_ALLOCATION_USAGE_SCRIPT);
241    alloc->setName(name.string(), name.size());
242
243    uint32_t count = dataSize / type->getElementSizeBytes();
244
245    // Read in all of our allocation data
246    alloc->data(rsc, 0, 0, count, stream->getPtr() + stream->getPos(), dataSize);
247    stream->reset(stream->getPos() + dataSize);
248
249    return alloc;
250}
251
252void Allocation::sendDirty(const Context *rsc) const {
253    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
254        mToDirtyList[ct]->forceDirty();
255    }
256    mRSC->mHal.funcs.allocation.markDirty(rsc, this);
257}
258
259void Allocation::incRefs(const void *ptr, size_t ct, size_t startOff) const {
260    const uint8_t *p = static_cast<const uint8_t *>(ptr);
261    const Element *e = mHal.state.type->getElement();
262    uint32_t stride = e->getSizeBytes();
263
264    p += stride * startOff;
265    while (ct > 0) {
266        e->incRefs(p);
267        ct --;
268        p += stride;
269    }
270}
271
272void Allocation::decRefs(const void *ptr, size_t ct, size_t startOff) const {
273    const uint8_t *p = static_cast<const uint8_t *>(ptr);
274    const Element *e = mHal.state.type->getElement();
275    uint32_t stride = e->getSizeBytes();
276
277    p += stride * startOff;
278    while (ct > 0) {
279        e->decRefs(p);
280        ct --;
281        p += stride;
282    }
283}
284
285void Allocation::copyRange1D(Context *rsc, const Allocation *src, int32_t srcOff, int32_t destOff, int32_t len) {
286}
287
288void Allocation::resize1D(Context *rsc, uint32_t dimX) {
289    uint32_t oldDimX = mHal.state.dimensionX;
290    if (dimX == oldDimX) {
291        return;
292    }
293
294    Type *t = mHal.state.type->cloneAndResize1D(rsc, dimX);
295    if (dimX < oldDimX) {
296        decRefs(getPtr(), oldDimX - dimX, dimX);
297    }
298    rsc->mHal.funcs.allocation.resize(rsc, this, t, mHal.state.hasReferences);
299    mHal.state.type.set(t);
300    updateCache();
301}
302
303void Allocation::resize2D(Context *rsc, uint32_t dimX, uint32_t dimY) {
304    LOGE("not implemented");
305}
306
307/////////////////
308//
309
310namespace android {
311namespace renderscript {
312
313static void AllocationGenerateScriptMips(RsContext con, RsAllocation va);
314
315static void mip565(const Adapter2D &out, const Adapter2D &in) {
316    uint32_t w = out.getDimX();
317    uint32_t h = out.getDimY();
318
319    for (uint32_t y=0; y < h; y++) {
320        uint16_t *oPtr = static_cast<uint16_t *>(out.getElement(0, y));
321        const uint16_t *i1 = static_cast<uint16_t *>(in.getElement(0, y*2));
322        const uint16_t *i2 = static_cast<uint16_t *>(in.getElement(0, y*2+1));
323
324        for (uint32_t x=0; x < w; x++) {
325            *oPtr = rsBoxFilter565(i1[0], i1[1], i2[0], i2[1]);
326            oPtr ++;
327            i1 += 2;
328            i2 += 2;
329        }
330    }
331}
332
333static void mip8888(const Adapter2D &out, const Adapter2D &in) {
334    uint32_t w = out.getDimX();
335    uint32_t h = out.getDimY();
336
337    for (uint32_t y=0; y < h; y++) {
338        uint32_t *oPtr = static_cast<uint32_t *>(out.getElement(0, y));
339        const uint32_t *i1 = static_cast<uint32_t *>(in.getElement(0, y*2));
340        const uint32_t *i2 = static_cast<uint32_t *>(in.getElement(0, y*2+1));
341
342        for (uint32_t x=0; x < w; x++) {
343            *oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]);
344            oPtr ++;
345            i1 += 2;
346            i2 += 2;
347        }
348    }
349}
350
351static void mip8(const Adapter2D &out, const Adapter2D &in) {
352    uint32_t w = out.getDimX();
353    uint32_t h = out.getDimY();
354
355    for (uint32_t y=0; y < h; y++) {
356        uint8_t *oPtr = static_cast<uint8_t *>(out.getElement(0, y));
357        const uint8_t *i1 = static_cast<uint8_t *>(in.getElement(0, y*2));
358        const uint8_t *i2 = static_cast<uint8_t *>(in.getElement(0, y*2+1));
359
360        for (uint32_t x=0; x < w; x++) {
361            *oPtr = (uint8_t)(((uint32_t)i1[0] + i1[1] + i2[0] + i2[1]) * 0.25f);
362            oPtr ++;
363            i1 += 2;
364            i2 += 2;
365        }
366    }
367}
368
369static void mip(const Adapter2D &out, const Adapter2D &in) {
370    switch (out.getBaseType()->getElement()->getSizeBits()) {
371    case 32:
372        mip8888(out, in);
373        break;
374    case 16:
375        mip565(out, in);
376        break;
377    case 8:
378        mip8(out, in);
379        break;
380    }
381}
382
383void rsi_AllocationSyncAll(Context *rsc, RsAllocation va, RsAllocationUsageType src) {
384    Allocation *a = static_cast<Allocation *>(va);
385    a->sendDirty(rsc);
386    a->syncAll(rsc, src);
387}
388
389void rsi_AllocationGenerateMipmaps(Context *rsc, RsAllocation va) {
390    Allocation *texAlloc = static_cast<Allocation *>(va);
391    AllocationGenerateScriptMips(rsc, texAlloc);
392}
393
394void rsi_AllocationCopyToBitmap(Context *rsc, RsAllocation va, void *data, size_t dataLen) {
395    Allocation *texAlloc = static_cast<Allocation *>(va);
396    const Type * t = texAlloc->getType();
397
398    size_t s = t->getDimX() * t->getDimY() * t->getElementSizeBytes();
399    if (s != dataLen) {
400        rsc->setError(RS_ERROR_BAD_VALUE, "Bitmap size didn't match allocation size");
401        return;
402    }
403
404    memcpy(data, texAlloc->getPtr(), s);
405}
406
407void rsi_Allocation1DData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t lod,
408                          uint32_t count, const void *data, size_t sizeBytes) {
409    Allocation *a = static_cast<Allocation *>(va);
410    a->data(rsc, xoff, lod, count, data, sizeBytes);
411}
412
413void rsi_Allocation2DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t y, uint32_t lod, RsAllocationCubemapFace face,
414                                 const void *data, size_t eoff, uint32_t sizeBytes) { // TODO: this seems wrong, eoff and sizeBytes may be swapped
415    Allocation *a = static_cast<Allocation *>(va);
416    a->elementData(rsc, x, y, data, eoff, sizeBytes);
417}
418
419void rsi_Allocation1DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t lod,
420                                 const void *data, size_t eoff, uint32_t sizeBytes) { // TODO: this seems wrong, eoff and sizeBytes may be swapped
421    Allocation *a = static_cast<Allocation *>(va);
422    a->elementData(rsc, x, data, eoff, sizeBytes);
423}
424
425void rsi_Allocation2DData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
426                          uint32_t w, uint32_t h, const void *data, size_t sizeBytes) {
427    Allocation *a = static_cast<Allocation *>(va);
428    a->data(rsc, xoff, yoff, lod, face, w, h, data, sizeBytes);
429}
430
431void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data, size_t data_length) {
432    Allocation *a = static_cast<Allocation *>(va);
433    a->read(data);
434}
435
436void rsi_AllocationResize1D(Context *rsc, RsAllocation va, uint32_t dimX) {
437    Allocation *a = static_cast<Allocation *>(va);
438    a->resize1D(rsc, dimX);
439}
440
441void rsi_AllocationResize2D(Context *rsc, RsAllocation va, uint32_t dimX, uint32_t dimY) {
442    Allocation *a = static_cast<Allocation *>(va);
443    a->resize2D(rsc, dimX, dimY);
444}
445
446static void AllocationGenerateScriptMips(RsContext con, RsAllocation va) {
447    Context *rsc = static_cast<Context *>(con);
448    Allocation *texAlloc = static_cast<Allocation *>(va);
449    uint32_t numFaces = texAlloc->getType()->getDimFaces() ? 6 : 1;
450    for (uint32_t face = 0; face < numFaces; face ++) {
451        Adapter2D adapt(rsc, texAlloc);
452        Adapter2D adapt2(rsc, texAlloc);
453        adapt.setFace(face);
454        adapt2.setFace(face);
455        for (uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
456            adapt.setLOD(lod);
457            adapt2.setLOD(lod + 1);
458            mip(adapt2, adapt);
459        }
460    }
461}
462
463RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype,
464                                       RsAllocationMipmapControl mips,
465                                       uint32_t usages) {
466    Allocation * alloc = Allocation::createAllocation(rsc, static_cast<Type *>(vtype), usages, mips);
467    if (!alloc) {
468        return NULL;
469    }
470    alloc->incUserRef();
471    return alloc;
472}
473
474RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, RsType vtype,
475                                            RsAllocationMipmapControl mips,
476                                            const void *data, size_t data_length, uint32_t usages) {
477    Type *t = static_cast<Type *>(vtype);
478
479    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages);
480    Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
481    if (texAlloc == NULL) {
482        LOGE("Memory allocation failure");
483        return NULL;
484    }
485
486    memcpy(texAlloc->getPtr(), data, t->getDimX() * t->getDimY() * t->getElementSizeBytes());
487    if (mips == RS_ALLOCATION_MIPMAP_FULL) {
488        AllocationGenerateScriptMips(rsc, texAlloc);
489    }
490
491    texAlloc->sendDirty(rsc);
492    return texAlloc;
493}
494
495RsAllocation rsi_AllocationCubeCreateFromBitmap(Context *rsc, RsType vtype,
496                                                RsAllocationMipmapControl mips,
497                                                const void *data, size_t data_length, uint32_t usages) {
498    Type *t = static_cast<Type *>(vtype);
499
500    // Cubemap allocation's faces should be Width by Width each.
501    // Source data should have 6 * Width by Width pixels
502    // Error checking is done in the java layer
503    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages);
504    Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
505    if (texAlloc == NULL) {
506        LOGE("Memory allocation failure");
507        return NULL;
508    }
509
510    uint32_t faceSize = t->getDimX();
511    uint32_t strideBytes = faceSize * 6 * t->getElementSizeBytes();
512    uint32_t copySize = faceSize * t->getElementSizeBytes();
513
514    uint8_t *sourcePtr = (uint8_t*)data;
515    for (uint32_t face = 0; face < 6; face ++) {
516        Adapter2D faceAdapter(rsc, texAlloc);
517        faceAdapter.setFace(face);
518
519        for (uint32_t dI = 0; dI < faceSize; dI ++) {
520            memcpy(faceAdapter.getElement(0, dI), sourcePtr + strideBytes * dI, copySize);
521        }
522
523        // Move the data pointer to the next cube face
524        sourcePtr += copySize;
525    }
526
527    if (mips == RS_ALLOCATION_MIPMAP_FULL) {
528        AllocationGenerateScriptMips(rsc, texAlloc);
529    }
530
531    texAlloc->sendDirty(rsc);
532    return texAlloc;
533}
534
535}
536}
537
538const void * rsaAllocationGetType(RsContext con, RsAllocation va) {
539    Allocation *a = static_cast<Allocation *>(va);
540    a->getType()->incUserRef();
541
542    return a->getType();
543}
544