Aplikasi yang menggunakan RenderScript masih berjalan di dalam VM Android sehingga Anda memiliki akses ke semua API framework yang sudah biasa Anda gunakan, tetapi juga dapat memanfaatkan RenderScript jika perlu. Untuk memudahkan interaksi antara framework dan runtime RenderScript ini, lapisan kode menengah juga tersedia untuk mempermudah manajemen memori dan komunikasi di antara kedua level kode. Dokumen ini membahas berbagai lapisan kode ini secara lebih mendetail, serta bagaimana memori dibagi antara VM Android dan runtime RenderScript.
Lapisan Runtime RenderScript
Kode RenderScript Anda dikompilasi dan dieksekusi dalam lapisan runtime yang ringkas dan didefinisikan dengan baik. API runtime RenderScript menawarkan dukungan untuk komputasi intensif yang portabel dan skalabel secara otomatis sesuai jumlah core yang tersedia pada prosesor.
Catatan: Fungsi C standar dalam NDK harus dipastikan berjalan pada salah satu CPU, sehingga RenderScript tidak dapat mengakses library ini, karena RenderScript dirancang untuk berjalan pada berbagai jenis prosesor.
Tentukan kode RenderScript dalam file .rs
dan .rsh
di direktori src/
project Android Anda. Kode akan
dikompilasi menjadi bytecode menengah oleh
compiler llvm
yang berjalan sebagai bagian dari build Android. Saat aplikasi Anda
berjalan di perangkat, bytecode kemudian akan dikompilasi (pada saat yang sama) ke kode mesin oleh kompilator llvm
lain
yang berada di perangkat tersebut. Kode mesin dioptimalkan untuk
perangkat dan juga di-cache sehingga penggunaan aplikasi yang didukung RenderScript berikutnya tidak
mengompilasi ulang bytecode tersebut.
Beberapa fitur utama library runtime RenderScript meliputi:
- Fitur permintaan alokasi memori
- Sekumpulan besar fungsi matematika dengan versi kelebihan muatan berjenis skalar dan vektor dari berbagai rutinitas umum. Tersedia operasi seperti penambahan, perkalian, dot product, dan cross product, serta fungsi perbandingan dan aritmetika simpel.
- Rutinitas konversi untuk vektor dan jenis data primitif, rutinitas matriks, serta rutinitas tanggal dan waktu
- Struktur dan jenis data untuk mendukung sistem RenderScript, seperti jenis Vektor untuk menentukan dua, tiga, atau empat vektor.
- Fungsi logging
Lihat referensi API runtime RenderScript untuk informasi selengkapnya tentang fungsi yang tersedia.
Lapisan yang Direfleksikan
Lapisan yang direfleksikan adalah sekumpulan class yang dihasilkan oleh fitur build Android untuk memungkinkan akses ke runtime RenderScript dari framework Android. Lapisan ini juga menyediakan metode dan konstruktor yang memungkinkan Anda mengalokasikan dan bekerja dengan memori untuk pointer yang ditentukan dalam kode RenderScript Anda. Daftar berikut menjelaskan komponen utama yang direfleksikan:
- Setiap file
.rs
yang Anda buat akan diubah menjadi class yang bernamaproject_root/gen/package/name/ScriptC_renderscript_filename
dengan jenisScriptC
. File ini adalah versi.java
file.rs
Anda, yang dapat dipanggil dari framework Android. Class ini berisi item berikut yang direfleksikan dari file.rs
:- Fungsi nonstatis
- Variabel RenderScript global nonstatis. Metode
pengakses akan dibuat untuk setiap variabel sehingga Anda dapat membaca dan
menulis variabel RenderScript dari framework
Android. Jika variabel global diinisialisasi pada
lapisan runtime RenderScript, nilai tersebut akan digunakan untuk
menginisialisasi nilai yang berkaitan dalam lapisan framework
Android. Jika variabel global ditandai sebagai
const
, metodeset
tidak akan dibuat. Lihat di sini untuk detail selengkapnya. - Pointer global
struct
direfleksikan ke dalam class-nya sendiri yang bernamaproject_root/gen/package/name/ScriptField_struct_name
, yang memperluasScript.FieldBase
. Class ini merepresentasikan arraystruct
, yang memungkinkan Anda mengalokasikan memori untuk satu atau beberapa instance daristruct
ini.
Fungsi
Fungsi direfleksikan ke dalam class skrip sendiri, yang berada di
project_root/gen/package/name/ScriptC_renderscript_filename
. Sebagai
contoh, jika Anda menentukan fungsi berikut dalam kode RenderScript Anda:
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; }
kode Java berikut akan dibuat:
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); }
Fungsi tidak boleh memiliki nilai hasil, karena sistem RenderScript didesain agar berjalan secara asinkron. Saat kode framework Android memanggil RenderScript, panggilan tersebut akan diantrekan dan dijalankan ketika memungkinkan. Batasan ini memungkinkan sistem RenderScript berfungsi tanpa gangguan konstan, yang kemudian akan meningkatkan efisiensi. Jika fungsi diperbolehkan memiliki nilai hasil, panggilan akan diblokir hingga nilai tersebut dihasilkan.
Jika Anda ingin kode RenderScript mengirimkan nilai kembali ke framework Android, gunakan
fungsi
rsSendToClient()
.
Variabel
Variabel dari jenis yang didukung direfleksikan ke dalam class skrip sendiri, yang berada di
project_root/gen/package/name/ScriptC_renderscript_filename
. Serangkaian metode pengakses
akan dibuat untuk setiap variabel. Sebagai contoh, jika Anda menentukan variabel berikut dalam
kode RenderScript Anda:
uint32_t unsignedInteger = 1;
kode Java berikut akan dibuat:
private long mExportVar_unsignedInteger; public void set_unsignedInteger(long v){ mExportVar_unsignedInteger = v; setVar(mExportVarIdx_unsignedInteger, v); } public long get_unsignedInteger(){ return mExportVar_unsignedInteger; }
Struct
Struct direfleksikan ke dalam class-nya sendiri, yang berada di
<project_root>/gen/com/example/renderscript/ScriptField_struct_name
. Class ini
merepresentasikan array dari struct
dan memungkinkan Anda mengalokasikan memori untuk
struct
dalam jumlah tertentu. Sebagai contoh, jika Anda menentukan struct berikut:
typedef struct Point { float2 position; float size; } Point_t;
kode berikut akan dibuat di ScriptField_Point.java
:
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 */); } }
Kode yang dihasilkan kemudian diberikan kepada Anda untuk memudahkan alokasi memori bagi struct yang diminta oleh runtime RenderScript dan untuk berinteraksi dengan struct
dalam memori. Setiap class struct
menentukan metode dan konstruktor berikut:
- Konstruktor kelebihan muatan yang memungkinkan Anda mengalokasikan memori. Konstruktor
ScriptField_struct_name(RenderScript rs, int count)
memungkinkan Anda menentukan jumlah struktur yang diinginkan untuk mengalokasikan memori dengan parametercount
. KonstruktorScriptField_struct_name(RenderScript rs, int count, int usages)
menentukan parameter tambahan,usages
, yang memungkinkan Anda menentukan ruang memori alokasi memori ini. Terdapat empat kemungkinan ruang memori:USAGE_SCRIPT
: Mengatur alokasi di ruang memori skrip. Ini adalah ruang memori default jika Anda tidak menentukan ruang memori.USAGE_GRAPHICS_TEXTURE
: Mengatur alokasi di ruang memori tekstur GPU.USAGE_GRAPHICS_VERTEX
: Mengatur alokasi di ruang memori verteks GPU.USAGE_GRAPHICS_CONSTANTS
: Mengatur alokasi di ruang memori konstanta GPU yang digunakan oleh berbagai objek program.
Anda dapat menentukan beberapa ruang memori menggunakan operator
OR
bitwise. Dengan demikian, runtime RenderScript akan diberi tahu bahwa Anda ingin mengakses data di ruang memori yang ditentukan. Contoh berikut mengalokasikan memori untuk jenis data kustom di ruang memori skrip dan verteks: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);
- Class bertingkat yang bersifat statis,
Item
, memungkinkan Anda membuat instancestruct
dalam bentuk objek. Class bertingkat ini berguna jika dirasa lebih logis saat bekerja denganstruct
dalam kode Android Anda. Setelah selesai memanipulasi objek tersebut, Anda dapat memasukkannya ke memori yang dialokasikan dengan memanggilset(Item i, int index, boolean copyNow)
dan mengaturItem
ke posisi yang diinginkan dalam array. Runtime RenderScript akan otomatis memiliki akses ke memori yang baru ditulis tersebut. - Metode pengakses untuk mendapatkan dan menentukan nilai setiap kolom dalam struct. Masing-masing
metode pengakses ini memiliki parameter
index
untuk menetapkanstruct
dalam array tujuan pembacaan atau penulisan Anda. Setiap metode penyetel juga memiliki parametercopyNow
yang menetapkan apakah memori ini akan langsung disinkronkan ke runtime RenderScript atau tidak. Untuk menyinkronkan memori yang belum disinkronkan, panggilcopyAll()
. - Metode
createElement()
akan membuat deskripsi struct dalam memori. Deskripsi ini digunakan untuk mengalokasikan memori yang terdiri dari satu atau beberapa elemen. resize()
bekerja sepertirealloc()
di C, yang memungkinkan Anda memperluas memori yang telah dialokasikan, dan mempertahankan nilai saat ini yang dibuat sebelumnya.copyAll()
menyinkronkan memori yang telah ditentukan pada level framework ke runtime RenderScript. Saat Anda memanggil metode pengakses yang telah ditentukan pada sebuah anggota, terdapat parameter booleancopyNow
opsional yang dapat Anda tetapkan. Menetapkantrue
akan menyinkronkan memori saat Anda memanggil metode tersebut. Jika menetapkan false, Anda dapat memanggilcopyAll()
sekali, dan tindakan ini akan menyinkronkan memori untuk semua properti yang belum disinkronkan.
Pointer
Pointer global direfleksikan ke dalam class skrip sendiri, yang berada di
project_root/gen/package/name/ScriptC_renderscript_filename
. Anda
dapat mendeklarasikan pointer ke struct
atau salah satu jenis RenderScript yang didukung, tetapi
struct
tidak boleh berisi pointer atau array bertingkat. Sebagai contoh, jika Anda menentukan
pointer berikut ke struct
dan int32_t
typedef struct Point { float2 position; float size; } Point_t; Point_t *touchPoints; int32_t *intPointer;
kode Java berikut akan dibuat:
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; }
Metode get
dan metode khusus bernama bind_pointer_name
(bukan metode set()
) akan dibuat. Metode bind_pointer_name
memungkinkan Anda mengikat memori
yang dialokasikan di VM Android ke runtime RenderScript (Anda tidak dapat mengalokasikan
memori dalam file .rs
). Untuk informasi selengkapnya, lihat Bekerja
dengan Memori yang Dialokasikan.
API Alokasi Memori
Aplikasi yang menggunakan RenderScript masih berjalan di VM Android. Namun, kode RenderScript yang sebenarnya berjalan secara native dan
memerlukan akses ke memori yang dialokasikan di VM Android. Untuk melakukannya, Anda harus
menyematkan memori yang dialokasikan dalam VM ke runtime RenderScript. Proses
yang disebut binding ini memungkinkan runtime RenderScript bekerja tanpa masalah dengan memori yang dimintanya tetapi tidak dapat dialokasikan secara eksplisit. Hasil akhirnya pada dasarnya sama seperti jika Anda
memanggil malloc
di C. Keuntungan lainnya adalah bahwa VM Android dapat melakukan pembersihan sampah memori serta
berbagi memori dengan lapisan runtime RenderScript. Binding hanya diperlukan untuk memori yang dialokasikan secara dinamis. Memori
yang dialokasikan secara statis otomatis dibuat untuk kode RenderScript pada waktu kompilasi. Lihat Gambar 1
untuk informasi selengkapnya tentang cara alokasi memori dilakukan.
Untuk mendukung sistem alokasi memori ini, ada sekumpulan API yang memungkinkan VM Android
mengalokasikan memori dan menawarkan fungsionalitas serupa ke panggilan malloc
. Class ini
pada dasarnya menjelaskan bagaimana memori harus dialokasikan, kemudian juga melakukan alokasi tersebut. Untuk lebih
memahami cara kerjanya, coba pikirkan class tersebut sehubungan dengan panggilan malloc
sederhana
yang mungkin terlihat seperti berikut:
array = (int *)malloc(sizeof(int)*10);
Panggilan malloc
dapat dipecah menjadi dua bagian: ukuran memori yang dialokasikan (sizeof(int)
),
beserta berapa banyak unit dari memori tersebut yang harus dialokasikan (10). Framework Android menyediakan class untuk dua bagian ini
serta class untuk merepresentasikan malloc
sendiri.
Class Element
merepresentasikan bagian (sizeof(int)
)
dari panggilan malloc
dan mengenkapsulasi satu sel alokasi memori, seperti nilai
float tunggal atau struct. Class Type
mengenkapsulasi Element
dan jumlah elemen yang akan dialokasikan (10 dalam contoh kami). Anda dapat menganggap Type
sebagai
array Element
. Class Allocation
melakukan alokasi memori aktual
berdasarkan Type
yang ditentukan dan merepresentasikan memori aktual yang dialokasikan.
Biasanya, Anda tidak perlu memanggil API alokasi memori ini secara langsung. Class lapisan
yang direfleksikan akan menghasilkan kode untuk otomatis menggunakan API ini, dan untuk mengalokasikan memori, Anda hanya perlu memanggil
konstruktor yang dideklarasikan dalam salah satu class lapisan yang direfleksikan, kemudian mengikat
Allocation
memori yang dihasilkan ke RenderScript.
Terkadang, Anda mungkin ingin menggunakan class ini secara langsung untuk mengalokasikan memori
sendiri, seperti memuat bitmap dari resource atau saat Anda ingin mengalokasikan memori untuk pointer ke
jenis primitif. Untuk mencari tahu cara melakukannya, lihat bagian
Mengalokasikan dan mengikat memori ke RenderScript.
Tabel berikut menjelaskan tiga class manajemen memori secara lebih mendetail:
Jenis Objek Android | Deskripsi |
---|---|
Element |
Elemen menjelaskan satu sel alokasi memori dan dapat memiliki dua bentuk: dasar atau kompleks. Elemen dasar berisi satu komponen data dari setiap jenis data RenderScript yang valid.
Contoh jenis data elemen dasar mencakup satu nilai Elemen kompleks berisi sejumlah elemen dasar dan dibuat dari
|
Type |
Jenis adalah template alokasi memori dan terdiri dari satu elemen serta satu atau beberapa
dimensi. Jenis menjelaskan tata letak memori (pada dasarnya array Jenis terdiri dari lima dimensi: X, Y, Z, LOD (level detail), dan Faces (dari peta kubus). Anda dapat menentukan dimensi X,Y,Z ke nilai bilangan bulat positif apa pun dalam batasan memori yang tersedia. Alokasi dimensi tunggal memiliki dimensi X yang lebih besar dari nol, sementara dimensi Y dan Z miliknya adalah nol untuk mengindikasikan ketidakadaan. Sebagai contoh, alokasi x=10, y=1 dianggap dua dimensi, sedangkan x=10, y=0 dianggap satu dimensi. Dimensi LOD dan Faces berupa boolean untuk menunjukkan ada atau tidak ada. |
Allocation |
Alokasi menyediakan memori untuk aplikasi berdasarkan deskripsi memori
yang direpresentasikan oleh Data alokasi diupload melalui salah satu dari dua cara utama: dengan pemeriksaan jenis dan tanpa pemeriksaan jenis.
Untuk array sederhana, terdapat fungsi |
Bekerja dengan Memori
Variabel global nonstatis yang Anda deklarasikan dalam RenderScript akan diberi alokasi memori pada waktu kompilasi.
Anda dapat bekerja dengan variabel ini secara langsung dalam kode RenderScript tanpa harus mengalokasikan
memori untuknya pada level framework Android. Lapisan framework Android juga memiliki akses ke variabel
ini, dengan metode pengakses yang disediakan dan dibuat dalam class lapisan yang direfleksikan. Jika variabel ini
diinisialisasi pada lapisan runtime RenderScript, nilai tersebut akan digunakan untuk menginisialisasi nilai yang terkait
dalam lapisan framework Android. Jika variabel global ditandai sebagai konstanta, metode set
tidak akan dibuat. Lihat di sini untuk detail selengkapnya.
Catatan: Jika menggunakan struktur RenderScript tertentu yang berisi pointer, seperti
rs_program_fragment
dan rs_allocation
, Anda harus mendapatkan objek
class framework Android yang terkait terlebih dahulu, lalu memanggil metode set
untuk
struktur tersebut agar mengikat memori ke runtime RenderScript. Anda tidak dapat langsung memanipulasi struktur
ini pada lapisan runtime RenderScript. Batasan ini tidak berlaku untuk struktur
yang ditetapkan pengguna yang berisi pointer, karena sejak awal struktur tersebut tidak dapat diekspor ke class lapisan
yang direfleksikan. Error compiler akan muncul jika Anda mencoba mendeklarasikan struct global
nonstatis yang berisi pointer.
RenderScript juga memiliki dukungan untuk pointer, tetapi Anda harus mengalokasikan memori secara eksplisit dalam
kode framework Android Anda. Saat mendeklarasikan pointer global dalam file .rs
,
alokasikan memori melalui class lapisan yang direfleksikan yang sesuai dan ikat memori tersebut ke lapisan
RenderScript native. Anda dapat berinteraksi dengan memori ini dari lapisan framework Android serta
lapisan RenderScript, yang menawarkan fleksibilitas untuk memodifikasi variabel pada lapisan yang paling
sesuai.
Mengalokasikan dan mengikat memori dinamis ke RenderScript
Untuk mengalokasikan memori dinamis, Anda harus memanggil konstruktor class
Script.FieldBase
, yang merupakan cara paling umum. Alternatifnya, Anda dapat membuat file
Allocation
secara manual, yang diperlukan untuk hal-hal seperti pointer jenis primitif. Anda harus
menggunakan konstruktor class Script.FieldBase
apabila tersedia agar semuanya tetap ringkas.
Setelah mendapatkan alokasi memori, panggil metode bind
yang direfleksikan dari pointer untuk mengikat memori yang dialokasikan ke
runtime RenderScript.
Contoh di bawah ini mengalokasikan memori untuk pointer jenis primitif,
intPointer
, dan pointer ke struct, touchPoints
. Contoh ini juga mengikat memori ke
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); ... }
Membaca dan menulis ke memori
Anda dapat membaca dan menulis ke memori yang dialokasikan secara statis dan dinamis, baik pada runtime RenderScript maupun lapisan framework Android.
Memori yang dialokasikan secara statis dilengkapi dengan batasan komunikasi satu arah
pada level runtime RenderScript. Ketika kode RenderScript mengubah nilai suatu variabel, perubahan ini tidak
dikomunikasikan kembali ke lapisan framework Android untuk tujuan efisiensi. Nilai terakhir
yang ditentukan dari framework Android selalu dikembalikan selama panggilan ke
metode get
. Namun, ketika kode framework Android memodifikasi suatu variabel, perubahan tersebut dapat otomatis dikomunikasikan ke
runtime RenderScript atau disinkronkan di lain waktu. Jika perlu mengirim data
dari runtime RenderScript ke lapisan framework Android, Anda dapat menggunakan
fungsi rsSendToClient()
untuk mengatasi batasan ini.
Saat bekerja dengan memori yang dialokasikan secara dinamis, setiap perubahan pada lapisan runtime RenderScript akan disebarkan kembali ke lapisan framework Android jika Anda mengubah alokasi memori menggunakan pointer yang terkait. Memodifikasi objek pada lapisan framework Android akan langsung menyebarkan kembali perubahan tersebut ke lapisan runtime RenderScript.
Membaca dan menulis ke variabel global
Membaca dan menulis ke variabel global adalah proses yang mudah. Anda dapat menggunakan metode pengakses pada level framework Android, atau menentukannya secara langsung dalam kode RenderScript. Perlu diingat bahwa setiap perubahan yang Anda lakukan dalam kode RenderScript tidak akan disebarkan kembali ke lapisan framework Android (lihat di sini untuk detail selengkapnya).
Sebagai contoh, dengan struct berikut yang dideklarasikan dalam file bernama rsfile.rs
:
typedef struct Point { int x; int y; } Point_t; Point_t point;
Anda dapat menetapkan nilai ke struct seperti berikut secara langsung dalam rsfile.rs
. Nilai ini tidak
disebarkan kembali ke level framework Android:
point.x = 1; point.y = 1;
Anda dapat menetapkan nilai ke struct pada lapisan framework Android seperti berikut. Nilai ini disebarkan kembali ke level runtime RenderScript secara asinkron:
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);
Anda dapat membaca nilai tersebut dalam kode RenderScript seperti berikut:
rsDebug("Printing out a Point", point.x, point.y);
Anda dapat membaca nilai dalam lapisan framework Android dengan kode berikut. Perlu diingat bahwa kode ini hanya akan menampilkan nilai jika salah satunya telah ditentukan pada level framework Android. Anda akan mendapatkan pengecualian pointer null jika hanya menentukan nilai pada level runtime RenderScript:
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());
Membaca dan menulis pointer global
Dengan asumsi bahwa memori telah dialokasikan di level framework Android dan diikat ke runtime RenderScript,
Anda dapat membaca dan menulis memori dari level framework Android menggunakan metode get
dan set
untuk pointer tersebut.
Pada lapisan runtime RenderScript, Anda dapat membaca dan menulis ke memori dengan pointer seperti biasa, dan perubahannya akan disebarkan
kembali ke lapisan framework Android, tidak seperti memori yang dialokasikan secara statis.
Sebagai contoh, dengan pointer ke struct
berikut dalam file bernama rsfile.rs
:
typedef struct Point { int x; int y; } Point_t; Point_t *point;
Dengan asumsi Anda sudah mengalokasikan memori pada lapisan framework Android, Anda dapat mengakses nilai dalam
struct
seperti biasa. Setiap perubahan yang Anda lakukan pada struct melalui variabel pointernya
akan otomatis tersedia di lapisan framework Android:
Kotlin
point[index].apply { x = 1 y = 1 }
Java
point[index].x = 1; point[index].y = 1;
Anda juga dapat membaca dan menulis nilai ke pointer di lapisan framework Android:
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);
Setelah memori diikat, Anda tidak perlu mengikatnya ulang ke runtime RenderScript setiap kali melakukan perubahan pada nilai.