কম নির্ভুলতার সাথে অপ্টিমাইজ করুন

গ্রাফিক্স ডেটা এবং শেডার গণনার সংখ্যাসূচক বিন্যাস আপনার গেমের কার্যক্ষমতার উপর উল্লেখযোগ্য প্রভাব ফেলতে পারে।

সর্বোত্তম ফর্ম্যাটগুলি নিম্নলিখিতগুলি করে:

  • GPU ক্যাশে ব্যবহারের দক্ষতা বাড়ান
  • মেমরি ব্যান্ডউইথ খরচ, শক্তি সঞ্চয় এবং কর্মক্ষমতা বৃদ্ধি হ্রাস
  • শেডার প্রোগ্রামে গণনামূলক থ্রুপুট সর্বাধিক করুন
  • আপনার গেমের CPU RAM ব্যবহার কম করুন

ফ্লোটিং পয়েন্ট ফরম্যাট

আধুনিক 3D গ্রাফিক্সের বেশিরভাগ গণনা এবং ডেটা ফ্লোটিং পয়েন্ট সংখ্যা ব্যবহার করে। অ্যান্ড্রয়েডে ভলকান 32 বা 16 বিট আকারের ফ্লোটিং পয়েন্ট নম্বর ব্যবহার করে। একটি 32-বিট ফ্লোটিং পয়েন্ট সংখ্যাকে সাধারণত একক নির্ভুলতা বা সম্পূর্ণ নির্ভুলতা হিসাবে উল্লেখ করা হয়; একটি 16-বিট ফ্লোটিং পয়েন্ট সংখ্যা, অর্ধেক নির্ভুলতা।

Vulkan একটি 64-বিট ফ্লোটিং পয়েন্ট টাইপ সংজ্ঞায়িত করে, কিন্তু টাইপটি সাধারণত Android-এ Vulkan ডিভাইসগুলির দ্বারা সমর্থিত নয় এবং এটির ব্যবহার সুপারিশ করা হয় না৷ একটি 64-বিট ফ্লোটিং পয়েন্ট সংখ্যাকে সাধারণত ডবল নির্ভুলতা হিসাবে উল্লেখ করা হয়।

পূর্ণসংখ্যা বিন্যাস

স্বাক্ষরিত এবং স্বাক্ষরবিহীন পূর্ণসংখ্যাগুলিও ডেটা এবং গণনার জন্য ব্যবহৃত হয়। আদর্শ পূর্ণসংখ্যার আকার হল 32 বিট। অন্যান্য বিট মাপের জন্য সমর্থন ডিভাইস নির্ভর। অ্যান্ড্রয়েড চালিত ভলকান ডিভাইসগুলি সাধারণত 16-বিট এবং 8-বিট পূর্ণসংখ্যা সমর্থন করে। Vulkan একটি 64-বিট পূর্ণসংখ্যার ধরনকে সংজ্ঞায়িত করে, কিন্তু টাইপটি সাধারণত Android-এ Vulkan ডিভাইস দ্বারা সমর্থিত নয় এবং এটির ব্যবহার সুপারিশ করা হয় না।

সাবঅপ্টিমাল অর্ধ-নির্ভুল আচরণ

আধুনিক জিপিইউ আর্কিটেকচারগুলি একটি 32-বিট জোড়ায় দুটি 16-বিট মানকে একত্রিত করে এবং জোড়ার উপর কাজ করে এমন নির্দেশাবলী প্রয়োগ করে। সর্বোত্তম কর্মক্ষমতার জন্য, স্কেলার 16-বিট ফ্লোট ভেরিয়েবল ব্যবহার করা এড়িয়ে চলুন; দুই বা চার-উপাদান ভেক্টরে ডেটা ভেক্টরাইজ করুন। শেডার কম্পাইলার ভেক্টর অপারেশনে স্কেলার মান ব্যবহার করতে সক্ষম হতে পারে। যাইহোক, যদি আপনি স্কেলার অপ্টিমাইজ করার জন্য কম্পাইলারের উপর নির্ভর করেন, ভেক্টরাইজেশন যাচাই করতে কম্পাইলার আউটপুট পরিদর্শন করুন।

32-বিট এবং 16-বিট&#ndash;নির্ভুল ফ্লোটিং পয়েন্টে এবং থেকে রূপান্তর করার একটি গণনামূলক খরচ রয়েছে। আপনার কোডে যথার্থ রূপান্তর কমিয়ে ওভারহেড হ্রাস করুন।

আপনার অ্যালগরিদমের 16-বিট এবং 32-বিট সংস্করণগুলির মধ্যে বেঞ্চমার্ক কর্মক্ষমতা পার্থক্য। অর্ধেক নির্ভুলতা সবসময় একটি কর্মক্ষমতা উন্নতির ফলে হয় না, বিশেষ করে জটিল গণনার জন্য। যে অ্যালগরিদমগুলি ভেক্টরাইজড ডেটাতে ফিউজড মাল্টিপ্লাই-অ্যাড (এফএমএ) নির্দেশাবলীর ব্যাপক ব্যবহার করে তারা অর্ধেক নির্ভুলতায় উন্নত কর্মক্ষমতার জন্য ভাল প্রার্থী।

সংখ্যাসূচক বিন্যাস সমর্থন

অ্যান্ড্রয়েডের সমস্ত ভলকান ডিভাইস একক-নির্ভুলতা, 32-বিট ফ্লোটিং পয়েন্ট নম্বর এবং 32-বিট পূর্ণসংখ্যা ডেটা এবং শেডার গণনার সমর্থন করে। অন্যান্য ফরম্যাটগুলির জন্য সমর্থন উপলব্ধ হওয়ার নিশ্চয়তা নেই এবং যদি উপলব্ধ থাকে তবে সমস্ত ব্যবহারের ক্ষেত্রে নিশ্চিত নয়।

Vulkan ঐচ্ছিক সাংখ্যিক বিন্যাসের জন্য সমর্থনের দুটি বিভাগ আছে: পাটিগণিত এবং স্টোরেজ। একটি নির্দিষ্ট বিন্যাস ব্যবহার করার আগে, একটি ডিভাইস উভয় বিভাগে এটি সমর্থন করে তা নিশ্চিত করুন।

পাটিগণিত সমর্থন

একটি Vulkan ডিভাইসকে অবশ্যই একটি সংখ্যাসূচক বিন্যাসের জন্য গাণিতিক সমর্থন ঘোষণা করতে হবে যাতে এটি shader প্রোগ্রামগুলিতে ব্যবহারযোগ্য হয়। অ্যান্ড্রয়েডের ভলকান ডিভাইসগুলি সাধারণত পাটিগণিতের জন্য নিম্নলিখিত ফর্ম্যাটগুলিকে সমর্থন করে:

  • 32-বিট পূর্ণসংখ্যা (বাধ্যতামূলক)
  • 32-বিট ফ্লোটিং পয়েন্ট (আবশ্যিক)
  • 8-বিট পূর্ণসংখ্যা (ঐচ্ছিক)
  • 16-বিট পূর্ণসংখ্যা (ঐচ্ছিক)
  • 16-বিট অর্ধ-নির্ভুল ফ্লোটিং পয়েন্ট (ঐচ্ছিক)

একটি Vulkan ডিভাইস পাটিগণিতের জন্য 16-বিট পূর্ণসংখ্যা সমর্থন করে কিনা তা নির্ধারণ করতে, vkGetPhysicalDeviceFeatures2() ফাংশন কল করে এবং VkPhysicalDeviceFeatures2 ফলাফল কাঠামোতে shaderInt16 ক্ষেত্রটি সত্য কিনা তা পরীক্ষা করে ডিভাইসের বৈশিষ্ট্যগুলি পুনরুদ্ধার করুন।

একটি Vulkan ডিভাইস 16-বিট ফ্লোট বা 8-বিট পূর্ণসংখ্যা সমর্থন করে কিনা তা নির্ধারণ করতে, নিম্নলিখিত পদক্ষেপগুলি সম্পাদন করুন:

  1. ডিভাইসটি VK_KHR_shader_float16_int8 Vulkan এক্সটেনশন সমর্থন করে কিনা তা পরীক্ষা করুন। 16-বিট ফ্লোট এবং 8-বিট পূর্ণসংখ্যা সমর্থনের জন্য এক্সটেনশন প্রয়োজন।
  2. যদি VK_KHR_shader_float16_int8 সমর্থিত হয়, তাহলে একটি VkPhysicalDeviceShaderFloat16Int8Features গঠন পয়েন্টার একটি VkPhysicalDeviceFeatures2.pNext চেইনে যুক্ত করুন।
  3. vkGetPhysicalDeviceFeatures2() কল করার পরে VkPhysicalDeviceShaderFloat16Int8Features ফলাফল কাঠামোর shaderFloat16 এবং shaderInt8 ক্ষেত্রগুলি পরীক্ষা করুন। ক্ষেত্রের মান true হলে, বিন্যাসটি shader প্রোগ্রাম গাণিতিকের জন্য সমর্থিত।

Vulkan 1.1 বা 2022 অ্যান্ড্রয়েড বেসলাইন প্রোফাইলে প্রয়োজন না হলেও, Android ডিভাইসে VK_KHR_shader_float16_int8 এক্সটেনশনের জন্য সমর্থন খুবই সাধারণ।

স্টোরেজ সমর্থন

একটি Vulkan ডিভাইস নির্দিষ্ট স্টোরেজ প্রকারের জন্য একটি ঐচ্ছিক সাংখ্যিক বিন্যাসের জন্য সমর্থন ঘোষণা করতে হবে। VK_KHR_16bit_storage এক্সটেনশন 16-বিট পূর্ণসংখ্যা এবং 16-বিট ফ্লোটিং-পয়েন্ট ফরম্যাটের জন্য সমর্থন ঘোষণা করে। চারটি স্টোরেজ প্রকার এক্সটেনশন দ্বারা সংজ্ঞায়িত করা হয়। একটি ডিভাইস 16-বিট নম্বর সমর্থন করতে পারে কোনটি, কিছু বা সমস্ত স্টোরেজ প্রকারের জন্য।

স্টোরেজ প্রকারগুলি হল:

  • স্টোরেজ বাফার অবজেক্ট
  • অভিন্ন বাফার বস্তু
  • ধ্রুবক ব্লক ধাক্কা
  • Shader ইনপুট এবং আউটপুট ইন্টারফেস

বেশিরভাগ, কিন্তু সব নয়, অ্যান্ড্রয়েডের ভলকান 1.1 ডিভাইস স্টোরেজ বাফার অবজেক্টে 16-বিট ফর্ম্যাট সমর্থন করে। GPU মডেলের উপর ভিত্তি করে সমর্থন অনুমান করবেন না। প্রদত্ত GPU-এর জন্য পুরানো ড্রাইভার সহ ডিভাইসগুলি স্টোরেজ বাফার অবজেক্টগুলিকে সমর্থন নাও করতে পারে, যখন নতুন ড্রাইভারগুলির সাথে ডিভাইসগুলি করে।

ইউনিফর্ম বাফার, পুশ কনস্ট্যান্ট ব্লক এবং শেডার ইনপুট/আউটপুট ইন্টারফেসে 16-বিট ফর্ম্যাটের জন্য সমর্থন সাধারণত GPU প্রস্তুতকারকের উপর নির্ভর করে। অ্যান্ড্রয়েডে, একটি জিপিইউ সাধারণত এই তিনটি প্রকারের সবকটি সমর্থন করে বা তাদের কোনোটিই নয়।

একটি উদাহরণ ফাংশন যা ভলকান গাণিতিক এবং স্টোরেজ বিন্যাস সমর্থনের জন্য পরীক্ষা করে:

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;
  }
}

ডেটার জন্য যথার্থতা স্তর

একটি অর্ধ-নির্ভুল ফ্লোটিং পয়েন্ট সংখ্যা একটি একক-নির্ভুলতা ফ্লোটিং পয়েন্ট সংখ্যার চেয়ে কম নির্ভুলতায় মানগুলির একটি ছোট পরিসর উপস্থাপন করতে পারে। অর্ধ-নির্ভুলতা প্রায়শই একক-নির্ভুলতার চেয়ে একটি সহজ এবং উপলব্ধিগতভাবে ক্ষতিহীন পছন্দ। যাইহোক, অর্ধ-নির্ভুলতা সব ব্যবহারের ক্ষেত্রে ব্যবহারিক নাও হতে পারে। কিছু ধরণের ডেটার জন্য, হ্রাসকৃত পরিসর এবং নির্ভুলতার ফলে গ্রাফিক আর্টিফ্যাক্ট বা ভুল রেন্ডারিং হতে পারে।

অর্ধ-নির্ভুল ফ্লোটিং পয়েন্টে প্রতিনিধিত্বের জন্য ভাল প্রার্থী যে ডেটা প্রকারগুলি অন্তর্ভুক্ত করে:

  • স্থানীয় স্থান স্থানাঙ্কে অবস্থান ডেটা
  • সীমিত UV মোড়ানো সহ ছোট টেক্সচারের জন্য টেক্সচার ইউভি যা একটি -1.0 থেকে 1.0 স্থানাঙ্ক পরিসরে সীমাবদ্ধ হতে পারে
  • সাধারণ, স্পর্শক এবং বিট্যাঞ্জেন্ট ডেটা
  • ভার্টেক্স রঙের ডেটা
  • 0.0 কে কেন্দ্র করে কম নির্ভুলতার প্রয়োজনীয়তা সহ ডেটা

অর্ধ-নির্ভুল ফ্লোটে উপস্থাপনের জন্য সুপারিশ করা হয় না এমন ডেটা প্রকারের মধ্যে রয়েছে:

  • গ্লোবাল ওয়ার্ল্ড কোঅর্ডিনেটে অবস্থান ডেটা
  • অ্যাটলাস শীটে UI উপাদান স্থানাঙ্কের মতো উচ্চ-নির্ভুলতার ব্যবহারের ক্ষেত্রে টেক্সচার ইউভি

শেডার কোডে যথার্থতা

ওপেনজিএল শেডিং ল্যাঙ্গুয়েজ (জিএলএসএল) এবং হাই-লেভেল শেডার ল্যাঙ্গুয়েজ (এইচএলএসএল) শেডার প্রোগ্রামিং ল্যাঙ্গুয়েজগুলি সাংখ্যিক প্রকারের জন্য শিথিল নির্ভুলতা বা স্পষ্ট নির্ভুলতার স্পেসিফিকেশন সমর্থন করে। শিথিল নির্ভুলতা শেডার কম্পাইলারের জন্য একটি সুপারিশ হিসাবে বিবেচিত হয়। স্পষ্ট নির্ভুলতা নির্দিষ্ট নির্ভুলতা একটি প্রয়োজন. অ্যান্ড্রয়েডের ভলকান ডিভাইসগুলি সাধারণত 16-বিট ফর্ম্যাট ব্যবহার করে যখন শিথিল নির্ভুলতার দ্বারা প্রস্তাবিত হয়। অন্যান্য ভলকান ডিভাইস, বিশেষ করে ডেস্কটপ কম্পিউটারে গ্রাফিক্স হার্ডওয়্যার ব্যবহার করে 16-বিট ফরম্যাটের জন্য সমর্থন নেই, শিথিল নির্ভুলতা উপেক্ষা করতে পারে এবং এখনও 32-বিট ফর্ম্যাট ব্যবহার করতে পারে।

GLSL-এ স্টোরেজ এক্সটেনশন

স্টোরেজ এবং ইউনিফর্ম বাফার স্ট্রাকচারে 16-বিট বা 8-বিট সাংখ্যিক বিন্যাসের জন্য সমর্থন সক্ষম করার জন্য উপযুক্ত GLSL এক্সটেনশনগুলিকে অবশ্যই সংজ্ঞায়িত করতে হবে। প্রাসঙ্গিক এক্সটেনশন ঘোষণা হল:

// 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 এ স্বস্তিদায়ক নির্ভুলতা

একটি একক-নির্ভুলতা ফ্লোট এবং অর্ধ-নির্ভুল ফ্লোটের জন্য mediump কোয়ালিফায়ার প্রস্তাব করতে একটি ফ্লোটিং পয়েন্ট টাইপের আগে highp কোয়ালিফায়ার ব্যবহার করুন। ভলকান-এর জন্য GLSL কম্পাইলাররা লিগ্যাসি lowp কোয়ালিফায়ারকে mediump হিসেবে ব্যাখ্যা করে। শিথিল নির্ভুলতার কিছু উদাহরণ:

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

GLSL এ স্পষ্ট নির্ভুলতা

আপনার GLSL কোডে GL_EXT_shader_explicit_arithmetic_types_float16 এক্সটেনশন অন্তর্ভুক্ত করুন 16-বিট ফ্লোটিং পয়েন্ট প্রকারের ব্যবহার সক্ষম করতে:

#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require

নিম্নলিখিত কীওয়ার্ডগুলি ব্যবহার করে GLSL-এ 16-বিট ফ্লোটিং পয়েন্ট স্কেলার, ভেক্টর এবং ম্যাট্রিক্স প্রকারগুলি ঘোষণা করুন:

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

নিম্নলিখিত কীওয়ার্ডগুলি ব্যবহার করে GLSL-এ 16-বিট পূর্ণসংখ্যা স্কেলার এবং ভেক্টর প্রকারগুলি ঘোষণা করুন:

int16_t     i16vec2     i16vec3    i16vec4
uint16_t    u16vec2     u16vec3    u16vec4

এইচএলএসএল-এ শিথিল নির্ভুলতা

HLSL শিথিল নির্ভুলতার পরিবর্তে ন্যূনতম নির্ভুলতা শব্দটি ব্যবহার করে। একটি ন্যূনতম নির্ভুলতা টাইপ কীওয়ার্ড ন্যূনতম নির্ভুলতা নির্দিষ্ট করে, তবে কম্পাইলার একটি উচ্চ নির্ভুলতা প্রতিস্থাপন করতে পারে যদি লক্ষ্য হার্ডওয়্যারের জন্য উচ্চ নির্ভুলতা একটি ভাল পছন্দ হয়। একটি ন্যূনতম নির্ভুলতা 16-বিট ফ্লোট min16float কীওয়ার্ড দ্বারা নির্দিষ্ট করা হয়। ন্যূনতম নির্ভুলতা স্বাক্ষরিত এবং স্বাক্ষরবিহীন 16-বিট পূর্ণসংখ্যা যথাক্রমে min16int এবং min16uint কীওয়ার্ড দ্বারা নির্দিষ্ট করা হয়। ন্যূনতম নির্ভুলতা ঘোষণার অতিরিক্ত উদাহরণগুলির মধ্যে নিম্নলিখিতগুলি অন্তর্ভুক্ত রয়েছে:

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

এইচএলএসএল-এ স্পষ্ট নির্ভুলতা

অর্ধ-নির্ভুলতা ফ্লোটিং-পয়েন্ট half বা float16_t কীওয়ার্ড দ্বারা নির্দিষ্ট করা হয়। স্বাক্ষরিত এবং স্বাক্ষরবিহীন 16-বিট পূর্ণসংখ্যা যথাক্রমে int16_t এবং uint16_t কীওয়ার্ড দ্বারা নির্দিষ্ট করা হয়। সুস্পষ্ট নির্ভুল ঘোষণার অতিরিক্ত উদাহরণগুলির মধ্যে নিম্নলিখিতগুলি অন্তর্ভুক্ত রয়েছে:

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