ในฐานะนักพัฒนา WebGL คุณอาจทั้งตื่นเต้นและกังวลใจที่จะเริ่มต้นใช้งาน WebGPU ซึ่งเป็น API กราฟิกสมัยใหม่ที่นำมาใช้ในเว็บเพื่อแทนที่ WebGL
คุณก็คงโล่งใจเมื่อทราบว่า WebGL และ WebGPU มีแนวคิดหลักหลายอย่างที่เหมือนกัน ทั้ง 2 API ช่วยให้คุณสามารถเรียกใช้โปรแกรมขนาดเล็กที่เรียกว่า Shader ใน GPU ได้ WebGL รองรับเวิร์กเท็กซ์และแฟรกเมนต์ Shader ส่วน WebGPU รองรับ Compute Shader ด้วย WebGL ใช้ภาษาการจัดแสง OpenGL (GLSL) ส่วน WebGPU ใช้ภาษาการจัดแสง WebGPU (WGSL) แม้ว่าภาษาทั้ง 2 ภาษาจะแตกต่างกัน แต่แนวคิดพื้นฐานส่วนใหญ่จะเหมือนกัน
บทความนี้จะเน้นความแตกต่างบางประการระหว่าง WebGL กับ WebGPU เพื่อช่วยให้คุณเริ่มต้นใช้งาน
สถานะส่วนกลาง
WebGL มีสถานะส่วนกลางจำนวนมาก การตั้งค่าบางอย่างมีผลกับการดำเนินการทั้งหมดในการเรนเดอร์ เช่น การกำหนดค่าพื้นผิวและบัฟเฟอร์ คุณตั้งค่าสถานะส่วนกลางนี้โดยการเรียกใช้ฟังก์ชัน API ต่างๆ และสถานะนี้จะมีผลจนกว่าคุณจะเปลี่ยนแปลง สถานะส่วนกลางใน WebGL เป็นแหล่งที่มาของข้อผิดพลาดหลัก เนื่องจากคุณอาจลืมเปลี่ยนการตั้งค่าส่วนกลาง นอกจากนี้ สถานะส่วนกลางยังทําให้แชร์โค้ดได้ยาก เนื่องจากนักพัฒนาแอปต้องระมัดระวังไม่ให้เปลี่ยนสถานะส่วนกลางโดยไม่ตั้งใจในลักษณะที่ส่งผลต่อส่วนอื่นๆ ของโค้ด
WebGPU เป็น API ที่ไม่มีสถานะ และจะไม่รักษาสถานะส่วนกลาง แต่จะใช้แนวคิดของ ไปป์ไลน์เพื่อรวมสถานะการแสดงผลทั้งหมดที่เป็นแบบส่วนกลางใน WebGL ไปป์ไลน์มีข้อมูล เช่น การผสมผสาน โทโพโลยี และแอตทริบิวต์ที่จะใช้ ไปป์ไลน์จะเปลี่ยนแปลงไม่ได้ หากต้องการเปลี่ยนการตั้งค่าบางอย่าง คุณจะต้องสร้างไปป์ไลน์อื่น WebGPU ยังใช้โปรแกรมเข้ารหัสคําสั่งเพื่อจัดกลุ่มคําสั่งเข้าด้วยกันและดําเนินการตามลําดับที่บันทึกไว้ ซึ่งมีประโยชน์ในการแสดงผลเงา เช่น ในกรณีที่แอปพลิเคชันบันทึกสตรีมคําสั่งหลายรายการในครั้งเดียวเมื่อทำการแรเงาวัตถุแต่ละรายการ โดยแต่ละรายการสําหรับแผนที่เงาของแสงแต่ละดวง
กล่าวโดยสรุปคือ เนื่องจากรูปแบบสถานะส่วนกลางของ WebGL ทำให้การสร้างไลบรารีและแอปพลิเคชันที่มีประสิทธิภาพและประกอบเข้าด้วยกันได้นั้นเป็นเรื่องยากและเปราะบาง WebGPU จึงลดจำนวนสถานะที่นักพัฒนาซอฟต์แวร์ต้องติดตามขณะส่งคําสั่งไปยัง GPU ลงอย่างมาก
หยุดซิงค์
ใน GPU การส่งคําสั่งและรอให้คําสั่งดำเนินการพร้อมกันนั้นมักจะไม่มีประสิทธิภาพ เนื่องจากอาจล้างไปป์ไลน์และทำให้เกิดฟองอากาศ โดยเฉพาะอย่างยิ่งใน WebGPU และ WebGL ซึ่งใช้สถาปัตยกรรมแบบหลายกระบวนการที่มีไดรเวอร์ GPU ที่ทำงานในกระบวนการแยกต่างหากจาก JavaScript
ตัวอย่างเช่น ใน WebGL การเรียก gl.getError()
ต้องใช้ IPC แบบซิงค์จากกระบวนการ JavaScript ไปยังกระบวนการ GPU และกลับ ซึ่งอาจทำให้เกิดบั๊กในฝั่ง CPU เมื่อ 2 กระบวนการสื่อสารกัน
WebGPU จึงออกแบบมาให้ทำงานแบบอะซิงโครนัสโดยสมบูรณ์เพื่อหลีกเลี่ยงปัญหาเหล่านี้ รูปแบบข้อผิดพลาดและการดำเนินการอื่นๆ ทั้งหมดจะเกิดขึ้นแบบไม่พร้อมกัน ตัวอย่างเช่น เมื่อคุณสร้างพื้นผิว การดำเนินการจะดูเหมือนสำเร็จทันที แม้ว่าพื้นผิวจะเป็นข้อผิดพลาดก็ตาม คุณค้นพบข้อผิดพลาดแบบไม่พร้อมกันได้เท่านั้น การออกแบบนี้ช่วยให้การสื่อสารข้ามกระบวนการทำงานได้อย่างราบรื่น และแอปพลิเคชันมีประสิทธิภาพที่เชื่อถือได้
โปรแกรมประมวลผลเฉดสี
เชดเดอร์การประมวลผลคือโปรแกรมที่ทำงานบน GPU เพื่อทำการประมวลผลทั่วไป โดยจะใช้ได้เฉพาะใน WebGPU เท่านั้น ไม่ใช่ WebGL
ซึ่งแตกต่างจากเวิร์กเทกซ์และแฟรกเมนต์ Shader ตรงที่ไม่ได้จำกัดไว้ที่การประมวลผลกราฟิกเท่านั้น แต่สามารถใช้กับงานได้หลากหลาย เช่น แมชชีนเลิร์นนิง การจำลองฟิสิกส์ และการประมวลผลทางวิทยาศาสตร์ เทรดหลายร้อยหรือหลายพันรายการจะดำเนินการเชิ้ตการประมวลผลพร้อมกัน ซึ่งทำให้มีประสิทธิภาพมากในการประมวลผลชุดข้อมูลขนาดใหญ่ ดูข้อมูลเกี่ยวกับการประมวลผลด้วย GPU และรายละเอียดเพิ่มเติมในบทความที่ครอบคลุมเกี่ยวกับ WebGPU
การประมวลผลเฟรมวิดีโอ
การประมวลผลเฟรมวิดีโอโดยใช้ JavaScript และ WebAssembly มีข้อเสียอยู่บ้าง เช่น ต้นทุนในการคัดลอกข้อมูลจากหน่วยความจำ GPU ไปยังหน่วยความจำ CPU และการทำงานแบบขนานที่จำกัดซึ่งทำได้ด้วยเวิร์กเกอร์และเธรด CPU WebGPU ไม่มีการจํากัดเหล่านี้ จึงเหมาะสําหรับการประมวลผลเฟรมวิดีโอเนื่องจากการผสานรวมอย่างใกล้ชิดกับ WebCodecs API
ข้อมูลโค้ดต่อไปนี้แสดงวิธีนําเข้า VideoFrame เป็นพื้นผิวภายนอกใน WebGPU และประมวลผล คุณสามารถลองใช้เดโมนี้ได้
// Init WebGPU device and pipeline...
// Configure canvas context...
// Feed camera stream to video...
(function render() {
const videoFrame = new VideoFrame(video);
applyFilter(videoFrame);
requestAnimationFrame(render);
})();
function applyFilter(videoFrame) {
const texture = device.importExternalTexture({ source: videoFrame });
const bindgroup = device.createBindGroup({
layout: pipeline.getBindGroupLayout(0),
entries: [{ binding: 0, resource: texture }],
});
// Finally, submit commands to GPU
}
การย้ายแอปพลิเคชันได้โดยค่าเริ่มต้น
WebGPU จะบังคับให้คุณขอ limits
โดยค่าเริ่มต้น requestDevice()
จะแสดงผล GPUDevice ที่อาจไม่ตรงกับความสามารถของฮาร์ดแวร์ของอุปกรณ์จริง แต่แสดงผล GPU ทั้งหมดที่สมเหตุสมผลและมีค่าส่วนร่วมต่ำสุด การกําหนดให้นักพัฒนาแอปต้องขอขีดจํากัดของอุปกรณ์จะช่วยให้ WebGPU มั่นใจได้ว่าแอปพลิเคชันจะทํางานบนอุปกรณ์จํานวนมากที่สุด
การจัดการภาพพิมพ์แคนวาส
WebGL จะจัดการผืนผ้าใบโดยอัตโนมัติหลังจากที่คุณสร้างบริบท WebGL และระบุแอตทริบิวต์บริบท เช่น alpha, antialias, colorSpace, depth, preserveDrawingBuffer หรือ stencil
ส่วน WebGPU กำหนดให้คุณจัดการ Canvas ด้วยตนเอง ตัวอย่างเช่น หากต้องการใช้การลบรอยหยักใน WebGPU คุณจะต้องสร้างพื้นผิวแบบ Multisample และแสดงผลกับพื้นผิวนั้น จากนั้นคุณจะต้องเปลี่ยนพื้นผิวแบบ Multisample เป็นพื้นผิวปกติและวาดพื้นผิวนั้นลงในผืนผ้าใบ การจัดการด้วยตนเองนี้ช่วยให้คุณส่งออกไปยังผืนผ้าใบได้เท่าที่ต้องการจากออบเจ็กต์ GPUDevice รายการเดียว ในทางตรงกันข้าม WebGL จะสร้างบริบทได้เพียง 1 รายการต่อผืนผ้าใบเท่านั้น
ดูการสาธิต Canvas หลายรายการของ WebGPU
โปรดทราบว่าขณะนี้เบราว์เซอร์มีการจำกัดจำนวนภาพพิมพ์แคนวาส WebGL ต่อหน้า ขณะเขียนบทความนี้ Chrome และ Safari ใช้แคนวาส WebGL ได้พร้อมกันสูงสุด 16 รายการเท่านั้น ส่วน Firefox สร้างได้สูงสุด 200 รายการ ในทางกลับกัน ไม่มีการจํากัดจํานวนภาพพิมพ์แคนวาส WebGPU ต่อหน้า
ข้อความแสดงข้อผิดพลาดที่เป็นประโยชน์
WebGPU มีสแต็กการเรียกใช้สำหรับข้อความทุกรายการที่แสดงผลจาก API ซึ่งหมายความว่าคุณจะดูได้อย่างรวดเร็วว่าข้อผิดพลาดเกิดขึ้นที่ใดในโค้ด ซึ่งมีประโยชน์สำหรับการแก้ไขข้อบกพร่องและแก้ไขข้อผิดพลาด
นอกจากแสดงสแต็กการเรียกแล้ว ข้อความแสดงข้อผิดพลาดของ WebGPU ยังเข้าใจง่ายและนำไปใช้ได้จริง โดยปกติแล้วข้อความแสดงข้อผิดพลาดจะมีคำอธิบายข้อผิดพลาดและคำแนะนำเกี่ยวกับวิธีแก้ไขข้อผิดพลาด
นอกจากนี้ WebGPU ยังให้คุณระบุ label
ที่กําหนดเองสําหรับออบเจ็กต์ WebGPU แต่ละรายการได้ด้วย จากนั้นเบราว์เซอร์จะใช้ป้ายกำกับนี้ในข้อความ GPUError คำเตือนในคอนโซล และเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ของเบราว์เซอร์
จากชื่อไปยังดัชนี
ใน WebGL สิ่งต่างๆ เชื่อมต่อกันด้วยชื่อ เช่น คุณสามารถประกาศตัวแปรแบบคงที่ชื่อ myUniform
ใน GLSL และรับตำแหน่งโดยใช้ gl.getUniformLocation(program, 'myUniform')
ซึ่งจะมีประโยชน์เมื่อคุณได้รับข้อผิดพลาดเนื่องจากพิมพ์ชื่อตัวแปรแบบคงที่ผิด
ในทางกลับกัน ใน WebGPU ทุกอย่างจะเชื่อมต่อกันทั้งหมดด้วยออฟเซตหรือดัชนีไบต์ (มักเรียกว่าตำแหน่ง) คุณมีหน้าที่รับผิดชอบในการดูแลให้ตำแหน่งของโค้ดใน WGSL และ JavaScript ซิงค์กันอยู่เสมอ
การสร้าง Mipmap
ใน WebGL คุณสามารถสร้าง MIP ระดับ 0 ของพื้นผิว แล้วเรียกใช้ gl.generateMipmap()
จากนั้น WebGL จะสร้าง MIP ระดับอื่นๆ ทั้งหมดให้คุณ
ใน WebGPU คุณต้องสร้างมิpmap ด้วยตัวเอง ยังไม่มีฟังก์ชันในตัวสำหรับดำเนินการนี้ ดูข้อมูลเพิ่มเติมเกี่ยวกับผลการตัดสินได้ในการสนทนาเกี่ยวกับข้อกำหนด คุณสามารถใช้ไลบรารีที่มีประโยชน์ เช่น webgpu-utils เพื่อสร้างมิpmap หรือดูวิธีทําด้วยตนเองก็ได้
บัฟเฟอร์พื้นที่เก็บข้อมูลและพื้นผิวพื้นที่เก็บข้อมูล
ทั้ง WebGL และ WebGPU รองรับบัฟเฟอร์แบบคงที่ และช่วยให้คุณส่งพารามิเตอร์แบบคงที่ที่มีขนาดจํากัดไปยังโปรแกรมเปลี่ยนสีได้ WebGPU รองรับบัฟเฟอร์พื้นที่เก็บข้อมูลซึ่งมีลักษณะคล้ายกับบัฟเฟอร์แบบสอดคล้องกันเท่านั้น และมีประสิทธิภาพและยืดหยุ่นกว่าบัฟเฟอร์แบบสอดคล้องกัน
ข้อมูลบัฟเฟอร์พื้นที่เก็บข้อมูลที่ส่งไปยังโปรแกรมเปลี่ยนรูปแบบสามารถมีขนาดใหญ่กว่าบัฟเฟอร์แบบคงที่ได้ แม้ว่าข้อกำหนดจะระบุว่าการเชื่อมโยงบัฟเฟอร์แบบสอดคล้องกันมีขนาดได้สูงสุด 64 KB (ดู
maxUniformBufferBindingSize
) แต่ขนาดสูงสุดของการเชื่อมโยงบัฟเฟอร์พื้นที่เก็บข้อมูลใน WebGPU จะต้องไม่น้อยกว่า 128 MB (ดูmaxStorageBufferBindingSize
)บัฟเฟอร์พื้นที่เก็บข้อมูลเป็นแบบเขียนได้และรองรับการดำเนินการแบบอะตอมบางอย่าง ส่วนบัฟเฟอร์แบบสอดคล้องกันเป็นแบบอ่านอย่างเดียว ซึ่งช่วยให้ใช้อัลกอริทึมประเภทใหม่ๆ ได้
การเชื่อมโยงบัฟเฟอร์พื้นที่เก็บข้อมูลรองรับอาร์เรย์ขนาดรันไทม์สำหรับอัลกอริทึมที่ยืดหยุ่นมากขึ้น ขณะที่ต้องระบุขนาดอาร์เรย์บัฟเฟอร์แบบสอดคล้องกันในโปรแกรมเปลี่ยนรูปแบบ
เท็กเจอร์พื้นที่เก็บข้อมูลใช้ได้ใน WebGPU เท่านั้น และมีความเกี่ยวข้องกับเท็กเจอร์เหมือนกับที่บัฟเฟอร์พื้นที่เก็บข้อมูลเกี่ยวข้องกับบัฟเฟอร์แบบสอดคล้องกัน โดยมีความยืดหยุ่นมากกว่าพื้นผิวปกติ รองรับการเขียนแบบเข้าถึงแบบสุ่ม (และอ่านด้วยในอนาคต)
การเปลี่ยนแปลงบัฟเฟอร์และพื้นผิว
ใน WebGL คุณสามารถสร้างบัฟเฟอร์หรือพื้นผิว แล้วเปลี่ยนขนาดได้ทุกเมื่อด้วย gl.bufferData()
และ gl.texImage2D()
ตามลำดับ
ใน WebGPU บัฟเฟอร์และพื้นผิวจะเปลี่ยนแปลงไม่ได้ ซึ่งหมายความว่าคุณจะเปลี่ยนขนาด การใช้งาน หรือรูปแบบของรายการดังกล่าวไม่ได้หลังจากสร้างแล้ว คุณเปลี่ยนได้เฉพาะเนื้อหาเท่านั้น
ความแตกต่างของรูปแบบพื้นที่ทำงาน
ใน WebGL ช่วง clip space ของ Z จะอยู่ที่ -1 ถึง 1 ใน WebGPU ช่วงพื้นที่คลิป Z จะอยู่ที่ 0 ถึง 1 ซึ่งหมายความว่าวัตถุที่มีค่า z เท่ากับ 0 จะอยู่ใกล้กับกล้องมากที่สุด ส่วนวัตถุที่มีค่า z เท่ากับ 1 จะอยู่ไกลที่สุด
WebGL ใช้รูปแบบ OpenGL ซึ่งแกน Y จะขึ้นและแกน Z จะหันเข้าหาผู้ชม WebGPU ใช้รูปแบบ Metal ซึ่งแกน Y จะลงและแกน Z จะอยู่นอกหน้าจอ โปรดทราบว่าทิศทางของแกน Y จะลงต่ำในพิกัดเฟรมบ buffer, พิกัดวิวพอร์ต และพิกัดเศษ/พิกเซล ในมุมมองคลิป ทิศทางแกน Y จะยังคงขึ้นอยู่เช่นเดียวกับใน WebGL
ขอขอบคุณ
ขอขอบคุณ Corentin Wallez, Gregg Tavares, Stephen White, Ken Russell และ Rachel Andrew ที่ตรวจสอบบทความนี้
นอกจากนี้ เราขอแนะนําให้ไปที่ WebGPUFundamentals.org เพื่อดูรายละเอียดความแตกต่างระหว่าง WebGPU กับ WebGL