/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "rsContext.h" #include using namespace android; using namespace android::renderscript; Type::Type(Context *rsc) : ObjectBase(rsc) { mAllocFile = __FILE__; mAllocLine = __LINE__; mLODs = 0; mLODCount = 0; clear(); } Type::~Type() { for (uint32_t ct = 0; ct < mRSC->mStateType.mTypes.size(); ct++) { if (mRSC->mStateType.mTypes[ct] == this) { mRSC->mStateType.mTypes.removeAt(ct); break; } } if (mLODs) { delete [] mLODs; } } void Type::clear() { if (mLODs) { delete [] mLODs; mLODs = NULL; } mDimX = 0; mDimY = 0; mDimZ = 0; mDimLOD = 0; mFaces = false; mElement.clear(); } TypeState::TypeState() { } TypeState::~TypeState() { } size_t Type::getOffsetForFace(uint32_t face) const { rsAssert(mFaces); return 0; } void Type::compute() { uint32_t oldLODCount = mLODCount; if (mDimLOD) { uint32_t l2x = rsFindHighBit(mDimX) + 1; uint32_t l2y = rsFindHighBit(mDimY) + 1; uint32_t l2z = rsFindHighBit(mDimZ) + 1; mLODCount = rsMax(l2x, l2y); mLODCount = rsMax(mLODCount, l2z); } else { mLODCount = 1; } if (mLODCount != oldLODCount) { delete [] mLODs; mLODs = new LOD[mLODCount]; } uint32_t tx = mDimX; uint32_t ty = mDimY; uint32_t tz = mDimZ; size_t offset = 0; for (uint32_t lod=0; lod < mLODCount; lod++) { mLODs[lod].mX = tx; mLODs[lod].mY = ty; mLODs[lod].mZ = tz; mLODs[lod].mOffset = offset; offset += tx * rsMax(ty, 1u) * rsMax(tz, 1u) * mElement->getSizeBytes(); if (tx > 1) tx >>= 1; if (ty > 1) ty >>= 1; if (tz > 1) tz >>= 1; } // At this point the offset is the size of a mipmap chain; mMipChainSizeBytes = offset; if (mFaces) { offset *= 6; } mTotalSizeBytes = offset; makeGLComponents(); } uint32_t Type::getLODOffset(uint32_t lod, uint32_t x) const { uint32_t offset = mLODs[lod].mOffset; offset += x * mElement->getSizeBytes(); return offset; } uint32_t Type::getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const { uint32_t offset = mLODs[lod].mOffset; offset += (x + y * mLODs[lod].mX) * mElement->getSizeBytes(); return offset; } uint32_t Type::getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const { uint32_t offset = mLODs[lod].mOffset; offset += (x + y*mLODs[lod].mX + z*mLODs[lod].mX*mLODs[lod].mY) * mElement->getSizeBytes(); return offset; } void Type::makeGLComponents() { uint32_t userNum = 0; for (uint32_t ct=0; ct < getElement()->getFieldCount(); ct++) { const Component &c = getElement()->getField(ct)->getComponent(); switch(c.getKind()) { case RS_KIND_USER: mGL.mUser[userNum].size = c.getVectorSize(); mGL.mUser[userNum].offset = mElement->getFieldOffsetBytes(ct); mGL.mUser[userNum].type = c.getGLType(); mGL.mUser[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized(); mGL.mUser[userNum].name.setTo(getElement()->getFieldName(ct)); userNum ++; break; case RS_KIND_POSITION: rsAssert(mGL.mVtx.size == 0); mGL.mVtx.size = c.getVectorSize(); mGL.mVtx.offset = mElement->getFieldOffsetBytes(ct); mGL.mVtx.type = c.getGLType(); mGL.mVtx.normalized = false; mGL.mVtx.name.setTo("Position"); break; case RS_KIND_COLOR: rsAssert(mGL.mColor.size == 0); mGL.mColor.size = c.getVectorSize(); mGL.mColor.offset = mElement->getFieldOffsetBytes(ct); mGL.mColor.type = c.getGLType(); mGL.mColor.normalized = c.getType() != RS_TYPE_FLOAT_32; mGL.mColor.name.setTo("Color"); break; case RS_KIND_NORMAL: rsAssert(mGL.mNorm.size == 0); mGL.mNorm.size = c.getVectorSize(); mGL.mNorm.offset = mElement->getFieldOffsetBytes(ct); mGL.mNorm.type = c.getGLType(); mGL.mNorm.normalized = false; mGL.mNorm.name.setTo("Normal"); break; case RS_KIND_TEXTURE: rsAssert(mGL.mTex.size == 0); mGL.mTex.size = c.getVectorSize(); mGL.mTex.offset = mElement->getFieldOffsetBytes(ct); mGL.mTex.type = c.getGLType(); mGL.mTex.normalized = false; mGL.mTex.name.setTo("Texture"); break; case RS_KIND_POINT_SIZE: rsAssert(!mGL.mPointSize.size); mGL.mPointSize.size = c.getVectorSize(); mGL.mPointSize.offset = mElement->getFieldOffsetBytes(ct); mGL.mPointSize.type = c.getGLType(); mGL.mPointSize.normalized = false; mGL.mPointSize.name.setTo("PointSize"); break; default: break; } } } void Type::enableGLVertexBuffer(VertexArray *va) const { // Note: We are only going to enable buffers and never disable them // here. The reason is more than one Allocation may be used as a vertex // source. So we cannot disable arrays that may have been in use by // another allocation. uint32_t stride = mElement->getSizeBytes(); if (mGL.mVtx.size) { va->addLegacy(mGL.mVtx.type, mGL.mVtx.size, stride, RS_KIND_POSITION, false, mGL.mVtx.offset); } if (mGL.mNorm.size) { va->addLegacy(mGL.mNorm.type, 3, stride, RS_KIND_NORMAL, false, mGL.mNorm.offset); } if (mGL.mColor.size) { va->addLegacy(mGL.mColor.type, mGL.mColor.size, stride, RS_KIND_COLOR, true, mGL.mColor.offset); } if (mGL.mTex.size) { va->addLegacy(mGL.mTex.type, mGL.mTex.size, stride, RS_KIND_TEXTURE, false, mGL.mTex.offset); } if (mGL.mPointSize.size) { va->addLegacy(mGL.mPointSize.type, 1, stride, RS_KIND_POINT_SIZE, false, mGL.mPointSize.offset); } } void Type::enableGLVertexBuffer2(VertexArray *va) const { // Do legacy buffers enableGLVertexBuffer(va); uint32_t stride = mElement->getSizeBytes(); for (uint32_t ct=0; ct < RS_MAX_ATTRIBS; ct++) { if (mGL.mUser[ct].size) { va->addUser(mGL.mUser[ct], stride); } } } void Type::dumpLOGV(const char *prefix) const { char buf[1024]; ObjectBase::dumpLOGV(prefix); LOGV("%s Type: x=%i y=%i z=%i mip=%i face=%i", prefix, mDimX, mDimY, mDimZ, mDimLOD, mFaces); sprintf(buf, "%s element: ", prefix); mElement->dumpLOGV(buf); } bool Type::getIsNp2() const { uint32_t x = getDimX(); uint32_t y = getDimY(); uint32_t z = getDimZ(); if (x && (x & (x-1))) { return true; } if (y && (y & (y-1))) { return true; } if (z && (z & (z-1))) { return true; } return false; } ////////////////////////////////////////////////// // namespace android { namespace renderscript { void rsi_TypeBegin(Context *rsc, RsElement vse) { TypeState * stc = &rsc->mStateType; stc->mX = 0; stc->mY = 0; stc->mZ = 0; stc->mLOD = false; stc->mFaces = false; stc->mElement.set(static_cast(vse)); } void rsi_TypeAdd(Context *rsc, RsDimension dim, size_t value) { TypeState * stc = &rsc->mStateType; if (dim < 0) { //error return; } switch (dim) { case RS_DIMENSION_X: stc->mX = value; return; case RS_DIMENSION_Y: stc->mY = value; return; case RS_DIMENSION_Z: stc->mZ = value; return; case RS_DIMENSION_FACE: stc->mFaces = (value != 0); return; case RS_DIMENSION_LOD: stc->mLOD = (value != 0); return; default: break; } int32_t arrayNum = dim - RS_DIMENSION_ARRAY_0; if ((dim < 0) || (dim > RS_DIMENSION_MAX)) { LOGE("rsTypeAdd: Bad dimension"); //error return; } // todo: implement array support } RsType rsi_TypeCreate(Context *rsc) { TypeState * stc = &rsc->mStateType; for (uint32_t ct=0; ct < stc->mTypes.size(); ct++) { Type *t = stc->mTypes[ct]; if (t->getElement() != stc->mElement.get()) continue; if (t->getDimX() != stc->mX) continue; if (t->getDimY() != stc->mY) continue; if (t->getDimZ() != stc->mZ) continue; if (t->getDimLOD() != stc->mLOD) continue; if (t->getDimFaces() != stc->mFaces) continue; t->incUserRef(); return t; } Type * st = new Type(rsc); st->incUserRef(); st->setDimX(stc->mX); st->setDimY(stc->mY); st->setDimZ(stc->mZ); st->setElement(stc->mElement.get()); st->setDimLOD(stc->mLOD); st->setDimFaces(stc->mFaces); st->compute(); stc->mElement.clear(); stc->mTypes.push(st); return st; } } }