Erweitertes RenderScript

<ph type="x-smartling-placeholder">

Da Anwendungen, die RenderScript nutzen, immer noch innerhalb der Android-VM ausgeführt werden, haben Sie Zugriff auf alle Framework-APIs, mit denen Sie vertraut sind, gegebenenfalls RenderScript verwenden. Um diese Interaktion zwischen dem Framework und der RenderScript-Laufzeit, ist auch eine Zwischenschicht mit Code vorhanden. um die Kommunikation und Speicherverwaltung zwischen den beiden Codeebenen zu erleichtern. In diesem Dokument werden diese verschiedene Codeebenen und die gemeinsame Nutzung des Arbeitsspeichers durch die Android-VM und RenderScript-Laufzeit

RenderScript-Laufzeitebene

Ihr RenderScript-Code wurde kompiliert die in einer kompakten und klar definierten Laufzeitebene ausgeführt wird. Die RenderScript-Laufzeit-APIs bieten Unterstützung für rechenintensiven, portierbaren und automatisch skalierbaren Anzahl der auf einem Prozessor verfügbaren Kerne.

Hinweis:Die Standard-C-Funktionen im NDK müssen ausgeführt wird, sodass RenderScript nicht auf diese Bibliotheken zugreifen kann. da RenderScript auf verschiedenen Prozessortypen ausgeführt werden kann.

Sie definieren Ihren RenderScript-Code in .rs und .rsh im Verzeichnis src/ Ihres Android-Projekts. Der Code von der Funktion in den Zwischen-Bytecode Compiler llvm, der als Teil eines Android-Builds ausgeführt wird. Wenn Ihre Anwendung auf einem Gerät ausgeführt wird, wird der Bytecode dann (Just-in-Time) von einem anderen Gerät in Maschinencode kompiliert. Compiler llvm, der sich auf dem Gerät befindet. Der Maschinencode ist für den Gerät und auch im Cache gespeichert, sodass spätere Nutzungen der RenderScript-fähigen Anwendung den Bytecode neu zu kompilieren.

Zu den Hauptfunktionen der RenderScript-Laufzeitbibliotheken gehören:

  • Funktionen für Anfragen zur Arbeitsspeicherzuweisung
  • Große Sammlung mathematischer Funktionen mit überlasteten skalaren und vektortypisierten Versionen häufig vorkommenden Routinen. Operationen wie Addieren, Multiplizieren, Punktprodukt und Kreuzprodukt sowie atomare arithmetische und Vergleichsfunktionen.
  • Konvertierungsroutinen für primitive Datentypen und Vektoren, Matrixroutinen sowie Datum und Uhrzeit Abläufe
  • Datentypen und -strukturen zur Unterstützung des RenderScript-Systems wie Vektortypen für zwei-, drei- oder vier-Vektoren definieren.
  • Logging-Funktionen

Weitere Informationen zu den verfügbaren Funktionen finden Sie in der Referenz zur RenderScript RunScript Runtime API.

Reflektierte Ebene

Die widergespiegelte Ebene besteht aus einer Reihe von Klassen, die von den Android-Build-Tools generiert werden, um den Zugriff zu ermöglichen zur RenderScript-Laufzeit aus dem Android-Framework. Diese Ebene bietet auch Methoden, und Konstruktoren, die es Ihnen ermöglichen, Zeiger, die in Ihren RenderScript-Code. In der folgenden Liste werden die wichtigsten Komponenten, die sich spiegeln:

  • Jede von Ihnen erstellte .rs-Datei wird in einer Klasse namens project_root/gen/package/name/ScriptC_renderscript_filename von Geben Sie ScriptC ein. Diese Datei ist die .java-Version von .rs-Datei, die Sie aus dem Android-Framework aufrufen können. Diese Klasse enthält die Die folgenden Elemente spiegeln sich in der Datei .rs wider: <ph type="x-smartling-placeholder">
      </ph>
    • Nicht statische Funktionen
    • Nicht statische, globale RenderScript-Variablen. Accessor für jede Variable generiert, sodass Sie lesen und die RenderScript-Variablen aus der Android-App Framework. Wenn eine globale Variable bei der RenderScript-Laufzeitebene, werden diese Werte für Initialisieren der entsprechenden Werte im Android-Framework Ebene. Wenn globale Variablen als const gekennzeichnet sind, ist die set-Methode nicht generiert. Hier ansehen .

    • Globale Zeiger
  • Ein struct wird in einer eigenen Klasse namens project_root/gen/package/name/ScriptField_struct_name, die sich über Script.FieldBase erstreckt. Diese Klasse stellt ein Array der struct, mit dem Sie einer oder mehreren Instanzen dieses Speichers Arbeitsspeicher zuweisen können struct

Funktionen

Funktionen spiegeln sich in der Skriptklasse selbst wider, project_root/gen/package/name/ScriptC_renderscript_filename Für Beispiel, wenn Sie die folgende Funktion in Ihrem RenderScript-Code definieren:

void touch(float x, float y, float pressure, int id) {
    if (id >= 10) {
        return;
    }

    touchPos[id].x = x;
    touchPos[id].y = y;
    touchPressure[id] = pressure;
}

wird der folgende Java-Code generiert:

public void invoke_touch(float x, float y, float pressure, int id) {
    FieldPacker touch_fp = new FieldPacker(16);
    touch_fp.addF32(x);
    touch_fp.addF32(y);
    touch_fp.addF32(pressure);
    touch_fp.addI32(id);
    invoke(mExportFuncIdx_touch, touch_fp);
}

Funktionen können keine Rückgabewerte aufweisen, da das RenderScript-System asynchron. Wenn Ihr Android-Framework-Code RenderScript aufruft, wird der Aufruf in die Warteschlange gestellt und durchgeführt werden. Durch diese Einschränkung kann das RenderScript-System ohne konstante und erhöht die Effizienz. Wenn Funktionen Rückgabewerte haben dürfen, wird der Aufruf bis der Wert zurückgegeben wird.

Wenn der RenderScript-Code einen Wert an das Android-Framework zurücksenden soll, verwenden Sie die Methode rsSendToClient() .

Variablen

Variablen der unterstützten Typen werden in der Skriptklasse selbst wiedergegeben. Sie finden sie im project_root/gen/package/name/ScriptC_renderscript_filename Eine Zugriffsfunktion für jede Variable generiert. Wenn Sie beispielsweise die folgende Variable in Ihrem RenderScript-Code:

uint32_t unsignedInteger = 1;

wird der folgende Java-Code generiert:

private long mExportVar_unsignedInteger;
public void set_unsignedInteger(long v){
    mExportVar_unsignedInteger = v;
    setVar(mExportVarIdx_unsignedInteger, v);
}

public long get_unsignedInteger(){
    return mExportVar_unsignedInteger;
}
  

Strukturen

Structs werden in ihren eigenen Klassen widergespiegelt, die sich <project_root>/gen/com/example/renderscript/ScriptField_struct_name Dieses Klasse stellt ein Array von struct dar und ermöglicht das Zuweisen von Arbeitsspeicher angegebene Anzahl von structs Angenommen, Sie definieren die folgende Struktur:

typedef struct Point {
    float2 position;
    float size;
} Point_t;

wird der folgende Code in ScriptField_Point.java generiert:

package com.example.android.rs.hellocompute;

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

  /**
  * @hide
  */
public class ScriptField_Point extends android.renderscript.Script.FieldBase {

    static public class Item {
        public static final int sizeof = 12;

        Float2 position;
        float size;

        Item() {
            position = new Float2();
        }
    }

    private Item mItemArray[];
    private FieldPacker mIOBuffer;
    public static Element createElement(RenderScript rs) {
        Element.Builder eb = new Element.Builder(rs);
        eb.add(Element.F32_2(rs), "position");
        eb.add(Element.F32(rs), "size");
        return eb.create();
    }

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

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

    private void copyToArray(Item i, int index) {
        if (mIOBuffer == null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count
        */);
        mIOBuffer.reset(index * Item.sizeof);
        mIOBuffer.addF32(i.position);
        mIOBuffer.addF32(i.size);
    }

    public 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);
            mAllocation.setFromFieldPacker(index, mIOBuffer);
        }
    }

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

    public void set_position(int index, Float2 v, boolean copyNow) {
        if (mIOBuffer == null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count */);
        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
        if (mItemArray[index] == null) mItemArray[index] = new Item();
        mItemArray[index].position = v;
        if (copyNow) {
            mIOBuffer.reset(index * Item.sizeof);
            mIOBuffer.addF32(v);
            FieldPacker fp = new FieldPacker(8);
            fp.addF32(v);
            mAllocation.setFromFieldPacker(index, 0, fp);
        }
    }

    public void set_size(int index, float v, boolean copyNow) {
        if (mIOBuffer == null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count */);
        if (mItemArray == null) mItemArray = new Item[getType().getX() /* count */];
        if (mItemArray[index] == null) mItemArray[index] = new Item();
        mItemArray[index].size = v;
        if (copyNow)  {
            mIOBuffer.reset(index * Item.sizeof + 8);
            mIOBuffer.addF32(v);
            FieldPacker fp = new FieldPacker(4);
            fp.addF32(v);
            mAllocation.setFromFieldPacker(index, 1, fp);
        }
    }

    public Float2 get_position(int index) {
        if (mItemArray == null) return null;
        return mItemArray[index].position;
    }

    public float get_size(int index) {
        if (mItemArray == null) return 0;
        return mItemArray[index].size;
    }

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

    public void resize(int newSize) {
        if (mItemArray != null)  {
            int oldSize = mItemArray.length;
            int copySize = Math.min(oldSize, newSize);
            if (newSize == oldSize) return;
            Item ni[] = new Item[newSize];
            System.arraycopy(mItemArray, 0, ni, 0, copySize);
            mItemArray = ni;
        }
        mAllocation.resize(newSize);
        if (mIOBuffer != null) mIOBuffer = new FieldPacker(Item.sizeof * getType().getX()/* count */);
    }
}

Der generierte Code wird Ihnen zur Verfügung gestellt, damit Sie Arbeitsspeicher für die angeforderten Structs zuweisen können. durch die RenderScript-Laufzeit aus und interagieren mit structs. im Gedächtnis gespeichert. In jeder struct-Klasse werden die folgenden Methoden und Konstruktoren definiert:

  • Überlastete Konstruktoren, mit denen Sie Arbeitsspeicher zuweisen können. Die Der ScriptField_struct_name(RenderScript rs, int count)-Konstruktor ermöglicht definieren Sie die Anzahl der Strukturen, der Sie Arbeitsspeicher zuweisen möchten, count-Parameter. Der ScriptField_struct_name(RenderScript rs, int count, int usages)-Konstruktor definiert den zusätzlichen Parameter usages, der können Sie den Arbeitsspeicherbereich dieser Arbeitsspeicherzuweisung angeben. Es gibt vier Speicherbereiche, Möglichkeiten: <ph type="x-smartling-placeholder">

    Mit dem bitweisen Operator OR können Sie mehrere Speicherbereiche angeben. Vorgehensweise benachrichtigt die RenderScript-Laufzeit, dass Sie auf die Daten im angegebenen Speicherbereichen. Im folgenden Beispiel wird Arbeitsspeicher für einen benutzerdefinierten Datentyp zugewiesen sowohl im Skript- als auch im Scheitelpunktspeicherbereich:

    Kotlin

    val touchPoints: ScriptField_Point = ScriptField_Point(
            myRenderScript,
            2,
            Allocation.USAGE_SCRIPT or Allocation.USAGE_GRAPHICS_VERTEX
    )
    

    Java

    ScriptField_Point touchPoints = new ScriptField_Point(myRenderScript, 2,
            Allocation.USAGE_SCRIPT | Allocation.USAGE_GRAPHICS_VERTEX);
    
  • Mit der statischen verschachtelten Klasse Item können Sie eine Instanz der struct in Form eines Objekts. Diese verschachtelte Klasse ist nützlich, durch die struct in Ihrem Android-Code. Wenn Sie mit der Bearbeitung des Objekts fertig sind, können Sie das Objekt in den zugewiesenen Speicher übertragen, indem Sie set(Item i, int index, boolean copyNow) aufrufen und Item an die gewünschte Position im das Array. Die RenderScript-Laufzeit hat automatisch Zugriff auf den neu geschriebenen Arbeitsspeicher.
  • Zugriffsmethoden zum Abrufen und Festlegen der Werte der einzelnen Felder in einer Struktur. Jede dieser Optionen Zugriffsmethode auf Methoden hat einen index-Parameter, um die struct in das Array, in das Sie schreiben oder lesen möchten. Jede Setter-Methode hat auch ein copyNow-Parameter, der angibt, ob diese Erinnerung sofort synchronisiert werden soll in die RenderScript-Laufzeit ein. Um Erinnerungen zu synchronisieren, die nicht synchronisiert wurden, rufe copyAll()
  • Die Methode createElement() erstellt eine Beschreibung der Struktur im Arbeitsspeicher. Dieses description wird verwendet, um Speicher zuzuweisen, der aus einem oder mehreren Elementen besteht.
  • resize() funktioniert ähnlich wie ein realloc() in C, sodass Sie den zuvor zugewiesenen Speicher erweitern und die aktuellen Werte beibehalten, erstellt.
  • copyAll() synchronisiert den auf Framework-Ebene festgelegten Arbeitsspeicher mit dem RenderScript-Laufzeit Wenn Sie für ein Mitglied eine Zugriffsmethode festlegen, gibt es eine optionale Funktion. Boolescher Parameter copyNow, den Sie angeben können. Angabe true synchronisiert den Arbeitsspeicher, wenn Sie die Methode aufrufen. Wenn Sie „false“ angeben, können Sie copyAll() einmal aufrufen, um den Speicher für alle Eigenschaften, die noch nicht synchronisiert wurden.

Mauszeiger

Globale Verweise werden in der Skriptklasse selbst widergespiegelt, die sich im project_root/gen/package/name/ScriptC_renderscript_filename Ich kann Zeiger auf ein struct oder einen der unterstützten RenderScript-Typen deklarieren, aber ein struct darf keine Zeiger oder verschachtelten Arrays enthalten. Wenn Sie beispielsweise die Folgende Verweise auf struct und int32_t

typedef struct Point {
    float2 position;
    float size;
} Point_t;

Point_t *touchPoints;
int32_t *intPointer;

wird der folgende Java-Code generiert:

private ScriptField_Point mExportVar_touchPoints;
public void bind_touchPoints(ScriptField_Point v) {
    mExportVar_touchPoints = v;
    if (v == null) bindAllocation(null, mExportVarIdx_touchPoints);
    else bindAllocation(v.getAllocation(), mExportVarIdx_touchPoints);
}

public ScriptField_Point get_touchPoints() {
    return mExportVar_touchPoints;
}

private Allocation mExportVar_intPointer;
public void bind_intPointer(Allocation v) {
    mExportVar_intPointer = v;
    if (v == null) bindAllocation(null, mExportVarIdx_intPointer);
    else bindAllocation(v, mExportVarIdx_intPointer);
}

public Allocation get_intPointer() {
    return mExportVar_intPointer;
}
  

Eine get-Methode und eine spezielle Methode namens bind_pointer_name (anstelle einer set()-Methode) generiert werden. Mit der Methode bind_pointer_name können Sie den Arbeitsspeicher binden das in der Android-VM der RenderScript-Laufzeit zugewiesen ist. Sie können Arbeitsspeicher in der Datei .rs). Weitere Informationen finden Sie unter Arbeiten mit „Alised Memory“.

APIs zur Arbeitsspeicherzuweisung

Anwendungen, die RenderScript verwenden, werden weiterhin auf der Android-VM ausgeführt. Der eigentliche RenderScript-Code wird jedoch nativ ausgeführt und benötigt Zugriff auf den Arbeitsspeicher, der in der Android-VM zugewiesen ist. Um dies zu erreichen, müssen Sie Der Arbeitsspeicher, der in der VM zugewiesen ist, wird der RenderScript-Laufzeit zugeordnet. Dieses -Vorgang (Bindung) ermöglicht der RenderScript-Laufzeit, nahtlos mit dem Speicher zu arbeiten, -Anfragen aber nicht explizit zuweisen. Das Endergebnis ist im Wesentlichen das gleiche, mit dem Namen malloc in C. Der zusätzliche Vorteil besteht darin, dass die Android-VM die automatische Speicherbereinigung ausführen kann, Arbeitsspeicher gemeinsam mit der RenderScript-Laufzeitebene nutzen. Das Binden ist nur für dynamisch zugewiesenen Arbeitsspeicher erforderlich. Statisch Der zugewiesene Speicher wird für den RenderScript-Code bei der Kompilierung automatisch erstellt. Siehe Abbildung 1 finden Sie weitere Informationen zur Speicherzuweisung.

Zur Unterstützung dieses Arbeitsspeicherzuweisungssystems gibt es eine Reihe von APIs, mit denen die Android-VM Arbeitsspeicher zuweisen und bieten ähnliche Funktionen wie ein malloc-Aufruf. Diese Kurse beschreiben, wie der Arbeitsspeicher zugewiesen werden sollte, und führen auch die Zuordnung durch. Damit Sie wie diese Klassen funktionieren, ist es hilfreich, sie in Bezug malloc-Aufruf, der so aussehen kann:

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

Der Aufruf malloc kann in zwei Teile unterteilt werden: die Größe des zugewiesenen Arbeitsspeichers (sizeof(int)), sowie die Anzahl der Speichereinheiten, die zugewiesen werden sollen (10). Das Android-Framework stellt Klassen für diese beiden Teile sowie eine Klasse, die malloc selbst darstellt.

Die Klasse Element stellt den Teil (sizeof(int)) dar des malloc-Aufrufs und kapselt eine Zelle einer Arbeitsspeicherzuweisung, z. B. eine einzelne Gleitkommawert oder eine Struktur. Die Klasse Type kapselt das Element und die Menge der zuzuweisenden Elemente (in unserem Beispiel 10). Sie können sich einen Type als Ein Array mit Element-Werten. Die Klasse Allocation übernimmt die Arbeitsspeicherzuweisung basierend auf einem bestimmten Type und stellt den tatsächlich zugewiesenen Arbeitsspeicher dar.

In den meisten Fällen müssen Sie diese APIs zur Arbeitsspeicherzuweisung nicht direkt aufrufen. Die reflektierte Schicht Klassen generieren Code zur Verwendung dieser APIs. Zum Zuweisen von Arbeitsspeicher müssen Sie lediglich eine -Konstruktor an, der in einer der Klassen für reflektierte Ebenen deklariert ist, und binden Sie den resultierenden Allocation-Speicher an das RenderScript. Es gibt Situationen, in denen Sie diese Klassen direkt verwenden möchten, um Speicher zum Beispiel das Laden einer Bitmap aus einer Ressource oder das Zuweisen von Arbeitsspeicher für Verweise auf primitiven Typen. Eine Anleitung dazu finden Sie Speicher dem RenderScript-Abschnitt zuweisen und ihn binden In der folgenden Tabelle werden die drei Arbeitsspeicherverwaltungsklassen ausführlicher beschrieben:

Android-Objekttyp Beschreibung
Element

Ein Element beschreibt eine Zelle einer Arbeitsspeicherzuweisung und kann in zwei Formen auftreten: einfach oder komplex sind.

Ein Basiselement enthält eine einzelne Datenkomponente eines beliebigen gültigen RenderScript-Datentyps. Beispiele für grundlegende Elementdatentypen sind ein einzelner float-Wert, ein float4-Vektor oder ein einzelne RGB-565-Farbe.

Komplexe Elemente enthalten eine Liste grundlegender Elemente und werden aus struct-Elemente, die Sie im RenderScript-Code deklarieren. Zum Beispiel könnte eine Zuordnung kann mehrere structs enthalten, die der Reihe nach im Speicher angeordnet sind. Jede Struktur wird als ihre und nicht auf jeden Datentyp innerhalb dieser Struktur.

Type

Ein Typ ist eine Vorlage für die Arbeitsspeicherzuweisung und besteht aus einem Element und mindestens einem Dimensionen. Sie beschreibt das Layout des Arbeitsspeichers (im Grunde ein Array von Elements), weist jedoch keinen Speicher für die Daten zu, die er enthält. beschrieben.

Ein Typ besteht aus fünf Dimensionen: X, Y, Z, Detailebene (Detailebene) und Flächen (eines Würfels). Karte). Sie können die Dimensionen X, Y und Z auf eine beliebige positive Ganzzahl innerhalb des des verfügbaren Arbeitsspeichers. Eine einzelne Dimensionszuweisung hat die x-Dimension größer als null sind, während die Dimensionen Y und Z null sind, um anzuzeigen, dass das Element nicht vorhanden ist. Für Beispiel: Eine Zuordnung von x=10, y=1 wird als zweidimensional angesehen, und x=10, y=0 ist als eindimensional betrachtet. Die Dimensionen „LOD“ und „Faces“ sind boolesche Werte zur Angabe, oder nicht vorhanden ist.

Allocation

Eine Zuordnung stellt den Arbeitsspeicher für Anwendungen basierend auf einer Beschreibung des Arbeitsspeichers bereit der durch ein Type dargestellt wird. Zugewiesener Arbeitsspeicher kann in Arbeitsspeicher auf mehreren Ebenen gleichzeitig. Wenn der Arbeitsspeicher in einem Bereich geändert wird, müssen Sie explizit synchronisiert den Arbeitsspeicher, sodass er in allen anderen Bereichen, in denen er vorhanden ist, aktualisiert wird.

Zuordnungsdaten werden hauptsächlich auf zwei Arten hochgeladen: mit einem Häkchen und mit dem ohne Häkchen. Für einfache Arrays gibt es copyFrom()-Funktionen, die ein Array aus Android-System und kopieren Sie es in den nativen Layer-Speicher. Die ungeprüften Varianten können dass das Android-System Arrays von Strukturen kopieren kann, da es Strukturen. Wenn es beispielsweise eine Zuordnung gibt, die ein Array aus n Gleitkommazahlen ist, werden die Daten die in einem float[n]- oder byte[n*4]-Array enthalten sind, können kopiert werden.

Mit Memory arbeiten

Nicht statische, globale Variablen, die Sie in Ihrem RenderScript deklarieren, werden zum Zeitpunkt der Kompilierung zugewiesen. Sie können diese Variablen direkt in Ihrem RenderScript-Code verwenden, ohne auf der Ebene des Android-Frameworks. Auch die Android-Framework-Ebene hat Zugriff auf diese Variablen. mit den bereitgestellten Zugriffsmethoden, die in den Klassen der reflektierten Ebenen generiert werden. Wenn diese Variablen die auf der RenderScript-Laufzeitebene initialisiert wurden, werden diese Werte zur Initialisierung der entsprechenden auf der Android-Framework-Ebene. Wenn globale Variablen als const gekennzeichnet sind, ist eine set-Methode nicht generiert. Weitere Informationen

Hinweis:Wenn Sie bestimmte RenderScript-Strukturen verwenden, die Verweise enthalten, z. B. rs_program_fragment und rs_allocation müssen Sie ein Objekt des entsprechenden Android-Framework-Klasse und rufen dann dafür die Methode set auf. -Struktur fest, um den Speicher an die RenderScript-Laufzeit zu binden. Sie können diese Strukturen nicht direkt bearbeiten auf der RenderScript-Laufzeitebene. Diese Einschränkung gilt nicht für benutzerdefinierte Strukturen die Zeiger enthalten, da diese nicht in eine Klasse für reflektierte Ebenen exportiert werden können überhaupt erst. Ein Compiler-Fehler wird generiert, wenn Sie versuchen, eine nicht-statische, globale Struktur, die einen Zeiger enthält.

RenderScript unterstützt auch Pointer, aber Sie müssen den Speicher explizit in Ihrem Android-Framework-Code Wenn Sie einen globalen Zeiger in Ihrer .rs-Datei deklarieren, Ordnen Sie Arbeitsspeicher über die entsprechende reflektierte Schichtklasse zu und binden Sie diesen Speicher an die native RenderScript-Ebene. Sie können über die Android-Framework-Ebene mit diesem Memory interagieren der RenderScript-Ebene, die Ihnen die Flexibilität bietet, Variablen so weit wie möglich entsprechenden Layers.

Dynamischen Speicher dem RenderScript zuordnen und an ihn binden

Um dynamischen Arbeitsspeicher zuzuweisen, müssen Sie den Konstruktor eines Script.FieldBase, die gängigste Methode. Alternativ können Sie auch Allocation manuell. Dies ist z. B. für Zeiger primitiver Typen erforderlich. Sie sollten Verwenden Sie der Einfachheit halber nach Möglichkeit einen Script.FieldBase-Klassenkonstruktor. Nachdem Sie eine Arbeitsspeicherzuweisung erhalten haben, rufen Sie die reflektierte bind-Methode des Zeigers auf, um den zugewiesenen Speicher an den RenderScript-Laufzeit

Im folgenden Beispiel wird Speicher sowohl für einen primitiven Zeiger zugewiesen, intPointer und einem Zeiger auf die Struktur touchPoints. Außerdem wird der Speicher mit dem RenderScript:

Kotlin

private lateinit var myRenderScript: RenderScript
private lateinit var script: ScriptC_example
private lateinit var resources: Resources

public fun init(rs: RenderScript, res: Resources) {
    myRenderScript = rs
    resources = res

    // allocate memory for the struct pointer, calling the constructor
    val touchPoints = ScriptField_Point(myRenderScript, 2)

    // Create an element manually and allocate memory for the int pointer
    val intPointer: Allocation = Allocation.createSized(myRenderScript, Element.I32(myRenderScript), 2)

    // create an instance of the RenderScript, pointing it to the bytecode resource
    script = ScriptC_point(myRenderScript/*, resources, R.raw.example*/)

    // bind the struct and int pointers to the RenderScript
    script.bind_touchPoints(touchPoints)
    script.bind_intPointer(intPointer)

   ...
}

Java

private RenderScript myRenderScript;
private ScriptC_example script;
private Resources resources;

public void init(RenderScript rs, Resources res) {
    myRenderScript = rs;
    resources = res;

    // allocate memory for the struct pointer, calling the constructor
    ScriptField_Point touchPoints = new ScriptField_Point(myRenderScript, 2);

    // Create an element manually and allocate memory for the int pointer
    intPointer = Allocation.createSized(myRenderScript, Element.I32(myRenderScript), 2);

    // create an instance of the RenderScript, pointing it to the bytecode resource
    script = new ScriptC_example(myRenderScript, resources, R.raw.example);

    // bind the struct and int pointers to the RenderScript
    script.bind_touchPoints(touchPoints);
    script.bind_intPointer(intPointer);

   ...
}

Lesen und Schreiben in den Arbeitsspeicher

Sie können in der RenderScript-Laufzeit statisch und dynamisch zugewiesenen Speicher lesen und schreiben. und Android-Framework-Ebene.

Statisch zugewiesener Arbeitsspeicher unterliegt einer Einwegkommunikationseinschränkung auf der RenderScript-Laufzeitebene. Wenn der RenderScript-Code den Wert einer Variablen ändert, ist dies zur Steigerung der Effizienz an die Android-Framework-Ebene zurückgesendet. Der letzte Wert die vom Android-Framework festgelegt wird, wird bei einem Aufruf von get immer zurückgegeben. . Wenn jedoch der Android-Framework-Code eine Variable ändert, kann diese Änderung die RenderScript-Laufzeit automatisch oder zu einem späteren Zeitpunkt synchronisiert. Wenn Sie Daten senden müssen von der RenderScript-Laufzeit zur Android-Framework-Ebene übertragen, können Sie die Methode rsSendToClient()-Funktion diese Begrenzung zu überwinden.

Bei der Arbeit mit dynamisch zugewiesenem Arbeitsspeicher werden alle Änderungen an der RenderScript-Laufzeitebene weitergegeben zurück zur Android-Framework-Ebene, wenn Sie die Arbeitsspeicherzuweisung mithilfe des zugehörigen Zeigers geändert haben. Wird ein Objekt auf der Android-Framework-Ebene geändert, wird diese Änderung sofort in das RenderScript-Format übernommen. Laufzeitebene.

Globale Variablen lesen und schreiben

Das Lesen und Schreiben von globalen Variablen ist ein einfacher Vorgang. Sie können die Zugriffsmethoden auf Android-Framework-Ebene ausführen oder sie direkt im RenderScript-Code festlegen. Denken Sie daran, dass alle Änderungen am RenderScript-Code werden nicht übernommen. zurück zur Android-Framework-Ebene, Hier finden Sie weitere Informationen. .

Beispiel: Bei der folgenden Struktur, die in einer Datei mit dem Namen rsfile.rs deklariert wurde:

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

Point_t point;

Du kannst der Struktur direkt in rsfile.rs Werte zuweisen. Diese Werte sind nicht auf die Android-Framework-Ebene übergeben:

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

Sie können der Struktur auf der Ebene des Android-Frameworks auf folgende Weise Werte zuweisen. Diese Werte sind asynchron an die RenderScript-Laufzeitebene zurückgegeben:

Kotlin

val script: ScriptC_rsfile = ...

...

script._point = ScriptField_Point.Item().apply {
    x = 1
    y = 1
}

Java

ScriptC_rsfile script;

...

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

Sie können die Werte in Ihrem RenderScript-Code wie folgt lesen:

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

Mit dem folgenden Code können Sie die Werte in der Android-Framework-Ebene lesen. Beachten Sie, dass dies Code gibt nur dann einen Wert zurück, wenn einer auf Android-Framework-Ebene festgelegt wurde. Sie erhalten einen Nullzeiger, Ausnahme, wenn Sie den Wert nur auf der RenderScript-Laufzeitebene festlegen:

Kotlin

Log.i("TAGNAME", "Printing out a Point: ${mScript._point.x} ${mScript._point.y}")
println("${point.x} ${point.y}")

Java

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

Globale Hinweise lesen und schreiben

Unter der Annahme, dass Arbeitsspeicher auf Android-Framework-Ebene zugewiesen und an die RenderScript-Laufzeit gebunden ist, Sie können Arbeitsspeicher auf Android-Framework-Ebene mit den Methoden get und set für diesen Zeiger lesen und schreiben. Auf der RenderScript-Laufzeitebene können Sie wie gewohnt mit Zeigern lesen und schreiben und die Änderungen werden übernommen. im Gegensatz zum statisch zugewiesenen Speicher zurück in die Android-Framework-Ebene.

Im folgenden Beispiel wird auf eine struct in einer Datei namens rsfile.rs verwiesen:

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

Point_t *point;

Wenn Sie bereits Arbeitsspeicher auf Android-Framework-Ebene zugewiesen haben, können Sie auf Werte in struct wie gewohnt. Alle Änderungen, die Sie über die Zeigervariable der Struktur vornehmen sind automatisch für die Android-Framework-Ebene verfügbar:

Kotlin

point[index].apply {
    x = 1
    y = 1
}

Java

point[index].x = 1;
point[index].y = 1;

Sie können auch Werte auf der Android-Framework-Ebene lesen und schreiben:

Kotlin

val i = ScriptField_Point.Item().apply {
    x = 100
    y = 100
}
val p = ScriptField_Point(rs, 1).apply {
    set(i, 0, true)
}
script.bind_point(p)

p.get_x(0)            //read x and y from index 0
p.get_y(0)

Java

ScriptField_Point p = new ScriptField_Point(rs, 1);
Item i = new ScriptField_Point.Item();
i.x=100;
i.y = 100;
p.set(i, 0, true);
script.bind_point(p);

p.get_x(0);            //read x and y from index 0
p.get_y(0);

Sobald der Arbeitsspeicher bereits gebunden ist, müssen Sie den Arbeitsspeicher nicht noch einmal an das RenderScript-Objekt binden. Laufzeit, wenn Sie einen Wert ändern.