Added Vulkan examples sources!

This commit is contained in:
saschawillems 2016-02-16 15:07:25 +01:00
parent 367fda186b
commit c91341813c
868 changed files with 514080 additions and 5584 deletions

402
base/vulkanMeshLoader.hpp Normal file
View file

@ -0,0 +1,402 @@
/*
* Simple wrapper for getting an index buffer and vertices out of an assimp mesh
*
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
#pragma once
#include <stdlib.h>
#include <string>
#include <fstream>
#include <assert.h>
#include <stdio.h>
#include <vector>
#include <map>
#ifdef _WIN32
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#else
#endif
#include "vulkan/vulkan.h"
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <assimp/cimport.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
namespace vkMeshLoader
{
typedef enum VertexLayout {
VERTEX_LAYOUT_POSITION = 0x0,
VERTEX_LAYOUT_NORMAL = 0x1,
VERTEX_LAYOUT_COLOR = 0x2,
VERTEX_LAYOUT_UV = 0x3,
VERTEX_LAYOUT_TANGENT = 0x4,
VERTEX_LAYOUT_BITANGENT = 0x5
} VertexLayout;
struct MeshBufferInfo
{
VkBuffer buf = VK_NULL_HANDLE;
VkDeviceMemory mem = VK_NULL_HANDLE;
};
struct MeshBuffer
{
MeshBufferInfo vertices;
MeshBufferInfo indices;
uint32_t indexCount;
};
// Get vertex size from vertex layout
static uint32_t vertexSize(std::vector<vkMeshLoader::VertexLayout> layout)
{
uint32_t vSize = 0;
for (auto& layoutDetail : layout)
{
switch (layoutDetail)
{
// UV only has two components
case VERTEX_LAYOUT_UV:
vSize += 2 * sizeof(float);
break;
default:
vSize += 3 * sizeof(float);
}
}
return vSize;
}
static void freeMeshBufferResources(VkDevice device, vkMeshLoader::MeshBuffer *meshBuffer)
{
vkDestroyBuffer(device, meshBuffer->vertices.buf, nullptr);
vkFreeMemory(device, meshBuffer->vertices.mem, nullptr);
if (meshBuffer->indices.buf != VK_NULL_HANDLE)
{
vkDestroyBuffer(device, meshBuffer->indices.buf, nullptr);
vkFreeMemory(device, meshBuffer->indices.mem, nullptr);
}
}
}
// Simple mesh class for getting all the necessary stuff from models loaded via ASSIMP
class VulkanMeshLoader {
private:
struct Vertex
{
glm::vec3 m_pos;
glm::vec2 m_tex;
glm::vec3 m_normal;
glm::vec3 m_color;
glm::vec3 m_tangent;
glm::vec3 m_binormal;
Vertex() {}
Vertex(const glm::vec3& pos, const glm::vec2& tex, const glm::vec3& normal, const glm::vec3& tangent, const glm::vec3& bitangent, const glm::vec3& color)
{
m_pos = pos;
m_tex = tex;
m_normal = normal;
m_color = color;
m_tangent = tangent;
m_binormal = bitangent;
}
};
struct MeshEntry {
uint32_t NumIndices;
uint32_t MaterialIndex;
uint32_t vertexBase;
std::vector<Vertex> Vertices;
std::vector<unsigned int> Indices;
};
VkBool32 getMemoryType(VkPhysicalDeviceMemoryProperties deviceMemoryProperties, uint32_t typeBits, VkFlags properties, uint32_t * typeIndex)
{
for (int i = 0; i < 32; i++)
{
if ((typeBits & 1) == 1)
{
if ((deviceMemoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
{
*typeIndex = i;
return true;
}
}
typeBits >>= 1;
}
return false;
}
public:
std::vector<MeshEntry> m_Entries;
struct Dimension
{
glm::vec3 min = glm::vec3(FLT_MAX);
glm::vec3 max = glm::vec3(-FLT_MAX);
glm::vec3 size;
} dim;
uint32_t numVertices = 0;
// Optional
struct
{
VkBuffer buf;
VkDeviceMemory mem;
} vertexBuffer;
struct {
VkBuffer buf;
VkDeviceMemory mem;
uint32_t count;
} indexBuffer;
VkPipelineVertexInputStateCreateInfo vi;
std::vector<VkVertexInputBindingDescription> bindingDescriptions;
std::vector<VkVertexInputAttributeDescription> attributeDescriptions;
VkPipeline pipeline;
Assimp::Importer Importer;
const aiScene* pScene;
~VulkanMeshLoader()
{
m_Entries.clear();
}
// Loads the mesh with some default flags
bool LoadMesh(const std::string& Filename)
{
int flags = aiProcess_FlipWindingOrder | aiProcess_Triangulate | aiProcess_PreTransformVertices | aiProcess_CalcTangentSpace | aiProcess_GenSmoothNormals;
return LoadMesh(Filename, flags);
}
// Load the mesh with custom flags
bool LoadMesh(const std::string& Filename, int flags)
{
pScene = Importer.ReadFile(Filename.c_str(), flags);
if (pScene)
{
return InitFromScene(pScene, Filename);
}
else
{
printf("Error parsing '%s': '%s'\n", Filename.c_str(), Importer.GetErrorString());
return false;
}
}
bool InitFromScene(const aiScene* pScene, const std::string& Filename)
{
m_Entries.resize(pScene->mNumMeshes);
// Counters
for (unsigned int i = 0; i < m_Entries.size(); i++)
{
m_Entries[i].vertexBase = numVertices;
numVertices += pScene->mMeshes[i]->mNumVertices;;
}
// Initialize the meshes in the scene one by one
for (unsigned int i = 0; i < m_Entries.size(); i++)
{
const aiMesh* paiMesh = pScene->mMeshes[i];
InitMesh(i, paiMesh, pScene);
}
return true;
}
void InitMesh(unsigned int index, const aiMesh* paiMesh, const aiScene* pScene)
{
m_Entries[index].MaterialIndex = paiMesh->mMaterialIndex;
aiColor3D pColor(0.f, 0.f, 0.f);
pScene->mMaterials[paiMesh->mMaterialIndex]->Get(AI_MATKEY_COLOR_DIFFUSE, pColor);
aiVector3D Zero3D(0.0f, 0.0f, 0.0f);
for (unsigned int i = 0; i < paiMesh->mNumVertices; i++) {
aiVector3D* pPos = &(paiMesh->mVertices[i]);
aiVector3D* pNormal = &(paiMesh->mNormals[i]);
aiVector3D *pTexCoord;
if (paiMesh->HasTextureCoords(0))
{
pTexCoord = &(paiMesh->mTextureCoords[0][i]);
}
else {
pTexCoord = &Zero3D;
}
aiVector3D* pTangent = (paiMesh->HasTangentsAndBitangents()) ? &(paiMesh->mTangents[i]) : &Zero3D;
aiVector3D* pBiTangent = (paiMesh->HasTangentsAndBitangents()) ? &(paiMesh->mBitangents[i]) : &Zero3D;
Vertex v(glm::vec3(pPos->x, -pPos->y, pPos->z),
glm::vec2(pTexCoord->x , pTexCoord->y),
glm::vec3(pNormal->x, pNormal->y, pNormal->z),
glm::vec3(pTangent->x, pTangent->y, pTangent->z),
glm::vec3(pBiTangent->x, pBiTangent->y, pBiTangent->z),
glm::vec3(pColor.r, pColor.g, pColor.b)
);
dim.max.x = fmax(pPos->x, dim.max.x);
dim.max.y = fmax(pPos->y, dim.max.y);
dim.max.z = fmax(pPos->z, dim.max.z);
dim.min.x = fmin(pPos->x, dim.min.x);
dim.min.y = fmin(pPos->y, dim.min.y);
dim.min.z = fmin(pPos->z, dim.min.z);
m_Entries[index].Vertices.push_back(v);
}
dim.size = dim.max - dim.min;
for (unsigned int i = 0; i < paiMesh->mNumFaces; i++)
{
const aiFace& Face = paiMesh->mFaces[i];
assert(Face.mNumIndices == 3);
m_Entries[index].Indices.push_back(Face.mIndices[0]);
m_Entries[index].Indices.push_back(Face.mIndices[1]);
m_Entries[index].Indices.push_back(Face.mIndices[2]);
}
}
// Clean up vulkan resources used by a mesh
static void freeVulkanResources(VkDevice device, VulkanMeshLoader *mesh)
{
vkDestroyBuffer(device, mesh->vertexBuffer.buf, nullptr);
vkFreeMemory(device, mesh->vertexBuffer.mem, nullptr);
vkDestroyBuffer(device, mesh->indexBuffer.buf, nullptr);
vkFreeMemory(device, mesh->indexBuffer.mem, nullptr);
}
// Create vertex and index buffer with given layout
void createVulkanBuffers(
VkDevice device,
VkPhysicalDeviceMemoryProperties deviceMemoryProperties,
vkMeshLoader::MeshBuffer *meshBuffer,
std::vector<vkMeshLoader::VertexLayout> layout,
float scale)
{
std::vector<float> vertexBuffer;
for (int m = 0; m < m_Entries.size(); m++)
{
for (int i = 0; i < m_Entries[m].Vertices.size(); i++)
{
// Push vertex data depending on layout
for (auto& layoutDetail : layout)
{
// Position
if (layoutDetail == vkMeshLoader::VERTEX_LAYOUT_POSITION)
{
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_pos.x * scale);
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_pos.y * scale);
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_pos.z * scale);
}
// Normal
if (layoutDetail == vkMeshLoader::VERTEX_LAYOUT_NORMAL)
{
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_normal.x);
vertexBuffer.push_back(-m_Entries[m].Vertices[i].m_normal.y);
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_normal.z);
}
// Texture coordinates
if (layoutDetail == vkMeshLoader::VERTEX_LAYOUT_UV)
{
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_tex.s);
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_tex.t);
}
// Color
if (layoutDetail == vkMeshLoader::VERTEX_LAYOUT_COLOR)
{
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_color.r);
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_color.g);
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_color.b);
}
// Tangent
if (layoutDetail == vkMeshLoader::VERTEX_LAYOUT_TANGENT)
{
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_tangent.x);
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_tangent.y);
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_tangent.z);
}
// Bitangent
if (layoutDetail == vkMeshLoader::VERTEX_LAYOUT_BITANGENT)
{
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_binormal.x);
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_binormal.y);
vertexBuffer.push_back(m_Entries[m].Vertices[i].m_binormal.z);
}
// todo : add checks if vertex component exists
}
}
}
size_t vertexBufferSize = vertexBuffer.size() * sizeof(float);
std::vector<uint32_t> indexBuffer;
for (uint32_t m = 0; m < m_Entries.size(); m++)
{
uint32_t indexBase = (uint32_t)indexBuffer.size();
for (uint32_t i = 0; i < m_Entries[m].Indices.size(); i++)
{
indexBuffer.push_back(m_Entries[m].Indices[i] + indexBase);
}
}
size_t indexBufferSize = indexBuffer.size() * sizeof(uint32_t);
VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo();
VkMemoryRequirements memReqs;
VkResult err;
void *data;
// Generate vertex buffer
VkBufferCreateInfo vBufferInfo = vkTools::initializers::bufferCreateInfo(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, vertexBufferSize);
err = vkCreateBuffer(device, &vBufferInfo, nullptr, &meshBuffer->vertices.buf);
assert(!err);
vkGetBufferMemoryRequirements(device, meshBuffer->vertices.buf, &memReqs);
memAlloc.allocationSize = memReqs.size;
getMemoryType(deviceMemoryProperties, memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAlloc.memoryTypeIndex);
err = vkAllocateMemory(device, &memAlloc, nullptr, &meshBuffer->vertices.mem);
assert(!err);
err = vkMapMemory(device, meshBuffer->vertices.mem, 0, vertexBufferSize, 0, &data);
assert(!err);
memcpy(data, vertexBuffer.data(), vertexBufferSize);
vkUnmapMemory(device, meshBuffer->vertices.mem);
err = vkBindBufferMemory(device, meshBuffer->vertices.buf, meshBuffer->vertices.mem, 0);
assert(!err);
// Generate index buffer
VkBufferCreateInfo iBufferInfo = vkTools::initializers::bufferCreateInfo(VK_BUFFER_USAGE_INDEX_BUFFER_BIT, indexBufferSize);
err = vkCreateBuffer(device, &iBufferInfo, nullptr, &meshBuffer->indices.buf);
assert(!err);
vkGetBufferMemoryRequirements(device, meshBuffer->indices.buf, &memReqs);
memAlloc.allocationSize = memReqs.size;
getMemoryType(deviceMemoryProperties, memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAlloc.memoryTypeIndex);
err = vkAllocateMemory(device, &memAlloc, nullptr, &meshBuffer->indices.mem);
assert(!err);
err = vkMapMemory(device, meshBuffer->indices.mem, 0, indexBufferSize, 0, &data);
assert(!err);
memcpy(data, indexBuffer.data(), indexBufferSize);
vkUnmapMemory(device, meshBuffer->indices.mem);
err = vkBindBufferMemory(device, meshBuffer->indices.buf, meshBuffer->indices.mem, 0);
assert(!err);
meshBuffer->indexCount = (uint32_t)indexBuffer.size();
}
};

View file

@ -0,0 +1,557 @@
/*
* Simple texture loader for Vulkan
*
* Note : No mip maps (yet), only uses optimal tiling (unless linear is forced)
*
* Copyright (C) 2015 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
#pragma once
#include <vulkan/vulkan.h>
#include <gli/gli.hpp>
namespace vkTools
{
struct VulkanTexture
{
VkSampler sampler;
VkImage image;
VkImageLayout imageLayout;
VkDeviceMemory deviceMemory;
VkImageView view;
uint32_t width, height;
uint32_t mipLevels;
};
class VulkanTextureLoader
{
private:
VkPhysicalDevice physicalDevice;
VkDevice device;
VkQueue queue;
VkCommandBuffer cmdBuffer;
VkCommandPool cmdPool;
VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
// Try to find appropriate memory type for a memory allocation
VkBool32 getMemoryType(uint32_t typeBits, VkFlags properties, uint32_t *typeIndex)
{
for (int i = 0; i < 32; i++) {
if ((typeBits & 1) == 1) {
if ((deviceMemoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
{
*typeIndex = i;
return true;
}
}
typeBits >>= 1;
}
return false;
}
public:
// Load a 2D texture
void loadTexture(const char* filename, VkFormat format, VulkanTexture *texture)
{
loadTexture(filename, format, texture, false);
}
// Load a 2D texture
void loadTexture(const char* filename, VkFormat format, VulkanTexture *texture, bool forceLinear)
{
gli::texture2D tex2D(gli::load(filename));
assert(!tex2D.empty());
texture->width = (uint32_t)tex2D[0].dimensions().x;
texture->height = (uint32_t)tex2D[0].dimensions().y;
VkResult err;
// Get device properites for the requested texture format
VkFormatProperties formatProperties;
vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties);
// Only use linear tiling if requested (and supported by the device)
// Support for linear tiling is mostly limited, so prefer to use
// optimal tiling instead
// On most implementations linear tiling will only support a very
// limited amount of formats and features (mip maps, cubemaps, arrays, etc.)
VkBool32 useStaging = true;
// Only use linear tiling if forced
if (forceLinear)
{
useStaging = formatProperties.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
}
VkImageCreateInfo imageCreateInfo = {};
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCreateInfo.pNext = NULL;
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = format;
imageCreateInfo.extent = { texture->width, texture->height, 1 };
imageCreateInfo.mipLevels = 1;
imageCreateInfo.arrayLayers = 1;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR;
imageCreateInfo.usage = (useStaging) ? VK_IMAGE_USAGE_TRANSFER_SRC_BIT : VK_IMAGE_USAGE_SAMPLED_BIT;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.flags = 0;
VkMemoryAllocateInfo memAllocInfo = {};
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAllocInfo.pNext = NULL;
memAllocInfo.allocationSize = 0;
memAllocInfo.memoryTypeIndex = 0;
VkImage mappableImage;
VkDeviceMemory mappableMemory;
// Create base image, if linear texturing is forced
// this can directly be used
err = vkCreateImage(device, &imageCreateInfo, nullptr, &mappableImage);
assert(!err);
// Get memory requirements for this image
// like size and alignment
VkMemoryRequirements memReqs;
vkGetImageMemoryRequirements(device, mappableImage, &memReqs);
// Set memory allocation size to required memory size
memAllocInfo.allocationSize = memReqs.size;
// Get memory type that can be mapped to host memory
getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAllocInfo.memoryTypeIndex);
// Allocate host memory
err = vkAllocateMemory(device, &memAllocInfo, nullptr, &(mappableMemory));
assert(!err);
// Bind allocated image for use
err = vkBindImageMemory(device, mappableImage, mappableMemory, 0);
assert(!err);
// Get sub resource layout
// Mip map count, array layer, etc.
VkImageSubresource subRes = {};
subRes.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
subRes.mipLevel = 0;
subRes.arrayLayer = 0;
VkSubresourceLayout subResLayout;
void *data;
// Get sub resources layout
// Includes row pitch, size offsets, etc.
vkGetImageSubresourceLayout(device, mappableImage, &subRes, &subResLayout);
// Map image memory
err = vkMapMemory(device, mappableMemory, 0, memReqs.size, 0, &data);
assert(!err);
// Copy image data into memory
memcpy(data, tex2D[subRes.mipLevel].data(), tex2D[subRes.mipLevel].size());
vkUnmapMemory(device, mappableMemory);
if (useStaging)
{
VkCommandBufferBeginInfo cmdBufInfo = {};
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdBufInfo.pNext = NULL;
err = vkBeginCommandBuffer(cmdBuffer, &cmdBufInfo);
assert(!err);
// Setup texture as blit target with optimal tiling
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
err = vkCreateImage(device, &imageCreateInfo, nullptr, &texture->image);
assert(!err);
vkGetImageMemoryRequirements(device, texture->image, &memReqs);
memAllocInfo.allocationSize = memReqs.size;
// Get device only memory type
getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAllocInfo.memoryTypeIndex);
// Allocate device memory
err = vkAllocateMemory(device, &memAllocInfo, nullptr, &texture->deviceMemory);
assert(!err);
// Bind allocated image for use
err = vkBindImageMemory(device, texture->image, texture->deviceMemory, 0);
assert(!err);
// Image barrier for linear image (base)
// Linear image will be used as a source for the blit
setImageLayout(cmdBuffer,
mappableImage,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
// Image barrier for optimal image (target)
// Optimal image will be used as a target for the blit
setImageLayout(cmdBuffer,
texture->image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
// Copy region for image blit
VkImageCopy copyRegion = {};
copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copyRegion.srcSubresource.baseArrayLayer = 0;
copyRegion.srcSubresource.mipLevel = 0;
copyRegion.srcSubresource.layerCount = 1;
copyRegion.srcOffset = { 0, 0, 0 };
copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copyRegion.dstSubresource.baseArrayLayer = 0;
copyRegion.dstSubresource.mipLevel = 0;
copyRegion.dstSubresource.layerCount = 1;
copyRegion.dstOffset = { 0, 0, 0 };
copyRegion.extent.width = texture->width;
copyRegion.extent.height = texture->height;
copyRegion.extent.depth = 1;
// Put image copy into command buffer
vkCmdCopyImage(cmdBuffer,
mappableImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &copyRegion);
// Change texture image layout to shader read after the copy
texture->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
setImageLayout(cmdBuffer,
texture->image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
texture->imageLayout);
err = vkEndCommandBuffer(cmdBuffer);
assert(!err);
VkFence nullFence = { VK_NULL_HANDLE };
VkSubmitInfo submitInfo = vkTools::initializers::submitInfo();
submitInfo.waitSemaphoreCount = 0;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &cmdBuffer;
err = vkQueueSubmit(queue, 1, &submitInfo, nullFence);
assert(!err);
err = vkQueueWaitIdle(queue);
assert(!err);
}
else
{
// Linear tiled images don't need to be staged
// and can be directly used as textures
texture->image = mappableImage;
texture->deviceMemory = mappableMemory;
texture->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
// Setup image memory barrier
setImageLayout(cmdBuffer,
texture->image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
texture->imageLayout);
}
// Create sampler
// In Vulkan textures are accessed by samplers
// This separates all the sampling information from the
// texture data
// This means you could have multiple sampler objects
// for the same texture with different settings
// This is similar to the samplers available with OpenGL 3.3
VkSamplerCreateInfo sampler = {};
sampler.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
sampler.magFilter = VK_FILTER_LINEAR;
sampler.minFilter = VK_FILTER_LINEAR;
sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
sampler.mipLodBias = 0.0f;
sampler.maxAnisotropy = 0;
sampler.compareOp = VK_COMPARE_OP_NEVER;
sampler.minLod = 0.0f;
sampler.maxLod = 0.0f;
sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
err = vkCreateSampler(device, &sampler, nullptr, &texture->sampler);
assert(!err);
// Create image view
// Textures are not directly accessed by the shaders and
// are abstracted by image views containing additional
// information and sub resource ranges
VkImageViewCreateInfo view = {};
view.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
view.pNext = NULL;
view.image = VK_NULL_HANDLE;
view.viewType = VK_IMAGE_VIEW_TYPE_2D;
view.format = format;
view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
view.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
view.image = texture->image;
err = vkCreateImageView(device, &view, nullptr, &texture->view);
assert(!err);
if (useStaging)
{
vkDestroyImage(device, mappableImage, nullptr);
vkFreeMemory(device, mappableMemory, nullptr);
}
}
// Clean up vulkan resources used by a texture object
void destroyTexture(VulkanTexture texture)
{
vkDestroyImageView(device, texture.view, nullptr);
vkDestroyImage(device, texture.image, nullptr);
vkDestroySampler(device, texture.sampler, nullptr);
vkFreeMemory(device, texture.deviceMemory, nullptr);
}
VulkanTextureLoader(VkPhysicalDevice physicalDevice, VkDevice device, VkQueue queue, VkCommandPool cmdPool)
{
this->physicalDevice = physicalDevice;
this->device = device;
this->queue = queue;
this->cmdPool = cmdPool;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties);
// Create command buffer for submitting image barriers
// and converting tilings
VkCommandBufferAllocateInfo cmdBufInfo = {};
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cmdBufInfo.commandPool = cmdPool;
cmdBufInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
cmdBufInfo.commandBufferCount = 1;
VkResult vkRes = vkAllocateCommandBuffers(device, &cmdBufInfo, &cmdBuffer);
assert(vkRes == VK_SUCCESS);
}
~VulkanTextureLoader()
{
vkFreeCommandBuffers(device, cmdPool, 1, &cmdBuffer);
}
// Load a cubemap texture (single file)
void loadCubemap(const char* filename, VkFormat format, VulkanTexture *texture)
{
VkFormatProperties formatProperties;
VkResult err;
gli::textureCube texCube(gli::load(filename));
assert(!texCube.empty());
texture->width = (uint32_t)texCube[0].dimensions().x;
texture->height = (uint32_t)texCube[0].dimensions().y;
// Get device properites for the requested texture format
vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProperties);
VkImageCreateInfo imageCreateInfo = vkTools::initializers::imageCreateInfo();
imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
imageCreateInfo.format = format;
imageCreateInfo.extent = { texture->width, texture->height, 1 };
imageCreateInfo.mipLevels = 1;
imageCreateInfo.arrayLayers = 1;
imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR;
imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageCreateInfo.flags = 0;
VkMemoryAllocateInfo memAllocInfo = vkTools::initializers::memoryAllocateInfo();
VkMemoryRequirements memReqs;
struct {
VkImage image;
VkDeviceMemory memory;
} cubeFace[6];
VkCommandBufferBeginInfo cmdBufInfo = {};
cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdBufInfo.pNext = NULL;
err = vkBeginCommandBuffer(cmdBuffer, &cmdBufInfo);
assert(!err);
// Load separate cube map faces into linear tiled textures
for (uint32_t face = 0; face < 6; ++face)
{
err = vkCreateImage(device, &imageCreateInfo, nullptr, &cubeFace[face].image);
assert(!err);
vkGetImageMemoryRequirements(device, cubeFace[face].image, &memReqs);
memAllocInfo.allocationSize = memReqs.size;
getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, &memAllocInfo.memoryTypeIndex);
err = vkAllocateMemory(device, &memAllocInfo, nullptr, &cubeFace[face].memory);
assert(!err);
err = vkBindImageMemory(device, cubeFace[face].image, cubeFace[face].memory, 0);
assert(!err);
VkImageSubresource subRes = {};
subRes.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
VkSubresourceLayout subResLayout;
void *data;
vkGetImageSubresourceLayout(device, cubeFace[face].image, &subRes, &subResLayout);
assert(!err);
err = vkMapMemory(device, cubeFace[face].memory, 0, memReqs.size, 0, &data);
assert(!err);
memcpy(data, texCube[face][subRes.mipLevel].data(), texCube[face][subRes.mipLevel].size());
vkUnmapMemory(device, cubeFace[face].memory);
// Image barrier for linear image (base)
// Linear image will be used as a source for the copy
setImageLayout(
cmdBuffer,
cubeFace[face].image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
}
// Transfer cube map faces to optimal tiling
// Setup texture as blit target with optimal tiling
imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
imageCreateInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT;
imageCreateInfo.arrayLayers = 6;
err = vkCreateImage(device, &imageCreateInfo, nullptr, &texture->image);
assert(!err);
vkGetImageMemoryRequirements(device, texture->image, &memReqs);
memAllocInfo.allocationSize = memReqs.size;
getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &memAllocInfo.memoryTypeIndex);
err = vkAllocateMemory(device, &memAllocInfo, nullptr, &texture->deviceMemory);
assert(!err);
err = vkBindImageMemory(device, texture->image, texture->deviceMemory, 0);
assert(!err);
// Image barrier for optimal image (target)
// Optimal image will be used as destination for the copy
setImageLayout(
cmdBuffer,
texture->image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
// Copy cube map faces one by one
for (uint32_t face = 0; face < 6; ++face)
{
// Copy region for image blit
VkImageCopy copyRegion = {};
copyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copyRegion.srcSubresource.baseArrayLayer = 0;
copyRegion.srcSubresource.mipLevel = 0;
copyRegion.srcSubresource.layerCount = 1;
copyRegion.srcOffset = { 0, 0, 0 };
copyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
copyRegion.dstSubresource.baseArrayLayer = face;
copyRegion.dstSubresource.mipLevel = 0;
copyRegion.dstSubresource.layerCount = 1;
copyRegion.dstOffset = { 0, 0, 0 };
copyRegion.extent.width = texture->width;
copyRegion.extent.height = texture->height;
copyRegion.extent.depth = 1;
// Put image copy into command buffer
vkCmdCopyImage(
cmdBuffer,
cubeFace[face].image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
texture->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &copyRegion);
// Change texture image layout to shader read after the copy
texture->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
setImageLayout(
cmdBuffer,
texture->image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
texture->imageLayout);
}
err = vkEndCommandBuffer(cmdBuffer);
assert(!err);
VkFence nullFence = { VK_NULL_HANDLE };
VkSubmitInfo submitInfo = vkTools::initializers::submitInfo();
submitInfo.waitSemaphoreCount = 0;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &cmdBuffer;
err = vkQueueSubmit(queue, 1, &submitInfo, nullFence);
assert(!err);
err = vkQueueWaitIdle(queue);
assert(!err);
// Create sampler
VkSamplerCreateInfo sampler = vkTools::initializers::samplerCreateInfo();
sampler.magFilter = VK_FILTER_LINEAR;
sampler.minFilter = VK_FILTER_LINEAR;
sampler.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
sampler.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
sampler.addressModeV = sampler.addressModeU;
sampler.addressModeW = sampler.addressModeU;
sampler.mipLodBias = 0.0f;
sampler.maxAnisotropy = 8;
sampler.compareOp = VK_COMPARE_OP_NEVER;
sampler.minLod = 0.0f;
sampler.maxLod = 0.0f;
sampler.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE;
err = vkCreateSampler(device, &sampler, nullptr, &texture->sampler);
assert(!err);
// Create image view
VkImageViewCreateInfo view = vkTools::initializers::imageViewCreateInfo();
view.image = VK_NULL_HANDLE;
view.viewType = VK_IMAGE_VIEW_TYPE_CUBE;
view.format = format;
view.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A };
view.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
view.subresourceRange.layerCount = 6;
view.image = texture->image;
err = vkCreateImageView(device, &view, nullptr, &texture->view);
assert(!err);
// Cleanup
for (auto& face : cubeFace)
{
vkDestroyImage(device, face.image, nullptr);
vkFreeMemory(device, face.memory, nullptr);
}
}
};
};

217
base/vulkanandroid.cpp Normal file
View file

@ -0,0 +1,217 @@
/*
* Android Vulkan function pointer loader
*
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
#include "vulkanandroid.h"
#ifdef __ANDROID__
#include <android/log.h>
#include <dlfcn.h>
PFN_vkCreateInstance vkCreateInstance;
PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
PFN_vkCreateDevice vkCreateDevice;
PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties;
PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties;
PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures;
PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties;
PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
PFN_vkCreateShaderModule vkCreateShaderModule;
PFN_vkCreateBuffer vkCreateBuffer;
PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
PFN_vkMapMemory vkMapMemory;
PFN_vkUnmapMemory vkUnmapMemory;
PFN_vkBindBufferMemory vkBindBufferMemory;
PFN_vkDestroyBuffer vkDestroyBuffer;
PFN_vkAllocateMemory vkAllocateMemory;
PFN_vkBindImageMemory vkBindImageMemory;
PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout;
PFN_vkCmdCopyImage vkCmdCopyImage;
PFN_vkCreateSampler vkCreateSampler;
PFN_vkDestroyImage vkDestroyImage;
PFN_vkFreeMemory vkFreeMemory;
PFN_vkCreateRenderPass vkCreateRenderPass;
PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
PFN_vkCmdEndRenderPass vkCmdEndRenderPass;
PFN_vkCreateImage vkCreateImage;
PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
PFN_vkCreateImageView vkCreateImageView;
PFN_vkDestroyImageView vkDestroyImageView;
PFN_vkCreateSemaphore vkCreateSemaphore;
PFN_vkDestroySemaphore vkDestroySemaphore;
PFN_vkCreateCommandPool vkCreateCommandPool;
PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
PFN_vkEndCommandBuffer vkEndCommandBuffer;
PFN_vkGetDeviceQueue vkGetDeviceQueue;
PFN_vkQueueSubmit vkQueueSubmit;
PFN_vkQueueWaitIdle vkQueueWaitIdle;
PFN_vkCreateFramebuffer vkCreateFramebuffer;
PFN_vkCreatePipelineCache vkCreatePipelineCache;
PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
PFN_vkCreateComputePipelines vkCreateComputePipelines;
PFN_vkCreateDescriptorPool vkCreateDescriptorPool;
PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout;
PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets;
PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets;
PFN_vkCmdBindPipeline vkCmdBindPipeline;
PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers;
PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer;
PFN_vkCmdSetViewport vkCmdSetViewport;
PFN_vkCmdSetScissor vkCmdSetScissor;
PFN_vkCmdDrawIndexed vkCmdDrawIndexed;
PFN_vkCmdDraw vkCmdDraw;
PFN_vkCmdDispatch vkCmdDispatch;
PFN_vkDestroyPipeline vkDestroyPipeline;
PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout;
PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout;
PFN_vkDestroyDevice vkDestroyDevice;
PFN_vkDestroyInstance vkDestroyInstance;
PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool;
PFN_vkFreeCommandBuffers vkFreeCommandBuffers;
PFN_vkDestroyRenderPass vkDestroyRenderPass;
PFN_vkDestroyFramebuffer vkDestroyFramebuffer;
PFN_vkDestroyShaderModule vkDestroyShaderModule;
PFN_vkDestroyPipelineCache vkDestroyPipelineCache;
PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR;
PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
void *libVulkan;
// Dynamically load Vulkan library and base function pointers
bool loadVulkanLibrary()
{
__android_log_print(ANDROID_LOG_INFO, "vulkanandroid", "Loading libvulkan.so...\n");
// Load vulkan library
libVulkan = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
if (!libVulkan)
{
__android_log_print(ANDROID_LOG_INFO, "vulkanandroid", "Could not load vulkan library : %s!\n", dlerror());
return false;
}
// Load base function pointers
vkEnumerateInstanceExtensionProperties = reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(dlsym(libVulkan, "vkEnumerateInstanceExtensionProperties"));
vkEnumerateInstanceLayerProperties = reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(dlsym(libVulkan, "vkEnumerateInstanceLayerProperties"));
vkCreateInstance = reinterpret_cast<PFN_vkCreateInstance>(dlsym(libVulkan, "vkCreateInstance"));
vkGetInstanceProcAddr = reinterpret_cast<PFN_vkGetInstanceProcAddr>(dlsym(libVulkan, "vkGetInstanceProcAddr"));
vkGetDeviceProcAddr = reinterpret_cast<PFN_vkGetDeviceProcAddr>(dlsym(libVulkan, "vkGetDeviceProcAddr"));
return true;
}
// Load instance based Vulkan function pointers
void loadVulkanFunctions(VkInstance instance)
{
__android_log_print(ANDROID_LOG_INFO, "vulkanandroid", "Loading instance based function pointers...\n");
vkEnumeratePhysicalDevices = reinterpret_cast<PFN_vkEnumeratePhysicalDevices>(vkGetInstanceProcAddr(instance, "vkEnumeratePhysicalDevices"));
vkGetPhysicalDeviceProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties"));
vkEnumerateDeviceLayerProperties = reinterpret_cast<PFN_vkEnumerateDeviceLayerProperties>(vkGetInstanceProcAddr(instance, "vkEnumerateDeviceLayerProperties"));
vkEnumerateDeviceExtensionProperties = reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(vkGetInstanceProcAddr(instance, "vkEnumerateDeviceExtensionProperties"));
vkGetPhysicalDeviceQueueFamilyProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceQueueFamilyProperties>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceQueueFamilyProperties"));
vkGetPhysicalDeviceFeatures = reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures"));
vkCreateDevice = reinterpret_cast<PFN_vkCreateDevice>(vkGetInstanceProcAddr(instance, "vkCreateDevice"));
vkGetPhysicalDeviceFormatProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFormatProperties"));
vkGetPhysicalDeviceMemoryProperties = reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceMemoryProperties"));
vkCmdPipelineBarrier = reinterpret_cast<PFN_vkCmdPipelineBarrier>(vkGetInstanceProcAddr(instance, "vkCmdPipelineBarrier"));
vkCreateShaderModule = reinterpret_cast<PFN_vkCreateShaderModule>(vkGetInstanceProcAddr(instance, "vkCreateShaderModule"));
vkCreateBuffer = reinterpret_cast<PFN_vkCreateBuffer>(vkGetInstanceProcAddr(instance, "vkCreateBuffer"));
vkGetBufferMemoryRequirements = reinterpret_cast<PFN_vkGetBufferMemoryRequirements>(vkGetInstanceProcAddr(instance, "vkGetBufferMemoryRequirements"));
vkMapMemory = reinterpret_cast<PFN_vkMapMemory>(vkGetInstanceProcAddr(instance, "vkMapMemory"));
vkUnmapMemory = reinterpret_cast<PFN_vkUnmapMemory>(vkGetInstanceProcAddr(instance, "vkUnmapMemory"));
vkBindBufferMemory = reinterpret_cast<PFN_vkBindBufferMemory>(vkGetInstanceProcAddr(instance, "vkBindBufferMemory"));
vkDestroyBuffer = reinterpret_cast<PFN_vkDestroyBuffer>(vkGetInstanceProcAddr(instance, "vkDestroyBuffer"));
vkAllocateMemory = reinterpret_cast<PFN_vkAllocateMemory>(vkGetInstanceProcAddr(instance, "vkAllocateMemory"));
vkFreeMemory = reinterpret_cast<PFN_vkFreeMemory>(vkGetInstanceProcAddr(instance, "vkFreeMemory"));
vkCreateRenderPass = reinterpret_cast<PFN_vkCreateRenderPass>(vkGetInstanceProcAddr(instance, "vkCreateRenderPass"));
vkCmdBeginRenderPass = reinterpret_cast<PFN_vkCmdBeginRenderPass>(vkGetInstanceProcAddr(instance, "vkCmdBeginRenderPass"));
vkCmdEndRenderPass = reinterpret_cast<PFN_vkCmdEndRenderPass>(vkGetInstanceProcAddr(instance, "vkCmdEndRenderPass"));
vkCreateImage = reinterpret_cast<PFN_vkCreateImage>(vkGetInstanceProcAddr(instance, "vkCreateImage"));
vkGetImageMemoryRequirements = reinterpret_cast<PFN_vkGetImageMemoryRequirements>(vkGetInstanceProcAddr(instance, "vkGetImageMemoryRequirements"));
vkCreateImageView = reinterpret_cast<PFN_vkCreateImageView>(vkGetInstanceProcAddr(instance, "vkCreateImageView"));
vkDestroyImageView = reinterpret_cast<PFN_vkDestroyImageView>(vkGetInstanceProcAddr(instance, "vkDestroyImageView"));
vkBindImageMemory = reinterpret_cast<PFN_vkBindImageMemory>(vkGetInstanceProcAddr(instance, "vkBindImageMemory"));
vkGetImageSubresourceLayout = reinterpret_cast<PFN_vkGetImageSubresourceLayout>(vkGetInstanceProcAddr(instance, "vkGetImageSubresourceLayout"));
vkCmdCopyImage = reinterpret_cast<PFN_vkCmdCopyImage>(vkGetInstanceProcAddr(instance, "vkCmdCopyImage"));
vkDestroyImage = reinterpret_cast<PFN_vkDestroyImage>(vkGetInstanceProcAddr(instance, "vkDestroyImage"));
vkCreateSampler = reinterpret_cast<PFN_vkCreateSampler>(vkGetInstanceProcAddr(instance, "vkCreateSampler"));
vkCreateSemaphore = reinterpret_cast<PFN_vkCreateSemaphore>(vkGetInstanceProcAddr(instance, "vkCreateSemaphore"));
vkDestroySemaphore = reinterpret_cast<PFN_vkDestroySemaphore>(vkGetInstanceProcAddr(instance, "vkDestroySemaphore"));
vkCreateCommandPool = reinterpret_cast<PFN_vkCreateCommandPool>(vkGetInstanceProcAddr(instance, "vkCreateCommandPool"));
vkAllocateCommandBuffers = reinterpret_cast<PFN_vkAllocateCommandBuffers>(vkGetInstanceProcAddr(instance, "vkAllocateCommandBuffers"));
vkBeginCommandBuffer = reinterpret_cast<PFN_vkBeginCommandBuffer>(vkGetInstanceProcAddr(instance, "vkBeginCommandBuffer"));
vkEndCommandBuffer = reinterpret_cast<PFN_vkEndCommandBuffer>(vkGetInstanceProcAddr(instance, "vkEndCommandBuffer"));
vkGetDeviceQueue = reinterpret_cast<PFN_vkGetDeviceQueue>(vkGetInstanceProcAddr(instance, "vkGetDeviceQueue"));
vkQueueSubmit = reinterpret_cast<PFN_vkQueueSubmit>(vkGetInstanceProcAddr(instance, "vkQueueSubmit"));
vkQueueWaitIdle = reinterpret_cast<PFN_vkQueueWaitIdle>(vkGetInstanceProcAddr(instance, "vkQueueWaitIdle"));
vkCreateFramebuffer = reinterpret_cast<PFN_vkCreateFramebuffer>(vkGetInstanceProcAddr(instance, "vkCreateFramebuffer"));
vkCreatePipelineCache = reinterpret_cast<PFN_vkCreatePipelineCache>(vkGetInstanceProcAddr(instance, "vkCreatePipelineCache"));
vkCreatePipelineLayout = reinterpret_cast<PFN_vkCreatePipelineLayout>(vkGetInstanceProcAddr(instance, "vkCreatePipelineLayout"));
vkCreateGraphicsPipelines = reinterpret_cast<PFN_vkCreateGraphicsPipelines>(vkGetInstanceProcAddr(instance, "vkCreateGraphicsPipelines"));
vkCreateComputePipelines = reinterpret_cast<PFN_vkCreateComputePipelines>(vkGetInstanceProcAddr(instance, "vkCreateComputePipelines"));
vkCreateDescriptorPool = reinterpret_cast<PFN_vkCreateDescriptorPool>(vkGetInstanceProcAddr(instance, "vkCreateDescriptorPool"));
vkCreateDescriptorSetLayout = reinterpret_cast<PFN_vkCreateDescriptorSetLayout>(vkGetInstanceProcAddr(instance, "vkCreateDescriptorSetLayout"));
vkAllocateDescriptorSets = reinterpret_cast<PFN_vkAllocateDescriptorSets>(vkGetInstanceProcAddr(instance, "vkAllocateDescriptorSets"));
vkUpdateDescriptorSets = reinterpret_cast<PFN_vkUpdateDescriptorSets>(vkGetInstanceProcAddr(instance, "vkUpdateDescriptorSets"));
vkCmdBindDescriptorSets = reinterpret_cast<PFN_vkCmdBindDescriptorSets>(vkGetInstanceProcAddr(instance, "vkCmdBindDescriptorSets"));
vkCmdBindPipeline = reinterpret_cast<PFN_vkCmdBindPipeline>(vkGetInstanceProcAddr(instance, "vkCmdBindPipeline"));
vkCmdBindVertexBuffers = reinterpret_cast<PFN_vkCmdBindVertexBuffers>(vkGetInstanceProcAddr(instance, "vkCmdBindVertexBuffers"));
vkCmdBindIndexBuffer = reinterpret_cast<PFN_vkCmdBindIndexBuffer>(vkGetInstanceProcAddr(instance, "vkCmdBindIndexBuffer"));
vkCmdSetViewport = reinterpret_cast<PFN_vkCmdSetViewport>(vkGetInstanceProcAddr(instance, "vkCmdSetViewport"));
vkCmdSetScissor = reinterpret_cast<PFN_vkCmdSetScissor>(vkGetInstanceProcAddr(instance, "vkCmdSetScissor"));
vkCmdDrawIndexed = reinterpret_cast<PFN_vkCmdDrawIndexed>(vkGetInstanceProcAddr(instance, "vkCmdDrawIndexed"));
vkCmdDraw = reinterpret_cast<PFN_vkCmdDraw>(vkGetInstanceProcAddr(instance, "vkCmdDraw"));
vkCmdDispatch = reinterpret_cast<PFN_vkCmdDispatch>(vkGetInstanceProcAddr(instance, "vkCmdDispatch"));
vkDestroyPipeline = reinterpret_cast<PFN_vkDestroyPipeline>(vkGetInstanceProcAddr(instance, "vkDestroyPipeline"));
vkDestroyPipelineLayout = reinterpret_cast<PFN_vkDestroyPipelineLayout>(vkGetInstanceProcAddr(instance, "vkDestroyPipelineLayout"));;
vkDestroyDescriptorSetLayout = reinterpret_cast<PFN_vkDestroyDescriptorSetLayout>(vkGetInstanceProcAddr(instance, "vkDestroyDescriptorSetLayout"));
vkDestroyDevice = reinterpret_cast<PFN_vkDestroyDevice>(vkGetInstanceProcAddr(instance, "vkDestroyDevice"));
vkDestroyInstance = reinterpret_cast<PFN_vkDestroyInstance>(vkGetInstanceProcAddr(instance, "vkDestroyInstance"));
vkDestroyDescriptorPool = reinterpret_cast<PFN_vkDestroyDescriptorPool>(vkGetInstanceProcAddr(instance, "vkDestroyDescriptorPool"));
vkFreeCommandBuffers = reinterpret_cast<PFN_vkFreeCommandBuffers>(vkGetInstanceProcAddr(instance, "vkFreeCommandBuffers"));
vkDestroyRenderPass = reinterpret_cast<PFN_vkDestroyRenderPass>(vkGetInstanceProcAddr(instance, "vkDestroyRenderPass"));
vkDestroyFramebuffer = reinterpret_cast<PFN_vkDestroyFramebuffer>(vkGetInstanceProcAddr(instance, "vkDestroyFramebuffer"));
vkDestroyShaderModule = reinterpret_cast<PFN_vkDestroyShaderModule>(vkGetInstanceProcAddr(instance, "vkDestroyShaderModule"));
vkDestroyPipelineCache = reinterpret_cast<PFN_vkDestroyPipelineCache>(vkGetInstanceProcAddr(instance, "vkDestroyPipelineCache"));
vkCreateAndroidSurfaceKHR = reinterpret_cast<PFN_vkCreateAndroidSurfaceKHR>(vkGetInstanceProcAddr(instance, "vkCreateAndroidSurfaceKHR"));
vkDestroySurfaceKHR = reinterpret_cast<PFN_vkDestroySurfaceKHR>(vkGetInstanceProcAddr(instance, "vkDestroySurfaceKHR"));
}
void freeVulkanLibrary()
{
dlclose(libVulkan);
}
#endif

115
base/vulkanandroid.h Normal file
View file

@ -0,0 +1,115 @@
/*
* Android Vulkan function pointer prototypes
*
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
#pragma once
#ifndef VULKANANDROID_H
#define VULKANANDROID_H
// Vulkan needs to be loaded dynamically on android
#pragma once
#ifndef VULKANANDROID_HPP
#define VULKANANDROID_HPP
#include "vulkan/vulkan.h"
#ifdef __ANDROID__
// Function pointer prototypes
// Not complete, just the functions used in the caps viewer!
extern PFN_vkCreateInstance vkCreateInstance;
extern PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr;
extern PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr;
extern PFN_vkCreateDevice vkCreateDevice;
extern PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices;
extern PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties;
extern PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties;
extern PFN_vkEnumerateDeviceLayerProperties vkEnumerateDeviceLayerProperties;
extern PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties;
extern PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeatures;
extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties;
extern PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties;
extern PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties;
extern PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties;
extern PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier;
extern PFN_vkCreateShaderModule vkCreateShaderModule;
extern PFN_vkCreateBuffer vkCreateBuffer;
extern PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements;
extern PFN_vkMapMemory vkMapMemory;
extern PFN_vkUnmapMemory vkUnmapMemory;
extern PFN_vkBindBufferMemory vkBindBufferMemory;
extern PFN_vkDestroyBuffer vkDestroyBuffer;
extern PFN_vkAllocateMemory vkAllocateMemory;
extern PFN_vkBindImageMemory vkBindImageMemory;
extern PFN_vkGetImageSubresourceLayout vkGetImageSubresourceLayout;
extern PFN_vkCmdCopyImage vkCmdCopyImage;
extern PFN_vkCreateSampler vkCreateSampler;
extern PFN_vkDestroyImage vkDestroyImage;
extern PFN_vkFreeMemory vkFreeMemory;
extern PFN_vkCreateRenderPass vkCreateRenderPass;
extern PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass;
extern PFN_vkCmdEndRenderPass vkCmdEndRenderPass;
extern PFN_vkCreateImage vkCreateImage;
extern PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements;
extern PFN_vkCreateImageView vkCreateImageView;
extern PFN_vkDestroyImageView vkDestroyImageView;
extern PFN_vkCreateSemaphore vkCreateSemaphore;
extern PFN_vkDestroySemaphore vkDestroySemaphore;
extern PFN_vkCreateCommandPool vkCreateCommandPool;
extern PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers;
extern PFN_vkBeginCommandBuffer vkBeginCommandBuffer;
extern PFN_vkEndCommandBuffer vkEndCommandBuffer;
extern PFN_vkGetDeviceQueue vkGetDeviceQueue;
extern PFN_vkQueueSubmit vkQueueSubmit;
extern PFN_vkQueueWaitIdle vkQueueWaitIdle;
extern PFN_vkCreateFramebuffer vkCreateFramebuffer;
extern PFN_vkCreatePipelineCache vkCreatePipelineCache;
extern PFN_vkCreatePipelineLayout vkCreatePipelineLayout;
extern PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines;
extern PFN_vkCreateComputePipelines vkCreateComputePipelines;
extern PFN_vkCreateDescriptorPool vkCreateDescriptorPool;
extern PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout;
extern PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets;
extern PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets;
extern PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets;
extern PFN_vkCmdBindPipeline vkCmdBindPipeline;
extern PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers;
extern PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer;
extern PFN_vkCmdSetViewport vkCmdSetViewport;
extern PFN_vkCmdSetScissor vkCmdSetScissor;
extern PFN_vkCmdDrawIndexed vkCmdDrawIndexed;
extern PFN_vkCmdDraw vkCmdDraw;
extern PFN_vkCmdDispatch vkCmdDispatch;
extern PFN_vkDestroyPipeline vkDestroyPipeline;
extern PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout;
extern PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout;
extern PFN_vkDestroyDevice vkDestroyDevice;
extern PFN_vkDestroyInstance vkDestroyInstance;
extern PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool;
extern PFN_vkFreeCommandBuffers vkFreeCommandBuffers;
extern PFN_vkDestroyRenderPass vkDestroyRenderPass;
extern PFN_vkDestroyFramebuffer vkDestroyFramebuffer;
extern PFN_vkDestroyShaderModule vkDestroyShaderModule;
extern PFN_vkDestroyPipelineCache vkDestroyPipelineCache;
extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR;
extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR;
bool loadVulkanLibrary();
void loadVulkanFunctions(VkInstance instance);
void freeVulkanLibrary();
#endif
#endif // VULKANANDROID_HPP
#endif // VULKANANDROID_H

91
base/vulkandebug.cpp Normal file
View file

@ -0,0 +1,91 @@
#include "vulkandebug.h"
#include <iostream>
namespace vkDebug
{
int validationLayerCount = 9;
const char *validationLayerNames[] =
{
"VK_LAYER_LUNARG_threading",
"VK_LAYER_LUNARG_mem_tracker",
"VK_LAYER_LUNARG_object_tracker",
"VK_LAYER_LUNARG_draw_state",
"VK_LAYER_LUNARG_param_checker",
"VK_LAYER_LUNARG_swapchain",
"VK_LAYER_LUNARG_device_limits",
"VK_LAYER_LUNARG_image",
"VK_LAYER_GOOGLE_unique_objects",
};
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallback;
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallback;
PFN_vkDebugReportMessageEXT dbgBreakCallback;
VkDebugReportCallbackEXT msgCallback;
VkBool32 messageCallback(
VkDebugReportFlagsEXT flags,
VkDebugReportObjectTypeEXT objType,
uint64_t srcObject,
size_t location,
int32_t msgCode,
const char* pLayerPrefix,
const char* pMsg,
void* pUserData)
{
char *message = (char *)malloc(strlen(pMsg) + 100);
assert(message);
if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
{
std::cout << "ERROR: " << "[" << pLayerPrefix << "] Code " << msgCode << " : " << pMsg << "\n";
}
else
if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
{
// Uncomment to see warnings
//std::cout << "WARNING: " << "[" << pLayerPrefix << "] Code " << msgCode << " : " << pMsg << "\n";
}
else
{
return false;
}
fflush(stdout);
free(message);
return false;
}
void setupDebugging(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportCallbackEXT callBack)
{
CreateDebugReportCallback = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT");
DestroyDebugReportCallback = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT");
dbgBreakCallback = (PFN_vkDebugReportMessageEXT)vkGetInstanceProcAddr(instance, "vkDebugReportMessageEXT");
VkDebugReportCallbackCreateInfoEXT dbgCreateInfo;
dbgCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
dbgCreateInfo.pNext = NULL;
dbgCreateInfo.pfnCallback = (PFN_vkDebugReportCallbackEXT)messageCallback;
dbgCreateInfo.pUserData = NULL;
dbgCreateInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
VkDebugReportCallbackEXT debugReportCallback;
VkResult err = CreateDebugReportCallback(
instance,
&dbgCreateInfo,
NULL,
&debugReportCallback);
assert(!err);
}
void freeDebugCallback(VkInstance instance)
{
if (msgCallback != nullptr)
{
DestroyDebugReportCallback(instance, msgCallback, nullptr);
}
}
}

45
base/vulkandebug.h Normal file
View file

@ -0,0 +1,45 @@
#pragma once
#include "vulkan/vulkan.h"
#include <math.h>
#include <stdlib.h>
#include <string>
#include <cstring>
#include <fstream>
#include <assert.h>
#include <stdio.h>
#include <vector>
#ifdef _WIN32
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#else
#endif
namespace vkDebug
{
// Default validation layers
extern int validationLayerCount;
extern const char *validationLayerNames[];
// Default debug callback
VkBool32 messageCallback(
VkDebugReportFlagsEXT flags,
VkDebugReportObjectTypeEXT objType,
uint64_t srcObject,
size_t location,
int32_t msgCode,
const char* pLayerPrefix,
const char* pMsg,
void* pUserData);
// Load debug function pointers and set debug callback
// if callBack is NULL, default message callback will be used
void setupDebugging(
VkInstance instance,
VkDebugReportFlagsEXT flags,
VkDebugReportCallbackEXT callBack);
// Clear debug callback
void freeDebugCallback(VkInstance instance);
}

1043
base/vulkanexamplebase.cpp Normal file

File diff suppressed because it is too large Load diff

237
base/vulkanexamplebase.h Normal file
View file

@ -0,0 +1,237 @@
/*
* Vulkan Example base class
*
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
#pragma once
#ifdef _WIN32
#pragma comment(linker, "/subsystem:windows")
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#else
// todo : split linux xcb/x11 and android
#include <xcb/xcb.h>
#endif
#include <iostream>
#include <chrono>
#define GLM_FORCE_RADIANS
#include <glm/glm.hpp>
#include <string>
#include <array>
#include "vulkan/vulkan.h"
#include "vulkantools.h"
#include "vulkandebug.h"
#include "vulkanswapchain.hpp"
#include "vulkanTextureLoader.hpp"
#include "vulkanMeshLoader.hpp"
#define deg_to_rad(deg) deg * float(M_PI / 180)
class VulkanExampleBase
{
private:
// Set to true when example is created with enabled validation layers
bool enableValidation = false;
// Create application wide Vulkan instance
VkResult createInstance(bool enableValidation);
// Create logical Vulkan device based on physical device
VkResult createDevice(VkDeviceQueueCreateInfo requestedQueues, bool enableValidation);
protected:
// Last frame time, measured using a high performance timer (if available)
float frameTimer = 1.0f;
// Vulkan instance, stores all per-application states
VkInstance instance;
// Physical device (GPU) that Vulkan will ise
VkPhysicalDevice physicalDevice;
// Stores all available memory (type) properties for the physical device
VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
// Logical device, application's view of the physical device (GPU)
VkDevice device;
// Handle to the device graphics queue that command buffers are submitted to
VkQueue queue;
// Color buffer format
VkFormat colorformat = VK_FORMAT_B8G8R8A8_UNORM;
// Depth buffer format
// Depth format is selected during Vulkan initialization
VkFormat depthFormat;
// Command buffer pool
VkCommandPool cmdPool;
// Command buffer used for setup
VkCommandBuffer setupCmdBuffer = VK_NULL_HANDLE;
// Command buffer for submitting a post present barrier
VkCommandBuffer postPresentCmdBuffer = VK_NULL_HANDLE;
// Command buffers used for rendering
std::vector<VkCommandBuffer> drawCmdBuffers;
// Global render pass for frame buffer writes
VkRenderPass renderPass;
// List of available frame buffers (same as number of swap chain images)
std::vector<VkFramebuffer>frameBuffers;
// Active frame buffer index
uint32_t currentBuffer = 0;
// Descriptor set pool
VkDescriptorPool descriptorPool;
// List of shader modules created (stored for cleanup)
std::vector<VkShaderModule> shaderModules;
// Pipeline cache object
VkPipelineCache pipelineCache;
// Wraps the swap chain to present images (framebuffers) to the windowing system
VulkanSwapChain swapChain;
// Simple texture loader
vkTools::VulkanTextureLoader *textureLoader = nullptr;
public:
bool prepared = false;
uint32_t width = 1280;
uint32_t height = 720;
VkClearColorValue defaultClearColor = { { 0.025f, 0.025f, 0.025f, 1.0f } };
float zoom = 0;
// Defines a frame rate independent timer value clamped from -1.0...1.0
// For use in animations, rotations, etc.
float timer = 0.0f;
// Multiplier for speeding up (or slowing down) the global timer
float timerSpeed = 0.25f;
bool paused = false;
// Use to adjust mouse rotation speed
float rotationSpeed = 1.0f;
// Use to adjust mouse zoom speed
float zoomSpeed = 1.0f;
glm::vec3 rotation = glm::vec3();
glm::vec2 mousePos;
std::string title = "Vulkan Example";
std::string name = "vulkanExample";
struct
{
VkImage image;
VkDeviceMemory mem;
VkImageView view;
} depthStencil;
// OS specific
#ifdef _WIN32
HWND window;
HINSTANCE windowInstance;
#else
struct {
bool left = false;
bool right = false;
} mouseButtons;
bool quit;
xcb_connection_t *connection;
xcb_screen_t *screen;
xcb_window_t window;
xcb_intern_atom_reply_t *atom_wm_delete_window;
#endif
VulkanExampleBase(bool enableValidation);
VulkanExampleBase() : VulkanExampleBase(false) {};
~VulkanExampleBase();
// Setup the vulkan instance, enable required extensions and connect to the physical device (GPU)
void initVulkan(bool enableValidation);
#ifdef _WIN32
void setupConsole(std::string title);
HWND setupWindow(HINSTANCE hinstance, WNDPROC wndproc);
void handleMessages(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
#else
xcb_window_t setupWindow();
void initxcbConnection();
void handleEvent(const xcb_generic_event_t *event);
#endif
// Pure virtual render function (override in derived class)
virtual void render() = 0;
// Called when view change occurs
// Can be overriden in derived class to e.g. update uniform buffers
// Containing view dependant matrices
virtual void viewChanged();
// Get memory type for a given memory allocation (flags and bits)
VkBool32 getMemoryType(uint32_t typeBits, VkFlags properties, uint32_t *typeIndex);
// Creates a new (graphics) command pool object storing command buffers
void createCommandPool();
// Setup default depth and stencil views
void setupDepthStencil();
// Create framebuffers for all requested swap chain images
void setupFrameBuffer();
// Setup a default render pass
void setupRenderPass();
// Connect and prepare the swap chain
void initSwapchain();
// Create swap chain images
void setupSwapChain();
// Check if command buffers are valid (!= VK_NULL_HANDLE)
bool checkCommandBuffers();
// Create command buffers for drawing commands
void createCommandBuffers();
// Destroy all command buffers and set their handles to VK_NULL_HANDLE
// May be necessary during runtime if options are toggled
void destroyCommandBuffers();
// Create command buffer for setup commands
void createSetupCommandBuffer();
// Finalize setup command bufferm submit it to the queue and remove it
void flushSetupCommandBuffer();
// Create a cache pool for rendering pipelines
void createPipelineCache();
// Prepare commonly used Vulkan functions
void prepare();
// Load a SPIR-V shader
VkPipelineShaderStageCreateInfo loadShader(const char* fileName, VkShaderStageFlagBits stage);
// Load a GLSL shader
// NOTE : This may not work with any IHV and requires some magic
VkPipelineShaderStageCreateInfo loadShaderGLSL(const char* fileName, VkShaderStageFlagBits stage);
// Create a buffer, fill it with data and bind buffer memory
// Can be used for e.g. vertex or index buffer based on mesh data
VkBool32 createBuffer(
VkBufferUsageFlags usage,
VkDeviceSize size,
void *data,
VkBuffer *buffer,
VkDeviceMemory *memory);
// Overload that assigns buffer info to descriptor
VkBool32 createBuffer(
VkBufferUsageFlags usage,
VkDeviceSize size,
void *data,
VkBuffer *buffer,
VkDeviceMemory *memory,
VkDescriptorBufferInfo *descriptor);
// Load a mesh (using ASSIMP) and create vulkan vertex and index buffers with given vertex layout
void loadMesh(
const char *filename,
vkMeshLoader::MeshBuffer *meshBuffer,
std::vector<vkMeshLoader::VertexLayout> vertexLayout,
float scale);
// Start the main render loop
void renderLoop();
// Submit a post present image barrier to the queue
// Transforms image layout back to color attachment layout
void submitPostPresentBarrier(VkImage image);
};

406
base/vulkanswapchain.hpp Normal file
View file

@ -0,0 +1,406 @@
/*
* Class wrapping access to the swap chain
*
* Copyright (C) 2015 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
#pragma once
#include <stdlib.h>
#include <string>
#include <fstream>
#include <assert.h>
#include <stdio.h>
#ifdef _WIN32
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#else
#endif
#include <vulkan/vulkan.h>
#include "vulkantools.h"
#ifdef __ANDROID__
#include "vulkanandroid.h"
#endif
// Macro to get a procedure address based on a vulkan instance
#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
{ \
fp##entrypoint = (PFN_vk##entrypoint) vkGetInstanceProcAddr(inst, "vk"#entrypoint); \
if (fp##entrypoint == NULL) \
{ \
exit(1); \
} \
}
// Macro to get a procedure address based on a vulkan device
#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \
{ \
fp##entrypoint = (PFN_vk##entrypoint) vkGetDeviceProcAddr(dev, "vk"#entrypoint); \
if (fp##entrypoint == NULL) \
{ \
exit(1); \
} \
}
typedef struct _SwapChainBuffers {
VkImage image;
VkImageView view;
} SwapChainBuffer;
class VulkanSwapChain
{
private:
VkInstance instance;
VkDevice device;
VkPhysicalDevice physicalDevice;
VkSurfaceKHR surface;
// Function pointers
PFN_vkGetPhysicalDeviceSurfaceSupportKHR fpGetPhysicalDeviceSurfaceSupportKHR;
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR fpGetPhysicalDeviceSurfaceCapabilitiesKHR;
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR fpGetPhysicalDeviceSurfaceFormatsKHR;
PFN_vkGetPhysicalDeviceSurfacePresentModesKHR fpGetPhysicalDeviceSurfacePresentModesKHR;
PFN_vkCreateSwapchainKHR fpCreateSwapchainKHR;
PFN_vkDestroySwapchainKHR fpDestroySwapchainKHR;
PFN_vkGetSwapchainImagesKHR fpGetSwapchainImagesKHR;
PFN_vkAcquireNextImageKHR fpAcquireNextImageKHR;
PFN_vkQueuePresentKHR fpQueuePresentKHR;
public:
VkFormat colorFormat;
VkColorSpaceKHR colorSpace;
VkImage* swapchainImages;
VkSwapchainKHR swapChain = VK_NULL_HANDLE;
uint32_t imageCount;
SwapChainBuffer* buffers;
// Index of the deteced graphics and presenting device queue
uint32_t queueNodeIndex = UINT32_MAX;
// wip naming
void initSwapChain(
#ifdef _WIN32
void* platformHandle, void* platformWindow
#else
#ifdef __ANDROID__
ANativeWindow* window
#else
xcb_connection_t* connection, xcb_window_t window
#endif
#endif
)
{
uint32_t queueCount;
VkQueueFamilyProperties *queueProps;
VkResult err;
// Create surface depending on OS
#ifdef _WIN32
VkWin32SurfaceCreateInfoKHR surfaceCreateInfo = {};
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
surfaceCreateInfo.hinstance = (HINSTANCE)platformHandle;
surfaceCreateInfo.hwnd = (HWND)platformWindow;
err = vkCreateWin32SurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
#else
#ifdef __ANDROID__
VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo = {};
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
surfaceCreateInfo.window = window;
err = vkCreateAndroidSurfaceKHR(instance, &surfaceCreateInfo, NULL, &surface);
#else
VkXcbSurfaceCreateInfoKHR surfaceCreateInfo = {};
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
surfaceCreateInfo.connection = connection;
surfaceCreateInfo.window = window;
err = vkCreateXcbSurfaceKHR(instance, &surfaceCreateInfo, nullptr, &surface);
#endif
#endif
uint32_t i;
// Get queue properties
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, NULL);
queueProps = (VkQueueFamilyProperties *)malloc(queueCount * sizeof(VkQueueFamilyProperties));
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueCount, queueProps);
assert(queueCount >= 1);
// Iterate over each queue to learn whether it supports presenting:
VkBool32* supportsPresent = (VkBool32 *)malloc(queueCount * sizeof(VkBool32));
for (i = 0; i < queueCount; i++)
{
fpGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i,
surface,
&supportsPresent[i]);
}
// Search for a graphics and a present queue in the array of queue
// families, try to find one that supports both
uint32_t graphicsQueueNodeIndex = UINT32_MAX;
uint32_t presentQueueNodeIndex = UINT32_MAX;
for (i = 0; i < queueCount; i++)
{
if ((queueProps[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0)
{
if (graphicsQueueNodeIndex == UINT32_MAX)
{
graphicsQueueNodeIndex = i;
}
if (supportsPresent[i] == VK_TRUE)
{
graphicsQueueNodeIndex = i;
presentQueueNodeIndex = i;
break;
}
}
}
if (presentQueueNodeIndex == UINT32_MAX)
{
// If there's no queue that supports both present and graphics
// try to find a separate present queue
for (uint32_t i = 0; i < queueCount; ++i)
{
if (supportsPresent[i] == VK_TRUE)
{
presentQueueNodeIndex = i;
break;
}
}
}
free(supportsPresent);
// Generate error if could not find both a graphics and a present queue
if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX)
{
// todo : error message
}
if (graphicsQueueNodeIndex != presentQueueNodeIndex)
{
// todo : error message
}
queueNodeIndex = graphicsQueueNodeIndex;
// Get list of supported formats
uint32_t formatCount;
err = fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, NULL);
assert(!err);
VkSurfaceFormatKHR *surfFormats = (VkSurfaceFormatKHR *)malloc(formatCount * sizeof(VkSurfaceFormatKHR));
err = fpGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, surfFormats);
assert(!err);
// If the format list includes just one entry of VK_FORMAT_UNDEFINED,
// the surface has no preferred format. Otherwise, at least one
// supported format will be returned.
if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)
{
colorFormat = VK_FORMAT_B8G8R8A8_UNORM;
}
else
{
assert(formatCount >= 1);
colorFormat = surfFormats[0].format;
}
colorSpace = surfFormats[0].colorSpace;
}
void init(VkInstance instance, VkPhysicalDevice physicalDevice, VkDevice device)
{
this->instance = instance;
this->physicalDevice = physicalDevice;
this->device = device;
GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceSupportKHR);
GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceCapabilitiesKHR);
GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfaceFormatsKHR);
GET_INSTANCE_PROC_ADDR(instance, GetPhysicalDeviceSurfacePresentModesKHR);
GET_DEVICE_PROC_ADDR(device, CreateSwapchainKHR);
GET_DEVICE_PROC_ADDR(device, DestroySwapchainKHR);
GET_DEVICE_PROC_ADDR(device, GetSwapchainImagesKHR);
GET_DEVICE_PROC_ADDR(device, AcquireNextImageKHR);
GET_DEVICE_PROC_ADDR(device, QueuePresentKHR);
}
void setup(VkCommandBuffer cmdBuffer, uint32_t *width, uint32_t *height)
{
VkResult err;
VkSwapchainKHR oldSwapchain = swapChain;
// Get physical device surface properties and formats
VkSurfaceCapabilitiesKHR surfCaps;
err = fpGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfCaps);
assert(!err);
uint32_t presentModeCount;
err = fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, NULL);
assert(!err);
// todo : replace with vector?
VkPresentModeKHR *presentModes = (VkPresentModeKHR *)malloc(presentModeCount * sizeof(VkPresentModeKHR));
err = fpGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes);
assert(!err);
VkExtent2D swapchainExtent = {};
// width and height are either both -1, or both not -1.
if (surfCaps.currentExtent.width == -1)
{
// If the surface size is undefined, the size is set to
// the size of the images requested.
swapchainExtent.width = *width;
swapchainExtent.height = *height;
}
else
{
// If the surface size is defined, the swap chain size must match
swapchainExtent = surfCaps.currentExtent;
*width = surfCaps.currentExtent.width;
*height = surfCaps.currentExtent.height;
}
// Try to use mailbox mode
// Low latency and non-tearing
VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
for (size_t i = 0; i < presentModeCount; i++)
{
if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
{
swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
break;
}
if ((swapchainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR) && (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR))
{
swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
}
}
// Determine the number of images
uint32_t desiredNumberOfSwapchainImages = surfCaps.minImageCount + 1;
if ((surfCaps.maxImageCount > 0) && (desiredNumberOfSwapchainImages > surfCaps.maxImageCount))
{
desiredNumberOfSwapchainImages = surfCaps.maxImageCount;
}
VkSurfaceTransformFlagsKHR preTransform;
if (surfCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
{
preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
}
else {
preTransform = surfCaps.currentTransform;
}
VkSwapchainCreateInfoKHR swapchainCI = {};
swapchainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
swapchainCI.pNext = NULL;
swapchainCI.surface = surface;
swapchainCI.minImageCount = desiredNumberOfSwapchainImages;
swapchainCI.imageFormat = colorFormat;
swapchainCI.imageColorSpace = colorSpace;
swapchainCI.imageExtent = { swapchainExtent.width, swapchainExtent.height };
swapchainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
swapchainCI.preTransform = (VkSurfaceTransformFlagBitsKHR)preTransform;
swapchainCI.imageArrayLayers = 1;
swapchainCI.queueFamilyIndexCount = VK_SHARING_MODE_EXCLUSIVE;
swapchainCI.queueFamilyIndexCount = 0;
swapchainCI.pQueueFamilyIndices = NULL;
swapchainCI.presentMode = swapchainPresentMode;
swapchainCI.oldSwapchain = oldSwapchain;
swapchainCI.clipped = true;
swapchainCI.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
err = fpCreateSwapchainKHR(device, &swapchainCI, nullptr, &swapChain);
assert(!err);
// If we just re-created an existing swapchain, we should destroy the old
// swapchain at this point.
// Note: destroying the swapchain also cleans up all its associated
// presentable images once the platform is done with them.
if (oldSwapchain != VK_NULL_HANDLE)
{
fpDestroySwapchainKHR(device, oldSwapchain, nullptr);
}
err = fpGetSwapchainImagesKHR(device, swapChain, &imageCount, NULL);
assert(!err);
swapchainImages = (VkImage*)malloc(imageCount * sizeof(VkImage));
assert(swapchainImages);
err = fpGetSwapchainImagesKHR(device, swapChain, &imageCount, swapchainImages);
assert(!err);
buffers = (SwapChainBuffer*)malloc(sizeof(SwapChainBuffer)*imageCount);
assert(buffers);
//buffers.resize(imageCount);
for (uint32_t i = 0; i < imageCount; i++)
{
VkImageViewCreateInfo colorAttachmentView = {};
colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
colorAttachmentView.pNext = NULL;
colorAttachmentView.format = colorFormat;
colorAttachmentView.components = {
VK_COMPONENT_SWIZZLE_R,
VK_COMPONENT_SWIZZLE_G,
VK_COMPONENT_SWIZZLE_B,
VK_COMPONENT_SWIZZLE_A
};
colorAttachmentView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
colorAttachmentView.subresourceRange.baseMipLevel = 0;
colorAttachmentView.subresourceRange.levelCount = 1;
colorAttachmentView.subresourceRange.baseArrayLayer = 0;
colorAttachmentView.subresourceRange.layerCount = 1;
colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D;
colorAttachmentView.flags = 0;
buffers[i].image = swapchainImages[i];
vkTools::setImageLayout(
cmdBuffer,
buffers[i].image,
VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
colorAttachmentView.image = buffers[i].image;
err = vkCreateImageView(device, &colorAttachmentView, nullptr, &buffers[i].view);
assert(!err);
}
}
// Acquires the next image in the swap chain
VkResult acquireNextImage(VkSemaphore presentCompleteSemaphore, uint32_t *currentBuffer)
{
return fpAcquireNextImageKHR(device, swapChain, UINT64_MAX, presentCompleteSemaphore, (VkFence)nullptr, currentBuffer);
}
// Present the current image to the queue
VkResult queuePresent(VkQueue queue, uint32_t currentBuffer)
{
VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.pNext = NULL;
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = &swapChain;
presentInfo.pImageIndices = &currentBuffer;
return fpQueuePresentKHR(queue, &presentInfo);
}
void cleanup()
{
for (uint32_t i = 0; i < imageCount; i++)
{
vkDestroyImageView(device, buffers[i].view, nullptr);
}
fpDestroySwapchainKHR(device, swapChain, nullptr);
vkDestroySurfaceKHR(instance, surface, nullptr);
}
};

771
base/vulkantools.cpp Normal file
View file

@ -0,0 +1,771 @@
/*
* Assorted commonly used Vulkan helper functions
*
* Copyright (C) 2015 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
#include "vulkantools.h"
#ifdef __ANDROID__
#include "vulkanandroid.h"
#endif
namespace vkTools
{
VkBool32 checkGlobalExtensionPresent(const char* extensionName)
{
uint32_t extensionCount = 0;
std::vector<VkExtensionProperties> extensions;
vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, NULL);
extensions.resize(extensionCount);
vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, extensions.data());
for (auto& ext : extensions)
{
if (!strcmp(extensionName, ext.extensionName))
{
return true;
}
}
return false;
}
VkBool32 checkDeviceExtensionPresent(VkPhysicalDevice physicalDevice, const char* extensionName)
{
uint32_t extensionCount = 0;
std::vector<VkExtensionProperties> extensions;
vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &extensionCount, NULL);
extensions.resize(extensionCount);
vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &extensionCount, extensions.data());
for (auto& ext : extensions)
{
if (!strcmp(extensionName, ext.extensionName))
{
return true;
}
}
return false;
}
std::string errorString(VkResult errorCode)
{
switch (errorCode)
{
// todo : update to SDK 0.10.1
#define STR(r) case VK_ ##r: return #r
STR(NOT_READY);
STR(TIMEOUT);
STR(EVENT_SET);
STR(EVENT_RESET);
STR(INCOMPLETE);
STR(ERROR_OUT_OF_HOST_MEMORY);
STR(ERROR_OUT_OF_DEVICE_MEMORY);
STR(ERROR_INITIALIZATION_FAILED);
STR(ERROR_DEVICE_LOST);
STR(ERROR_MEMORY_MAP_FAILED);
STR(ERROR_LAYER_NOT_PRESENT);
STR(ERROR_EXTENSION_NOT_PRESENT);
STR(ERROR_INCOMPATIBLE_DRIVER);
#undef STR
default:
return "UNKNOWN_ERROR";
}
}
// Create an image memory barrier for changing the layout of
// an image and put it into an active command buffer
// See chapter 11.4 "Image Layout" for details
//todo : rename
void setImageLayout(VkCommandBuffer cmdbuffer, VkImage image, VkImageAspectFlags aspectMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout)
{
// Create an image barrier object
VkImageMemoryBarrier imageMemoryBarrier = vkTools::initializers::imageMemoryBarrier();
imageMemoryBarrier.oldLayout = oldImageLayout;
imageMemoryBarrier.newLayout = newImageLayout;
imageMemoryBarrier.image = image;
imageMemoryBarrier.subresourceRange.aspectMask = aspectMask;
imageMemoryBarrier.subresourceRange.baseMipLevel = 0;
imageMemoryBarrier.subresourceRange.levelCount = 1;
imageMemoryBarrier.subresourceRange.layerCount = 1;
// Source layouts (old)
// Undefined layout
// Only allowed as initial layout!
// Make sure any writes to the image have been finished
if (oldImageLayout == VK_IMAGE_LAYOUT_UNDEFINED)
{
imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
}
// Old layout is color attachment
// Make sure any writes to the color buffer have been finished
if (oldImageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
{
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
}
// Old layout is transfer source
// Make sure any reads from the image have been finished
if (oldImageLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
{
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
}
// Old layout is shader read (sampler, input attachment)
// Make sure any shader reads from the image have been finished
if (oldImageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
{
imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
}
// Target layouts (new)
// New layout is transfer destination (copy, blit)
// Make sure any copyies to the image have been finished
if (newImageLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
{
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
}
// New layout is transfer source (copy, blit)
// Make sure any reads from and writes to the image have been finished
if (newImageLayout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL)
{
imageMemoryBarrier.srcAccessMask = imageMemoryBarrier.srcAccessMask | VK_ACCESS_TRANSFER_READ_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
}
// New layout is color attachment
// Make sure any writes to the color buffer hav been finished
if (newImageLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
{
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
}
// New layout is depth attachment
// Make sure any writes to depth/stencil buffer have been finished
if (newImageLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
{
imageMemoryBarrier.dstAccessMask = imageMemoryBarrier.dstAccessMask | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
}
// New layout is shader read (sampler, input attachment)
// Make sure any writes to the image have been finished
if (newImageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
{
imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
}
// Put barrier on top
VkPipelineStageFlags srcStageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkPipelineStageFlags destStageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
// Put barrier inside setup command buffer
vkCmdPipelineBarrier(
cmdbuffer,
srcStageFlags,
destStageFlags,
0,
0, nullptr,
0, nullptr,
1, &imageMemoryBarrier);
}
void exitFatal(std::string message, std::string caption)
{
#ifdef _WIN32
MessageBox(NULL, message.c_str(), caption.c_str(), MB_OK | MB_ICONERROR);
#else
// TODO : Linux
#endif
std::cerr << message << "\n";
exit(1);
}
std::string readTextFile(const char *fileName)
{
std::string fileContent;
std::ifstream fileStream(fileName, std::ios::in);
if (!fileStream.is_open()) {
printf("File %s not found\n", fileName);
return "";
}
std::string line = "";
while (!fileStream.eof()) {
getline(fileStream, line);
fileContent.append(line + "\n");
}
fileStream.close();
return fileContent;
}
// Load a binary file into a buffer (e.g. SPIR-V)
char *readBinaryFile(const char *filename, size_t *psize)
{
long int size;
size_t retval;
void *shader_code;
FILE *fp = fopen(filename, "rb");
if (!fp) return NULL;
fseek(fp, 0L, SEEK_END);
size = ftell(fp);
fseek(fp, 0L, SEEK_SET);
shader_code = malloc(size);
retval = fread(shader_code, size, 1, fp);
assert(retval == 1);
*psize = size;
return (char*)shader_code;
}
VkShaderModule loadShader(const char *fileName, VkDevice device, VkShaderStageFlagBits stage)
{
size_t size = 0;
const char *shaderCode = readBinaryFile(fileName, &size);
assert(size > 0);
VkShaderModule shaderModule;
VkShaderModuleCreateInfo moduleCreateInfo;
VkResult err;
moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
moduleCreateInfo.pNext = NULL;
moduleCreateInfo.codeSize = size;
moduleCreateInfo.pCode = (uint32_t*)shaderCode;
moduleCreateInfo.flags = 0;
err = vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderModule);
assert(!err);
return shaderModule;
}
VkShaderModule loadShaderGLSL(const char *fileName, VkDevice device, VkShaderStageFlagBits stage)
{
std::string shaderSrc = readTextFile(fileName);
const char *shaderCode = shaderSrc.c_str();
size_t size = strlen(shaderCode);
assert(size > 0);
VkShaderModule shaderModule;
VkShaderModuleCreateInfo moduleCreateInfo;
VkResult err;
moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
moduleCreateInfo.pNext = NULL;
moduleCreateInfo.codeSize = 3 * sizeof(uint32_t) + size + 1;
moduleCreateInfo.pCode = (uint32_t*)malloc(moduleCreateInfo.codeSize);
moduleCreateInfo.flags = 0;
// Magic SPV number
((uint32_t *)moduleCreateInfo.pCode)[0] = 0x07230203;
((uint32_t *)moduleCreateInfo.pCode)[1] = 0;
((uint32_t *)moduleCreateInfo.pCode)[2] = stage;
memcpy(((uint32_t *)moduleCreateInfo.pCode + 3), shaderCode, size + 1);
err = vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderModule);
assert(!err);
return shaderModule;
}
VkImageMemoryBarrier prePresentBarrier(VkImage presentImage)
{
VkImageMemoryBarrier imageMemoryBarrier = vkTools::initializers::imageMemoryBarrier();
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = 0;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
imageMemoryBarrier.image = presentImage;
return imageMemoryBarrier;
}
VkImageMemoryBarrier postPresentBarrier(VkImage presentImage)
{
VkImageMemoryBarrier imageMemoryBarrier = vkTools::initializers::imageMemoryBarrier();
imageMemoryBarrier.srcAccessMask = 0;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrier.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
imageMemoryBarrier.image = presentImage;
return imageMemoryBarrier;
}
void destroyUniformData(VkDevice device, vkTools::UniformData *uniformData)
{
vkDestroyBuffer(device, uniformData->buffer, nullptr);
vkFreeMemory(device, uniformData->memory, nullptr);
}
}
VkMemoryAllocateInfo vkTools::initializers::memoryAllocateInfo()
{
VkMemoryAllocateInfo memAllocInfo = {};
memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAllocInfo.pNext = NULL;
memAllocInfo.allocationSize = 0;
memAllocInfo.memoryTypeIndex = 0;
return memAllocInfo;
}
VkCommandBufferAllocateInfo vkTools::initializers::commandBufferAllocateInfo(VkCommandPool commandPool, VkCommandBufferLevel level, uint32_t bufferCount)
{
VkCommandBufferAllocateInfo commandBufferAllocateInfo = {};
commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
commandBufferAllocateInfo.commandPool = commandPool;
commandBufferAllocateInfo.level = level;
commandBufferAllocateInfo.commandBufferCount = bufferCount;
return commandBufferAllocateInfo;
}
VkCommandBufferBeginInfo vkTools::initializers::commandBufferBeginInfo()
{
VkCommandBufferBeginInfo cmdBufferBeginInfo = {};
cmdBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cmdBufferBeginInfo.pNext = NULL;
return cmdBufferBeginInfo;
}
VkRenderPassBeginInfo vkTools::initializers::renderPassBeginInfo()
{
VkRenderPassBeginInfo renderPassBeginInfo = {};
renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
renderPassBeginInfo.pNext = NULL;
return renderPassBeginInfo;
}
VkImageMemoryBarrier vkTools::initializers::imageMemoryBarrier()
{
VkImageMemoryBarrier imageMemoryBarrier = {};
imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imageMemoryBarrier.pNext = NULL;
// Some default values
imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
return imageMemoryBarrier;
}
VkBufferMemoryBarrier vkTools::initializers::bufferMemoryBarrier()
{
VkBufferMemoryBarrier bufferMemoryBarrier = {};
bufferMemoryBarrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
bufferMemoryBarrier.pNext = NULL;
return bufferMemoryBarrier;
}
VkMemoryBarrier vkTools::initializers::memoryBarrier()
{
VkMemoryBarrier memoryBarrier = {};
memoryBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
memoryBarrier.pNext = NULL;
return memoryBarrier;
}
VkImageCreateInfo vkTools::initializers::imageCreateInfo()
{
VkImageCreateInfo imageCreateInfo = {};
imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageCreateInfo.pNext = NULL;
return imageCreateInfo;
}
VkSamplerCreateInfo vkTools::initializers::samplerCreateInfo()
{
VkSamplerCreateInfo samplerCreateInfo = {};
samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerCreateInfo.pNext = NULL;
return samplerCreateInfo;
}
VkImageViewCreateInfo vkTools::initializers::imageViewCreateInfo()
{
VkImageViewCreateInfo imageViewCreateInfo = {};
imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageViewCreateInfo.pNext = NULL;
return imageViewCreateInfo;
}
VkFramebufferCreateInfo vkTools::initializers::framebufferCreateInfo()
{
VkFramebufferCreateInfo framebufferCreateInfo = {};
framebufferCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
framebufferCreateInfo.pNext = NULL;
return framebufferCreateInfo;
}
VkSemaphoreCreateInfo vkTools::initializers::semaphoreCreateInfo(
VkSemaphoreCreateFlags flags)
{
VkSemaphoreCreateInfo semaphoreCreateInfo = {};
semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
semaphoreCreateInfo.pNext = NULL;
semaphoreCreateInfo.flags = flags;
return semaphoreCreateInfo;
}
VkSubmitInfo vkTools::initializers::submitInfo()
{
VkSubmitInfo submitInfo = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.pNext = NULL;
return submitInfo;
}
VkViewport vkTools::initializers::viewport(
float width,
float height,
float minDepth,
float maxDepth)
{
VkViewport viewport = {};
viewport.width = width;
viewport.height = height;
viewport.minDepth = minDepth;
viewport.maxDepth = maxDepth;
return viewport;
}
VkRect2D vkTools::initializers::rect2D(
int32_t width,
int32_t height,
int32_t offsetX,
int32_t offsetY)
{
VkRect2D rect2D = {};
rect2D.extent.width = width;
rect2D.extent.height = height;
rect2D.offset.x = offsetX;
rect2D.offset.y = offsetY;
return rect2D;
}
VkBufferCreateInfo vkTools::initializers::bufferCreateInfo(
VkBufferUsageFlags usage,
VkDeviceSize size)
{
VkBufferCreateInfo bufCreateInfo = {};
bufCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufCreateInfo.pNext = NULL;
bufCreateInfo.usage = usage;
bufCreateInfo.size = size;
bufCreateInfo.flags = 0;
return bufCreateInfo;
}
VkDescriptorPoolCreateInfo vkTools::initializers::descriptorPoolCreateInfo(
uint32_t poolSizeCount,
VkDescriptorPoolSize* pPoolSizes,
uint32_t maxSets)
{
VkDescriptorPoolCreateInfo descriptorPoolInfo = {};
descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
descriptorPoolInfo.pNext = NULL;
descriptorPoolInfo.poolSizeCount = poolSizeCount;
descriptorPoolInfo.pPoolSizes = pPoolSizes;
descriptorPoolInfo.maxSets = maxSets;
return descriptorPoolInfo;
}
VkDescriptorPoolSize vkTools::initializers::descriptorPoolSize(
VkDescriptorType type,
uint32_t descriptorCount)
{
VkDescriptorPoolSize descriptorPoolSize = {};
descriptorPoolSize.type = type;
descriptorPoolSize.descriptorCount = descriptorCount;
return descriptorPoolSize;
}
VkDescriptorSetLayoutBinding vkTools::initializers::descriptorSetLayoutBinding(
VkDescriptorType type,
VkShaderStageFlags stageFlags,
uint32_t binding)
{
VkDescriptorSetLayoutBinding setLayoutBinding = {};
setLayoutBinding.descriptorType = type;
setLayoutBinding.stageFlags = stageFlags;
setLayoutBinding.binding = binding;
// Default value in all examples
setLayoutBinding.descriptorCount = 1;
return setLayoutBinding;
}
VkDescriptorSetLayoutCreateInfo vkTools::initializers::descriptorSetLayoutCreateInfo(
const VkDescriptorSetLayoutBinding* pBindings,
uint32_t bindingCount)
{
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {};
descriptorSetLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
descriptorSetLayoutCreateInfo.pNext = NULL;
descriptorSetLayoutCreateInfo.pBindings = pBindings;
descriptorSetLayoutCreateInfo.bindingCount = bindingCount;
return descriptorSetLayoutCreateInfo;
}
VkPipelineLayoutCreateInfo vkTools::initializers::pipelineLayoutCreateInfo(
const VkDescriptorSetLayout* pSetLayouts,
uint32_t setLayoutCount)
{
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {};
pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutCreateInfo.pNext = NULL;
pipelineLayoutCreateInfo.setLayoutCount = setLayoutCount;
pipelineLayoutCreateInfo.pSetLayouts = pSetLayouts;
return pipelineLayoutCreateInfo;
}
VkDescriptorSetAllocateInfo vkTools::initializers::descriptorSetAllocateInfo(
VkDescriptorPool descriptorPool,
const VkDescriptorSetLayout* pSetLayouts,
uint32_t descriptorSetCount)
{
VkDescriptorSetAllocateInfo descriptorSetAllocateInfo = {};
descriptorSetAllocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
descriptorSetAllocateInfo.pNext = NULL;
descriptorSetAllocateInfo.descriptorPool = descriptorPool;
descriptorSetAllocateInfo.pSetLayouts = pSetLayouts;
descriptorSetAllocateInfo.descriptorSetCount = descriptorSetCount;
return descriptorSetAllocateInfo;
}
VkDescriptorImageInfo vkTools::initializers::descriptorImageInfo(VkSampler sampler, VkImageView imageView, VkImageLayout imageLayout)
{
VkDescriptorImageInfo descriptorImageInfo = {};
descriptorImageInfo.sampler = sampler;
descriptorImageInfo.imageView = imageView;
descriptorImageInfo.imageLayout = imageLayout;
return descriptorImageInfo;
}
VkWriteDescriptorSet vkTools::initializers::writeDescriptorSet(
VkDescriptorSet dstSet,
VkDescriptorType type,
uint32_t binding,
VkDescriptorBufferInfo* bufferInfo)
{
VkWriteDescriptorSet writeDescriptorSet = {};
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSet.pNext = NULL;
writeDescriptorSet.dstSet = dstSet;
writeDescriptorSet.descriptorType = type;
writeDescriptorSet.dstBinding = binding;
writeDescriptorSet.pBufferInfo = bufferInfo;
// Default value in all examples
writeDescriptorSet.descriptorCount = 1;
return writeDescriptorSet;
}
VkWriteDescriptorSet vkTools::initializers::writeDescriptorSet(
VkDescriptorSet dstSet,
VkDescriptorType type,
uint32_t binding,
VkDescriptorImageInfo * imageInfo)
{
VkWriteDescriptorSet writeDescriptorSet = {};
writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
writeDescriptorSet.pNext = NULL;
writeDescriptorSet.dstSet = dstSet;
writeDescriptorSet.descriptorType = type;
writeDescriptorSet.dstBinding = binding;
writeDescriptorSet.pImageInfo = imageInfo;
// Default value in all examples
writeDescriptorSet.descriptorCount = 1;
return writeDescriptorSet;
}
VkVertexInputBindingDescription vkTools::initializers::vertexInputBindingDescription(
uint32_t binding,
uint32_t stride,
VkVertexInputRate inputRate)
{
VkVertexInputBindingDescription vInputBindDescription = {};
vInputBindDescription.binding = binding;
vInputBindDescription.stride = stride;
vInputBindDescription.inputRate = inputRate;
return vInputBindDescription;
}
VkVertexInputAttributeDescription vkTools::initializers::vertexInputAttributeDescription(
uint32_t binding,
uint32_t location,
VkFormat format,
uint32_t offset)
{
VkVertexInputAttributeDescription vInputAttribDescription = {};
vInputAttribDescription.location = location;
vInputAttribDescription.binding = binding;
vInputAttribDescription.format = format;
vInputAttribDescription.offset = offset;
return vInputAttribDescription;
}
VkPipelineVertexInputStateCreateInfo vkTools::initializers::pipelineVertexInputStateCreateInfo()
{
VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo = {};
pipelineVertexInputStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
pipelineVertexInputStateCreateInfo.pNext = NULL;
return pipelineVertexInputStateCreateInfo;
}
VkPipelineInputAssemblyStateCreateInfo vkTools::initializers::pipelineInputAssemblyStateCreateInfo(
VkPrimitiveTopology topology,
VkPipelineInputAssemblyStateCreateFlags flags,
VkBool32 primitiveRestartEnable)
{
VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo = {};
pipelineInputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
pipelineInputAssemblyStateCreateInfo.topology = topology;
pipelineInputAssemblyStateCreateInfo.flags = flags;
pipelineInputAssemblyStateCreateInfo.primitiveRestartEnable = primitiveRestartEnable;
return pipelineInputAssemblyStateCreateInfo;
}
VkPipelineRasterizationStateCreateInfo vkTools::initializers::pipelineRasterizationStateCreateInfo(
VkPolygonMode polygonMode,
VkCullModeFlags cullMode,
VkFrontFace frontFace,
VkPipelineRasterizationStateCreateFlags flags)
{
VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo = {};
pipelineRasterizationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
pipelineRasterizationStateCreateInfo.polygonMode = polygonMode;
pipelineRasterizationStateCreateInfo.cullMode = cullMode;
pipelineRasterizationStateCreateInfo.frontFace = frontFace;
pipelineRasterizationStateCreateInfo.flags = flags;
pipelineRasterizationStateCreateInfo.depthClampEnable = VK_TRUE;
return pipelineRasterizationStateCreateInfo;
}
VkPipelineColorBlendAttachmentState vkTools::initializers::pipelineColorBlendAttachmentState(
VkColorComponentFlags colorWriteMask,
VkBool32 blendEnable)
{
VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState = {};
pipelineColorBlendAttachmentState.colorWriteMask = colorWriteMask;
pipelineColorBlendAttachmentState.blendEnable = blendEnable;
return pipelineColorBlendAttachmentState;
}
VkPipelineColorBlendStateCreateInfo vkTools::initializers::pipelineColorBlendStateCreateInfo(
uint32_t attachmentCount,
const VkPipelineColorBlendAttachmentState * pAttachments)
{
VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo = {};
pipelineColorBlendStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
pipelineColorBlendStateCreateInfo.pNext = NULL;
pipelineColorBlendStateCreateInfo.attachmentCount = attachmentCount;
pipelineColorBlendStateCreateInfo.pAttachments = pAttachments;
return pipelineColorBlendStateCreateInfo;
}
VkPipelineDepthStencilStateCreateInfo vkTools::initializers::pipelineDepthStencilStateCreateInfo(
VkBool32 depthTestEnable,
VkBool32 depthWriteEnable,
VkCompareOp depthCompareOp)
{
VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo = {};
pipelineDepthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
pipelineDepthStencilStateCreateInfo.depthTestEnable = depthTestEnable;
pipelineDepthStencilStateCreateInfo.depthWriteEnable = depthWriteEnable;
pipelineDepthStencilStateCreateInfo.depthCompareOp = depthCompareOp;
pipelineDepthStencilStateCreateInfo.front = pipelineDepthStencilStateCreateInfo.back;
pipelineDepthStencilStateCreateInfo.back.compareOp = VK_COMPARE_OP_ALWAYS;
return pipelineDepthStencilStateCreateInfo;
}
VkPipelineViewportStateCreateInfo vkTools::initializers::pipelineViewportStateCreateInfo(
uint32_t viewportCount,
uint32_t scissorCount,
VkPipelineViewportStateCreateFlags flags)
{
VkPipelineViewportStateCreateInfo pipelineViewportStateCreateInfo = {};
pipelineViewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
pipelineViewportStateCreateInfo.viewportCount = viewportCount;
pipelineViewportStateCreateInfo.scissorCount = scissorCount;
pipelineViewportStateCreateInfo.flags = flags;
return pipelineViewportStateCreateInfo;
}
VkPipelineMultisampleStateCreateInfo vkTools::initializers::pipelineMultisampleStateCreateInfo(
VkSampleCountFlagBits rasterizationSamples,
VkPipelineMultisampleStateCreateFlags flags)
{
VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo = {};
pipelineMultisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
pipelineMultisampleStateCreateInfo.rasterizationSamples = rasterizationSamples;
return pipelineMultisampleStateCreateInfo;
}
VkPipelineDynamicStateCreateInfo vkTools::initializers::pipelineDynamicStateCreateInfo(
const VkDynamicState * pDynamicStates,
uint32_t dynamicStateCount,
VkPipelineDynamicStateCreateFlags flags)
{
VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo = {};
pipelineDynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
pipelineDynamicStateCreateInfo.pDynamicStates = pDynamicStates;
pipelineDynamicStateCreateInfo.dynamicStateCount = dynamicStateCount;
return pipelineDynamicStateCreateInfo;
}
VkPipelineTessellationStateCreateInfo vkTools::initializers::pipelineTessellationStateCreateInfo(uint32_t patchControlPoints)
{
VkPipelineTessellationStateCreateInfo pipelineTessellationStateCreateInfo = {};
pipelineTessellationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
pipelineTessellationStateCreateInfo.patchControlPoints = patchControlPoints;
return pipelineTessellationStateCreateInfo;
}
VkGraphicsPipelineCreateInfo vkTools::initializers::pipelineCreateInfo(
VkPipelineLayout layout,
VkRenderPass renderPass,
VkPipelineCreateFlags flags)
{
VkGraphicsPipelineCreateInfo pipelineCreateInfo = {};
pipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipelineCreateInfo.pNext = NULL;
pipelineCreateInfo.layout = layout;
pipelineCreateInfo.renderPass = renderPass;
pipelineCreateInfo.flags = flags;
return pipelineCreateInfo;
}
VkComputePipelineCreateInfo vkTools::initializers::computePipelineCreateInfo(VkPipelineLayout layout, VkPipelineCreateFlags flags)
{
VkComputePipelineCreateInfo computePipelineCreateInfo = {};
computePipelineCreateInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO;
computePipelineCreateInfo.layout = layout;
computePipelineCreateInfo.flags = flags;
return computePipelineCreateInfo;
}
VkPushConstantRange vkTools::initializers::pushConstantRange(
VkShaderStageFlags stageFlags,
uint32_t size,
uint32_t offset)
{
VkPushConstantRange pushConstantRange = {};
pushConstantRange.stageFlags = stageFlags;
pushConstantRange.offset = offset;
pushConstantRange.size = size;
return pushConstantRange;
}

243
base/vulkantools.h Normal file
View file

@ -0,0 +1,243 @@
/*
* Assorted commonly used Vulkan helper functions
*
* Copyright (C) 2015 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/
#pragma once
#include "vulkan/vulkan.h"
#include <math.h>
#include <stdlib.h>
#include <string>
#include <cstring>
#include <fstream>
#include <assert.h>
#include <stdio.h>
#include <vector>
#include <iostream>
#ifdef _WIN32
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#else
#endif
// todo : remove if added to SDK
#define VK_FLAGS_NONE 0
namespace vkTools
{
// Check if extension is globally available
VkBool32 checkGlobalExtensionPresent(const char* extensionName);
// Check if extension is present on the given device
VkBool32 checkDeviceExtensionPresent(VkPhysicalDevice physicalDevice, const char* extensionName);
// Return string representation of a vulkan error string
std::string errorString(VkResult errorCode);
// Put an image memory barrier for setting an image layout into the given command buffer
void setImageLayout(
VkCommandBuffer cmdbuffer,
VkImage image,
VkImageAspectFlags aspectMask,
VkImageLayout oldImageLayout,
VkImageLayout newImageLayout);
// Display error message and exit on fatal error
void exitFatal(std::string message, std::string caption);
// Load a text file (e.g. GLGL shader) into a std::string
std::string readTextFile(const char *fileName);
// Load a binary file into a buffer (e.g. SPIR-V)
char *readBinaryFile(const char *filename, size_t *psize);
// Load a SPIR-V shader
VkShaderModule loadShader(const char *fileName, VkDevice device, VkShaderStageFlagBits stage);
// Load a GLSL shader
// Note : Only for testing purposes, support for directly feeding GLSL shaders into Vulkan
// may be dropped at some point
VkShaderModule loadShaderGLSL(const char *fileName, VkDevice device, VkShaderStageFlagBits stage);
// Returns a pre-present image memory barrier
// Transforms the image's layout from color attachment to present khr
VkImageMemoryBarrier prePresentBarrier(VkImage presentImage);
// Returns a post-present image memory barrier
// Transforms the image's layout back from present khr to color attachment
VkImageMemoryBarrier postPresentBarrier(VkImage presentImage);
// Contains all vulkan objects
// required for a uniform data object
struct UniformData
{
VkBuffer buffer;
VkDeviceMemory memory;
VkDescriptorBufferInfo descriptor;
uint32_t allocSize;
};
// Destroy (and free) Vulkan resources used by a uniform data structure
void destroyUniformData(VkDevice device, vkTools::UniformData *uniformData);
// Contains often used vulkan object initializers
// Save lot of VK_STRUCTURE_TYPE assignments
// Some initializers are parameterized for convenience
namespace initializers
{
VkMemoryAllocateInfo memoryAllocateInfo();
VkCommandBufferAllocateInfo commandBufferAllocateInfo(
VkCommandPool commandPool,
VkCommandBufferLevel level,
uint32_t bufferCount);
VkCommandBufferBeginInfo commandBufferBeginInfo();
VkRenderPassBeginInfo renderPassBeginInfo();
VkImageMemoryBarrier imageMemoryBarrier();
VkBufferMemoryBarrier bufferMemoryBarrier();
VkMemoryBarrier memoryBarrier();
VkImageCreateInfo imageCreateInfo();
VkSamplerCreateInfo samplerCreateInfo();
VkImageViewCreateInfo imageViewCreateInfo();
VkFramebufferCreateInfo framebufferCreateInfo();
VkSemaphoreCreateInfo semaphoreCreateInfo(
VkSemaphoreCreateFlags flags);
VkSubmitInfo submitInfo();
VkViewport viewport(
float width,
float height,
float minDepth,
float maxDepth);
VkRect2D rect2D(
int32_t width,
int32_t height,
int32_t offsetX,
int32_t offsetY);
VkBufferCreateInfo bufferCreateInfo(
VkBufferUsageFlags usage,
VkDeviceSize size);
VkDescriptorPoolCreateInfo descriptorPoolCreateInfo(
uint32_t poolSizeCount,
VkDescriptorPoolSize* pPoolSizes,
uint32_t maxSets);
VkDescriptorPoolSize descriptorPoolSize(
VkDescriptorType type,
uint32_t descriptorCount);
VkDescriptorSetLayoutBinding descriptorSetLayoutBinding(
VkDescriptorType type,
VkShaderStageFlags stageFlags,
uint32_t binding);
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo(
const VkDescriptorSetLayoutBinding* pBindings,
uint32_t bindingCount);
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo(
const VkDescriptorSetLayout* pSetLayouts,
uint32_t setLayoutCount );
VkDescriptorSetAllocateInfo descriptorSetAllocateInfo(
VkDescriptorPool descriptorPool,
const VkDescriptorSetLayout* pSetLayouts,
uint32_t descriptorSetCount);
VkDescriptorImageInfo descriptorImageInfo(
VkSampler sampler,
VkImageView imageView,
VkImageLayout imageLayout);
VkWriteDescriptorSet writeDescriptorSet(
VkDescriptorSet dstSet,
VkDescriptorType type,
uint32_t binding,
VkDescriptorBufferInfo* bufferInfo);
VkWriteDescriptorSet writeDescriptorSet(
VkDescriptorSet dstSet,
VkDescriptorType type,
uint32_t binding,
VkDescriptorImageInfo* imageInfo);
VkVertexInputBindingDescription vertexInputBindingDescription(
uint32_t binding,
uint32_t stride,
VkVertexInputRate inputRate);
VkVertexInputAttributeDescription vertexInputAttributeDescription(
uint32_t binding,
uint32_t location,
VkFormat format,
uint32_t offset);
VkPipelineVertexInputStateCreateInfo pipelineVertexInputStateCreateInfo();
VkPipelineInputAssemblyStateCreateInfo pipelineInputAssemblyStateCreateInfo(
VkPrimitiveTopology topology,
VkPipelineInputAssemblyStateCreateFlags flags,
VkBool32 primitiveRestartEnable);
VkPipelineRasterizationStateCreateInfo pipelineRasterizationStateCreateInfo(
VkPolygonMode polygonMode,
VkCullModeFlags cullMode,
VkFrontFace frontFace,
VkPipelineRasterizationStateCreateFlags flags);
VkPipelineColorBlendAttachmentState pipelineColorBlendAttachmentState(
VkColorComponentFlags colorWriteMask,
VkBool32 blendEnable);
VkPipelineColorBlendStateCreateInfo pipelineColorBlendStateCreateInfo(
uint32_t attachmentCount,
const VkPipelineColorBlendAttachmentState* pAttachments);
VkPipelineDepthStencilStateCreateInfo pipelineDepthStencilStateCreateInfo(
VkBool32 depthTestEnable,
VkBool32 depthWriteEnable,
VkCompareOp depthCompareOp);
VkPipelineViewportStateCreateInfo pipelineViewportStateCreateInfo(
uint32_t viewportCount,
uint32_t scissorCount,
VkPipelineViewportStateCreateFlags flags);
VkPipelineMultisampleStateCreateInfo pipelineMultisampleStateCreateInfo(
VkSampleCountFlagBits rasterizationSamples,
VkPipelineMultisampleStateCreateFlags flags);
VkPipelineDynamicStateCreateInfo pipelineDynamicStateCreateInfo(
const VkDynamicState *pDynamicStates,
uint32_t dynamicStateCount,
VkPipelineDynamicStateCreateFlags flags);
VkPipelineTessellationStateCreateInfo pipelineTessellationStateCreateInfo(
uint32_t patchControlPoints);
VkGraphicsPipelineCreateInfo pipelineCreateInfo(
VkPipelineLayout layout,
VkRenderPass renderPass,
VkPipelineCreateFlags flags);
VkComputePipelineCreateInfo computePipelineCreateInfo(
VkPipelineLayout layout,
VkPipelineCreateFlags flags);
VkPushConstantRange pushConstantRange(
VkShaderStageFlags stageFlags,
uint32_t size,
uint32_t offset);
}
}