rsAllocation.cpp revision eb4fe18dd88634330f9566cbb9e785d8c7ec5813
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#ifndef ANDROID_RS_SERIALIZE
172    mToDirtyList.push(p);
173#endif //ANDROID_RS_SERIALIZE
174}
175
176void Allocation::removeProgramToDirty(const Program *p) {
177#ifndef ANDROID_RS_SERIALIZE
178    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
179        if (mToDirtyList[ct] == p) {
180            mToDirtyList.removeAt(ct);
181            return;
182        }
183    }
184    rsAssert(0);
185#endif //ANDROID_RS_SERIALIZE
186}
187
188void Allocation::dumpLOGV(const char *prefix) const {
189    ObjectBase::dumpLOGV(prefix);
190
191    String8 s(prefix);
192    s.append(" type ");
193    if (mHal.state.type.get()) {
194        mHal.state.type->dumpLOGV(s.string());
195    }
196
197    LOGV("%s allocation ptr=%p  mUsageFlags=0x04%x, mMipmapControl=0x%04x",
198         prefix, getPtr(), mHal.state.usageFlags, mHal.state.mipmapControl);
199}
200
201void Allocation::serialize(OStream *stream) const {
202    // Need to identify ourselves
203    stream->addU32((uint32_t)getClassId());
204
205    String8 name(getName());
206    stream->addString(&name);
207
208    // First thing we need to serialize is the type object since it will be needed
209    // to initialize the class
210    mHal.state.type->serialize(stream);
211
212    uint32_t dataSize = mHal.state.type->getSizeBytes();
213    // Write how much data we are storing
214    stream->addU32(dataSize);
215    // Now write the data
216    stream->addByteArray(getPtr(), dataSize);
217}
218
219Allocation *Allocation::createFromStream(Context *rsc, IStream *stream) {
220    // First make sure we are reading the correct object
221    RsA3DClassID classID = (RsA3DClassID)stream->loadU32();
222    if (classID != RS_A3D_CLASS_ID_ALLOCATION) {
223        LOGE("allocation loading skipped due to invalid class id\n");
224        return NULL;
225    }
226
227    String8 name;
228    stream->loadString(&name);
229
230    Type *type = Type::createFromStream(rsc, stream);
231    if (!type) {
232        return NULL;
233    }
234    type->compute();
235
236    // Number of bytes we wrote out for this allocation
237    uint32_t dataSize = stream->loadU32();
238    if (dataSize != type->getSizeBytes()) {
239        LOGE("failed to read allocation because numbytes written is not the same loaded type wants\n");
240        ObjectBase::checkDelete(type);
241        return NULL;
242    }
243
244    Allocation *alloc = Allocation::createAllocation(rsc, type, RS_ALLOCATION_USAGE_SCRIPT);
245    alloc->setName(name.string(), name.size());
246
247    uint32_t count = dataSize / type->getElementSizeBytes();
248
249    // Read in all of our allocation data
250    alloc->data(rsc, 0, 0, count, stream->getPtr() + stream->getPos(), dataSize);
251    stream->reset(stream->getPos() + dataSize);
252
253    return alloc;
254}
255
256void Allocation::sendDirty(const Context *rsc) const {
257#ifndef ANDROID_RS_SERIALIZE
258    for (size_t ct=0; ct < mToDirtyList.size(); ct++) {
259        mToDirtyList[ct]->forceDirty();
260    }
261#endif //ANDROID_RS_SERIALIZE
262    mRSC->mHal.funcs.allocation.markDirty(rsc, this);
263}
264
265void Allocation::incRefs(const void *ptr, size_t ct, size_t startOff) const {
266    const uint8_t *p = static_cast<const uint8_t *>(ptr);
267    const Element *e = mHal.state.type->getElement();
268    uint32_t stride = e->getSizeBytes();
269
270    p += stride * startOff;
271    while (ct > 0) {
272        e->incRefs(p);
273        ct --;
274        p += stride;
275    }
276}
277
278void Allocation::decRefs(const void *ptr, size_t ct, size_t startOff) const {
279    const uint8_t *p = static_cast<const uint8_t *>(ptr);
280    const Element *e = mHal.state.type->getElement();
281    uint32_t stride = e->getSizeBytes();
282
283    p += stride * startOff;
284    while (ct > 0) {
285        e->decRefs(p);
286        ct --;
287        p += stride;
288    }
289}
290
291void Allocation::copyRange1D(Context *rsc, const Allocation *src, int32_t srcOff, int32_t destOff, int32_t len) {
292}
293
294void Allocation::resize1D(Context *rsc, uint32_t dimX) {
295    uint32_t oldDimX = mHal.state.dimensionX;
296    if (dimX == oldDimX) {
297        return;
298    }
299
300    Type *t = mHal.state.type->cloneAndResize1D(rsc, dimX);
301    if (dimX < oldDimX) {
302        decRefs(getPtr(), oldDimX - dimX, dimX);
303    }
304    rsc->mHal.funcs.allocation.resize(rsc, this, t, mHal.state.hasReferences);
305    mHal.state.type.set(t);
306    updateCache();
307}
308
309void Allocation::resize2D(Context *rsc, uint32_t dimX, uint32_t dimY) {
310    LOGE("not implemented");
311}
312
313/////////////////
314//
315#ifndef ANDROID_RS_SERIALIZE
316
317
318namespace android {
319namespace renderscript {
320
321static void AllocationGenerateScriptMips(RsContext con, RsAllocation va);
322
323static void mip565(const Adapter2D &out, const Adapter2D &in) {
324    uint32_t w = out.getDimX();
325    uint32_t h = out.getDimY();
326
327    for (uint32_t y=0; y < h; y++) {
328        uint16_t *oPtr = static_cast<uint16_t *>(out.getElement(0, y));
329        const uint16_t *i1 = static_cast<uint16_t *>(in.getElement(0, y*2));
330        const uint16_t *i2 = static_cast<uint16_t *>(in.getElement(0, y*2+1));
331
332        for (uint32_t x=0; x < w; x++) {
333            *oPtr = rsBoxFilter565(i1[0], i1[1], i2[0], i2[1]);
334            oPtr ++;
335            i1 += 2;
336            i2 += 2;
337        }
338    }
339}
340
341static void mip8888(const Adapter2D &out, const Adapter2D &in) {
342    uint32_t w = out.getDimX();
343    uint32_t h = out.getDimY();
344
345    for (uint32_t y=0; y < h; y++) {
346        uint32_t *oPtr = static_cast<uint32_t *>(out.getElement(0, y));
347        const uint32_t *i1 = static_cast<uint32_t *>(in.getElement(0, y*2));
348        const uint32_t *i2 = static_cast<uint32_t *>(in.getElement(0, y*2+1));
349
350        for (uint32_t x=0; x < w; x++) {
351            *oPtr = rsBoxFilter8888(i1[0], i1[1], i2[0], i2[1]);
352            oPtr ++;
353            i1 += 2;
354            i2 += 2;
355        }
356    }
357}
358
359static void mip8(const Adapter2D &out, const Adapter2D &in) {
360    uint32_t w = out.getDimX();
361    uint32_t h = out.getDimY();
362
363    for (uint32_t y=0; y < h; y++) {
364        uint8_t *oPtr = static_cast<uint8_t *>(out.getElement(0, y));
365        const uint8_t *i1 = static_cast<uint8_t *>(in.getElement(0, y*2));
366        const uint8_t *i2 = static_cast<uint8_t *>(in.getElement(0, y*2+1));
367
368        for (uint32_t x=0; x < w; x++) {
369            *oPtr = (uint8_t)(((uint32_t)i1[0] + i1[1] + i2[0] + i2[1]) * 0.25f);
370            oPtr ++;
371            i1 += 2;
372            i2 += 2;
373        }
374    }
375}
376
377static void mip(const Adapter2D &out, const Adapter2D &in) {
378    switch (out.getBaseType()->getElement()->getSizeBits()) {
379    case 32:
380        mip8888(out, in);
381        break;
382    case 16:
383        mip565(out, in);
384        break;
385    case 8:
386        mip8(out, in);
387        break;
388    }
389}
390
391void rsi_AllocationSyncAll(Context *rsc, RsAllocation va, RsAllocationUsageType src) {
392    Allocation *a = static_cast<Allocation *>(va);
393    a->sendDirty(rsc);
394    a->syncAll(rsc, src);
395}
396
397void rsi_AllocationGenerateMipmaps(Context *rsc, RsAllocation va) {
398    Allocation *texAlloc = static_cast<Allocation *>(va);
399    AllocationGenerateScriptMips(rsc, texAlloc);
400}
401
402void rsi_AllocationCopyToBitmap(Context *rsc, RsAllocation va, void *data, size_t dataLen) {
403    Allocation *texAlloc = static_cast<Allocation *>(va);
404    const Type * t = texAlloc->getType();
405
406    size_t s = t->getDimX() * t->getDimY() * t->getElementSizeBytes();
407    if (s != dataLen) {
408        rsc->setError(RS_ERROR_BAD_VALUE, "Bitmap size didn't match allocation size");
409        return;
410    }
411
412    memcpy(data, texAlloc->getPtr(), s);
413}
414
415void rsi_Allocation1DData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t lod,
416                          uint32_t count, const void *data, uint32_t sizeBytes) {
417    Allocation *a = static_cast<Allocation *>(va);
418    a->data(rsc, xoff, lod, count, data, sizeBytes);
419}
420
421void rsi_Allocation2DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t y, uint32_t lod, RsAllocationCubemapFace face,
422                                 const void *data, uint32_t eoff, uint32_t sizeBytes) {
423    Allocation *a = static_cast<Allocation *>(va);
424    a->elementData(rsc, x, y, data, eoff, sizeBytes);
425}
426
427void rsi_Allocation1DElementData(Context *rsc, RsAllocation va, uint32_t x, uint32_t lod,
428                                 const void *data, uint32_t eoff, uint32_t sizeBytes) {
429    Allocation *a = static_cast<Allocation *>(va);
430    a->elementData(rsc, x, data, eoff, sizeBytes);
431}
432
433void rsi_Allocation2DData(Context *rsc, RsAllocation va, uint32_t xoff, uint32_t yoff, uint32_t lod, RsAllocationCubemapFace face,
434                          uint32_t w, uint32_t h, const void *data, uint32_t sizeBytes) {
435    Allocation *a = static_cast<Allocation *>(va);
436    a->data(rsc, xoff, yoff, lod, face, w, h, data, sizeBytes);
437}
438
439void rsi_AllocationRead(Context *rsc, RsAllocation va, void *data, size_t data_length) {
440    Allocation *a = static_cast<Allocation *>(va);
441    a->read(data);
442}
443
444void rsi_AllocationResize1D(Context *rsc, RsAllocation va, uint32_t dimX) {
445    Allocation *a = static_cast<Allocation *>(va);
446    a->resize1D(rsc, dimX);
447}
448
449void rsi_AllocationResize2D(Context *rsc, RsAllocation va, uint32_t dimX, uint32_t dimY) {
450    Allocation *a = static_cast<Allocation *>(va);
451    a->resize2D(rsc, dimX, dimY);
452}
453
454static void AllocationGenerateScriptMips(RsContext con, RsAllocation va) {
455    Context *rsc = static_cast<Context *>(con);
456    Allocation *texAlloc = static_cast<Allocation *>(va);
457    uint32_t numFaces = texAlloc->getType()->getDimFaces() ? 6 : 1;
458    for (uint32_t face = 0; face < numFaces; face ++) {
459        Adapter2D adapt(rsc, texAlloc);
460        Adapter2D adapt2(rsc, texAlloc);
461        adapt.setFace(face);
462        adapt2.setFace(face);
463        for (uint32_t lod=0; lod < (texAlloc->getType()->getLODCount() -1); lod++) {
464            adapt.setLOD(lod);
465            adapt2.setLOD(lod + 1);
466            mip(adapt2, adapt);
467        }
468    }
469}
470
471RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype,
472                                       RsAllocationMipmapControl mips,
473                                       uint32_t usages) {
474    Allocation * alloc = Allocation::createAllocation(rsc, static_cast<Type *>(vtype), usages, mips);
475    if (!alloc) {
476        return NULL;
477    }
478    alloc->incUserRef();
479    return alloc;
480}
481
482RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, RsType vtype,
483                                            RsAllocationMipmapControl mips,
484                                            const void *data, size_t data_length, uint32_t usages) {
485    Type *t = static_cast<Type *>(vtype);
486
487    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages);
488    Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
489    if (texAlloc == NULL) {
490        LOGE("Memory allocation failure");
491        return NULL;
492    }
493
494    memcpy(texAlloc->getPtr(), data, t->getDimX() * t->getDimY() * t->getElementSizeBytes());
495    if (mips == RS_ALLOCATION_MIPMAP_FULL) {
496        AllocationGenerateScriptMips(rsc, texAlloc);
497    }
498
499    texAlloc->sendDirty(rsc);
500    return texAlloc;
501}
502
503RsAllocation rsi_AllocationCubeCreateFromBitmap(Context *rsc, RsType vtype,
504                                                RsAllocationMipmapControl mips,
505                                                const void *data, size_t data_length, uint32_t usages) {
506    Type *t = static_cast<Type *>(vtype);
507
508    // Cubemap allocation's faces should be Width by Width each.
509    // Source data should have 6 * Width by Width pixels
510    // Error checking is done in the java layer
511    RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages);
512    Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
513    if (texAlloc == NULL) {
514        LOGE("Memory allocation failure");
515        return NULL;
516    }
517
518    uint32_t faceSize = t->getDimX();
519    uint32_t strideBytes = faceSize * 6 * t->getElementSizeBytes();
520    uint32_t copySize = faceSize * t->getElementSizeBytes();
521
522    uint8_t *sourcePtr = (uint8_t*)data;
523    for (uint32_t face = 0; face < 6; face ++) {
524        Adapter2D faceAdapter(rsc, texAlloc);
525        faceAdapter.setFace(face);
526
527        for (uint32_t dI = 0; dI < faceSize; dI ++) {
528            memcpy(faceAdapter.getElement(0, dI), sourcePtr + strideBytes * dI, copySize);
529        }
530
531        // Move the data pointer to the next cube face
532        sourcePtr += copySize;
533    }
534
535    if (mips == RS_ALLOCATION_MIPMAP_FULL) {
536        AllocationGenerateScriptMips(rsc, texAlloc);
537    }
538
539    texAlloc->sendDirty(rsc);
540    return texAlloc;
541}
542
543}
544}
545
546const void * rsaAllocationGetType(RsContext con, RsAllocation va) {
547    Allocation *a = static_cast<Allocation *>(va);
548    a->getType()->incUserRef();
549
550    return a->getType();
551}
552
553#endif //ANDROID_RS_SERIALIZE
554