|
Grado en Ingeniería Informática
Animación por Ordenador
Curso 2025/2026
|
Práctica 1f
|
|
Creación del dispositivo lógico
|
|
Objetivos
|
|
Añadir al proyecto la creación de un dispositivo lógico.
|
|
Dispositivos lógicos
|
|
A partir de un dispositivo físico (VkPhysicalDevice) se
puede construir un dispositivo lógico (VkDevice), que es
una representación del dispositivo físico con un determinado estado.
Se pueden construir varios dispositivos lógicos a partir de un mismo
dispositivo físico. La mayoría de las funciones de Vulkan tienen
como primer argumento el dispositivo lógico sobre el que se aplica
la función.
VkResult vkCreateDevice (
VkPhysicalDevice physicalDevice,
const VkDeviceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDevice* pDevice);
|
Para configurar el dispositivo lógico a crear se utiliza una estructura
VkDeviceCreateInfo, que se identifica indicando como campo
sType el valor VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO.
La estructura especifica las capas, las extensiones, las familias de colas y las características a utilizar en el dispositivo.
typedef struct VkDeviceCreateInfo {
VkStructureType sType;
const void* pNext;
VkDeviceCreateFlags flags;
uint32_t queueCreateInfoCount;
const VkDeviceQueueCreateInfo* pQueueCreateInfos;
uint32_t enabledLayerCount;
const char* const* ppEnabledLayerNames;
uint32_t enabledExtensionCount;
const char* const* ppEnabledExtensionNames;
const VkPhysicalDeviceFeatures* pEnabledFeatures;
} VkDeviceCreateInfo;
|
Las colas de comandos a utilizar en el dispositivo lógico se
describen con estructuras VkDeviceQueueCreateInfo. El campo
sType toma el valor
VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO. De momento no se han
definido flags para esta estructura. El índice de la familia
corresponde a su posición en el listado de familias del dispositivo
y queueCount se refiere al número de colas en paralelo a
utilizar en el dispositivo. Al crear un dispositivo lógico se pueden
configurar varias familias de colas con varias colas en cada una de
ellas.
typedef struct VkDeviceQueueCreateInfo {
VkStructureType sType;
const void* pNext;
VkDeviceQueueCreateFlags flags;
uint32_t queueFamilyIndex;
uint32_t queueCount;
const float* pQueuePriorities;
} VkDeviceQueueCreateInfo;
|
|
|
Modificaciones de la clase
GEGraphicsContext
|
|
Las modificaciones necesarias para incluir
el dispositivo lógico (una estructura VkDevice) se limitan
a la clase GEGraphicsContext. La
modificación consiste en añadir el campos device
(dispositivo lógico) y el método
createLogicalDevice().
#pragma once
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <vulkan/vulkan.h>
class GEGraphicsContext
{
public:
VkInstance instance;
VkSurfaceKHR surface;
VkPhysicalDevice physicalDevice;
VkDevice device;
uint32_t graphicsQueueFamilyIndex;
uint32_t presentQueueFamilyIndex;
private:
VkPhysicalDeviceMemoryProperties memProperties;
public:
GEGraphicsContext(GLFWwindow* window);
~GEGraphicsContext();
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
VkFormat findDepthFormat();
private:
// Métodos de inicialización de Vulkan
void createInstance();
void createSurface(GLFWwindow* window);
void pickPhysicalDevice();
void createLogicalDevice();
// Métodos auxiliares
void showInstanceProperties();
bool isDeviceSuitable(VkPhysicalDevice pDevice);
void showDevices();
void resumeDeviceProperties(VkPhysicalDevice pDevice, int index);
};
|
Los métodos modificados son el constructor (para añadir la
construcción del dispositivo lógico) y el destructor (para añadir la
destrucción del dispositivo lógico). Además se ha añadido el método createLogicalDevice()
que
genera el dispositivo lógico asociado al dispositivo físico
considerando en su configuración la selección de familias de colas
para la generación de gráficos y su presentación.
///////////////////////////////////////////////////////////////////////////////////
///// /////
///// Métodos públicos /////
///// /////
///////////////////////////////////////////////////////////////////////////////////
//
// FUNCIÓN: GEGraphicsContext::GEGraphicsContext()
//
// PROPÓSITO: Crea un contexto gráfico de Vulkan (instancia, superficie y dispositivo)
//
GEGraphicsContext::GEGraphicsContext(GLFWwindow* window)
{
createInstance();
createSurface(window);
// showInstanceProperties();
pickPhysicalDevice();
// showDevices();
createLogicalDevice();
std::cout << "Logical device created!" << std::endl;
}
//
// FUNCIÓN: GEGraphicsContext::~GEGraphicsContext()
//
// PROPÓSITO: Destruye el contexto gráfico
//
GEGraphicsContext::~GEGraphicsContext()
{
vkDestroyDevice(device, nullptr);
vkDestroySurfaceKHR(instance, surface, nullptr);
vkDestroyInstance(instance, nullptr);
}
...
///////////////////////////////////////////////////////////////////////////////////
///// /////
///// Métodos de inicialización de Vulkan /////
///// /////
///////////////////////////////////////////////////////////////////////////////////
...
//
// FUNCIÓN: GEGraphicsContext::createLogicalDevice()
//
// PROPÓSITO: Crea el dispositivo lógico sobre el que generar los gráficos
// y selecciona la familia de colas sobre el dispositivo
//
void GEGraphicsContext::createLogicalDevice()
{
std::vector<VkDeviceQueueCreateInfo> queueCreateInfo;
uint32_t queueCreateInfoCount;
if (graphicsQueueFamilyIndex == presentQueueFamilyIndex)
{
VkDeviceQueueCreateInfo graphicsQueueCreateInfo = {};
graphicsQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
graphicsQueueCreateInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
graphicsQueueCreateInfo.queueCount = 1;
float graphicsQueuePriority = 1.0f;
graphicsQueueCreateInfo.pQueuePriorities = &graphicsQueuePriority;
queueCreateInfoCount = 1;
queueCreateInfo = { graphicsQueueCreateInfo };
}
else
{
VkDeviceQueueCreateInfo graphicsQueueCreateInfo = {};
graphicsQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
graphicsQueueCreateInfo.queueFamilyIndex = graphicsQueueFamilyIndex;
graphicsQueueCreateInfo.queueCount = 1;
float graphicsQueuePriority = 1.0f;
graphicsQueueCreateInfo.pQueuePriorities = &graphicsQueuePriority;
VkDeviceQueueCreateInfo presentQueueCreateInfo = {};
presentQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
presentQueueCreateInfo.queueFamilyIndex = presentQueueFamilyIndex;
presentQueueCreateInfo.queueCount = 1;
float presentQueuePriority = 1.0f;
presentQueueCreateInfo.pQueuePriorities = &presentQueuePriority;
queueCreateInfoCount = 2;
queueCreateInfo = { graphicsQueueCreateInfo ,presentQueueCreateInfo };
}
VkDeviceCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
createInfo.pQueueCreateInfos = queueCreateInfo.data();
createInfo.queueCreateInfoCount = queueCreateInfoCount;
createInfo.enabledExtensionCount = 0;
createInfo.enabledLayerCount = 0;
std::vector<const char*> deviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
VkPhysicalDeviceFeatures supportedFeatures = {};
VkPhysicalDeviceFeatures requiredFeatures = {};
vkGetPhysicalDeviceFeatures(physicalDevice, &supportedFeatures);
requiredFeatures.multiDrawIndirect = supportedFeatures.multiDrawIndirect;
requiredFeatures.tessellationShader = VK_TRUE;
requiredFeatures.geometryShader = VK_TRUE;
requiredFeatures.samplerAnisotropy = VK_TRUE;
createInfo.pEnabledFeatures = &requiredFeatures;
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS)
{
throw std::runtime_error("failed to create logical device!");
}
}
|
|
|
Aspecto final
|
|
El
aspecto de la aplicación muestra la consola con el mensaje de
creación del dispositivo lógico.
|
|