C++程序  |  237行  |  5.8 KB

/*
 * 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 android::RSC::Element;
using android::RSC::RS;
using android::RSC::Type;
using android::RSC::sp;

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(const sp<RS>& rs, const 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;
}