Android高效計算——RenderScript(二)

来源:http://www.cnblogs.com/willhua/archive/2016/08/18/5782293.html
-Advertisement-
Play Games

3 RenderScript運行時層與反射層 3.1 RenderScript運行時層 RenderScript運行時層是指.rs代碼運行時所在的層級。當對安卓項目進行編譯的時候,.rs或者.rsh中編寫的代碼都會被llvm編譯器編譯成位元組碼。當該安卓應用在設備上運行的時候,這些位元組碼將會被設備上另 ...


3 RenderScript運行時層與反射層

3.1 RenderScript運行時層

RenderScript運行時層是指.rs代碼運行時所在的層級。當對安卓項目進行編譯的時候,.rs或者.rsh中編寫的代碼都會被llvm編譯器編譯成位元組碼。當該安卓應用在設備上運行的時候,這些位元組碼將會被設備上另外一個llvm編譯(just-in-time)成機器碼。這些機器碼是針對該設備進行了優化的,且緩存在設備上,等到下次被應用的時候就不需要重新編譯了,以加快速度。雖然RenderScript運行時層很像NDK,但是由於NDK中的C函數只針對CPU設計,與RenderScript還能夠在GPU和DSP上運行的目標不同,因此在RenderScript中不能使用NDK中的C函數。

RenderScript運行時庫的特性包括:

  • 請求記憶體分配,即其記憶體是由Android framework層負責分配的。
  • 一系列針對標量與向量計算的數學函數
  • 提供基本數據到向量/矩陣或者數據到時間的轉換函數
  • 預定義的一系列二維、三維、四維向量類型
  • Log功能,rsDebug函數

3.2 反射層

反射層由安卓編譯工具基於開發者編寫的.rs/.rsh文件自動生成的,反射層的作用就是給Android framework層提供對RenderScript運行時層操作的Java介面,包括記憶體分配、計算任務啟動、數據交互等。

每一個.rs文件都會被映射成繼承於ScriptC的類:ScriptC_RenderScript_filename,該類被生成在gen目錄下與.rs文件相同的包下。該類就是.rs文件的Java版本。該類主要包含.rs中的如下內容:

  • 非靜態函數。.rs中的非kernel函數不能有返回值,因為RenderScript系統被設計成非同步執行。當你從安卓層調用RenderScript函數的時候,這個調用被放在隊列中,然後當輪到該調用的時候再執行。這樣的話可以使RenderScript避免被經常打斷以提升性能。如果想在RenderScript代碼(.rs)中給安卓層返回值,則可以使用rsSendToClient()
  • 非靜態全局變數。而且會對這些變數生成get/set方法(const變數則不會生成set方法),且如果在RenderScript中對這些變數進行了初始化,那麼在反射層也會進行相同的初始化。
  • 全局指針。指針會被映射到.rs對應的類中。可以聲明一個指針指向struct或者其他任何RenderScript支持的類型的指針。因為不容許在.rs中給指針分配記憶體,對於每個指針,都會生成一個對應的get方法以及bind_pointer_name,這個函數用於把在安卓VM中分配的記憶體綁定到RenderScript運行時。
  • 定義的struct。Struct也是定義在.rs文件中,無論是單獨定義struct還是和其他RenderScript代碼放在一起,都會給每個單獨的struct生成一個ScriptField_struct_name.java的類文件,你可以通過它來給一個或者多個該struct實例分配記憶體。但是註意:只有當你定義的struct在RenderScript代碼中被用到了才會生成對應的類文件,若是沒有使用的話則不會生成。在struct中不能含有指針或者數列。

 Struct映射的詳細解釋

反射層生成的Struct主要包括:

  • 構造函數:ScriptField_struct_name(RenderScript rs, int count),這個構造函數用來分配count數量的struct記憶體
  • 構造函數:ScriptField_struct_name(RenderScript rs, int count, int usages)不僅通過count指定要分配的struct數量,並且通過usages指定這些記憶體被分配在哪個區域。主要有:
  1. USAGE_SCRIPT:指定在腳本記憶體區分配記憶體,這也是預設的記憶體分配區
  2. USAGE_GRAPHICS_TEXTURE: 在GPU的紋理記憶體區分配
  3. USAGE_GRAPHICS_VERTEX:在GPU的頂點記憶體區分配
  4. USAGE_GRAPHICS_CONSTANTS:在GPU的常量記憶體區分配。常量記憶體區被多個應用共同使用

可以使用或操作符來指定在多個記憶體區分配該記憶體,這樣做表示向RenderScript表明:我想在多個記憶體區來訪問該數據。

  • 一個Item內部類,通過該內部類你可以創建該結構的實例,這對於如果需要在安卓層中使用結構實例就非常有用。可以使用set(Item i, int index, boolean copyNow)方法來把某個Item實例插入到已經分配好的記憶體的指定位置。
  • 結構中的每個欄位都會有一個對應的set/get方法,且這些方法中都有一個index參數來指定要設置/讀取記憶體區的哪個對象。每一個set方法都有一個copyNow參數來說明是否立即同步該記憶體到RenderScript運行時。通過調用copyAll方法可以同步所有還沒有同步的記憶體。
  • 創建該結構在記憶體中的描述Element,通過該Element可以分配由一個或者多個該結構對應的Element組成的記憶體。
  • resize()函數。就像C中的realloc()一樣,可以擴展之前分配的記憶體,並保持之前創建的對象的值。
  • copyAll()用來同步在framework層設置的值到RenderScript運行時層。當調用set方法時,如果給copyNow設置的false,則將會在調用copyNow時同步到RenderScript運行時層。

代碼舉例:

.rs文件,文件名:script.rs

#pragma version(1)
#pragma rs java_package_name(com.example.renderscripttest)
#pragma rs_fp_relaxed

uint32_t width;
uint32_t height;

rs_allocation inBitmap;
rs_allocation rgbBitmap;
rs_allocation yuvBitmap;

//multipliers to convert a RGB colors to black and white
const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};

typedef struct Point_2D{
    int x;
    int y;
}Point;

static Point *spPoint;
static Point sPoint;
Point point;
Point *pPoint;

//google sample
void root(const uchar4 *v_in, uchar4 *v_out) {
  //unpack a color to a float4
  float4 f4 = rsUnpackColor8888(*v_in);
  //take the dot product of the color and the multiplier
  float3 mono = dot(f4.rgb, gMonoMult);
  //repack the float to a color
  *v_out = rsPackColorTo8888(mono);
}

void __attribute((kernel)) setPoint(const uint2 in, uint32_t x, uint32_t y){
rsDebug("lyh", point.x);
    point.x = 9; //struct is used
    point.y = 12;
    rsSendToClient(0, &point, 1);
    rsDebug("willhua", point.x);
}

uchar4 __attribute__((kernel)) halveBitmap(uchar4 in){
    uchar4 out = in;
    out.r = in.r / 2;
    out.r = in.r / 2;
    out.r = in.r / 2;
    return out;
}

uchar4 __attribute__((kernel)) averageBitmap(uchar4 in, uint32_t x, uint32_t y){
    uchar4 out = in;
    
    uchar4 left = in;
    uchar4 top = in;
    uchar4 right = in;
    uchar4 bottom = in;
    
    if(x - 1 > -1){ //access other element
        left = rsGetElementAt_uchar4(inBitmap, x - 1, y);
    }
    if(y - 1 > -1){
        top = rsGetElementAt_uchar4(inBitmap, x , y - 1);
    }
    if(x + 1 < width){
        right = rsGetElementAt_uchar4(inBitmap, x + 1, y);
    }
    if(y + 1 < height){
        bottom = rsGetElementAt_uchar4(inBitmap, x, y + 1);
    }
    
    out.r = (left.r + top.r + right.r + bottom.r) / 4;
    out.g = (left.g + top.g + right.g + bottom.g) / 4;
    out.b = (left.b + top.b + right.b + bottom.b) / 4;
    
    return out;
}    
View Code

反射層生成的ScriptC子類:

/*
 * Copyright (C) 2011-2014 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.
 */

/*
 * This file is auto-generated. DO NOT MODIFY!
 * The source Renderscript file: G:\\Files\\EclipseWorkSpace\\RenderScriptTest\\src\\com\\example\\renderscripttest\\script.rs
 */

package com.example.renderscripttest;

import android.support.v8.renderscript.*;
import android.content.res.Resources;

/**
 * @hide
 */
public class ScriptC_script extends ScriptC {
    private static final String __rs_resource_name = "script";
    // Constructor
    public  ScriptC_script(RenderScript rs) {
        this(rs,
             rs.getApplicationContext().getResources(),
             rs.getApplicationContext().getResources().getIdentifier(
                 __rs_resource_name, "raw",
                 rs.getApplicationContext().getPackageName()));
    }

    public  ScriptC_script(RenderScript rs, Resources resources, int id) {
        super(rs, resources, id);
        __U32 = Element.U32(rs);
        __ALLOCATION = Element.ALLOCATION(rs);
        __ScriptField_Point_2D = ScriptField_Point_2D.createElement(rs);
        __U8_4 = Element.U8_4(rs);
        __U32_2 = Element.U32_2(rs);
    }

    private Element __ALLOCATION;
    private Element __ScriptField_Point_2D;
    private Element __U32;
    private Element __U32_2;
    private Element __U8_4;
    private FieldPacker __rs_fp_ALLOCATION;
    private FieldPacker __rs_fp_ScriptField_Point_2D;
    private FieldPacker __rs_fp_U32;
    private final static int mExportVarIdx_width = 0;
    private long mExportVar_width;
    public synchronized void set_width(long v) {
        if (__rs_fp_U32!= null) {
            __rs_fp_U32.reset();
        } else {
            __rs_fp_U32 = new FieldPacker(4);
        }
        __rs_fp_U32.addU32(v);
        setVar(mExportVarIdx_width, __rs_fp_U32);
        mExportVar_width = v;
    }

    public long get_width() {
        return mExportVar_width;
    }

    public Script.FieldID getFieldID_width() {
        return createFieldID(mExportVarIdx_width, null);
    }

    private final static int mExportVarIdx_height = 1;
    private long mExportVar_height;
    public synchronized void set_height(long v) {
        if (__rs_fp_U32!= null) {
            __rs_fp_U32.reset();
        } else {
            __rs_fp_U32 = new FieldPacker(4);
        }
        __rs_fp_U32.addU32(v);
        setVar(mExportVarIdx_height, __rs_fp_U32);
        mExportVar_height = v;
    }

    public long get_height() {
        return mExportVar_height;
    }

    public Script.FieldID getFieldID_height() {
        return createFieldID(mExportVarIdx_height, null);
    }

    private final static int mExportVarIdx_inBitmap = 2;
    private Allocation mExportVar_inBitmap;
    public synchronized void set_inBitmap(Allocation v) {
        setVar(mExportVarIdx_inBitmap, v);
        mExportVar_inBitmap = v;
    }

    public Allocation get_inBitmap() {
        return mExportVar_inBitmap;
    }

    public Script.FieldID getFieldID_inBitmap() {
        return createFieldID(mExportVarIdx_inBitmap, null);
    }

    private final static int mExportVarIdx_rgbBitmap = 3;
    private Allocation mExportVar_rgbBitmap;
    public synchronized void set_rgbBitmap(Allocation v) {
        setVar(mExportVarIdx_rgbBitmap, v);
        mExportVar_rgbBitmap = v;
    }

    public Allocation get_rgbBitmap() {
        return mExportVar_rgbBitmap;
    }

    public Script.FieldID getFieldID_rgbBitmap() {
        return createFieldID(mExportVarIdx_rgbBitmap, null);
    }

    private final static int mExportVarIdx_yuvBitmap = 4;
    private Allocation mExportVar_yuvBitmap;
    public synchronized void set_yuvBitmap(Allocation v) {
        setVar(mExportVarIdx_yuvBitmap, v);
        mExportVar_yuvBitmap = v;
    }

    public Allocation get_yuvBitmap() {
        return mExportVar_yuvBitmap;
    }

    public Script.FieldID getFieldID_yuvBitmap() {
        return createFieldID(mExportVarIdx_yuvBitmap, null);
    }

    private final static int mExportVarIdx_point = 5;
    private ScriptField_Point_2D.Item mExportVar_point;
    public synchronized void set_point(ScriptField_Point_2D.Item v) {
        mExportVar_point = v;
        FieldPacker fp = new FieldPacker(8);
        fp.addI32(v.x);
        fp.addI32(v.y);
        int []__dimArr = new int[1];
        __dimArr[0] = 1;
        setVar(mExportVarIdx_point, fp, __ScriptField_Point_2D, __dimArr);
    }

    public ScriptField_Point_2D.Item get_point() {
        return mExportVar_point;
    }

    public Script.FieldID getFieldID_point() {
        return createFieldID(mExportVarIdx_point, null);
    }

    private final static int mExportVarIdx_pPoint = 6;
    private ScriptField_Point_2D mExportVar_pPoint;
    public void bind_pPoint(ScriptField_Point_2D v) {
        mExportVar_pPoint = v;
        if (v == null) bindAllocation(null, mExportVarIdx_pPoint);
        else bindAllocation(v.getAllocation(), mExportVarIdx_pPoint);
    }

    public ScriptField_Point_2D get_pPoint() {
        return mExportVar_pPoint;
    }

    private final static int mExportForEachIdx_root = 0;
    public Script.KernelID getKernelID_root() {
        return createKernelID(mExportForEachIdx_root, 3, null, null);
    }

    public void forEach_root(Allocation ain, Allocation aout) {
        forEach_root(ain, aout, null);
    }

    public void forEach_root(Allocation ain, Allocation aout, Script.LaunchOptions sc) {
        // check ain
        if (!ain.getType().getElement().isCompatible(__U8_4)) {
            throw new RSRuntimeException("Type mismatch with U8_4!");
        }
        // check aout
        if (!aout.getType().getElement().isCompatible(__U8_4)) {
            throw new RSRuntimeException("Type mismatch with U8_4!");
        }
        Type t0, t1;        // Verify dimensions
        t0 = ain.getType();
        t1 = aout.getType();
        if ((t0.getCount() != t1.getCount()) ||
            (t0.getX() != t1.getX()) ||
            (t0.getY() != t1.getY()) ||
            (t0.getZ() != t1.getZ()) ||
            (t0.hasFaces()   != t1.hasFaces()) ||
            (t0.hasMipmaps() != t1.hasMipmaps())) {
            throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
        }

        forEach(mExportForEachIdx_root, ain, aout, null, sc);
    }

    private final static int mExportForEachIdx_setPoint = 1;
    public Script.KernelID getKernelID_setPoint() {
        return createKernelID(mExportForEachIdx_setPoint, 57, null, null);
    }

    public void forEach_setPoint(Allocation ain) {
        forEach_setPoint(ain, null);
    }

    public void forEach_setPoint(Allocation ain, Script.LaunchOptions sc) {
        // check ain
        if (!ain.getType().getElement().isCompatible(__U32_2)) {
            throw new RSRuntimeException("Type mismatch with U32_2!");
        }
        forEach(mExportForEachIdx_setPoint, ain, null, null, sc);
    }

    private final static int mExportForEachIdx_halveBitmap = 2;
    public Script.KernelID getKernelID_halveBitmap() {
        return createKernelID(mExportForEachIdx_halveBitmap, 35, null, null);
    }

    public void forEach_halveBitmap(Allocation ain, Allocation aout) {
        forEach_halveBitmap(ain, aout, null);
    }

    public void forEach_halveBitmap(Allocation ain, Allocation aout, Script.LaunchOptions sc) {
        // check ain
        if (!ain.getType().getElement().isCompatible(__U8_4)) {
            throw new RSRuntimeException("Type mismatch with U8_4!");
        }
        // check aout
        if (!aout.getType().getElement().isCompatible(__U8_4)) {
            throw new RSRuntimeException("Type mismatch with U8_4!");
        }
        Type t0, t1;        // Verify dimensions
        t0 = ain.getType();
        t1 = aout.getType();
        if ((t0.getCount() != t1.getCount()) ||
            (t0.getX() != t1.getX()) ||
            (t0.getY() != t1.getY()) ||
            (t0.getZ() != t1.getZ()) ||
            (t0.hasFaces()   != t1.hasFaces()) ||
            (t0.hasMipmaps() != t1.hasMipmaps())) {
            throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
        }

        forEach(mExportForEachIdx_halveBitmap, ain, aout, null, sc);
    }

    private final static int mExportForEachIdx_averageBitmap = 3;
    public Script.KernelID getKernelID_averageBitmap() {
        return createKernelID(mExportForEachIdx_averageBitmap, 59, null, null);
    }

    public void forEach_averageBitmap(Allocation ain, Allocation aout) {
        forEach_averageBitmap(ain, aout, null);
    }

    public void forEach_averageBitmap(Allocation ain, Allocation aout, Script.LaunchOptions sc) {
        // check ain
        if (!ain.getType().getElement().isCompatible(__U8_4)) {
            throw new RSRuntimeException("Type mismatch with U8_4!");
        }
        // check aout
        if (!aout.getType().getElement().isCompatible(__U8_4)) {
            throw new RSRuntimeException("Type mismatch with U8_4!");
        }
        Type t0, t1;        // Verify dimensions
        t0 = ain.getType();
        t1 = aout.getType();
        if ((t0.getCount() != t1.getCount()) ||
            (t0.getX() != t1.getX()) ||
            (t0.getY() != t1.getY()) ||
            (t0.getZ() != t1.getZ()) ||
            (t0.hasFaces()   != t1.hasFaces()) ||
            (t0.hasMipmaps() != t1.hasMipmaps())) {
            throw new RSRuntimeException("Dimension mismatch between parameters ain and aout!");
        }

        forEach(mExportForEachIdx_averageBitmap, ain, aout, null, sc);
    }

}
View Code

反射層生成的struct,Point_2D, 對應的類:

/*
 * Copyright (C) 2011-2014 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.
 */

/*
 * This file is auto-generated. DO NOT MODIFY!
 * The source Renderscript file: G:\\Files\\EclipseWorkSpace\\RenderScriptTest\\src\\com\\example\\renderscripttest\\script.rs
 */

package com.example.renderscripttest;

import android.support.v8.renderscript.*;
import android.content.res.Resources;

/**
 * @hide
 */
public class ScriptField_Point_2D extends android.support.v8.renderscript.Script.FieldBase {
    static public class Item {
        public static final int sizeof = 8;

        int x;
        int y;

        Item() {
        }

    }

    private Item mItemArray[];
    private FieldPacker mIOBuffer;
    private static java.lang.ref.WeakReference<Element> mElementCache = new java.lang.ref.WeakReference<Element>(null);
    public static Element createElement(RenderScript rs) {
        Element.Builder eb = new Element.Builder(rs);
        eb.add(Element.I32(rs), "x");
        eb.add(Element.I32(rs), "y");
        return eb.create();
    }

    private  ScriptField_Point_2D(RenderScript rs) {
        mItemArray = null;
        mIOBuffer = null;
        mElement = createElement(rs);
    }

    public  ScriptField_Point_2D(RenderScript rs, int count) {
        mItemArray = null;
        mIOBuffer = null;
        mElement = createElement(rs);
        init(rs, count);
    }

    public  ScriptField_Point_2D(RenderScript rs, int count, int usages) {
        mItemArray = null;
        mIOBuffer = null;
        mElement = createElement(rs);
        init(rs, count, usages);
    }

    public static ScriptField_Point_2D create1D(RenderScript rs, int dimX, int usages) {
        ScriptField_Point_2D obj = new ScriptField_Point_2D(rs);
        obj.mAllocation = Allocation.createSized(rs, obj.mElement, dimX, usages);
        return obj;
    }

    public static ScriptField_Point_2D create1D(RenderScript rs, int dimX) {
        return create1D(rs, dimX, Allocation.USAGE_SCRIPT);
    }

    public static ScriptField_Point_2D create2D(RenderScript rs, int dimX, int dimY) {
        return create2D(rs, dimX, dimY, Allocation.USAGE_SCRIPT);
    }

    public static ScriptField_Point_2D create2D(RenderScript rs, int dimX, int dimY, int usages) {
        ScriptField_Point_2D obj = new ScriptField_Point_2D(rs);
        Type.Builder b = new Type.Builder(rs, obj.mElement);
        b.setX(dimX);
        b.setY(dimY);
        Type t = b.create();
        obj.mAllocation = Allocation.createTyped(rs, t, usages);
        return obj;
    }

    public static Type.Builder createTypeBuilder(RenderScript rs) {
        Element e = createElement(rs);
        return new Type.Builder(rs, e);
    }

    public static ScriptField_Point_2D createCustom(RenderScript rs, Type.Builder tb, int usages) {
        ScriptField_Point_2D obj = new ScriptField_Point_2D(rs);
        Type t = tb.create();
        if (t.getElement() != obj.mElement) {
            throw new RSIllegalArgumentException("Type.Builder did not match expected element type.");
        }
        obj.mAllocation = Allocation.createTyped(rs, t, usages);
        return obj;
    }

    private void copyToArrayLocal(Item i, FieldPacker fp) {
        fp.addI32(i.x);
        fp.addI32(i.y);
    }

    private void copyToArray(Item i, int index) {
        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
        mIOBuffer.reset(index * mElement.getBytesSize());
        copyToArrayLocal(i, mIOBuffer);
    }

    public synchronized void set(Item i, int index, boolean copyNow) {
        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
        mItemArray[index] = i;
        if (copyNow)  {
            copyToArray(i, index);
            FieldPacker fp = new FieldPacker(mElement.getBytesSize());
            copyToArrayLocal(i, fp);
            mAllocation.setFromFieldPacker(index, fp);
        }

    }

    public synchronized Item get(int index) {
        if (mItemArray == null) return null;
        return mItemArray[index];
    }

    public synchronized void set_x(int index, int v, boolean copyNow) {
        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
        if (mItemArray[index] == null) mItemArray[index] = new Item();
        mItemArray[index].x = v;
        if (copyNow)  {
            mIOBuffer.reset(index * mElement.getBytesSize());
            mIOBuffer.addI32(v);
            FieldPacker fp = new FieldPacker(4);
            fp.addI32(v);
            mAllocation.setFromFieldPacker(index, 0, fp);
        }

    }

    public synchronized void set_y(int index, int v, boolean copyNow) {
        if (mIOBuffer == null) mIOBuffer = new FieldPacker(mElement.getBytesSize() * getType().getX()/* count */);
        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
        if (mItemArray[index] == null) mItemArray[index] = new Item();
        mItemArray[index].y = v;
        if (copyNow)  {
            mIOBuffer.reset(index * mElement.getBytesSize() + 4);
            mIOBuffer.addI32(v);
            FieldPacker fp = new FieldPacker(4);
            fp.addI32(v);
            mAllocation.setFromFieldPacker(index, 1, fp);
        }

    }

    public synchronized int get_x(int index) {
        if (mItemArray == null) return 0;
        return mItemArray[index].x;
    }

    public synchronized int get_y(int index) {
        if (mItemArray == null) return 0;
        return mItemArray[index].y;
    }

    public synchronized void copyAll() {
        for (int ct = 0; ct < mItemArray.length; ct++) copyToArray(mItemArray[ct], ct);
        mAllocation.setFromFieldPacker(0, mIOBuffer);
    }

}
View Code

 

4 記憶體

我們已經知道,應用自身運行在安卓VM中,而RenderScript部分代碼則運行在本地,且其記憶體是由上層的應用分配的。

4.1 記憶體分配API

記憶體API主要包含三個類:Element,Type與Allocation。他們三者對應的關係能用malloc函數的使用來很好的說明,例如:     

 int *array = (int *)malloc(sizeof(int) * 10);

malloc函數的參數可以分成兩個部分:第一個就是sizeof(int),該過程指定每個記憶體單元需要多個記憶體;第二個就是*10,該過程指定需要分配多個這樣的記憶體單元。對應的記憶體分配APIs就是Element類,表示的是一個記憶體單元,就像一個float或者一個struct所表示的記憶體。而Type表示的就是“*10”部分,就像一個Element序列一樣。Allocation則用來執行由Type所描述的記憶體分配,且最終代表分配得到的記憶體。

大部分情況下都不需要直接使用這些API,因為系統在自動生成反射層的時候已經做好了封裝,需要做的就是調用對應類的構造函數並把分配的記憶體綁定到RenderScript而已。但是比如當你載入一張圖片到RenderScript層或者給一個指針分配記憶體時,就需要應用到這些API。

4.2 靜態記憶體

4.2.1 靜態記憶體的分配

這裡的靜態記憶體指的是在RenderScript中聲明的非靜態的全局變數(靜態的或者局部的變數就無法在Android framework層訪問,也就不討論),他們在編譯時就分配了記憶體,在RenderScript代碼中可以直接使用它們而不需要在Android Framework層給他們分配記憶體。在Android Framework層也可以通過反射層生成的函數來訪問他們。如果這些變數在RenderScript中被初始化,那麼他們也將在Android Framework層中被進行同樣的初始化。

註意:如果在RenderScript中使用到了RenderScript中預定義了的一些含有指針的結構體,比如rs_program_fragment和rs_allocation,那麼就需要先在Android Framework層構造一個該結構對應類的實例,然後調用set方法把記憶體綁定到RenderScript運行時,而不能直接在RenderScript層操作。但是這個對於用戶自定義的包含指針的結果無效,因為根本就無法自定義包含指針的結構。

4.2.2 靜態記憶體的讀寫

在RenderScript層對靜態分配的記憶體的寫操作是單向的。當你在RenderScript層修改了某個變數的值,出於性能方面的考慮,這個變化不會反應給安卓層。在安卓層調用get方法獲得的是安卓層最後一次通過set方法設置的值,除非通過rsSendToClient()等手段,否則安卓層是永遠獲取不到RenderScript對靜態分配的記憶體的修改的。但是,當安卓層修改了某個變數的值後,該值的變化隨後就會自動同步到RenderScript層。

下麵是讀寫示例。假如在rsfile.rs中定義了全局變數point:

typedef struct Point {
    int x;
    int y;
} Point_t;

Point_t point;

那麼在RenderScript中可以如下直接給變數賦值:

point.x = 1;
point.y = 1;

在Android framework層中可以這樣修改該變數的值,且修改的值會通知到RenderScript層:

ScriptC_rsfile mScript;
...
Item i = new ScriptField_Point.Item();
i.x = 1;
i.y = 1;
mScript.set_point(i);

在RenderScript中讀取變數的值:

rsDebug("Printing out a Point", point.x, point.y);

在Android framework中讀取變數的值。再一次強調:讀取到的永遠是Android framework層最後一次調用set方法給該變數賦的值,而如果在Android framework層沒有用set方法給變數賦過值的話,那麼讀取的將是null,下麵代碼也會報空指針錯誤

Log.i("TAGNAME", "Printing out a Point: " + mScript.get_point().x + " " + mScript.get_point().y);
System.out.println(point.get_x() + " " + point.get_y());

4.3 動態記憶體

4.3.1 動態記憶體的分配

對於動態記憶體,比如指針,就必須在Android Framework層中給它分配記憶體。需要兩個過程:分配記憶體與綁定記憶體。這樣做的好處在於:安卓VM能夠完全掌握RenderScript記憶體的分配與回收。

無論在Android Framework層還是RenderScript中,都可以通過該指針來訪問分配的記憶體。

為了給RenderScript動態分配記憶體,最常見的做法是調用Script.FieldBase的構造函數,當然好也可以手動創建Allocation來實現,為了簡單起見,應該使用Script.FieldBase.當獲取分配的記憶體對象後,就可以通過反射層的bind方法把該記憶體綁定到RenderScript。下麵代碼是兩種實現方式的例子:

private RenderScript myRenderScript;
private ScriptC_example mScript;
private Resources resources;
public void init(RenderScript rs, Resources res) { myRenderScript = rs; resources = res; //使用反射層生成的類分配記憶體 ScriptField_Point touchPoints = new ScriptField_Point(myRenderScript, 2); //自己使用API分配記憶體 intPointer = Allocation.createSized(myRenderScript, Element.I32(myRenderScript), 2); mScript = new ScriptC_example(myRenderScript, resources, R.raw.example); //綁定記憶體 mScript.bind_touchPoints(touchPoints); mScript.bind_intPointer(intPointer); ... }

4.3.2 動態記憶體的讀寫

對於動態記憶體,在Android framework層可以通過反射層的set/get方法來讀/寫記憶體,在RenderScript中也可以像往常一樣讀/寫,且任意一方的寫操作都會通知到另外一方

下麵是示例。假設在rsfile.rs定義瞭如下全局指針:

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 測試demo的github地址: https://github.com/lily1010/html5_geolocation HTML5 Geolocation API 用於獲得用戶的地理位置。鑒於該特性可能侵犯用戶的隱私,除非用戶同意,否則用戶位置信息是不可用的。 一 基於瀏覽器的HTML5查找地 ...
  • Html篇: 1.你做的頁面在哪些流覽器測試過?這些瀏覽器的內核分別是什麼? IE: trident內核 Firefox:gecko內核 Safari:webkit內核 Opera:以前是presto內核,Opera現已改用Google Chrome的Blink內核 Chrome:Blink(基於w ...
  • 對apply、call、bind的認識,並且列出一些它們的妙用加深記憶。 apply、call 在 javascript 中,call 和 apply 都是為了改變某個函數運行時的上下文(context)而存在的,換句話說,就是為了改變函數體內部 this 的指向。 JavaScript 的一大特點 ...
  • 2016-08-18 text-decoration blink貌似在firefox里也不起作用? 下劃線 頂劃線 消除線 文字閃爍 ...
  • 我們常用的在a標簽中有點擊事件:1. a href="javascript:js_method();" 這是我們平臺上常用的方法,但是這種方法在傳遞this等參數的時候很容易出問題,而且javascript:協議作為a的href屬性的時候不僅會導致不必要的觸發window.onbeforeunloa ...
  • 1. 概述 jquery允許拓展自定義的方法, 綁定到$.fn對象上, 編寫一個jQuery插件的原則: 2. example 3. 使用過濾 針對特定元素的拓展 類似submit方法只能作用在form上,我們也可以自定義針對指定dom元素使用的方法。 jquery的filter這時派上了用場。 e ...
  • xcode7下的ios模擬器輸入內容無法系統鍵盤,只能用電腦鍵盤輸入內容,這樣可能會對調試帶來麻煩。 其實xcode7下的ios模擬器預設只能使用一種,要麼是模擬器系統鍵盤,要麼就是是電腦鍵盤。設置方法如下: 打開ios模擬器菜單欄:Hardware-->Keyboard,會分別看到三個選項:Use ...
  • Swift - 用UIScrollView實現視差動畫效果 效果 源碼 https://github.com/YouXianMing/Swift-Animations ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...