Added Vulkan device class that encapsulates access to the physical and logical device and includes common functions
This commit is contained in:
parent
3339279825
commit
3c944c2bd9
3 changed files with 183 additions and 40 deletions
162
base/vulkandevice.hpp
Normal file
162
base/vulkandevice.hpp
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Vulkan device class
|
||||
*
|
||||
* Encapsulates a physical Vulkan device and it's logical representation
|
||||
*
|
||||
* 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 <exception>
|
||||
#include "vulkan/vulkan.h"
|
||||
#include "vulkantools.h"
|
||||
|
||||
namespace vk
|
||||
{
|
||||
struct VulkanDevice
|
||||
{
|
||||
/** @brief Physical device representation */
|
||||
VkPhysicalDevice physicalDevice;
|
||||
/** @brief Logical device representation (application's view of the device) */
|
||||
VkDevice device;
|
||||
/** @brief Properties of the physical device including limits that the application can check against */
|
||||
VkPhysicalDeviceProperties properties;
|
||||
/** @brief Features of the physical device that an application can use to check if a feature is supported */
|
||||
VkPhysicalDeviceFeatures features;
|
||||
/** @brief Memory types and heaps of the physical device */
|
||||
VkPhysicalDeviceMemoryProperties memoryProperties;
|
||||
|
||||
/** @brief Set to true when the debug marker extension is detected */
|
||||
bool enableDebugMarkers = false;
|
||||
|
||||
/**
|
||||
* Return the index of a memory type that has all the requested property bits set
|
||||
*
|
||||
* @param typeBits Bitmask with bits set for each memory type supported by the resource to request for (from VkMemoryRequirements)
|
||||
* @param properties Bitmask of properties for the memory type to request
|
||||
*
|
||||
* @return Index of the requested memory type
|
||||
*
|
||||
* @throw Throws an exception if no memory type could be found that supports the requested properties
|
||||
*/
|
||||
uint32_t getMemoryType(uint32_t typeBits, VkMemoryPropertyFlags properties)
|
||||
{
|
||||
for (uint32_t i = 0; i < memoryProperties.memoryTypeCount - 1; i++)
|
||||
{
|
||||
if ((typeBits & 1) == 1)
|
||||
{
|
||||
if ((memoryProperties.memoryTypes[i].propertyFlags & properties) == properties)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
typeBits >>= 1;
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
//todo : Exceptions are disabled by default on Android (need to add LOCAL_CPP_FEATURES += exceptions to Android.mk), so for now just return zero
|
||||
return 0;
|
||||
#else
|
||||
throw "Could not find a memory type for the passed properties";
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the logical device based on the passed physical device
|
||||
*
|
||||
* @param physicalDevice The physical device for which the logical reprenstation is to be created
|
||||
* @param queueCreateInfos A vector containing queue create infos for all queues to be requested on the device
|
||||
* @param enabledFeatures Can be used to enable certain features upon device creation
|
||||
* @param useSwapChain Set to false for headless rendering to omit the swapchain device extensions
|
||||
*
|
||||
* @return VkResult of the device creation call
|
||||
*/
|
||||
VkResult create(VkPhysicalDevice physicalDevice, std::vector<VkDeviceQueueCreateInfo> &queueCreateInfos, VkPhysicalDeviceFeatures enabledFeatures, bool useSwapChain = true)
|
||||
{
|
||||
this->physicalDevice = physicalDevice;
|
||||
|
||||
// Store Properties features, limits and properties of the physical device for later use
|
||||
// Device properties also contain limits and sparse properties
|
||||
vkGetPhysicalDeviceProperties(physicalDevice, &properties);
|
||||
// Features should be checked by the examples before using them
|
||||
vkGetPhysicalDeviceFeatures(physicalDevice, &features);
|
||||
// Memory properties are used regularly for creating all kinds of buffer
|
||||
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memoryProperties);
|
||||
|
||||
// Create the logical device representation
|
||||
std::vector<const char*> deviceExtensions;
|
||||
if (useSwapChain)
|
||||
{
|
||||
// If the device will be used for presenting to a display via a swapchain
|
||||
// we need to request the swapchain extension
|
||||
deviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
VkDeviceCreateInfo deviceCreateInfo = {};
|
||||
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
deviceCreateInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());;
|
||||
deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||
deviceCreateInfo.pEnabledFeatures = &enabledFeatures;
|
||||
|
||||
// Cnable the debug marker extension if it is present (likely meaning a debugging tool is present)
|
||||
if (vkTools::checkDeviceExtensionPresent(physicalDevice, VK_EXT_DEBUG_MARKER_EXTENSION_NAME))
|
||||
{
|
||||
deviceExtensions.push_back(VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
|
||||
enableDebugMarkers = true;
|
||||
}
|
||||
|
||||
if (deviceExtensions.size() > 0)
|
||||
{
|
||||
deviceCreateInfo.enabledExtensionCount = (uint32_t)deviceExtensions.size();
|
||||
deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data();
|
||||
}
|
||||
|
||||
return vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a buffer on the device
|
||||
*
|
||||
* @param usageFlags Usage flag bitmask for the buffer (i.e. index, vertex, uniform buffer)
|
||||
* @param memoryPropertyFlags Memory properties for this buffer (i.e. device local, host visible, coherent)
|
||||
* @param size Size of the buffer in byes
|
||||
* @param buffer Pointer to the buffer handle acquired by the function
|
||||
* @param memory Pointer to the memory handle acquired by the function
|
||||
* @param data Pointer to the data that should be copied to the buffer after creation (optional, if not set, no data is copied over)
|
||||
*
|
||||
* @return VK_SUCCESS if buffer handle and memory have been created and (optionally passed) data has been copied
|
||||
*/
|
||||
VkResult createBuffer(VkBufferUsageFlags usageFlags, VkMemoryPropertyFlags memoryPropertyFlags, VkDeviceSize size, VkBuffer *buffer, VkDeviceMemory *memory, void *data = nullptr)
|
||||
{
|
||||
// Create the buffer handle
|
||||
VkBufferCreateInfo bufferCreateInfo = vkTools::initializers::bufferCreateInfo(usageFlags, size);
|
||||
VK_CHECK_RESULT(vkCreateBuffer(device, &bufferCreateInfo, nullptr, buffer));
|
||||
|
||||
// Create the memory backing up the buffer handle
|
||||
VkMemoryRequirements memReqs;
|
||||
VkMemoryAllocateInfo memAlloc = vkTools::initializers::memoryAllocateInfo();
|
||||
vkGetBufferMemoryRequirements(device, *buffer, &memReqs);
|
||||
memAlloc.allocationSize = memReqs.size;
|
||||
// Find a memory type index that fits the properties of the buffer
|
||||
memAlloc.memoryTypeIndex = getMemoryType(memReqs.memoryTypeBits, memoryPropertyFlags);
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device, &memAlloc, nullptr, memory));
|
||||
|
||||
// If a pointer to the buffer data has been passed, map the buffer and copy over the data
|
||||
if (data != nullptr)
|
||||
{
|
||||
void *mapped;
|
||||
VK_CHECK_RESULT(vkMapMemory(device, *memory, 0, size, 0, &mapped));
|
||||
memcpy(mapped, data, size);
|
||||
vkUnmapMemory(device, *memory);
|
||||
}
|
||||
|
||||
// Attach the memory to the buffer object
|
||||
VK_CHECK_RESULT(vkBindBufferMemory(device, *buffer, *memory, 0));
|
||||
|
||||
return VK_SUCCESS;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -50,33 +50,6 @@ VkResult VulkanExampleBase::createInstance(bool enableValidation)
|
|||
return vkCreateInstance(&instanceCreateInfo, nullptr, &instance);
|
||||
}
|
||||
|
||||
VkResult VulkanExampleBase::createDevice(VkDeviceQueueCreateInfo requestedQueues, bool enableValidation)
|
||||
{
|
||||
std::vector<const char*> enabledExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME };
|
||||
|
||||
VkDeviceCreateInfo deviceCreateInfo = {};
|
||||
deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
deviceCreateInfo.pNext = NULL;
|
||||
deviceCreateInfo.queueCreateInfoCount = 1;
|
||||
deviceCreateInfo.pQueueCreateInfos = &requestedQueues;
|
||||
deviceCreateInfo.pEnabledFeatures = &enabledFeatures;
|
||||
|
||||
// enable the debug marker extension if it is present (likely meaning a debugging tool is present)
|
||||
if (vkTools::checkDeviceExtensionPresent(physicalDevice, VK_EXT_DEBUG_MARKER_EXTENSION_NAME))
|
||||
{
|
||||
enabledExtensions.push_back(VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
|
||||
enableDebugMarkers = true;
|
||||
}
|
||||
|
||||
if (enabledExtensions.size() > 0)
|
||||
{
|
||||
deviceCreateInfo.enabledExtensionCount = (uint32_t)enabledExtensions.size();
|
||||
deviceCreateInfo.ppEnabledExtensionNames = enabledExtensions.data();
|
||||
}
|
||||
|
||||
return vkCreateDevice(physicalDevice, &deviceCreateInfo, nullptr, &device);
|
||||
}
|
||||
|
||||
std::string VulkanExampleBase::getWindowTitle()
|
||||
{
|
||||
std::string device(deviceProperties.deviceName);
|
||||
|
|
@ -858,21 +831,27 @@ void VulkanExampleBase::initVulkan(bool enableValidation)
|
|||
}
|
||||
assert(graphicsQueueIndex < queueCount);
|
||||
|
||||
// Vulkan device
|
||||
std::array<float, 1> queuePriorities = { 0.0f };
|
||||
VkDeviceQueueCreateInfo queueCreateInfo = {};
|
||||
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queueCreateInfo.queueFamilyIndex = graphicsQueueIndex;
|
||||
queueCreateInfo.queueCount = 1;
|
||||
queueCreateInfo.pQueuePriorities = queuePriorities.data();
|
||||
// Vulkan device creation
|
||||
|
||||
VK_CHECK_RESULT(createDevice(queueCreateInfo, enableValidation));
|
||||
// We will be requesting queues from one family only
|
||||
// todo: Multiple queue families for transfer and async compute
|
||||
std::vector<float> queuePriorities = { 0.0f };
|
||||
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos = {};
|
||||
queueCreateInfos.resize(1);
|
||||
queueCreateInfos[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queueCreateInfos[0].queueFamilyIndex = graphicsQueueIndex;
|
||||
queueCreateInfos[0].queueCount = 1;
|
||||
queueCreateInfos[0].pQueuePriorities = queuePriorities.data();
|
||||
|
||||
VK_CHECK_RESULT(vulkanDevice.create(physicalDevice, queueCreateInfos, enabledFeatures));
|
||||
|
||||
// Assign device to base class context
|
||||
device = vulkanDevice.device;
|
||||
|
||||
// Store properties (including limits) and features of the phyiscal device
|
||||
// So examples can check against them and see if a feature is actually supported
|
||||
vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties);
|
||||
vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures);
|
||||
|
||||
// Gather physical device memory properties
|
||||
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &deviceMemoryProperties);
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "vulkantools.h"
|
||||
#include "vulkandebug.h"
|
||||
|
||||
#include "vulkandevice.hpp"
|
||||
#include "vulkanswapchain.hpp"
|
||||
#include "vulkanTextureLoader.hpp"
|
||||
#include "vulkanMeshLoader.hpp"
|
||||
|
|
@ -60,7 +61,7 @@ private:
|
|||
bool enableValidation = false;
|
||||
// Set to true when the debug marker extension is detected
|
||||
bool enableDebugMarkers = false;
|
||||
// Set tot true if v-sync will be forced for the swapchain
|
||||
// Set to true if v-sync will be forced for the swapchain
|
||||
bool enableVSync = false;
|
||||
// Device features enabled by the example
|
||||
// If not set, no additional features are enabled (may result in validation layer errors)
|
||||
|
|
@ -69,8 +70,6 @@ private:
|
|||
float fpsTimer = 0.0f;
|
||||
// Create application wide Vulkan instance
|
||||
VkResult createInstance(bool enableValidation);
|
||||
// Create logical Vulkan device based on physical device
|
||||
VkResult createDevice(VkDeviceQueueCreateInfo requestedQueues, bool enableValidation);
|
||||
// Get window title with example name, device, et.
|
||||
std::string getWindowTitle();
|
||||
// Destination dimensions for resizing the window
|
||||
|
|
@ -94,8 +93,11 @@ protected:
|
|||
VkPhysicalDeviceFeatures deviceFeatures;
|
||||
// Stores all available memory (type) properties for the physical device
|
||||
VkPhysicalDeviceMemoryProperties deviceMemoryProperties;
|
||||
// Logical device, application's view of the physical device (GPU)
|
||||
/** @brief Logical device, application's view of the physical device (GPU) */
|
||||
// todo: getter? should always point to VulkanDevice->device
|
||||
VkDevice device;
|
||||
/** @brief Encapsulated physical and logical vulkan device */
|
||||
vk::VulkanDevice vulkanDevice;
|
||||
// Handle to the device graphics queue that command buffers are submitted to
|
||||
VkQueue queue;
|
||||
// Color buffer format
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue