Il formato numerico dei dati grafici e dei calcoli dello shaker può avere un un impatto significativo sulle prestazioni del tuo gioco.
I formati ottimali sono i seguenti:
- Aumentare l'efficienza dell'utilizzo della cache GPU
- Riduzione del consumo di larghezza di banda della memoria, risparmio energetico e aumento delle prestazioni
- Massimizzare la velocità effettiva di calcolo nei programmi Shar
- Riduci al minimo l'utilizzo della RAM della CPU per il gioco
Formati con virgola mobile
La maggior parte dei calcoli e dei dati nella grafica 3D moderna utilizza la rappresentazione in virgola mobile numeri. Vulkan su Android utilizza numeri in virgola mobile come 32 o a 16 bit. Un numero in virgola mobile a 32 bit è comunemente noto come precisione singola o completa; un numero in virgola mobile a 16 bit, metà la precisione.
Vulkan definisce un tipo con virgola mobile a 64 bit, ma il tipo non è comunemente utilizzato supportata dai dispositivi Vulkan su Android e il suo utilizzo è sconsigliato. A 64 bit il numero in virgola mobile è comunemente chiamato precisione doppia.
Formati interi
Per i dati e i calcoli vengono utilizzati anche i numeri interi firmati e non. La la dimensione intero standard è di 32 bit. Il supporto per altre dimensioni di bit è il dispositivo dipendono da te. I dispositivi Vulkan con sistema operativo Android in genere supportano i formati a 16 e 8 bit numeri interi. Vulkan definisce un tipo di numero intero a 64 bit, ma il tipo non è comunemente utilizzato supportata dai dispositivi Vulkan su Android e il suo utilizzo è sconsigliato.
Comportamento di mezza precisione non ottimale
Le moderne architetture GPU combinano due valori a 16 bit in una coppia a 32 bit implementare le istruzioni che operano sulla coppia. Per prestazioni ottimali, evita di utilizzando variabili scalare in virgola mobile a 16 bit; vettorializziamo i dati in due o quattro elementi vettori di rete. Il compilatore shaker può essere in grado di utilizzare valori scalari operazioni. Tuttavia, se ti affidi al compilatore per ottimizzare gli scalari, ispeziona l'output del compilatore per verificare la vettorizzazione.
La conversione in virgola mobile a e da a 32 bit e a 16 bit con precisione in virgola mobile ha un di calcolo dei costi computazionali. Riduci l'overhead riducendo al minimo le conversioni di precisione le API nel tuo codice.
Confronta le differenze di prestazioni tra le versioni a 16 e a 32 bit del tuo degli algoritmi. Una precisione dimezzata non sempre porta a un miglioramento delle prestazioni, soprattutto per i calcoli complicati. Algoritmi che fanno un uso intensivo dei le istruzioni per la moltiplicazione con aggiunta di elementi (FMA) su dati vettoriali sono buoni candidati per ha migliorato le prestazioni con una precisione dimezzata.
Supporto del formato numerico
Tutti i dispositivi Vulkan su Android supportano la modalità a precisione singola a 32 bit in virgola mobile e numeri interi a 32 bit nei calcoli dei dati e dello shaker. Supporto per la disponibilità di altri formati non è garantita e, se disponibili, non sono garantiti per tutti i casi d'uso.
Vulkan prevede due categorie di supporto per i formati numerici facoltativi: aritmetici e spazio di archiviazione. Prima di utilizzare un formato specifico, assicurati che un dispositivo lo supporti in categorie.
Supporto aritmetico
Un dispositivo Vulkan deve dichiarare il supporto aritmetico per un formato numerico perché essere utilizzabili nei programmi SHARING. I dispositivi Vulkan su Android di solito supportano seguenti formati per operazioni aritmetiche:
- Numero intero a 32 bit (obbligatorio)
- rappresentazione in virgola mobile a 32 bit (obbligatorio)
- Numero intero a 8 bit (facoltativo)
- Numero intero a 16 bit (facoltativo)
- (Facoltativo) Virgola in virgola mobile a mezza precisione a 16 bit
Per determinare se un dispositivo Vulkan supporta numeri interi a 16 bit per l'aritmetica:
recupera le funzionalità del dispositivo chiamando il
vkGetPhysicalDeviceFeatures2() e controllare se
il campo shaderInt16
in VkPhysicalDeviceFeatures2
che la struttura dei risultati sia vera.
Per determinare se un dispositivo Vulkan supporta numeri in virgola mobile a 16 bit o numeri interi a 8 bit, segui questi passaggi:
- Verifica se il dispositivo supporta VK_KHR_shader_float16_int8 Estensione Vulkan. L'estensione è richiesto per il supporto di numeri in virgola mobile a 16 bit e numeri interi a 8 bit.
- Se il criterio
VK_KHR_shader_float16_int8
è supportato, aggiungi un Puntatore della struttura VkPhysicalDeviceShaderFloat16Int8Features a una catenaVkPhysicalDeviceFeatures2.pNext
. - Controlla i campi
shaderFloat16
eshaderInt8
della Struttura dei risultatiVkPhysicalDeviceShaderFloat16Int8Features
dopo la chiamatavkGetPhysicalDeviceFeatures2()
. Se il valore del campo ètrue
, il formato è supportato per l'aritmetica del programma specifico.
Sebbene non sia un requisito in Vulkan 1.1 o nel 2022
Profilo Android Baseline, supporto per VK_KHR_shader_float16_int8
è molto comune sui dispositivi Android.
Supporto dello spazio di archiviazione
Un dispositivo Vulkan deve dichiarare il supporto di un formato numerico facoltativo per tipi di archiviazione specifici. Estensione VK_KHR_16bit_storage dichiara il supporto per formati interi a 16 bit e in virgola mobile a 16 bit. Quattro. i tipi di archiviazione sono definiti dall'estensione. Un dispositivo può supportare numeri a 16 bit per nessuno, alcuni o tutti i tipi di archiviazione.
I tipi di archiviazione sono:
- Oggetti buffer di archiviazione
- Oggetti buffer uniforme
- Spingi blocchi costanti
- Interfacce di input e output dello Shader
La maggior parte dei dispositivi Vulkan 1.1 su Android, ma non tutti, supporta i formati a 16 bit in oggetti buffer di archiviazione. Non dare per scontato il supporto in base al modello GPU. Dispositivi con driver meno recenti per una determinata GPU, potrebbero non supportare oggetti buffer di archiviazione, mentre quelli con driver più recenti sì.
Supporto per formati a 16 bit nei buffer uniformi, push con blocchi costanti e Shar di input/output dipende in genere dal produttore della GPU. Attivato Android, una GPU in genere supporta tutti e tre questi tipi o nessuno dei due che li rappresentano.
Una funzione di esempio che verifica il supporto dell'aritmetica e dei formati di archiviazione 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;
}
}
Livello di precisione dei dati
Un numero in virgola mobile con mezza precisione può rappresentare un intervallo di valori minore con una precisione inferiore rispetto a un numero in virgola mobile a precisione singola. La mezza precisione è spesso una scelta semplice e percettivamente senza perdita di precisione singola. Tuttavia, la metà della precisione potrebbe non essere pratica in tutti i casi d'uso. Per alcuni tipi di dati, la riduzione dell'intervallo e della precisione può o rendering non corretto.
Tipi di dati che sono buoni candidati per la rappresentazione a metà precisione la rappresentazione in virgola mobile include:
- Posizione dei dati nelle coordinate dello spazio locale
- Raggi UV texture per texture più piccole con wrapping UV limitato che possono essere vincolato a un intervallo di coordinate compreso tra -1,0 e 1,0
- Dati normali, tangenti e bitangent
- Dati colore Vertex
- Dati con requisiti di precisione bassi incentrati su 0,0
Tipi di dati che non sono consigliati per la rappresentazione in numero in virgola mobile a metà precisione include:
- Posizione dei dati nelle coordinate mondiali
- UV texture per casi d'uso ad alta precisione come le coordinate degli elementi UI in un foglio atlas
Precisione nel codice dello shaker
OpenGL Shading Language (GLSL) e Shader High-level Shader Language (HLSL) i linguaggi di programmazione supportano precisione o precisione esplicita per i tipi numerici. Viene trattata la precisione confortevole come suggerimento per il compilatore shar. La precisione esplicita è un requisito della precisione specificata. I dispositivi Vulkan su Android in genere utilizzano Formati a 16 bit suggeriti da una precisione rilassata. Altri dispositivi Vulkan in particolare sui computer che utilizzano hardware grafico non supportato per i formati a 16 bit, potrebbero ignorare una precisione rilassata e utilizzare comunque i formati a 32 bit.
Estensioni dello spazio di archiviazione in GLSL
È necessario definire le estensioni GLSL appropriate per abilitare il supporto delle versioni a 16 bit o Formati numerici a 8 bit nelle strutture di archiviazione e buffer uniformi. I contenuti pertinenti dichiarazioni di estensione sono:
// 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
Queste estensioni sono specifiche di GLSL e non hanno un equivalente in HLSL.
Precisione confortevole in GLSL
Utilizza il qualificatore highp
prima di un tipo con rappresentazione in virgola mobile per suggerire una
numero in virgola mobile a precisione singola e il qualificatore mediump
per un numero in virgola mobile a mezza precisione.
I compilatori GLSL per Vulkan interpretano il qualificatore lowp
precedente come mediump
.
Alcuni esempi di precisione rilassata:
mediump vec4 my_vector; // Suggest 16-bit half precision
highp mat4 my_matrix; // Suggest 32-bit single precision
Precisione esplicita in GLSL
Includi l'estensione GL_EXT_shader_explicit_arithmetic_types_float16
nel tuo
Codice GLSL per consentire l'uso di tipi di rappresentazione in virgola mobile a 16 bit:
#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require
Dichiara i tipi di scalari, vettoriali e matrici a virgola mobile a 16 bit in GLSL utilizzando il metodo seguenti parole chiave:
float16_t f16vec2 f16vec3 f16vec4
f16mat2 f16mat3 f16mat4
f16mat2x2 f16mat2x3 f16mat2x4
f16mat3x2 f16mat3x3 f16mat3x4
f16mat4x2 f16mat4x3 f16mat4x4
Dichiara i tipi di vettori e scalari interi a 16 bit in GLSL utilizzando quanto segue: parole chiave:
int16_t i16vec2 i16vec3 i16vec4
uint16_t u16vec2 u16vec3 u16vec4
Precisione rilassata in HLSL
HLSL utilizza il termine precisione minima anziché precisione rilassata. Minima
precisione specifica specifica la precisione minima, ma il compilatore può
sostituisci una precisione maggiore se una precisione maggiore è una scelta migliore per il
hardware di destinazione. Un numero in virgola mobile a 16 bit con precisione minima viene specificato dal
min16float
parola chiave. I numeri interi a 16 bit con e senza segno di precisione minima sono
specificate rispettivamente dalle parole chiave min16int
e min16uint
. Aggiuntivo
esempi di dichiarazioni di precisione minima sono i seguenti:
// Four element vector and four-by-four matrix types
min16float4 my_vector4;
min16float4x4 my_matrix4x4;
Precisione esplicita in HLSL
Il valore in virgola mobile a mezza precisione è specificato dal criterio half
o float16_t
parole chiave. I numeri interi a 16 bit, firmati e non, vengono specificati dall'int16_t
e uint16_t
parole chiave. Ulteriori esempi di precisione esplicita
le dichiarazioni includono:
// Four element vector and four-by-four matrix types
half4 my_vector4;
half4x4 my_matrix4x4;