GPU API ใหม่ของ SDL3 ถูกผสานแล้ว
(github.com/libsdl-org)- PR #9312 สำหรับ GPU API ใหม่ของ SDL3 ถูกผสานเมื่อวันที่ 29 สิงหาคม 2024 และดำเนินไปในรูปแบบที่รีบนำแนวทางที่อิงกับ Refresh ขึ้นมาเพื่อให้ได้รับการตรวจสอบมากขึ้น ในช่วงที่ SDL 3.0 ใกล้เข้ามา
- ข้อเสนอนี้มีลักษณะเป็นการนำ Refresh ซึ่งเป็นคอมโพเนนต์กราฟิกของ MoonWorks มาเป็นตัวเลือก API ขั้นสุดท้ายของ SDL_gpu โดยรองรับ Vulkan และ PS5 graphics API และขณะนั้นกำลังพัฒนาการรองรับ D3D11 deferred context อยู่
- การออกแบบ API ใช้โมเดลเรนเดอร์สมัยใหม่ที่แบ่งงานออกเป็น render pass, compute pass และ copy pass และตั้งค่าให้การเขียนรีซอร์สสามารถ cycle ภายในได้ เพื่อหลีกเลี่ยง dependency ระหว่างเฟรม
- ฝั่งเชเดอร์ถูกปรับจากข้อเสนอเริ่มต้นที่เน้น การคอมไพล์แบบออฟไลน์ ไปสู่การตรวจสอบการรองรับการสร้างเชเดอร์ที่รันไทม์ และมีการหารือโครงสร้างที่รับฟอร์แมต IR แยกตามแบ็กเอนด์ เพื่อไม่ให้ SDL เองต้องครอบ shader compiler
- หลังผสานทันที มีการปรับแก้ตามมา เช่น ชื่อฟังก์ชัน API, แมโครการตั้งค่าบิลด์, UTF-8 BOM, ข้อจำกัด 60 FPS ของ D3D12 swapchain และ thatcosmonaut ได้รับสิทธิ์ commit เพิ่ม
จุดเริ่มต้นของ PR และสถานะการผสาน
- PR #9312 เริ่มจากข้อเสนอ GPU API ใหม่ที่นำขึ้นมาเพื่อให้ SDL_gpu ได้รับการตรวจสอบอย่างรวดเร็ว
- มีเป้าหมายเพื่อดึง “สายตาให้มากขึ้น” ให้เร็ว ในช่วงที่ SDL 3.0 ใกล้เข้ามา
- ถูกผสานหลังมีการยืนยันว่า
It's mergedเมื่อวันที่ 29 สิงหาคม 2024
- หลังผสานทันที มีคำขอให้พักการเปลี่ยนแปลงไว้ชั่วคราวและดำเนินการรีวิวกับปรับแก้ก่อน
- ต่อมาสถานะกลายเป็น
everything is mergedและมีคำแนะนำว่าสามารถผสานการเปลี่ยนแปลงฝั่ง GPU ต่อได้อีกครั้ง - thatcosmonaut ถูกเพิ่มสิทธิ์ commit ด้วยเหตุผลว่ามีแนวโน้มสูงที่จะเป็นผู้รีวิว incoming changes
- ต่อมาสถานะกลายเป็น
ตัวเลือก API ที่อิงกับ Refresh
- แกนหลักของข้อเสนอคือการนำ Refresh ซึ่งเป็นคอมโพเนนต์กราฟิกของ MoonWorks มาเป็นตัวเลือก API ขั้นสุดท้ายของ SDL_gpu
- MoonWorks ถูกแนะนำว่าเป็นโปรเจกต์ที่ใกล้เคียงกับผู้สืบทอดของ XNA มากกว่าจะเป็นการนำ XNA มา reimplement เหมือน FNA
- Refresh คล้ายกับ FNA3D แต่มีเป้าหมายเป็น API สมัยใหม่อย่าง Vulkan
- ในเวลานั้น Refresh รองรับ Vulkan และ PS5 graphics API
- การรองรับ D3D11 deferred context อยู่ระหว่างพัฒนา
- มีการแนะนำว่าถูกใช้งานจริงในโปรดักชันของ Samurai Gunn 2 บน PC และคอนโซล
- ผู้เขียน PR ระบุให้ thatcosmonaut เป็นผู้ติดต่อหลัก และทีม FNA core team ก็จะมีส่วนร่วมในการดำเนินงานด้วย
การออกแบบ API และการจัดการรีซอร์ส
- API ถูกจัดเป็น API เรนเดอร์สมัยใหม่ที่มี deferred context เป็นศูนย์กลาง
- งานถูกแบ่งเป็น render pass, compute pass และ copy pass
- ส่วนที่เหลือของ API ถูกอธิบายว่าเป็นรูปแบบมาตรฐานที่ใกล้กับการเรียก binding, render และ compute dispatch
- งานทั้งหมดที่เขียนลงรีซอร์สสามารถหลีกเลี่ยง dependency ระหว่างเฟรมได้ผ่าน cycle
- แฮนเดิลรีซอร์สกราฟิกอย่าง
GpuBuffersทำหน้าที่เป็นคอนเทนเนอร์สำหรับ cycle การอ้างอิงรีซอร์สภายใน - ต่อมาแนวคิด cycle ถูกทำให้ง่ายขึ้นเป็น bool และ enum
WriteOptionsหลายตัวถูกลบออก
- แฮนเดิลรีซอร์สกราฟิกอย่าง
- ช่วงแรกมี enum
WriteOptionsหลายตัว เนื่องจากปัญหาพฤติกรรมของ data API ที่เกี่ยวกับไดรเวอร์ AMD D3D11- มีคำอธิบายว่าไม่สามารถเลี่ยงปัญหาที่ D3D11 data API ทำงานไม่เป็นไปตามคาดบน AMD ได้อย่างสมบูรณ์
- ต่อมาส่วนนี้ถูกทำให้ง่ายขึ้น และมีการบันทึกวิธีทำงานไว้ในโค้ด
การหารือระบบเชเดอร์
- แนวทางเชเดอร์เริ่มต้นคือสคริปต์ชื่อ
shaderbuild.py- ทำหน้าที่เป็น front-end ให้เครื่องมือบิลด์เชเดอร์แบบออฟไลน์บนเครื่องไคลเอนต์
- มีโครงสร้างที่รวมหลายฟอร์แมตและส่งต่อให้เหมาะกับแต่ละ render backend
- แนวทางนี้ถูกอธิบายว่าเป็นการออกแบบที่ไม่ปิดกั้น การคอมไพล์เชเดอร์แบบออนไลน์
- มีคำอธิบายว่าสามารถรวมซอร์ส SDLSL ในอนาคตไว้ในไบนารี และแปลงทันทีเป็น bytecode ของแบ็กเอนด์ที่จำเป็นใน
CreateShaderModuleได้ - จุดเด่นที่ถูกนำเสนอคือสามารถอนุญาต online compile ได้โดยไม่ทำให้ public API แตกหัก
- มีคำอธิบายว่าสามารถรวมซอร์ส SDLSL ในอนาคตไว้ในไบนารี และแปลงทันทีเป็น bytecode ของแบ็กเอนด์ที่จำเป็นใน
- จากฟีดแบ็กภายนอก มีความกังวลว่าการคอมไพล์แบบออฟไลน์ล้วน ๆ ไม่เข้ากับบางเอนจิน
- มีข้อสังเกตว่าการต้องติดตั้ง Python,
glslc,spirv-crossไว้ใน PATH อาจเป็นภาระสำหรับนักพัฒนา - ยังมีความเห็นว่าใน ecosystem ของ SDL เครื่องมือคอมไพล์เชเดอร์แบบออฟไลน์ในรูปแบบ satellite library แยกต่างหากอาจเป็นธรรมชาติกว่า
- มีข้อสังเกตว่าการต้องติดตั้ง Python,
- ต่อมาระบบเชเดอร์ถูกปรับไปในทิศทางที่แยกเชเดอร์ “raw” กับ “portable”
- ใช้พอร์ต FNA3D เป็น stress test สำหรับการรองรับการสร้างเชเดอร์ที่รันไทม์
- มีการกล่าวถึงโครงสร้างที่ใช้ MojoShader SPIR-V emitter เพื่อส่งตรงบน Vulkan และแปลงผ่าน SDL_shader ซึ่งเป็นไลบรารีแยกแบบเลือกใช้ได้บนแบ็กเอนด์อื่น
- เป้าหมายคือโครงสร้างที่ SDL เองไม่รู้หรือไม่สนใจว่าเชเดอร์มาจากที่ใด
ความคืบหน้าของแบ็กเอนด์และการทดสอบ
- implementation เริ่มต้นที่อิงกับ Refresh ถูกประเมินว่ามีจุดแข็งตรงที่มี Vulkan backend อยู่แล้ว
- มีความเห็นว่า Vulkan backend มีประสิทธิภาพสูงเมื่ออิงกับ Refresh 2.0
- การที่ compute เป็นฟีเจอร์ชั้นหนึ่งก็ถูกชี้ว่าเป็นความแตกต่างสำคัญเมื่อเทียบกับร่าง SDL_GPU เดิม
- ตั้งแต่ปลายเดือนมีนาคมถึงต้นเดือนเมษายน 2024 มีการแชร์กรณีรันเกมจริงหลายรายการ
- อธิบายว่ามาถึงสถานะที่ทำงานได้โดยไม่ต้องมีการคอมไพล์เชเดอร์แบบออฟไลน์
- มีการแชร์ revision ปัจจุบันที่ Streets of Rage 4 บูตได้
- Wizorb รันบน Metal ได้
- Celeste เข้าสู่สถานะ in-game ได้ในส่วนใหญ่ของ trace database
- มีการเพิ่มฟีเจอร์ควบคู่กันไปด้วย
- มีการระบุว่าการรองรับ hardware instancing จะถูกเพิ่มใน push ถัดไป
- ต่อมา instancing และ occlusion queries ถูกเพิ่มเข้ามา และมีการแชร์สถานะว่ายังต้องเติม implementation ฝั่ง Metal ให้ครบ
ประเด็นบิลด์, API และแพลตฟอร์มจากการรีวิว
- เกิดข้อผิดพลาดนิยาม typedef ซ้ำของ
VkInstance,VkSurfaceKHRเนื่องจากลำดับการ include ของ Vulkan- มีการเสนอแพตช์ให้สลับลำดับ include ระหว่าง Vulkan header กับ
SDL_vulkan.hในSDL_gpu_vulkan.c - ยังมีการเสนอแพตช์ให้กำหนดค่าเริ่มต้นเป็น 0 เพื่อลดคำเตือนว่า
suitableQueueFamilyIndexอาจยังไม่ได้ถูก initialize
- มีการเสนอแพตช์ให้สลับลำดับ include ระหว่าง Vulkan header กับ
- มีการหยิบยกความจำเป็นในการอัปเดต dynapi ด้วย
- มีคำแนะนำว่าสามารถอัปเดตได้โดยรัน
gendynapi.pyใต้src/dynapi/ - แต่มี caveat ว่าระหว่างรันจะมีคำเตือนเรื่องเอกสารขาดหายออกมาจำนวนมาก
- มีคำแนะนำว่าสามารถอัปเดตได้โดยรัน
- มีข้อเสนอให้เปลี่ยนชนิด byte size ใน signature ของฟังก์ชัน API เป็น
size_tแต่สรุปว่าใน GPU API ควรคงUint32ไว้- มีความเห็นว่าเมื่อขนาดบัฟเฟอร์ใหญ่มาก การรองรับร่วมกันระหว่าง 32/64 บิตอาจยากขึ้น
- มีการกล่าวถึงความเป็นไปได้ของ
Uint64เป็นทางเลือก แต่ท้ายที่สุดมีความเห็นให้คงUint32
การปรับแก้ตามมาหลังผสาน
- หลังผสาน มีการทำ tweak หลายอย่างใน #10622
- มีคำแนะนำว่าจะผสานชื่อฟังก์ชันใหม่ก่อน เพื่อให้ผู้ใช้เบต้าได้รับไปใช้งาน
- ปัญหาที่แมโครฝั่งขวาในการตั้งค่าบิลด์ต้องถูกนิยามไว้ เช่น
SDL_GPU_VULKAN SDL_VIDEO_VULKAN,SDL_GPU_METAL SDL_VIDEO_METALถูกแก้ใน #10622 - ปัญหา UTF-8 BOM ในไฟล์ซอร์ส GPU ก็ถูกแก้ใน #10622
- ฝั่ง D3D12 พบว่า
D3D12_ClaimWindow()ตั้งค่า swapchain เป็น VSYNC ทำให้testspriteถูกจำกัดที่ 60 FPS- มีการอธิบายว่า workflow ที่ตั้งใจไว้คือสร้าง swapchain ในขั้น claim window ด้วยพารามิเตอร์ที่รองรับทั่วไปคือ SDR และ VSYNC จากนั้นค่อย query ความรองรับ แล้วเรียก
SetSwapchainParameters - แม้ render driver จะเรียก
SetSwapchainParametersหลัง claim แล้ว แต่ข้อจำกัด 60 FPS ยังเหลืออยู่ใน D3D12 driver จึงกลายเป็นประเด็นที่ต้องตรวจสอบ
- มีการอธิบายว่า workflow ที่ตั้งใจไว้คือสร้าง swapchain ในขั้น claim window ด้วยพารามิเตอร์ที่รองรับทั่วไปคือ SDR และ VSYNC จากนั้นค่อย query ความรองรับ แล้วเรียก
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
SDL3 ยังอยู่ในขั้นพรีวิว แต่ GPU API ใหม่ถูกผสานเข้าเมนแบรนช์แล้ว และผู้ดูแล SDL3 กำลังปรับแต่งขั้นสุดท้ายอยู่
ตามที่เข้าใจ แก่นของ GPU API ใหม่นี้คือช่วยให้เขียนโค้ดกราฟิกและเชดเดอร์เพียงครั้งเดียว แล้วทำงานได้บนหลายแพลตฟอร์ม รวมถึงคอนโซล โดยไม่ต้องยุ่งยากมากนัก เมื่อก่อนต้องใช้ Unity หรือ Unreal หรือไม่ก็โซลูชันคัสตอมของตัวเอง
WebGPU/WGSL ก็เป็น สแตกกราฟิกข้ามแพลตฟอร์ม ที่คล้ายกัน แต่เท่าที่รู้ยังไม่มีใครทำแบ็กเอนด์สำหรับคอนโซล ในทางกลับกัน SDL3 GPU API ดูเหมือนจะยังไม่รองรับ WebGPU เป็นแบ็กเอนด์ในตอนนี้
SDL3 น่าจับตาเพราะนำ abstraction สำหรับคอนโซลเข้ามา ทำให้ GPU API ไม่ต้องมี dependency เพิ่มเติม ยิ่งไปกว่านั้น Godot รองรับ Steam Deck อย่างเป็นทางการ และหวังว่าในอนาคตจะรองรับคอนโซลมากขึ้นด้วย ในเรื่องที่เกี่ยวข้อง Miguel de Icaza กำลังผลักดันการนำ Swift มาใช้ใน Godot และยังทำงานพอร์ตเอดิเตอร์ไปเป็น SwiftUI บน iPad ด้วย ความคืบหน้า [3] น่าสนใจ
[1] https://bkaradzic.github.io/bgfx/overview.html
[2] https://github.com/bgbernovici/myndsmith
[3] https://blog.la-terminal.net/xogot-code-editing/
บริบทเพิ่มเติมอยู่ที่นี่: https://icculus.org/finger/flibitijibibo?date=2024-06-15&time=13-14-16
น่าติดตามว่ากระแสนี้จะลงตัวอย่างไร สุดท้ายแล้วถ้ามีตัวเลือกมากขึ้นสำหรับการสร้างเอนจินเกมและแอปแบบคัสตอมก็คงดี
ช่วงหลังเจาะลึก Vulkan อยู่มาก การเรียนรู้นั้นสนุกและได้เปิดหูเปิดตา แต่ด้วยลักษณะของ Vulkan เอง ทำให้รู้สึกว่าคืบหน้าได้ช้า ถ้ามี SDL3 ตอนเริ่มต้น ก็คงเลือกทางนั้นด้วยความเต็มใจ และน่าจะมีผลงานให้เห็นมากกว่านี้เมื่อเทียบกับเวลาที่ลงทุนไป
ต้องรอดูเมื่อเวลาผ่านไปว่า API นี้จะใช้งานได้จริงแค่ไหน โดยเฉพาะ การซิงโครไนซ์ทรัพยากร และวิธีเปลี่ยนชื่อออบเจ็กต์จะเป็นประเด็นสำคัญ
ต้องรอดูด้วยว่าประสิทธิภาพจะดีกว่า WebGPU หรือ abstraction อื่น ๆ หรือไม่ และจะยังคงมีขนาดเล็กต่อไปได้หรือไม่ในสถานการณ์ที่ต้องหลบเลี่ยงบั๊กของไดรเวอร์
ผมยังค่อนข้างกังขากับไบต์โค้ดใหม่สำหรับภาษาเชดดิ้งด้วย ใน WebGPU การแยกวิเคราะห์เชดเดอร์ขณะรันไทม์ไม่ใช่เรื่องน่ากังวลและเร็วมาก การสร้างเชดเดอร์แบบเนทีฟก็เร็วเช่นกัน [1] สิ่งที่ช้าคือ การสร้างไปป์ไลน์ และไบต์โค้ดนี้ไม่ได้ช่วยในส่วนนั้น
[1] http://kvark.github.io/naga/shader/2022/02/17/shader-translation-benchmark.html
สงสัยว่าเขาทำได้เร็วขนาดนี้ได้อย่างไร WebGPU แบบเนทีฟใช้เวลาพัฒนานานและยังไม่ได้สรุปเป็นขั้นสุดท้ายด้วยซ้ำ แต่ SDL GPU API รองรับแพลตฟอร์มได้มากกว่า จึงดูเหมือนน่าจะใช้เวลานานกว่าด้วยซ้ำ
มีโปรเจกต์พี่น้องสำหรับภาษาเชดดิ้งข้ามแพลตฟอร์ม [1] และอีกโปรเจกต์หนึ่งที่แปลงภาษาที่มีอยู่ไปมาระหว่างกัน [2] แต่ของเหล่านั้นจะเสร็จเมื่อเสร็จ ส่วนที่เหลือของ API ไม่จำเป็นต้องรอสิ่งนั้น
WebGPU เป็นผลผลิตจากคณะกรรมการที่ประกอบด้วยผู้ผลิตและนักกฎหมายด้านภาษา หรือไม่ก็นักกฎหมายด้านมาตรฐาน สร้างขึ้นท่ามกลางการเมืองและระบบราชการ ซึ่งเห็นได้ชัดเจน SDL_GPU ถูกสร้างโดยนักพัฒนาเกมที่ให้ความสำคัญกับความใช้ได้จริงเหนือสิ่งอื่นใด และด้วยเหตุนี้จึงมักถูกมองต่ำจากหอคอยงาช้าง
[1]: https://github.com/libsdl-org/SDL_shader_tools
[2]: https://github.com/flibitijibibo/SDL_gpu_shadercross
ดีใจที่ได้มีส่วนร่วมในส่วน dx12 :)
อาจจะลองใช้ดูสักครั้ง ผมรู้สึกมาตลอดว่า SDL เป็นซอฟต์แวร์คุณภาพดี คอมไพล์เร็ว คอมไพล์บนหลายแพลตฟอร์มได้ง่าย และทำงานได้ดีเสมอ เลยคาดหวังกับ API ใหม่นี้ด้วย
โดยรวมแล้วเป็นแฟนตัวยงของ SDL
ตอนที่มองหาไลบรารีเกมข้ามแพลตฟอร์ม SDL และ API ของมันให้ความรู้สึกว่าอยู่ในจุดสมดุลที่พอดี ผมแค่อยากได้ไลบรารี C/C++ ที่เรียกใช้เพื่อสร้างหน้าต่างและกราฟิกคอนเท็กซ์ได้ กับเฟรมเวิร์กเรนเดอร์สไปรต์ที่รวดเร็ว ไม่ได้ต้องการ IDE ทั้งชุดหรือไลบรารีเทอะทะ และก็ไม่อยากเรียนภาษาใหม่
SDL3 ให้ความรู้สึกว่ากำลังเจอกับ second-system effect SDL2 ใกล้เคียงกับ SDL1 ที่มีแฮนเดิลหน้าต่างแบบชัดเจน ดังนั้น SDL3 จึงเป็นระบบที่สอง ไม่ใช่ที่สาม SDL1/2 เป็นเลเยอร์บาง ๆ ที่ครอบ boilerplate เฉพาะแพลตฟอร์มสำหรับเปิดหน้าต่างและจัดการอีเวนต์อินพุต ทำให้เข้าไปเขียนโค้ดเรนเดอร์ OpenGL ที่อยากเขียนจริง ๆ ได้อย่างรวดเร็ว
แต่ถ้าจะรองรับระบบปฏิบัติการของ Apple ด้วย ก็จะถูกจำกัดอยู่กับ OpenGL 4.1 ซึ่ง Apple ประกาศอย่างเป็นทางการว่าจะเลิกใช้ไปเมื่อ 5 ปีก่อน จึงใช้ฟีเจอร์ GPU สมัยใหม่อย่าง compute shader ไม่ได้
จะไปเส้นทาง Vulkan แล้วใช้ MoltenVK บนระบบของ Apple ก็ได้ แต่ Vulkan มีความซับซ้อนสูงกว่า OpenGL พอสมควร อย่างที่คนมักพูดกันว่า “โค้ด 1,000 บรรทัดเพื่อวาดสามเหลี่ยมหนึ่งรูป” เป้าหมายของ GPU API ใน SDL3 คือให้ทางเลือกที่เข้าถึงง่ายกว่าแต่ยังยืดหยุ่นพอ
คอนโซลก็น่าจะเป็นเรื่องคล้ายกัน
ว่ากันว่ามีคนจำนวนมากขอว่า “ช่วยเพิ่มการรองรับเชดเดอร์ที่ทำงานได้ทุกแพลตฟอร์มให้เหมือน SDL_render ได้ไหม” และนั่นคือจุดเริ่มต้น
SDL3 ยังเพิ่ม audio API ระดับสูงขึ้นด้วย แต่ไม่ค่อยรู้ข้อดีของมัน
นอกจากนี้ SDL2 ยังพัฒนาไปมากหลัง 2.0.0 และ SDL3 ก็สานต่อวิวัฒนาการนั้นโดยยอมให้มีการเปลี่ยนแปลงที่ทำลายความเข้ากันได้ของ API SDL3 ไม่ได้เขียนใหม่ตั้งแต่ศูนย์ และจากมุมของผู้ใช้ SDL การย้ายจาก SDL2 ไป SDL3 ไม่น่าจะยากขนาดนั้น
อีกทั้ง SDL1/2 ก็ไม่เคย “บางอย่างเดียว” ถึงขั้นไม่มีระบบกราฟิกระดับสูงของตัวเอง การมีสิ่งพื้นฐานให้ผู้ใช้ใหม่หรือผู้ใช้ทั่วไปแสดงอะไรบนหน้าจอได้ทันทีนั้นมีประโยชน์
อย่างที่ ahefner ชี้ไว้ SDL1 ถือว่าค่อนข้าง “บาง” ตามมาตรฐานปัจจุบัน แต่ก็ยังให้ความสามารถพอที่จะวาดสิ่งพื้นฐานบนหน้าจอได้โดยไม่ต้องเขียนคณิตศาสตร์พิกเซลเอง และในยุค 90 นั่นช่วยได้มากทีเดียว
ถึงอย่างนั้น abstraction นี้ก็อาจช่วยตอบโจทย์ความต้องการที่เกินกว่าเกม 2D ง่าย ๆ และทำให้เล็งไปยังระบบนิเวศ graphics API ที่น่าเสียดายว่ากำลังแตกเป็นส่วน ๆ มากขึ้นได้ ความฝันถึงอนาคต OpenGL(Next) ที่เป็นสากลได้หายไปแล้ว เพียงแต่ส่วนที่ยากที่สุดอย่าง การแปลงเชดเดอร์ ดูเหมือนจะยังไม่มี
ยังไม่เคยใช้ไลบรารีนี้ แต่ถ้าเข้าใจจากเธรดที่ลิงก์ไว้ถูกต้อง ตอนนี้อยากเห็นตัวอย่างฟีเจอร์ GPU compute ข้ามแพลตฟอร์ม ที่มีให้แล้ว มีคำแนะนำไหมว่าควรเริ่มจากตรงไหน