Last active
January 25, 2024 20:45
-
-
Save rossant/610961a9f9b7210cb208b616e69f4f37 to your computer and use it in GitHub Desktop.
Vulkan minimal example that generates a SYNC-HAZARD-WRITE-AFTER-READ validation error
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Requires gcc, the Vulkan SDK, and libglfw3-dev | |
// On Linux, compile with: | |
// gcc -Wall -o fail fail.c -Ibuild/_deps/glfw-src/include/ -lglfw -lvulkan | |
#include <assert.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#include <vulkan/vulkan.h> | |
#include <GLFW/glfw3.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
const uint32_t WIDTH = 800; | |
const uint32_t HEIGHT = 600; | |
#define STR(r) \ | |
case VK_##r: \ | |
str = #r; \ | |
break | |
#define noop | |
static inline int check_result(VkResult res) | |
{ | |
char* str = "UNKNOWN_ERROR"; | |
switch (res) | |
{ | |
STR(NOT_READY); | |
STR(TIMEOUT); | |
STR(EVENT_SET); | |
STR(EVENT_RESET); | |
STR(INCOMPLETE); | |
STR(ERROR_OUT_OF_HOST_MEMORY); | |
STR(ERROR_OUT_OF_DEVICE_MEMORY); | |
STR(ERROR_INITIALIZATION_FAILED); | |
STR(ERROR_DEVICE_LOST); | |
STR(ERROR_MEMORY_MAP_FAILED); | |
STR(ERROR_LAYER_NOT_PRESENT); | |
STR(ERROR_EXTENSION_NOT_PRESENT); | |
STR(ERROR_FEATURE_NOT_PRESENT); | |
STR(ERROR_INCOMPATIBLE_DRIVER); | |
STR(ERROR_TOO_MANY_OBJECTS); | |
STR(ERROR_FORMAT_NOT_SUPPORTED); | |
STR(ERROR_SURFACE_LOST_KHR); | |
STR(ERROR_NATIVE_WINDOW_IN_USE_KHR); | |
STR(SUBOPTIMAL_KHR); | |
STR(ERROR_OUT_OF_DATE_KHR); | |
STR(ERROR_INCOMPATIBLE_DISPLAY_KHR); | |
STR(ERROR_VALIDATION_FAILED_EXT); | |
STR(ERROR_INVALID_SHADER_NV); | |
default: | |
noop; | |
} | |
if (res != VK_SUCCESS) | |
{ | |
printf("VkResult is %s in %s at line %d\n", str, __FILE__, __LINE__); | |
return 1; | |
} | |
return 0; | |
} | |
#define VK_CHECK_RESULT(f) \ | |
{ \ | |
VkResult res = (f); \ | |
check_result(res); \ | |
} | |
static VkResult create_debug_utils_messenger_EXT( | |
VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, | |
const VkAllocationCallbacks* pAllocator, VkDebugUtilsMessengerEXT* pDebugMessenger) | |
{ | |
PFN_vkCreateDebugUtilsMessengerEXT func = | |
(PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr( | |
instance, "vkCreateDebugUtilsMessengerEXT"); | |
if (func != NULL) | |
{ | |
return func(instance, pCreateInfo, pAllocator, pDebugMessenger); | |
} | |
else | |
{ | |
return VK_ERROR_EXTENSION_NOT_PRESENT; | |
} | |
} | |
static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback( | |
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, | |
VkDebugUtilsMessageTypeFlagsEXT messageType, | |
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) | |
{ | |
// Hide long list of extensions. | |
if (strstr(pCallbackData->pMessage, "Extension: VK_") != NULL) | |
return VK_FALSE; | |
printf("validation layer: %s\n", pCallbackData->pMessage); | |
if (messageSeverity >= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT && pUserData != NULL) | |
{ | |
uint32_t* n_errors = (uint32_t*)pUserData; | |
(*n_errors)++; | |
} | |
return VK_FALSE; | |
} | |
static void destroy_debug_utils_messenger_EXT( | |
VkInstance instance, VkDebugUtilsMessengerEXT debug_messenger, | |
const VkAllocationCallbacks* pAllocator) | |
{ | |
PFN_vkDestroyDebugUtilsMessengerEXT func = | |
(PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr( | |
instance, "vkDestroyDebugUtilsMessengerEXT"); | |
if (func != NULL) | |
{ | |
func(instance, debug_messenger, pAllocator); | |
} | |
} | |
static VkInstance createInstance(VkDebugUtilsMessengerEXT* debug_messenger, void* debug_data) | |
{ | |
uint32_t glfwExtensionCount = 0; | |
const char** glfwExtensions; | |
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); | |
const char* addExtensions[] = { | |
"VK_EXT_debug_utils", // | |
}; | |
uint32_t addExtensionCount = sizeof(addExtensions) / sizeof(char*); | |
uint32_t extensionCount = glfwExtensionCount + addExtensionCount; | |
char** extensions = calloc(extensionCount, sizeof(char*)); | |
memcpy(extensions, glfwExtensions, glfwExtensionCount * sizeof(char*)); | |
memcpy(&extensions[glfwExtensionCount], addExtensions, sizeof(addExtensions)); | |
// Prepare the creation of the Vulkan instance. | |
VkApplicationInfo appInfo = {0}; | |
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; | |
appInfo.pApplicationName = "fail"; | |
appInfo.applicationVersion = 1; | |
appInfo.pEngineName = "fail"; | |
appInfo.engineVersion = 1; | |
appInfo.apiVersion = VK_API_VERSION_1_3; | |
VkInstanceCreateInfo info_inst = {0}; | |
info_inst.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; | |
info_inst.pApplicationInfo = &appInfo; | |
info_inst.enabledExtensionCount = extensionCount; | |
info_inst.ppEnabledExtensionNames = (const char* const*)extensions; | |
// Validation layers. | |
VkDebugUtilsMessengerCreateInfoEXT info_debug = {0}; | |
info_debug.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; | |
info_debug.flags = 0; | |
info_debug.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; | |
info_debug.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; | |
info_debug.pfnUserCallback = debug_callback; | |
info_debug.pUserData = debug_data; | |
VkValidationFeatureEnableEXT enables[16] = {0}; | |
VkValidationFeaturesEXT features = {0}; | |
info_inst.enabledLayerCount = 1; | |
info_inst.ppEnabledLayerNames = (const char*[]){"VK_LAYER_KHRONOS_validation"}; | |
// https://vulkan.lunarg.com/doc/sdk/1.2.170.0/linux/best_practices.html | |
enables[0] = VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT; | |
enables[1] = VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT; | |
enables[2] = VK_VALIDATION_FEATURE_ENABLE_SYNCHRONIZATION_VALIDATION_EXT; | |
features.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT; | |
features.enabledValidationFeatureCount = 3; | |
features.pEnabledValidationFeatures = enables; | |
// pNext chain | |
features.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&info_debug; | |
info_inst.pNext = &features; | |
// Create the Vulkan instance. | |
VkInstance instance; | |
VK_CHECK_RESULT(vkCreateInstance(&info_inst, NULL, &instance)); | |
// Create the debug utils messenger. | |
VK_CHECK_RESULT( | |
create_debug_utils_messenger_EXT(instance, &info_debug, NULL, debug_messenger)); | |
free(extensions); | |
return instance; | |
} | |
VkPhysicalDevice pickPhysicalDevice(VkInstance instance) | |
{ | |
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; | |
uint32_t deviceCount = 0; | |
vkEnumeratePhysicalDevices(instance, &deviceCount, NULL); | |
if (deviceCount == 0) | |
{ | |
fprintf(stderr, "Failed to find GPUs with Vulkan support!\n"); | |
exit(1); | |
} | |
VkPhysicalDevice devices[deviceCount]; | |
vkEnumeratePhysicalDevices(instance, &deviceCount, devices); | |
// Just pick the first device for simplicity | |
physicalDevice = devices[0]; | |
return physicalDevice; | |
} | |
VkDevice createLogicalDevice(VkPhysicalDevice physicalDevice, uint32_t* queueFamilyIndex) | |
{ | |
VkDevice device; | |
VkDeviceQueueCreateInfo queueCreateInfo = {0}; | |
queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; | |
queueCreateInfo.queueFamilyIndex = *queueFamilyIndex; | |
queueCreateInfo.queueCount = 1; | |
float queuePriority = 1.0f; | |
queueCreateInfo.pQueuePriorities = &queuePriority; | |
VkPhysicalDeviceFeatures deviceFeatures = {0}; | |
vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures); | |
VkDeviceCreateInfo createInfo = {0}; | |
createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; | |
createInfo.pQueueCreateInfos = &queueCreateInfo; | |
createInfo.queueCreateInfoCount = 1; | |
createInfo.pEnabledFeatures = &deviceFeatures; | |
createInfo.enabledExtensionCount = 1; | |
createInfo.ppEnabledExtensionNames = (const char*[]){ | |
VK_KHR_SWAPCHAIN_EXTENSION_NAME, | |
}; | |
if (vkCreateDevice(physicalDevice, &createInfo, NULL, &device) != VK_SUCCESS) | |
{ | |
fprintf(stderr, "Failed to create logical device!\n"); | |
exit(1); | |
} | |
return device; | |
} | |
uint32_t findQueueFamilies(VkPhysicalDevice device) | |
{ | |
uint32_t queueFamilyCount = 0; | |
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, NULL); | |
VkQueueFamilyProperties queueFamilies[queueFamilyCount]; | |
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies); | |
for (uint32_t i = 0; i < queueFamilyCount; i++) | |
{ | |
if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) | |
{ | |
return i; | |
} | |
} | |
fprintf(stderr, "Failed to find a suitable queue family!\n"); | |
exit(1); | |
} | |
VkSurfaceKHR createSurface(VkInstance instance, GLFWwindow* window) | |
{ | |
VkSurfaceKHR surface; | |
if (glfwCreateWindowSurface(instance, window, NULL, &surface) != VK_SUCCESS) | |
{ | |
fprintf(stderr, "Failed to create window surface!\n"); | |
exit(1); | |
} | |
return surface; | |
} | |
VkSwapchainKHR createSwapChain( | |
VkPhysicalDevice physicalDevice, VkDevice device, VkSurfaceKHR surface, VkFormat* format, | |
uint32_t* imageCount, VkExtent2D* extent, VkImage* swapChainImages) | |
{ | |
assert(device); | |
VkSwapchainKHR swapChain; | |
VkSurfaceCapabilitiesKHR capabilities; | |
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities); | |
VkSurfaceFormatKHR surfaceFormat; | |
uint32_t formatCount; | |
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, NULL); | |
VkSurfaceFormatKHR formats[formatCount]; | |
vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, formats); | |
surfaceFormat = formats[0]; | |
VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; | |
VkSwapchainCreateInfoKHR createInfo = {0}; | |
createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; | |
createInfo.surface = surface; | |
createInfo.minImageCount = capabilities.minImageCount + 1; | |
createInfo.imageFormat = surfaceFormat.format; | |
createInfo.imageColorSpace = surfaceFormat.colorSpace; | |
createInfo.imageExtent = capabilities.currentExtent; | |
createInfo.imageArrayLayers = 1; | |
createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; | |
createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; | |
createInfo.preTransform = capabilities.currentTransform; | |
createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; | |
createInfo.presentMode = presentMode; | |
createInfo.clipped = VK_TRUE; | |
createInfo.oldSwapchain = VK_NULL_HANDLE; | |
if (vkCreateSwapchainKHR(device, &createInfo, NULL, &swapChain) != VK_SUCCESS) | |
{ | |
fprintf(stderr, "Failed to create swap chain!\n"); | |
exit(1); | |
} | |
*extent = createInfo.imageExtent; | |
vkGetSwapchainImagesKHR(device, swapChain, imageCount, NULL); | |
vkGetSwapchainImagesKHR(device, swapChain, imageCount, swapChainImages); | |
*format = createInfo.imageFormat; | |
return swapChain; | |
} | |
VkImageView createImageView(VkDevice device, VkImage image, VkFormat format) | |
{ | |
VkImageViewCreateInfo viewInfo = {0}; | |
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; | |
viewInfo.image = image; | |
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; | |
viewInfo.format = format; | |
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; | |
viewInfo.subresourceRange.baseMipLevel = 0; | |
viewInfo.subresourceRange.levelCount = 1; | |
viewInfo.subresourceRange.baseArrayLayer = 0; | |
viewInfo.subresourceRange.layerCount = 1; | |
VkImageView imageView; | |
if (vkCreateImageView(device, &viewInfo, NULL, &imageView) != VK_SUCCESS) | |
{ | |
fprintf(stderr, "Failed to create image views!\n"); | |
exit(1); | |
} | |
return imageView; | |
} | |
VkRenderPass createRenderPass(VkDevice device, VkFormat format) | |
{ | |
VkRenderPass renderPass; | |
VkAttachmentDescription colorAttachment = {0}; | |
colorAttachment.format = format; | |
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 = {0}; | |
colorAttachmentRef.attachment = 0; | |
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; | |
VkSubpassDescription subpass = {0}; | |
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; | |
subpass.colorAttachmentCount = 1; | |
subpass.pColorAttachments = &colorAttachmentRef; | |
VkRenderPassCreateInfo renderPassInfo = {0}; | |
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; | |
renderPassInfo.attachmentCount = 1; | |
renderPassInfo.pAttachments = &colorAttachment; | |
renderPassInfo.subpassCount = 1; | |
renderPassInfo.pSubpasses = &subpass; | |
if (vkCreateRenderPass(device, &renderPassInfo, NULL, &renderPass) != VK_SUCCESS) | |
{ | |
fprintf(stderr, "Failed to create render pass!\n"); | |
exit(1); | |
} | |
return renderPass; | |
} | |
VkFramebuffer createFramebuffer( | |
VkDevice device, VkRenderPass renderPass, VkImageView imageView, VkExtent2D extent) | |
{ | |
VkFramebuffer framebuffer; | |
VkImageView attachments[] = {imageView}; | |
VkFramebufferCreateInfo framebufferInfo = {0}; | |
framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; | |
framebufferInfo.renderPass = renderPass; | |
framebufferInfo.attachmentCount = 1; | |
framebufferInfo.pAttachments = attachments; | |
framebufferInfo.width = extent.width; | |
framebufferInfo.height = extent.height; | |
framebufferInfo.layers = 1; | |
if (vkCreateFramebuffer(device, &framebufferInfo, NULL, &framebuffer) != VK_SUCCESS) | |
{ | |
fprintf(stderr, "Failed to create framebuffer!\n"); | |
exit(1); | |
} | |
return framebuffer; | |
} | |
VkCommandPool createCommandPool(VkDevice device, uint32_t queueFamilyIndex) | |
{ | |
VkCommandPoolCreateInfo poolInfo = {}; | |
poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; | |
poolInfo.queueFamilyIndex = queueFamilyIndex; | |
poolInfo.flags = 0; | |
VkCommandPool commandPool; | |
if (vkCreateCommandPool(device, &poolInfo, NULL, &commandPool) != VK_SUCCESS) | |
{ | |
fprintf(stderr, "Failed to create command pool\n"); | |
exit(1); | |
} | |
return commandPool; | |
} | |
VkCommandBuffer* createCommandBuffers( | |
VkDevice device, VkCommandPool commandPool, VkRenderPass renderPass, VkImage image, | |
VkFramebuffer* framebuffers, VkExtent2D extent, uint32_t imageCount) | |
{ | |
VkCommandBuffer* commandBuffers = malloc(imageCount * sizeof(VkCommandBuffer)); | |
VkCommandBufferAllocateInfo allocInfo = {}; | |
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; | |
allocInfo.commandPool = commandPool; | |
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; | |
allocInfo.commandBufferCount = imageCount; | |
vkAllocateCommandBuffers(device, &allocInfo, commandBuffers); | |
VkImageMemoryBarrier imageBarrier = {}; | |
imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; | |
imageBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; | |
imageBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; | |
imageBarrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; | |
imageBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | |
imageBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | |
imageBarrier.image = image; | |
imageBarrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; | |
imageBarrier.subresourceRange.baseMipLevel = 0; | |
imageBarrier.subresourceRange.levelCount = 1; | |
imageBarrier.subresourceRange.baseArrayLayer = 0; | |
imageBarrier.subresourceRange.layerCount = 1; | |
for (size_t i = 0; i < imageCount; i++) | |
{ | |
VkCommandBufferBeginInfo beginInfo = {}; | |
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; | |
vkBeginCommandBuffer(commandBuffers[i], &beginInfo); | |
VkRenderPassBeginInfo renderPassInfo = {}; | |
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; | |
renderPassInfo.renderPass = renderPass; | |
renderPassInfo.framebuffer = framebuffers[i]; | |
renderPassInfo.renderArea.offset = (VkOffset2D){0, 0}; | |
renderPassInfo.renderArea.extent = extent; | |
VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; | |
renderPassInfo.clearValueCount = 1; | |
renderPassInfo.pClearValues = &clearColor; | |
vkCmdPipelineBarrier( | |
commandBuffers[i], VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, | |
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, &imageBarrier); | |
vkCmdBeginRenderPass(commandBuffers[i], &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); | |
vkCmdEndRenderPass(commandBuffers[i]); | |
vkEndCommandBuffer(commandBuffers[i]); | |
} | |
return commandBuffers; | |
} | |
VkSemaphore createSemaphore(VkDevice device) | |
{ | |
VkSemaphoreCreateInfo semaphoreInfo = {}; | |
semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; | |
VkSemaphore semaphore; | |
if (vkCreateSemaphore(device, &semaphoreInfo, NULL, &semaphore) != VK_SUCCESS) | |
{ | |
fprintf(stderr, "Failed to create semaphore\n"); | |
exit(1); | |
} | |
return semaphore; | |
} | |
int main() | |
{ | |
if (!glfwInit()) | |
{ | |
fprintf(stderr, "Failed to initialize GLFW\n"); | |
return -1; | |
} | |
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); | |
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan Window", NULL, NULL); | |
if (!window) | |
{ | |
fprintf(stderr, "Failed to create GLFW window\n"); | |
glfwTerminate(); | |
return -1; | |
} | |
VkDebugUtilsMessengerEXT debug_callback; | |
VkInstance instance = createInstance(&debug_callback, NULL); | |
VkPhysicalDevice physicalDevice = pickPhysicalDevice(instance); | |
uint32_t queueFamilyIndex = findQueueFamilies(physicalDevice); | |
VkDevice device = createLogicalDevice(physicalDevice, &queueFamilyIndex); | |
VkSurfaceKHR surface = createSurface(instance, window); | |
VkFormat format; | |
uint32_t imageCount; | |
VkExtent2D extent; | |
VkImage swapChainImages[10] = {0}; | |
VkSwapchainKHR swapChain = createSwapChain( | |
physicalDevice, device, surface, &format, &imageCount, &extent, swapChainImages); | |
VkImageView* imageViews = malloc(imageCount * sizeof(VkImageView)); | |
for (uint32_t i = 0; i < imageCount; i++) | |
imageViews[i] = createImageView(device, swapChainImages[i], format); | |
VkRenderPass renderPass = createRenderPass(device, format); | |
VkFramebuffer* framebuffers = malloc(imageCount * sizeof(VkFramebuffer)); | |
for (uint32_t i = 0; i < imageCount; i++) | |
framebuffers[i] = createFramebuffer(device, renderPass, imageViews[i], extent); | |
VkCommandPool commandPool = createCommandPool(device, queueFamilyIndex); | |
VkCommandBuffer* commandBuffers = createCommandBuffers( | |
device, commandPool, renderPass, swapChainImages[0], framebuffers, extent, imageCount); | |
VkSemaphore imageAvailableSemaphore = createSemaphore(device); | |
VkSemaphore renderFinishedSemaphore = createSemaphore(device); | |
uint32_t imageIndex; | |
vkAcquireNextImageKHR( | |
device, swapChain, UINT64_MAX, imageAvailableSemaphore, VK_NULL_HANDLE, &imageIndex); | |
VkSubmitInfo submitInfo = {}; | |
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; | |
VkSemaphore waitSemaphores[] = {imageAvailableSemaphore}; | |
// NOTE: the warning disappears by putting VK_PIPELINE_STAGE_ALL_COMMANDS_BIT here, | |
// but then we've got: | |
// | |
// Validation Warning: [ UNASSIGNED-BestPractices-pipeline-stage-flags ] | MessageID = | |
// 0x48a09f6c | vkQueueSubmit(): pSubmits[0].pWaitDstStageMask[0] using | |
// VK_PIPELINE_STAGE_ALL_COMMANDS_BIT | |
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; | |
submitInfo.waitSemaphoreCount = 1; | |
submitInfo.pWaitSemaphores = waitSemaphores; | |
submitInfo.pWaitDstStageMask = waitStages; | |
submitInfo.commandBufferCount = 1; | |
submitInfo.pCommandBuffers = &commandBuffers[imageIndex]; | |
VkSemaphore signalSemaphores[] = {renderFinishedSemaphore}; | |
submitInfo.signalSemaphoreCount = 1; | |
submitInfo.pSignalSemaphores = signalSemaphores; | |
VkQueue graphicsQueue; | |
vkGetDeviceQueue(device, queueFamilyIndex, 0, &graphicsQueue); | |
vkQueueSubmit(graphicsQueue, 1, &submitInfo, NULL); | |
/* | |
Here we get this: | |
validation layer: Validation Error: [ SYNC-HAZARD-WRITE-AFTER-READ ] Object 0: handle = | |
0x5599afbbf520, type = VK_OBJECT_TYPE_QUEUE; | MessageID = 0x376bc9df | vkQueueSubmit(): Hazard | |
WRITE_AFTER_READ for entry 0, VkCommandBuffer 0x5599b202e960[], Submitted access info | |
(submitted_usage: SYNC_IMAGE_LAYOUT_TRANSITION, command: vkCmdBeginRenderPass, seq_no: 1, | |
renderpass: VkRenderPass 0xcad092000000000d[], reset_no: 1). Access info (prior_usage: | |
SYNC_PRESENT_ENGINE_SYNCVAL_PRESENT_ACQUIRE_READ_SYNCVAL, read_barriers: | |
VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT|VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT, , | |
batch_tag: 1, vkAcquireNextImageKHR aquire_tag:1: VkSwapchainKHR 0xf443490000000006[], | |
image_index: 0image: VkImage 0xcb3ee80000000007[]). | |
*/ | |
VkPresentInfoKHR presentInfo = {}; | |
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; | |
presentInfo.waitSemaphoreCount = 1; | |
presentInfo.pWaitSemaphores = signalSemaphores; | |
VkSwapchainKHR swapChains[] = {swapChain}; | |
presentInfo.swapchainCount = 1; | |
presentInfo.pSwapchains = swapChains; | |
presentInfo.pImageIndices = &imageIndex; | |
vkQueuePresentKHR(graphicsQueue, &presentInfo); | |
vkQueueWaitIdle(graphicsQueue); | |
destroy_debug_utils_messenger_EXT(instance, debug_callback, NULL); | |
vkDestroySemaphore(device, imageAvailableSemaphore, NULL); | |
vkDestroySemaphore(device, renderFinishedSemaphore, NULL); | |
for (uint32_t i = 0; i < imageCount; i++) | |
{ | |
vkDestroyFramebuffer(device, framebuffers[i], NULL); | |
vkDestroyImageView(device, imageViews[i], NULL); | |
} | |
vkDestroyCommandPool(device, commandPool, NULL); | |
vkDestroyRenderPass(device, renderPass, NULL); | |
vkDestroySwapchainKHR(device, swapChain, NULL); | |
vkDestroyDevice(device, NULL); | |
vkDestroySurfaceKHR(instance, surface, NULL); | |
vkDestroyInstance(instance, NULL); | |
glfwDestroyWindow(window); | |
glfwTerminate(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment