| /* |
| * Copyright (C) 2012 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 <malloc.h> |
| #include <string.h> |
| |
| #include "RenderScript.h" |
| #include "rsCppInternal.h" |
| |
| // From system/graphics.h |
| enum { |
| HAL_PIXEL_FORMAT_YV12 = 0x32315659, // YCrCb 4:2:0 Planar |
| HAL_PIXEL_FORMAT_YCrCb_420_SP = 0x11, // NV21 |
| }; |
| |
| using namespace android; |
| using namespace RSC; |
| |
| void Type::calcElementCount() { |
| bool hasLod = hasMipmaps(); |
| uint32_t x = getX(); |
| uint32_t y = getY(); |
| uint32_t z = getZ(); |
| uint32_t faces = 1; |
| if (hasFaces()) { |
| faces = 6; |
| } |
| if (x == 0) { |
| x = 1; |
| } |
| if (y == 0) { |
| y = 1; |
| } |
| if (z == 0) { |
| z = 1; |
| } |
| |
| uint32_t count = x * y * z * faces; |
| while (hasLod && ((x > 1) || (y > 1) || (z > 1))) { |
| if(x > 1) { |
| x >>= 1; |
| } |
| if(y > 1) { |
| y >>= 1; |
| } |
| if(z > 1) { |
| z >>= 1; |
| } |
| |
| count += x * y * z * faces; |
| } |
| mElementCount = count; |
| } |
| |
| |
| Type::Type(void *id, sp<RS> rs) : BaseObj(id, rs) { |
| mDimX = 0; |
| mDimY = 0; |
| mDimZ = 0; |
| mDimMipmaps = false; |
| mDimFaces = false; |
| mElement = nullptr; |
| mYuvFormat = RS_YUV_NONE; |
| } |
| |
| void Type::updateFromNative() { |
| BaseObj::updateFromNative(); |
| |
| /* |
| * We have 6 integers / pointers (uintptr_t) to obtain from the return buffer: |
| * mDimX (buffer[0]); |
| * mDimY (buffer[1]); |
| * mDimZ (buffer[2]); |
| * mDimLOD (buffer[3]); |
| * mDimFaces (buffer[4]); |
| * mElement (buffer[5]); |
| */ |
| uintptr_t dataBuffer[6]; |
| RS::dispatch->TypeGetNativeData(mRS->getContext(), getID(), dataBuffer, 6); |
| |
| mDimX = (uint32_t)dataBuffer[0]; |
| mDimY = (uint32_t)dataBuffer[1]; |
| mDimZ = (uint32_t)dataBuffer[2]; |
| mDimMipmaps = dataBuffer[3] == 1 ? true : false; |
| mDimFaces = dataBuffer[4] == 1 ? true : false; |
| |
| uintptr_t elementID = dataBuffer[5]; |
| if(elementID != 0) { |
| // Just create a new Element and update it from native. |
| sp<Element> e = new Element((void *)elementID, mRS); |
| e->updateFromNative(); |
| mElement = e; |
| } |
| calcElementCount(); |
| } |
| |
| sp<const Type> Type::create(sp<RS> rs, sp<const Element> e, uint32_t dimX, uint32_t dimY, uint32_t dimZ) { |
| void * id = RS::dispatch->TypeCreate(rs->getContext(), e->getID(), dimX, dimY, dimZ, false, false, 0); |
| Type *t = new Type(id, rs); |
| |
| t->mElement = e; |
| t->mDimX = dimX; |
| t->mDimY = dimY; |
| t->mDimZ = dimZ; |
| t->mDimMipmaps = false; |
| t->mDimFaces = false; |
| t->mYuvFormat = RS_YUV_NONE; |
| |
| t->calcElementCount(); |
| |
| return t; |
| } |
| |
| Type::Builder::Builder(sp<RS> rs, sp<const Element> e) { |
| mRS = rs.get(); |
| mElement = e; |
| mDimX = 0; |
| mDimY = 0; |
| mDimZ = 0; |
| mDimMipmaps = false; |
| mDimFaces = false; |
| mYuvFormat = RS_YUV_NONE; |
| } |
| |
| void Type::Builder::setX(uint32_t value) { |
| if(value < 1) { |
| ALOGE("Values of less than 1 for Dimension X are not valid."); |
| } |
| mDimX = value; |
| } |
| |
| void Type::Builder::setY(uint32_t value) { |
| if(value < 1) { |
| ALOGE("Values of less than 1 for Dimension Y are not valid."); |
| } |
| mDimY = value; |
| } |
| |
| void Type::Builder::setZ(uint32_t value) { |
| if(value < 1) { |
| ALOGE("Values of less than 1 for Dimension Z are not valid."); |
| } |
| mDimZ = value; |
| } |
| |
| void Type::Builder::setYuvFormat(RsYuvFormat format) { |
| if (format != RS_YUV_NONE && !(mElement->isCompatible(Element::YUV(mRS)))) { |
| ALOGE("Invalid element for use with YUV."); |
| return; |
| } |
| |
| if (format != RS_YUV_NONE && |
| format != RS_YUV_YV12 && |
| format != RS_YUV_NV21 && |
| format != RS_YUV_420_888) { |
| ALOGE("Invalid YUV format."); |
| return; |
| } |
| mYuvFormat = format; |
| } |
| |
| |
| void Type::Builder::setMipmaps(bool value) { |
| mDimMipmaps = value; |
| } |
| |
| void Type::Builder::setFaces(bool value) { |
| mDimFaces = value; |
| } |
| |
| sp<const Type> Type::Builder::create() { |
| if (mDimZ > 0) { |
| if ((mDimX < 1) || (mDimY < 1)) { |
| ALOGE("Both X and Y dimension required when Z is present."); |
| return nullptr; |
| } |
| if (mDimFaces) { |
| ALOGE("Cube maps not supported with 3D types."); |
| return nullptr; |
| } |
| } |
| if (mDimY > 0) { |
| if (mDimX < 1) { |
| ALOGE("X dimension required when Y is present."); |
| return nullptr; |
| } |
| } |
| if (mDimFaces) { |
| if (mDimY < 1) { |
| ALOGE("Cube maps require 2D Types."); |
| return nullptr; |
| } |
| } |
| |
| if (mYuvFormat != RS_YUV_NONE) { |
| if (mDimZ || mDimFaces || mDimMipmaps) { |
| ALOGE("YUV only supports basic 2D."); |
| return nullptr; |
| } |
| } |
| |
| if (mYuvFormat == RS_YUV_420_888) { |
| ALOGE("YUV_420_888 not supported."); |
| return nullptr; |
| } |
| |
| void * id = RS::dispatch->TypeCreate(mRS->getContext(), mElement->getID(), mDimX, mDimY, mDimZ, |
| mDimMipmaps, mDimFaces, mYuvFormat); |
| Type *t = new Type(id, mRS); |
| t->mElement = mElement; |
| t->mDimX = mDimX; |
| t->mDimY = mDimY; |
| t->mDimZ = mDimZ; |
| t->mDimMipmaps = mDimMipmaps; |
| t->mDimFaces = mDimFaces; |
| t->mYuvFormat = mYuvFormat; |
| |
| t->calcElementCount(); |
| return t; |
| } |
| |