هنا سوف أنشر ترجمة دليل Vulkan API. رابط المصدر - vulkan-tutorial.com . نظرًا لأن مستخدمًا آخر في Habr ، kiwhy (https://habr.com/ru/users/kiwhy/) ، يشارك في ترجمة نفس الدليل ، فقد اتفقنا على
مشاركة الدروس فيما بيننا. سأقدم في منشوراتي روابط إلى فصول تمت ترجمتها بواسطة kiwhy.
المحتوى
1 المقدمة
انظر مقال المؤلف kiwhy - habr.com/ru/post/462137
2. نظرة عامة
خلفية فولكان
كيفية رسم مثلث؟
- الخطوة 1 - المثيل والأجهزة المادية
- الخطوة 2 - وحدة المنطق وعائلات قائمة الانتظار
- الخطوة 3 - سطح النافذة وسلاسل التبادل
- الخطوة 4 - طرق عرض الصور و frameebuffers
- الخطوة 5 - تقديم التمريرات
- الخطوة 6 - خط أنابيب الرسومات
- الخطوة 7 - تجمع الأوامر ومخازن الأوامر
- الخطوة 8 - الحلقة الرئيسية
- الاستنتاجات
مفاهيم API
في هذا الفصل ، سنبدأ مع Vulkan ونرى المشكلات التي يمكنه حلها. سنصف الخطوات المطلوبة لإنشاء مثلثك الأول. سيعطيك هذا نظرة عامة على المعيار ويسمح لك بفهم المنطق وراء تخطيط الفصول اللاحقة. نختتم بإلقاء نظرة على بنية Vulkan API وحالات الاستخدام النموذجية.
المتطلبات الأساسية لـ Vulkan
مثل واجهات برمجة التطبيقات الرسومية السابقة ، تم تصميم Vulkan على أنه تجريد عبر الأنظمة الأساسية عبر وحدة معالجة الرسومات . تكمن المشكلة الرئيسية في معظم واجهات برمجة التطبيقات هذه في أنها استخدمت أثناء تطويرها أجهزة رسومات اقتصرت على الوظائف الثابتة. كان على المطورين توفير بيانات قمة الرأس بتنسيق قياسي وكانوا معتمدين تمامًا على مصنعي وحدة معالجة الرسومات للإضاءة والظلال.
مع تطور بنية بطاقات الفيديو ، بدأت تظهر المزيد والمزيد من الوظائف القابلة للبرمجة فيها. يجب دمج جميع الميزات الجديدة مع واجهات برمجة التطبيقات الحالية بطريقة ما. أدى ذلك إلى تجريدات غير كاملة والعديد من الفرضيات من جانب سائق الرسومات حول كيفية ترجمة نية المبرمج إلى بنى رسومات حديثة. لذلك ، تم إصدار عدد كبير من تحديثات برنامج التشغيل لتحسين الأداء في الألعاب. نظرًا لتعقيد هذه المحركات ، غالبًا ما تكون هناك اختلافات بين البائعين ، على سبيل المثال ، في البنية المعتمدة للتظليل... بصرف النظر عن هذا ، شهد العقد الماضي أيضًا تدفقًا للأجهزة المحمولة المزودة بأجهزة رسومات قوية. يمكن أن تختلف بنيات وحدات معالجة الرسومات المحمولة هذه اختلافًا كبيرًا اعتمادًا على متطلبات الحجم والطاقة. أحد الأمثلة على ذلك هو العرض القائم على التجانب ، والذي يمكن أن يوفر أداءً أفضل من خلال تحكم أفضل في الوظائف. هناك قيد آخر بسبب عمر واجهة برمجة التطبيقات وهو الدعم المحدود للتعدد ، مما قد يؤدي إلى اختناق على جانب وحدة المعالجة المركزية.
يساعد Vulkan في حل هذه المشكلات لأنه تم إنشاؤه من الألف إلى الياء لبنى الرسومات الحديثة. هذا يقلل من الحمل على جانب السائق من خلال السماح للمطورين بوصف أهدافهم بوضوح باستخدام واجهة برمجة تطبيقات مطولة. يسمح لك Vulkan بإنشاء وإرسال أوامر بالتوازي في سلاسل متعددة. كما أنه يقلل من اختلافات التجميع بين التظليل عن طريق الانتقال إلى تنسيق رمز ثنائي موحد واستخدام مترجم واحد. أخيرًا ، يجمع Vulkan القدرات الأساسية لبطاقات الرسومات الحالية معًا من خلال دمج إمكانات الرسومات والحوسبة في واجهة برمجة تطبيقات واحدة.
كيف ارسم مثلث؟
سنلقي نظرة سريعة على الخطوات المطلوبة لرسم مثلث. سيعطيك هذا لمحة عامة عن العملية. سيتم إعطاء وصف مفصل لكل مفهوم في الفصول التالية.
الخطوة 1 - المثيلات والأجهزة المادية التي
تعمل مع Vulkan يبدأ بتكوين Vulkan API من خلال VkInstance . يتم إنشاء مثيل باستخدام وصف البرنامج وأي ملحقات تريد استخدامها. بعد إنشاء مثيل ، يمكنك الاستعلام عن الأجهزة التي يدعمها Vulkan وتحديد واحد أو أكثر من أجهزة VkPhysicalDevices لإجراء العمليات. يمكنك الاستفسار عن معلمات مثل حجم VRAM وإمكانيات الجهاز لتحديد الأجهزة التي تريدها إذا كنت تفضل استخدام بطاقات رسومات متخصصة.
الخطوة 2 - Logic Device و Queue Families
بعد تحديد الجهاز المناسب لاستخدامه ، تحتاج إلى إنشاء VkDevice (جهاز منطقي) ، حيث ستصف بمزيد من التفصيل الميزات ( VkPhysicalDeviceFeatures ) التي ستستخدمها ، على سبيل المثال ، التقديم إلى منافذ عرض متعددة. s (عرض منفذ عرض متعدد) وعوامات 64 بت. تحتاج أيضًا إلى تحديد عائلات قائمة الانتظار التي ترغب في استخدامها. يتم تنفيذ العديد من العمليات التي تتم باستخدام Vulkan ، مثل أوامر الرسم والعمليات داخل الذاكرة ، بشكل غير متزامن بعد إرسالها إلى VkQueue... يتم تخصيص قوائم الانتظار من عائلة قوائم الانتظار ، حيث تدعم كل عائلة مجموعة محددة من العمليات. على سبيل المثال ، قد توجد مجموعات منفصلة من قوائم الانتظار لعمليات الرسومات وعمليات الحساب وعمليات نقل بيانات الذاكرة. بالإضافة إلى ذلك ، يمكن استخدام توفرها كمعامل رئيسي عند اختيار جهاز مادي. لا تقدم بعض الأجهزة التي تدعم Vulkan أي إمكانات رسومات ، ومع ذلك ، تدعم جميع بطاقات الرسومات الحديثة التي تدعم Vulkan بشكل عام جميع عمليات قائمة الانتظار التي نحتاجها.
الخطوة 3 - سطح النافذة وسلاسل التبديل
إذا كنت مهتمًا بأكثر من مجرد عرض خارج الشاشة ، فأنت بحاجة إلى إنشاء نافذة لعرض الصور المعروضة. يمكن إنشاء Windows باستخدام واجهات برمجة تطبيقات النظام الأساسي الأصلي أو المكتبات مثل GLFW و SDL . سنستخدم GLFW في هذا البرنامج التعليمي ، والذي سنقوم بتغطيته بمزيد من التفاصيل في الفصل التالي.
نحتاج إلى مكونين آخرين لعرضهما في نافذة التطبيق: سطح النافذة (
VkSurfaceKHR) وسلسلة العرض ( VkSwapchainKHR). انتبه إلى postfixKHRمما يدل على أن هذه الكائنات هي جزء من امتداد Vulkan. تعد Vulkan API مستقلة تمامًا عن النظام الأساسي ، لذلك نحتاج إلى استخدام الامتداد القياسي WSI (واجهة نظام النافذة) للتفاعل مع مدير النوافذ. Surface عبارة عن نافذة تجريدية عبر الأنظمة الأساسية للعرض ، والتي يتم إنشاؤها عادةً عن طريق الرجوع إلى مقبض نافذة أصلي ، على سبيل المثال HWNDفي Windows. لحسن الحظ ، تحتوي مكتبة GLFW على وظيفة مضمنة للعمل مع التفاصيل الخاصة بالنظام الأساسي.
سلسلة العرض هي مجموعة من أهداف العرض. وتتمثل مهمتها في التأكد من أن الصورة التي يتم تقديمها حاليًا تختلف عن الصورة المعروضة على الشاشة. هذا يسمح لك بتتبع تلك الصور المعروضة فقط. في كل مرة نحتاج فيها إلى إنشاء إطار ، يتعين علينا تقديم طلب لسلسلة العرض لتزويدنا بصورة لعرضها. بعد إنشاء الإطار ، تُعاد الصورة إلى سلسلة العرض لتُعرض على الشاشة في مرحلة ما. يعتمد عدد أهداف التجسيد وشروط عرض الصور النهائية على الشاشة على الوضع الحالي. تتضمن هذه الأوضاع التخزين المؤقت المزدوج (vsync) والتخزين المؤقت الثلاثي. سنقوم بتغطيتها في الفصل الخاص بإنشاء سلسلة عرض.
بعض منصات تتيح تقديم مباشرة إلى الشاشة عبر ملحقات
VK_KHR_displayو VK_KHR_display_swapchainدون التفاعل مع أي مدير النافذة. يتيح لك ذلك إنشاء سطح يمثل الشاشة بأكملها ويمكن استخدامه ، على سبيل المثال ، لتنفيذ مدير النوافذ الخاص بك.
الخطوة 4 - طرق عرض الصور و frameebuffer من
أجل الرسم في الصورة التي تم الحصول عليها من سلسلة العرض ، علينا أن نلفها في VkImageView و VkFramebuffer . يشير عرض الصورة إلى جزء معين من الصورة المستخدمة ، ويشير الإطار المؤقت إلى عروض الصور ، والتي تُستخدم كمخازن مؤقتة للون والعمق والاستنسل. نظرًا لأنه يمكن أن يكون هناك العديد من الصور المختلفة في سلسلة العرض ، فسننشئ عرضًا للصورة ومخزنًا مؤقتًا للإطار لكل منهما مقدمًا ونختار الصورة المطلوبة أثناء الرسم.
الخطوة 5 -
تصيير التصيير تصف تصاريح التجسيد الخاصة بـ Vulkan نوع الصور المستخدمة أثناء عمليات التجسيد ، وكيفية استخدامها ، وكيفية التعامل مع محتواها. قبل رسم المثلث ، سنخبر فولكان بأننا نريد استخدام صورة واحدة كمخزن ألوان وأننا بحاجة إلى مسحها قبل الرسم. إذا كان ممر العرض يصف فقط نوع الصور المستخدمة كمخازن مؤقتة ، فإن VkFramebuffer يربط فعليًا صورًا معينة بتلك الفتحات.
الخطوة 6 - خط أنابيب
الرسومات يتم تكوين خط أنابيب الرسومات في Vulkan عن طريق إنشاء كائن VkPipeline . يصف الحالة القابلة للتكوين لبطاقة الفيديو ، مثل حجم منفذ العرض أو تشغيل المخزن المؤقت العميق ، بالإضافة إلى الحالة القابلة للبرمجة باستخدام كائنات VkShaderModule . يتم إنشاء كائنات VkShaderModule من shader bytecode . يحتاج السائق أيضًا إلى تحديد أهداف العرض التي سيتم استخدامها في خط الأنابيب. قمنا بتعيينهم من خلال الرجوع إلى تصريح التصيير.
تتمثل إحدى الميزات الأكثر تميزًا لـ Vulkan على واجهات برمجة التطبيقات الحالية في أنه يجب تكوين جميع إعدادات خط أنابيب رسومات النظام تقريبًا مسبقًا. هذا يعني أنك إذا كنت تريد التبديل إلى تظليل مختلف أو تغيير تخطيط الرأس قليلاً ، فأنت بحاجة إلى إعادة إنشاء خط أنابيب الرسومات بالكامل. لذلك ، سيتعين عليك إنشاء الكثير من كائنات VkPipeline مسبقًا لجميع المجموعات المطلوبة لعمليات العرض. يمكن فقط تغيير بعض الإعدادات الأساسية ديناميكيًا ، مثل حجم منفذ العرض واللون الواضح. يجب وصف جميع الدول بشكل صريح. لذلك ، على سبيل المثال ، لا توجد حالة مزج ألوان افتراضية.
لحسن الحظ ، نظرًا لأن العملية تشبه إلى حد كبير التجميع ، فبدلاً من التجميع السريع ، يتمتع السائق بمزيد من فرص التحسين ويكون الأداء أكثر قابلية للتنبؤ لأن التغييرات المهمة في الحالة ، مثل التبديل إلى خط أنابيب رسومات مختلف ، محددة بشكل صريح.
الخطوة 7 - تجمع الأوامر ومخازن الأوامر
كما ذكرنا ، يجب وضع العديد من العمليات في Vulkan ، مثل عمليات الرسم في قائمة الانتظار. قبل إرسال العمليات ، يجب كتابتها إلى VkCommandBuffer . تأتي المخازن المؤقتة للأوامر من VkCommandPool ، المرتبطة بعائلة قائمة انتظار معينة. لرسم مثلث بسيط ، نحتاج إلى كتابة مخزن أوامر بالعمليات التالية:
- ابدأ تصيير تمرير
- ربط خط أنابيب الرسومات
- ارسم 3 رؤوس
- نهاية تصيير تمرير
نظرًا لأن مثيل الصورة في الإطارات المؤقتة تعتمد على الصورة التي ستعطيناها سلسلة العرض ، نحتاج إلى كتابة مخزن أوامر لكل صورة ممكنة وتحديد الصورة التي نحتاجها أثناء الرسم. يمكننا كتابة مخزن الأوامر في كل مرة لكل إطار ، لكن هذا أقل كفاءة.
الخطوة 8 - الحلقة الرئيسية
بعد أن أرسلنا أوامر الرسم إلى مخزن الأوامر ، تبدو الحلقة الرئيسية بسيطة بما يكفي. أولاً ، نحصل على الصورة من سلسلة العرض باستخدام
vkAcquireNextImageKHR. يمكننا بعد ذلك تحديد مخزن الأوامر المناسب لهذه الصورة وتشغيلها باستخدام vkQueueSubmit . أخيرًا ، نعيد الصورة إلى سلسلة العرض لعرضها باستخدام vkQueuePresentKHR.
يتم تنفيذ العمليات المرسلة إلى قائمة الانتظار بشكل غير متزامن. لذلك ، يجب علينا استخدام كائنات التزامن - الإشارات - لضمان ترتيب بدء التشغيل الصحيح. من الضروري تكوين تنفيذ المخزن المؤقت لأمر الرسم بطريقة لا يتم تنفيذها إلا بعد جلب الصورة من سلسلة العرض ، وإلا فقد ينشأ موقف عندما نبدأ في تقديم صورة لا تزال قيد القراءة للعرض على الشاشة. الاستدعاء
vkQueuePresentKHR، بدوره ، يجب أن ينتظر حتى يكتمل العرض ، والذي سنستخدم الإشارة الثانية له. سوف يخطر حول نهاية العرض.
الاستنتاجات
تمنحك هذه النظرة العامة السريعة نظرة عامة على العمل قبل رسم مثلثك الأول. في الواقع ، هناك العديد من الخطوات. يتضمن ذلك تخصيص مخازن مؤقتة للرأس ، وإنشاء مخازن مؤقتة موحدة ، وتحميل صور نسيج - سنغطيها جميعًا في الفصول التالية ، ولكن لنبدأ الآن ببساطة. كلما تحركنا أكثر ، زادت صعوبة المادة. لاحظ أننا قررنا السير في الطريق الصعب من خلال تضمين إحداثيات الرأس في البداية في تظليل الرأس بدلاً من استخدام المخزن المؤقت للقمة. يرجع هذا القرار إلى حقيقة أنه لإدارة المخازن المؤقتة للقمة ، عليك أولاً أن تكون على دراية بالمخازن المؤقتة للأوامر.
دعونا نلخص بإيجاز. لرسم المثلث الأول نحتاج:
- قم بإنشاء VkInstance
- حدد بطاقة فيديو مدعومة ( VkPhysicalDevice )
- قم بإنشاء VkDevice و VkQueue للرسم والعرض
- إنشاء نافذة وسطح نافذة وعرض سلسلة
- التفاف صور سلسلة العرض في VkImageView
- قم بإنشاء ممر تصيير يعرّف أهداف التصيير واستخداماتها
- إنشاء الإطارات المؤقتة لتمرير التجسيد
- تكوين خط أنابيب الرسومات
- توزيع وكتابة أوامر الرسم إلى المخزن المؤقت لكل صورة في سلسلة العرض
- اعرض الإطارات للصور المستلمة عن طريق إرسال مخزن الأوامر الصحيح وإعادة الصور إلى سلسلة العرض
على الرغم من وجود العديد من الخطوات ، إلا أن معنى كل منها سيكون واضحًا في الفصول التالية. إذا لم تتمكن من اكتشاف خطوة ، فارجع إلى هذا الفصل.
مفاهيم API
سيختتم هذا الفصل بنظرة عامة موجزة حول كيفية هيكلة Vulkan APIs على مستوى أدنى.
معيار الترميز يتم تصنيف
جميع وظائف وتعدادات وهياكل Vulkan تحت عنوان
vulkan.hمضمن في Vulkan SDK التي طورتها LunarG. سيتم تناول تثبيت SDK في الفصل التالي.
تُسبَق الدوال
vkبأحرف صغيرة ، وأنواع مُعدَّدة (تعداد) وتُسبَق الهياكل Vk، وتُسبَق القيم التي تم تعدادها VK_. يستخدم API على نطاق واسع الهياكل لتوفير معلمات للوظائف. على سبيل المثال ، عادةً ما يتم إنشاء الكائنات وفقًا للنمط التالي:
تتطلب العديد من الهياكل في Vulkan تحديد نوع البنية بشكل صريح في العضو
sType. pNextيمكن للعضو أن يشير إلى هيكل ملحق وسيكون دائمًا من النوعnullptr... ستحتوي الوظائف التي تنشئ كائنًا أو تدمره على معلمة VkAllocationCallbacks تتيح لك استخدام مخصص الذاكرة الخاص بك والذي سيكون أيضًا من النوع في البرنامج التعليمي nullptr.
تقوم جميع الوظائف تقريبًا بإرجاع VkResult ، وهو
VK_SUCCESSإما رمز خطأ. تحدد المواصفات رموز الخطأ التي يمكن لكل دالة إرجاعها وما تعنيه.
طبقات التحقق من الصحة
كما ذكرنا ، تم تصميم Vulkan لتوفير أداء عالي مع أحمال منخفضة للسائق. لذلك ، فهو يتضمن قدرات محدودة للغاية للكشف التلقائي عن الأخطاء وتصحيحها إذا قمت بخطأ ما ، فسوف يتعطل برنامج التشغيل أو ما هو أسوأ ، يستمر في العمل على بطاقة الرسومات الخاصة بك ، لكنه يفشل في بطاقات الرسومات الأخرى.
لذلك يسمح لك Vulkan بتشغيل عمليات تحقق متقدمة باستخدام ميزة تعرف باسم طبقات التحقق من الصحة... طبقات التحقق من الصحة هي أجزاء من التعليمات البرمجية التي يمكن إدراجها بين API وبرنامج تشغيل الرسومات لإجراء تحقق إضافي على معلمات الوظيفة وتتبع مشكلات إدارة الذاكرة. هذا مناسب لأنه يمكنك بدء تشغيلهم أثناء التطوير ثم تعطيلهم تمامًا عند بدء البرنامج دون أي تكلفة إضافية. يمكن لأي شخص كتابة طبقات التحقق الخاصة به ، لكن Vulkan SDK من LunarG توفر مجموعة قياسية سنستخدمها خلال البرنامج التعليمي. تحتاج أيضًا إلى تسجيل وظيفة رد اتصال لتلقي رسائل تصحيح الأخطاء من الطبقات.
نظرًا لأن العمليات في Vulkan مفصلة للغاية ، وطبقات التحقق من الصحة واسعة جدًا ، فسيكون من الأسهل عليك تحديد سبب الشاشة السوداء مقارنةً بـ OpenGL و Direct3D.
لم يتبق سوى خطوة واحدة قبل أن نبدأ في البرمجة ، وهي إعداد بيئة التطوير.