สำหรับภาระงานที่การประมวลผล GPU เหมาะสมที่สุด ให้ย้ายข้อมูลสคริปต์ RenderScript ไปยัง OpenGL ES (GLES) อนุญาตแอปพลิเคชันที่เขียนด้วยภาษา Kotlin, Java หรือการใช้ NDK เพื่อใช้ประโยชน์จากฮาร์ดแวร์ GPU ภาพรวมระดับสูงต่อไปนี้ช่วยให้คุณใช้ตัวปรับเงาการประมวลผล OpenGL ES 3.1 เพื่อ แทนที่สคริปต์ RenderScript
การเริ่มต้น GLES
ทำตามขั้นตอนต่อไปนี้แทนการสร้างออบเจ็กต์บริบท RenderScript เพื่อสร้างบริบทนอกหน้าจอ GLES โดยใช้ EGL ดังนี้
รับจอแสดงผลเริ่มต้น
เริ่มต้น EGL โดยใช้การแสดงผลเริ่มต้น โดยระบุเวอร์ชัน GLES
เลือกการกำหนดค่า EGL ที่มีประเภทแพลตฟอร์มเป็น
EGL_PBUFFER_BIT
ใช้การแสดงผลและการกำหนดค่าเพื่อสร้างบริบท EGL
สร้างพื้นผิวนอกหน้าจอด้วย
eglCreatePBufferSurface
หากบริบท จะใช้สำหรับการประมวลผลเท่านั้น ซึ่งอาจจะมีขนาดเล็กเล็กน้อย (1x1) แพลตฟอร์มสร้างเธรดการแสดงผลและเรียก
eglMakeCurrent
ในเธรดการแสดงผลพร้อมจอแสดงผล พื้นผิว และบริบท EGL เพื่อเชื่อมโยงบริบท GL กับชุดข้อความ
แอปตัวอย่างสาธิตวิธีการเริ่มต้นบริบท GLES ใน
GLSLImageProcessor.kt
ดูข้อมูลเพิ่มเติมได้ที่
EGLSurfaces และ OpenGL ES
เอาต์พุตการแก้ไขข้อบกพร่อง GLES
การได้รับข้อผิดพลาดที่เป็นประโยชน์จาก OpenGL ใช้ส่วนขยายเพื่อเปิดใช้การบันทึกการแก้ไขข้อบกพร่อง
ที่ตั้งค่า Callback ที่เป็นเอาต์พุตการแก้ไขข้อบกพร่อง ใช้วิธีการจาก SDK
glDebugMessageCallbackKHR
เป็นไปไม่ได้เลย และมีการ
ข้อยกเว้น ตัวอย่างแอป
จะมี Wrapper สําหรับการติดต่อกลับจากโค้ด NDK
การจัดสรร GLES
การจัดสรร RenderScript สามารถย้ายข้อมูลไปที่ พื้นผิวการเก็บข้อมูลที่เปลี่ยนแปลงไม่ได้ หรือ ออบเจ็กต์บัฟเฟอร์พื้นที่เก็บข้อมูล Shader สำหรับรูปภาพแบบอ่านอย่างเดียว คุณ ใช้ออบเจ็กต์ตัวอย่าง ซึ่งช่วยให้ดำเนินการต่อไปนี้ได้ ในการกรองด้วย
ทรัพยากร GLES จะได้รับการจัดสรรภายใน GLES เพื่อหลีกเลี่ยงการคัดลอกความทรงจำ
ค่าใช้จ่ายในการดำเนินการเมื่อโต้ตอบกับ
คอมโพเนนต์อื่นๆ ของ Android
สำหรับรูปภาพ KHR ที่อนุญาตให้แชร์
ของข้อมูลภาพในอาร์เรย์ 2 มิติ ต้องใช้ส่วนขยายนี้สำหรับอุปกรณ์ Android
เริ่มต้นด้วย Android 8.0
แกนประมวลผลกราฟิก
ไลบรารี Android Jetpack
มีการรองรับการสร้างรูปภาพเหล่านี้ภายในโค้ดที่มีการจัดการและการแมป
ไปยัง HardwareBuffer
ที่จัดสรรไว้:
val outputBuffers = Array(numberOfOutputImages) {
HardwareBuffer.create(
width, height, HardwareBuffer.RGBA_8888, 1,
HardwareBuffer.USAGE_GPU_SAMPLED_IMAGE
)
}
val outputEGLImages = Array(numberOfOutputImages) { i ->
androidx.opengl.EGLExt.eglCreateImageFromHardwareBuffer(
display,
outputBuffers[i]
)!!
}
แต่ไม่ได้สร้างพื้นผิวพื้นที่เก็บข้อมูลที่เปลี่ยนแปลงไม่ได้สำหรับ
ตัวปรับแสงเงาประมวลผลเพื่อเขียนลงในบัฟเฟอร์โดยตรง ตัวอย่างใช้
glCopyTexSubImage2D
เพื่อคัดลอกพื้นผิวพื้นที่เก็บข้อมูลที่ใช้
โดยตัวปรับแสงเงาการประมวลผลลงใน KHR Image
หากไดรเวอร์ OpenGL สนับสนุน
ส่วนขยาย EGL Image Storage ตามด้วยส่วนขยายดังกล่าว
สามารถใช้สร้างพื้นผิวพื้นที่เก็บข้อมูลที่เปลี่ยนแปลงไม่ได้ที่ใช้ร่วมกันเพื่อหลีกเลี่ยงการคัดลอก
การแปลงไปใช้เครื่องมือปรับแสงเงาการประมวลผล GLSL
ระบบจะแปลงสคริปต์ RenderScript ของคุณเป็นตัวปรับเงาการประมวลผล GLSL
เขียนตัวปรับแสงเงาการประมวลผล GLSL
ใน OpenGL ES ตัวปรับแสงเงาประมวลผลจะเขียนในส่วน ภาษาแรเงา OpenGL (GLSL)
การปรับตัวทั่วโลกของสคริปต์
คุณจะใช้เครื่องแบบก็ได้ โดยขึ้นอยู่กับลักษณะเฉพาะของสคริปต์ทั่วโลก หรือวัตถุบัฟเฟอร์แบบเดียวกันสำหรับส่วนกลางที่ไม่มีการปรับเปลี่ยนภายในตัวปรับแสงเงา:
- บัฟเฟอร์แบบเดียวกัน: แนะนำสำหรับโกลบอลของสคริปต์ที่มีการเปลี่ยนแปลงบ่อยในขนาดที่ใหญ่กว่า ดันขีดจำกัดคงที่
สำหรับส่วนกลางที่มีการเปลี่ยนแปลงภายในตัวปรับแสงเงา คุณสามารถใช้ พื้นผิวการเก็บข้อมูลที่เปลี่ยนแปลงไม่ได้ หรือ ออบเจ็กต์บัฟเฟอร์พื้นที่เก็บข้อมูล Shader
ดำเนินการคำนวณ
ตัวปรับแสงเงาการประมวลผลไม่ได้เป็นส่วนหนึ่งของไปป์ไลน์กราฟิก มีจุดประสงค์ทั่วไป และออกแบบมาเพื่อคำนวณงานที่ โหลดพร้อมกันได้มาก วิธีนี้ช่วยให้คุณมี ควบคุมการทำงานของโฆษณาได้มากขึ้น แต่ก็หมายความว่าคุณจะต้อง เข้าใจได้มากขึ้นว่างานของคุณ ทำงานควบคู่กันไปอย่างไร
สร้างและเริ่มต้นโปรแกรมประมวลผล
การสร้างและการเริ่มต้นโปรแกรมประมวลผลมีสิ่งต่างๆ หลายอย่างเหมือนกับ การทำงานกับตัวปรับแสงเงา GLES อื่นๆ
สร้างโปรแกรมและตัวปรับแสงเงาการประมวลผลที่เชื่อมโยงกับโปรแกรมดังกล่าว
แนบแหล่งที่มาของตัวปรับแสงเงา คอมไพล์ตัวปรับแสงเงา (และตรวจสอบผลลัพธ์ ของวิดีโอรวม)
แนบตัวปรับแสงเงา ลิงก์โปรแกรม และใช้โปรแกรมดังกล่าว
สร้าง เริ่มต้น และเชื่อมโยงแบบเดียวกันทั้งหมด
เริ่มการคำนวณ
ตัวควบคุมเฉดสีการประมวลผลทำงานภายในพื้นที่แบบ 1 มิติ 2 มิติ หรือ 3 มิติในชุด สำหรับกลุ่มงาน ซึ่งกำหนดไว้ภายในซอร์สโค้ดของตัวปรับแสงเงา และแสดงถึง ขนาดการเรียกใช้ขั้นต่ำและรูปทรงเรขาคณิตของตัวปรับแสงเงา ตัวปรับแสงเงาต่อไปนี้ทำงานในภาพ 2 มิติและกำหนดกลุ่มงานเป็น 2 ส่วน ขนาด:
private const val WORKGROUP_SIZE_X = 8
private const val WORKGROUP_SIZE_Y = 8
private const val ROTATION_MATRIX_SHADER =
"""#version 310 es
layout (local_size_x = $WORKGROUP_SIZE_X, local_size_y = $WORKGROUP_SIZE_Y, local_size_z = 1) in;
กลุ่มงานจะแชร์ความทรงจำได้ ซึ่งกำหนดโดย GL_MAX_COMPUTE_SHARED_MEMORY_SIZE
มีขนาดอย่างน้อย 32 KB และสามารถใช้ memoryBarrierShared()
เพื่อแสดง
การเข้าถึงหน่วยความจำที่สอดคล้องกัน
กำหนดขนาดกลุ่มงาน
แม้ว่าพื้นที่ทำงานของปัญหาจะทำงานได้ดีกับขนาดกลุ่มงานขนาด 1 การตั้งค่า ขนาดกลุ่มงานที่เหมาะสมเป็นสิ่งสำคัญสำหรับการทำให้ตัวโหลดเงาประมวลผลขนานกัน หากขนาดเล็กเกินไป ไดรเวอร์ GPU อาจไม่ทำให้การประมวลผลขนานกัน มากพอ เป็นต้น ตามหลักการ ขนาดเหล่านี้ควรปรับแต่งตาม GPU ค่าเริ่มต้นที่สมเหตุสมผลทำงานได้ดีพอในอุปกรณ์ปัจจุบัน เช่น กลุ่มงาน ขนาด 8x8 ในข้อมูลโค้ดตัวปรับแสงเงา
มี GL_MAX_COMPUTE_WORK_GROUP_COUNT
แต่ก็เพียงพอ ต้อง
อย่างน้อย 65535 ในทั้ง 3 แกนตามข้อกำหนด
ส่งตัวปรับแสงเงา
ขั้นตอนสุดท้ายในการประมวลผลการคำนวณคือจ่ายตัวปรับแสงเงาโดยใช้
ของฟังก์ชันการจ่ายงาน เช่น
glDispatchCompute
ฟังก์ชันการมอบหมายงานมีหน้าที่ดังนี้
สำหรับการตั้งค่าจำนวนกลุ่มงานสำหรับแต่ละแกน
GLES31.glDispatchCompute(
roundUp(inputImage.width, WORKGROUP_SIZE_X),
roundUp(inputImage.height, WORKGROUP_SIZE_Y),
1 // Z workgroup size. 1 == only one z level, which indicates a 2D kernel
)
หากต้องการส่งคืนค่า โปรดรอให้การดำเนินการประมวลผลเสร็จสิ้นก่อนโดยใช้ อุปสรรคด้านหน่วยความจำ:
GLES31.glMemoryBarrier(GLES31.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT)
ในการเชื่อมโยงเคอร์เนลหลายรายการเข้าด้วยกัน
(เช่น หากต้องการย้ายข้อมูลโค้ดโดยใช้ ScriptGroup
) ให้สร้างและส่ง
หลายโปรแกรมและซิงค์การเข้าถึงเอาต์พุตด้วยหน่วยความจำ
อุปสรรค
ตัวอย่างแอป แสดงงานประมวลผล 2 งาน ได้แก่
- การหมุนเวียน HUE: งานประมวลผลที่มีตัวปรับแสงเงาการประมวลผลเดียว โปรดดู
GLSLImageProcessor::rotateHue
สำหรับตัวอย่างโค้ด - เบลอ: งานประมวลผลที่ซับซ้อนขึ้นซึ่งทำงานประมวลผล 2 รายการตามลำดับ
ตัวปรับแสงเงา ดูตัวอย่างโค้ดได้ที่
GLSLImageProcessor::blur
ดูข้อมูลเพิ่มเติมเกี่ยวกับอุปสรรคด้านหน่วยความจำได้ที่ การรับประกันระดับการเข้าถึง และ ตัวแปรที่แชร์ ที่ใช้เวลาเพียง 2 นาที