M1 पर conformant OpenGL 4.6 सपोर्ट
(rosenzweig.io)- M1 कई वर्षों तक OpenGL 4.1 पर अटका रहा, लेकिन Fedora Asahi Remix के नवीनतम M1/M2 ड्राइवर अब OpenGL 4.6 और OpenGL ES 3.2 को पूरी तरह सपोर्ट करते हैं
- Asahi का open source Linux ड्राइवर vendor के non-conformant 4.1 ड्राइवर के विपरीत Khronos सूची में दर्ज conformant driver है, जो Blender जैसे आधुनिक OpenGL workloads के साथ compatibility बढ़ाता है
- OpenGL 4.6 में robustness, SPIR-V, clip control, cull distance, compute shaders और बेहतर transform feedback की जरूरत होती है, लेकिन M1 hardware आधुनिक graphics standards से सीधे मेल नहीं खाता
- hardware में मौजूद न होने वाले features को driver और compiler तकनीकों से पूरा किया गया: geometry shaders, tessellation, transform feedback को compute shaders से, और cull distance व clip control को shader transformations से संभाला गया
- 100,000 से अधिक conformance tests पास करने के लिए buffer और image robustness को software में implement किया गया, और clamp, preamble optimization, तथा mipmap workaround से अतिरिक्त लागत घटाई गई
Fedora Asahi Remix में OpenGL 4.6/ES 3.2 उपलब्ध
- M1 अब तक सिर्फ OpenGL 4.1 तक सपोर्ट करता था, लेकिन अब OpenGL 4.6 और OpenGL ES 3.2 को सपोर्ट करता है
- नवीनतम M1/M2 series ड्राइवर Fedora Asahi Remix इंस्टॉल करके इस्तेमाल किए जा सकते हैं
- जिन उपयोगकर्ताओं ने इसे पहले से इंस्टॉल किया है, वे इस कमांड से अपडेट करें
dnf upgrade --refresh
- Asahi का open source Mesa driver vendor के non-conformant 4.1 ड्राइवर के विपरीत नवीनतम OpenGL versions के लिए conformance रखता है
- conformant 4.6/3.2 ड्राइवर को correctness सुनिश्चित करने के लिए 100,000 से अधिक tests पास करने होते हैं
- Khronos की आधिकारिक सूची में Asahi का OpenGL 4.6 और OpenGL ES 3.2 शामिल हैं
- 6 महीने पहले OpenGL ES 3.1 ड्राइवर के साथ M1 के standard graphics API के लिए पहला conformant driver आया था, और अब OpenGL 4.6 भी पूरा हो गया है
- Vulkan सपोर्ट पर भी काम जारी है
OpenGL 4.1 की बाधा पार करने के लिए feature implementation
- OpenGL 4.6, 4.1 की तुलना में कई अनिवार्य features जोड़ता है
- Robustness
- SPIR-V
- Clip control
- Cull distance
- Compute shaders
- upgraded transform feedback
- M1, OpenGL ES 3.1 के बाद के graphics standards के लिए बहुत उपयुक्त नहीं है
- Vulkan कुछ features को optional बनाता है, लेकिन उसके ऊपर DirectX और OpenGL को layer करने के लिए missing features की जरूरत पड़ती है
- M1 का मौजूदा समाधान OpenGL 4.1 feature set से आगे नहीं बढ़ पाता था
- जिन नए features के लिए hardware support नहीं है, उन्हें driver techniques से implement किया गया
- Geometry shaders, tessellation, और transform feedback को compute shaders से संभाला गया
- Cull distance को transformed interpolants से संभाला गया
- Clip control को vertex shader epilogue में implement किया गया
Buffer robustness और M1 का software correction
- GPU पारंपरिक रूप से safety की बजाय performance को प्राथमिकता देता है, इसलिए shader अगर buffer सीमा के बाहर पढ़े तो गलत code में undefined behavior हो सकता है
- web browser जैसे applications, जो untrusted shaders को संभालते हैं, उनके लिए यह समझौता उचित नहीं है
- graphics API स्वयं security boundary नहीं है, इसलिए कुछ sanitization जरूरी है
- API के undefined behavior को कम करना defense in depth में मदद करता है
- Robustness चालू होने पर application कुछ performance छोड़कर out-of-bounds access के लिए defined behavior चुन सकता है
- अलग-अलग APIs में out-of-bounds buffer load का परिणाम अलग होता है
- Direct3D और Vulkan
robustBufferAccess2: 0 लौटाते हैं - OpenGL और Vulkan
robustBufferAccess: 0 या buffer के अंदर का कुछ data लौटाते हैं - OpenGL ES: मनमाना मान संभव है, लेकिन crash नहीं होना चाहिए
- Direct3D और Vulkan
- OpenGL की requirement यह है कि out-of-bounds access पर 0 या buffer के भीतर का data लौटे, इसलिए आखिरी valid index और access index का unsigned minimum निकालकर safe index से load किया जा सकता है
- robustness के बिना uniform buffer load:
load.i32 result, buffer, index - robustness लागू करने के बाद:
umin idx, index, lastके बादload.i32 result, buffer, idx
- robustness के बिना uniform buffer load:
- M1 का preamble सभी threads में एक ही value बार-बार calculate करने के बजाय उसे एक बार calculate करके reuse करता है
- uniform buffer size fixed होती है, इसलिए अतिरिक्त robustness arithmetic को भी preamble में ले जाया जा सकता है
- robust storage buffer में भले ही load/store खुद move न हो सके, clamp calculation को preamble में ले जाया जा सकता है
Vertex buffer robustness implementation
- graphics API में application vertex buffer का GPU base address और attribute layout सेट करता है
- हर attribute का एक offset और format होता है
- buffer में stride होता है, जो प्रति vertex bytes की संख्या बताता है
- vertex shader vertex के आधार पर implicit indexing से attribute पढ़ता है
- कुछ hardware robust vertex fetch को native रूप से implement करते हैं या bounds-checked buffer के जरिए software fetch को तेज करते हैं, लेकिन M1 में दोनों नहीं हैं
- M1 GPU memory load 64-bit base address और element-unit offset लेता है, और
imadinteger multiply-add instruction भी देता है- 32-bit attribute load को
imad idx, stride/4, vertex, offset/4औरload.i32 result, base, idxइन दो instructions से implement किया जा सकता है - 4 tightly packed 32-bit values वाला vector attribute
load.v4i32 result, base, vertex << 2एक instruction में load किया जा सकता है
- 32-bit attribute load को
- Robustness के लिए clamp जरूरी है, लेकिन vertex buffer size bytes में होती है जबकि optimized load vertex-unit index का इस्तेमाल करता है
- इस समस्या को एक buffer के भीतर कई attributes और offsets को per-attribute अलग base address की तरह reinterpret करके हल किया गया
- shader में offset जोड़ने के बजाय per-attribute base pass किया जाता है
- byte-unit buffer size को हर attribute के लिए vertex-unit size में बदला जा सकता है
- offset की जगह vertex index को clamp किया जाता है
- driver हर attribute format के size का उपयोग करके आखिरी valid vertex index पहले से calculate करता है और shader को देता है
- अगर buffer इतना छोटा हो कि कुछ भी load न किया जा सके, तो clamp से समस्या हल नहीं होती; ऐसे में उस attribute के buffer को छोटे zero buffer से बदल दिया जाता है
- per-attribute base address इस्तेमाल होने के कारण यह निर्णय भी per-attribute लिया जा सकता है
- अंत में, थोड़ी driver-side calculation और एक
uminकी लागत पर robust vertex buffer implement किया गया
Image robustness और mipmap workaround
- Buffer robustness के अलावा image robustness भी जरूरी है, और out-of-bounds image load को 0 लौटाना चाहिए
- mipmapped image में कई levels of detail शामिल होते हैं
- base level मूल image होता है
- हर अगला level पिछले level का छोटा किया हुआ image होता है
- rendering के दौरान hardware screen size के करीब वाले level को चुनकर efficiency और visual quality बेहतर करता है
- specification के अनुसार robustness में image load को इन स्थितियों में 0 लौटाना चाहिए
- जब X या Y coordinate सीमा से बाहर हो
- जब level सीमा से बाहर हो
- M1 GPU का image load behavior इन requirements से अलग है
- X या Y coordinate सीमा से बाहर हो तो 0 लौटाता है
- level सीमा से बाहर हो तो आखिरी level का मान लौटाता है
- vendor ने hardware documentation सार्वजनिक नहीं की है, इसलिए यह behavior इरादतन है या hardware bug, यह स्पष्ट नहीं है; conformance पास करने के लिए workaround जरूरी था
- सीधा workaround यह है कि level valid होने पर ही load किया जाए, नहीं तो 0 लौटाया जाए, लेकिन branch अप्रभावी है
- बेहतर तरीका यह है कि out-of-bounds level पर भी load crash नहीं करता, इसका फायदा उठाकर पहले load किया जाए और फिर compare-select से 0 चुना जाए
- लेकिन M1 GPU का instruction set scalar है, जबकि image load red/green/blue/alpha वाले 4-component vector लौटाता है
- हर component के लिए
uleselचाहिए, जिससे assembly बड़ी हो जाती है
- अंतिम workaround इस तथ्य का उपयोग करता है कि X या Y सीमा से बाहर होने पर hardware 0 लौटाता है
- अधिकतम image width 16384px है, इसलिए X को 20000 जैसे मान पर बदलने से वह सीमा से बाहर हो जाता है
- अगर level valid है तो मूल X इस्तेमाल किया जाता है, और अगर valid नहीं है तो X को 20000 बनाकर image load से 0 लौटवाया जाता है
- यह तरीका पूरे vector को select करने के बजाय सिर्फ एक scalar बदलता है, इसलिए compact assembly में compile होता है
- अगर constant को uniform register में पहले से लोड कर दिया जाए, तो workaround की लागत सिर्फ एक instruction रह जाती है
- इसी तरीके से conformance पास किया गया
1 टिप्पणियां
Hacker News की राय
Alyssa Rosenzweig कम्युनिटी में लगातार योगदान देने वाला एक बड़ा तोहफा जैसी लगती हैं
हर ब्लॉग पोस्ट में आधुनिक graphics hardware की अंदरूनी संरचना के बारे में कुछ न कुछ ऐसा सीखने को मिल ही जाता है जो पहले नहीं पता था
यह काम दिखाता है कि बातें नहीं, काबिलियत हर बार जीतती है
सिर्फ ब्लॉग पढ़ने भर से दिमाग गरम हो जाए, इतना कुछ खोलकर समझने लायक होता है; और निष्कर्ष आखिरी वाक्य में नहीं बल्कि दूसरे वाक्य में होने के बावजूद, अंत में आप हर bit manipulation का पीछा करते हुए rabbit hole में उतर ही जाते हैं
अगर प्रति पैराग्राफ सीख की संख्या जैसा कोई benchmark हो, तो Alyssa शायद हर जगह पहले नंबर पर होंगी
अगर किसी दिन Apple OpenGL 3.3 core को हटा दे, तो शायद अंततः बाकी सब भी उसे हटाने लगें
आम तौर पर सुना है कि OpenGL, Vulkan से इस्तेमाल में आसान है, लेकिन बहुत जटिल API कम अनुभव वाले developers के लिए GPU का उपयोग कठिन बना सकती है और entry barrier बनकर indie game developers को बाहर धकेल सकती है
आजकल सब Unity और Unreal इस्तेमाल करते हैं, इसलिए शून्य से बनाना या कोई और engine इस्तेमाल करना अजीब लगता है; Unity के और ज्यादा lock-in की कोशिश के बाद game development जगत को जागते देखना दिलचस्प है, लेकिन झुंझलाहट भी होती है
game development में open source हमेशा तंग हालत में रहा है, और Godot मौजूद होने के बावजूद Unity और Unreal को गंभीर चुनौती देना मुश्किल दिखता है
Godot पर्याप्त रूप से सक्षम हो भी, तो भी indie developers Unity और Unreal से ज्यादा परिचित हैं, इसलिए उनके वहीं बने रहने की संभावना ज्यादा है
game development में open source की स्थिति कभी-कभी निराशाजनक लगती है, और अगली पीढ़ी के graphics API का आना चीजों को आसान नहीं बनाता
OpenGL triangle rendering example करीब 200 lines का है, और Vulkan triangle rendering example करीब 1000 lines का
Vulkan को बहुत flexible तरह से design किया गया है, लेकिन उसमें convenience features ज्यादा नहीं हैं
किसी भी स्थिति में, OpenGL driver के direct API के रूप में expose करने के लिए बहुत high-level था; GPU hardware जिस तरह काम करता है, उसके हिसाब से Vulkan जैसी low-level API को base layer बनाकर उसके ऊपर OpenGL जैसी चीज रखना बेहतर मेल खाता है
साथ ही ऐसा भी नहीं कि हर कोई Unity और Unreal ही इस्तेमाल करता है
The Game Awards 2023 में Game of the Year के 6 nominee सभी अपने in-house engines से बने थे, और indie scene में भी Hades जैसे अपने engine बनाने वाले developers अब भी हैं
हालांकि बहुसंख्यक लोग तैयार engines इस्तेमाल करते हैं, यह सही है
अगर यह आपकी सभी जरूरी सुविधाएं पूरी करता है और आप state-based rendering pipeline स्वीकार कर सकते हैं, तो नए project में इसे इस्तेमाल करना भी अच्छा विकल्प है
यह अभी भी चलता है और आजकल Metal के ऊपर एक layer के रूप में run होता है, लेकिन macOS या iOS के लिए GL code build करने पर deprecation warnings लगातार आते हैं
define से इन्हें बंद किया जा सकता है
OpenGL की समस्या यह है कि यह GPU के काम करने के तरीके से बहुत दूर है, इसलिए अच्छा performance निकालना मुश्किल होता है
सोचता हूं कि इस काम का कितना हिस्सा M1 GPU code से बंधा है, और feature-on-feature implementation का कितना हिस्सा दूसरी जगहों पर भी reuse किया जा सकता है
यह Zink के उस तरीके जैसा बहुत लगता है जिसमें वह अधिक primitive Vulkan के ऊपर जटिल OpenGL features चलाता है, लेकिन M1 के लिए अभी target करने लायक Vulkan backend नहीं है
अंततः यह workload का सवाल है, और इसे अलग-अलग hardware पर reuse किया जा सकता है
यह उन hardware के लिए भी मददगार हो सकता है जो पुराने हैं और अच्छी तरह समझे जा चुके हैं, लेकिन आधुनिक workloads के लिए अकेले इस्तेमाल करना मुश्किल है
इससे होने वाला performance impact कितना होगा, खासकर macOS पर सीधे Metal इस्तेमाल करने की तुलना में, यह जानने की बहुत उत्सुकता है
जवाब निश्चित ही “स्थिति पर निर्भर करता है” होगा, लेकिन फिर भी जिज्ञासा है
शायद लेख में इसका जवाब हो, लेकिन ज्यादातर बातें मेरी समझ में नहीं आईं
“hardware support” भी आम तौर पर GPU microcode में implement होता है और कई बार वही silicon path इस्तेमाल करता है
कोई भी feature performance bottleneck बन सकता है, और वास्तव में करके देखे बिना यह जानना मुश्किल है कि bottleneck कहां आएगा
यह सही है कि Apple GPU geometry shaders को native तौर पर support नहीं करता, लेकिन geometry shaders का design अच्छा नहीं है और वे GPU hardware के साथ ठीक से मेल नहीं खाते
जिन hardware में असल support बताया जाता है, उन पर भी वे धीमे माने जाते हैं, और Nvidia ने mesh shading design की, इसकी वजह है
transform feedback का भी अक्सर जिक्र होता है, लेकिन Apple GPU किसी भी shader stage से arbitrary memory locations में लिख सकता है, इसलिए transform feedback वस्तुतः अनावश्यक है
मुख्य बात यह है कि Apple ने एक साफ-सुथरा compute architecture implement करते हुए कई पुराने अवशेषों और ऐसी features को काट दिया जो ठीक से काम न करने के लिए जाने जाते हैं
“M1 OpenGL 4.1 में फंस गया” कहना उचित नहीं लगता
OpenGL को बहुत पहले से follow नहीं किया, इसलिए 4.1 के बाद कौन-सी features की बात है, यह नहीं जानता; लेकिन अगर OpenGL में कोई ऐसी feature है जो Metal में नहीं की जा सकती, तो मुझे बहुत आश्चर्य होगा
उल्टा, Metal में बहुत सी चीजें संभव हैं जो OpenGL में बिल्कुल संभव नहीं हैं, और Metal shading language में full pointers होना ही इसका एक उदाहरण है
यह M1 पर Fedora के लिए है
अगर यह macOS पर भी संभव हो जाए तो हैरानी होगी, लेकिन सोचता हूँ कि ऐसा बनाने के लिए क्या-क्या चाहिए होगा
M1 GPU के लिए शुरुआती Mesa driver भी IOKit के जरिए macOS के AGX driver को command buffer भेजने के तरीके से bootstrap किया गया था
https://rosenzweig.io/blog/asahi-gpu-part-2.html
https://github.com/AsahiLinux/gpu/blob/main/demo/iokit.c
इसलिए GPU के surface को macOS स्क्रीन पर composite किए जा सकने वाले target के रूप में पास करने के लिए Mesa की तरफ थोड़ा और glue code चाहिए
मेरी समझ में, ठीक-ठाक Vulkan या OpenGL implementation बनाने के लिए GPU processing संभालने वाला kernel-side counterpart चाहिए होता है
शायद इसलिए macOS के लिए native Vulkan implement करने की कोशिश करने वाला कोई नहीं दिखता
हालांकि अगर Apple driver के ऊपर यह संभव हो तो, मुझे ठीक से नहीं पता
लेकिन एक suboptimal legacy API के लिए इतने resources लगाने की वजह है या नहीं, यह नहीं जानता
out-of-bounds access को trap से arbitrary data लौटाने में बदलने को robustness कहना काफी मजेदार है
graphics programming वाकई अजीब है
GPU driver का मुख्य काम broken applications को चलाना या उन्हें तेज चलाना है
defaults को strict बना देने से broken code रिलीज़ करने वाली video game industry की structural समस्या ठीक नहीं होगी, बस users दूर चले जाएंगे
ऐसे hardware में जहाँ branching आम तौर पर बहुत महंगी होती है, system को edge cases को सबसे efficient तरीके से चुपचाप handle करने को बताने वाला flag उपयोगी लगता है
ऐसे कई valid use cases भी होंगे जहाँ programmer reasonably भरोसा कर सकता है कि ये edge cases final rendered frame पर लगभग असर नहीं डालते
इसे इस बात के साथ मिलाएँ कि GPU आम तौर पर traps को खास पसंद नहीं करते, तो बात समझ आती है
Carmack ने भी कभी कहा था कि megatexture design करते समय manufacturers को virtual memory के idea को स्वीकार करवाना बहुत दर्दनाक था
जहाँ “performance safety से ऊपर” वाली culture हावी है, वहाँ दूसरी programming languages की बात करना दीवार से बात करने जैसा है
यह निश्चित रूप से बहुत दिलचस्प काम है, लेकिन सोचता हूँ कि पहले Vulkan को target क्यों नहीं किया गया
आजकल यह ज्यादा महत्वपूर्ण target लगता है, और इसके ऊपर पहले से OpenGL implementation भी है
किसी खास OpenGL feature को support करने के लिए Vulkan driver को उसके बराबर feature support करना पड़ता है, और आम तौर पर extension चाहिए होता है
यानी सिर्फ basic Vulkan driver implement करने से OGL 4.6 support मुफ्त में नहीं मिल जाता, और Mesa से OGL 4.6 को Vulkan में translate करवाने के लिए Vulkan driver में OGL 4.6 features सारे implement करने होंगे
इसके अलावा Alyssa reverse engineering और OpenGL driver projects पहले कर चुकी हैं
पूरी परिस्थितियाँ नहीं जानता, लेकिन familiar API के लिए driver बनाना unfamiliar API के driver से कहीं आसान और तेज होने की संभावना है
वहाँ से नए OpenGL तक ले जाना शायद पूर्ण Vulkan implementation से कम काम रहा होगा, और Vulkan के लिए जरूरी चीजें भी काफी सीखी होंगी
इसलिए लगता है कि जल्दी कुछ working पाने के लिए पहले lower-version OpenGL को चुना गया
अगर 90 के दशक में John Carmack ने Quake II में OpenGL इस्तेमाल करने पर इतना ज़ोर न दिया होता, तो 3D गेम्स में OpenGL की मौजूदगी शायद बन ही न पाती—यह सोचकर काफ़ी हैरानी होती है
OpenGL को आखिरकार उस रूप में ढालने का श्रेय SGI और कई सिस्टम्स व आर्किटेक्चर्स पर compatible implementations बनाने की विशाल कोशिश को जाता है
https://web.archive.org/web/19970707113513/http://www.opengl.org/
3D games से जुड़ी बहुत-सी चीज़ों का श्रेय Doom और Quake को जाता है
उनके मुताबिक Microsoft में API सुधारने के लिए बड़े incompatible changes करते रहने की हिम्मत थी, जबकि compatibility की चिंताओं ने OpenGL को पीछे रोक रखा था
उन्होंने कहा कि Direct3D multithreading को बेहतर संभालता है, और नए versions में state management भी बेहतर है
फिर भी उन्होंने कहा कि id Software inertia की वजह से OpenGL पर ही बना हुआ है, और फायदों के बावजूद Direct3D पर जाने की कोई योजना नहीं है
स्रोत: https://www.bit-tech.net/news/gaming/pc/carmack-directx-better-opengl/1/