Even more shader stuff!
This commit is contained in:
534
cve_device.cpp
Normal file
534
cve_device.cpp
Normal file
@@ -0,0 +1,534 @@
|
||||
#include "cve_device.hpp"
|
||||
|
||||
// std headers
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace cve {
|
||||
|
||||
// local callback functions
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData,
|
||||
void *pUserData) {
|
||||
std::cerr << "validation layer: " << pCallbackData->pMessage << std::endl;
|
||||
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
VkResult CreateDebugUtilsMessengerEXT(
|
||||
VkInstance instance,
|
||||
const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,
|
||||
const VkAllocationCallbacks *pAllocator,
|
||||
VkDebugUtilsMessengerEXT *pDebugMessenger) {
|
||||
auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
|
||||
instance,
|
||||
"vkCreateDebugUtilsMessengerEXT");
|
||||
if (func != nullptr) {
|
||||
return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
|
||||
} else {
|
||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
}
|
||||
}
|
||||
|
||||
void DestroyDebugUtilsMessengerEXT(
|
||||
VkInstance instance,
|
||||
VkDebugUtilsMessengerEXT debugMessenger,
|
||||
const VkAllocationCallbacks *pAllocator) {
|
||||
auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(
|
||||
instance,
|
||||
"vkDestroyDebugUtilsMessengerEXT");
|
||||
if (func != nullptr) {
|
||||
func(instance, debugMessenger, pAllocator);
|
||||
}
|
||||
}
|
||||
|
||||
// class member functions
|
||||
CveDevice::CveDevice(CveWindow &window) : window{window} {
|
||||
createInstance();
|
||||
setupDebugMessenger();
|
||||
createSurface();
|
||||
pickPhysicalDevice();
|
||||
createLogicalDevice();
|
||||
createCommandPool();
|
||||
}
|
||||
|
||||
CveDevice::~CveDevice() {
|
||||
vkDestroyCommandPool(device_, commandPool, nullptr);
|
||||
vkDestroyDevice(device_, nullptr);
|
||||
|
||||
if (enableValidationLayers) {
|
||||
DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
|
||||
}
|
||||
|
||||
vkDestroySurfaceKHR(instance, surface_, nullptr);
|
||||
vkDestroyInstance(instance, nullptr);
|
||||
}
|
||||
|
||||
void CveDevice::createInstance() {
|
||||
if (enableValidationLayers && !checkValidationLayerSupport()) {
|
||||
throw std::runtime_error("validation layers requested, but not available!");
|
||||
}
|
||||
|
||||
VkApplicationInfo appInfo = {};
|
||||
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
appInfo.pApplicationName = "LittleVulkanEngine App";
|
||||
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
appInfo.pEngineName = "No Engine";
|
||||
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
|
||||
appInfo.apiVersion = VK_API_VERSION_1_0;
|
||||
|
||||
VkInstanceCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
createInfo.pApplicationInfo = &appInfo;
|
||||
|
||||
auto extensions = getRequiredExtensions();
|
||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||
createInfo.ppEnabledExtensionNames = extensions.data();
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo;
|
||||
if (enableValidationLayers) {
|
||||
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
|
||||
createInfo.ppEnabledLayerNames = validationLayers.data();
|
||||
|
||||
populateDebugMessengerCreateInfo(debugCreateInfo);
|
||||
createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT *)&debugCreateInfo;
|
||||
} else {
|
||||
createInfo.enabledLayerCount = 0;
|
||||
createInfo.pNext = nullptr;
|
||||
}
|
||||
|
||||
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create instance!");
|
||||
}
|
||||
|
||||
hasGflwRequiredInstanceExtensions();
|
||||
}
|
||||
|
||||
void CveDevice::pickPhysicalDevice() {
|
||||
uint32_t deviceCount = 0;
|
||||
vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
|
||||
if (deviceCount == 0) {
|
||||
throw std::runtime_error("failed to find GPUs with Vulkan support!");
|
||||
}
|
||||
std::cout << "Device count: " << deviceCount << std::endl;
|
||||
std::vector<VkPhysicalDevice> devices(deviceCount);
|
||||
vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
|
||||
|
||||
for (const auto &device : devices) {
|
||||
if (isDeviceSuitable(device)) {
|
||||
physicalDevice = device;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (physicalDevice == VK_NULL_HANDLE) {
|
||||
throw std::runtime_error("failed to find a suitable GPU!");
|
||||
}
|
||||
|
||||
vkGetPhysicalDeviceProperties(physicalDevice, &properties);
|
||||
std::cout << "physical device: " << properties.deviceName << std::endl;
|
||||
}
|
||||
|
||||
void CveDevice::createLogicalDevice() {
|
||||
QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
|
||||
|
||||
std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
|
||||
std::set<uint32_t> uniqueQueueFamilies = {indices.graphicsFamily, indices.presentFamily};
|
||||
|
||||
float queuePriority = 1.0f;
|
||||
for (uint32_t queueFamily : uniqueQueueFamilies) {
|
||||
VkDeviceQueueCreateInfo queueCreateInfo = {};
|
||||
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queueCreateInfo.queueFamilyIndex = queueFamily;
|
||||
queueCreateInfo.queueCount = 1;
|
||||
queueCreateInfo.pQueuePriorities = &queuePriority;
|
||||
queueCreateInfos.push_back(queueCreateInfo);
|
||||
}
|
||||
|
||||
VkPhysicalDeviceFeatures deviceFeatures = {};
|
||||
deviceFeatures.samplerAnisotropy = VK_TRUE;
|
||||
|
||||
VkDeviceCreateInfo createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
|
||||
createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
|
||||
createInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||
|
||||
createInfo.pEnabledFeatures = &deviceFeatures;
|
||||
createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
|
||||
createInfo.ppEnabledExtensionNames = deviceExtensions.data();
|
||||
|
||||
// might not really be necessary anymore because device specific validation layers
|
||||
// have been deprecated
|
||||
if (enableValidationLayers) {
|
||||
createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
|
||||
createInfo.ppEnabledLayerNames = validationLayers.data();
|
||||
} else {
|
||||
createInfo.enabledLayerCount = 0;
|
||||
}
|
||||
|
||||
if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device_) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create logical device!");
|
||||
}
|
||||
|
||||
vkGetDeviceQueue(device_, indices.graphicsFamily, 0, &graphicsQueue_);
|
||||
vkGetDeviceQueue(device_, indices.presentFamily, 0, &presentQueue_);
|
||||
}
|
||||
|
||||
void CveDevice::createCommandPool() {
|
||||
QueueFamilyIndices queueFamilyIndices = findPhysicalQueueFamilies();
|
||||
|
||||
VkCommandPoolCreateInfo poolInfo = {};
|
||||
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily;
|
||||
poolInfo.flags =
|
||||
VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
|
||||
if (vkCreateCommandPool(device_, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create command pool!");
|
||||
}
|
||||
}
|
||||
|
||||
void CveDevice::createSurface() { window.createWindowSurface(instance, &surface_); }
|
||||
|
||||
bool CveDevice::isDeviceSuitable(VkPhysicalDevice device) {
|
||||
QueueFamilyIndices indices = findQueueFamilies(device);
|
||||
|
||||
bool extensionsSupported = checkDeviceExtensionSupport(device);
|
||||
|
||||
bool swapChainAdequate = false;
|
||||
if (extensionsSupported) {
|
||||
SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);
|
||||
swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
|
||||
}
|
||||
|
||||
VkPhysicalDeviceFeatures supportedFeatures;
|
||||
vkGetPhysicalDeviceFeatures(device, &supportedFeatures);
|
||||
|
||||
return indices.isComplete() && extensionsSupported && swapChainAdequate &&
|
||||
supportedFeatures.samplerAnisotropy;
|
||||
}
|
||||
|
||||
void CveDevice::populateDebugMessengerCreateInfo(
|
||||
VkDebugUtilsMessengerCreateInfoEXT &createInfo) {
|
||||
createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||
createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||
createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||
createInfo.pfnUserCallback = debugCallback;
|
||||
createInfo.pUserData = nullptr; // Optional
|
||||
}
|
||||
|
||||
void CveDevice::setupDebugMessenger() {
|
||||
if (!enableValidationLayers) return;
|
||||
VkDebugUtilsMessengerCreateInfoEXT createInfo;
|
||||
populateDebugMessengerCreateInfo(createInfo);
|
||||
if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to set up debug messenger!");
|
||||
}
|
||||
}
|
||||
|
||||
bool CveDevice::checkValidationLayerSupport() {
|
||||
uint32_t layerCount;
|
||||
vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
|
||||
|
||||
std::vector<VkLayerProperties> availableLayers(layerCount);
|
||||
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
|
||||
|
||||
for (const char *layerName : validationLayers) {
|
||||
bool layerFound = false;
|
||||
|
||||
for (const auto &layerProperties : availableLayers) {
|
||||
if (strcmp(layerName, layerProperties.layerName) == 0) {
|
||||
layerFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!layerFound) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<const char *> CveDevice::getRequiredExtensions() {
|
||||
uint32_t glfwExtensionCount = 0;
|
||||
const char **glfwExtensions;
|
||||
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
|
||||
|
||||
std::vector<const char *> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
|
||||
|
||||
if (enableValidationLayers) {
|
||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
return extensions;
|
||||
}
|
||||
|
||||
void CveDevice::hasGflwRequiredInstanceExtensions() {
|
||||
uint32_t extensionCount = 0;
|
||||
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
|
||||
std::vector<VkExtensionProperties> extensions(extensionCount);
|
||||
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
|
||||
|
||||
std::cout << "available extensions:" << std::endl;
|
||||
std::unordered_set<std::string> available;
|
||||
for (const auto &extension : extensions) {
|
||||
std::cout << "\t" << extension.extensionName << std::endl;
|
||||
available.insert(extension.extensionName);
|
||||
}
|
||||
|
||||
std::cout << "required extensions:" << std::endl;
|
||||
auto requiredExtensions = getRequiredExtensions();
|
||||
for (const auto &required : requiredExtensions) {
|
||||
std::cout << "\t" << required << std::endl;
|
||||
if (available.find(required) == available.end()) {
|
||||
throw std::runtime_error("Missing required glfw extension");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CveDevice::checkDeviceExtensionSupport(VkPhysicalDevice device) {
|
||||
uint32_t extensionCount;
|
||||
vkEnumerateDeviceExtensionProperties(device, nullptr, &extensionCount, nullptr);
|
||||
|
||||
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
|
||||
vkEnumerateDeviceExtensionProperties(
|
||||
device,
|
||||
nullptr,
|
||||
&extensionCount,
|
||||
availableExtensions.data());
|
||||
|
||||
std::set<std::string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
|
||||
|
||||
for (const auto &extension : availableExtensions) {
|
||||
requiredExtensions.erase(extension.extensionName);
|
||||
}
|
||||
|
||||
return requiredExtensions.empty();
|
||||
}
|
||||
|
||||
QueueFamilyIndices CveDevice::findQueueFamilies(VkPhysicalDevice device) {
|
||||
QueueFamilyIndices indices;
|
||||
|
||||
uint32_t queueFamilyCount = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
|
||||
|
||||
std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
|
||||
|
||||
int i = 0;
|
||||
for (const auto &queueFamily : queueFamilies) {
|
||||
if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
|
||||
indices.graphicsFamily = i;
|
||||
indices.graphicsFamilyHasValue = true;
|
||||
}
|
||||
VkBool32 presentSupport = false;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface_, &presentSupport);
|
||||
if (queueFamily.queueCount > 0 && presentSupport) {
|
||||
indices.presentFamily = i;
|
||||
indices.presentFamilyHasValue = true;
|
||||
}
|
||||
if (indices.isComplete()) {
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
|
||||
SwapChainSupportDetails CveDevice::querySwapChainSupport(VkPhysicalDevice device) {
|
||||
SwapChainSupportDetails details;
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface_, &details.capabilities);
|
||||
|
||||
uint32_t formatCount;
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface_, &formatCount, nullptr);
|
||||
|
||||
if (formatCount != 0) {
|
||||
details.formats.resize(formatCount);
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface_, &formatCount, details.formats.data());
|
||||
}
|
||||
|
||||
uint32_t presentModeCount;
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface_, &presentModeCount, nullptr);
|
||||
|
||||
if (presentModeCount != 0) {
|
||||
details.presentModes.resize(presentModeCount);
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(
|
||||
device,
|
||||
surface_,
|
||||
&presentModeCount,
|
||||
details.presentModes.data());
|
||||
}
|
||||
return details;
|
||||
}
|
||||
|
||||
VkFormat CveDevice::findSupportedFormat(
|
||||
const std::vector<VkFormat> &candidates, VkImageTiling tiling, VkFormatFeatureFlags features) {
|
||||
for (VkFormat format : candidates) {
|
||||
VkFormatProperties props;
|
||||
vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &props);
|
||||
|
||||
if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features) {
|
||||
return format;
|
||||
} else if (
|
||||
tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("failed to find supported format!");
|
||||
}
|
||||
|
||||
uint32_t CveDevice::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) {
|
||||
VkPhysicalDeviceMemoryProperties memProperties;
|
||||
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
|
||||
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) {
|
||||
if ((typeFilter & (1 << i)) &&
|
||||
(memProperties.memoryTypes[i].propertyFlags & properties) == properties) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error("failed to find suitable memory type!");
|
||||
}
|
||||
|
||||
void CveDevice::createBuffer(
|
||||
VkDeviceSize size,
|
||||
VkBufferUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties,
|
||||
VkBuffer &buffer,
|
||||
VkDeviceMemory &bufferMemory) {
|
||||
VkBufferCreateInfo bufferInfo{};
|
||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
bufferInfo.size = size;
|
||||
bufferInfo.usage = usage;
|
||||
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
if (vkCreateBuffer(device_, &bufferInfo, nullptr, &buffer) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create vertex buffer!");
|
||||
}
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
vkGetBufferMemoryRequirements(device_, buffer, &memRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = memRequirements.size;
|
||||
allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties);
|
||||
|
||||
if (vkAllocateMemory(device_, &allocInfo, nullptr, &bufferMemory) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to allocate vertex buffer memory!");
|
||||
}
|
||||
|
||||
vkBindBufferMemory(device_, buffer, bufferMemory, 0);
|
||||
}
|
||||
|
||||
VkCommandBuffer CveDevice::beginSingleTimeCommands() {
|
||||
VkCommandBufferAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
allocInfo.commandPool = commandPool;
|
||||
allocInfo.commandBufferCount = 1;
|
||||
|
||||
VkCommandBuffer commandBuffer;
|
||||
vkAllocateCommandBuffers(device_, &allocInfo, &commandBuffer);
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo{};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
|
||||
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
||||
return commandBuffer;
|
||||
}
|
||||
|
||||
void CveDevice::endSingleTimeCommands(VkCommandBuffer commandBuffer) {
|
||||
vkEndCommandBuffer(commandBuffer);
|
||||
|
||||
VkSubmitInfo submitInfo{};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &commandBuffer;
|
||||
|
||||
vkQueueSubmit(graphicsQueue_, 1, &submitInfo, VK_NULL_HANDLE);
|
||||
vkQueueWaitIdle(graphicsQueue_);
|
||||
|
||||
vkFreeCommandBuffers(device_, commandPool, 1, &commandBuffer);
|
||||
}
|
||||
|
||||
void CveDevice::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) {
|
||||
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||
|
||||
VkBufferCopy copyRegion{};
|
||||
copyRegion.srcOffset = 0; // Optional
|
||||
copyRegion.dstOffset = 0; // Optional
|
||||
copyRegion.size = size;
|
||||
vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, ©Region);
|
||||
|
||||
endSingleTimeCommands(commandBuffer);
|
||||
}
|
||||
|
||||
void CveDevice::copyBufferToImage(
|
||||
VkBuffer buffer, VkImage image, uint32_t width, uint32_t height, uint32_t layerCount) {
|
||||
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||
|
||||
VkBufferImageCopy region{};
|
||||
region.bufferOffset = 0;
|
||||
region.bufferRowLength = 0;
|
||||
region.bufferImageHeight = 0;
|
||||
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.mipLevel = 0;
|
||||
region.imageSubresource.baseArrayLayer = 0;
|
||||
region.imageSubresource.layerCount = layerCount;
|
||||
|
||||
region.imageOffset = {0, 0, 0};
|
||||
region.imageExtent = {width, height, 1};
|
||||
|
||||
vkCmdCopyBufferToImage(
|
||||
commandBuffer,
|
||||
buffer,
|
||||
image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
1,
|
||||
®ion);
|
||||
endSingleTimeCommands(commandBuffer);
|
||||
}
|
||||
|
||||
void CveDevice::createImageWithInfo(
|
||||
const VkImageCreateInfo &imageInfo,
|
||||
VkMemoryPropertyFlags properties,
|
||||
VkImage &image,
|
||||
VkDeviceMemory &imageMemory) {
|
||||
if (vkCreateImage(device_, &imageInfo, nullptr, &image) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create image!");
|
||||
}
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
vkGetImageMemoryRequirements(device_, image, &memRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = memRequirements.size;
|
||||
allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties);
|
||||
|
||||
if (vkAllocateMemory(device_, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to allocate image memory!");
|
||||
}
|
||||
|
||||
if (vkBindImageMemory(device_, image, imageMemory, 0) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to bind image memory!");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace lve
|
||||
108
cve_device.hpp
Normal file
108
cve_device.hpp
Normal file
@@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
|
||||
#include "cve_window.hpp"
|
||||
|
||||
// std lib headers
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace cve {
|
||||
|
||||
struct SwapChainSupportDetails {
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
std::vector<VkSurfaceFormatKHR> formats;
|
||||
std::vector<VkPresentModeKHR> presentModes;
|
||||
};
|
||||
|
||||
struct QueueFamilyIndices {
|
||||
uint32_t graphicsFamily;
|
||||
uint32_t presentFamily;
|
||||
bool graphicsFamilyHasValue = false;
|
||||
bool presentFamilyHasValue = false;
|
||||
bool isComplete() { return graphicsFamilyHasValue && presentFamilyHasValue; }
|
||||
};
|
||||
|
||||
class CveDevice {
|
||||
public:
|
||||
#ifdef NDEBUG
|
||||
const bool enableValidationLayers = false;
|
||||
#else
|
||||
const bool enableValidationLayers = true;
|
||||
#endif
|
||||
|
||||
CveDevice(CveWindow &window);
|
||||
~CveDevice();
|
||||
|
||||
// Not copyable or movable
|
||||
CveDevice(const CveDevice &) = delete;
|
||||
void operator=(const CveDevice &) = delete;
|
||||
CveDevice(CveDevice &&) = delete;
|
||||
CveDevice &operator=(CveDevice &&) = delete;
|
||||
|
||||
VkCommandPool getCommandPool() { return commandPool; }
|
||||
VkDevice device() { return device_; }
|
||||
VkSurfaceKHR surface() { return surface_; }
|
||||
VkQueue graphicsQueue() { return graphicsQueue_; }
|
||||
VkQueue presentQueue() { return presentQueue_; }
|
||||
|
||||
SwapChainSupportDetails getSwapChainSupport() { return querySwapChainSupport(physicalDevice); }
|
||||
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
|
||||
QueueFamilyIndices findPhysicalQueueFamilies() { return findQueueFamilies(physicalDevice); }
|
||||
VkFormat findSupportedFormat(
|
||||
const std::vector<VkFormat> &candidates, VkImageTiling tiling, VkFormatFeatureFlags features);
|
||||
|
||||
// Buffer Helper Functions
|
||||
void createBuffer(
|
||||
VkDeviceSize size,
|
||||
VkBufferUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties,
|
||||
VkBuffer &buffer,
|
||||
VkDeviceMemory &bufferMemory);
|
||||
VkCommandBuffer beginSingleTimeCommands();
|
||||
void endSingleTimeCommands(VkCommandBuffer commandBuffer);
|
||||
void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size);
|
||||
void copyBufferToImage(
|
||||
VkBuffer buffer, VkImage image, uint32_t width, uint32_t height, uint32_t layerCount);
|
||||
|
||||
void createImageWithInfo(
|
||||
const VkImageCreateInfo &imageInfo,
|
||||
VkMemoryPropertyFlags properties,
|
||||
VkImage &image,
|
||||
VkDeviceMemory &imageMemory);
|
||||
|
||||
VkPhysicalDeviceProperties properties;
|
||||
|
||||
private:
|
||||
void createInstance();
|
||||
void setupDebugMessenger();
|
||||
void createSurface();
|
||||
void pickPhysicalDevice();
|
||||
void createLogicalDevice();
|
||||
void createCommandPool();
|
||||
|
||||
// helper functions
|
||||
bool isDeviceSuitable(VkPhysicalDevice device);
|
||||
std::vector<const char *> getRequiredExtensions();
|
||||
bool checkValidationLayerSupport();
|
||||
QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device);
|
||||
void populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT &createInfo);
|
||||
void hasGflwRequiredInstanceExtensions();
|
||||
bool checkDeviceExtensionSupport(VkPhysicalDevice device);
|
||||
SwapChainSupportDetails querySwapChainSupport(VkPhysicalDevice device);
|
||||
|
||||
VkInstance instance;
|
||||
VkDebugUtilsMessengerEXT debugMessenger;
|
||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
||||
CveWindow &window;
|
||||
VkCommandPool commandPool;
|
||||
|
||||
VkDevice device_;
|
||||
VkSurfaceKHR surface_;
|
||||
VkQueue graphicsQueue_;
|
||||
VkQueue presentQueue_;
|
||||
|
||||
const std::vector<const char *> validationLayers = {"VK_LAYER_KHRONOS_validation"};
|
||||
const std::vector<const char *> deviceExtensions = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
|
||||
};
|
||||
|
||||
} // namespace lve
|
||||
45
cve_pipeline.cpp
Normal file
45
cve_pipeline.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#include "cve_pipeline.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
|
||||
namespace cve {
|
||||
CvePipeline::CvePipeline(CveDevice &device, const std::string& vertFilepath,
|
||||
const std::string& fragFilepath, const PipelineConfigInfo &configInfo) : cveDevice{device} {
|
||||
createGraphicsPipeline(vertFilepath, fragFilepath, configInfo);
|
||||
}
|
||||
|
||||
std::vector<char> CvePipeline::readFile(const std::string& filepath) {
|
||||
std::ifstream file{filepath, std::ios::ate | std::ios::binary};
|
||||
|
||||
if (!file.is_open()) {
|
||||
throw std::runtime_error("Failed to open file: "
|
||||
+ filepath);
|
||||
}
|
||||
|
||||
size_t fileSize = static_cast<size_t>(file.tellg());
|
||||
std::vector<char> buffer(fileSize);
|
||||
|
||||
file.seekg(0);
|
||||
file.read(buffer.data(), fileSize);
|
||||
|
||||
file.close();
|
||||
return buffer;
|
||||
}
|
||||
void CvePipeline::createGraphicsPipeline(const std::string& vertFilepath,
|
||||
const std::string& fragFilepath, const PipelineConfigInfo &configInfo) {
|
||||
auto vertCode = readFile(vertFilepath);
|
||||
auto fragCode = readFile(fragFilepath);
|
||||
|
||||
std::cout << "Vertex shader code size: " << vertCode.size() << '\n';
|
||||
std::cout << "Fragment shader code size: " << fragCode.size() << '\n';
|
||||
}
|
||||
|
||||
void createShaderModule(const std::vector<char>& code, VkShaderModule *shaderModule) {
|
||||
VkShaderModuleCreateInfo createInfo{};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
createInfo.codeSize = code.size();
|
||||
createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
|
||||
}
|
||||
}
|
||||
36
cve_pipeline.hpp
Normal file
36
cve_pipeline.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include "cve_device.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace cve {
|
||||
struct PipelineConfigInfo {
|
||||
|
||||
};
|
||||
class CvePipeline {
|
||||
public:
|
||||
CvePipeline(CveDevice &device, const std::string& vertFilepath,
|
||||
const std::string& fragFilepath, const PipelineConfigInfo &configInfo);
|
||||
~CvePipeline() {};
|
||||
|
||||
CvePipeline(const CvePipeline&) = delete;
|
||||
void operator=(const CvePipeline&) = delete;
|
||||
|
||||
static PipelineConfigInfo defaultPipelineConfigInfo(uint32_t width, uint32_t height);
|
||||
|
||||
private:
|
||||
static std::vector<char> readFile(const std::string& filepath);
|
||||
|
||||
void createGraphicsPipeline(const std::string& vertFilepath,
|
||||
const std::string& fragFilepath, const PipelineConfigInfo &configInfo);
|
||||
|
||||
void createShaderModule(const std::vector<char>& code, VkShaderModule *shaderModule);
|
||||
|
||||
CveDevice& cveDevice;
|
||||
VkPipeline graphicsPipeline;
|
||||
VkShaderModule vertShaderModule;
|
||||
VkShaderModule fragShaderModule;
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user