|
Una instancia es una estructura que inicializa la biblioteca de
Vulkan para poder ejecutar sus funciones en una aplicación.
Básicamente es una estructura que almacena los punteros a las
funciones de la biblioteca. El uso de instancias permite
personalizar el entorno de ejecución de Vulkan por medio de dos
características: capas y extensiones. Las capas permiten sustituir
las versiones de las funciones, por ejemplo sustituyendo funciones
muy rápidas que no realizan comprobaciones por versiones más lentas
que si las introducen. Las extensiones permiten añadir nuevas
funciones al conjunto básico de Vulkan.
Para crear una instancia se utiliza el siguiente método:
VkResult vkCreateInstance (
const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance);
|
Vulkan permite utilizar gestores de memoria dinámica propios. De
esta forma, la creación y liberación de estructuras se puede
personalizar por medio de una estructura VkAllocationCallbacks.
En las funciones de la biblioteca que admiten este campo se puede
introducir un valor nulo (nullptr) para indicar que se
utilice el gestor de memoria por defecto.
typedef struct VkAllocationCallbacks {
void* pUserData;
PFN_vkAllocationFunction pfnAllocation;
PFN_vkReallocationFunction pfnReallocation;
PFN_vkFreeFunction pfnFree;
PFN_vkInternalAllocationNotification pfnInternalAllocation;
PFN_vkInternalFreeNotification pfnInternalFree;
} VkAllocationCallbacks;
|
La estructura VkInstanceCreateInfo permite definir
las características de la instancia que se desea crear. Casi todas
las estructuras de Vulkan comienzan con un campo llamado sType
que identifica el tipo de estructura. En este caso el valor que debe
tener este campo es VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO. Los
campos pNext y flags son también comunes a muchas
estructuras de Vulkan y están pensados para posibles ampliaciones
futuras por lo que se suelen dejar nulos. El campo
pApplicationInfo contiene información sobre la aplicación que
estamos programando. Los campos enabledLayerCount y
ppEnabledLayerNames describen el número y los nombres de las
capas que se quieren activar en la instancia. Los campos
enabledExtensionCount y ppEnabledExtensionNames
describen el número y los nombres de las extensiones a incluir en la
instancia.
typedef struct VkInstanceCreateInfo {
VkStructureType sType;
const void* pNext;
VkInstanceCreateFlags flags;
const VkApplicationInfo* pApplicationInfo;
uint32_t enabledLayerCount;
const char* const* ppEnabledLayerNames;
uint32_t enabledExtensionCount;
const char* const* ppEnabledExtensionNames;
} VkInstanceCreateInfo;
|
La estructura VkApplicationInfo permite describir la aplicación.
El campo sType de esta estructura debe contener el valor VK_STRUCTURE_TYPE_APPLICATION_INFO.
El resto de campos son de texto libre para indicar el nombre de la aplicación y la versión.
typedef struct VkApplicationInfo {
VkStructureType sType;
const void* pNext;
const char* pApplicationName;
uint32_t applicationVersion;
const char* pEngineName;
uint32_t engineVersion;
uint32_t apiVersion;
} VkApplicationInfo;
|
Para conocer cuales son las capas disponibles a la hora de crear una
instancia se utiliza el método vkEnumerateInstanceLayerProperties().
Generalmente se ejecuta en dos pasos. En el primer paso el argumento
pProperties se deja a nulo y la función devuelve en
pPropertyCount el número de capas disponibles. Esto permite
reservar la memoria suficiente para almacenar la información. En la
segunda ejecución se introduce el número de capas a leer y el array
de estructuras para almacenar sus propiedades.
VkResult vkEnumerateInstanceLayerProperties (
uint32_t* pPropertyCount,
VkLayerProperties* pProperties);
|
Las propiedades de las capas se describen en estructuras
VkLayerProperties. El primer campo de la estructura contiene el
nombre de la capa que se podrá utilizar en el proceso de creación de
la instancia.
typedef struct VkLayerProperties {
char layerName[VK_MAX_EXTENSION_NAME_SIZE];
uint32_t specVersion;
uint32_t implementationVersion;
char description[VK_MAX_DESCRIPTION_SIZE];
} VkLayerProperties;
|
Para obtener las
extensiones disponibles se utiliza el método vkEnumerateInstanceExtensionProperties()
que lee las extensiones asociadas a cada capa. Si el parámetro
pLayerName se deja a nulo se leen las extensiones
independientes de las capas. De nuevo se trata de una función que se ejecuta en dos pasos,
el primero para conocer el número de extensiones y el segundo para
leer realmente la lista de propiedades.
VkResult vkEnumerateInstanceExtensionProperties (
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties);
|
La estructura VkExtensionProperties contiene simplemente el
nombre de la extensión, que se utiliza en la creación de las
instancias, y la versión.
typedef struct VkExtensionProperties {
char extensionName[VK_MAX_EXTENSION_NAME_SIZE];
uint32_t specVersion;
} VkExtensionProperties;
|
Como las extensiones amplían las funciones disponibles en las
instancias, no podemos saber a priori cuales son estas funciones
disponibles. Para poder ejecutarlas se obtiene el puntero a la
función a partir de su nombre mediante los siguientes métodos. El
primero permite obtener funciones genéricas de la instancia y el
segundo obtiene referencias a funciones vinculadas a un dispositivo.
PFN_vkVoidFunction vkGetInstanceProcAddr (
VkInstance instance,
const char* pName);
PFN_vkVoidFunction vkGetDeviceProcAddr (
VkDevice device,
const char* pName);
|
La biblioteca GLFW dispone de una función para obtener las
extensiones que necesita para usar Vulkan como contexto gráfico de
las ventanas. Con esta función se puede obtener en una única
llamada la lista de extensiones a incluir en la instancia.
const char** glfwGetRequiredInstanceExtensions(
uint32_t* glfwExtensionCount);
|
|