Grafik verilerinin ve gölgelendirici hesaplamalarının sayısal biçimi, oyununuzun performansı üzerinde önemli bir etkiye sahip olabilir.
En uygun biçimler şunları yapar:
- GPU önbelleği kullanımının verimliliğini artırma
- Bellek bant genişliği tüketimini azaltarak güç tasarrufu sağlar ve performansı artırır.
- Gölgeleyici programlarında hesaplama performansını en üst düzeye çıkarma
- Oyununuzun CPU RAM kullanımını en aza indirme
Kayan nokta biçimleri
Modern 3D grafiklerdeki hesaplamaların ve verilerin çoğu kayan nokta sayılarını kullanır. Android'de Vulkan, 32 veya 16 bit boyutunda kayan noktalı sayılar kullanır. 32 bit kayan nokta sayısı genellikle tek duyarlıklı veya tam duyarlıklı, 16 bit kayan nokta sayısı ise yarı duyarlıklı olarak adlandırılır.
Vulkan, 64 bit kayan nokta türü tanımlar ancak bu tür, Android'deki Vulkan cihazlar tarafından yaygın olarak desteklenmez ve kullanılması önerilmez. 64 bitlik kayan noktalı sayı, genellikle çift duyarlıklı olarak adlandırılır.
Tam sayı biçimleri
İşaretli ve işaretsiz tam sayılar da veriler ve hesaplamalar için kullanılır. Standart tam sayı boyutu 32 bittir. Diğer bit boyutları için destek, cihaza bağlıdır. Android çalıştıran Vulkan cihazlar genellikle 16 bit ve 8 bit tam sayıları destekler. Vulkan, 64 bit tam sayı türü tanımlar ancak bu tür, Android'deki Vulkan cihazlar tarafından yaygın olarak desteklenmez ve kullanılması önerilmez.
Yarı hassasiyet davranışı ideal değil
Modern GPU mimarileri, iki adet 16 bit değeri 32 bitlik bir çiftte birleştirir ve bu çift üzerinde çalışan talimatları uygular. Optimum performans için skaler 16 bit kayan nokta değişkenleri kullanmaktan kaçının. Verileri iki veya dört öğeli vektörler halinde vektörleştirin. Gölgelendirici derleyici, vektör işlemlerinde skaler değerler kullanabilir. Ancak skalerleri optimize etmek için derleyiciyi kullanıyorsanız vektörleştirmeyi doğrulamak için derleyici çıkışını inceleyin.
32 bit ve 16 bit hassasiyetli kayan nokta arasında dönüşüm yapmanın hesaplama maliyeti vardır. Kodunuzdaki hassas dönüşümleri en aza indirerek ek yükü azaltın.
Algoritmalarınızın 16 bit ve 32 bit sürümleri arasındaki performans farklarını karşılaştırın. Yarı hassasiyet, özellikle karmaşık hesaplamalarda her zaman performans artışı sağlamaz. Vektörleştirilmiş verilerde birleştirilmiş çarpma-toplama (FMA) talimatlarını yoğun şekilde kullanan algoritmalar, yarı hassasiyette daha iyi performans için iyi adaylardır.
Sayısal biçim desteği
Android'deki tüm Vulkan cihazlar, veri ve gölgelendirici hesaplamalarında tek duyarlıklı, 32 bit kayan noktalı sayıları ve 32 bit tam sayıları destekler. Diğer biçimlerin destekleneceği garanti edilmez ve destekleniyorsa tüm kullanım alanları için geçerli olacağı garanti edilmez.
Vulkan'da isteğe bağlı sayısal biçimler için iki destek kategorisi vardır: aritmetik ve depolama. Belirli bir biçimi kullanmadan önce, cihazın bu biçimi her iki kategoride de desteklediğinden emin olun.
Aritmetik desteği
Vulkan cihazların, gölgelendirici programlarında kullanılabilmesi için sayısal biçimlerde aritmetik desteği bildirmesi gerekir. Android'deki Vulkan cihazlar genellikle aritmetik için aşağıdaki biçimleri destekler:
- 32 bit tam sayı (zorunlu)
- 32 bit kayan nokta (zorunlu)
- 8 bit tam sayı (isteğe bağlı)
- 16 bit tam sayı (isteğe bağlı)
- 16 bit yarı hassasiyetli kayan nokta (isteğe bağlı)
Bir Vulkan cihazın aritmetik için 16 bit tam sayıları destekleyip desteklemediğini belirlemek üzere vkGetPhysicalDeviceFeatures2() işlevini çağırarak cihazın özelliklerini alın ve VkPhysicalDeviceFeatures2 sonuç yapısındaki shaderInt16 alanının doğru olup olmadığını kontrol edin.
Bir Vulkan cihazın 16 bit kayan nokta veya 8 bit tam sayıları destekleyip desteklemediğini belirlemek için aşağıdaki adımları uygulayın:
- Cihazın VK_KHR_shader_float16_int8 Vulkan uzantısını destekleyip desteklemediğini kontrol edin. Uzantı, 16 bit kayan nokta ve 8 bit tam sayı desteği için gereklidir.
VK_KHR_shader_float16_int8destekleniyorsaVkPhysicalDeviceFeatures2.pNextzincirine bir VkPhysicalDeviceShaderFloat16Int8Features yapı işaretçisi ekleyin.vkGetPhysicalDeviceFeatures2()yöntemini çağırdıktan sonraVkPhysicalDeviceShaderFloat16Int8Featuressonuç yapısınınshaderFloat16veshaderInt8alanlarını kontrol edin. Alan değeritrueise biçim, gölgelendirici program aritmetiği için desteklenir.
Vulkan 1.1 veya 2022 Android Baseline profilinde zorunlu olmasa da VK_KHR_shader_float16_int8 uzantısı desteği Android cihazlarda çok yaygındır.
Depolama alanı desteği
Vulkan cihazı, belirli depolama alanı türleri için isteğe bağlı bir sayısal biçimi desteklediğini beyan etmelidir. VK_KHR_16bit_storage uzantısı, 16 bit tam sayı ve 16 bit kayan nokta biçimleri için destek sunar. Uzantı tarafından dört depolama alanı türü tanımlanır. Bir cihaz, depolama türlerinin hiçbiri, bazıları veya tümü için 16 bit sayıları destekleyebilir.
Depolama türleri şunlardır:
- Depolama arabelleği nesneleri
- Tek tip arabellek nesneleri
- Push sabit blokları
- Gölgelendirici giriş ve çıkış arayüzleri
Android'deki Vulkan 1.1 cihazların çoğu, depolama arabelleği nesnelerinde 16 bit biçimleri destekler ancak hepsi desteklemez. GPU modeline göre desteklendiğini varsaymayın. Belirli bir GPU için eski sürücüleri olan cihazlar depolama arabelleği nesnelerini desteklemeyebilir ancak daha yeni sürücüleri olan cihazlar destekler.
Tek tip arabelleklerde, sabit bloklarda ve gölgelendirici giriş/çıkış arayüzlerinde 16 bit biçimlerin desteklenmesi genellikle GPU üreticisine bağlıdır. Android'de GPU'lar genellikle bu üç türün tümünü destekler veya hiçbirini desteklemez.
Vulkan aritmetik ve depolama biçimi desteğini test eden örnek bir işlev:
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;
}
}
Veriler için kesinlik düzeyi
Yarı duyarlıklı kayan nokta sayısı, tek duyarlıklı kayan nokta sayısına kıyasla daha düşük duyarlılıkta daha küçük bir değer aralığını temsil edebilir. Yarı hassasiyet, tek hassasiyete kıyasla genellikle basit ve algısal olarak kayıpsız bir seçenektir. Ancak yarı hassasiyet tüm kullanım alanlarında pratik olmayabilir. Bazı veri türlerinde, aralığın ve hassasiyetin azalması grafik kusurlarına veya yanlış oluşturmaya neden olabilir.
Yarı duyarlıklı kayan nokta gösterimi için uygun veri türleri şunlardır:
- Yerel alan koordinatlarında konum verileri
- -1,0 ila 1,0 koordinat aralığıyla sınırlandırılabilen, sınırlı UV sarmalama özelliğine sahip daha küçük dokular için doku UV'leri
- Normal, teğet ve biteğet verileri
- Köşe noktası renk verileri
- 0,0'a odaklanan düşük hassasiyet gereksinimleri olan veriler
Yarı duyarlıklı kayan nokta olarak temsil edilmesi önerilmeyen veri türleri şunlardır:
- Global dünya koordinatlarında konum verileri
- Atlas sayfasındaki kullanıcı arayüzü öğesi koordinatları gibi yüksek hassasiyetli kullanım alanları için doku UV'leri
Gölgeleyici kodunda hassasiyet
OpenGL Shading Language (GLSL) ve High-level Shader Language (HLSL) gölgelendirici programlama dilleri, sayısal türler için esnek hassasiyet veya açık hassasiyet belirtimini destekler. Rahat hassasiyet, gölgelendirici derleyici için bir öneri olarak değerlendirilir. Açık hassasiyet, belirtilen hassasiyetin bir gerekliliğidir. Android'deki Vulkan cihazlar, esnek hassasiyet önerildiğinde genellikle 16 bit biçimleri kullanır. Diğer Vulkan cihazları, özellikle de 16 bit biçimleri desteklemeyen grafik donanımı kullanan masaüstü bilgisayarlarda, esnek hassasiyeti yoksayabilir ve 32 bit biçimleri kullanmaya devam edebilir.
GLSL'de depolama uzantıları
Depolama ve tek tip arabellek yapılarında 16 bit veya 8 bit sayısal biçimlerin desteklenmesi için uygun GLSL uzantıları tanımlanmalıdır. İlgili uzantı beyanları şunlardır:
// 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
Bu uzantılar GLSL'ye özeldir ve HLSL'de eşdeğeri yoktur.
GLSL'de esnek hassasiyet
Tek duyarlıklı kayan nokta önermek için kayan nokta türünden önce highp niteleyicisini, yarı duyarlıklı kayan nokta için ise mediump niteleyicisini kullanın.
Vulkan için GLSL derleyicileri, eski lowp niteleyicisini mediump olarak yorumlar.
Esnek hassasiyetle ilgili bazı örnekler:
mediump vec4 my_vector; // Suggest 16-bit half precision
highp mat4 my_matrix; // Suggest 32-bit single precision
GLSL'de açık hassasiyet
16 bit kayan nokta türlerinin kullanımını etkinleştirmek için GLSL kodunuza GL_EXT_shader_explicit_arithmetic_types_float16 uzantısını ekleyin:
#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require
GLSL'de 16 bit kayan nokta skaler, vektör ve matris türlerini aşağıdaki anahtar kelimeleri kullanarak bildirin:
float16_t f16vec2 f16vec3 f16vec4
f16mat2 f16mat3 f16mat4
f16mat2x2 f16mat2x3 f16mat2x4
f16mat3x2 f16mat3x3 f16mat3x4
f16mat4x2 f16mat4x3 f16mat4x4
GLSL'de 16 bit tam sayı skaler ve vektör türlerini aşağıdaki anahtar kelimeleri kullanarak tanımlayın:
int16_t i16vec2 i16vec3 i16vec4
uint16_t u16vec2 u16vec3 u16vec4
HLSL'de esnek hassasiyet
HLSL, esnek hassasiyet yerine minimum hassasiyet terimini kullanır. Minimum kesinlik türü anahtar kelimesi, minimum kesinliği belirtir ancak derleyici, hedef donanım için daha yüksek kesinlik daha iyi bir seçimse daha yüksek kesinlik kullanabilir. Minimum hassasiyetli 16 bit kayan nokta, min16float anahtar kelimesiyle belirtilir. Minimum hassasiyetli işaretli ve işaretsiz 16 bit tam sayılar sırasıyla min16int ve min16uint anahtar kelimeleriyle belirtilir. Minimum hassasiyet beyanlarına örnek olarak şunlar verilebilir:
// Four element vector and four-by-four matrix types
min16float4 my_vector4;
min16float4x4 my_matrix4x4;
HLSL'de açık hassasiyet
Yarı hassasiyetli kayan nokta, half veya float16_t anahtar kelimeleriyle belirtilir. İşaretli ve işaretsiz 16 bit tam sayılar sırasıyla int16_t ve uint16_t anahtar kelimeleriyle belirtilir. Açık hassasiyet beyanlarına dair diğer örnekler şunlardır:
// Four element vector and four-by-four matrix types
half4 my_vector4;
half4x4 my_matrix4x4;