20#if defined(__FreeBSD__) || defined(NDEBUG)
27std::vector<VkVertexInputAttributeDescription>
31std::vector<VkVertexInputAttributeDescription>
35std::vector<VkVertexInputAttributeDescription>
40 mWindowSystem{windowSystem},
47 SetupDebugMessenger();
50 CreateLogicalDevice();
58 CreateColorResources();
59 CreateDepthResources();
63 CreateCommandBuffers();
69 vkWaitForFences(mLogicalDevice, 1, &mInFlightFences[mCurrentFrame], VK_TRUE, UINT64_MAX);
72 VkResult result = vkAcquireNextImageKHR(mLogicalDevice, mSwapChain, UINT64_MAX, mImageAvailableSemaphores[mCurrentFrame], VK_NULL_HANDLE, &imageIndex);
74 if (result == VK_ERROR_OUT_OF_DATE_KHR)
81 if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
83 throw std::runtime_error(
"failed to acquire swap chain image!");
87 vkResetFences(mLogicalDevice, 1, &mInFlightFences[mCurrentFrame]);
89 vkResetCommandBuffer(mCommandBuffers[mCurrentFrame], 0);
90 RecordCommandBuffer(mCommandBuffers[mCurrentFrame], imageIndex);
92 VkSubmitInfo submitInfo{};
93 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
95 VkSemaphore waitSemaphores[] = { mImageAvailableSemaphores[mCurrentFrame] };
96 VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
97 submitInfo.waitSemaphoreCount = 1;
98 submitInfo.pWaitSemaphores = waitSemaphores;
99 submitInfo.pWaitDstStageMask = waitStages;
101 submitInfo.commandBufferCount = 1;
102 submitInfo.pCommandBuffers = &mCommandBuffers[mCurrentFrame];
104 VkSemaphore signalSemaphores[] = { mRenderFinishedSemaphores[mCurrentFrame] };
105 submitInfo.signalSemaphoreCount = 1;
106 submitInfo.pSignalSemaphores = signalSemaphores;
108 if (vkQueueSubmit(mGraphicsQueue, 1, &submitInfo, mInFlightFences[mCurrentFrame]) != VK_SUCCESS)
110 throw std::runtime_error(
"failed to submit draw command buffer!");
113 VkPresentInfoKHR presentInfo{};
114 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
116 presentInfo.waitSemaphoreCount = 1;
117 presentInfo.pWaitSemaphores = signalSemaphores;
119 VkSwapchainKHR swapChains[] = { mSwapChain };
120 presentInfo.swapchainCount = 1;
121 presentInfo.pSwapchains = swapChains;
123 presentInfo.pImageIndices = &imageIndex;
125 result = vkQueuePresentKHR(mPresentQueue, &presentInfo);
127 if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || mWindowSystem.IsFramebufferResized())
129 mWindowSystem.ResetFramebufferResizedFlag();
134 if (result != VK_SUCCESS)
136 throw std::runtime_error(
"failed to present swap chain image!");
145 vkWaitForFences(mLogicalDevice, 1, &mInFlightFences[mCurrentFrame], VK_TRUE, UINT64_MAX);
147 VkResult result = vkAcquireNextImageKHR(mLogicalDevice, mSwapChain, UINT64_MAX, mImageAvailableSemaphores[mCurrentFrame], VK_NULL_HANDLE, &mImageIndex);
149 if (result == VK_ERROR_OUT_OF_DATE_KHR)
156 if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR)
158 throw std::runtime_error(
"failed to acquire swap chain image!");
162 vkResetFences(mLogicalDevice, 1, &mInFlightFences[mCurrentFrame]);
164 vkResetCommandBuffer(mCommandBuffers[mCurrentFrame], 0);
171 VkCommandBufferBeginInfo beginInfo{};
172 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
176 if (vkBeginCommandBuffer(mCommandBuffers[mCurrentFrame], &beginInfo) != VK_SUCCESS)
178 throw std::runtime_error(
"failed to begin recording command buffer!");
181 VkRenderPassBeginInfo renderPassInfo{};
182 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
183 renderPassInfo.renderPass = mRenderPass;
184 renderPassInfo.framebuffer = mSwapChainFramebuffers[mImageIndex];
186 renderPassInfo.renderArea.offset = { 0, 0 };
187 renderPassInfo.renderArea.extent = mSwapChainExtent;
189 std::array<VkClearValue, 2> clearValues{};
190 clearValues[0].color = { {0.0f, 0.0f, 0.0f, 1.0f} };
191 clearValues[1].depthStencil = { 1.0f, 0 };
192 renderPassInfo.clearValueCount =
static_cast<uint32_t
>(clearValues.size());
193 renderPassInfo.pClearValues = clearValues.data();
195 vkCmdBeginRenderPass(mCommandBuffers[mCurrentFrame], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
200 vkCmdEndRenderPass(mCommandBuffers[mCurrentFrame]);
205 if (vkEndCommandBuffer(mCommandBuffers[mCurrentFrame]) != VK_SUCCESS)
207 throw std::runtime_error(
"failed to record command buffer!");
210 VkSubmitInfo submitInfo{};
211 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
213 VkSemaphore waitSemaphores[] = { mImageAvailableSemaphores[mCurrentFrame] };
214 VkPipelineStageFlags waitStages[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
215 submitInfo.waitSemaphoreCount = 1;
216 submitInfo.pWaitSemaphores = waitSemaphores;
217 submitInfo.pWaitDstStageMask = waitStages;
219 submitInfo.commandBufferCount = 1;
220 submitInfo.pCommandBuffers = &mCommandBuffers[mCurrentFrame];
222 VkSemaphore signalSemaphores[] = { mRenderFinishedSemaphores[mCurrentFrame] };
223 submitInfo.signalSemaphoreCount = 1;
224 submitInfo.pSignalSemaphores = signalSemaphores;
226 if (vkQueueSubmit(mGraphicsQueue, 1, &submitInfo, mInFlightFences[mCurrentFrame]) != VK_SUCCESS)
228 throw std::runtime_error(
"failed to submit draw command buffer!");
231 VkPresentInfoKHR presentInfo{};
232 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
234 presentInfo.waitSemaphoreCount = 1;
235 presentInfo.pWaitSemaphores = signalSemaphores;
237 VkSwapchainKHR swapChains[] = { mSwapChain };
238 presentInfo.swapchainCount = 1;
239 presentInfo.pSwapchains = swapChains;
241 presentInfo.pImageIndices = &mImageIndex;
243 VkResult result = vkQueuePresentKHR(mPresentQueue, &presentInfo);
245 if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || mWindowSystem.IsFramebufferResized())
247 mWindowSystem.ResetFramebufferResizedFlag();
252 if (result != VK_SUCCESS)
254 throw std::runtime_error(
"failed to present swap chain image!");
263 vkDeviceWaitIdle(mLogicalDevice);
272 vkDestroySemaphore(mLogicalDevice, mRenderFinishedSemaphores[i],
nullptr);
273 vkDestroySemaphore(mLogicalDevice, mImageAvailableSemaphores[i],
nullptr);
274 vkDestroyFence(mLogicalDevice, mInFlightFences[i],
nullptr);
277 vkDestroyCommandPool(mLogicalDevice, mCommandPool,
nullptr);
279 vkDestroyDevice(mLogicalDevice,
nullptr);
282 DestroyDebugUtilsMessengerEXT(mInstance, mDebugMessenger,
nullptr);
284 vkDestroySurfaceKHR(mInstance, mSurface,
nullptr);
285 vkDestroyInstance(mInstance,
nullptr);
290 if (std::find(mObservers.begin(), mObservers.end(), notifier) == mObservers.end())
292 mObservers.push_back(notifier);
298 mObservers.erase(std::remove(mObservers.begin(), mObservers.end(), notifier), mObservers.end());
321void VulkanRenderer::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory)
323 VkBufferCreateInfo bufferInfo{};
324 bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
325 bufferInfo.size = size;
327 bufferInfo.usage = usage;
328 bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
330 if (vkCreateBuffer(mLogicalDevice, &bufferInfo,
nullptr, &buffer) != VK_SUCCESS)
332 throw std::runtime_error(
"failed to create vertex buffer!");
335 VkMemoryRequirements memRequirements;
336 vkGetBufferMemoryRequirements(mLogicalDevice, buffer, &memRequirements);
338 VkMemoryAllocateInfo allocInfo{};
339 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
340 allocInfo.allocationSize = memRequirements.size;
341 allocInfo.memoryTypeIndex =
FindMemoryType(memRequirements.memoryTypeBits, properties);
343 if (vkAllocateMemory(mLogicalDevice, &allocInfo,
nullptr, &bufferMemory) != VK_SUCCESS)
345 throw std::runtime_error(
"failed to allocate vertex buffer memory!");
348 vkBindBufferMemory(mLogicalDevice, buffer, bufferMemory, 0);
353 auto commandBuffer = BeginSingleTimeCommand();
355 VkBufferCopy copyRegion{};
356 copyRegion.srcOffset = 0;
357 copyRegion.dstOffset = 0;
358 copyRegion.size = size;
359 vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, ©Region);
361 EndSingleTimeCommand(commandBuffer);
366 return mLogicalDevice;
371 VkCommandBuffer commandBuffer = BeginSingleTimeCommand();
373 VkImageMemoryBarrier barrier{};
374 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
375 barrier.oldLayout = oldLayout;
376 barrier.newLayout = newLayout;
378 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
379 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
381 barrier.image = image;
382 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
383 barrier.subresourceRange.baseMipLevel = 0;
384 barrier.subresourceRange.levelCount = mipmapLevels;
385 barrier.subresourceRange.baseArrayLayer = 0;
386 barrier.subresourceRange.layerCount = 1;
388 VkPipelineStageFlags sourceStage;
389 VkPipelineStageFlags destinationStage;
391 if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
393 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
395 if (HasStencilComponent(format))
397 barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
402 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
405 if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
406 barrier.srcAccessMask = 0;
407 barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
409 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
410 destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
412 else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
413 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
414 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
416 sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
417 destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
419 else if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
420 barrier.srcAccessMask = 0;
421 barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
423 sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
424 destinationStage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
427 throw std::invalid_argument(
"unsupported layout transition!");
430 vkCmdPipelineBarrier(
432 sourceStage, destinationStage,
439 EndSingleTimeCommand(commandBuffer);
444 VkCommandBuffer commandBuffer = BeginSingleTimeCommand();
446 VkBufferImageCopy region{};
447 region.bufferOffset = 0;
448 region.bufferRowLength = 0;
449 region.bufferImageHeight = 0;
451 region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
452 region.imageSubresource.mipLevel = 0;
453 region.imageSubresource.baseArrayLayer = 0;
454 region.imageSubresource.layerCount = 1;
456 region.imageOffset = { 0, 0, 0 };
457 region.imageExtent = {
463 vkCmdCopyBufferToImage(
467 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
472 EndSingleTimeCommand(commandBuffer);
478 VkFormatProperties formatProperties;
479 vkGetPhysicalDeviceFormatProperties(mPhysicalDevice, imageFormat, &formatProperties);
481 if (!(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT))
483 throw std::runtime_error(
"texture image format does not support linear blitting!");
486 VkCommandBuffer commandBuffer = BeginSingleTimeCommand();
488 VkImageMemoryBarrier barrier{};
489 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
490 barrier.image = image;
491 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
492 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
493 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
494 barrier.subresourceRange.baseArrayLayer = 0;
495 barrier.subresourceRange.layerCount = 1;
496 barrier.subresourceRange.levelCount = 1;
498 int32_t mipWidth = texWidth;
499 int32_t mipHeight = texHeight;
501 for (uint32_t i = 1; i < mipLevels; i++)
503 barrier.subresourceRange.baseMipLevel = i - 1;
504 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
505 barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
506 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
507 barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
509 vkCmdPipelineBarrier(commandBuffer,
510 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
516 blit.srcOffsets[0] = { 0, 0, 0 };
517 blit.srcOffsets[1] = { mipWidth, mipHeight, 1 };
518 blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
519 blit.srcSubresource.mipLevel = i - 1;
520 blit.srcSubresource.baseArrayLayer = 0;
521 blit.srcSubresource.layerCount = 1;
522 blit.dstOffsets[0] = { 0, 0, 0 };
523 blit.dstOffsets[1] = { mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 };
524 blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
525 blit.dstSubresource.mipLevel = i;
526 blit.dstSubresource.baseArrayLayer = 0;
527 blit.dstSubresource.layerCount = 1;
529 vkCmdBlitImage(commandBuffer,
530 image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
531 image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
535 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
536 barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
537 barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
538 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
540 vkCmdPipelineBarrier(commandBuffer,
541 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
546 if (mipWidth > 1) mipWidth /= 2;
547 if (mipHeight > 1) mipHeight /= 2;
550 barrier.subresourceRange.baseMipLevel = mipLevels - 1;
551 barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
552 barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
553 barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
554 barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
556 vkCmdPipelineBarrier(commandBuffer,
557 VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
562 EndSingleTimeCommand(commandBuffer);
565void VulkanRenderer::CreateInstance()
570 throw std::runtime_error(
"validation layers requested, but not available!");
573 VkApplicationInfo appInfo{};
574 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
575 appInfo.pApplicationName = mWindowSystem.GetApplication().GetScreenSettings().name.c_str();
576 appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
577 appInfo.pEngineName =
"Rendering Engine";
578 appInfo.engineVersion = VK_MAKE_VERSION(
579 RENDERING_ENGINE_VERSION_MAJOR,
580 RENDERING_ENGINE_VERSION_MINOR,
581 RENDERING_ENGINE_VERSION_PATCH
583 appInfo.apiVersion = VK_API_VERSION_1_0;
585 VkInstanceCreateInfo createInfo{};
586 createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
587 createInfo.pApplicationInfo = &appInfo;
589 auto extensionsNames = GetRequiredExtensions();
590 createInfo.enabledExtensionCount =
static_cast<uint32_t
>(extensionsNames.size());
591 createInfo.ppEnabledExtensionNames = extensionsNames.data();
593 VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
596 createInfo.enabledLayerCount =
static_cast<uint32_t
>(mValidationLayers.size());
597 createInfo.ppEnabledLayerNames = mValidationLayers.data();
599 PopulateDebugMessengerCreateInfo(debugCreateInfo);
600 createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugCreateInfo;
604 createInfo.enabledLayerCount = 0;
606 createInfo.pNext =
nullptr;
609 if (vkCreateInstance(&createInfo,
nullptr, &mInstance) != VK_SUCCESS)
611 throw std::runtime_error(
"failed to create instance!");
613 std::cout <<
"Vulkan instance created" << std::endl;
616bool VulkanRenderer::CheckValidationLayerSupport()
619 vkEnumerateInstanceLayerProperties(&layerCount,
nullptr);
621 std::vector<VkLayerProperties> availableLayers(layerCount);
622 vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
624 for (
const char* layerName : mValidationLayers)
626 bool layerFound =
false;
628 for (
const auto& layerProperties : availableLayers)
630 if (strcmp(layerName, layerProperties.layerName) == 0)
646std::vector<const char*> VulkanRenderer::GetRequiredExtensions()
648 uint32_t glfwExtensionCount = 0;
649 const char** glfwExtensions;
650 glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
652 std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
656 extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
662void VulkanRenderer::PopulateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo)
665 createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
666 createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
667 createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
668 createInfo.pfnUserCallback = DebugCallback;
671VKAPI_ATTR VkBool32 VKAPI_CALL VulkanRenderer::DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData)
673 std::cerr <<
"validation layer: " << pCallbackData->pMessage << std::endl;
677void VulkanRenderer::SetupDebugMessenger()
684 VkDebugUtilsMessengerCreateInfoEXT createInfo{};
685 PopulateDebugMessengerCreateInfo(createInfo);
687 if (CreateDebugUtilsMessengerEXT(mInstance, &createInfo,
nullptr, &mDebugMessenger) != VK_SUCCESS)
689 throw std::runtime_error(
"failed to set up debug messenger!");
693VkResult VulkanRenderer::CreateDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerCreateInfoEXT
const* pCreateInfo, VkAllocationCallbacks
const* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger)
695 auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance,
"vkCreateDebugUtilsMessengerEXT");
698 return func(instance, pCreateInfo, pAllocator, pDebugMessenger);
702 return VK_ERROR_EXTENSION_NOT_PRESENT;
706void VulkanRenderer::DestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT debugMessenger,
const VkAllocationCallbacks* pAllocator)
708 auto func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance,
"vkDestroyDebugUtilsMessengerEXT");
711 func(instance, debugMessenger, pAllocator);
715void VulkanRenderer::CreateSurface()
717 GLFWwindow* window =
static_cast<GLFWwindow*
>(mWindowSystem.GetNativeHandle());
718 if (glfwCreateWindowSurface(mInstance, window,
nullptr, &mSurface) != VK_SUCCESS)
720 throw std::runtime_error(
"failed to create window surface!");
724void VulkanRenderer::PickPhysicalDevice()
726 uint32_t deviceCount = 0;
727 vkEnumeratePhysicalDevices(mInstance, &deviceCount,
nullptr);
729 if (deviceCount == 0)
731 throw std::runtime_error(
"failed to find GPUs with Vulkan support!");
734 std::vector<VkPhysicalDevice> devices(deviceCount);
735 vkEnumeratePhysicalDevices(mInstance, &deviceCount, devices.data());
737 for (
const auto& device : devices)
739 if (IsDeviceSuitable(device)) {
740 mPhysicalDevice = device;
741 vkGetPhysicalDeviceFeatures(mPhysicalDevice, &mPhysDevSupportedFeatures);
742 vkGetPhysicalDeviceProperties(mPhysicalDevice, &mPhysicalDeviceProperties);
743 mMSAASamples = CheckMaxUsableSampleCount();
748 if (mPhysicalDevice == VK_NULL_HANDLE)
750 throw std::runtime_error(
"failed to find a suitable GPU!");
754bool VulkanRenderer::IsDeviceSuitable(VkPhysicalDevice device)
767 QueueFamilyIndices indices = FindQueueFamilies(device);
769 bool extensionsSupported = CheckDeviceExtensionSupport(device);
771 bool swapChainAdequate =
false;
772 if (extensionsSupported)
774 auto const swapChainSupport = QuerySwapChainSupport(device);
775 swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty();
777 return indices.IsComplete() && extensionsSupported && swapChainAdequate;
782 QueueFamilyIndices indices;
784 uint32_t queueFamilyCount = 0;
785 vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount,
nullptr);
787 std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount);
788 vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data());
791 for (
const auto& queueFamily : queueFamilies)
793 if (queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT)
795 indices.graphicsFamily = i;
798 VkBool32 presentSupport =
false;
799 vkGetPhysicalDeviceSurfaceSupportKHR(device, i, mSurface, &presentSupport);
802 indices.presentFamily = i;
804 if (indices.IsComplete())
814bool VulkanRenderer::CheckDeviceExtensionSupport(VkPhysicalDevice physicalDevice)
816 uint32_t extensionCount;
817 vkEnumerateDeviceExtensionProperties(physicalDevice,
nullptr, &extensionCount,
nullptr);
819 std::vector<VkExtensionProperties> availableExtensions(extensionCount);
820 vkEnumerateDeviceExtensionProperties(physicalDevice,
nullptr, &extensionCount, availableExtensions.data());
822 std::set<std::string> requiredExtensions(mDeviceExtensions.begin(), mDeviceExtensions.end());
824 for (
const auto& extension : availableExtensions)
826 requiredExtensions.erase(extension.extensionName);
829 return requiredExtensions.empty();
834 SwapChainSupportDetails scsDetails;
836 vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, mSurface, &scsDetails.capabilities);
838 uint32_t formatCount;
839 vkGetPhysicalDeviceSurfaceFormatsKHR(device, mSurface, &formatCount,
nullptr);
841 if (formatCount != 0)
843 scsDetails.formats.resize(formatCount);
844 vkGetPhysicalDeviceSurfaceFormatsKHR(device, mSurface, &formatCount, scsDetails.formats.data());
847 uint32_t presentModeCount;
848 vkGetPhysicalDeviceSurfacePresentModesKHR(device, mSurface, &presentModeCount,
nullptr);
850 if (presentModeCount != 0)
852 scsDetails.presentModes.resize(presentModeCount);
853 vkGetPhysicalDeviceSurfacePresentModesKHR(device, mSurface, &presentModeCount, scsDetails.presentModes.data());
859VkSampleCountFlagBits VulkanRenderer::CheckMaxUsableSampleCount()
861 VkPhysicalDeviceProperties physicalDeviceProperties;
862 vkGetPhysicalDeviceProperties(mPhysicalDevice, &physicalDeviceProperties);
864 VkSampleCountFlags counts = physicalDeviceProperties.limits.framebufferColorSampleCounts & physicalDeviceProperties.limits.framebufferDepthSampleCounts;
865 if (counts & VK_SAMPLE_COUNT_64_BIT) {
return VK_SAMPLE_COUNT_64_BIT; }
866 if (counts & VK_SAMPLE_COUNT_32_BIT) {
return VK_SAMPLE_COUNT_32_BIT; }
867 if (counts & VK_SAMPLE_COUNT_16_BIT) {
return VK_SAMPLE_COUNT_16_BIT; }
868 if (counts & VK_SAMPLE_COUNT_8_BIT) {
return VK_SAMPLE_COUNT_8_BIT; }
869 if (counts & VK_SAMPLE_COUNT_4_BIT) {
return VK_SAMPLE_COUNT_4_BIT; }
870 if (counts & VK_SAMPLE_COUNT_2_BIT) {
return VK_SAMPLE_COUNT_2_BIT; }
872 return VK_SAMPLE_COUNT_1_BIT;
875void VulkanRenderer::CreateLogicalDevice()
877 QueueFamilyIndices indices = FindQueueFamilies(mPhysicalDevice);
879 std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
880 std::set<uint32_t> uniqueQueueFamilies = { indices.graphicsFamily.value(), indices.presentFamily.value() };
882 float queuePriority = 1.0f;
883 for (uint32_t queueFamily : uniqueQueueFamilies)
885 VkDeviceQueueCreateInfo queueCreateInfo{};
886 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
887 queueCreateInfo.queueFamilyIndex = queueFamily;
888 queueCreateInfo.queueCount = 1;
889 queueCreateInfo.pQueuePriorities = &queuePriority;
890 queueCreateInfos.push_back(queueCreateInfo);
893 VkDeviceQueueCreateInfo queueCreateInfo{};
894 queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
895 queueCreateInfo.queueFamilyIndex = indices.graphicsFamily.value();
896 queueCreateInfo.queueCount = 1;
898 queueCreateInfo.pQueuePriorities = &queuePriority;
900 VkPhysicalDeviceFeatures deviceFeatures{};
901 if (mPhysDevSupportedFeatures.samplerAnisotropy)
903 deviceFeatures.samplerAnisotropy = VK_TRUE;
907 deviceFeatures.samplerAnisotropy = VK_FALSE;
910 if (mPhysDevSupportedFeatures.sampleRateShading)
912 deviceFeatures.sampleRateShading = VK_TRUE;
916 deviceFeatures.sampleRateShading = VK_FALSE;
919 VkDeviceCreateInfo createInfo{};
920 createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
922 createInfo.pQueueCreateInfos = queueCreateInfos.data();
923 createInfo.queueCreateInfoCount =
static_cast<uint32_t
>(queueCreateInfos.size());
925 createInfo.pEnabledFeatures = &deviceFeatures;
927 createInfo.enabledExtensionCount =
static_cast<uint32_t
>(mDeviceExtensions.size());
928 createInfo.ppEnabledExtensionNames = mDeviceExtensions.data();
932 createInfo.enabledLayerCount =
static_cast<uint32_t
>(mValidationLayers.size());
933 createInfo.ppEnabledLayerNames = mValidationLayers.data();
937 createInfo.enabledLayerCount = 0;
940 if (vkCreateDevice(mPhysicalDevice, &createInfo,
nullptr, &mLogicalDevice) != VK_SUCCESS)
942 throw std::runtime_error(
"failed to create logical device!");
945 vkGetDeviceQueue(mLogicalDevice, indices.graphicsFamily.value(), 0, &mGraphicsQueue);
946 vkGetDeviceQueue(mLogicalDevice, indices.presentFamily.value(), 0, &mPresentQueue);
949void VulkanRenderer::CreateSwapChain()
951 SwapChainSupportDetails swapChainSupport = QuerySwapChainSupport(mPhysicalDevice);
953 VkSurfaceFormatKHR surfaceFormat = ChooseSwapSurfaceFormat(swapChainSupport.formats);
954 VkPresentModeKHR presentMode = ChooseSwapPresentMode(swapChainSupport.presentModes);
955 VkExtent2D extent = ChooseSwapExtent(swapChainSupport.capabilities);
957 uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
958 if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount)
960 imageCount = swapChainSupport.capabilities.maxImageCount;
963 VkSwapchainCreateInfoKHR createInfo{};
964 createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
965 createInfo.surface = mSurface;
967 createInfo.minImageCount = imageCount;
968 createInfo.imageFormat = surfaceFormat.format;
969 createInfo.imageColorSpace = surfaceFormat.colorSpace;
970 createInfo.imageExtent = extent;
971 createInfo.imageArrayLayers = 1;
972 createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
974 QueueFamilyIndices indices = FindQueueFamilies(mPhysicalDevice);
975 uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value(), indices.presentFamily.value() };
977 if (indices.graphicsFamily != indices.presentFamily) {
978 createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
979 createInfo.queueFamilyIndexCount = 2;
980 createInfo.pQueueFamilyIndices = queueFamilyIndices;
984 createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
985 createInfo.queueFamilyIndexCount = 0;
986 createInfo.pQueueFamilyIndices =
nullptr;
989 createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
990 createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
991 createInfo.presentMode = presentMode;
992 createInfo.clipped = VK_TRUE;
993 createInfo.oldSwapchain = VK_NULL_HANDLE;
995 if (vkCreateSwapchainKHR(mLogicalDevice, &createInfo,
nullptr, &mSwapChain) != VK_SUCCESS)
997 throw std::runtime_error(
"failed to create swap chain!");
1000 vkGetSwapchainImagesKHR(mLogicalDevice, mSwapChain, &imageCount,
nullptr);
1001 mSwapChainImages.resize(imageCount);
1002 vkGetSwapchainImagesKHR(mLogicalDevice, mSwapChain, &imageCount, mSwapChainImages.data());
1004 mSwapChainImageFormat = surfaceFormat.format;
1005 mSwapChainExtent = extent;
1008void VulkanRenderer::RecreateSwapChain()
1013 while (width == 0 || height == 0)
1015 GLFWwindow* window =
static_cast<GLFWwindow*
>(mWindowSystem.GetNativeHandle());
1016 glfwGetFramebufferSize(window, &width, &height);
1019 vkDeviceWaitIdle(mLogicalDevice);
1023 for (
auto& observer : mObservers)
1025 observer->OnRenderResourcesRelease();
1032 CreateColorResources();
1033 CreateDepthResources();
1034 CreateFramebuffers();
1035 CreateCommandBuffers();
1037 for (
auto& observer : mObservers)
1039 observer->OnRenderResourcesRebuild();
1043VkSurfaceFormatKHR VulkanRenderer::ChooseSwapSurfaceFormat(std::vector<VkSurfaceFormatKHR>
const& availableFormats)
1045 for (
const auto& availableFormat : availableFormats)
1047 if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
1049 return availableFormat;
1053 return availableFormats[0];
1056VkPresentModeKHR VulkanRenderer::ChooseSwapPresentMode(std::vector<VkPresentModeKHR>
const& availablePresentModes)
1058 for (
const auto& availablePresentMode : availablePresentModes)
1060 if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR)
1062 return availablePresentMode;
1065 return VK_PRESENT_MODE_FIFO_KHR;
1068VkExtent2D VulkanRenderer::ChooseSwapExtent(VkSurfaceCapabilitiesKHR
const& capabilities)
1070 if (capabilities.currentExtent.width != UINT32_MAX)
1072 return capabilities.currentExtent;
1077 GLFWwindow* window =
static_cast<GLFWwindow*
>(mWindowSystem.GetNativeHandle());
1078 glfwGetFramebufferSize(window, &width, &height);
1080 VkExtent2D actualExtent = {
1081 static_cast<uint32_t
>(width),
1082 static_cast<uint32_t
>(height)
1085 actualExtent.width = std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
1086 actualExtent.height = std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
1088 return actualExtent;
1092void VulkanRenderer::CreateImageViews()
1094 mSwapChainImageViews.resize(mSwapChainImages.size());
1096 for (uint32_t i = 0; i < mSwapChainImages.size(); i++)
1098 mSwapChainImageViews[i] = CreateImageView(mSwapChainImages[i], mSwapChainImageFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1);
1102VkImageView VulkanRenderer::CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, std::uint32_t mipmapLevels)
1104 VkImageViewCreateInfo viewInfo{};
1105 viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
1106 viewInfo.image = image;
1107 viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
1108 viewInfo.format = format;
1109 viewInfo.subresourceRange.aspectMask = aspectFlags;
1110 viewInfo.subresourceRange.baseMipLevel = 0;
1111 viewInfo.subresourceRange.levelCount = mipmapLevels;
1112 viewInfo.subresourceRange.baseArrayLayer = 0;
1113 viewInfo.subresourceRange.layerCount = 1;
1115 VkImageView imageView;
1116 if (vkCreateImageView(mLogicalDevice, &viewInfo,
nullptr, &imageView) != VK_SUCCESS)
1118 throw std::runtime_error(
"failed to create texture image view!");
1124void VulkanRenderer::CreateRenderPass()
1126 VkAttachmentDescription colorAttachment{};
1127 colorAttachment.format = mSwapChainImageFormat;
1128 colorAttachment.samples = mMSAASamples;
1129 colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1130 colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
1131 colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1132 colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1133 colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1134 colorAttachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1136 VkAttachmentReference colorAttachmentRef{};
1137 colorAttachmentRef.attachment = 0;
1138 colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1140 VkAttachmentDescription depthAttachment{};
1141 depthAttachment.format = FindDepthFormat();
1142 depthAttachment.samples = mMSAASamples;
1143 depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1144 depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1145 depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1146 depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1147 depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1148 depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1150 VkAttachmentReference depthAttachmentRef{};
1151 depthAttachmentRef.attachment = 1;
1152 depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
1154 VkAttachmentDescription colorAttachmentResolve{};
1155 colorAttachmentResolve.format = mSwapChainImageFormat;
1156 colorAttachmentResolve.samples = VK_SAMPLE_COUNT_1_BIT;
1157 colorAttachmentResolve.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1158 colorAttachmentResolve.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
1159 colorAttachmentResolve.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1160 colorAttachmentResolve.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
1161 colorAttachmentResolve.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1162 colorAttachmentResolve.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1164 VkAttachmentReference colorAttachmentResolveRef{};
1165 colorAttachmentResolveRef.attachment = 2;
1166 colorAttachmentResolveRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1168 VkSubpassDescription subpass{};
1169 subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1170 subpass.colorAttachmentCount = 1;
1171 subpass.pColorAttachments = &colorAttachmentRef;
1172 subpass.pDepthStencilAttachment = &depthAttachmentRef;
1173 subpass.pResolveAttachments = &colorAttachmentResolveRef;
1175 VkSubpassDependency dependency{};
1176 dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
1177 dependency.dstSubpass = 0;
1178 dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
1179 dependency.srcAccessMask = 0;
1180 dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
1181 dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
1183 std::array<VkAttachmentDescription, 3> attachments = { colorAttachment, depthAttachment, colorAttachmentResolve };
1185 VkRenderPassCreateInfo renderPassInfo{};
1186 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
1187 renderPassInfo.attachmentCount =
static_cast<uint32_t
>(attachments.size());
1188 renderPassInfo.pAttachments = attachments.data();
1189 renderPassInfo.subpassCount = 1;
1190 renderPassInfo.pSubpasses = &subpass;
1191 renderPassInfo.dependencyCount = 1;
1192 renderPassInfo.pDependencies = &dependency;
1194 if (vkCreateRenderPass(mLogicalDevice, &renderPassInfo,
nullptr, &mRenderPass) != VK_SUCCESS)
1196 throw std::runtime_error(
"failed to create render pass!");
1200VkFormat VulkanRenderer::FindDepthFormat()
1202 return FindSupportedFormat(
1203 { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT, VK_FORMAT_D24_UNORM_S8_UINT },
1204 VK_IMAGE_TILING_OPTIMAL,
1205 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
1209VkFormat VulkanRenderer::FindSupportedFormat(
const std::vector<VkFormat>& candidates, VkImageTiling tiling, VkFormatFeatureFlags features)
1211 for (VkFormat format : candidates)
1213 VkFormatProperties props;
1214 vkGetPhysicalDeviceFormatProperties(mPhysicalDevice, format, &props);
1216 if (tiling == VK_IMAGE_TILING_LINEAR && (props.linearTilingFeatures & features) == features)
1220 else if (tiling == VK_IMAGE_TILING_OPTIMAL && (props.optimalTilingFeatures & features) == features)
1226 throw std::runtime_error(
"failed to find supported format!");
1229void VulkanRenderer::CreateCommandPool()
1231 QueueFamilyIndices queueFamilyIndices = FindQueueFamilies(mPhysicalDevice);
1233 VkCommandPoolCreateInfo poolInfo{};
1234 poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
1235 poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();
1236 poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
1238 if (vkCreateCommandPool(mLogicalDevice, &poolInfo,
nullptr, &mCommandPool) != VK_SUCCESS)
1240 throw std::runtime_error(
"failed to create command pool!");
1244void VulkanRenderer::CreateColorResources()
1246 VkFormat colorFormat = mSwapChainImageFormat;
1248 CreateVulkanImage(mSwapChainExtent.width, mSwapChainExtent.height, 1, mMSAASamples, colorFormat, VK_IMAGE_TILING_OPTIMAL,
1249 VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
1250 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, mColorImage, mColorImageMemory);
1251 mColorImageView = CreateImageView(mColorImage, colorFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1);
1254void VulkanRenderer::CreateVulkanImage(uint32_t width, uint32_t height, std::uint32_t mipmapLevels, VkSampleCountFlagBits numSamples, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory)
1256 VkImageCreateInfo imageInfo{};
1257 imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
1258 imageInfo.imageType = VK_IMAGE_TYPE_2D;
1259 imageInfo.extent.width =
static_cast<uint32_t
>(width);
1260 imageInfo.extent.height =
static_cast<uint32_t
>(height);
1261 imageInfo.extent.depth = 1;
1262 imageInfo.mipLevels = mipmapLevels;
1263 imageInfo.arrayLayers = 1;
1265 imageInfo.format = format;
1266 imageInfo.tiling = tiling;
1268 imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1270 imageInfo.usage = usage;
1272 imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1274 imageInfo.samples = numSamples;
1275 imageInfo.flags = 0;
1277 if (vkCreateImage(mLogicalDevice, &imageInfo,
nullptr, &image) != VK_SUCCESS)
1279 throw std::runtime_error(
"failed to create image!");
1282 VkMemoryRequirements memRequirements;
1283 vkGetImageMemoryRequirements(mLogicalDevice, image, &memRequirements);
1285 VkMemoryAllocateInfo allocInfo{};
1286 allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
1287 allocInfo.allocationSize = memRequirements.size;
1288 allocInfo.memoryTypeIndex =
FindMemoryType(memRequirements.memoryTypeBits, properties);
1290 if (vkAllocateMemory(mLogicalDevice, &allocInfo,
nullptr, &imageMemory) != VK_SUCCESS) {
1291 throw std::runtime_error(
"failed to allocate image memory!");
1294 vkBindImageMemory(mLogicalDevice, image, imageMemory, 0);
1299 VkPhysicalDeviceMemoryProperties memProperties;
1300 vkGetPhysicalDeviceMemoryProperties(mPhysicalDevice, &memProperties);
1302 for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
1304 if (typeFilter & (1 << i) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)
1310 throw std::runtime_error(
"failed to find suitable memory type!");
1315 return mPhysicalDevice;
1320 return mPhysDevSupportedFeatures;
1325 std::uint32_t bindingNumber = 0;
1326 std::vector<VkDescriptorSetLayoutBinding> bindings;
1329 VkDescriptorSetLayoutBinding uboLayoutBinding{};
1330 uboLayoutBinding.binding = bindingNumber;
1331 uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1332 uboLayoutBinding.descriptorCount = 1;
1333 uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
1334 uboLayoutBinding.pImmutableSamplers =
nullptr;
1336 bindings.push_back(uboLayoutBinding);
1339 if (!packedMaterialData.
buffer.empty())
1343 VkDescriptorSetLayoutBinding customMaterialVariables;
1344 customMaterialVariables.binding = bindingNumber;
1345 customMaterialVariables.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
1346 customMaterialVariables.descriptorCount = 1;
1347 customMaterialVariables.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
1348 customMaterialVariables.pImmutableSamplers =
nullptr;
1350 bindings.push_back(customMaterialVariables);
1353 for (
const auto& textureName : material->
GetTextures())
1357 VkDescriptorSetLayoutBinding samplerLayoutBinding{};
1358 samplerLayoutBinding.binding = bindingNumber;
1359 samplerLayoutBinding.descriptorCount = 1;
1360 samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
1361 samplerLayoutBinding.pImmutableSamplers =
nullptr;
1362 samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
1364 bindings.push_back(samplerLayoutBinding);
1367 VkDescriptorSetLayoutCreateInfo layoutInfo{};
1368 layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
1369 layoutInfo.bindingCount =
static_cast<uint32_t
>(bindings.size());
1370 layoutInfo.pBindings = bindings.data();
1372 VkDescriptorSetLayout result;
1373 if (vkCreateDescriptorSetLayout(mLogicalDevice, &layoutInfo,
nullptr, &result) != VK_SUCCESS)
1375 throw std::runtime_error(
"failed to create descriptor set layout!");
1383 return mCommandBuffers;
1388 VkPipelineLayout pipelineLayout;
1389 VkPipeline pipeline;
1391 VkShaderModule vertShaderModule = CreateShaderModule(spvVertShaderCode);
1392 VkShaderModule fragShaderModule = CreateShaderModule(spvFragShaderCode);
1394 VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
1395 vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1396 vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
1398 vertShaderStageInfo.module = vertShaderModule;
1399 vertShaderStageInfo.pName =
"main";
1401 VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
1402 fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
1403 fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
1404 fragShaderStageInfo.module = fragShaderModule;
1405 fragShaderStageInfo.pName =
"main";
1407 VkPipelineShaderStageCreateInfo shaderStages[] = { vertShaderStageInfo, fragShaderStageInfo };
1409 VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
1410 vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
1412 VkVertexInputBindingDescription bindingDescription;
1413 std::vector<VkVertexInputAttributeDescription> attributeDescriptions{};
1426 vertexInputInfo.vertexBindingDescriptionCount = 1;
1427 vertexInputInfo.vertexAttributeDescriptionCount =
static_cast<uint32_t
>(attributeDescriptions.size());
1429 vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
1430 vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
1432 VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
1433 inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
1434 inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
1435 inputAssembly.primitiveRestartEnable = VK_FALSE;
1437 VkViewport viewport{};
1440 viewport.width = (float)mSwapChainExtent.width;
1441 viewport.height = (float)mSwapChainExtent.height;
1442 viewport.minDepth = 0.0f;
1443 viewport.maxDepth = 1.0f;
1446 scissor.offset = { 0, 0 };
1447 scissor.extent = mSwapChainExtent;
1449 VkPipelineViewportStateCreateInfo viewportState{};
1450 viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
1451 viewportState.viewportCount = 1;
1452 viewportState.pViewports = &viewport;
1453 viewportState.scissorCount = 1;
1454 viewportState.pScissors = &scissor;
1456 VkPipelineRasterizationStateCreateInfo rasterizer{};
1457 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
1458 rasterizer.depthClampEnable = VK_FALSE;
1459 rasterizer.rasterizerDiscardEnable = VK_FALSE;
1460 rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
1461 rasterizer.lineWidth = 1.0f;
1464 rasterizer.cullMode = VK_CULL_MODE_NONE;
1468 rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
1470 rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
1471 rasterizer.depthBiasEnable = VK_FALSE;
1472 rasterizer.depthBiasConstantFactor = 0.0f;
1473 rasterizer.depthBiasClamp = 0.0f;
1474 rasterizer.depthBiasSlopeFactor = 0.0f;
1476 VkPipelineMultisampleStateCreateInfo multisampling{};
1477 multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
1478 multisampling.sampleShadingEnable = VK_FALSE;
1479 multisampling.rasterizationSamples = mMSAASamples;
1480 multisampling.minSampleShading = 1.0f;
1481 multisampling.pSampleMask =
nullptr;
1482 multisampling.alphaToCoverageEnable = VK_FALSE;
1483 multisampling.alphaToOneEnable = VK_FALSE;
1485 VkPipelineColorBlendAttachmentState colorBlendAttachment{};
1486 colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
1488 colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
1489 colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
1490 colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
1491 colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
1492 colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
1493 colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
1495 VkPipelineColorBlendStateCreateInfo colorBlending{};
1496 colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
1497 colorBlending.logicOpEnable = VK_FALSE;
1498 colorBlending.logicOp = VK_LOGIC_OP_COPY;
1499 colorBlending.attachmentCount = 1;
1500 colorBlending.pAttachments = &colorBlendAttachment;
1501 colorBlending.blendConstants[0] = 0.0f;
1502 colorBlending.blendConstants[1] = 0.0f;
1503 colorBlending.blendConstants[2] = 0.0f;
1504 colorBlending.blendConstants[3] = 0.0f;
1507 std::vector<VkDynamicState> dynamicStates = {
1508 VK_DYNAMIC_STATE_VIEWPORT,
1509 VK_DYNAMIC_STATE_SCISSOR
1511 VkPipelineDynamicStateCreateInfo dynamicState{};
1512 dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
1513 dynamicState.dynamicStateCount =
static_cast<uint32_t
>(dynamicStates.size());
1514 dynamicState.pDynamicStates = dynamicStates.data();
1516 VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
1517 pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
1518 pipelineLayoutInfo.setLayoutCount = 1;
1519 pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
1521 if (vkCreatePipelineLayout(mLogicalDevice, &pipelineLayoutInfo,
nullptr, &pipelineLayout) != VK_SUCCESS)
1523 throw std::runtime_error(
"failed to create pipeline layout!");
1526 VkPipelineDepthStencilStateCreateInfo depthStencil{};
1527 depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
1530 depthStencil.depthTestEnable = VK_FALSE;
1531 depthStencil.depthWriteEnable = VK_FALSE;
1535 depthStencil.depthTestEnable = VK_TRUE;
1538 depthStencil.depthCompareOp = VK_COMPARE_OP_LESS;
1539 depthStencil.depthBoundsTestEnable = VK_FALSE;
1542 depthStencil.stencilTestEnable = VK_FALSE;
1544 depthStencil.back = {};
1546 VkGraphicsPipelineCreateInfo pipelineInfo{};
1547 pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
1548 pipelineInfo.stageCount = 2;
1549 pipelineInfo.pStages = shaderStages;
1550 pipelineInfo.pVertexInputState = &vertexInputInfo;
1551 pipelineInfo.pInputAssemblyState = &inputAssembly;
1552 pipelineInfo.pViewportState = &viewportState;
1553 pipelineInfo.pRasterizationState = &rasterizer;
1554 pipelineInfo.pMultisampleState = &multisampling;
1555 pipelineInfo.pDepthStencilState = &depthStencil;
1556 pipelineInfo.pColorBlendState = &colorBlending;
1557 pipelineInfo.pDynamicState =
nullptr;
1558 pipelineInfo.layout = pipelineLayout;
1559 pipelineInfo.renderPass = mRenderPass;
1560 pipelineInfo.subpass = 0;
1561 pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
1562 pipelineInfo.basePipelineIndex = -1;
1565 if (vkCreateGraphicsPipelines(mLogicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo,
nullptr, &pipeline) != VK_SUCCESS)
1567 throw std::runtime_error(
"failed to create graphics pipeline!");
1569 vkDestroyShaderModule(mLogicalDevice, fragShaderModule,
nullptr);
1570 vkDestroyShaderModule(mLogicalDevice, vertShaderModule,
nullptr);
1572 return std::pair<VkPipelineLayout, VkPipeline>(pipelineLayout, pipeline);
1575void VulkanRenderer::CreateDepthResources()
1577 VkFormat depthFormat = FindDepthFormat();
1579 CreateVulkanImage(mSwapChainExtent.width, mSwapChainExtent.height, 1, mMSAASamples, depthFormat,
1580 VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
1581 mDepthImage, mDepthImageMemory);
1582 mDepthImageView = CreateImageView(mDepthImage, depthFormat, VK_IMAGE_ASPECT_DEPTH_BIT, 1);
1585void VulkanRenderer::CreateFramebuffers()
1587 mSwapChainFramebuffers.resize(mSwapChainImageViews.size());
1589 for (
size_t i = 0; i < mSwapChainImageViews.size(); i++)
1591 std::array<VkImageView, 3> attachments = { mColorImageView, mDepthImageView, mSwapChainImageViews[i] };
1593 VkFramebufferCreateInfo framebufferInfo{};
1594 framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
1595 framebufferInfo.renderPass = mRenderPass;
1596 framebufferInfo.attachmentCount =
static_cast<uint32_t
>(attachments.size());
1597 framebufferInfo.pAttachments = attachments.data();
1598 framebufferInfo.width = mSwapChainExtent.width;
1599 framebufferInfo.height = mSwapChainExtent.height;
1600 framebufferInfo.layers = 1;
1602 if (vkCreateFramebuffer(mLogicalDevice, &framebufferInfo,
nullptr, &mSwapChainFramebuffers[i]) != VK_SUCCESS)
1604 throw std::runtime_error(
"failed to create framebuffer!");
1609void VulkanRenderer::CreateCommandBuffers()
1613 VkCommandBufferAllocateInfo allocInfo{};
1614 allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
1615 allocInfo.commandPool = mCommandPool;
1616 allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1617 allocInfo.commandBufferCount = (uint32_t)mCommandBuffers.size();
1619 if (vkAllocateCommandBuffers(mLogicalDevice, &allocInfo, mCommandBuffers.data()) != VK_SUCCESS)
1621 throw std::runtime_error(
"failed to allocate command buffers!");
1625void VulkanRenderer::CreateSyncObjects()
1630 mImagesInFlight.resize(mSwapChainImages.size(), VK_NULL_HANDLE);
1632 VkSemaphoreCreateInfo semaphoreInfo{};
1633 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
1635 VkFenceCreateInfo fenceInfo{};
1636 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
1637 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
1641 if (vkCreateSemaphore(mLogicalDevice, &semaphoreInfo,
nullptr, &mImageAvailableSemaphores[i]) != VK_SUCCESS ||
1642 vkCreateSemaphore(mLogicalDevice, &semaphoreInfo,
nullptr, &mRenderFinishedSemaphores[i]) != VK_SUCCESS ||
1643 vkCreateFence(mLogicalDevice, &fenceInfo,
nullptr, &mInFlightFences[i]) != VK_SUCCESS)
1645 throw std::runtime_error(
"failed to create synchronization objects for a frame!");
1650VkShaderModule VulkanRenderer::CreateShaderModule(std::vector<char>& code)
1652 VkShaderModuleCreateInfo createInfo{};
1653 createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
1654 createInfo.codeSize = code.size();
1655 createInfo.pCode =
reinterpret_cast<const uint32_t*
>(code.data());
1657 VkShaderModule shaderModule;
1658 if (vkCreateShaderModule(mLogicalDevice, &createInfo,
nullptr, &shaderModule) != VK_SUCCESS)
1660 throw std::runtime_error(
"failed to create shader module!");
1663 return shaderModule;
1666void VulkanRenderer::CleanupSwapChain()
1668 vkDestroyImageView(mLogicalDevice, mColorImageView,
nullptr);
1669 vkDestroyImage(mLogicalDevice, mColorImage,
nullptr);
1670 vkFreeMemory(mLogicalDevice, mColorImageMemory,
nullptr);
1672 vkDestroyImageView(mLogicalDevice, mDepthImageView,
nullptr);
1673 vkDestroyImage(mLogicalDevice, mDepthImage,
nullptr);
1674 vkFreeMemory(mLogicalDevice, mDepthImageMemory,
nullptr);
1675 for (
auto framebuffer : mSwapChainFramebuffers)
1677 vkDestroyFramebuffer(mLogicalDevice, framebuffer,
nullptr);
1680 vkFreeCommandBuffers(mLogicalDevice, mCommandPool,
static_cast<uint32_t
>(mCommandBuffers.size()), mCommandBuffers.data());
1682 vkDestroyRenderPass(mLogicalDevice, mRenderPass,
nullptr);
1683 for (
auto imageView : mSwapChainImageViews)
1685 vkDestroyImageView(mLogicalDevice, imageView,
nullptr);
1687 vkDestroySwapchainKHR(mLogicalDevice, mSwapChain,
nullptr);
1690void VulkanRenderer::RecordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex)
1692 VkCommandBufferBeginInfo beginInfo{};
1693 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1697 if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS)
1699 throw std::runtime_error(
"failed to begin recording command buffer!");
1702 VkRenderPassBeginInfo renderPassInfo{};
1703 renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1704 renderPassInfo.renderPass = mRenderPass;
1705 renderPassInfo.framebuffer = mSwapChainFramebuffers[imageIndex];
1707 renderPassInfo.renderArea.offset = { 0, 0 };
1708 renderPassInfo.renderArea.extent = mSwapChainExtent;
1710 std::array<VkClearValue, 2> clearValues{};
1711 clearValues[0].color = { {0.0f, 0.0f, 0.0f, 1.0f} };
1712 clearValues[1].depthStencil = { 1.0f, 0 };
1713 renderPassInfo.clearValueCount =
static_cast<uint32_t
>(clearValues.size());
1714 renderPassInfo.pClearValues = clearValues.data();
1716 vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
1718 vkCmdEndRenderPass(commandBuffer);
1720 if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS)
1722 throw std::runtime_error(
"failed to record command buffer!");
1726VkCommandBuffer VulkanRenderer::BeginSingleTimeCommand()
1728 VkCommandBufferAllocateInfo allocInfo{};
1729 allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
1730 allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
1731 allocInfo.commandPool = mCommandPool;
1732 allocInfo.commandBufferCount = 1;
1734 VkCommandBuffer commandBuffer;
1735 vkAllocateCommandBuffers(mLogicalDevice, &allocInfo, &commandBuffer);
1737 VkCommandBufferBeginInfo beginInfo{};
1738 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1739 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1741 vkBeginCommandBuffer(commandBuffer, &beginInfo);
1743 return commandBuffer;
1746bool VulkanRenderer::HasStencilComponent(VkFormat format)
1748 return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT;
1751void VulkanRenderer::EndSingleTimeCommand(VkCommandBuffer commandBuffer)
1753 vkEndCommandBuffer(commandBuffer);
1755 VkSubmitInfo submitInfo{};
1756 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1757 submitInfo.commandBufferCount = 1;
1758 submitInfo.pCommandBuffers = &commandBuffer;
1760 vkQueueSubmit(mGraphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
1761 vkQueueWaitIdle(mGraphicsQueue);
1763 vkFreeCommandBuffers(mLogicalDevice, mCommandPool, 1, &commandBuffer);
1769 VkVertexInputBindingDescription binding{};
1770 binding.binding = 0;
1771 binding.stride =
sizeof(T);
1772 binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
1779 std::vector<VkVertexInputAttributeDescription> attributeDescriptions{};
1780 attributeDescriptions.resize(3);
1782 attributeDescriptions[0].binding = 0;
1783 attributeDescriptions[0].location = 0;
1784 attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
1785 attributeDescriptions[0].offset = offsetof(Vertex2D, position);
1787 attributeDescriptions[1].binding = 0;
1788 attributeDescriptions[1].location = 1;
1789 attributeDescriptions[1].format = VK_FORMAT_R32G32B32A32_SFLOAT;
1790 attributeDescriptions[1].offset = offsetof(Vertex2D, color);
1792 attributeDescriptions[2].binding = 0;
1793 attributeDescriptions[2].location = 2;
1794 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
1795 attributeDescriptions[2].offset = offsetof(Vertex2D, textureCoordinates);
1797 return attributeDescriptions;
1803 std::vector<VkVertexInputAttributeDescription> attributeDescriptions{};
1804 attributeDescriptions.resize(3);
1806 attributeDescriptions[0].binding = 0;
1807 attributeDescriptions[0].location = 0;
1808 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
1809 attributeDescriptions[0].offset = offsetof(VertexPositionColorTexture, position);
1811 attributeDescriptions[1].binding = 0;
1812 attributeDescriptions[1].location = 1;
1813 attributeDescriptions[1].format = VK_FORMAT_R32G32B32A32_SFLOAT;
1814 attributeDescriptions[1].offset = offsetof(VertexPositionColorTexture, color);
1816 attributeDescriptions[2].binding = 0;
1817 attributeDescriptions[2].location = 2;
1818 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
1819 attributeDescriptions[2].offset = offsetof(VertexPositionColorTexture, textureCoordinates);
1821 return attributeDescriptions;
1827 std::vector<VkVertexInputAttributeDescription> attributeDescriptions{};
1828 attributeDescriptions.resize(5);
1830 attributeDescriptions[0].binding = 0;
1831 attributeDescriptions[0].location = 0;
1832 attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
1833 attributeDescriptions[0].offset = offsetof(VertexPositionColorTextureNormalTangent, position);
1835 attributeDescriptions[1].binding = 0;
1836 attributeDescriptions[1].location = 1;
1837 attributeDescriptions[1].format = VK_FORMAT_R32G32B32A32_SFLOAT;
1838 attributeDescriptions[1].offset = offsetof(VertexPositionColorTextureNormalTangent, color);
1840 attributeDescriptions[2].binding = 0;
1841 attributeDescriptions[2].location = 2;
1842 attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
1843 attributeDescriptions[2].offset = offsetof(VertexPositionColorTextureNormalTangent, textureCoordinates);
1845 attributeDescriptions[3].binding = 0;
1846 attributeDescriptions[3].location = 3;
1847 attributeDescriptions[3].format = VK_FORMAT_R32G32B32_SFLOAT;
1848 attributeDescriptions[3].offset = offsetof(VertexPositionColorTextureNormalTangent, normal);
1850 attributeDescriptions[4].binding = 0;
1851 attributeDescriptions[4].location = 4;
1852 attributeDescriptions[4].format = VK_FORMAT_R32G32B32_SFLOAT;
1853 attributeDescriptions[4].offset = offsetof(VertexPositionColorTextureNormalTangent, tangent);
1855 return attributeDescriptions;
Interface for backend-specific material GPU resources.
Interface for GPU mesh resource management.
Interface for rendering backend resource aggregation and submission.
Interface for observing renderer resource lifecycle events.
Interface for backend-specific GPU texture resource management.
Abstract interface for platform-specific window management.
Represents a material instance with parameter values, texture bindings, and rendering configuration.
std::vector< std::string > GetTextures() const
Returns the list of texture names used by this material.
PackedMaterialData PackMaterialParameters()
Packs the current float/vector parameters into a binary buffer and layout metadata.
const MaterialSettings GetMaterialSettings() const
Returns the material's static settings (domain, blend mode, shading model, etc.).
Vulkan-specific implementation of material render resources.
Vulkan implementation of the mesh GPU resource interface.
Vulkan implementation of IRenderResources for the Rendering Engine.
bool BeginFrame() override
Begins frame rendering operations.
VulkanRenderer(IWindowSystem &windowSystem)
Constructs a VulkanRenderer bound to a specific window system.
ITextureRenderResources * ProvideTextureRenderResources() const override
Provides access to texture-related GPU resources.
VkPhysicalDeviceFeatures & GetPhysDevSupportedFeatures()
Returns reference to the physical device�s supported features.
void GenerateMipmaps(VkImage image, VkFormat imageFormat, int32_t texWidth, int32_t texHeight, uint32_t mipLevels)
Generates mipmaps for a given image resource.
void CopyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height)
Copies buffer data into an image (used for uploading texture data).
static std::vector< VkVertexInputAttributeDescription > GetAttributeDescriptions()
Returns vertex attribute descriptions for a specific vertex type.
VkDevice & GetLogicalDevice()
Returns reference to the logical Vulkan device.
VkDescriptorSetLayout CreateDescriptorSetLayout(Material *material)
Creates a descriptor set layout corresponding to a given material.
IRenderResources * ProvideRenderResources() const override
Provides access to the general rendering resource manager.
void InitializeRenderer() override
Initializes all rendering subsystems and GPU resources.
void BeginRenderPass() override
Begins the active render pass for the current frame.
IMeshRenderResources * ProvideMeshRenderResources() const override
Provides access to mesh-related GPU resources.
void CopyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size)
Copies data from one buffer to another using a temporary command buffer.
void EndRenderPass() override
Ends the active render pass.
void EndFrame() override
Completes the current frame rendering and presents the result.
VkPhysicalDevice & GetPhysicalDevice()
Returns reference to the physical device.
void CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory)
Creates a new Vulkan buffer with the specified usage and memory properties.
void UnregisterObserver(IRendererObserver *notifier) override
Unregisters a previously registered observer.
void WaitIdle() override
Waits until the GPU has finished all pending rendering operations.
std::pair< VkPipelineLayout, VkPipeline > CreateGraphicsPipeline(Material *material, VkDescriptorSetLayout &descriptorSetLayout, std::vector< char > &spvVertShaderCode, std::vector< char > &spvFragShaderCode)
Creates a Vulkan graphics pipeline based on material and shader inputs.
void DrawFrame() override
Executes a full frame rendering cycle.
static VkVertexInputBindingDescription GetBindingDescription()
Returns a vertex input binding description for a specific vertex type.
uint32_t FindMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties)
Finds a suitable memory type for a given allocation.
void TransitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, std::uint32_t mipmapLevels)
Transitions the image layout for a given Vulkan image.
void RegisterObserver(IRendererObserver *notifier) override
Registers an observer for rendering events.
void ShutdownRenderer() override
Destroys and cleans up all rendering resources.
std::vector< VkCommandBuffer > GetComandBuffers()
Returns the collection of command buffers used for rendering.
IMaterialRenderResources * ProvideMaterialRenderResources() const override
Provides access to material-related GPU resources.
Vulkan-specific implementation of ITextureRenderResources.
const bool enableValidationLayers
const int MAX_FRAMES_IN_FLIGHT
Number of frames that can be processed simultaneously (double buffering).
MaterialDomain materialDomain
Contains the raw buffer data and layout metadata of packed material parameters.
std::vector< uint8_t > buffer
Holds indices of Vulkan queue families supporting required operations.
Describes capabilities and available configurations for a physical device's swap chain.