Grafik verilerinin sayısal biçimi ve gölgelendirici hesaplamaları, oyununuzun performansı üzerinde önemli bir etkiye sahip olabilir.
En uygun biçimler şunları yapar:
- GPU önbellek 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 programlarda hesaplama işleme hızı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 noktalı sayılar kullanır. Android'de Vulkan, 32 veya 16 bit boyutunda kayan noktalı sayılar kullanır. 32 bitlik kayan noktalı sayı genellikle tek duyarlıklı veya tam duyarlıklı, 16 bitlik kayan noktalı sayı ise yarı duyarlıklı olarak adlandırılır.
Vulkan, 64 bit kayan nokta türünü 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ılar genellikle çift duyarlıklı olarak adlandırılır.
Tam sayı biçimleri
Veriler ve hesaplamalar için işaretli ve işaretsiz tam sayılar da kullanılır. Standart tam sayı boyutu 32 bittir. Diğer bit boyutları için destek cihaza bağlıdır. Android'de Vulkan'ı destekleyen cihazlar genellikle 16 bit ve 8 bitlik tam sayıları destekler. Vulkan, 64 bitlik bir 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ım duyarlıklı alt optimal davranış
Modern GPU mimarileri, iki 16 bitlik değeri 32 bitlik bir çiftte birleştirir ve çift üzerinde çalışan talimatları uygular. Optimum performans için skalar 16 bit kayan nokta değişkenleri kullanmaktan kaçının. Verileri iki veya dört öğeli vektörler halinde vektörize edin. Shader derleyici, vektör işlemlerinde skaler değerleri kullanabilir. Ancak, derleyicinin ölçekleri optimize etmesine güveniyorsanız vektörleştirme işlemini doğrulamak için derleyici çıkışını inceleyin.
32 bit ve 16 bit hassasiyetli kayan nokta arasında dönüştürme işleminin hesaplama maliyeti vardır. Kodunuzdaki kesin 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 karşılaştırma performansı farklılıkları. Yarım duyarlıklı sayı, özellikle karmaşık hesaplamalarda her zaman performans artışı sağlamaz. Vektörel verilerde birleştirilmiş çarpma-toplama (FMA) talimatlarını yoğun olarak kullanan algoritmalar, yarı duyarlılıkta 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 nokta sayılarını ve 32 bit tam sayıları destekler. Diğer biçimler için destek sunulacağı garanti edilmez. Destek sunulursa da tüm kullanım alanlarında destekleneceği garanti edilmez.
Vulkan, isteğe bağlı sayısal biçimler için iki destek kategorisine sahiptir: 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
Bir Vulkan cihazının, gölgelendirici programlarda 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ı duyarlıklı kayan nokta (isteğe bağlı)
Bir Vulkan cihazının aritmetik işlemler için 16 bitlik 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ın 16 bit kayan sayıları 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_int8
destekleniyorsaVkPhysicalDeviceFeatures2.pNext
zincirine VkPhysicalDeviceShaderFloat16Int8Features yapı işaretçisi ekleyin.shaderFloat16
veshaderInt8
alanlarını kontrol edin.VkPhysicalDeviceShaderFloat16Int8Features
sonuç yapısıvkGetPhysicalDeviceFeatures2()
çağrıldıktan sonra. Alan değeritrue
ise gölgelendirici program aritmetiği için biçim desteklenir.
Vulkan 1.1 veya 2022 Android Baseline profilinde zorunlu olmasa da VK_KHR_shader_float16_int8
uzantısı Android cihazlarda çok yaygın olarak desteklenir.
Depolama alanı desteği
Bir Vulkan cihazı, belirli depolama türleri için isteğe bağlı sayısal biçim desteğini bildirmelidir. VK_KHR_16bit_storage uzantısı, 16 bitlik tam sayı ve 16 bitlik kayan nokta biçimleri için destek beyan eder. Uzantı tarafından dört depolama türü tanımlanır. Bir cihaz, hiçbir depolama türü, bazı depolama türleri veya tüm depolama türleri için 16 bit sayıları destekleyebilir.
Depolama alanı türleri şunlardır:
- Depolama arabelleği nesneleri
- Tek tip arabellek nesneleri
- Sabit blokları itme
- Shader giriş ve çıkış arayüzleri
Android'deki Vulkan 1.1 cihazların çoğu, depolama arabelleği nesnelerinde 16 bit biçimleri destekler ancak bazıları desteklemez. GPU modeline göre destek olup olmadığını tahmin etmeyin. Belirli bir GPU için eski sürücülerin yüklü olduğu cihazlar depolama arabelleği nesnelerini desteklemeyebilir. Yeni sürücülerin yüklü olduğu cihazlar ise bu nesneleri destekler.
Tekdüzen arabelleklerde, push constant bloklarında ve gölgelendirici giriş/çıkış arayüzlerinde 16 bit biçimler için destek genellikle GPU üreticisine bağlıdır. Android'de GPU'lar genellikle bu üç türün tamamını 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ım 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ım duyarlılık, genellikle tek duyarlılığa kıyasla basit ve algısal olarak kayıpsız bir seçimdir. Ancak yarı duyarlılık, tüm kullanım alanlarında pratik olmayabilir. Bazı veri türlerinde, aralığın ve hassasiyetin azaltılması grafik artefaktlarına veya yanlış oluşturmaya neden olabilir.
Yarım duyarlıklı kayan nokta gösterimi için uygun olan veri türleri şunlardır:
- Konum verilerini yerel uzay koordinatlarına yerleştirme
- -1,0 ile 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 bitangent verileri
- Vertex renk verileri
- 0,0'a odaklanan düşük hassasiyet şartlarına sahip veriler
Yarım duyarlıklı kayan nokta gösterimi için önerilmeyen veri türleri şunlardır:
- Konum verilerini küresel dünya koordinatlarında konumlandırma
- Bir atlas sayfasındaki kullanıcı arayüzü öğesi koordinatları gibi yüksek hassasiyetli kullanım alanları için doku UV'leri
Gölgeleyici kodundaki hassasiyet
OpenGL Shading Language (GLSL) ve High-level Shader Language (HLSL) gölgelendirici programlama dilleri, sayısal türler için gevşek hassasiyet veya açık hassasiyet belirtilmesini destekler. Gevşek hassasiyet, gölgelendirici derleyici için öneri olarak değerlendirilir. Açık hassasiyet, belirtilen hassasiyetin bir gereğidir. Android'deki Vulkan cihazlar, genellikle gevşek hassasiyet önerildiğinde 16 bit biçimleri kullanır. Diğer Vulkan cihazları, özellikle 16 bit biçimler için destekten yoksun grafik donanımı kullanan masaüstü bilgisayarlarda, gevşek hassasiyeti yoksayabilir ve 32 bit biçimleri kullanmaya devam edebilir.
GLSL'deki 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ı bildirimleri ş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 karşılığı yoktur.
GLSL'de hassasiyetin azaltılması
Tek duyarlıklı kayan nokta önermek için kayan nokta türünden önce highp
, yarım duyarlıklı kayan nokta için ise mediump
niteleyicisini kullanın.
Vulkan için GLSL derleyicileri, eski lowp
tanımlayıcısını mediump
olarak yorumlar.
Gevşek hassasiyete ilişkin 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ılmasını sağlamak için GLSL kodunuza GL_EXT_shader_explicit_arithmetic_types_float16
uzantısını ekleyin:
#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require
Aşağıdaki anahtar kelimeleri kullanarak GLSL'de 16 bitlik kayan noktalı skaler, vektör ve matris türlerini bildirin:
float16_t f16vec2 f16vec3 f16vec4
f16mat2 f16mat3 f16mat4
f16mat2x2 f16mat2x3 f16mat2x4
f16mat3x2 f16mat3x3 f16mat3x4
f16mat4x2 f16mat4x3 f16mat4x4
Aşağıdaki anahtar kelimeleri kullanarak GLSL'de 16 bitlik tamsayı skalar ve vektör türlerini bildirin:
int16_t i16vec2 i16vec3 i16vec4
uint16_t u16vec2 u16vec3 u16vec4
HLSL'de gevşek hassasiyet
HLSL, gevşek hassasiyet yerine minimum hassasiyet terimini kullanır. Minimum hassasiyet türü anahtar kelimesi minimum hassasiyeti belirtir ancak derleyici, hedef donanım için daha iyi bir seçenekse daha yüksek bir hassasiyetle değiştirebilir. Minimum hassasiyete sahip 16 bitlik bir kayan nokta, min16float
anahtar kelimesiyle belirtilir. İmzalı ve imzasız 16 bitlik tam sayıların minimum hassasiyeti sırasıyla min16int
ve min16uint
anahtar kelimeleriyle belirtilir. Minimum hassasiyet beyanlarına ilişkin ek örnekler:
// Four element vector and four-by-four matrix types
min16float4 my_vector4;
min16float4x4 my_matrix4x4;
HLSL'de açık hassasiyet
Yarım duyarlıklı kayan nokta, half
veya float16_t
anahtar kelimeleriyle belirtilir. İmzalı ve imzasız 16 bitlik tam sayılar sırasıyla int16_t
ve uint16_t
anahtar kelimeleriyle belirtilir. Açık hassasiyet beyanlarına ilişkin ek örnekler:
// Four element vector and four-by-four matrix types
half4 my_vector4;
half4x4 my_matrix4x4;
-enable-16bit-types