#include "renderer.h" #include #include #include #include #include #include #include #include "platform.h" #include "mesh.h" Renderer::Renderer() { createInstance(); #ifdef DEBUG if(enableDebug) createDebugMessenger(); #endif createLogicalDevice(); createCommandPool(); createPresentationRenderPass(); createDescriptorPool(); worldPass_ = new WorldPass(*this); postPass_ = new PostPass(*this); } Renderer::~Renderer() { vkDeviceWaitIdle(device_); delete postPass_; delete worldPass_; vkDestroyDescriptorPool(device_, descriptorPool_, nullptr); 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) { vkAcquireNextImageKHR(device_, target->swapchain, UINT64_MAX, target->imageAvailableSemaphore, nullptr, &target->currentImage); vkWaitForFences(device_, 1, &target->fences[target->currentImage], true, UINT64_MAX); vkResetFences(device_, 1, &target->fences[target->currentImage]); const VkCommandBuffer commandBuffer = target->commandBuffers[target->currentImage]; 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); worldPass_->render(commandBuffer, world, target); VkClearValue clearColor = {}; VkRenderPassBeginInfo renderPassBeginInfo = {}; renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; renderPassBeginInfo.framebuffer = target->swapchainFramebuffers[target->currentImage]; renderPassBeginInfo.renderPass = presentationRenderPass_; renderPassBeginInfo.renderArea.extent = target->extent; renderPassBeginInfo.clearValueCount = 1; renderPassBeginInfo.pClearValues = &clearColor; vkCmdBeginRenderPass(commandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); postPass_->render(commandBuffer, target); 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[target->currentImage]); 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 = &target->currentImage; 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_B8G8R8A8_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 | VK_IMAGE_USAGE_TRANSFER_SRC_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->swapchainImages = new VkImage[swapchainImageCount]; vkGetSwapchainImagesKHR(device_, target->swapchain, &swapchainImageCount, target->swapchainImages); // create frame resources target->swapchainImageViews = new VkImageView[swapchainImageCount]; target->swapchainFramebuffers = new VkFramebuffer[swapchainImageCount]; target->offscreenColorImages = new VkImage[swapchainImageCount]; target->offscreenColorMemory = new VkDeviceMemory[swapchainImageCount]; target->offscreenColorImageViews = new VkImageView[swapchainImageCount]; target->offscreenDepthImages = new VkImage[swapchainImageCount]; target->offscreenDepthMemory = new VkDeviceMemory[swapchainImageCount]; target->offscreenDepthImageViews = new VkImageView[swapchainImageCount]; target->offscreenFramebuffers = new VkFramebuffer[swapchainImageCount]; for(uint32_t i = 0; i < swapchainImageCount; i++) { // swapchain image view { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = target->swapchainImages[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->swapchainImageViews[i]); } // swapchain framebuffer { VkFramebufferCreateInfo framebufferInfo = {}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = presentationRenderPass_; framebufferInfo.attachmentCount = 1; framebufferInfo.pAttachments = &target->swapchainImageViews[i]; framebufferInfo.width = target->extent.width; framebufferInfo.height = target->extent.height; framebufferInfo.layers = 1; vkCreateFramebuffer(device_, &framebufferInfo, nullptr, &target->swapchainFramebuffers[i]); } // offscreen image { VkImageCreateInfo imageCreateInfo = {}; imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT; imageCreateInfo.extent.width = target->extent.width; imageCreateInfo.extent.height = target->extent.height; imageCreateInfo.extent.depth = 1; imageCreateInfo.mipLevels = 1; imageCreateInfo.arrayLayers = 1; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; vkCreateImage(device_, &imageCreateInfo, nullptr, &target->offscreenColorImages[i]); VkMemoryRequirements memoryRequirements = {}; vkGetImageMemoryRequirements(device_, target->offscreenColorImages[i], &memoryRequirements); VkMemoryAllocateInfo allocateInfo = {}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = memoryRequirements.size; allocateInfo.memoryTypeIndex = findMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vkAllocateMemory(device_, &allocateInfo, nullptr, &target->offscreenColorMemory[i]); vkBindImageMemory(device_, target->offscreenColorImages[i], target->offscreenColorMemory[i], 0); } // offscreen image view { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = target->offscreenColorImages[i]; createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; createInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT; createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; createInfo.subresourceRange.levelCount = 1; createInfo.subresourceRange.layerCount = 1; vkCreateImageView(device_, &createInfo, nullptr, &target->offscreenColorImageViews[i]); } // offscreen depth image { VkImageCreateInfo imageCreateInfo = {}; imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.format = VK_FORMAT_D32_SFLOAT; imageCreateInfo.extent.width = target->extent.width; imageCreateInfo.extent.height = target->extent.height; imageCreateInfo.extent.depth = 1; imageCreateInfo.mipLevels = 1; imageCreateInfo.arrayLayers = 1; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; vkCreateImage(device_, &imageCreateInfo, nullptr, &target->offscreenDepthImages[i]); VkMemoryRequirements memoryRequirements = {}; vkGetImageMemoryRequirements(device_, target->offscreenDepthImages[i], &memoryRequirements); VkMemoryAllocateInfo allocateInfo = {}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = memoryRequirements.size; allocateInfo.memoryTypeIndex = findMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); vkAllocateMemory(device_, &allocateInfo, nullptr, &target->offscreenDepthMemory[i]); vkBindImageMemory(device_, target->offscreenDepthImages[i], target->offscreenDepthMemory[i], 0); } // offscreen depth image view { VkImageViewCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; createInfo.image = target->offscreenDepthImages[i]; createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; createInfo.format = VK_FORMAT_D32_SFLOAT; createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; createInfo.subresourceRange.levelCount = 1; createInfo.subresourceRange.layerCount = 1; vkCreateImageView(device_, &createInfo, nullptr, &target->offscreenDepthImageViews[i]); } // offscreen framebuffer { const std::array attachments = { target->offscreenColorImageViews[i], target->offscreenDepthImageViews[i] }; VkFramebufferCreateInfo framebufferInfo = {}; framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; framebufferInfo.renderPass = worldPass_->getRenderPass(); framebufferInfo.attachmentCount = attachments.size(); framebufferInfo.pAttachments = attachments.data(); framebufferInfo.width = target->extent.width; framebufferInfo.height = target->extent.height; framebufferInfo.layers = 1; vkCreateFramebuffer(device_, &framebufferInfo, nullptr, &target->offscreenFramebuffers[i]); } } postPass_->createDescriptorSet(target); 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; vkFreeDescriptorSets(device_, descriptorPool_, target->numImages, target->postSets); for(uint32_t i = 0; i < target->numImages; i++) { vkDestroyFramebuffer(device_, target->offscreenFramebuffers[i], nullptr); vkDestroyImageView(device_, target->offscreenDepthImageViews[i], nullptr); vkFreeMemory(device_, target->offscreenDepthMemory[i], nullptr); vkDestroyImage(device_, target->offscreenDepthImages[i], nullptr); vkDestroyImageView(device_, target->offscreenColorImageViews[i], nullptr); vkFreeMemory(device_, target->offscreenColorMemory[i], nullptr); vkDestroyImage(device_, target->offscreenColorImages[i], nullptr); vkDestroyFramebuffer(device_, target->swapchainFramebuffers[i], nullptr); vkDestroyImageView(device_, target->swapchainImageViews[i], nullptr); } delete[] target->offscreenFramebuffers; delete[] target->offscreenDepthImageViews; delete[] target->offscreenDepthMemory; delete[] target->offscreenDepthImages; delete[] target->offscreenColorImageViews; delete[] target->offscreenColorMemory; delete[] target->offscreenColorImages; delete[] target->swapchainFramebuffers; delete[] target->swapchainImageViews; delete[] target->swapchainImages; delete[] target->postSets; vkDestroySwapchainKHR(device_, target->swapchain, nullptr); delete target; } void Renderer::takeScreenshot(RenderTarget* target) { VkImageCreateInfo imageCreateInfo = {}; imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; imageCreateInfo.format = VK_FORMAT_R8G8B8A8_UNORM; imageCreateInfo.extent.width = target->extent.width; imageCreateInfo.extent.height = target->extent.height; imageCreateInfo.extent.depth = 1; imageCreateInfo.mipLevels = 1; imageCreateInfo.arrayLayers = 1; imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT; VkImage image = nullptr; vkCreateImage(device_, &imageCreateInfo, nullptr, &image); VkMemoryRequirements memoryRequirements = {}; vkGetImageMemoryRequirements(device_, image, &memoryRequirements); VkMemoryAllocateInfo allocateInfo = {}; allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocateInfo.allocationSize = memoryRequirements.size; allocateInfo.memoryTypeIndex = findMemoryType(memoryRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); VkDeviceMemory imageMemory = nullptr; vkAllocateMemory(device_, &allocateInfo, nullptr, &imageMemory); vkBindImageMemory(device_, image, imageMemory, 0); VkCommandBufferAllocateInfo bufferAllocateInfo = {}; bufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; bufferAllocateInfo.commandPool = commandPool_; bufferAllocateInfo.commandBufferCount = 1; VkCommandBuffer commandBuffer = nullptr; vkAllocateCommandBuffers(device_, &bufferAllocateInfo, &commandBuffer); VkCommandBufferBeginInfo beginInfo = {}; beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; vkBeginCommandBuffer(commandBuffer, &beginInfo); // change screenshot image to transfer dst layout { VkImageMemoryBarrier imageMemoryBarrier = {}; imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; imageMemoryBarrier.image = image; imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageMemoryBarrier.subresourceRange.layerCount = 1; imageMemoryBarrier.subresourceRange.levelCount = 1; vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); } const VkImage srcImage = target->swapchainImages[0]; // FIXME: use previous image // change offscreen image to transfer src layout { VkImageMemoryBarrier imageMemoryBarrier = {}; imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imageMemoryBarrier.srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; imageMemoryBarrier.image = srcImage; imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageMemoryBarrier.subresourceRange.layerCount = 1; imageMemoryBarrier.subresourceRange.levelCount = 1; vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); } VkImageCopy imageCopy = {}; imageCopy.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageCopy.srcSubresource.layerCount = 1; imageCopy.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageCopy.dstSubresource.layerCount = 1; imageCopy.extent.width = target->extent.width; imageCopy.extent.height = target->extent.height; imageCopy.extent.depth = 1; // Issue the copy command vkCmdCopyImage( commandBuffer, srcImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imageCopy); // change screenshot image from transfer dst to general (for mapping memory) { VkImageMemoryBarrier imageMemoryBarrier = {}; imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; imageMemoryBarrier.image = image; imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageMemoryBarrier.subresourceRange.layerCount = 1; imageMemoryBarrier.subresourceRange.levelCount = 1; vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); } // change offscreen image layout back to normal { VkImageMemoryBarrier imageMemoryBarrier = {}; imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; imageMemoryBarrier.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; imageMemoryBarrier.image = srcImage; imageMemoryBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; imageMemoryBarrier.subresourceRange.layerCount = 1; imageMemoryBarrier.subresourceRange.levelCount = 1; vkCmdPipelineBarrier( commandBuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); } vkEndCommandBuffer(commandBuffer); VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &commandBuffer; VkFenceCreateInfo fenceCreateInfo = {}; fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; VkFence fence = nullptr; vkCreateFence(device_, &fenceCreateInfo, nullptr, &fence); vkQueueSubmit(graphicsQueue_, 1, &submitInfo, fence); vkWaitForFences(device_, 1, &fence, true, -1); vkDestroyFence(device_, fence, nullptr); vkFreeCommandBuffers(device_, commandPool_, 1, &commandBuffer); VkImageSubresource subResource = {}; subResource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; VkSubresourceLayout subResourceLayout = {}; vkGetImageSubresourceLayout(device_, image, &subResource, &subResourceLayout); const char* data = nullptr; vkMapMemory(device_, imageMemory, 0, VK_WHOLE_SIZE, 0, (void**)&data); data += subResourceLayout.offset; std::ofstream file("screenshot.ppm", std::ios::out | std::ios::binary); file << "P6\n" << target->extent.width << "\n" << target->extent.height << "\n" << 255 << "\n"; for(uint32_t y = 0; y < target->extent.height; y++) { const unsigned int* row = reinterpret_cast(data); for(uint32_t x = 0; x < target->extent.width; x++) { file.write(reinterpret_cast(row), 3); row++; } data += subResourceLayout.rowPitch; } file.close(); vkUnmapMemory(device_, imageMemory); vkFreeMemory(device_, imageMemory, nullptr); vkDestroyImage(device_, image, nullptr); } 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(const uint32_t typeFilter, const VkMemoryPropertyFlags properties) { for (uint32_t i = 0; i < deviceMemoryProperties_.memoryTypeCount; i++) { if ((typeFilter & (1 << i)) && (deviceMemoryProperties_.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::destroyMeshBuffers(Mesh* mesh) { vkDeviceWaitIdle(device_); vkFreeMemory(device_, mesh->indexMemory, nullptr); vkDestroyBuffer(device_, mesh->indexBuffer, nullptr); vkFreeMemory(device_, mesh->vertexMemory, nullptr); vkDestroyBuffer(device_, mesh->vertexBuffer, nullptr); } 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; vkGetPhysicalDeviceMemoryProperties(physicalDevice_, &deviceMemoryProperties_); 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_); } void Renderer::createDescriptorPool() { const std::array poolSizes = { VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 15}, VkDescriptorPoolSize{VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 15} }; VkDescriptorPoolCreateInfo poolInfo = {}; poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; poolInfo.poolSizeCount = poolSizes.size(); poolInfo.pPoolSizes = poolSizes.data(); poolInfo.maxSets = 15; vkCreateDescriptorPool(device_, &poolInfo, nullptr, &descriptorPool_); }