التحسين بدقة مخفّضة

يمكن أن يكون للتنسيق الرقمي لبيانات الرسومات والعمليات الحسابية للتظليل تأثير كبير في أداء لعبتك

في ما يلي التنسيقات المثلى:

  • زيادة كفاءة استخدام ذاكرة التخزين المؤقت لوحدة GPU
  • تقليل استهلاك معدل نقل البيانات للذاكرة وتوفير الطاقة وتحسين الأداء
  • زيادة سرعة معالجة البيانات الحاسوبية في برامج التظليل
  • تقليل استخدام ذاكرة الوصول العشوائي (RAM) لوحدة المعالجة المركزية في لعبتك

تنسيقات النقاط العائمة

معظم العمليات الحسابية والبيانات في الرسومات الثلاثية الأبعاد الحديثة تستخدم النقطة العائمة الأرقام. يستخدم Vulkan على Android أرقام النقاط العائمة التي تبلغ 32 أو بحجم 16 بت. يُشار عادةً إلى رقم النقطة العائمة 32 بت دقة واحدة أو دقة كاملة؛ رقم نقطة عائمة 16 بت، نصف والدقة.

يحدد Vulkan نوع النقطة العائمة 64 بت، لكن هذا النوع ليس شائعًا متوافقة مع أجهزة Vulkan على Android، ولا يُنصح باستخدامها. 64 بت ويُشار عادةً إلى رقم النقطة العائمة باسم "الدقة المزدوجة".

تنسيقات الأعداد الصحيحة

تُستخدم الأعداد الصحيحة الموقّعة وغير الموقَّعة أيضًا للبيانات والحسابات. تشير رسالة الأشكال البيانية حجم العدد الصحيح القياسي هو 32 بت. دعم أحجام البت الأخرى هو الجهاز يعتمد بشكل كبير. عادةً ما تدعم أجهزة Vulkan التي تعمل بنظام التشغيل Android 16 بت و8 بت. الأعداد الصحيحة. يحدد Vulkan نوع عدد صحيح 64 بت، لكن النوع ليس عادةً متوافقة مع أجهزة Vulkan على Android، ولا يُنصح باستخدامها.

سلوك دون المستوى المثالي

تجمع بُنى وحدة معالجة الرسومات الحديثة بين قيمتين 16 بت معًا في زوج 32 بت وتنفيذ التعليمات التي تعمل على الزوج. للحصول على الأداء الأمثل، تجنب باستخدام متغيرات عائمة عدد 16 بت؛ توجيه البيانات إلى عنصرين أو أربعة عناصر المتجهات. قد يتمكن المحول البرمجي للتظليل من استخدام القيم العددية في المتجه العمليات التجارية. ومع ذلك، إذا كنت تعتمد على المحول البرمجي لتحسين الكميات القياسية، مخرج برنامج التجميع للتحقق من المتجه.

فعند التحويل من وإلى النقطة العائمة بدقة 32 بت و16 بت التكلفة الحاسوبية. يمكنك خفض النفقات العامة من خلال تقليل الإحالات الناجحة الدقيقة في الرمز.

مقارنة الاختلافات في الأداء بين الإصدار 16 بت و32 بت من الخوارزميات. لا يؤدي نصف الدقة دائمًا إلى تحسين الأداء، خاصة في العمليات الحسابية المعقدة. يشير هذا المصطلح إلى الخوارزميات التي تستخدم الأجهزة المدمجة بشكل مكثّف. تعد إرشادات الضرب والإضافة (FMA) على البيانات المتجهة مرشحة بشكل جيد تحسين الأداء بنصف الدقة.

إتاحة التنسيق الرقمي

جميع أجهزة Vulkan التي تعمل بنظام التشغيل Android متوافقة مع نقطة عائمة بدقة واحدة 32 بت الأرقام والأرقام الصحيحة 32 بت في العمليات الحسابية باستخدام أداة التظليل. الدعم لـ لا تكون التنسيقات الأخرى مضمونة وإذا كانت متاحة، فهي غير مضمونة لجميع حالات الاستخدام.

يحتوي Vulkan على فئتين من الدعم للتنسيقات الرقمية الاختيارية: الحسابي ومساحة التخزين. قبل استخدام تنسيق معيّن، تأكَّد من أنّ الجهاز يتيح استخدام تنسيق معيّن لكليهما. الفئات.

الدعم الحسابي

يجب أن يعلن جهاز Vulkan عن توافقه الحسابي مع تنسيق رقمي من أجل أن تكون قابلة للاستخدام في برامج التظليل. تدعم أجهزة Vulkan على Android عادةً التنسيقات التالية في الحساب:

  • عدد صحيح 32 بت (إلزامي)
  • نقطة عائمة 32 بت (إلزامية)
  • عدد صحيح 8 بت (اختياري)
  • عدد صحيح 16 بت (اختياري)
  • نقطة عائمة بنصف الدقة 16 بت (اختياري)

لتحديد ما إذا كان جهاز Vulkan يتيح الأعداد الصحيحة 16 بت للعمليات الحسابية، لاسترداد ميزات الجهاز من خلال استدعاء استخدام الدالة vkGetFinancialDeviceFeatures2() والتحقق مما إذا كان الحقل shaderInt16 في VkmaterialDeviceFeatures2 بنية النتيجة true.

لتحديد ما إذا كان جهاز Vulkan يتيح أعدادًا عائمة 16 بت أو أعداد صحيحة 8 بت، إجراء الخطوات التالية:

  1. تحقق مما إذا كان الجهاز يتوافق مع VK_KHR_shader_float16_int8 الإضافة Vulkan. الإضافة هي مطلوب لدعم الأعداد العشرية 16 بت وعددًا صحيحًا 8 بت.
  2. إذا كانت السمة VK_KHR_shader_float16_int8 متاحة، يمكنك إلحاق مؤشر بنية VkUserDeviceShaderFloat16Int8Features إلى سلسلة VkPhysicalDeviceFeatures2.pNext.
  3. راجِع الحقلين shaderFloat16 وshaderInt8 في بنية نتائج VkPhysicalDeviceShaderFloat16Int8Features بعد الطلب vkGetPhysicalDeviceFeatures2() إذا كانت قيمة الحقل هي true، يكون التنسيق هو متوافقة مع العمليات الحسابية لبرنامج Shader.

ليس شرطًا في الإصدار 1.1 من Vulkan أو إصدار العام 2022 الملف الشخصي في Android Baseline، وهو دعم لـ VK_KHR_shader_float16_int8 الإضافة هذه أمرًا شائعًا جدًا على أجهزة Android.

التوافق مع مساحة التخزين

يجب أن يعلن جهاز Vulkan عن دعمه لتنسيق رقمي اختياري أنواع تخزين محددة. الإضافة VK_KHR_16bit_storage تُعلِن عن توافق تنسيق الأعداد الصحيحة 16 بت و16 بت من النقاط العائمة. أربع قطع أنواع مساحات التخزين المحددة من خلال الإضافة. يمكن لأي جهاز دعم أرقام 16 بت. لبعض أنواع مساحات التخزين أو بعضها أو جميعها.

أنواع مساحات التخزين هي:

  • عناصر التخزين المؤقت
  • عناصر المخزن المؤقت الموحدة
  • دفع القوالب الثابتة
  • واجهات إدخال وإخراج أداة تظليل

تدعم معظم أجهزة Vulkan 1.1 على Android، وليس كلها بتنسيقات 16 بت عناصر المخزن المؤقت للتخزين. ولا تفترض الدعم حسب طراز وحدة معالجة الرسومات. الأجهزة مع برامج التشغيل القديمة لوحدة معالجة الرسومات المحددة قد لا تتوافق مع كائنات المخزن المؤقت للتخزين، بينما تقوم الأجهزة ذات السائقين الأحدث بفعل ذلك.

التوافق مع تنسيقات 16 بت في وحدات تخزين مؤقتة موحَّدة، ودفع الكتل الثابتة، وأداة التظليل تعتمد واجهات الإدخال/الإخراج بشكل عام على الشركة المصنعة لوحدة GPU. مشغَّلة فإن وحدة معالجة الرسومات في جهاز Android إما تدعم عادةً جميع هذه الأنواع الثلاثة أو لا تدعم معهم.

مثال على دالة تختبر دعم تنسيق التخزين وحساب Vulkan:

struct ReducedPrecisionSupportInfo {
  // Arithmetic support
  bool has_8_bit_int_ = false;
  bool has_16_bit_int_ = false;
  bool has_16_bit_float_ = false;
  // Storage support
  bool has_16_bit_SSBO_ = false;
  bool has_16_bit_UBO_ = false;
  bool has_16_bit_push_ = false;
  bool has_16_bit_input_output_ = false;
  // Use 16-bit floats if we have arithmetic
  // support and at least SSBO storage support.
  bool use_16bit_floats_ = false;
};

void CheckFormatSupport(VkPhysicalDevice physical_device,
    ReducedPrecisionSupportInfo &info) {

  // Retrieve the device extension list so we
  // can check for our desired extensions.
  uint32_t device_extension_count;
  vkEnumerateDeviceExtensionProperties(physical_device, nullptr,
      &device_extension_count, nullptr);
  std::vector<VkExtensionProperties> device_extensions(device_extension_count);
  vkEnumerateDeviceExtensionProperties(physical_device, nullptr,
      &device_extension_count, device_extensions.data());

  bool has_16_8_extension = HasDeviceExtension("VK_KHR_shader_float16_int8",
      device_extensions);

  // Initialize the device features structure and
  // chain the storage features structure and 8/16-bit
  // support structure if applicable.
  VkPhysicalDeviceFeatures2 device_features;
  memset(&device_features, 0, sizeof(device_features));
  device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;

  VkPhysicalDeviceShaderFloat16Int8Features f16_int8_features;
  memset(&f16_int8_features, 0, sizeof(f16_int8_features));
  f16_int8_features.sType =
      VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR;

  VkPhysicalDevice16BitStorageFeatures storage_features;
  memset(&storage_features, 0, sizeof(storage_features));
  storage_features.sType =
      VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES;
  device_features.pNext = &storage_features;

  if (has_16_8_extension) {
    storage_features.pNext = &f16_int8_features;
  }

  vkGetPhysicalDeviceFeatures2(physical_device, &device_features);

  // Parse the storage features and determine
  // what kinds of 16-bit storage access are available.
  if (storage_features.storageBuffer16BitAccess ||
      storage_features.uniformAndStorageBuffer16BitAccess) {
    info.has_16_bit_SSBO_ = true;
  }
  info.has_16_bit_UBO_ = storage_features.uniformAndStorageBuffer16BitAccess;
  info.has_16_bit_push_ = storage_features.storagePushConstant16;
  info.has_16_bit_input_output_ = storage_features.storageInputOutput16;

  info.has_16_bit_int_ = device_features.features.shaderInt16;
  if (has_16_8_extension) {
    info.has_16_bit_float_ = f16_int8_features.shaderFloat16;
    info.has_8_bit_int_ = f16_int8_features.shaderInt8;
  }

  // Get arithmetic and at least some form of storage
  // support before enabling 16-bit float usage.
  if (info.has_16_bit_float_ && info.has_16_bit_SSBO_) {
    info.use_16bit_floats_ = true;
  }
}

مستوى دقة البيانات

يمكن أن يمثل رقم النقطة العائمة بنصف الدقة نطاقًا أصغر من القيم بدقة أقل من رقم نقطة عائمة أحادية الدقة. غالبًا ما يكون نصف الدقة اختيارًا بسيطًا يخلو من فقدان البيانات على مدار دقة واحدة. ومع ذلك، قد لا يكون نصف الدقة عمليًا في جميع حالات الاستخدام. بالنسبة إلى بعض أنواع البيانات، يمكن أن يؤدي انخفاض النطاق والدقة إلى رسومات أو العرض غير الصحيح.

أنواع البيانات المرشحة جيدًا للتمثيل بنصف الدقة تشمل النقطة العائمة ما يلي:

  • تحديد موضع البيانات في إحداثيات المساحة المحلية
  • أشعة فوق بنفسجية قوية لقوام أصغر مع التفاف محدود للأشعة فوق البنفسجية يمكن نطاق إحداثي من -1.0 إلى 1.0
  • البيانات العادية والمماسية وظل التماس
  • بيانات لون Vertex
  • يشير هذا المصطلح إلى البيانات ذات متطلبات الدقة المنخفضة في التركيز على 0.0.

أنواع البيانات غير التي يُنصَح باستخدامها في بيانات عائمة بنصف الدقة تشمل:

  • تحديد مواضع البيانات في الإحداثيات العالمية العالمية
  • أشعة فوق بنفسجية قوية لحالات الاستخدام عالية الدقة مثل إحداثيات عنصر واجهة المستخدم في ورقة أطلس

الدقة في رمز أداة التظليل

تتيح لك OpenGL Shading Language (GLSL) أداة تظليل لغة Shader عالية المستوى (HLSL) تدعم لغات البرمجة مواصفات الاسترخاء الدقة أو الدقة الصريحة للأنواع الرقمية. تتم معالجة الدقة الهادئة كتوصية للمحول البرمجي للتظليل. الدقة الصريحة هي بالدقة المحددة. تستخدم أجهزة Vulkan على Android بشكل عام تنسيقات 16 بت عند اقتراحها بدقة سلسة. أجهزة Vulkan أخرى خاصة على أجهزة الكمبيوتر المكتبية التي تستخدم أجهزة الرسومات التي تفتقر إلى الدعم مع تنسيقات 16 بت، قد يتجاهل الدقة المريحة مع استمرار استخدام تنسيقات 32 بت.

إضافات التخزين في GLSL

ينبغي تحديد إضافات GLSL المناسبة لتمكين دعم 16 بت أو تنسيقات رقمية 8 بت في مساحة التخزين وبُنى مخزن مؤقت موحد. ذات الصلة تعريفات الإضافات هي:

// Enable 16-bit formats in storage and uniform buffers.
#extension GL_EXT_shader_16bit_storage : require
// Enable 8-bit formats in storage and uniform buffers.
#extension GL_EXT_shader_8bit_storage : require

هذه الإضافات خاصة بـ GLSL وليس لها ما يعادلها في HLSL.

الدقة المتساوية في GLSL

يمكنك استخدام مؤهِّل highp قبل نوع النقطة العائمة لاقتراح فاصلة عائمة أحادية الدقة ومؤهِّل mediump للتعويم بنصف الدقة. تفسّر برامج GLSL في Vulkan مؤهل lowp القديم على أنّه mediump. في ما يلي بعض الأمثلة على الدقة المبسّطة:

mediump vec4 my_vector; // Suggest 16-bit half precision
highp mat4 my_matrix;   // Suggest 32-bit single precision

الدقة الصريحة في GLSL

تضمين الإضافة GL_EXT_shader_explicit_arithmetic_types_float16 في رمز GLSL لتفعيل استخدام أنواع النقاط العائمة 16 بت:

#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require

تعريف أنواع النقطة العائمة والمتجهات والمصفوفة ذات الإصدار 16 بت في GLSL باستخدام الكلمات الرئيسية التالية:

float16_t   f16vec2     f16vec3    f16vec4
f16mat2     f16mat3     f16mat4
f16mat2x2   f16mat2x3   f16mat2x4
f16mat3x2   f16mat3x3   f16mat3x4
f16mat4x2   f16mat4x3   f16mat4x4

يمكنك تعريف الأنواع العددية والمتجهات التي تضم عددًا صحيحًا 16 بت في GLSL باستخدام ما يلي: الكلمات الرئيسية:

int16_t     i16vec2     i16vec3    i16vec4
uint16_t    u16vec2     u16vec3    u16vec4

الدقة المتساوية في بروتوكول HLSL

يستخدم HLSL مصطلح الدقة الأدنى بدلاً من الدقة المريحة. الحد الأدنى الكلمة الرئيسية من نوع الدقة تحدد الحد الأدنى من الدقة، ولكن يمكن لبرنامج التحويل البرمجي أن تستبدل الدقة الأعلى إذا كانت الدقة الأعلى خيارًا أفضل الأجهزة المستهدفة. ويتم تحديد الحد الأدنى للدقة العائمة 16 بت من خلال كلمة رئيسية واحدة (min16float). يتم التعامل مع الأعداد الصحيحة 16 بت التي لا تحمل توقيعًا بالدقة الأدنى أو لا المحددان من خلال الكلمتين الرئيسيتين min16int وmin16uint على التوالي. معلومات إضافية وتشمل أمثلة بيانات الدقة الأدنى ما يلي:

// Four element vector and four-by-four matrix types
min16float4 my_vector4;
min16float4x4 my_matrix4x4;

الدقة الصريحة في بروتوكول HLSL

يتم تحديد النقطة العائمة نصف الدقيقة من خلال half أو float16_t. كلماتك الرئيسية. تحدد السمة int16_t الأعداد الصحيحة 16 بت الموقَّعة وغير الموقَّعة. وuint16_t كلمة رئيسية على التوالي. أمثلة إضافية للدقة الصريحة تتضمن التصريحات ما يلي:

// Four element vector and four-by-four matrix types
half4 my_vector4;
half4x4 my_matrix4x4;