Copiando dados de uma imagem para um staging buffer
Da mesma forma que fizemos anteriormente com o buffer de vértice, vamos primeiro criar um staging buffer na memória visível pela CPU para que possamos usar vkMapMemory
e copiar os pixels para ele. Embora seja possível criar uma imagem de staging para essa finalidade, o Vulkan também permite que copiemos pixels de um objeto VkBuffer
para um objeto VkImage
, e a API para isso é mais rápida em alguns hardwares (HEBERT, 2016). Adicionamos as variáveis para este buffer temporário na função addTextureImage
:
VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
Para a criação do staging buffer utilizamos nossa função auxiliar createBuffer
. O buffer deve estar na memória visível do host para que possamos mapeá-lo e ele deve ser usado como uma fonte de transferência para que possamos copiá-lo para uma imagem mais tarde, para isso, usamos os sinalizadores VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
e VK_BUFFER_USAGE_TRANSFER_SRC_BIT
, respectivamente:
createBuffer(
imageSize,
VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT
| VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
stagingBuffer,
stagingBufferMemory
);
Também utilizamos aqui o sinalizador VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
para solicitar que as gravações na memória pelo host sejam visíveis para o dispositivo (e vice-versa) sem a necessidade de liberar os caches de memória.
Podemos então copiar diretamente os valores de pixels que recebemos do objeto QImage
para o buffer, da mesma forma que fizemos para o buffer de vértice:
void *data;
VkDevice device = m_window->device();
m_deviceFunctions->vkMapMemory(
device,
stagingBufferMemory,
0,
imageSize,
0,
&data
);
memcpy(data, image.constBits(), static_cast<size_t>(imageSize));
m_deviceFunctions->vkUnmapMemory(device, stagingBufferMemory);