#include "renderer.h" #include #include #include #include #include #include #include "platform.h" #include "mesh.h" Renderer::Renderer() { createInstance(); #ifdef DEBUG if(enableDebug) createDebugMessenger(); #endif createLogicalDevice(); createCommandPool(); createPresentationRenderPass(); worldPass_ = new WorldPass(*this); } Renderer::~Renderer() { vkDeviceWaitIdle(device_); delete worldPass_; vkDestroyRenderPass(device_, presentationRenderPass_, nullptr); vkDestroyCommandPool(device_, commandPool_, nullptr); #ifdef DEBUG destroyMessenger_(instance_, messenger_, nullptr); #endif vkDestroyDevice(device_, nullptr); vkDestroyInstance(instance_, nullptr); } void Renderer::render(World& world, RenderTarget* target) { uint32_t imageIndex = 0; vkAcquireNextImageKHR(device_, target->swapchain, UINT64_MAX, target->imageAvailableSemaphore, nullptr, &imageIndex); vkWaitForFences(device_, 1, &target->fences[imageIndex], true, UINT64_MAX); vkResetFences(device_, 1, &target->fences[imageIndex]); const VkCommandBuffer commandBuffer = target->commandBuffers[imageIndex]; VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; vkBeginCommandBuffer(commandBuffer, &beginInfo); VkViewport viewport = {}; viewport.width = target->extent.width; viewport.height = target->extent.height; viewport.maxDepth = 1.0f; vkCmdSetViewport(commandBuffer, 0, 1, &viewport); VkRect2D scissor = {}; scissor.extent = target->extent; vkCmdSetScissor(commandBuffer, 0, 1, &scissor); VkClearValue clearColor = {}; clearColor.color.float32[0] = sin((platform::getTime() / 500.0f) * 0.2f) * 0.5f + 0.5f; clearColor.color.float32[1] = sin((platform::getTime() / 500.0f) * 0.4f) * 0.5f + 0.5f; clearColor.color.float32[2] = sin((platform::getTime() / 500.0f) * 0.8f) * 0.5f + 0.5f; VkRenderPassBeginInfo renderPassBeginInfo = {}; renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassBeginInfo.framebuffer = target->framebuffers[imageIndex]; renderPassBeginInfo.renderPass = presentationRenderPass_; renderPassBeginInfo.renderArea.extent = target->extent; renderPassBeginInfo.clearValueCount = 1; renderPassBeginInfo.pClearValues = &clearColor; vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); worldPass_->render(world, commandBuffer); vkCmdEndRenderPass(commandBuffer); vkEndCommandBuffer(commandBuffer); const VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.waitSemaphoreCount = 1; submitInfo.pWaitSemaphores = &target->imageAvailableSemaphore; submitInfo.pWaitDstStageMask = &waitStage; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &commandBuffer; submitInfo.signalSemaphoreCount = 1; submitInfo.pSignalSemaphores = &target->renderFinishedSemaphore; vkQueueSubmit(graphicsQueue_, 1, &submitInfo, target->fences[imageIndex]); VkPresentInfoKHR presentInfo = {}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.waitSemaphoreCount = 1; presentInfo.pWaitSemaphores = &target->renderFinishedSemaphore; presentInfo.swapchainCount = 1; presentInfo.pSwapchains = &target->swapchain; presentInfo.pImageIndices = &imageIndex; vkQueuePresentKHR(graphicsQueue_, &presentInfo); } RenderTarget* Renderer::createSurfaceRenderTarget(VkSurfaceKHR surface, RenderTarget* oldTarget) { vkDeviceWaitIdle(device_); RenderTarget* target = new RenderTarget(); target->surface = surface; VkSurfaceCapabilitiesKHR surfaceCapabilities = {}; vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice_, surface, &surfaceCapabilities); target->extent = surfaceCapabilities.currentExtent; uint32_t surfaceFormatCount = 0; vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice_, surface, &surfaceFormatCount, nullptr); VkSurfaceFormatKHR* surfaceFormats = new VkSurfaceFormatKHR[surfaceFormatCount]; vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice_, surface, &surfaceFormatCount, surfaceFormats); uint32_t chosenFormat = 0; for(uint32_t i = 0; i < surfaceFormatCount; i++) { if(surfaceFormats[i].format == VK_FORMAT_R8G8B8_SRGB) chosenFormat = i; } VkBool32 supported = false; vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice_, queueIndices.presentation, surface, &supported); VkSwapchainCreateInfoKHR swapchainCreateInfo = {}; swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchainCreateInfo.surface = surface; swapchainCreateInfo.minImageCount = surfaceCapabilities.minImageCount; swapchainCreateInfo.imageColorSpace = surfaceFormats[chosenFormat].colorSpace; swapchainCreateInfo.imageFormat = surfaceFormats[chosenFormat].format; swapchainCreateInfo.imageExtent = surfaceCapabilities.currentExtent; swapchainCreateInfo.imageArrayLayers = 1; swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapchainCreateInfo.queueFamilyIndexCount = 1; swapchainCreateInfo.pQueueFamilyIndices = &queueIndices.presentation; swapchainCreateInfo.preTransform = surfaceCapabilities.currentTransform; swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapchainCreateInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; swapchainCreateInfo.clipped = true; if(oldTarget) swapchainCreateInfo.oldSwapchain = oldTarget->swapchain; vkCreateSwapchainKHR(device_, &swapchainCreateInfo, nullptr, &target->swapchain); if(oldTarget) destroyRenderTarget(oldTarget); delete[] surfaceFormats; uint32_t swapchainImageCount = 0; vkGetSwapchainImagesKHR(device_, target->swapchain, &swapchainImageCount, nullptr); target->numImages = swapchainImageCount; target->images = new VkImage[swapchainImageCount]; vkGetSwapchainImagesKHR(device_, target->swapchain, &swapchainImageCount, target->images); target->imageViews = new VkImageView[swapchainImageCount]; for(uint32_t i = 0; i < swapchainImageCount; i++) { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = target->images[i]; createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; createInfo.format = VK_FORMAT_B8G8R8A8_SRGB; createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; createInfo.subresourceRange.levelCount = 1; createInfo.subresourceRange.layerCount = 1; vkCreateImageView(device_, &createInfo, nullptr, &target->imageViews[i]); } target->framebuffers = new VkFramebuffer[swapchainImageCount]; for(uint32_t i = 0; i < swapchainImageCount; i++) { VkFramebufferCreateInfo framebufferInfo = {}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = presentationRenderPass_; framebufferInfo.attachmentCount = 1; framebufferInfo.pAttachments = &target->imageViews[i]; framebufferInfo.width = target->extent.width; framebufferInfo.height = target->extent.height; framebufferInfo.layers = 1; vkCreateFramebuffer(device_, &framebufferInfo, nullptr, &target->framebuffers[i]); } VkCommandBufferAllocateInfo allocateInfo = {}; allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocateInfo.commandPool = commandPool_; allocateInfo.commandBufferCount = swapchainImageCount; target->commandBuffers = new VkCommandBuffer[swapchainImageCount]; vkAllocateCommandBuffers(device_, &allocateInfo, target->commandBuffers); VkSemaphoreCreateInfo semaphoreCreateInfo = {}; semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; vkCreateSemaphore(device_, &semaphoreCreateInfo, nullptr, &target->imageAvailableSemaphore); vkCreateSemaphore(device_, &semaphoreCreateInfo, nullptr, &target->renderFinishedSemaphore); VkFenceCreateInfo fenceCreateInfo = {}; fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; target->fences = new VkFence[swapchainImageCount]; for(uint32_t i = 0; i < swapchainImageCount; i++) vkCreateFence(device_, &fenceCreateInfo, nullptr, &target->fences[i]); return target; } void Renderer::destroyRenderTarget(RenderTarget* target) { vkDeviceWaitIdle(device_); for(uint32_t i = 0; i < target->numImages; i++) vkDestroyFence(device_, target->fences[i], nullptr); delete[] target->fences; vkDestroySemaphore(device_, target->renderFinishedSemaphore, nullptr); vkDestroySemaphore(device_, target->imageAvailableSemaphore, nullptr); vkFreeCommandBuffers(device_, commandPool_, target->numImages, target->commandBuffers); delete[] target->commandBuffers; for(uint32_t i = 0; i < target->numImages; i++) { vkDestroyFramebuffer(device_, target->framebuffers[i], nullptr); vkDestroyImageView(device_, target->imageViews[i], nullptr); } delete[] target->framebuffers; delete[] target->imageViews; delete[] target->images; vkDestroySwapchainKHR(device_, target->swapchain, nullptr); delete target; } VkShaderModule Renderer::createShader(const char* path) { std::ifstream file(path, std::ios::ate | std::ios::binary); size_t fileSize = (size_t) file.tellg(); std::vector buffer(fileSize); file.seekg(0); file.read(buffer.data(), fileSize); file.close(); VkShaderModuleCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; createInfo.codeSize = buffer.size(); createInfo.pCode = reinterpret_cast(buffer.data()); VkShaderModule shaderModule; vkCreateShaderModule(device_, &createInfo, nullptr, &shaderModule); return shaderModule; } uint32_t Renderer::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; } } return 0; } void Renderer::fillMeshBuffers(Mesh* mesh) { // vertex { VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = sizeof(Vertex) * mesh->vertices.size(); bufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; vkCreateBuffer(device_, &bufferInfo, nullptr, &mesh->vertexBuffer); VkMemoryRequirements memRequirements; vkGetBufferMemoryRequirements(device_, mesh->vertexBuffer, &memRequirements); VkMemoryAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); vkAllocateMemory(device_, &allocInfo, nullptr, &mesh->vertexMemory); vkBindBufferMemory(device_, mesh->vertexBuffer, mesh->vertexMemory, 0); void* data; vkMapMemory(device_, mesh->vertexMemory, 0, bufferInfo.size, 0, &data); memcpy(data, mesh->vertices.data(), bufferInfo.size); vkUnmapMemory(device_, mesh->vertexMemory); } // index { VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; bufferInfo.size = sizeof(uint32_t) * mesh->indices.size(); bufferInfo.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; vkCreateBuffer(device_, &bufferInfo, nullptr, &mesh->indexBuffer); VkMemoryRequirements memRequirements; vkGetBufferMemoryRequirements(device_, mesh->indexBuffer, &memRequirements); VkMemoryAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); vkAllocateMemory(device_, &allocInfo, nullptr, &mesh->indexMemory); vkBindBufferMemory(device_, mesh->indexBuffer, mesh->indexMemory, 0); void* data; vkMapMemory(device_, mesh->indexMemory, 0, bufferInfo.size, 0, &data); memcpy(data, mesh->indices.data(), bufferInfo.size); vkUnmapMemory(device_, mesh->indexMemory); } } void Renderer::createInstance() { uint32_t layerCount = 0; vkEnumerateInstanceLayerProperties(&layerCount, nullptr); VkLayerProperties* availableLayers = new VkLayerProperties[layerCount]; vkEnumerateInstanceLayerProperties(&layerCount, availableLayers); std::vector enabledLayers; #ifdef DEBUG for(uint32_t i = 0; i < layerCount; i++) { if(!strcmp(availableLayers[i].layerName, "VK_LAYER_LUNARG_standard_validation")) enabledLayers.push_back("VK_LAYER_LUNARG_standard_validation"); } #endif delete[] availableLayers; uint32_t extensionCount = 0; vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); VkExtensionProperties* availableExtensions = new VkExtensionProperties[extensionCount]; vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, availableExtensions); std::vector enabledExtensions; #ifdef DEBUG for(uint32_t i = 0; i < extensionCount; i++) { if(!strcmp(availableExtensions[i].extensionName, "VK_EXT_debug_utils")) { enabledExtensions.push_back("VK_EXT_debug_utils"); enableDebug = true; } } #endif delete[] availableExtensions; auto requiredExtensions = platform::getRequiredExtensions(); enabledExtensions.insert(enabledExtensions.end(), requiredExtensions.begin(), requiredExtensions.end()); VkInstanceCreateInfo instanceCreateInfo = {}; instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instanceCreateInfo.enabledLayerCount = enabledLayers.size(); instanceCreateInfo.ppEnabledLayerNames = enabledLayers.data(); instanceCreateInfo.enabledExtensionCount = enabledExtensions.size(); instanceCreateInfo.ppEnabledExtensionNames = enabledExtensions.data(); vkCreateInstance(&instanceCreateInfo, nullptr, &instance_); } #ifdef DEBUG void Renderer::createDebugMessenger() { createMessenger_ = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance_, "vkCreateDebugUtilsMessengerEXT"); destroyMessenger_ = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance_, "vkDestroyDebugUtilsMessengerEXT"); VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {}; messengerCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; messengerCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; messengerCreateInfo.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; messengerCreateInfo.pfnUserCallback = [](VkDebugUtilsMessageSeverityFlagBitsEXT, unsigned int, const VkDebugUtilsMessengerCallbackDataEXT* callback, void*) -> unsigned int { std::cout << callback->pMessage << std::endl; return VK_SUCCESS; }; createMessenger_(instance_, &messengerCreateInfo, nullptr, &messenger_); } #endif void Renderer::createLogicalDevice() { uint32_t physicalDeviceCount = 0; vkEnumeratePhysicalDevices(instance_, &physicalDeviceCount, nullptr); VkPhysicalDevice* physicalDevices = new VkPhysicalDevice[physicalDeviceCount]; vkEnumeratePhysicalDevices(instance_, &physicalDeviceCount, physicalDevices); for(uint32_t i = 0; i < physicalDeviceCount; i++) { VkPhysicalDeviceProperties properties = {}; vkGetPhysicalDeviceProperties(physicalDevices[i], &properties); physicalDevice_ = physicalDevices[i]; } delete[] physicalDevices; uint32_t queueFamilyPropertiesCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice_, &queueFamilyPropertiesCount, nullptr); VkQueueFamilyProperties* queueFamilyProperties = new VkQueueFamilyProperties[queueFamilyPropertiesCount]; vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice_, &queueFamilyPropertiesCount, queueFamilyProperties); for(uint32_t i = 0; i < queueFamilyPropertiesCount; i++) { if(queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) queueIndices.graphics = i; } delete[] queueFamilyProperties; queueIndices.presentation = queueIndices.graphics; //FIXME: this may not always be true!! const std::set queueFamilyIndices = {queueIndices.graphics}; std::vector deviceQueueCreateInfos; for(auto queueFamilyIndex : queueFamilyIndices) { const float priority = 1.0f; VkDeviceQueueCreateInfo queueCreateInfo = {}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = queueFamilyIndex; queueCreateInfo.queueCount = 1; queueCreateInfo.pQueuePriorities = &priority; deviceQueueCreateInfos.push_back(queueCreateInfo); } const std::vector enabledExtensions = {"VK_KHR_swapchain"}; VkDeviceCreateInfo deviceCreateInfo = {}; deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; deviceCreateInfo.queueCreateInfoCount = deviceQueueCreateInfos.size(); deviceCreateInfo.pQueueCreateInfos = deviceQueueCreateInfos.data(); deviceCreateInfo.enabledExtensionCount = enabledExtensions.size(); deviceCreateInfo.ppEnabledExtensionNames = enabledExtensions.data(); vkCreateDevice(physicalDevice_, &deviceCreateInfo, nullptr, &device_); vkGetDeviceQueue(device_, queueIndices.graphics, 0, &graphicsQueue_); } void Renderer::createCommandPool() { VkCommandPoolCreateInfo poolCreateInfo = {}; poolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolCreateInfo.queueFamilyIndex = queueIndices.graphics; poolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; vkCreateCommandPool(device_, &poolCreateInfo, nullptr, &commandPool_); } void Renderer::createPresentationRenderPass() { VkAttachmentDescription colorAttachment = {}; colorAttachment.format = VK_FORMAT_B8G8R8A8_SRGB; colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; VkAttachmentReference colorAttachmentRef = {}; colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; VkSubpassDescription subpass = {}; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; subpass.colorAttachmentCount = 1; subpass.pColorAttachments = &colorAttachmentRef; VkRenderPassCreateInfo renderPassInfo = {}; renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; renderPassInfo.attachmentCount = 1; renderPassInfo.pAttachments = &colorAttachment; renderPassInfo.subpassCount = 1; renderPassInfo.pSubpasses = &subpass; vkCreateRenderPass(device_, &renderPassInfo, nullptr, &presentationRenderPass_); }