Escuela Técnica Superior de Ingeniería

 

Grado en Ingeniería Informática

Animación por Ordenador

Curso 2025/2026

 

Práctica 1d

Creación de la superficie

 

Objetivos

 

Añadir al proyecto la creación de la superficie que acogerá la imagen.

 

 

Superficies

 

El núcleo de Vulkan contiene las funciones dedicadas a configurar los procesos a ejecutar en las tarjetas gráficas y otros dispositivos de computación paralela. El proceso de mostrar el resultado en una ventana se conoce como presentación y no forma parte del núcleo.

Para mostrar los gráficos en una ventana, Vulkan utiliza varias extensiones que se conocen comúnmente como WSI (Window System Integration). Vulkan ofrece una extensión llamada VK_KHR_surface que describe las funciones y estructuras genéricas necesarias para desarrollar el proceso de presentación. Esta extensión contiene la definición de la estructura VkSurfaceKHR, que describe un superficie sobre la que se puede realizar la presentación de una imagen.

Además de esta extensión genérica, en cada plataforma hay que incluir una extensión específica. El estándar de Vulkan ofrece ya numerosas extensiones para distintas plataformas: VK_KHR_win32_surface, VK_KHR_android_surface, VK_KHR_xcb_surface, VK_KHR_xlib_surface, VK_KHR_wayland_surface, VK_MVK_ios_surface, VK_MVK_macos_surface, VK_GGP_stream_descriptor_surface, VK_FUCHSIA_imagepipe_surface, VK_EXT_directfb_surface.

El uso de las funciones de las extensiones WSI es tan común que estas funciones se han declarado en la cabecera de Vulkan de forma que no hay que buscar los punteros a estas funciones a partir de su nombre. Para crear una superficie sobre la plataforma Windows se utiliza la función vkCreateWin32SurfaceKHR().

VkResult vkCreateWin32SurfaceKHR(
  VkInstance                         instance,
  const VkWin32SurfaceCreateInfoKHR* pCreateInfo,
  const VkAllocationCallbacks*       pAllocator,
  VkSurfaceKHR*                      pSurface);

La información necesaria para crear una superficie sobre Windows incluye las referencias a los manejadores (hinstance y hwnd) asociados a la aplicación o módulo y a la ventana de la interfaz gráfica. El campo sType debe tener el valor VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR. Los campos pNext y flags no se utilizan por el momento.

typedef struct VkWin32SurfaceCreateInfoKHR {
  VkStructureType              sType;
  const void*                  pNext;
  VkWin32SurfaceCreateFlagsKHR flags;
  HINSTANCE                    hinstance;
  HWND                         hwnd;
} VkWin32SurfaceCreateInfoKHR;

GLFW contiene funciones que facilitan la construcción superficies, como glfwGetRequiredInstanceExtensions(), que obtiene los nombres de las extensiones necesarias, o glfwCreateWindowSurface(), que genera la superficie sin necesidad de obtener los manejadores.

VkResult glfwCreateWindowSurface (
  VkInstance                   instance,
  GLFWwindow*                  window,
  const VkAllocationCallbacks* allocator,
  VkSurfaceKHR*                surface);

No todos los dispositivos físicos soportan la capacidad de presentar imágenes sobre una superficie. Para comprobarlo se puede utilizar una función genérica o una función específica de la plataforma utilizada. La comprobación se realiza sobre las familias de colas que soporta el dispositivo.

VkResult vkGetPhysicalDeviceSurfaceSupportKHR( 
  VkPhysicalDevice physicalDevice, 
  uint32_t         queueFamilyIndex,
  VkSurfaceKHR     surface, 
  VkBool32*        pSupported);

VkBool32 vkGetPhysicalDeviceWin32PresentationSupportKHR(
  VkPhysicalDevice physicalDevice, 
  uint32_t         queueFamilyIndex);

 

 

Modificaciones de la clase GEGraphicsContext

 

Para gestionar la superficie se deben incluir en la clase GEGraphicsContext un nuevo campo de tipo VkSurfaceKHR. Además se incluye un nuevo método, createSurface(), dedicado a la creación de la superficie.

#pragma once

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <vulkan/vulkan.h>

class GEGraphicsContext
{
public:
  VkInstance instance;
  VkSurfaceKHR surface;

private:

public:
  GEGraphicsContext(GLFWwindow* window);
  ~GEGraphicsContext();

private:
  // Métodos de inicialización de Vulkan
  void createInstance();
  void createSurface(GLFWwindow* window);

  // Métodos auxiliares
  void showInstanceProperties();
};

En el código de la clase es necesario añadir el nuevo método y modificar el constructor y el destructor. El constructor debe añadir la llamada a la creación de la superficie. El destructor de la clase debe incluir la destrucción de la superfice creada.  El método createSurface() es el encargado de generar la superficie llamando a la función glfwCreateWindowSurface(), lo que nos evita tener que trabajar sobre los manejadores utilizados por Windows.

#include "CAVulkanState.h"

#include <iostream>

///////////////////////////////////////////////////////////////////////////////////
/////                                                                         /////
/////                          Métodos públicos                               /////
/////                                                                         /////
///////////////////////////////////////////////////////////////////////////////////

//
// FUNCIÓN: GEGraphicsContext::GEGraphicsContext()
//
// PROPÓSITO: Crea un contexto gráfico de Vulkan (instancia y superficie)
//
GEGraphicsContext::GEGraphicsContext(GLFWwindow* window)
{
  createInstance();
  createSurface(window);
  // showInstanceProperties();

  std::cout << "Surface created!" << std::endl;
}

//
// FUNCIÓN: GEGraphicsContext::~GEGraphicsContext()
//
// PROPÓSITO: Destruye el contexto gráfico
//
GEGraphicsContext::~GEGraphicsContext()
{
  vkDestroySurfaceKHR(instance, surface, nullptr);
  vkDestroyInstance(instance, nullptr);
}

///////////////////////////////////////////////////////////////////////////////////
/////                                                                         /////
/////                 Métodos de inicialización de Vulkan                     /////
/////                                                                         /////
///////////////////////////////////////////////////////////////////////////////////

//
// FUNCIÓN: GEGraphicsContext::createSurface(GLFWwindow* window)
//
// PROPÓSITO: Crea la superficie sobre la que mostrar la representación gráfica
//
void GEGraphicsContext::createSurface(GLFWwindow* window)
{
  if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS)
  {
    throw std::runtime_error("failed to create window surface!");
  }
}

 

 

Aspecto final

 

El aspecto de la aplicación muestra ahora el mensaje de creación de la superficie.

Figura19