เพิ่มประสิทธิภาพโดยลดความแม่นยำ

รูปแบบตัวเลขของข้อมูลกราฟิกและการคำนวณตัวปรับแสงเงาอาจมี ผลกระทบที่สำคัญต่อประสิทธิภาพของเกม

รูปแบบที่เหมาะสมที่สุดมีดังต่อไปนี้

  • เพิ่มประสิทธิภาพการใช้แคช GPU
  • ลดการใช้แบนด์วิดท์ของหน่วยความจำ ประหยัดพลังงาน และเพิ่มประสิทธิภาพ
  • เพิ่มอัตราการส่งข้อมูลในการประมวลผลสูงสุดในโปรแกรม Shadter
  • ลดการใช้ RAM ของ CPU ในเกม

รูปแบบจุดทศนิยม

การคำนวณและข้อมูลส่วนใหญ่ในกราฟิก 3 มิติสมัยใหม่จะใช้จุดทศนิยม ตัวเลข Vulkan ใน Android ใช้จำนวนทศนิยมที่มีค่า 32 หรือ ขนาด 16 บิต โดยทั่วไป จำนวนทศนิยม 32 บิตเรียกว่า ความแม่นยำเดียวหรือความแม่นยำเต็มรูปแบบ ทศนิยม 16 บิต ได้แม่นยำ

Vulkan กำหนดประเภทจุดลอยตัว 64 บิต แต่ไม่ใช่ประเภทดังกล่าวโดยทั่วไป รองรับโดยอุปกรณ์ Vulkan ใน Android และไม่แนะนำให้ใช้ 64 บิต โดยทั่วไป จำนวนทศนิยมหมายถึงความแม่นยำสองเท่า

รูปแบบจำนวนเต็ม

ระบบใช้ตัวเลขจำนวนเต็มที่ลงชื่อและไม่ลงนามสำหรับข้อมูลและการคำนวณด้วย ขนาดจำนวนเต็มมาตรฐานคือ 32 บิต การรองรับบิตขนาดอื่นๆ คืออุปกรณ์ ที่ต้องพึ่งพา อุปกรณ์ Vulkan ที่ใช้ Android โดยทั่วไปจะรองรับ 16 บิตและ 8 บิต จำนวนเต็ม Vulkan กำหนดประเภทจำนวนเต็ม 64 บิต แต่ไม่ใช่ประเภททั่วไป รองรับโดยอุปกรณ์ Vulkan ใน Android และไม่แนะนำให้ใช้

ลักษณะการทำงานของความแม่นยําที่ต่ำกว่ามาตรฐาน

สถาปัตยกรรม GPU สมัยใหม่จะรวมค่า 16 บิต 2 ค่าเข้าด้วยกันในคู่แบบ 32 บิตและ ใช้คำแนะนำที่ใช้กับการจับคู่ เพื่อประสิทธิภาพสูงสุด โปรดหลีกเลี่ยง โดยใช้ตัวแปรจำนวนลอยตัว 16 บิตแบบสเกลาร์ เวกเตอร์ข้อมูลเป็นองค์ประกอบ 2 หรือ 4 องค์ประกอบ เวกเตอร์ คอมไพเลอร์ตัวปรับแสงเงาอาจใช้ค่าสเกลาร์ในเวกเตอร์ได้ การดำเนินงาน อย่างไรก็ตาม หากคุณอาศัยคอมไพเลอร์เพื่อเพิ่มประสิทธิภาพสเกลาร์ ให้ตรวจสอบ เอาต์พุตของคอมไพเลอร์เพื่อยืนยันเวกเตอร์

การแปลงเป็นและจากจุดทศนิยมแบบ 32 บิตและ 16 บิต&#ndash;มี สำหรับต้นทุนการคำนวณนี้ ลดค่าใช้จ่ายโดยลดความแม่นยำใน Conversion โค้ด

ความแตกต่างของประสิทธิภาพเมื่อเปรียบเทียบระหว่างเวอร์ชัน 16 บิตและ 32 บิต อัลกอริทึม ความแม่นยําเพียงครึ่งเดียวไม่ได้ทําให้ประสิทธิภาพดีขึ้นเสมอไป โดยเฉพาะการคำนวณที่ซับซ้อน อัลกอริทึมที่ผสมวิธีการรวมเข้าด้วยกัน วิธีการคูณเพิ่ม (FMA) เกี่ยวกับข้อมูลเวกเตอร์เป็นตัวเลือกที่ดี ประสิทธิภาพดีขึ้นโดยมีความแม่นยำครึ่งหนึ่ง

การสนับสนุนรูปแบบตัวเลข

อุปกรณ์ Vulkan ทั้งหมดบน Android รองรับจุดลอยตัว 32 บิตที่มีความแม่นยำสูง และจำนวนเต็ม 32 บิตในการคำนวณข้อมูลและเครื่องมือเฉดสี การสนับสนุนสำหรับ รูปแบบอื่นๆ นั้นไม่รับประกันว่าจะพร้อมใช้งาน และหากมี ก็ไม่รับประกัน สำหรับ Use Case ทั้งหมด

Vulkan มีการสนับสนุน 2 หมวดหมู่สำหรับรูปแบบตัวเลขที่ไม่บังคับ ได้แก่ เลขคณิต และพื้นที่เก็บข้อมูล ก่อนใช้รูปแบบที่เจาะจง ให้ตรวจสอบว่าอุปกรณ์รองรับรูปแบบดังกล่าวทั้ง 2 รูปแบบ หมวดหมู่ต่างๆ

การรองรับเลขคณิต

อุปกรณ์ Vulkan ต้องประกาศการรองรับเลขคณิตสำหรับรูปแบบตัวเลขเพื่อให้ สามารถใช้ในโปรแกรม เฉดสีต่างๆ ได้ อุปกรณ์ Vulkan บน Android โดยทั่วไปจะรองรับ รูปแบบต่อไปนี้สำหรับการคำนวณ

  • จำนวนเต็ม 32 บิต (บังคับ)
  • จุดลอยตัว 32 บิต (บังคับ)
  • จำนวนเต็ม 8 บิต (ไม่บังคับ)
  • จำนวนเต็ม 16 บิต (ไม่บังคับ)
  • จุดลอยตัวแบบครึ่งความแม่นยำ 16 บิต (ไม่บังคับ)

หากต้องการตรวจสอบว่าอุปกรณ์ Vulkan รองรับจำนวนเต็ม 16 บิตสำหรับเลขคณิตหรือไม่ เรียกฟีเจอร์ของอุปกรณ์โดยการเรียกใช้ vkGetPhysicalDeviceFeatures2() และตรวจสอบว่า ช่อง shaderInt16 ใน VkPhysicalDeviceFeatures2 ของโครงสร้างผลลัพธ์เป็นจริง

วิธีพิจารณาว่าอุปกรณ์ Vulkan รองรับทศนิยม 16 บิตหรือจำนวนเต็ม 8 บิตหรือไม่ ให้ทำตามขั้นตอนต่อไปนี้

  1. ตรวจสอบว่าอุปกรณ์รองรับ VK_KHR_shader_float16_int8 ส่วนขยาย Vulkan ส่วนขยายคือ จำเป็นสำหรับการรองรับจำนวนลอยตัว 16 บิตและจำนวนเต็ม 8 บิต
  2. หากระบบรองรับ VK_KHR_shader_float16_int8 ให้เพิ่ม ตัวชี้โครงสร้าง VkPhysicalDeviceShaderFloat16Int8Features เป็นเชน VkPhysicalDeviceFeatures2.pNext
  3. ตรวจสอบช่อง shaderFloat16 และ shaderInt8 ของ โครงสร้างผลลัพธ์ VkPhysicalDeviceShaderFloat16Int8Features รายการหลังจากการโทร vkGetPhysicalDeviceFeatures2() หากค่าในช่องคือ true รูปแบบจะเป็น สนับสนุนสำหรับคณิตศาสตร์ของโปรแกรม Shadter

แม้ว่าจะไม่ใช่ข้อกำหนดใน Vulkan 1.1 หรือปี 2022 โปรไฟล์ Android Baseline ที่รองรับ VK_KHR_shader_float16_int8 พบได้บ่อยมากในอุปกรณ์ Android

การรองรับพื้นที่เก็บข้อมูล

อุปกรณ์ Vulkan ต้องประกาศการรองรับรูปแบบตัวเลขที่ไม่บังคับสำหรับ พื้นที่เก็บข้อมูลบางประเภท ส่วนขยาย VK_KHR_16bit_storage ประกาศว่ารองรับจำนวนเต็ม 16 บิตและรูปแบบจุดลอยตัว 16 บิต 4 อย่าง ส่วนขยายกำหนดประเภทพื้นที่เก็บข้อมูล อุปกรณ์รองรับหมายเลข 16 บิตได้ สำหรับพื้นที่เก็บข้อมูล ไม่มี บางรายการ หรือทุกประเภท

ประเภทพื้นที่เก็บข้อมูลมีดังนี้

  • ออบเจ็กต์บัฟเฟอร์พื้นที่เก็บข้อมูล
  • วัตถุบัฟเฟอร์แบบเดียวกัน
  • พุชบล็อกคงที่
  • อินเทอร์เฟซอินพุตและเอาต์พุตเฉดสี

อุปกรณ์ Vulkan 1.1 ส่วนใหญ่ใน Android (แต่ไม่ใช่ทั้งหมด) รองรับรูปแบบ 16 บิตใน ออบเจ็กต์บัฟเฟอร์พื้นที่เก็บข้อมูล อย่าคิดเรื่องการรองรับตามโมเดล GPU อุปกรณ์ ไดรเวอร์รุ่นเก่าสำหรับ GPU ที่ระบุอาจไม่รองรับออบเจ็กต์บัฟเฟอร์ของพื้นที่เก็บข้อมูล ในขณะที่อุปกรณ์ที่มีไดรเวอร์รุ่นใหม่กว่า

รองรับรูปแบบ 16 บิตในบัฟเฟอร์ที่สม่ำเสมอ พุชบล็อกแบบคงที่ และตัวปรับแสงเงา โดยทั่วไปอินเทอร์เฟซอินพุต/เอาต์พุตจะขึ้นอยู่กับผู้ผลิต GPU เปิด Android ปกติแล้ว GPU จะรองรับทั้ง 3 ประเภทนี้หรือไม่รองรับ ให้พวกเขา

ฟังก์ชันตัวอย่างที่ทดสอบการสนับสนุนรูปแบบคณิตและรูปแบบพื้นที่เก็บข้อมูล 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

ประเภทข้อมูลที่ไม่แนะนำสำหรับการแสดงในแบบลอยที่มีความแม่นยำครึ่งหนึ่ง รวมข้อมูลต่อไปนี้

  • ตำแหน่งของข้อมูลในพิกัดโลก
  • UV พื้นผิวสำหรับกรณีการใช้งานที่มีความแม่นยำสูง เช่น พิกัดองค์ประกอบ UI ใน แผ่นแผนที่

ความแม่นยำของโค้ดตัวปรับแสงเงา

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 จะระบุจุดลอยตัวที่มีความแม่นยําครึ่งหนึ่ง คีย์เวิร์ด จำนวนเต็ม 16 บิตที่มีลายเซ็นและไม่มีการรับรองจะระบุโดย int16_t และ uint16_t คีย์เวิร์ดตามลำดับ ตัวอย่างเพิ่มเติมเกี่ยวกับความแม่นยำที่ชัดเจน รวมทั้งสิ่งต่อไปนี้

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