ในฐานะนักพัฒนา WebGL คุณอาจรู้สึกทั้งกังวลและตื่นเต้นที่จะได้เริ่มใช้ WebGPU ซึ่งเป็น API กราฟิกสมัยใหม่ที่นำมาใช้ในเว็บเพื่อแทนที่ WebGL
คุณก็คงโล่งใจเมื่อทราบว่า WebGL และ WebGPU มีแนวคิดหลักหลายอย่างที่เหมือนกัน ทั้ง 2 API ช่วยให้คุณสามารถเรียกใช้โปรแกรมขนาดเล็กที่เรียกว่า Shader ใน GPU ได้ WebGL รองรับเวิร์กเท็กซ์และแฟรกเมนต์ Shader ส่วน WebGPU รองรับทั้งเวิร์กเท็กซ์และคอมพิวต Shader WebGL จะใช้ OpenGL Shading Language (GLSL) ในขณะที่ WebGPU ใช้ภาษา WebGPU Shading Language (WGSL) แม้ว่าทั้ง 2 ภาษาจะต่างกัน แต่แนวคิดที่สำคัญก็เหมือนกันเป็นส่วนใหญ่
บทความนี้จะเน้นความแตกต่างบางประการระหว่าง WebGL กับ WebGPU เพื่อช่วยให้คุณเริ่มต้นใช้งาน
สถานะส่วนกลาง
WebGL มีสถานะส่วนกลางจำนวนมาก การตั้งค่าบางอย่างมีผลกับการดำเนินการทั้งหมดของการแสดงผล เช่น การกำหนดค่าพื้นผิวและบัฟเฟอร์ คุณตั้งค่าสถานะส่วนกลางนี้โดยการเรียกใช้ฟังก์ชัน API ต่างๆ และสถานะนี้จะมีผลจนกว่าคุณจะเปลี่ยนแปลง สถานะส่วนกลางใน WebGL เป็นแหล่งที่มาของข้อผิดพลาดหลัก เนื่องจากคุณอาจลืมเปลี่ยนการตั้งค่าส่วนกลางได้ง่ายๆ นอกจากนี้ สถานะส่วนกลางยังทําให้แชร์โค้ดได้ยาก เนื่องจากนักพัฒนาแอปต้องระมัดระวังไม่ให้เปลี่ยนสถานะส่วนกลางโดยไม่ตั้งใจในลักษณะที่ส่งผลต่อส่วนอื่นๆ ของโค้ด
WebGPU เป็น API ที่ไม่มีสถานะ และจะไม่รักษาสถานะส่วนกลาง แต่จะใช้แนวคิดของ ไปป์ไลน์เพื่อรวมสถานะการแสดงผลทั้งหมดที่เป็นแบบส่วนกลางใน WebGL ไปป์ไลน์มีข้อมูล เช่น การผสมผสาน โทโพโลยี และแอตทริบิวต์ที่จะใช้ ไปป์ไลน์จะเปลี่ยนแปลงไม่ได้ หากต้องการเปลี่ยนการตั้งค่าบางอย่าง คุณจะต้องสร้างไปป์ไลน์อื่น นอกจากนี้ WebGPU ยังใช้โปรแกรมเปลี่ยนไฟล์แบบคำสั่งเพื่อจัดกลุ่มคำสั่งไว้ด้วยกันและดำเนินการตามลำดับที่มีการบันทึก ซึ่งจะมีประโยชน์ในการทำแผนที่เงา เช่น เมื่อส่งผ่านวัตถุเพียงครั้งเดียว แอปพลิเคชันสามารถบันทึกสตรีมคำสั่งหลายรายการ โดยใช้ครั้งละ 1 สำหรับแผนที่เงาของแสงแต่ละดวง
กล่าวโดยสรุปคือ เนื่องจากรูปแบบสถานะส่วนกลางของ WebGL ทำให้การสร้างไลบรารีและแอปพลิเคชันที่มีประสิทธิภาพและประกอบเข้าด้วยกันได้นั้นเป็นเรื่องยากและเปราะบาง WebGPU จึงลดจำนวนสถานะที่นักพัฒนาซอฟต์แวร์ต้องติดตามขณะส่งคําสั่งไปยัง GPU ลงอย่างมาก
หยุดซิงค์
ใน GPU การส่งคําสั่งและรอให้คําสั่งดำเนินการพร้อมกันนั้นมักจะไม่มีประสิทธิภาพ เนื่องจากอาจล้างไปป์ไลน์และทำให้เกิดฟองอากาศ โดยเฉพาะอย่างยิ่งใน WebGPU และ WebGL ซึ่งใช้สถาปัตยกรรมแบบหลายกระบวนการที่มีไดรเวอร์ GPU ที่ทำงานในกระบวนการแยกต่างหากจาก JavaScript
ตัวอย่างเช่น ใน WebGL การเรียก gl.getError()
ต้องใช้ IPC แบบซิงค์จากกระบวนการ JavaScript ไปยังกระบวนการ GPU และกลับ ซึ่งอาจทำให้เกิดบั๊กในฝั่ง CPU เมื่อ 2 กระบวนการสื่อสารกัน
WebGPU จึงออกแบบมาให้ทำงานแบบอะซิงโครนัสโดยสมบูรณ์เพื่อหลีกเลี่ยงปัญหาเหล่านี้ รูปแบบข้อผิดพลาดและการดำเนินการอื่นๆ ทั้งหมดจะเกิดขึ้นแบบไม่พร้อมกัน ตัวอย่างเช่น เมื่อคุณสร้างพื้นผิว การดำเนินการจะสำเร็จโดยทันที แม้ว่าจริงๆ แล้วพื้นผิวจะเกิดข้อผิดพลาดก็ตาม คุณจะเห็นข้อผิดพลาดแบบไม่พร้อมกันเท่านั้น การออกแบบนี้ช่วยให้การสื่อสารข้ามกระบวนการไม่มีบัเบิ้ลและช่วยให้แอปพลิเคชันมีประสิทธิภาพที่เชื่อถือได้
โปรแกรมประมวลผลเฉดสี
ตัวปรับแสงเงาการประมวลผลเป็นโปรแกรมที่ทำงานบน GPU เพื่อคำนวณตามจุดประสงค์ทั่วไป โดยมีให้ใช้งานเฉพาะใน WebGPU เท่านั้น และไม่สามารถใช้ WebGL
ซึ่งแตกต่างจาก Vertex Shader และ Fragment 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()
จะแสดงผล GPU ที่อาจไม่ตรงกับความสามารถของฮาร์ดแวร์ของอุปกรณ์จริง แต่จะแสดงผลตัวส่วนร่วมที่สมเหตุสมผลและต่ำสุดของ GPU ทั้งหมด การกําหนดให้นักพัฒนาแอปต้องขอขีดจํากัดของอุปกรณ์จะช่วยให้ WebGPU มั่นใจได้ว่าแอปพลิเคชันจะทํางานบนอุปกรณ์จํานวนมากที่สุด
การจัดการ Canvas
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 รายการ ในทางกลับกัน ไม่มีการจำกัดจำนวน Canvas ของ WebGPU ต่อหน้าเว็บ
ข้อความแสดงข้อผิดพลาดที่เป็นประโยชน์
WebGPU มีสแต็กการเรียกใช้สำหรับข้อความทุกรายการที่แสดงผลจาก API ซึ่งหมายความว่าคุณจะดูได้อย่างรวดเร็วว่าข้อผิดพลาดเกิดขึ้นที่ใดในโค้ด ซึ่งมีประโยชน์สำหรับการแก้ไขข้อบกพร่องและแก้ไขข้อผิดพลาด
นอกจากแสดงสแต็กการเรียกแล้ว ข้อความแสดงข้อผิดพลาดของ WebGPU ยังเข้าใจง่ายและนำไปใช้ได้จริง โดยปกติแล้วข้อความแสดงข้อผิดพลาดจะมีคำอธิบายข้อผิดพลาดและคำแนะนำเกี่ยวกับวิธีแก้ไขข้อผิดพลาด
นอกจากนี้ WebGPU ยังให้คุณระบุ label
ที่กําหนดเองสําหรับออบเจ็กต์ WebGPU แต่ละรายการได้ด้วย จากนั้นเบราว์เซอร์จะใช้ป้ายกำกับนี้ในข้อความ GPUError คำเตือนในคอนโซล และเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ของเบราว์เซอร์
จากชื่อไปยังดัชนี
ใน WebGL สิ่งต่างๆ เชื่อมต่อกันด้วยชื่อ เช่น คุณสามารถประกาศตัวแปรแบบคงที่ชื่อ myUniform
ใน GLSL และรับตำแหน่งโดยใช้ gl.getUniformLocation(program, 'myUniform')
ซึ่งจะมีประโยชน์เมื่อคุณได้รับข้อผิดพลาดเนื่องจากพิมพ์ชื่อตัวแปรแบบเดียวกันผิด
ในทางกลับกัน ใน WebGPU ทุกอย่างจะเชื่อมต่อกันทั้งหมดด้วยออฟเซตหรือดัชนีไบต์ (มักเรียกว่าตำแหน่ง) คุณมีหน้าที่รับผิดชอบในการดูแลให้ตำแหน่งของโค้ดใน WGSL และ JavaScript ซิงค์กันอยู่เสมอ
การสร้าง Mipmap
ใน WebGL คุณสามารถสร้างความละเอียดของพื้นผิวระดับ 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 จะใช้รูปแบบโลหะ โดยแกน Y อยู่ด้านล่างและแกน Z อยู่นอกหน้าจอ โปรดทราบว่าทิศทางแกน Y จะลดลงในพิกัดเฟรมบัฟเฟอร์ พิกัดวิวพอร์ต และพิกัดส่วนย่อย/พิกเซล ในคลิปเพลย์ ทิศทางแกน Y จะยังคงขึ้นอยู่เช่นเดียวกับใน WebGL
ขอขอบคุณ
ขอขอบคุณ Corentin Wallez, Gregg Tavares, Stephen White, Ken Russell และ Rachel Andrew ที่ตรวจสอบบทความนี้
นอกจากนี้ เราขอแนะนําให้ไปที่ WebGPUFundamentals.org เพื่อดูรายละเอียดความแตกต่างระหว่าง WebGPU กับ WebGL