เนื่องจากแอปพลิเคชันที่ใช้ RenderScript ยังคงทำงานภายใน Android VM คุณจะมีสิทธิ์เข้าถึง API ของเฟรมเวิร์กทั้งหมดที่คุณคุ้นเคย แต่สามารถ ใช้ RenderScript ตามความเหมาะสม เพื่ออำนวยความสะดวกในการโต้ตอบระหว่าง เฟรมเวิร์กและรันไทม์ RenderScript ขึ้น ชั้นโค้ดระดับกลางยัง แสดงเพื่ออำนวยความสะดวกในการสื่อสารและการจัดการหน่วยความจำระหว่างโค้ดทั้ง 2 ระดับ เอกสารนี้ลงรายละเอียดเกี่ยวกับ เลเยอร์ต่างๆ ของโค้ดได้ รวมทั้งวิธีการแชร์หน่วยความจำระหว่าง Android VM และ รันไทม์ของ RenderScript
เลเยอร์รันไทม์ของ RenderScript
โค้ด RenderScript ได้รับการคอมไพล์และ ดำเนินการในเลเยอร์รันไทม์ที่กะทัดรัดและกำหนดไว้เป็นอย่างดี API รันไทม์ของ RenderScript รองรับ การคำนวณอย่างหนักที่พกพาได้และปรับขนาดได้โดยอัตโนมัติ จำนวนแกนที่มีอยู่บนโปรเซสเซอร์
หมายเหตุ: ฟังก์ชัน C มาตรฐานใน NDK ต้องมีลักษณะดังนี้ รับประกันการแสดงผลบน CPU ดังนั้น RenderScript จึงไม่สามารถเข้าถึงไลบรารีเหล่านี้ เนื่องจาก RenderScript ได้รับการออกแบบมาให้ทำงานกับโปรเซสเซอร์ประเภทต่างๆ
คุณกำหนดโค้ด RenderScript ใน .rs
และ .rsh
ไฟล์ในไดเรกทอรี src/
ของโปรเจ็กต์ Android ของคุณ โค้ด
จะถูกคอมไพล์เป็นไบต์โค้ดกลางโดย
คอมไพเลอร์ llvm
ที่ทำงานเป็นส่วนหนึ่งของบิลด์ Android กรณีที่แอปพลิเคชันของคุณ
ทำงานบนอุปกรณ์ จากนั้นจะมีการรวบรวมไบต์โค้ด (แบบทันท่วงที) ไปยังโค้ดของเครื่องโดยบุคคลอื่น
คอมไพเลอร์ llvm
ที่อยู่ในอุปกรณ์ โค้ดของเครื่องได้รับการเพิ่มประสิทธิภาพเพื่อ
อุปกรณ์และแคชด้วย ดังนั้นการใช้งานแอปพลิเคชันที่เปิดใช้งาน RenderScript ในภายหลังจึงไม่
คอมไพล์ไบต์โค้ดอีกครั้ง
คุณลักษณะสำคัญบางประการของไลบรารีรันไทม์ RenderScript มีดังนี้
- ฟีเจอร์คำขอจัดสรรหน่วยความจำ
- คอลเล็กชันฟังก์ชันคณิตศาสตร์ขนาดใหญ่ ซึ่งมีทั้งเวอร์ชันสเกลาร์และเวอร์ชันที่มีการพิมพ์เวกเตอร์มากเกินไป ของกิจวัตรประจำวันต่างๆ การดำเนินการ เช่น การบวก การคูณ ผลคูณไขว้ และข้ามผลิตภัณฑ์ รวมถึงฟังก์ชันเลขคณิตและการเปรียบเทียบ
- กิจวัตร Conversion ของประเภทข้อมูลและเวกเตอร์พื้นฐาน กิจวัตรเมทริกซ์ รวมถึงวันที่และเวลา กิจวัตร
- ประเภทข้อมูลและโครงสร้างที่จะรองรับระบบ RenderScript เช่น ประเภทเวกเตอร์สำหรับ โดยกำหนด 2, 3 หรือ 4 เวกเตอร์
- ฟังก์ชันการบันทึก
ดูข้อมูลอ้างอิงของ API รันไทม์ใน RenderScript สำหรับข้อมูลเพิ่มเติมเกี่ยวกับฟังก์ชันที่พร้อมใช้งาน
เลเยอร์สะท้อน
เลเยอร์สะท้อนแสงคือชุดคลาสที่เครื่องมือสร้างของ Android สร้างขึ้นเพื่ออนุญาตการเข้าถึง ไปยังรันไทม์ RenderScript จากเฟรมเวิร์ก Android เลเยอร์นี้ยังบอกวิธี และเครื่องมือสร้างที่ช่วยให้คุณจัดสรรและทำงานกับหน่วยความจำสำหรับตัวชี้ที่กำหนดไว้ใน โค้ด RenderScript ของคุณ รายการต่อไปนี้คือรายการหลัก ที่จะแสดงให้เห็น เช่น
- ระบบจะสร้างไฟล์
.rs
ทุกไฟล์ที่คุณสร้างในชั้นเรียนชื่อproject_root/gen/package/name/ScriptC_renderscript_filename
จาก ประเภทScriptC
ไฟล์นี้เป็นเวอร์ชัน.java
ของ.rs
ซึ่งคุณเรียกใช้ได้จากเฟรมเวิร์กของ Android คลาสนี้ประกอบด้วย รายการต่อไปนี้แสดงจากไฟล์.rs
:- ฟังก์ชันที่ไม่คงที่
- ตัวแปร RenderScript ร่วมที่ไม่คงที่ ผู้เข้าถึง
ระบบจะสร้างเมธอดสำหรับตัวแปรแต่ละตัว คุณจึงสามารถอ่านและ
เขียนตัวแปร RenderScript จาก Android
หากตัวแปรร่วมเริ่มต้นในเวลา
เลเยอร์รันไทม์ RenderScript ค่าเหล่านี้จะใช้เพื่อ
เริ่มต้นค่าที่เกี่ยวข้องในเฟรมเวิร์ก Android
หากทำเครื่องหมายตัวแปรร่วมเป็น
const
เมธอดset
จะไม่ใช่ ที่สร้างขึ้น ดูที่นี่ เพื่อดูรายละเอียดเพิ่มเติม - ตัวชี้ทั่วโลก
struct
จะแสดงในชั้นเรียนของตัวเองที่ชื่อproject_root/gen/package/name/ScriptField_struct_name
ซึ่งขยายไปScript.FieldBase
คลาสนี้จะแสดงอาร์เรย์ของstruct
ซึ่งให้คุณจัดสรรหน่วยความจำสำหรับอินสแตนซ์นี้อย่างน้อย 1 รายการstruct
ฟังก์ชัน
ฟังก์ชันจะปรากฏในคลาสสคริปต์ ซึ่งอยู่ใน
project_root/gen/package/name/ScriptC_renderscript_filename
สำหรับ
ตัวอย่างเช่น หากคุณกำหนดฟังก์ชันต่อไปนี้ในโค้ด RenderScript ของคุณ
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; }
ระบบจะสร้างโค้ด Java ต่อไปนี้ขึ้น
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); }
ฟังก์ชันไม่สามารถมีค่าแสดงผล เนื่องจากระบบ RenderScript ได้รับการออกแบบมาให้เป็น ไม่พร้อมกัน เมื่อโค้ดเฟรมเวิร์ก Android เรียกใช้ RenderScript การเรียกใช้จะอยู่ในคิวและเป็น ดำเนินการเมื่อเป็นไปได้ ข้อจำกัดนี้ช่วยให้ระบบ RenderScript ทำงานได้โดยไม่ต้องคงที่ และเพิ่มประสิทธิภาพ หากฟังก์ชันได้รับอนุญาตให้มีค่าแสดงผล การเรียก จะบล็อกจนกว่าจะมีการแสดงผลค่า
หากต้องการให้โค้ด RenderScript ส่งค่ากลับไปยังเฟรมเวิร์ก Android ให้ใช้เมธอด
rsSendToClient()
ตัวแปร
ตัวแปรของประเภทที่สนับสนุนจะแสดงในคลาสสคริปต์เอง ซึ่งอยู่ใน
project_root/gen/package/name/ScriptC_renderscript_filename
ชุดตัวเข้าถึง
ขึ้นสำหรับตัวแปรแต่ละตัว เช่น หากคุณกำหนดตัวแปรต่อไปนี้ใน
โค้ด RenderScript ของคุณ:
uint32_t unsignedInteger = 1;
ระบบจะสร้างโค้ด Java ต่อไปนี้ขึ้น
private long mExportVar_unsignedInteger; public void set_unsignedInteger(long v){ mExportVar_unsignedInteger = v; setVar(mExportVarIdx_unsignedInteger, v); } public long get_unsignedInteger(){ return mExportVar_unsignedInteger; }
โครงสร้าง
โครงสร้างจะแสดงเป็นชั้นเรียนของตนเอง ซึ่งอยู่ใน
<project_root>/gen/com/example/renderscript/ScriptField_struct_name
ช่วงเวลานี้
คลาสจะแสดงอาร์เรย์ของ struct
และอนุญาตให้คุณจัดสรรหน่วยความจำสำหรับ
จำนวน struct
ที่ระบุ ตัวอย่างเช่น หากคุณกําหนดโครงสร้างต่อไปนี้
typedef struct Point { float2 position; float size; } Point_t;
จากนั้นรหัสต่อไปนี้จะสร้างขึ้นใน 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 */); } }
จะมอบโค้ดที่สร้างขึ้นให้คุณเพื่อความสะดวกในการจัดสรรหน่วยความจำสำหรับ Struct ที่ขอ
ผ่านรันไทม์ RenderScript และโต้ตอบกับ struct
ในหน่วยความจำ คลาสของ struct
แต่ละรายการจะกำหนดเมธอดและตัวสร้างต่อไปนี้
- เครื่องมือสร้างที่มีการโหลดมากเกินไปซึ่งช่วยให้คุณจัดสรรหน่วยความจำได้
เครื่องมือสร้าง
ScriptField_struct_name(RenderScript rs, int count)
อนุญาตให้ คุณสามารถกำหนดจำนวนโครงสร้างที่ต้องการจัดสรรหน่วยความจำด้วย พารามิเตอร์count
ตัวสร้างScriptField_struct_name(RenderScript rs, int count, int usages)
กำหนดพารามิเตอร์เพิ่มเติมusages
ซึ่ง จะช่วยให้คุณระบุพื้นที่หน่วยความจำของการจัดสรรหน่วยความจำนี้ได้ มีพื้นที่หน่วยความจำ 4 รูปแบบ ที่เป็นไปได้:USAGE_SCRIPT
: จัดสรรในหน่วยความจำของสคริปต์ พื้นที่ทำงาน นี่คือพื้นที่หน่วยความจำเริ่มต้นหากคุณไม่ได้ระบุพื้นที่หน่วยความจำUSAGE_GRAPHICS_TEXTURE
: จัดสรรใน พื้นที่หน่วยความจำพื้นผิวของ GPUUSAGE_GRAPHICS_VERTEX
: จัดสรรในส่วนยอดมุม พื้นที่หน่วยความจำของ GPUUSAGE_GRAPHICS_CONSTANTS
: จัดสรรใน พื้นที่หน่วยความจำของ GPU คงที่ที่ออบเจ็กต์โปรแกรมต่างๆ ใช้
คุณสามารถระบุพื้นที่หน่วยความจำได้หลายพื้นที่โดยใช้โอเปอเรเตอร์
OR
แบบบิตไวส์ ดังนั้น แจ้งรันไทม์ RenderScript ที่คุณต้องการเข้าถึงข้อมูลใน พื้นที่หน่วยความจำที่ระบุ ตัวอย่างต่อไปนี้จัดสรรหน่วยความจำสำหรับประเภทข้อมูลที่กำหนดเอง ทั้งในพื้นที่หน่วยความจำของสคริปต์และ Vertex: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);
- คลาสที่ซ้อนกันแบบคงที่
Item
จะช่วยให้คุณสร้างอินสแตนซ์ของstruct
ในรูปแบบวัตถุ ชั้นเรียนที่ซ้อนกันนี้จะมีประโยชน์ในกรณีที่ทำงานอย่างสมเหตุสมผลมากขึ้น ที่มีstruct
ในโค้ด Android ของคุณ เมื่อจัดการออบเจ็กต์เสร็จแล้ว คุณจะพุชออบเจ็กต์ไปยังหน่วยความจำที่จัดสรรได้โดยเรียกใช้set(Item i, int index, boolean copyNow)
และตั้งค่าItem
ไปยังตำแหน่งที่ต้องการ อาร์เรย์ รันไทม์ของ RenderScript มีสิทธิ์เข้าถึงหน่วยความจำที่เขียนใหม่โดยอัตโนมัติ - เมธอดของตัวเข้าถึงเพื่อรับและกำหนดค่าของแต่ละช่องในโครงสร้าง แต่ละรายการ
เมธอดของตัวเข้าถึงมีพารามิเตอร์
index
เพื่อระบุstruct
ใน อาร์เรย์ที่ต้องการอ่านหรือเขียน เมธอด Setter แต่ละเมธอดยังมีcopyNow
ที่ระบุว่าจะซิงค์หน่วยความจำนี้ทันทีหรือไม่ ไปยังรันไทม์ RenderScript ได้ หากต้องการซิงค์หน่วยความจำที่ยังไม่ได้ซิงค์ ให้โทรcopyAll()
- เมธอด
createElement()
จะสร้างคําอธิบายโครงสร้างในหน่วยความจำ ช่วงเวลานี้ คำอธิบาย ใช้สำหรับจัดสรรหน่วยความจำที่ประกอบด้วยองค์ประกอบอย่างน้อย 1 อย่าง resize()
ทำงานคล้ายกับrealloc()
ในภาษา C ซึ่งช่วยให้คุณ ขยายหน่วยความจำที่จัดสรรไว้ก่อนหน้านี้ โดยรักษาค่าปัจจุบันที่ก่อนหน้านี้ใช้ สร้าง แล้วcopyAll()
ซิงค์ข้อมูลหน่วยความจำที่ตั้งค่าไว้ในระดับเฟรมเวิร์กกับ รันไทม์ของ RenderScript เมื่อคุณเรียกใช้ Method ของ Set Accessor ในสมาชิกจะมีตัวเลือกเสริม พารามิเตอร์บูลีนcopyNow
ที่คุณระบุได้ การระบุtrue
จะซิงค์หน่วยความจำเมื่อคุณเรียกใช้เมธอด หากคุณระบุ "เท็จ" คุณสามารถโทรหาcopyAll()
ได้ครั้งเดียว และโมเดลจะซิงค์หน่วยความจำสำหรับ ที่ยังไม่ได้ซิงค์
เคอร์เซอร์
ตัวชี้ทั่วโลกจะแสดงในคลาสสคริปต์เอง ซึ่งอยู่ใน
project_root/gen/package/name/ScriptC_renderscript_filename
คุณ
สามารถประกาศตัวชี้ไปยัง struct
หรือประเภท RenderScript ที่รองรับ แต่
struct
ต้องไม่มีเคอร์เซอร์หรืออาร์เรย์ที่ซ้อนกัน ตัวอย่างเช่น หากคุณกำหนด
ตามตัวชี้ไปยัง struct
และ int32_t
typedef struct Point { float2 position; float size; } Point_t; Point_t *touchPoints; int32_t *intPointer;
ระบบจะสร้างโค้ด Java ต่อไปนี้ขึ้น
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; }
เมธอด get
และเมธอดพิเศษที่ชื่อ bind_pointer_name
(แทนเมธอด set()
) เมธอด bind_pointer_name
ช่วยให้คุณเชื่อมโยงหน่วยความจำ
ที่จัดสรรใน Android VM ไปยังรันไทม์ RenderScript ได้ (คุณจัดสรรไม่ได้
ในไฟล์ .rs
) ดูข้อมูลเพิ่มเติมได้ที่การทํางาน
ด้วยหน่วยความจำที่จัดสรรแล้ว
API การจัดสรรหน่วยความจำ
แอปพลิเคชันที่ใช้ RenderScript ยังคงทำงานใน Android VM อย่างไรก็ตาม โค้ด RenderScript จริงจะทำงานแบบเนทีฟและ
ต้องมีสิทธิ์เข้าถึงหน่วยความจำที่จัดสรรใน Android VM เพื่อให้บรรลุเป้าหมายนี้ คุณต้อง
แนบหน่วยความจำที่จัดสรรใน VM ไปยังรันไทม์ของ RenderScript ช่วงเวลานี้
ที่เรียกว่าการผูก ช่วยให้รันไทม์ของ RenderScript ทำงานกับหน่วยความจำที่
คำขอแต่ไม่สามารถจัดสรรไว้อย่างชัดเจนได้ โดยพื้นฐานแล้ว ผลลัพธ์จะเหมือนกับว่าคุณมี
ที่เรียกว่า malloc
ใน C ประโยชน์เพิ่มเติมคือ Android VM สามารถจัดเก็บขยะและ
แชร์หน่วยความจำกับเลเยอร์รันไทม์ของ RenderScript จำเป็นต้องเชื่อมโยงเฉพาะหน่วยความจำที่จัดสรรแบบไดนามิกเท่านั้น แบบคงที่
ระบบจะสร้างหน่วยความจำที่จัดสรรสำหรับโค้ด RenderScript โดยอัตโนมัติในเวลาคอมไพล์ ดูรูปที่ 1
เพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับการจัดสรรหน่วยความจำ
มีชุดของ API ที่อนุญาตให้ Android VM สามารถรองรับระบบการจัดสรรหน่วยความจำนี้ได้
จัดสรรหน่วยความจำและมีฟังก์ชันการทำงานที่คล้ายกับการโทร malloc
ชั้นเรียนเหล่านี้
อธิบายถึงวิธีจัดสรรหน่วยความจำเป็นหลัก รวมถึงจัดสรรหน่วยความจำด้วย ให้ดียิ่งขึ้น
เข้าใจวิธีการทำงานของชั้นเรียนเหล่านี้ การคิดถึงชั้นเรียนเกี่ยวกับ
การเรียก malloc
ที่อาจมีลักษณะดังนี้
array = (int *)malloc(sizeof(int)*10);
การเรียกใช้ malloc
สามารถแบ่งออกเป็น 2 ส่วน ได้แก่ ขนาดของหน่วยความจำที่จัดสรร (sizeof(int)
)
รวมถึงจำนวนหน่วยของหน่วยความจำนั้นที่ควรจัดสรร (10) เฟรมเวิร์ก Android จะสอนทั้ง 2 ส่วนนี้ในลักษณะต่อไปนี้
ชั้นเรียนแสดงถึง malloc
เอง
คลาส Element
แสดงถึงส่วน (sizeof(int)
)
ของการเรียก malloc
และสรุปการจัดสรรหน่วยความจำ 1 เซลล์เช่นเซลล์เดียว
จำนวนลอยตัวหรือโครงสร้าง คลาส Type
สรุป Element
และจำนวนองค์ประกอบที่จะจัดสรร (10 ในตัวอย่างของเรา) ให้ Type
เป็น
อาร์เรย์ของ Element
ชั้นเรียน Allocation
จะดำเนินการตาม
การจัดสรรหน่วยความจำตาม Type
ที่ระบุและแสดงถึงหน่วยความจำที่จัดสรรตามจริง
ในกรณีส่วนใหญ่ คุณไม่จำเป็นต้องเรียกใช้ API การจัดสรรหน่วยความจำเหล่านี้โดยตรง ชั้นที่สะท้อน
คลาสจะสร้างโค้ดเพื่อใช้ API เหล่านี้โดยอัตโนมัติ และสิ่งที่คุณต้องทำเพื่อจัดสรรหน่วยความจำคือการเรียก
เครื่องมือสร้างที่ประกาศไว้ในคลาสเลเยอร์หนึ่งที่สะท้อนแล้วจึงเชื่อมโยง
หน่วยความจำผลลัพธ์ Allocation
ไปยัง RenderScript
อาจมีบางสถานการณ์ที่คุณอาจต้องใช้ชั้นเรียนเหล่านี้เพื่อจัดสรรหน่วยความจำใน
เช่น การโหลดบิตแมปจากทรัพยากร หรือเมื่อคุณต้องการจัดสรรหน่วยความจำสำหรับตัวชี้ไปยัง
ประเภทพื้นฐาน คุณสามารถดูวิธีดำเนินการได้ใน
จัดสรรและเชื่อมโยงหน่วยความจำกับส่วน RenderScript
ตารางต่อไปนี้จะอธิบายคลาสการจัดการหน่วยความจำ 3 คลาสโดยละเอียดยิ่งขึ้น
ประเภทออบเจ็กต์ Android | คำอธิบาย |
---|---|
Element |
องค์ประกอบจะอธิบายถึงการจัดสรรหน่วยความจำ 1 เซลล์และมี 2 รูปแบบ ได้แก่ แบบพื้นฐานหรือแบบพื้นฐาน ที่ซับซ้อน องค์ประกอบพื้นฐานประกอบด้วยข้อมูลคอมโพเนนต์เดียวของประเภทข้อมูล RenderScript ที่ถูกต้อง
ตัวอย่างประเภทข้อมูลองค์ประกอบพื้นฐาน ได้แก่ ค่า องค์ประกอบที่ซับซ้อนประกอบด้วยรายการองค์ประกอบพื้นฐานและสร้างขึ้นจาก
|
Type |
ประเภทคือเทมเพลตการจัดสรรหน่วยความจำและประกอบด้วยองค์ประกอบ 1 รายการและอย่างน้อย 1 รายการ
ขนาดกะทัดรัด โดยจะอธิบายเลย์เอาต์ของหน่วยความจำ (โดยพื้นฐานจะเป็นอาร์เรย์ของ ประเภทประกอบด้วยมิติข้อมูล 5 ส่วน ได้แก่ X, Y, Z, LOD (ระดับรายละเอียด) และด้าน (ของลูกบาศก์ แผนที่) คุณสามารถตั้งค่ามิติข้อมูล X,Y,Z เป็นค่าจำนวนเต็มบวกภายในค่า หน่วยความจำที่ใช้ได้ การจัดสรรมิติข้อมูลเดียวมีมิติข้อมูล X เป็น มากกว่า 0 ขณะที่มิติข้อมูล Y และ Z เป็น 0 แสดงว่าไม่มีอยู่ สำหรับ ตัวอย่างเช่น การจัดสรร x=10, y=1 จะถือว่าเป็น 2 มิติ และ x=10, y=0 นั้น ถือว่าเป็นหนึ่งมิติ มิติข้อมูล LOD และใบหน้าเป็นบูลีนเพื่อระบุปัจจุบัน หรือว่าไม่มี |
Allocation |
การจัดสรรที่จะมอบหน่วยความจำสำหรับแอปพลิเคชันตามคำอธิบายของหน่วยความจำ
ซึ่งแสดงด้วย ระบบจะอัปโหลดข้อมูลการจัดสรรด้วยวิธีใดวิธีหนึ่งใน 2 วิธีหลัก ได้แก่ การเลือกประเภทและยกเลิกการเลือกประเภท
สำหรับอาร์เรย์แบบง่ายจะมีฟังก์ชัน |
การทำงานกับหน่วยความจำ
ตัวแปรร่วมที่ไม่ใช่แบบคงที่ที่คุณประกาศใน RenderScript ได้รับการจัดสรรหน่วยความจำในเวลาคอมไพล์
คุณสามารถทำงานกับตัวแปรเหล่านี้ได้โดยตรงในโค้ด RenderScript โดยไม่ต้องจัดสรร
ให้สมาชิกในระดับเฟรมเวิร์ก Android เลเยอร์เฟรมเวิร์ก Android มีสิทธิ์เข้าถึงตัวแปรเหล่านี้ด้วย
ด้วยเมธอด Accessor ที่มีให้ซึ่งสร้างขึ้นในคลาสเลเยอร์สะท้อน หากตัวแปรเหล่านี้คือ
ซึ่งเริ่มต้นไว้ที่เลเยอร์รันไทม์ RenderScript ค่าเหล่านี้จะใช้เพื่อเริ่มต้น
ในเลเยอร์เฟรมเวิร์ก Android หากตัวแปรร่วมมีการทำเครื่องหมายเป็น Const ดังนั้นเมธอด set
จะเป็น
ไม่ได้สร้าง ดูรายละเอียดเพิ่มเติมที่นี่
หมายเหตุ: หากคุณใช้โครงสร้าง RenderScript บางอย่างที่มีเคอร์เซอร์ เช่น
rs_program_fragment
และ rs_allocation
คุณจะต้องได้ออบเจ็กต์ของ
คลาสเฟรมเวิร์ก Android ที่เกี่ยวข้องก่อนแล้วจึงเรียกใช้เมธอด set
สำหรับการดำเนินการดังกล่าว
ในการเชื่อมโยงหน่วยความจำกับรันไทม์ของ RenderScript คุณปรับเปลี่ยนโครงสร้างเหล่านี้โดยตรงไม่ได้
ที่เลเยอร์รันไทม์ RenderScript ข้อจำกัดนี้ไม่มีผลกับโครงสร้างที่ผู้ใช้กำหนด
ที่มีตัวชี้ เนื่องจากไม่สามารถส่งออกไปยังคลาสเลเยอร์ที่ปรากฏ
ตั้งแต่แรก ข้อผิดพลาดของคอมไพเลอร์จะสร้างขึ้นหากคุณพยายามประกาศโค้ดสากลที่ไม่ใช่แบบคงที่
โครงสร้างที่มีตัวชี้
RenderScript รองรับเคอร์เซอร์ด้วย แต่คุณต้องจัดสรรหน่วยความจำใน
โค้ดเฟรมเวิร์ก Android เมื่อคุณประกาศเคอร์เซอร์ส่วนกลางในไฟล์ .rs
คุณจะ
จัดสรรหน่วยความจำผ่านคลาสเลเยอร์สะท้อนภาพที่เหมาะสมและเชื่อมโยงหน่วยความจำนั้นกับเนทีฟ
เลเยอร์ RenderScript คุณโต้ตอบกับหน่วยความจำนี้ได้จากเลเยอร์เฟรมเวิร์กของ Android รวมถึง
เลเยอร์ RenderScript ซึ่งให้ความยืดหยุ่นในการแก้ไขตัวแปร
เลเยอร์ที่เหมาะสม
การจัดสรรและเชื่อมโยงหน่วยความจำแบบไดนามิกกับ RenderScript
ในการจัดสรรหน่วยความจำแบบไดนามิก คุณต้องเรียกใช้เครื่องมือสร้างของ
Script.FieldBase
ซึ่งเป็นวิธีที่นิยมใช้กันมากที่สุด อีกวิธีหนึ่งคือการสร้าง
Allocation
ด้วยตนเอง ซึ่งจำเป็นสำหรับสิ่งต่างๆ เช่น ตัวชี้ประเภทพื้นฐาน คุณควร
ใช้เครื่องมือสร้างคลาส Script.FieldBase
ทุกครั้งที่มีความเรียบง่าย
หลังจากได้รับการจัดสรรหน่วยความจำแล้ว ให้เรียกใช้เมธอด bind
ที่สะท้อนให้เห็นของตัวชี้เพื่อเชื่อมโยงหน่วยความจำที่จัดสรรกับ
รันไทม์ของ RenderScript
ตัวอย่างด้านล่างจัดสรรหน่วยความจำสำหรับทั้งตัวชี้ประเภทพื้นฐาน
intPointer
และตัวชี้ไปยังโครงสร้าง touchPoints
และยังเชื่อมโยงความทรงจำกับ
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); ... }
การอ่านและการเขียนไปยังความทรงจำ
คุณอ่านและเขียนไปยังหน่วยความจำที่จัดสรรแบบคงที่และแบบไดนามิกได้ทั้งที่รันไทม์ของ RenderScript และ Android เฟรมเวิร์ก
หน่วยความจำที่จัดสรรแบบคงที่มาพร้อมกับข้อจำกัดการสื่อสารทางเดียว
ที่ระดับรันไทม์ของ RenderScript เมื่อโค้ด RenderScript เปลี่ยนค่าของตัวแปร ค่าไม่ใช่
สื่อสารกลับไปยังเลเยอร์เฟรมเวิร์กของ Android เพื่อจุดประสงค์ด้านประสิทธิภาพ ค่าสุดท้าย
ที่ตั้งค่าจากเฟรมเวิร์กของ Android จะแสดงในระหว่างการเรียกใช้ get
เสมอ
อย่างไรก็ตาม เมื่อโค้ดเฟรมเวิร์กของ Android แก้ไขตัวแปร การเปลี่ยนแปลงดังกล่าวจะส่งไปถึง
รันไทม์ของ RenderScript โดยอัตโนมัติหรือซิงค์ในภายหลัง หากต้องการส่งข้อมูล
จากรันไทม์ของ RenderScript ไปยังเลเยอร์เฟรมเวิร์ก Android คุณสามารถใช้
ฟังก์ชัน rsSendToClient()
เพื่อก้าวข้ามข้อจำกัดนี้
เมื่อทำงานกับหน่วยความจำที่จัดสรรแบบไดนามิก การเปลี่ยนแปลงใดๆ ที่เลเยอร์รันไทม์ RenderScript จะกระจายไป กลับไปที่เลเยอร์เฟรมเวิร์ก Android หากคุณแก้ไขการจัดสรรหน่วยความจำโดยใช้ตัวชี้ที่เชื่อมโยง การแก้ไขออบเจ็กต์ที่เลเยอร์เฟรมเวิร์ก Android จะเผยแพร่โดยเปลี่ยนกลับไปยัง RenderScript ทันที เลเยอร์รันไทม์
การอ่านและการเขียนไปยังตัวแปรร่วม
การอ่านและการเขียนไปยังตัวแปรร่วมเป็นกระบวนการที่ตรงไปตรงมา คุณสามารถใช้เมธอดตัวเข้าถึง ที่ระดับเฟรมเวิร์ก Android หรือตั้งค่าโดยตรงในโค้ด RenderScript โปรดทราบว่า การเปลี่ยนแปลงที่คุณทำในโค้ด RenderScript ไม่เผยแพร่ กลับไปที่เลเยอร์เฟรมเวิร์ก Android (ดูที่นี่ เพื่อดูรายละเอียดเพิ่มเติม)
ตัวอย่างเช่น ด้วยโครงสร้างที่ประกาศไว้ในไฟล์ชื่อ rsfile.rs
ดังต่อไปนี้
typedef struct Point { int x; int y; } Point_t; Point_t point;
คุณกําหนดค่าให้กับโครงสร้างแบบนี้ได้โดยตรงใน rsfile.rs
ค่าเหล่านี้ไม่ใช่
เผยแพร่กลับไปที่ระดับเฟรมเวิร์กของ Android ดังนี้
point.x = 1; point.y = 1;
คุณกำหนดค่าให้กับ Struct ในเลเยอร์เฟรมเวิร์ก Android ได้ในลักษณะนี้ ค่าเหล่านี้ได้แก่ เผยแพร่กลับไปยังระดับรันไทม์ RenderScript ได้แบบไม่พร้อมกันดังนี้
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);
คุณสามารถอ่านค่าในโค้ด RenderScript ได้ดังต่อไปนี้
rsDebug("Printing out a Point", point.x, point.y);
อ่านค่าในเลเยอร์เฟรมเวิร์กของ Android ได้ด้วยโค้ดต่อไปนี้ โปรดทราบว่า จะแสดงผลค่าก็ต่อเมื่อตั้งค่าไว้ที่ระดับเฟรมเวิร์ก Android คุณจะได้รับเคอร์เซอร์ค่าว่าง ข้อยกเว้นในกรณีที่คุณตั้งค่าที่ระดับรันไทม์ของ 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());
การอ่านและการเขียนตัวชี้ทั่วโลก
สมมติว่ามีการจัดสรรหน่วยความจำในระดับเฟรมเวิร์ก Android และเชื่อมโยงกับรันไทม์ RenderScript แล้ว
คุณจะอ่านและเขียนหน่วยความจำจากระดับเฟรมเวิร์ก Android ได้โดยใช้เมธอด get
และ set
สำหรับตัวชี้นั้นๆ
ในเลเยอร์รันไทม์ RenderScript คุณสามารถอ่านและเขียนไปยังหน่วยความจำด้วยตัวชี้ตามปกติและระบบจะเผยแพร่การเปลี่ยนแปลง
กลับไปยังเลเยอร์เฟรมเวิร์ก Android ซึ่งจะต่างจากหน่วยความจำที่จัดสรรแบบคงที่
ตัวอย่างเช่น กำหนดตัวชี้ต่อไปนี้ให้กับ struct
ในไฟล์ชื่อ rsfile.rs
:
typedef struct Point { int x; int y; } Point_t; Point_t *point;
สมมติว่าคุณจัดสรรหน่วยความจำที่เลเยอร์เฟรมเวิร์ก Android แล้ว คุณจะเข้าถึงค่าได้ใน
struct
ตามปกติ การเปลี่ยนแปลงใดๆ ที่คุณทำกับโครงสร้างผ่านตัวแปรตัวชี้
จะพร้อมใช้งานโดยอัตโนมัติในเลเยอร์เฟรมเวิร์กของ Android:
Kotlin
point[index].apply { x = 1 y = 1 }
Java
point[index].x = 1; point[index].y = 1;
คุณสามารถอ่านและเขียนค่าลงในตัวชี้ที่เลเยอร์เฟรมเวิร์กของ 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);
เมื่อเชื่อมโยงหน่วยความจำแล้ว คุณไม่ต้องเชื่อมโยงหน่วยความจำกับ RenderScript อีก ทุกครั้งที่คุณทำการเปลี่ยนแปลงกับค่า