Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "vengine.h"
- #include "vtool.h"
- #define STB_IMAGE_IMPLEMENTATION
- #include <stb_image.h>
- #define TINYOBJLOADER_IMPLEMENTATION
- #include <tiny_obj_loader.h>
- #define SHADOWMAP_FILTER VK_FILTER_LINEAR
- #include <vector>
- namespace std {
- template<> struct hash<ve::VEngine::Vertex> {
- size_t operator()(ve::VEngine::Vertex const& vertex) const {
- return ((hash<glm::vec3>()(vertex.pos) ^ (hash<glm::vec3>()(vertex.normal) << 1)) >> 1) ^ (hash<glm::vec2>()(vertex.texCoord) << 1);
- }
- };
- }
- static void onWindowResized(GLFWwindow* window, int width, int height) {
- if (width == 0 || height == 0) return;
- ve::VEngine* app = reinterpret_cast<ve::VEngine*>(glfwGetWindowUserPointer(window));
- app->recreateSwapChain();
- }
- namespace ve {
- VEngine::VEngine()
- {
- }
- VEngine::~VEngine()
- {
- }
- void VEngine::Clear()
- {
- for (int index = 0; index < uniform_buffers_.size(); index++) {
- vkDestroyBuffer(logic_device_, uniform_buffers_[index], nullptr);
- vkFreeMemory(logic_device_, uniform_buffer_memorys_[index], nullptr);
- }
- }
- void VEngine::CreateTexture(const std::string & texture_path, VkImage& texture, VkDeviceMemory& texture_memory)
- {
- int texWidth, texHeight, texChannels;
- stbi_uc* pixels = stbi_load(texture_path.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
- VkDeviceSize imageSize = texWidth * texHeight * 4;
- if (!pixels) {
- throw std::runtime_error("failed to load texture image!");
- }
- VkBuffer stagingBuffer;
- VkDeviceMemory stagingBufferMemory;
- createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
- void* data;
- vkMapMemory(device, stagingBufferMemory, 0, imageSize, 0, &data);
- memcpy(data, pixels, static_cast<size_t>(imageSize));
- vkUnmapMemory(device, stagingBufferMemory);
- stbi_image_free(pixels);
- createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, texture, texture_memory);
- transitionImageLayout(texture, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
- copyBufferToImage(stagingBuffer, texture, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
- transitionImageLayout(texture, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
- vkDestroyBuffer(device, stagingBuffer, nullptr);
- vkFreeMemory(device, stagingBufferMemory, nullptr);
- }
- void VEngine::CreateTextureView(VkImageView & view, VkImage & texture)
- {
- view = createImageView(texture, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_ASPECT_COLOR_BIT);
- }
- void VEngine::CreateTextureSampler(VkSampler & sampler)
- {
- VkSamplerCreateInfo samplerInfo = {};
- samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
- samplerInfo.magFilter = VK_FILTER_LINEAR;
- samplerInfo.minFilter = VK_FILTER_LINEAR;
- samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
- samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
- samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
- samplerInfo.anisotropyEnable = VK_TRUE;
- samplerInfo.maxAnisotropy = 16;
- samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
- samplerInfo.unnormalizedCoordinates = VK_FALSE;
- samplerInfo.compareEnable = VK_FALSE;
- samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
- samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
- if (vkCreateSampler(device, &samplerInfo, nullptr, &sampler) != VK_SUCCESS) {
- throw std::runtime_error("failed to create texture sampler!");
- }
- }
- void VEngine::AddScene(const ve::VScene & scene)
- {
- std::cout << "add a scene to engine!\n";
- std::array<VkWriteDescriptorSet, 7> descriptorWrites = {};
- }
- const VkDevice VEngine::get_logic_device()
- {
- return logic_device_;
- }
- void VEngine::AddUniformBufferAndMemory(const VkBuffer & uniform_buffer, const VkDeviceMemory & uniform_buffer_memory)
- {
- uniform_buffers_.push_back(uniform_buffer);
- uniform_buffer_memorys_.push_back(uniform_buffer_memory);
- }
- void VEngine::cleanup() {
- cleanupSwapChain();
- vkDestroyBuffer(device, indexBuffer, nullptr);
- vkFreeMemory(device, indexBufferMemory, nullptr);
- vkDestroyBuffer(device, vertexBuffer, nullptr);
- vkFreeMemory(device, vertexBufferMemory, nullptr);
- vkDestroyBuffer(device, uniformMatrixBuffer, nullptr);
- vkFreeMemory(device, uniformMatrixBufferMemory, nullptr);
- vkDestroySemaphore(device, renderFinishedSemaphore, nullptr);
- vkDestroySemaphore(device, imageAvailableSemaphore, nullptr);
- vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
- vkDestroyDescriptorPool(device, descriptorPool, nullptr);
- vkDestroyCommandPool(device, commandPool, nullptr);
- vkDestroyDevice(device, nullptr);
- vkDestroySurfaceKHR(instance, surface, nullptr);
- vkDestroyInstance(instance, nullptr);
- glfwDestroyWindow(window);
- glfwTerminate();
- }
- void VEngine::Run()
- {
- loadModel();
- initWindow();
- initVulkan();
- mainLoop();
- cleanup();
- }
- void VEngine::initWindow() {
- glfwInit();
- glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
- window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
- glfwSetWindowUserPointer(window, this);
- glfwSetWindowSizeCallback(window, onWindowResized);
- }
- void VEngine::initVulkan() {
- createInstance();
- createSurface();
- pickPhysicalDevice();
- createLogicalDevice();
- createSemaphores();
- findDepthFormat(physicalDevice, &depthFormat);
- createSwapChain();
- createImageViews();
- createCommandPool();
- createRenderPass();
- createFramebuffers();
- createDescriptorSetLayout();
- createGraphicsPipeline();
- createVertexBuffer();
- createIndexBuffer();
- createUniformBuffer();
- createDescriptorPool();
- createDescriptorSet();
- createCommandBuffers();
- }
- void VEngine::mainLoop() {
- while (!glfwWindowShouldClose(window) && glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS) {
- glfwPollEvents();
- updateUniformBuffer();
- drawFrame();
- }
- vkDeviceWaitIdle(device);
- }
- void VEngine::cleanupSwapChain() {
- vkDestroyImageView(device, depthImageView, nullptr);
- vkDestroyImage(device, depthImage, nullptr);
- vkFreeMemory(device, depthImageMemory, nullptr);
- for (size_t i = 0; i < swapChainFramebuffers.size(); i++) {
- vkDestroyFramebuffer(device, swapChainFramebuffers[i], nullptr);
- }
- vkFreeCommandBuffers(device, commandPool, static_cast<uint32_t>(commandBuffers.size()), commandBuffers.data());
- vkDestroyPipeline(device, graphicsPipeline, nullptr);
- vkDestroyPipelineLayout(device, pipelineLayout, nullptr);
- vkDestroyRenderPass(device, renderPass, nullptr);
- for (size_t i = 0; i < swapChainImageViews.size(); i++) {
- vkDestroyImageView(device, swapChainImageViews[i], nullptr);
- }
- vkDestroySwapchainKHR(device, swapChain, nullptr);
- }
- void VEngine::recreateSwapChain() {
- vkDeviceWaitIdle(device);
- cleanupSwapChain();
- createSwapChain();
- createImageViews();
- createRenderPass();
- createGraphicsPipeline();
- createFramebuffers();
- createCommandBuffers();
- }
- void VEngine::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 = "Hello Vulkan";
- appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
- appInfo.pEngineName = "Vulkan 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();
- if (enableValidationLayers) {
- createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
- createInfo.ppEnabledLayerNames = validationLayers.data();
- }
- else {
- createInfo.enabledLayerCount = 0;
- }
- if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
- throw std::runtime_error("failed to create instance!");
- }
- }
- void VEngine::createSurface() {
- if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
- throw std::runtime_error("failed to create window surface!");
- }
- }
- void VEngine::pickPhysicalDevice() {
- uint32_t deviceCount = 0;
- vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
- if (deviceCount == 0) {
- throw std::runtime_error("failed to find GPUs with Vulkan support!");
- }
- 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!");
- }
- }
- void VEngine::createLogicalDevice() {
- QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
- std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
- std::set<int> uniqueQueueFamilies = { indices.graphicsFamily, indices.presentFamily };
- float queuePriority = 1.0f;
- for (int 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;
- deviceFeatures.sampleRateShading = 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();
- 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 VEngine::createSwapChain() {
- SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
- VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
- VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
- VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
- uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
- if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
- imageCount = swapChainSupport.capabilities.maxImageCount;
- }
- VkSwapchainCreateInfoKHR createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
- createInfo.surface = surface;
- createInfo.minImageCount = imageCount;
- createInfo.imageFormat = surfaceFormat.format;
- createInfo.imageColorSpace = surfaceFormat.colorSpace;
- createInfo.imageExtent = extent;
- createInfo.imageArrayLayers = 1;
- createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
- QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
- uint32_t queueFamilyIndices[] = { (uint32_t)indices.graphicsFamily, (uint32_t)indices.presentFamily };
- if (indices.graphicsFamily != indices.presentFamily) {
- createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
- createInfo.queueFamilyIndexCount = 2;
- createInfo.pQueueFamilyIndices = queueFamilyIndices;
- }
- else {
- createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
- }
- createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
- createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
- createInfo.presentMode = presentMode;
- createInfo.clipped = VK_TRUE;
- if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
- throw std::runtime_error("failed to create swap chain!");
- }
- vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
- swapChainImages.resize(imageCount);
- vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
- swapChainImageFormat = surfaceFormat.format;
- swapChainExtent = extent;
- }
- void VEngine::createImageViews() {
- swapChainImageViews.resize(swapChainImages.size());
- for (uint32_t i = 0; i < swapChainImages.size(); i++) {
- swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT);
- }
- }
- void VEngine::createRenderPass() {
- std::array<VkAttachmentDescription, 2> attachments{};
- attachments[0].format = swapChainImageFormat;
- attachments[0].samples = VK_SAMPLE_COUNT_1_BIT;
- attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
- attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- attachments[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
- attachments[1].format = depthFormat;
- attachments[1].samples = VK_SAMPLE_COUNT_1_BIT;
- attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
- attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
- attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
- attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
- attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- attachments[1].finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
- VkAttachmentReference colorAttachmentRef[1];
- colorAttachmentRef[0] = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
- VkAttachmentReference depthAttachmentRef = {};
- depthAttachmentRef.attachment = 1;
- depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
- VkSubpassDescription subpass = {};
- subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
- subpass.colorAttachmentCount = 1;
- subpass.pColorAttachments = colorAttachmentRef;
- subpass.pDepthStencilAttachment = &depthAttachmentRef;
- VkSubpassDependency dependency[2] = {};
- dependency[0].srcSubpass = VK_SUBPASS_EXTERNAL;
- dependency[0].dstSubpass = 0;
- dependency[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
- dependency[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- dependency[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
- dependency[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
- dependency[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
- dependency[1].srcSubpass = 0;
- dependency[1].dstSubpass = VK_SUBPASS_EXTERNAL;
- dependency[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- dependency[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
- dependency[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
- dependency[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
- dependency[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
- VkRenderPassCreateInfo renderPassInfo = {};
- renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
- renderPassInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
- renderPassInfo.pAttachments = attachments.data();
- renderPassInfo.subpassCount = 1;
- renderPassInfo.pSubpasses = &subpass;
- renderPassInfo.dependencyCount = 2;
- renderPassInfo.pDependencies = dependency;
- if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
- throw std::runtime_error("failed to create render pass!");
- }
- }
- void VEngine::createDescriptorSetLayout() {
- VkDescriptorSetLayoutBinding uboLayoutBinding = {};
- uboLayoutBinding.binding = 0;
- uboLayoutBinding.descriptorCount = 1;
- uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- uboLayoutBinding.pImmutableSamplers = nullptr;
- uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
- VkDescriptorSetLayoutBinding usvLayoutBinding = {};
- usvLayoutBinding.binding = 1;
- usvLayoutBinding.descriptorCount = 1;
- usvLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- usvLayoutBinding.pImmutableSamplers = nullptr;
- usvLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
- VkDescriptorSetLayoutBinding usfLayoutBinding = {};
- usfLayoutBinding.binding = 2;
- usfLayoutBinding.descriptorCount = 1;
- usfLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- usfLayoutBinding.pImmutableSamplers = nullptr;
- usfLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
- VkDescriptorSetLayoutBinding specialLayoutBinding = {};
- specialLayoutBinding.binding = 6;
- specialLayoutBinding.descriptorCount = 1;
- specialLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- specialLayoutBinding.pImmutableSamplers = nullptr;
- specialLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
- VkDescriptorSetLayoutBinding specialTextureLayoutBinding = {};
- specialTextureLayoutBinding.binding = 7;
- specialTextureLayoutBinding.descriptorCount = 1;
- specialTextureLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- specialTextureLayoutBinding.pImmutableSamplers = nullptr;
- specialTextureLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
- VkDescriptorSetLayoutBinding samplerLayoutBinding = {};
- samplerLayoutBinding.binding = 3;
- samplerLayoutBinding.descriptorCount = 1;
- samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- samplerLayoutBinding.pImmutableSamplers = nullptr;
- samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
- VkDescriptorSetLayoutBinding specularSamplerLayoutBinding = {};
- specularSamplerLayoutBinding.binding = 4;
- specularSamplerLayoutBinding.descriptorCount = 1;
- specularSamplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- specularSamplerLayoutBinding.pImmutableSamplers = nullptr;
- specularSamplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
- VkDescriptorSetLayoutBinding bumpSamplerLayoutBinding = {};
- bumpSamplerLayoutBinding.binding = 5;
- bumpSamplerLayoutBinding.descriptorCount = 1;
- bumpSamplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- bumpSamplerLayoutBinding.pImmutableSamplers = nullptr;
- bumpSamplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
- VkDescriptorSetLayoutBinding cutoffSamplerLayoutBinding = {};
- cutoffSamplerLayoutBinding.binding = 8;
- cutoffSamplerLayoutBinding.descriptorCount = 1;
- cutoffSamplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- cutoffSamplerLayoutBinding.pImmutableSamplers = nullptr;
- cutoffSamplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
- VkDescriptorSetLayoutBinding shadowMapSamplerLayoutBinding = {};
- shadowMapSamplerLayoutBinding.binding = 9;
- shadowMapSamplerLayoutBinding.descriptorCount = 1;
- shadowMapSamplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
- shadowMapSamplerLayoutBinding.pImmutableSamplers = nullptr;
- shadowMapSamplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
- std::array<VkDescriptorSetLayoutBinding, 10> bindings = {
- uboLayoutBinding, usvLayoutBinding, usfLayoutBinding, specialLayoutBinding, specialTextureLayoutBinding,
- samplerLayoutBinding, specularSamplerLayoutBinding, bumpSamplerLayoutBinding, cutoffSamplerLayoutBinding,
- shadowMapSamplerLayoutBinding};
- VkDescriptorSetLayoutCreateInfo layoutInfo = {};
- layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
- layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
- layoutInfo.pBindings = bindings.data();
- if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) {
- throw std::runtime_error("failed to create descriptor set layout!");
- }
- }
- void VEngine::createGraphicsPipeline() {
- auto vertShaderCode = readFile("D:/project/vulkan_engine/media/shaders/shadow.vert.spv");
- auto fragShaderCode = readFile("D:/project/vulkan_engine/media/shaders/shadow.frag.spv");
- VkShaderModule vertShaderModule = createShaderModule(vertShaderCode);
- VkShaderModule fragShaderModule = createShaderModule(fragShaderCode);
- VkPipelineShaderStageCreateInfo vertShaderStageInfo = {};
- vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
- vertShaderStageInfo.module = vertShaderModule;
- vertShaderStageInfo.pName = "main";
- VkPipelineShaderStageCreateInfo fragShaderStageInfo = {};
- fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
- fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
- fragShaderStageInfo.module = fragShaderModule;
- fragShaderStageInfo.pName = "main";
- VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
- VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
- vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
- auto bindingDescription = Vertex::getBindingDescription();
- auto attributeDescriptions = Vertex::getAttributeDescriptions();
- vertexInputInfo.vertexBindingDescriptionCount = 1;
- vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
- vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
- vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
- VkPipelineInputAssemblyStateCreateInfo inputAssembly = {};
- inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
- inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
- inputAssembly.primitiveRestartEnable = VK_FALSE;
- VkViewport viewport = {};
- viewport.x = 0.0f;
- viewport.y = 0.0f;
- viewport.width = (float)swapChainExtent.width;
- viewport.height = (float)swapChainExtent.height;
- viewport.minDepth = 0.0f;
- viewport.maxDepth = 1.0f;
- VkRect2D scissor = {};
- scissor.offset = { 0, 0 };
- scissor.extent = swapChainExtent;
- VkPipelineViewportStateCreateInfo viewportState = {};
- viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
- viewportState.viewportCount = 1;
- viewportState.pViewports = &viewport;
- viewportState.scissorCount = 1;
- viewportState.pScissors = &scissor;
- VkPipelineRasterizationStateCreateInfo rasterizer = {};
- rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
- rasterizer.depthClampEnable = VK_FALSE;
- rasterizer.rasterizerDiscardEnable = VK_FALSE;
- rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
- rasterizer.lineWidth = 1.0f;
- rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
- rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
- rasterizer.depthBiasEnable = VK_FALSE;
- VkPipelineMultisampleStateCreateInfo multisampling = {};
- multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
- multisampling.sampleShadingEnable = VK_TRUE;
- multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
- VkPipelineDepthStencilStateCreateInfo depthStencil = {};
- depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
- depthStencil.depthTestEnable = VK_TRUE;
- depthStencil.depthWriteEnable = VK_TRUE;
- depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
- depthStencil.depthBoundsTestEnable = VK_FALSE;
- depthStencil.stencilTestEnable = VK_FALSE;
- std::array<VkPipelineColorBlendAttachmentState, 1> colorBlendAttachment = {};
- colorBlendAttachment[0].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
- colorBlendAttachment[0].blendEnable = VK_FALSE;
- /*colorBlendAttachment[0].colorBlendOp = VK_BLEND_OP_ADD;
- colorBlendAttachment[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_COLOR;
- colorBlendAttachment[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
- colorBlendAttachment[0].alphaBlendOp = VK_BLEND_OP_ADD;
- colorBlendAttachment[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
- colorBlendAttachment[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;*/
- VkPipelineColorBlendStateCreateInfo colorBlending = {};
- colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
- colorBlending.logicOpEnable = VK_FALSE;
- colorBlending.logicOp = VK_LOGIC_OP_COPY;
- colorBlending.attachmentCount = 1;
- colorBlending.pAttachments = colorBlendAttachment.data();
- colorBlending.blendConstants[0] = 0.0f;
- colorBlending.blendConstants[1] = 0.0f;
- colorBlending.blendConstants[2] = 0.0f;
- colorBlending.blendConstants[3] = 0.0f;
- // Push constants for model matrices
- VkPushConstantRange pushConstantRange = {};
- pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
- pushConstantRange.offset = 0;
- pushConstantRange.size = sizeof(ConstantMatrixModel);
- VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
- pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
- pipelineLayoutInfo.setLayoutCount = 1;
- pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
- pipelineLayoutInfo.pushConstantRangeCount = 1;
- pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
- if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {
- throw std::runtime_error("failed to create pipeline layout!");
- }
- VkGraphicsPipelineCreateInfo pipelineInfo = {};
- pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
- pipelineInfo.stageCount = 2;
- pipelineInfo.pStages = shaderStages;
- pipelineInfo.pVertexInputState = &vertexInputInfo;
- pipelineInfo.pInputAssemblyState = &inputAssembly;
- pipelineInfo.pViewportState = &viewportState;
- pipelineInfo.pRasterizationState = &rasterizer;
- pipelineInfo.pMultisampleState = &multisampling;
- pipelineInfo.pDepthStencilState = &depthStencil;
- pipelineInfo.pColorBlendState = &colorBlending;
- pipelineInfo.layout = pipelineLayout;
- pipelineInfo.renderPass = renderPass;
- pipelineInfo.subpass = 0;
- pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
- if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {
- throw std::runtime_error("failed to create graphics pipeline!");
- }
- vkDestroyShaderModule(device, fragShaderModule, nullptr);
- vkDestroyShaderModule(device, vertShaderModule, nullptr);
- }
- void VEngine::createFramebuffers() {
- swapChainFramebuffers.resize(swapChainImageViews.size());
- createImage(
- swapChainExtent.width,
- swapChainExtent.height,
- depthFormat,
- VK_IMAGE_TILING_OPTIMAL,
- VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
- depthImage,
- depthImageMemory);
- depthImageView = createImageView(depthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT);
- for (size_t i = 0; i < swapChainImageViews.size(); i++) {
- std::array<VkImageView, 2> attachments = {
- swapChainImageViews[i],
- depthImageView
- };
- VkFramebufferCreateInfo framebufferInfo = {};
- framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
- framebufferInfo.renderPass = renderPass;
- framebufferInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
- framebufferInfo.pAttachments = attachments.data();
- framebufferInfo.width = swapChainExtent.width;
- framebufferInfo.height = swapChainExtent.height;
- framebufferInfo.layers = 1;
- if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {
- throw std::runtime_error("failed to create framebuffer!");
- }
- }
- }
- void VEngine::createCommandBuffers()
- {
- commandBuffers.resize(swapChainFramebuffers.size());
- VkCommandBufferAllocateInfo allocInfo = {};
- allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- allocInfo.commandPool = commandPool;
- allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- allocInfo.commandBufferCount = (uint32_t)commandBuffers.size();
- if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) {
- throw std::runtime_error("failed to allocate command buffers!");
- }
- for (size_t i = 0; i < commandBuffers.size(); i++) {
- VkCommandBufferBeginInfo beginInfo = {};
- beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT;
- vkBeginCommandBuffer(commandBuffers[i], &beginInfo);
- VkRenderPassBeginInfo renderPassInfo = {};
- renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
- renderPassInfo.renderPass = renderPass;
- renderPassInfo.framebuffer = swapChainFramebuffers[i];
- renderPassInfo.renderArea.offset = { 0, 0 };
- renderPassInfo.renderArea.extent = swapChainExtent;
- std::array<VkClearValue, 2> clearValues = {};
- clearValues[0].color = { 0.2f, 0.2f, 0.2f, 1.0f };
- clearValues[1].depthStencil = { 1.0f, 0 };
- renderPassInfo.clearValueCount = static_cast<uint32_t>(clearValues.size());
- renderPassInfo.pClearValues = clearValues.data();
- vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
- vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
- VkBuffer vertexBuffers[] = { vertexBuffer };
- VkDeviceSize offsets[] = { 0 };
- vkCmdBindVertexBuffers(commandBuffers[i], 0, 1, vertexBuffers, offsets);
- vkCmdBindIndexBuffer(commandBuffers[i], indexBuffer, 0, VK_INDEX_TYPE_UINT32);
- vkCmdBindDescriptorSets(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
- glm::mat4 model = glm::mat4(1.0f);
- vkCmdPushConstants(commandBuffers[i], pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(ConstantMatrixModel), &model);
- vkCmdDrawIndexed(commandBuffers[i], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
- vkCmdEndRenderPass(commandBuffers[i]);
- if (vkEndCommandBuffer(commandBuffers[i]) != VK_SUCCESS) {
- throw std::runtime_error("failed to record command buffer!");
- }
- }
- }
- void VEngine::createCommandPool() {
- QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice);
- VkCommandPoolCreateInfo poolInfo = {};
- poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
- poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily;
- if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) {
- throw std::runtime_error("failed to create graphics command pool!");
- }
- }
- VkBool32 VEngine::findDepthFormat(VkPhysicalDevice physicalDevice, VkFormat *depthFormat) {
- // Since all depth formats may be optional, we need to find a suitable depth format to use
- // Start with the highest precision packed format
- std::vector<VkFormat> depthFormats = {
- VK_FORMAT_D32_SFLOAT_S8_UINT,
- VK_FORMAT_D32_SFLOAT,
- VK_FORMAT_D24_UNORM_S8_UINT,
- VK_FORMAT_D16_UNORM_S8_UINT,
- VK_FORMAT_D16_UNORM
- };
- for (auto& format : depthFormats)
- {
- VkFormatProperties formatProps;
- vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProps);
- // Format must support depth stencil attachment for optimal tiling
- if (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
- {
- *depthFormat = format;
- return true;
- }
- }
- return false;
- }
- bool VEngine::hasStencilComponent(VkFormat format) {
- return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
- }
- VkImageView VEngine::createImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags) {
- VkImageViewCreateInfo viewInfo = {};
- viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
- viewInfo.image = image;
- viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
- viewInfo.format = format;
- viewInfo.subresourceRange.aspectMask = aspectFlags;
- viewInfo.subresourceRange.baseMipLevel = 0;
- viewInfo.subresourceRange.levelCount = 1;
- viewInfo.subresourceRange.baseArrayLayer = 0;
- viewInfo.subresourceRange.layerCount = 1;
- VkImageView imageView;
- if (vkCreateImageView(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) {
- throw std::runtime_error("failed to create texture image view!");
- }
- return imageView;
- }
- void VEngine::createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) {
- VkImageCreateInfo imageInfo = {};
- imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
- imageInfo.imageType = VK_IMAGE_TYPE_2D;
- imageInfo.extent.width = width;
- imageInfo.extent.height = height;
- imageInfo.extent.depth = 1;
- imageInfo.mipLevels = 1;
- imageInfo.arrayLayers = 1;
- imageInfo.format = format;
- imageInfo.tiling = tiling;
- imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
- imageInfo.usage = usage;
- imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
- imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- 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!");
- }
- vkBindImageMemory(device, image, imageMemory, 0);
- }
- void VEngine::createTestImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) {
- VkImageCreateInfo imageInfo = {};
- imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
- imageInfo.imageType = VK_IMAGE_TYPE_2D;
- imageInfo.extent.width = width;
- imageInfo.extent.height = height;
- imageInfo.extent.depth = 1;
- imageInfo.mipLevels = 1;
- imageInfo.arrayLayers = 1;
- imageInfo.format = format;
- imageInfo.tiling = tiling;
- imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
- imageInfo.usage = usage;
- imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
- imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
- 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!");
- }
- vkBindImageMemory(device, image, imageMemory, 0);
- }
- void VEngine::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout) {
- VkCommandBuffer commandBuffer = beginSingleTimeCommands();
- VkImageMemoryBarrier barrier = {};
- barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- barrier.oldLayout = oldLayout;
- barrier.newLayout = newLayout;
- barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- barrier.image = image;
- if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
- barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
- if (hasStencilComponent(format)) {
- barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
- }
- }
- else {
- barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- }
- barrier.subresourceRange.baseMipLevel = 0;
- barrier.subresourceRange.levelCount = 1;
- barrier.subresourceRange.baseArrayLayer = 0;
- barrier.subresourceRange.layerCount = 1;
- if (oldLayout == VK_IMAGE_LAYOUT_PREINITIALIZED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
- barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
- barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
- }
- else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
- barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
- barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
- }
- else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
- barrier.srcAccessMask = 0;
- barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
- }
- else {
- throw std::invalid_argument("unsupported layout transition!");
- }
- vkCmdPipelineBarrier(
- commandBuffer,
- VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
- 0,
- 0, nullptr,
- 0, nullptr,
- 1, &barrier
- );
- endSingleTimeCommands(commandBuffer);
- }
- void VEngine::copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height) {
- 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 = 1;
- 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 VEngine::loadModel() {
- tinyobj::attrib_t attrib;
- std::vector<tinyobj::shape_t> shapes;
- std::vector<tinyobj::material_t> materials;
- std::string err;
- if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &err, MODEL_PATH.c_str())) {
- throw std::runtime_error(err);
- }
- std::unordered_map<Vertex, uint32_t> uniqueVertices = {};
- for (const auto& shape : shapes) {
- for (const auto& index : shape.mesh.indices) {
- Vertex vertex = {};
- vertex.pos = {
- attrib.vertices[3 * index.vertex_index + 0],
- attrib.vertices[3 * index.vertex_index + 1],
- attrib.vertices[3 * index.vertex_index + 2]
- };
- vertex.normal = {
- attrib.normals[3 * index.normal_index + 0],
- attrib.normals[3 * index.normal_index + 1],
- attrib.normals[3 * index.normal_index + 2]
- };
- vertex.texCoord = {
- attrib.texcoords[2 * index.texcoord_index + 0],
- 1.0f - attrib.texcoords[2 * index.texcoord_index + 1]
- };
- if (uniqueVertices.count(vertex) == 0) {
- uniqueVertices[vertex] = static_cast<uint32_t>(vertices.size());
- vertices.push_back(vertex);
- }
- indices.push_back(uniqueVertices[vertex]);
- }
- }
- }
- void VEngine::createVertexBuffer() {
- VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size();
- VkBuffer stagingBuffer;
- VkDeviceMemory stagingBufferMemory;
- createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
- void* data;
- vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
- memcpy(data, vertices.data(), (size_t)bufferSize);
- vkUnmapMemory(device, stagingBufferMemory);
- createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory);
- copyBuffer(stagingBuffer, vertexBuffer, bufferSize);
- vkDestroyBuffer(device, stagingBuffer, nullptr);
- vkFreeMemory(device, stagingBufferMemory, nullptr);
- }
- void VEngine::createIndexBuffer() {
- VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size();
- VkBuffer stagingBuffer;
- VkDeviceMemory stagingBufferMemory;
- createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
- void* data;
- vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
- memcpy(data, indices.data(), (size_t)bufferSize);
- vkUnmapMemory(device, stagingBufferMemory);
- createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory);
- copyBuffer(stagingBuffer, indexBuffer, bufferSize);
- vkDestroyBuffer(device, stagingBuffer, nullptr);
- vkFreeMemory(device, stagingBufferMemory, nullptr);
- }
- void VEngine::createUniformBuffer() {
- createBuffer(sizeof(UniformMatrixBufferObject), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformMatrixBuffer, uniformMatrixBufferMemory);
- }
- void VEngine::createDescriptorPool() {
- std::array<VkDescriptorPoolSize, 1> poolSizes = {};
- poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- poolSizes[0].descriptorCount = 1;
- VkDescriptorPoolCreateInfo poolInfo = {};
- poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
- poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
- poolInfo.pPoolSizes = poolSizes.data();
- poolInfo.maxSets = 1;
- if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
- throw std::runtime_error("failed to create descriptor pool!");
- }
- }
- void VEngine::createDescriptorSet() {
- VkDescriptorSetLayout layouts[] = { descriptorSetLayout };
- VkDescriptorSetAllocateInfo allocInfo = {};
- allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
- allocInfo.descriptorPool = descriptorPool;
- allocInfo.descriptorSetCount = 1;
- allocInfo.pSetLayouts = layouts;
- if (vkAllocateDescriptorSets(device, &allocInfo, &descriptorSet) != VK_SUCCESS) {
- throw std::runtime_error("failed to allocate descriptor set!");
- }
- VkDescriptorBufferInfo matrixBufferInfo = {};
- matrixBufferInfo.buffer = uniformMatrixBuffer;
- matrixBufferInfo.offset = 0;
- matrixBufferInfo.range = sizeof(UniformMatrixBufferObject);
- std::array<VkWriteDescriptorSet, 1> descriptorWrites = {};
- descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
- descriptorWrites[0].dstSet = descriptorSet;
- descriptorWrites[0].dstBinding = 0;
- descriptorWrites[0].dstArrayElement = 0;
- descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
- descriptorWrites[0].descriptorCount = 1;
- descriptorWrites[0].pBufferInfo = &matrixBufferInfo;
- vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
- }
- void VEngine::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 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 buffer memory!");
- }
- vkBindBufferMemory(device, buffer, bufferMemory, 0);
- }
- VkCommandBuffer VEngine::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 VEngine::endSingleTimeCommands(VkCommandBuffer commandBuffer) {
- vkEndCommandBuffer(commandBuffer);
- VkSubmitInfo submitInfo = {};
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &commandBuffer;
- /* vkQueueSubmit(presentQueue, 1, &submitInfo, VK_NULL_HANDLE);
- vkQueueWaitIdle(presentQueue);*/
- // Create fence to ensure that the command buffer has finished executing
- VkFenceCreateInfo fenceInfo = {};
- fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
- VkFence fence;
- vkCreateFence(device, &fenceInfo, nullptr, &fence);
- vkQueueSubmit(presentQueue, 1, &submitInfo, fence);
- vkWaitForFences(device, 1, &fence, VK_TRUE, 100000000000);
- vkDestroyFence(device, fence, nullptr);
- vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
- }
- void VEngine::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) {
- VkCommandBuffer commandBuffer = beginSingleTimeCommands();
- VkBufferCopy copyRegion = {};
- copyRegion.size = size;
- vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, ©Region);
- endSingleTimeCommands(commandBuffer);
- }
- uint32_t VEngine::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 VEngine::createSemaphores() {
- VkSemaphoreCreateInfo semaphoreInfo = {};
- semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphore));
- VK_CHECK_RESULT(vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphore));
- }
- void VEngine::updateUniformBuffer() {
- camera_control();
- if (glfwGetKey(window, GLFW_KEY_F4) == GLFW_PRESS) {
- auto color_file_name = "D:/project/vulkan_engine/build/color.ppm";
- auto depth_file_name = "D:/project/vulkan_engine/build/depth.ppm";
- SaveOutputColorTexture(color_file_name);
- SaveOutputDepthTexture(depth_file_name);
- }
- }
- void VEngine::camera_control()
- {
- // glfwGetTime is called only once, the first time this function is called
- static double lastTime = glfwGetTime();
- // Compute time difference between current and last frame
- double currentTime = glfwGetTime();
- float deltaTime = float(currentTime - lastTime);
- // Get mouse position
- double xpos, ypos;
- if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) {
- glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
- if (kFirstPress) {
- glfwGetCursorPos(window, &xpos, &ypos);
- last_xpos_ = xpos;
- last_ypos_ = ypos;
- kFirstPress = false;
- return;
- }
- glfwGetCursorPos(window, &xpos, &ypos);
- // Compute new orientation
- horizontalAngle += mouseSpeed * float(last_xpos_ - xpos);
- verticalAngle += mouseSpeed * float(last_ypos_ - ypos);
- last_xpos_ = xpos;
- last_ypos_ = ypos;
- }
- else {
- glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
- kFirstPress = true;
- }
- // Direction : Spherical coordinates to Cartesian coordinates conversion
- glm::vec3 direction(
- cos(verticalAngle) * sin(horizontalAngle),
- sin(verticalAngle),
- cos(verticalAngle) * cos(horizontalAngle)
- );
- // Right vector
- glm::vec3 right = glm::vec3(
- sin(horizontalAngle - 3.14f / 2.0f),
- 0,
- cos(horizontalAngle - 3.14f / 2.0f)
- );
- // Up vector
- glm::vec3 up = glm::cross(right, direction);
- // Move forward
- if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
- position += direction * deltaTime * speed;
- }
- // Move backward
- if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
- position -= direction * deltaTime * speed;
- }
- // Strafe right
- if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
- position += right * deltaTime * speed;
- }
- // Strafe left
- if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
- position -= right * deltaTime * speed;
- }
- // Strafe up
- if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS) {
- position.y += 2 * deltaTime * speed;
- }
- // Strafe down
- if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS) {
- position.y -= 2 * deltaTime * speed;
- }
- // Strafe down
- if (glfwGetKey(window, GLFW_KEY_M) == GLFW_PRESS) {
- RecreateBufer();
- }
- float FoV = initialFoV;// - 5 * glfwGetMouseWheel(); // Now GLFW 3 requires setting up a callback for this. It's a bit too complicated for this beginner's tutorial, so it's disabled instead.
- UniformMatrixBufferObject umo = {};
- // Projection matrix : 45?Field of View, 4:3 ratio, display range : 0.1 unit <-> 100 units
- umo.proj = clip * glm::perspective(FoV, 4.0f / 3.0f, 0.1f, 1000.0f);
- //ubo.proj[1][1] *= -1;
- auto camera_point = position + direction;
- // Camera matrix
- umo.view = glm::lookAt(
- position, // Camera is here
- camera_point, // and looks here : at the same position, plus "direction"
- up // Head is up (set to 0,-1,0 to look upside-down)
- );
- // direction light
- umo.lightPos = lightPos;
- // For the next frame, the "last time" will be "now"
- lastTime = currentTime;
- void* data;
- vkMapMemory(device, uniformMatrixBufferMemory, 0, sizeof(umo), 0, &data);
- memcpy(data, &umo, sizeof(umo));
- vkUnmapMemory(device, uniformMatrixBufferMemory);
- }
- void VEngine::drawFrame() {
- VkResult result = vkAcquireNextImageKHR(device, swapChain, std::numeric_limits<uint64_t>::max(), imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex);
- /*if (result == VK_ERROR_OUT_OF_DATE_KHR) {
- recreateSwapChain();
- return;
- }
- else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
- throw std::runtime_error("failed to acquire swap chain image!");
- }*/
- VkSubmitInfo shadowSubmitInfo = {};
- shadowSubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- VkSubmitInfo submitInfo = {};
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_ALL_COMMANDS_BIT };
- submitInfo.waitSemaphoreCount = 1;
- submitInfo.pWaitSemaphores = &imageAvailableSemaphore;
- submitInfo.pWaitDstStageMask = waitStages;
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &commandBuffers[imageIndex];
- submitInfo.signalSemaphoreCount = 1;
- submitInfo.pSignalSemaphores = &renderFinishedSemaphore;
- VK_CHECK_RESULT(vkQueueSubmit(presentQueue, 1, &submitInfo, VK_NULL_HANDLE));
- VkPresentInfoKHR presentInfo = {};
- presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
- presentInfo.waitSemaphoreCount = 1;
- presentInfo.pWaitSemaphores = &renderFinishedSemaphore;
- VkSwapchainKHR swapChains[] = { swapChain };
- presentInfo.swapchainCount = 1;
- presentInfo.pSwapchains = swapChains;
- presentInfo.pImageIndices = &imageIndex;
- VK_CHECK_RESULT(vkQueuePresentKHR(presentQueue, &presentInfo));
- /*if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
- recreateSwapChain();
- }
- else if (result != VK_SUCCESS) {
- throw std::runtime_error("failed to present swap chain image!");
- }*/
- VK_CHECK_RESULT(vkQueueWaitIdle(presentQueue));
- }
- void VEngine::RecreateBufer()
- {
- createVertexBuffer();
- createIndexBuffer();
- createUniformBuffer();
- createDescriptorPool();
- createDescriptorSet();
- createCommandBuffers();
- }
- void VEngine::SaveOutputColorTexture(const std::string& path)
- {
- bool supportsBlit = true;
- // Check blit support for source and destination
- VkFormatProperties formatProps;
- // Check if the device supports blitting from optimal images (the swapchain images are in optimal format)
- vkGetPhysicalDeviceFormatProperties(physicalDevice, swapChainImageFormat, &formatProps);
- if (!(formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT)) {
- std::cerr << "Device does not support blitting from optimal tiled images, using copy instead of blit!" << std::endl;
- supportsBlit = false;
- }
- // Check if the device supports blitting to linear images
- vkGetPhysicalDeviceFormatProperties(physicalDevice, swapChainImageFormat, &formatProps);
- if (!(formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT)) {
- std::cerr << "Device does not support blitting to linear tiled images, using copy instead of blit!" << std::endl;
- supportsBlit = false;
- }
- // Source for the copy is the last rendered swapchain image
- VkImage srcImage = swapChainImages[imageIndex];
- // Create the linear tiled destination image to copy to and to read the memory from
- VkImageCreateInfo imageCreateCI = {};
- imageCreateCI.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
- imageCreateCI.imageType = VK_IMAGE_TYPE_2D;
- // Note that vkCmdBlitImage (if supported) will also do format conversions if the swapchain color format would differ
- imageCreateCI.format = swapChainImageFormat;
- imageCreateCI.extent.width = WIDTH;
- imageCreateCI.extent.height = HEIGHT;
- imageCreateCI.extent.depth = 1;
- imageCreateCI.arrayLayers = 1;
- imageCreateCI.mipLevels = 1;
- imageCreateCI.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- imageCreateCI.samples = VK_SAMPLE_COUNT_1_BIT;
- imageCreateCI.tiling = VK_IMAGE_TILING_LINEAR;
- imageCreateCI.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT;
- // Create the image
- VkImage dstImage;
- VK_CHECK_RESULT(vkCreateImage(device, &imageCreateCI, nullptr, &dstImage));
- // Create memory to back up the image
- VkMemoryRequirements memRequirements;
- VkMemoryAllocateInfo memAllocInfo{};
- memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
- VkDeviceMemory dstImageMemory;
- vkGetImageMemoryRequirements(device, dstImage, &memRequirements);
- memAllocInfo.allocationSize = memRequirements.size;
- // Memory must be host visible to copy from
- memAllocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
- VK_CHECK_RESULT(vkAllocateMemory(device, &memAllocInfo, nullptr, &dstImageMemory));
- VK_CHECK_RESULT(vkBindImageMemory(device, dstImage, dstImageMemory, 0));
- // Do the actual blit from the swapchain image to our host visible destination image
- VkCommandBufferAllocateInfo cmdBufAllocateInfo{};
- cmdBufAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- cmdBufAllocateInfo.commandPool = commandPool;
- cmdBufAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- cmdBufAllocateInfo.commandBufferCount = 1;
- VkCommandBuffer copyCmd;
- VK_CHECK_RESULT(vkAllocateCommandBuffers(device, &cmdBufAllocateInfo, ©Cmd));
- VkCommandBufferBeginInfo cmdBufInfo{};
- cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- VK_CHECK_RESULT(vkBeginCommandBuffer(copyCmd, &cmdBufInfo));
- VkImageMemoryBarrier imageMemoryBarrier{};
- imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- // Transition destination image to transfer destination layout
- insertImageMemoryBarrier(
- copyCmd,
- dstImage,
- 0,
- VK_ACCESS_TRANSFER_WRITE_BIT,
- VK_IMAGE_LAYOUT_UNDEFINED,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_PIPELINE_STAGE_TRANSFER_BIT,
- VK_PIPELINE_STAGE_TRANSFER_BIT,
- VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
- // Transition swapchain image from present to transfer source layout
- insertImageMemoryBarrier(
- copyCmd,
- srcImage,
- VK_ACCESS_MEMORY_READ_BIT,
- VK_ACCESS_TRANSFER_READ_BIT,
- VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- VK_PIPELINE_STAGE_TRANSFER_BIT,
- VK_PIPELINE_STAGE_TRANSFER_BIT,
- VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
- // If source and destination support blit we'll blit as this also does automatic format conversion (e.g. from BGR to RGB)
- if (supportsBlit)
- {
- // Define the region to blit (we will blit the whole swapchain image)
- VkOffset3D blitSize;
- blitSize.x = WIDTH;
- blitSize.y = HEIGHT;
- blitSize.z = 1;
- VkImageBlit imageBlitRegion{};
- imageBlitRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- imageBlitRegion.srcSubresource.layerCount = 1;
- imageBlitRegion.srcOffsets[1] = blitSize;
- imageBlitRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- imageBlitRegion.dstSubresource.layerCount = 1;
- imageBlitRegion.dstOffsets[1] = blitSize;
- // Issue the blit command
- vkCmdBlitImage(
- copyCmd,
- srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- 1,
- &imageBlitRegion,
- VK_FILTER_NEAREST);
- }
- else
- {
- // Otherwise use image copy (requires us to manually flip components)
- VkImageCopy imageCopyRegion{};
- imageCopyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- imageCopyRegion.srcSubresource.layerCount = 1;
- imageCopyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
- imageCopyRegion.dstSubresource.layerCount = 1;
- imageCopyRegion.extent.width = WIDTH;
- imageCopyRegion.extent.height = HEIGHT;
- imageCopyRegion.extent.depth = 1;
- // Issue the copy command
- vkCmdCopyImage(
- copyCmd,
- srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- dstImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- 1,
- &imageCopyRegion);
- }
- // Transition destination image to general layout, which is the required layout for mapping the image memory later on
- insertImageMemoryBarrier(
- copyCmd,
- dstImage,
- VK_ACCESS_TRANSFER_WRITE_BIT,
- VK_ACCESS_MEMORY_READ_BIT,
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
- VK_IMAGE_LAYOUT_GENERAL,
- VK_PIPELINE_STAGE_TRANSFER_BIT,
- VK_PIPELINE_STAGE_TRANSFER_BIT,
- VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
- // Transition back the swap chain image after the blit is done
- insertImageMemoryBarrier(
- copyCmd,
- srcImage,
- VK_ACCESS_TRANSFER_READ_BIT,
- VK_ACCESS_MEMORY_READ_BIT,
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
- VK_PIPELINE_STAGE_TRANSFER_BIT,
- VK_PIPELINE_STAGE_TRANSFER_BIT,
- VkImageSubresourceRange{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
- endSingleTimeCommands(copyCmd);
- // Get layout of the image (including row pitch)
- VkImageSubresource subResource{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 };
- VkSubresourceLayout subResourceLayout;
- vkGetImageSubresourceLayout(device, dstImage, &subResource, &subResourceLayout);
- // Map image memory so we can start copying from it
- const char* data;
- vkMapMemory(device, dstImageMemory, 0, VK_WHOLE_SIZE, 0, (void**)&data);
- data += subResourceLayout.offset;
- std::ofstream file(path, std::ios::out | std::ios::binary);
- // ppm header
- file << "P6\n" << WIDTH << "\n" << HEIGHT << "\n" << 255 << "\n";
- // If source is BGR (destination is always RGB) and we can't use blit (which does automatic conversion), we'll have to manually swizzle color components
- bool colorSwizzle = false;
- // Check if source is BGR
- // Note: Not complete, only contains most common and basic BGR surface formats for demonstation purposes
- if (!supportsBlit)
- {
- std::vector<VkFormat> formatsBGR = { VK_FORMAT_B8G8R8A8_SRGB, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SNORM };
- colorSwizzle = (std::find(formatsBGR.begin(), formatsBGR.end(), swapChainImageFormat) != formatsBGR.end());
- }
- auto image_size = HEIGHT * WIDTH;
- for (uint32_t y = 0; y < HEIGHT; y++)
- {
- unsigned int *row = (unsigned int*)data;
- for (uint32_t x = 0; x < WIDTH; x++)
- {
- if (colorSwizzle)
- {
- file.write((char*)row + 2, 1);
- file.write((char*)row + 1, 1);
- file.write((char*)row, 1);
- }
- else
- {
- file.write((char*)row, 3);
- }
- row++;
- }
- data += subResourceLayout.rowPitch;
- }
- file.close();
- std::cout << "Screenshot saved to disk" << std::endl;
- // Clean up resources
- vkUnmapMemory(device, dstImageMemory);
- vkFreeMemory(device, dstImageMemory, nullptr);
- vkDestroyImage(device, dstImage, nullptr);
- }
- void VEngine::SaveOutputDepthTexture(const std::string& path)
- {
- VkDeviceSize size = WIDTH * HEIGHT * 4;
- VkBuffer dstBuffer;
- VkDeviceMemory dstMemory;
- createBuffer(
- size,
- VK_BUFFER_USAGE_TRANSFER_DST_BIT,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
- dstBuffer,
- dstMemory);
- VkCommandBuffer copyCmd = beginSingleTimeCommands();
- // depth format -> VK_FORMAT_D32_SFLOAT_S8_UINT
- VkBufferImageCopy region = {};
- region.bufferOffset = 0;
- region.bufferImageHeight = 0;
- region.bufferRowLength = 0;
- region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
- region.imageSubresource.mipLevel = 0;
- region.imageSubresource.baseArrayLayer = 0;
- region.imageSubresource.layerCount = 1;
- region.imageOffset = VkOffset3D{ 0, 0, 0 };
- region.imageExtent = VkExtent3D{ swapChainExtent.width, swapChainExtent.height, 1};
- vkCmdCopyImageToBuffer(
- copyCmd,
- depthImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
- dstBuffer,
- 1,
- ®ion
- );
- endSingleTimeCommands(copyCmd);
- // Map image memory so we can start copying from it
- void *data;
- vkMapMemory(device, dstMemory, 0, size, 0, &data);
- std::ofstream file(path, std::ios::out | std::ios::binary);
- // ppm header
- file << "P6\n" << WIDTH << "\n" << HEIGHT << "\n" << 255 << "\n";
- float *row = (float*)data;
- auto size_v = WIDTH * HEIGHT;
- for (uint32_t y = 0; y < size_v; y++) {
- file.write((char*)row + 1, 1);
- file.write((char*)row + 1, 1);
- file.write((char*)row + 1, 1);
- row++;
- }
- file.close();
- // Clean up resources
- vkUnmapMemory(device, dstMemory);
- vkFreeMemory(device, dstMemory, nullptr);
- vkDestroyBuffer(device, dstBuffer, nullptr);
- }
- VkShaderModule VEngine::createShaderModule(const std::vector<char>& code) {
- VkShaderModuleCreateInfo createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
- createInfo.codeSize = code.size();
- createInfo.pCode = reinterpret_cast<const uint32_t*>(code.data());
- VkShaderModule shaderModule;
- if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) {
- throw std::runtime_error("failed to create shader module!");
- }
- return shaderModule;
- }
- VkSurfaceFormatKHR VEngine::chooseSwapSurfaceFormat(const std::vector<VkSurfaceFormatKHR>& availableFormats) {
- if (availableFormats.size() == 1 && availableFormats[0].format == VK_FORMAT_UNDEFINED) {
- return{ VK_FORMAT_B8G8R8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR };
- }
- for (const auto& availableFormat : availableFormats) {
- if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
- return availableFormat;
- }
- }
- return availableFormats[0];
- }
- VkPresentModeKHR VEngine::chooseSwapPresentMode(const std::vector<VkPresentModeKHR> availablePresentModes) {
- VkPresentModeKHR bestMode = VK_PRESENT_MODE_FIFO_KHR;
- for (const auto& availablePresentMode : availablePresentModes) {
- if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) {
- return availablePresentMode;
- }
- else if (availablePresentMode == VK_PRESENT_MODE_IMMEDIATE_KHR) {
- bestMode = availablePresentMode;
- }
- }
- return bestMode;
- }
- VkExtent2D VEngine::chooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities) {
- if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max()) {
- return capabilities.currentExtent;
- }
- else {
- int width, height;
- glfwGetWindowSize(window, &width, &height);
- VkExtent2D actualExtent = {
- static_cast<uint32_t>(width),
- static_cast<uint32_t>(height)
- };
- actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
- actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height));
- return actualExtent;
- }
- }
- VEngine::SwapChainSupportDetails VEngine::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;
- }
- bool VEngine::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 && supportedFeatures.samplerAnisotropy;
- }
- bool VEngine::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();
- }
- VEngine::QueueFamilyIndices VEngine::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;
- }
- VkBool32 presentSupport = false;
- vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface, &presentSupport);
- if (queueFamily.queueCount > 0 && presentSupport) {
- indices.presentFamily = i;
- }
- if (indices.isComplete()) {
- break;
- }
- i++;
- }
- return indices;
- }
- std::vector<const char*> VEngine::getRequiredExtensions() {
- std::vector<const char*> extensions;
- unsigned int glfwExtensionCount = 0;
- const char** glfwExtensions;
- glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
- for (unsigned int i = 0; i < glfwExtensionCount; i++) {
- extensions.push_back(glfwExtensions[i]);
- }
- if (enableValidationLayers) {
- extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
- }
- return extensions;
- }
- bool VEngine::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<char> VEngine::readFile(const std::string& filename) {
- std::ifstream file(filename, std::ios::ate | std::ios::binary);
- if (!file.is_open()) {
- throw std::runtime_error("failed to open file!");
- }
- size_t fileSize = (size_t)file.tellg();
- std::vector<char> buffer(fileSize);
- file.seekg(0);
- file.read(buffer.data(), fileSize);
- file.close();
- return buffer;
- }
- glm::mat4 VEngine::GetOrthoMatrix(float left, float right, float bottom, float top, float near, float far)
- {
- glm::mat4 ortho = glm::mat4{
- 2.0f / (right - left), 0.0f, 0.0f, 0.0f,
- 0.0f, 2.0f / (bottom - top), 0.0f, 0.0f,
- 0.0f, 0.0f, 1.0f / (near - far), 0.0f,
- -(right + left) / (right - left),
- -(bottom + top) / (bottom - top),
- near / (near - far),
- 1.0f
- };
- return ortho;
- }
- void VEngine::insertImageMemoryBarrier(
- VkCommandBuffer cmdbuffer,
- VkImage image,
- VkAccessFlags srcAccessMask,
- VkAccessFlags dstAccessMask,
- VkImageLayout oldImageLayout,
- VkImageLayout newImageLayout,
- VkPipelineStageFlags srcStageMask,
- VkPipelineStageFlags dstStageMask,
- VkImageSubresourceRange subresourceRange)
- {
- VkImageMemoryBarrier imageMemoryBarrier{};
- imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
- imageMemoryBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- imageMemoryBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
- imageMemoryBarrier.srcAccessMask = srcAccessMask;
- imageMemoryBarrier.dstAccessMask = dstAccessMask;
- imageMemoryBarrier.oldLayout = oldImageLayout;
- imageMemoryBarrier.newLayout = newImageLayout;
- imageMemoryBarrier.image = image;
- imageMemoryBarrier.subresourceRange = subresourceRange;
- vkCmdPipelineBarrier(
- cmdbuffer,
- srcStageMask,
- dstStageMask,
- 0,
- 0, nullptr,
- 0, nullptr,
- 1, &imageMemoryBarrier);
- }
- }
Add Comment
Please, Sign In to add comment