aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Elliott <ian@lunarg.com>2015-07-06 14:27:58 -0600
committerCourtney Goeltzenleuchter <courtney@LunarG.com>2015-07-17 10:05:21 -0600
commitaaae5350faa95cd7223a2200c27f23cb3babd8e2 (patch)
tree009829d39672c90370f3e33538b359961aa54ec2
parent1153775dadb142631916ad8a480c134250a5b184 (diff)
downloadusermoji-aaae5350faa95cd7223a2200c27f23cb3babd8e2.tar.xz
demos: Changes to use new WSI swapchain extensions.
-rw-r--r--demos/cube.c332
-rw-r--r--demos/tri.c435
-rw-r--r--demos/vulkaninfo.c8
3 files changed, 638 insertions, 137 deletions
diff --git a/demos/cube.c b/demos/cube.c
index a3450304..7bdef0fd 100644
--- a/demos/cube.c
+++ b/demos/cube.c
@@ -37,7 +37,8 @@
#endif // _WIN32
#include <vulkan.h>
-#include <vk_wsi_lunarg.h>
+#include <vk_wsi_swapchain.h>
+#include <vk_wsi_device_swapchain.h>
#include "vk_debug_report_lunarg.h"
#include "icd-spv.h"
@@ -80,6 +81,15 @@
} while (0)
#endif // _WIN32
+#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
+{ \
+ demo->fp##entrypoint = (PFN_vk##entrypoint) vkGetInstanceProcAddr(inst, "vk"#entrypoint); \
+ if (demo->fp##entrypoint == NULL) { \
+ ERR_EXIT("vkGetInstanceProcAddr failed to find vk"#entrypoint, \
+ "vkGetInstanceProcAddr Failure"); \
+ } \
+}
+
#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \
{ \
demo->fp##entrypoint = (PFN_vk##entrypoint) vkGetDeviceProcAddr(dev, "vk"#entrypoint); \
@@ -282,6 +292,12 @@ void dbgFunc(
free(message);
}
+typedef struct _SwapChainBuffers {
+ VkImage image;
+ VkCmdBuffer cmd;
+ VkAttachmentView view;
+} SwapChainBuffers;
+
struct demo {
#ifdef _WIN32
#define APP_NAME_STR_LEN 80
@@ -294,6 +310,7 @@ struct demo {
xcb_window_t window;
xcb_intern_atom_reply_t *atom_wm_delete_window;
#endif // _WIN32
+ VkPlatformHandleXcbWSI platform_handle_xcb;
bool prepared;
bool use_staging_buffer;
bool use_glsl;
@@ -311,19 +328,19 @@ struct demo {
int width, height;
VkFormat format;
+ PFN_vkGetPhysicalDeviceSurfaceSupportWSI fpGetPhysicalDeviceSurfaceSupportWSI;
+ PFN_vkGetSurfaceInfoWSI fpGetSurfaceInfoWSI;
PFN_vkCreateSwapChainWSI fpCreateSwapChainWSI;
PFN_vkDestroySwapChainWSI fpDestroySwapChainWSI;
PFN_vkGetSwapChainInfoWSI fpGetSwapChainInfoWSI;
+ PFN_vkAcquireNextImageWSI fpAcquireNextImageWSI;
PFN_vkQueuePresentWSI fpQueuePresentWSI;
+ VkSurfaceDescriptionWindowWSI surface_description;
+ size_t swapChainImageCount;
VkSwapChainWSI swap_chain;
- VkCmdPool cmd_pool;
- struct {
- VkImage image;
- VkDeviceMemory mem;
- VkCmdBuffer cmd;
+ SwapChainBuffers *buffers;
- VkAttachmentView view;
- } buffers[DEMO_BUFFER_COUNT];
+ VkCmdPool cmd_pool;
struct {
VkFormat format;
@@ -551,23 +568,57 @@ void demo_update_data_buffer(struct demo *demo)
static void demo_draw(struct demo *demo)
{
- const VkPresentInfoWSI present = {
- .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_WSI,
+ VkResult U_ASSERT_ONLY err;
+ VkSemaphore presentCompleteSemaphore;
+ VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo = {
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
.pNext = NULL,
- .image = demo->buffers[demo->current_buffer].image,
- .flipInterval = 0,
+ .flags = VK_FENCE_CREATE_SIGNALED_BIT,
};
- VkResult U_ASSERT_ONLY err;
VkFence nullFence = { VK_NULL_HANDLE };
+ err = vkCreateSemaphore(demo->device,
+ &presentCompleteSemaphoreCreateInfo,
+ &presentCompleteSemaphore);
+ assert(!err);
+
+ // Get the index of the next available swapchain image:
+ err = demo->fpAcquireNextImageWSI(demo->device, demo->swap_chain,
+ UINT64_MAX,
+ presentCompleteSemaphore,
+ &demo->current_buffer);
+ // TODO: Deal with the VK_SUBOPTIMAL_WSI and VK_ERROR_OUT_OF_DATE_WSI
+ // return codes
+ assert(!err);
+
+ // Wait for the present complete semaphore to be signaled to ensure
+ // that the image won't be rendered to until the presentation
+ // engine has fully released ownership to the application, and it is
+ // okay to render to the image.
+ vkQueueWaitSemaphore(demo->queue, presentCompleteSemaphore);
+
+// FIXME/TODO: DEAL WITH VK_IMAGE_LAYOUT_PRESENT_SOURCE_WSI
err = vkQueueSubmit(demo->queue, 1, &demo->buffers[demo->current_buffer].cmd,
nullFence);
assert(!err);
+ VkPresentInfoWSI present = {
+ .sType = VK_STRUCTURE_TYPE_QUEUE_PRESENT_INFO_WSI,
+ .pNext = NULL,
+ .swapChainCount = 1,
+ .swapChains = &demo->swap_chain,
+ .imageIndices = &demo->current_buffer,
+ };
+
+// TBD/TODO: SHOULD THE "present" PARAMETER BE "const" IN THE HEADER?
err = demo->fpQueuePresentWSI(demo->queue, &present);
+ // TODO: Deal with the VK_SUBOPTIMAL_WSI and VK_ERROR_OUT_OF_DATE_WSI
+ // return codes
assert(!err);
- demo->current_buffer = (demo->current_buffer + 1) % DEMO_BUFFER_COUNT;
+// FIXME: UNCOMMENT THE FOLLOWING LINE ONCE WE HAVE A NEW-ENOUGH "vulkan.h" HEADER:
+// err = vkDestroySemaphore(demo->device, presentCompleteSemaphore);
+ assert(!err);
err = vkQueueWaitIdle(demo->queue);
assert(err == VK_SUCCESS);
@@ -575,35 +626,120 @@ static void demo_draw(struct demo *demo)
static void demo_prepare_buffers(struct demo *demo)
{
+ VkResult U_ASSERT_ONLY err;
+
+ // Check the surface properties and formats
+ size_t capsSize;
+ size_t presentModesSize;
+ err = demo->fpGetSurfaceInfoWSI(demo->device,
+ (const VkSurfaceDescriptionWSI *)&demo->surface_description,
+ VK_SURFACE_INFO_TYPE_PROPERTIES_WSI, &capsSize, NULL);
+ assert(!err);
+ err = demo->fpGetSurfaceInfoWSI(demo->device,
+ (const VkSurfaceDescriptionWSI *)&demo->surface_description,
+ VK_SURFACE_INFO_TYPE_PRESENT_MODES_WSI, &presentModesSize, NULL);
+ assert(!err);
+
+ VkSurfacePropertiesWSI *surfProperties =
+ (VkSurfacePropertiesWSI *)malloc(capsSize);
+ VkSurfacePresentModePropertiesWSI *presentModes =
+ (VkSurfacePresentModePropertiesWSI *)malloc(presentModesSize);
+
+ err = demo->fpGetSurfaceInfoWSI(demo->device,
+ (const VkSurfaceDescriptionWSI *)&demo->surface_description,
+ VK_SURFACE_INFO_TYPE_PROPERTIES_WSI, &capsSize, surfProperties);
+ assert(!err);
+ err = demo->fpGetSurfaceInfoWSI(demo->device,
+ (const VkSurfaceDescriptionWSI *)&demo->surface_description,
+ VK_SURFACE_INFO_TYPE_PRESENT_MODES_WSI, &presentModesSize, presentModes);
+ assert(!err);
+
+ VkExtent2D swapChainExtent;
+ // width and height are either both -1, or both not -1.
+ if (surfProperties->currentExtent.width == -1)
+ {
+ // If the surface size is undefined, the size is set to
+ // the size of the images requested.
+ swapChainExtent.width = demo->width;
+ swapChainExtent.height = demo->height;
+ }
+ else
+ {
+ // If the surface size is defined, the swap chain size must match
+ swapChainExtent = surfProperties->currentExtent;
+ }
+
+ // If mailbox mode is available, use it, as is the lowest-latency non-
+ // tearing mode. If not, fall back to IMMEDIATE which should always be
+ // available.
+ VkPresentModeWSI swapChainPresentMode = VK_PRESENT_MODE_IMMEDIATE_WSI;
+ size_t presentModeCount = presentModesSize / sizeof(VkSurfacePresentModePropertiesWSI);
+ for (size_t i = 0; i < presentModeCount; i++) {
+ if (presentModes[i].presentMode == VK_PRESENT_MODE_MAILBOX_WSI) {
+ swapChainPresentMode = VK_PRESENT_MODE_MAILBOX_WSI;
+ break;
+ }
+ }
+
+ // Determine the number of VkImage's to use in the swap chain (we desire to
+ // own only 1 image at a time, besides the images being displayed and
+ // queued for display):
+ uint32_t desiredNumberOfSwapChainImages = surfProperties->minImageCount + 1;
+ if ((surfProperties->maxImageCount > 0) &&
+ (desiredNumberOfSwapChainImages > surfProperties->maxImageCount))
+ {
+ // Application must settle for fewer images than desired:
+ desiredNumberOfSwapChainImages = surfProperties->maxImageCount;
+ }
+
+ VkSurfaceTransformFlagBitsWSI preTransform;
+ if (surfProperties->supportedTransforms & VK_SURFACE_TRANSFORM_NONE_BIT_WSI) {
+ preTransform = VK_SURFACE_TRANSFORM_NONE_WSI;
+ } else {
+ preTransform = surfProperties->currentTransform;
+ }
+
const VkSwapChainCreateInfoWSI swap_chain = {
.sType = VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_WSI,
.pNext = NULL,
- .pNativeWindowSystemHandle = demo->connection,
- .pNativeWindowHandle = (void *) (intptr_t) demo->window,
- .displayCount = 1,
- .imageCount = DEMO_BUFFER_COUNT,
+ .pSurfaceDescription = (const VkSurfaceDescriptionWSI *)&demo->surface_description,
+ .minImageCount = desiredNumberOfSwapChainImages,
.imageFormat = demo->format,
.imageExtent = {
- .width = demo->width,
- .height = demo->height,
+ .width = swapChainExtent.width,
+ .height = swapChainExtent.height,
},
+ .preTransform = preTransform,
.imageArraySize = 1,
- .imageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ .presentMode = swapChainPresentMode,
+ .oldSwapChain.handle = 0,
+ .clipped = true,
};
- VkSwapChainImageInfoWSI images[DEMO_BUFFER_COUNT];
- size_t images_size = sizeof(images);
- VkResult U_ASSERT_ONLY err;
uint32_t i;
err = demo->fpCreateSwapChainWSI(demo->device, &swap_chain, &demo->swap_chain);
assert(!err);
- err = demo->fpGetSwapChainInfoWSI(demo->swap_chain,
- VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_WSI,
- &images_size, images);
- assert(!err && images_size == sizeof(images));
+ size_t swapChainImagesSize;
+ err = demo->fpGetSwapChainInfoWSI(demo->device, demo->swap_chain,
+ VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI,
+ &swapChainImagesSize, NULL);
+ assert(!err);
- for (i = 0; i < DEMO_BUFFER_COUNT; i++) {
+ VkSwapChainImagePropertiesWSI* swapChainImages = (VkSwapChainImagePropertiesWSI*)malloc(swapChainImagesSize);
+ assert(swapChainImages);
+ err = demo->fpGetSwapChainInfoWSI(demo->device, demo->swap_chain,
+ VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI,
+ &swapChainImagesSize, swapChainImages);
+ assert(!err);
+
+ // The number of images within the swap chain is determined based on the size of the info returned
+ demo->swapChainImageCount = swapChainImagesSize / sizeof(VkSwapChainImagePropertiesWSI);
+
+ demo->buffers = (SwapChainBuffers*)malloc(sizeof(SwapChainBuffers)*demo->swapChainImageCount);
+ assert(demo->buffers);
+
+ for (i = 0; i < demo->swapChainImageCount; i++) {
VkAttachmentViewCreateInfo color_attachment_view = {
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO,
.pNext = NULL,
@@ -613,8 +749,7 @@ static void demo_prepare_buffers(struct demo *demo)
.arraySize = 1,
};
- demo->buffers[i].image = images[i].image;
- demo->buffers[i].mem = images[i].memory;
+ demo->buffers[i].image = swapChainImages[i].image;
demo_set_image_layout(demo, demo->buffers[i].image,
VK_IMAGE_ASPECT_COLOR,
@@ -1681,7 +1816,7 @@ static void demo_prepare(struct demo *demo)
demo_prepare_pipeline(demo);
demo_prepare_dynamic_states(demo);
- for (int i = 0; i < DEMO_BUFFER_COUNT; i++) {
+ for (uint32_t i = 0; i < demo->swapChainImageCount; i++) {
err = vkCreateCommandBuffer(demo->device, &cmd, &demo->buffers[i].cmd);
assert(!err);
}
@@ -1691,7 +1826,7 @@ static void demo_prepare(struct demo *demo)
demo_prepare_framebuffers(demo);
- for (int i = 0; i < DEMO_BUFFER_COUNT; i++) {
+ for (uint32_t i = 0; i < demo->swapChainImageCount; i++) {
demo->current_buffer = i;
demo_draw_build_cmd(demo, demo->buffers[i].cmd);
}
@@ -1735,7 +1870,7 @@ static void demo_cleanup(struct demo *demo)
vkFreeMemory(demo->device, demo->textures[i].mem);
vkDestroySampler(demo->device, demo->textures[i].sampler);
}
- demo->fpDestroySwapChainWSI(demo->swap_chain);
+ demo->fpDestroySwapChainWSI(demo->device, demo->swap_chain);
vkDestroyAttachmentView(demo->device, demo->depth.view);
vkDestroyImage(demo->device, demo->depth.image);
@@ -1745,10 +1880,11 @@ static void demo_cleanup(struct demo *demo)
vkDestroyBuffer(demo->device, demo->uniform_data.buf);
vkFreeMemory(demo->device, demo->uniform_data.mem);
- for (i = 0; i < DEMO_BUFFER_COUNT; i++) {
+ for (i = 0; i < demo->swapChainImageCount; i++) {
vkDestroyAttachmentView(demo->device, demo->buffers[i].view);
vkDestroyCommandBuffer(demo->device, demo->buffers[i].cmd);
}
+ free(demo->buffers);
vkDestroyCommandPool(demo->device, demo->cmd_pool);
vkDestroyDevice(demo->device);
@@ -1799,10 +1935,10 @@ LRESULT CALLBACK WndProc(HWND hWnd,
{
switch(uMsg)
{
- case WM_CLOSE:
+ case WM_CLOSE:
PostQuitMessage(0);
break;
- case WM_PAINT:
+ case WM_PAINT:
demo_run(&demo);
return 0;
default:
@@ -2045,9 +2181,9 @@ static void demo_init_vk(struct demo *demo)
err = vkGetGlobalExtensionProperties(NULL, &instance_extension_count, instance_extensions);
assert(!err);
for (uint32_t i = 0; i < instance_extension_count; i++) {
- if (!strcmp(VK_WSI_LUNARG_EXTENSION_NAME, instance_extensions[i].extName)) {
+ if (!strcmp("VK_WSI_swapchain", instance_extensions[i].extName)) {
WSIextFound = 1;
- extension_names[enabled_extension_count++] = VK_WSI_LUNARG_EXTENSION_NAME;
+ extension_names[enabled_extension_count++] = "VK_WSI_swapchain";
}
if (!strcmp(DEBUG_REPORT_EXTENSION_NAME, instance_extensions[i].extName)) {
if (demo->validate) {
@@ -2058,7 +2194,7 @@ static void demo_init_vk(struct demo *demo)
}
if (!WSIextFound) {
ERR_EXIT("vkGetGlobalExtensionProperties failed to find the "
- "\"VK_WSI_LunarG\" extension.\n\nDo you have a compatible "
+ "\"VK_WSI_swapchain\" extension.\n\nDo you have a compatible "
"Vulkan installable client driver (ICD) installed?\nPlease "
"look at the Getting Started guide for additional "
"information.\n",
@@ -2153,24 +2289,22 @@ static void demo_init_vk(struct demo *demo)
err = vkGetPhysicalDeviceExtensionProperties(
demo->gpu, NULL, &device_extension_count, device_extensions);
assert(!err);
-#if 0
- /* Will need this check in future */
+
for (uint32_t i = 0; i < device_extension_count; i++) {
- if (!strcmp(VK_WSI_LUNARG_EXTENSION_NAME, device_extensions[i].extName)) {
+ if (!strcmp("VK_WSI_device_swapchain", device_extensions[i].extName)) {
WSIextFound = 1;
- extension_names[enabled_extension_count++] = VK_WSI_LUNARG_EXTENSION_NAME;
+ extension_names[enabled_extension_count++] = "VK_WSI_device_swapchain";
}
assert(enabled_extension_count < 64);
}
if (!WSIextFound) {
- ERR_EXIT("vkGetGlobalExtensionProperties failed to find the "
- "\"VK_WSI_LunarG\" extension.\n\nDo you have a compatible "
+ ERR_EXIT("vkGetPhysicalDeviceExtensionProperties failed to find the "
+ "\"VK_WSI_device_swapchain\" extension.\n\nDo you have a compatible "
"Vulkan installable client driver (ICD) installed?\nPlease "
"look at the Getting Started guide for additional "
"information.\n",
"vkCreateInstance Failure");
}
-#endif
VkDeviceCreateInfo device = {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
@@ -2223,10 +2357,13 @@ static void demo_init_vk(struct demo *demo)
free(device_layers);
+ GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportWSI);
+ GET_DEVICE_PROC_ADDR(demo->device, GetSurfaceInfoWSI);
GET_DEVICE_PROC_ADDR(demo->device, CreateSwapChainWSI);
GET_DEVICE_PROC_ADDR(demo->device, CreateSwapChainWSI);
GET_DEVICE_PROC_ADDR(demo->device, DestroySwapChainWSI);
GET_DEVICE_PROC_ADDR(demo->device, GetSwapChainInfoWSI);
+ GET_DEVICE_PROC_ADDR(demo->device, AcquireNextImageWSI);
GET_DEVICE_PROC_ADDR(demo->device, QueuePresentWSI);
err = vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props);
@@ -2240,22 +2377,105 @@ static void demo_init_vk(struct demo *demo)
assert(!err);
assert(queue_count >= 1);
- // Graphics queue and MemMgr queue can be separate.
- // TODO: Add support for separate queues, including synchronization,
- // and appropriate tracking for QueueSubmit
+ // Construct the WSI surface description:
+ demo->surface_description.sType = VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_WSI;
+ demo->surface_description.pNext = NULL;
+#ifdef _WIN32
+ demo->surface_description.platform = VK_PLATFORM_WIN32_WSI;
+ demo->surface_description.pPlatformHandle = demo->connection;
+ demo->surface_description.pPlatformWindow = demo->window;
+#else // _WIN32
+ demo->platform_handle_xcb.connection = demo->connection;
+ demo->platform_handle_xcb.root = demo->screen->root;
+ demo->surface_description.platform = VK_PLATFORM_XCB_WSI;
+ demo->surface_description.pPlatformHandle = &demo->platform_handle_xcb;
+ demo->surface_description.pPlatformWindow = &demo->window;
+#endif // _WIN32
+
+ // Iterate over each queue to learn whether it supports presenting to WSI:
+ VkBool32* supportsPresent = (VkBool32 *)malloc(queue_count * sizeof(VkBool32));
for (i = 0; i < queue_count; i++) {
- if (demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
- break;
+ demo->fpGetPhysicalDeviceSurfaceSupportWSI(demo->gpu, i,
+ (VkSurfaceDescriptionWSI *) &demo->surface_description,
+ &supportsPresent[i]);
}
- assert(i < queue_count);
- demo->graphics_queue_node_index = i;
+
+ // Search for a graphics and a present queue in the array of queue
+ // families, try to find one that supports both
+ uint32_t graphicsQueueNodeIndex = UINT32_MAX;
+ uint32_t presentQueueNodeIndex = UINT32_MAX;
+ for (i = 0; i < queue_count; i++) {
+ if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
+ if (graphicsQueueNodeIndex == UINT32_MAX) {
+ graphicsQueueNodeIndex = i;
+ }
+
+ if (supportsPresent[i] == VK_TRUE) {
+ graphicsQueueNodeIndex = i;
+ presentQueueNodeIndex = i;
+ break;
+ }
+ }
+ }
+ if (presentQueueNodeIndex == UINT32_MAX) {
+ // If didn't find a queue that supports both graphics and present, then
+ // find a separate present queue.
+ for (size_t i = 0; i < queue_count; ++i) {
+ if (supportsPresent[i] == VK_TRUE) {
+ presentQueueNodeIndex = i;
+ break;
+ }
+ }
+ }
+ free(supportsPresent);
+
+ // Generate error if could not find both a graphics and a present queue
+ if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) {
+ ERR_EXIT("Could not find a graphics and a present queue\n",
+ "WSI Initialization Failure");
+ }
+
+ // TODO: Add support for separate queues, including presentation,
+ // synchronization, and appropriate tracking for QueueSubmit
+ // While it is possible for an application to use a separate graphics and a
+ // present queues, this demo program assumes it is only using one:
+ if (graphicsQueueNodeIndex != presentQueueNodeIndex) {
+ ERR_EXIT("Could not find a common graphics and a present queue\n",
+ "WSI Initialization Failure");
+ }
+
+ demo->graphics_queue_node_index = graphicsQueueNodeIndex;
err = vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index,
0, &demo->queue);
assert(!err);
- // for now hardcode format till get WSI support
- demo->format = VK_FORMAT_B8G8R8A8_UNORM;
+ // Get the list of VkFormat's that are supported:
+ size_t formatsSize;
+ err = demo->fpGetSurfaceInfoWSI(demo->device,
+ (VkSurfaceDescriptionWSI *) &demo->surface_description,
+ VK_SURFACE_INFO_TYPE_FORMATS_WSI,
+ &formatsSize, NULL);
+ assert(!err);
+ VkSurfaceFormatPropertiesWSI *surfFormats = (VkSurfaceFormatPropertiesWSI *)malloc(formatsSize);
+ err = demo->fpGetSurfaceInfoWSI(demo->device,
+ (VkSurfaceDescriptionWSI *) &demo->surface_description,
+ VK_SURFACE_INFO_TYPE_FORMATS_WSI,
+ &formatsSize, surfFormats);
+ assert(!err);
+ // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
+ // the surface has no preferred format. Otherwise, at least one
+ // supported format will be returned.
+ size_t formatCount = formatsSize / sizeof(VkSurfaceFormatPropertiesWSI);
+ if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)
+ {
+ demo->format = VK_FORMAT_B8G8R8A8_UNORM;
+ }
+ else
+ {
+ assert(formatCount >= 1);
+ demo->format = surfFormats[0].format;
+ }
demo->quit = false;
demo->curFrame = 0;
diff --git a/demos/tri.c b/demos/tri.c
index 5bf5d904..7ef86ffd 100644
--- a/demos/tri.c
+++ b/demos/tri.c
@@ -42,8 +42,9 @@
#endif // _WIN32
#include <vulkan.h>
-#include <vk_wsi_lunarg.h>
#include "vk_debug_report_lunarg.h"
+#include <vk_wsi_swapchain.h>
+#include <vk_wsi_device_swapchain.h>
#include "icd-spv.h"
@@ -53,6 +54,8 @@
#define APP_SHORT_NAME "tri"
#define APP_LONG_NAME "The Vulkan Triangle Demo Program"
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
#if defined(NDEBUG) && defined(__GNUC__)
#define U_ASSERT_ONLY __attribute__((unused))
#else
@@ -80,6 +83,15 @@
} while (0)
#endif // _WIN32
+#define GET_INSTANCE_PROC_ADDR(inst, entrypoint) \
+{ \
+ demo->fp##entrypoint = (PFN_vk##entrypoint) vkGetInstanceProcAddr(inst, "vk"#entrypoint); \
+ if (demo->fp##entrypoint == NULL) { \
+ ERR_EXIT("vkGetInstanceProcAddr failed to find vk"#entrypoint, \
+ "vkGetInstanceProcAddr Failure"); \
+ } \
+}
+
#define GET_DEVICE_PROC_ADDR(dev, entrypoint) \
{ \
demo->fp##entrypoint = (PFN_vk##entrypoint) vkGetDeviceProcAddr(dev, "vk"#entrypoint); \
@@ -131,6 +143,12 @@ void dbgFunc(
free(message);
}
+typedef struct _SwapChainBuffers {
+ VkImage image;
+ VkCmdBuffer cmd;
+ VkAttachmentView view;
+} SwapChainBuffers;
+
struct demo {
#ifdef _WIN32
#define APP_NAME_STR_LEN 80
@@ -142,6 +160,7 @@ struct demo {
xcb_screen_t *screen;
xcb_window_t window;
xcb_intern_atom_reply_t *atom_wm_delete_window;
+ VkPlatformHandleXcbWSI platform_handle_xcb;
#endif // _WIN32
bool prepared;
bool use_staging_buffer;
@@ -158,19 +177,19 @@ struct demo {
int width, height;
VkFormat format;
+ PFN_vkGetPhysicalDeviceSurfaceSupportWSI fpGetPhysicalDeviceSurfaceSupportWSI;
+ PFN_vkGetSurfaceInfoWSI fpGetSurfaceInfoWSI;
PFN_vkCreateSwapChainWSI fpCreateSwapChainWSI;
PFN_vkDestroySwapChainWSI fpDestroySwapChainWSI;
PFN_vkGetSwapChainInfoWSI fpGetSwapChainInfoWSI;
+ PFN_vkAcquireNextImageWSI fpAcquireNextImageWSI;
PFN_vkQueuePresentWSI fpQueuePresentWSI;
-
+ VkSurfaceDescriptionWindowWSI surface_description;
+ size_t swapChainImageCount;
VkSwapChainWSI swap_chain;
- VkCmdPool cmd_pool;
- struct {
- VkImage image;
- VkDeviceMemory mem;
+ SwapChainBuffers *buffers;
- VkAttachmentView view;
- } buffers[DEMO_BUFFER_COUNT];
+ VkCmdPool cmd_pool;
struct {
VkFormat format;
@@ -213,6 +232,7 @@ struct demo {
bool validate;
PFN_vkDbgCreateMsgCallback dbgCreateMsgCallback;
+ PFN_vkDbgDestroyMsgCallback dbgDestroyMsgCallback;
VkDbgMsgCallback msg_callback;
bool quit;
@@ -370,24 +390,58 @@ static void demo_draw_build_cmd(struct demo *demo)
static void demo_draw(struct demo *demo)
{
- const VkPresentInfoWSI present = {
- .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_WSI,
+ VkResult U_ASSERT_ONLY err;
+ VkSemaphore presentCompleteSemaphore;
+ VkSemaphoreCreateInfo presentCompleteSemaphoreCreateInfo = {
+ .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
.pNext = NULL,
- .image = demo->buffers[demo->current_buffer].image,
- .flipInterval = 0,
+ .flags = VK_FENCE_CREATE_SIGNALED_BIT,
};
- VkResult U_ASSERT_ONLY err;
+ err = vkCreateSemaphore(demo->device,
+ &presentCompleteSemaphoreCreateInfo,
+ &presentCompleteSemaphore);
+ assert(!err);
+
+ // Get the index of the next available swapchain image:
+ err = demo->fpAcquireNextImageWSI(demo->device, demo->swap_chain,
+ UINT64_MAX,
+ presentCompleteSemaphore,
+ &demo->current_buffer);
+ // TODO: Deal with the VK_SUBOPTIMAL_WSI and VK_ERROR_OUT_OF_DATE_WSI
+ // return codes
+ assert(!err);
+
+ // Wait for the present complete semaphore to be signaled to ensure
+ // that the image won't be rendered to until the presentation
+ // engine has fully released ownership to the application, and it is
+ // okay to render to the image.
+ vkQueueWaitSemaphore(demo->queue, presentCompleteSemaphore);
+
+// FIXME/TODO: DEAL WITH VK_IMAGE_LAYOUT_PRESENT_SOURCE_WSI
demo_draw_build_cmd(demo);
VkFence nullFence = { VK_NULL_HANDLE };
err = vkQueueSubmit(demo->queue, 1, &demo->draw_cmd, nullFence);
assert(!err);
+ VkPresentInfoWSI present = {
+ .sType = VK_STRUCTURE_TYPE_QUEUE_PRESENT_INFO_WSI,
+ .pNext = NULL,
+ .swapChainCount = 1,
+ .swapChains = &demo->swap_chain,
+ .imageIndices = &demo->current_buffer,
+ };
+
+// TBD/TODO: SHOULD THE "present" PARAMETER BE "const" IN THE HEADER?
err = demo->fpQueuePresentWSI(demo->queue, &present);
+ // TODO: Deal with the VK_SUBOPTIMAL_WSI and VK_ERROR_OUT_OF_DATE_WSI
+ // return codes
assert(!err);
- demo->current_buffer = (demo->current_buffer + 1) % DEMO_BUFFER_COUNT;
+// FIXME: UNCOMMENT THE FOLLOWING LINE ONCE WE HAVE A NEW-ENOUGH "vulkan.h" HEADER:
+// err = vkDestroySemaphore(demo->device, presentCompleteSemaphore);
+ assert(!err);
err = vkQueueWaitIdle(demo->queue);
assert(err == VK_SUCCESS);
@@ -395,35 +449,121 @@ static void demo_draw(struct demo *demo)
static void demo_prepare_buffers(struct demo *demo)
{
+ VkResult U_ASSERT_ONLY err;
+
+ // Check the surface proprties and formats
+ size_t capsSize;
+ size_t presentModesSize;
+ err = demo->fpGetSurfaceInfoWSI(demo->device,
+ (const VkSurfaceDescriptionWSI *)&demo->surface_description,
+ VK_SURFACE_INFO_TYPE_PROPERTIES_WSI, &capsSize, NULL);
+ assert(!err);
+ err = demo->fpGetSurfaceInfoWSI(demo->device,
+ (const VkSurfaceDescriptionWSI *)&demo->surface_description,
+ VK_SURFACE_INFO_TYPE_PRESENT_MODES_WSI, &presentModesSize, NULL);
+ assert(!err);
+
+ VkSurfacePropertiesWSI *surfProperties =
+ (VkSurfacePropertiesWSI *)malloc(capsSize);
+ VkSurfacePresentModePropertiesWSI *presentModes =
+ (VkSurfacePresentModePropertiesWSI *)malloc(presentModesSize);
+
+ err = demo->fpGetSurfaceInfoWSI(demo->device,
+ (const VkSurfaceDescriptionWSI *)&demo->surface_description,
+ VK_SURFACE_INFO_TYPE_PROPERTIES_WSI, &capsSize, surfProperties);
+ assert(!err);
+ err = demo->fpGetSurfaceInfoWSI(demo->device,
+ (const VkSurfaceDescriptionWSI *)&demo->surface_description,
+ VK_SURFACE_INFO_TYPE_PRESENT_MODES_WSI, &presentModesSize, presentModes);
+ assert(!err);
+
+ VkExtent2D swapChainExtent;
+ // width and height are either both -1, or both not -1.
+ if (surfProperties->currentExtent.width == -1)
+ {
+ // If the surface size is undefined, the size is set to
+ // the size of the images requested.
+ swapChainExtent.width = demo->width;
+ swapChainExtent.height = demo->height;
+ }
+ else
+ {
+ // If the surface size is defined, the swap chain size must match
+ swapChainExtent = surfProperties->currentExtent;
+ }
+
+ // If mailbox mode is available, use it, as is the lowest-latency non-
+ // tearing mode. If not, fall back to IMMEDIATE which should always be
+ // available.
+ VkPresentModeWSI swapChainPresentMode = VK_PRESENT_MODE_IMMEDIATE_WSI;
+ size_t presentModeCount = presentModesSize / sizeof(VkSurfacePresentModePropertiesWSI);
+ for (size_t i = 0; i < presentModeCount; i++) {
+ if (presentModes[i].presentMode == VK_PRESENT_MODE_MAILBOX_WSI) {
+ swapChainPresentMode = VK_PRESENT_MODE_MAILBOX_WSI;
+ break;
+ }
+ }
+
+ // Determine the number of VkImage's to use in the swap chain (we desire to
+ // own only 1 image at a time, besides the images being displayed and
+ // queued for display):
+ uint32_t desiredNumberOfSwapChainImages = surfProperties->minImageCount + 1;
+ if ((surfProperties->maxImageCount > 0) &&
+ (desiredNumberOfSwapChainImages > surfProperties->maxImageCount))
+ {
+ // Application must settle for fewer images than desired:
+ desiredNumberOfSwapChainImages = surfProperties->maxImageCount;
+ }
+
+ VkSurfaceTransformFlagBitsWSI preTransform;
+ if (surfProperties->supportedTransforms & VK_SURFACE_TRANSFORM_NONE_BIT_WSI) {
+ preTransform = VK_SURFACE_TRANSFORM_NONE_WSI;
+ } else {
+ preTransform = surfProperties->currentTransform;
+ }
+
const VkSwapChainCreateInfoWSI swap_chain = {
.sType = VK_STRUCTURE_TYPE_SWAP_CHAIN_CREATE_INFO_WSI,
.pNext = NULL,
- .pNativeWindowSystemHandle = demo->connection,
- .pNativeWindowHandle = (void *) (intptr_t) demo->window,
- .displayCount = 1,
- .imageCount = DEMO_BUFFER_COUNT,
+ .pSurfaceDescription = (const VkSurfaceDescriptionWSI *)&demo->surface_description,
+ .minImageCount = desiredNumberOfSwapChainImages,
.imageFormat = demo->format,
.imageExtent = {
- .width = demo->width,
- .height = demo->height,
+ .width = swapChainExtent.width,
+ .height = swapChainExtent.height,
},
+ .preTransform = preTransform,
.imageArraySize = 1,
- .imageUsageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
+ .presentMode = swapChainPresentMode,
+ .oldSwapChain.handle = 0,
+ .clipped = true,
};
- VkSwapChainImageInfoWSI images[DEMO_BUFFER_COUNT];
- size_t images_size = sizeof(images);
- VkResult U_ASSERT_ONLY err;
uint32_t i;
err = demo->fpCreateSwapChainWSI(demo->device, &swap_chain, &demo->swap_chain);
assert(!err);
- err = demo->fpGetSwapChainInfoWSI(demo->swap_chain,
- VK_SWAP_CHAIN_INFO_TYPE_PERSISTENT_IMAGES_WSI,
- &images_size, images);
- assert(!err && images_size == sizeof(images));
+ size_t swapChainImagesSize;
+ err = demo->fpGetSwapChainInfoWSI(demo->device, demo->swap_chain,
+ VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI,
+ &swapChainImagesSize, NULL);
+ assert(!err);
- for (i = 0; i < DEMO_BUFFER_COUNT; i++) {
+ VkSwapChainImagePropertiesWSI* swapChainImages = (VkSwapChainImagePropertiesWSI*)malloc(swapChainImagesSize);
+ assert(swapChainImages);
+ err = demo->fpGetSwapChainInfoWSI(demo->device, demo->swap_chain,
+ VK_SWAP_CHAIN_INFO_TYPE_IMAGES_WSI,
+ &swapChainImagesSize, swapChainImages);
+ assert(!err);
+
+ // The number of images within the swap chain is determined based on the
+ // size of the info returned
+ demo->swapChainImageCount = swapChainImagesSize / sizeof(VkSwapChainImagePropertiesWSI);
+
+ demo->buffers = (SwapChainBuffers*)malloc(sizeof(SwapChainBuffers)*demo->swapChainImageCount);
+ assert(demo->buffers);
+
+ for (i = 0; i < demo->swapChainImageCount; i++) {
VkAttachmentViewCreateInfo color_attachment_view = {
.sType = VK_STRUCTURE_TYPE_ATTACHMENT_VIEW_CREATE_INFO,
.pNext = NULL,
@@ -433,8 +573,7 @@ static void demo_prepare_buffers(struct demo *demo)
.arraySize = 1,
};
- demo->buffers[i].image = images[i].image;
- demo->buffers[i].mem = images[i].memory;
+ demo->buffers[i].image = swapChainImages[i].image;
demo_set_image_layout(demo, demo->buffers[i].image,
VK_IMAGE_ASPECT_COLOR,
@@ -1341,12 +1480,12 @@ LRESULT CALLBACK WndProc(HWND hWnd,
switch(uMsg)
{
- case WM_CREATE:
+ case WM_CREATE:
return 0;
- case WM_CLOSE:
+ case WM_CLOSE:
PostQuitMessage(0);
return 0;
- case WM_PAINT:
+ case WM_PAINT:
demo_run(&demo);
return 0;
default:
@@ -1486,6 +1625,28 @@ static void demo_create_window(struct demo *demo)
}
#endif // _WIN32
+/*
+ * Return 1 (true) if all layer names specified in check_names
+ * can be found in given layer properties.
+ */
+static VkBool32 demo_check_layers(uint32_t check_count, char **check_names,
+ uint32_t layer_count, VkLayerProperties *layers)
+{
+ for (uint32_t i = 0; i < check_count; i++) {
+ VkBool32 found = 0;
+ for (uint32_t j = 0; j < layer_count; j++) {
+ if (!strcmp(check_names[i], layers[j].layerName)) {
+ found = 1;
+ }
+ }
+ if (!found) {
+ fprintf(stderr, "Cannot find layer: %s\n", check_names[i]);
+ return 0;
+ }
+ }
+ return 1;
+}
+
static void demo_init_vk(struct demo *demo)
{
VkResult err;
@@ -1499,28 +1660,34 @@ static void demo_init_vk(struct demo *demo)
uint32_t enabled_extension_count = 0;
uint32_t enabled_layer_count = 0;
+ char *instance_validation_layers[] = {
+ "MemTracker",
+ };
+
+ char *device_validation_layers[] = {
+ "MemTracker",
+ };
+
/* Look for validation layers */
VkBool32 validation_found = 0;
err = vkGetGlobalLayerProperties(&instance_layer_count, NULL);
assert(!err);
- memset(layer_names, 0, sizeof(layer_names));
instance_layers = malloc(sizeof(VkLayerProperties) * instance_layer_count);
err = vkGetGlobalLayerProperties(&instance_layer_count, instance_layers);
assert(!err);
- for (uint32_t i = 0; i < instance_layer_count; i++) {
- if (!validation_found && demo->validate && !strcmp("Validation", instance_layers[i].layerName)) {
- layer_names[enabled_layer_count++] = "Validation";
- validation_found = 1;
+
+ if (demo->validate) {
+ validation_found = demo_check_layers(ARRAY_SIZE(instance_validation_layers), instance_validation_layers,
+ instance_layer_count, instance_layers);
+ if (!validation_found) {
+ ERR_EXIT("vkGetGlobalLayerProperties failed to find"
+ "required validation layer.\n\n"
+ "Please look at the Getting Started guide for additional "
+ "information.\n",
+ "vkCreateInstance Failure");
}
- assert(enabled_layer_count < 64);
- }
- if (demo->validate && !validation_found) {
- ERR_EXIT("vkGetGlobalLayerProperties failed to find any "
- "\"Validation\" layers.\n\n"
- "Please look at the Getting Started guide for additional "
- "information.\n",
- "vkCreateInstance Failure");
+ enabled_layer_count = ARRAY_SIZE(instance_validation_layers);
}
err = vkGetGlobalExtensionProperties(NULL, &instance_extension_count, NULL);
@@ -1532,9 +1699,9 @@ static void demo_init_vk(struct demo *demo)
err = vkGetGlobalExtensionProperties(NULL, &instance_extension_count, instance_extensions);
assert(!err);
for (uint32_t i = 0; i < instance_extension_count; i++) {
- if (!strcmp(VK_WSI_LUNARG_EXTENSION_NAME, instance_extensions[i].extName)) {
+ if (!strcmp("VK_WSI_swapchain", instance_extensions[i].extName)) {
WSIextFound = 1;
- extension_names[enabled_extension_count++] = VK_WSI_LUNARG_EXTENSION_NAME;
+ extension_names[enabled_extension_count++] = "VK_WSI_swapchain";
}
if (!strcmp(DEBUG_REPORT_EXTENSION_NAME, instance_extensions[i].extName)) {
if (demo->validate) {
@@ -1545,7 +1712,7 @@ static void demo_init_vk(struct demo *demo)
}
if (!WSIextFound) {
ERR_EXIT("vkGetGlobalExtensionProperties failed to find the "
- "\"VK_WSI_LunarG\" extension.\n\nDo you have a compatible "
+ "\"VK_WSI_swapchain\" extension.\n\nDo you have a compatible "
"Vulkan installable client driver (ICD) installed?\nPlease "
"look at the Getting Started guide for additional "
"information.\n",
@@ -1574,7 +1741,6 @@ static void demo_init_vk(struct demo *demo)
.queueFamilyIndex = 0,
.queueCount = 1,
};
-
uint32_t gpu_count;
uint32_t i;
uint32_t queue_count;
@@ -1610,38 +1776,62 @@ static void demo_init_vk(struct demo *demo)
err = vkGetPhysicalDeviceLayerProperties(demo->gpu, &device_layer_count, NULL);
assert(!err);
- memset(layer_names, 0, sizeof(layer_names));
device_layers = malloc(sizeof(VkLayerProperties) * device_layer_count);
err = vkGetPhysicalDeviceLayerProperties(demo->gpu, &device_layer_count, device_layers);
assert(!err);
- for (uint32_t i = 0; i < device_layer_count; i++) {
- if (!validation_found && demo->validate &&
- !strcmp("Validation", device_layers[i].layerName)) {
- layer_names[enabled_layer_count++] = "Validation";
- validation_found = 1;
+
+ if (demo->validate) {
+ validation_found = demo_check_layers(ARRAY_SIZE(device_validation_layers), device_validation_layers,
+ device_layer_count, device_layers);
+ if (!validation_found) {
+ ERR_EXIT("vkGetPhysicalDeviceLayerProperties failed to find"
+ "a required validation layer.\n\n"
+ "Please look at the Getting Started guide for additional "
+ "information.\n",
+ "vkCreateDevice Failure");
}
- assert(enabled_layer_count < 64);
+ enabled_layer_count = ARRAY_SIZE(device_validation_layers);
}
- if (demo->validate && !validation_found) {
- ERR_EXIT("vkGetGlobalLayerProperties failed to find any "
- "\"Validation\" layers.\n\n"
- "Please look at the Getting Started guide for additional "
+
+ uint32_t device_extension_count = 0;
+ VkExtensionProperties *device_extensions = NULL;
+ err = vkGetPhysicalDeviceExtensionProperties(
+ demo->gpu, NULL, &device_extension_count, NULL);
+ assert(!err);
+
+ WSIextFound = 0;
+ enabled_extension_count = 0;
+ memset(extension_names, 0, sizeof(extension_names));
+ device_extensions = malloc(sizeof(VkExtensionProperties) * device_extension_count);
+ err = vkGetPhysicalDeviceExtensionProperties(
+ demo->gpu, NULL, &device_extension_count, device_extensions);
+ assert(!err);
+
+ for (uint32_t i = 0; i < device_extension_count; i++) {
+ if (!strcmp("VK_WSI_device_swapchain", device_extensions[i].extName)) {
+ WSIextFound = 1;
+ extension_names[enabled_extension_count++] = "VK_WSI_device_swapchain";
+ }
+ assert(enabled_extension_count < 64);
+ }
+ if (!WSIextFound) {
+ ERR_EXIT("vkGetPhysicalDeviceExtensionProperties failed to find the "
+ "\"VK_WSI_device_swapchain\" extension.\n\nDo you have a compatible "
+ "Vulkan installable client driver (ICD) installed?\nPlease "
+ "look at the Getting Started guide for additional "
"information.\n",
"vkCreateInstance Failure");
}
- /* Don't need any device extensions */
- /* TODO: WSI device extension will go here eventually */
-
VkDeviceCreateInfo device = {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.pNext = NULL,
.queueRecordCount = 1,
.pRequestedQueues = &queue,
.layerCount = enabled_layer_count,
- .ppEnabledLayerNames = (const char*const*) layer_names,
- .extensionCount = 0,
- .ppEnabledExtensionNames = NULL,
+ .ppEnabledLayerNames = (const char *const*) ((demo->validate) ? device_validation_layers : NULL),
+ .extensionCount = enabled_extension_count,
+ .ppEnabledExtensionNames = (const char *const*) extension_names,
.flags = 0,
};
@@ -1674,19 +1864,20 @@ static void demo_init_vk(struct demo *demo)
}
}
+
err = vkCreateDevice(demo->gpu, &device, &demo->device);
assert(!err);
- free(device_layers);
-
+ GET_INSTANCE_PROC_ADDR(demo->inst, GetPhysicalDeviceSurfaceSupportWSI);
+ GET_DEVICE_PROC_ADDR(demo->device, GetSurfaceInfoWSI);
GET_DEVICE_PROC_ADDR(demo->device, CreateSwapChainWSI);
GET_DEVICE_PROC_ADDR(demo->device, CreateSwapChainWSI);
GET_DEVICE_PROC_ADDR(demo->device, DestroySwapChainWSI);
GET_DEVICE_PROC_ADDR(demo->device, GetSwapChainInfoWSI);
+ GET_DEVICE_PROC_ADDR(demo->device, AcquireNextImageWSI);
GET_DEVICE_PROC_ADDR(demo->device, QueuePresentWSI);
err = vkGetPhysicalDeviceProperties(demo->gpu, &demo->gpu_props);
- assert(!err);
err = vkGetPhysicalDeviceQueueCount(demo->gpu, &queue_count);
assert(!err);
@@ -1699,19 +1890,106 @@ static void demo_init_vk(struct demo *demo)
// Graphics queue and MemMgr queue can be separate.
// TODO: Add support for separate queues, including synchronization,
// and appropriate tracking for QueueSubmit
+
+ // Construct the WSI surface description:
+ demo->surface_description.sType = VK_STRUCTURE_TYPE_SURFACE_DESCRIPTION_WINDOW_WSI;
+ demo->surface_description.pNext = NULL;
+#ifdef _WIN32
+ demo->surface_description.platform = VK_PLATFORM_WIN32_WSI;
+ demo->surface_description.pPlatformHandle = demo->connection;
+ demo->surface_description.pPlatformWindow = demo->window;
+#else // _WIN32
+ demo->platform_handle_xcb.connection = demo->connection;
+ demo->platform_handle_xcb.root = demo->screen->root;
+ demo->surface_description.platform = VK_PLATFORM_XCB_WSI;
+ demo->surface_description.pPlatformHandle = &demo->platform_handle_xcb;
+ demo->surface_description.pPlatformWindow = &demo->window;
+#endif // _WIN32
+
+ // Iterate over each queue to learn whether it supports presenting to WSI:
+ VkBool32* supportsPresent = (VkBool32 *)malloc(queue_count * sizeof(VkBool32));
for (i = 0; i < queue_count; i++) {
- if (demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
- break;
+ demo->fpGetPhysicalDeviceSurfaceSupportWSI(demo->gpu, i,
+ (VkSurfaceDescriptionWSI *) &demo->surface_description,
+ &supportsPresent[i]);
+ }
+
+ // Search for a graphics and a present queue in the array of queue
+ // families, try to find one that supports both
+ uint32_t graphicsQueueNodeIndex = UINT32_MAX;
+ uint32_t presentQueueNodeIndex = UINT32_MAX;
+ for (i = 0; i < queue_count; i++) {
+ if ((demo->queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) != 0) {
+ if (graphicsQueueNodeIndex == UINT32_MAX) {
+ graphicsQueueNodeIndex = i;
+ }
+
+ if (supportsPresent[i] == VK_TRUE) {
+ graphicsQueueNodeIndex = i;
+ presentQueueNodeIndex = i;
+ break;
+ }
+ }
+ }
+ if (presentQueueNodeIndex == UINT32_MAX) {
+ // If didn't find a queue that supports both graphics and present, then
+ // find a separate present queue.
+ for (size_t i = 0; i < queue_count; ++i) {
+ if (supportsPresent[i] == VK_TRUE) {
+ presentQueueNodeIndex = i;
+ break;
+ }
+ }
+ }
+ free(supportsPresent);
+
+ // Generate error if could not find both a graphics and a present queue
+ if (graphicsQueueNodeIndex == UINT32_MAX || presentQueueNodeIndex == UINT32_MAX) {
+ ERR_EXIT("Could not find a graphics and a present queue\n",
+ "WSI Initialization Failure");
+ }
+
+ // TODO: Add support for separate queues, including presentation,
+ // synchronization, and appropriate tracking for QueueSubmit
+ // While it is possible for an application to use a separate graphics and a
+ // present queues, this demo program assumes it is only using one:
+ if (graphicsQueueNodeIndex != presentQueueNodeIndex) {
+ ERR_EXIT("Could not find a common graphics and a present queue\n",
+ "WSI Initialization Failure");
}
- assert(i < queue_count);
- demo->graphics_queue_node_index = i;
+
+ demo->graphics_queue_node_index = graphicsQueueNodeIndex;
err = vkGetDeviceQueue(demo->device, demo->graphics_queue_node_index,
0, &demo->queue);
assert(!err);
- // for now hardcode format till get WSI support
- demo->format = VK_FORMAT_B8G8R8A8_UNORM;
+ // Get the list of VkFormat's that are supported:
+ size_t formatsSize;
+ err = demo->fpGetSurfaceInfoWSI(demo->device,
+ (VkSurfaceDescriptionWSI *) &demo->surface_description,
+ VK_SURFACE_INFO_TYPE_FORMATS_WSI,
+ &formatsSize, NULL);
+ assert(!err);
+ VkSurfaceFormatPropertiesWSI *surfFormats = (VkSurfaceFormatPropertiesWSI *)malloc(formatsSize);
+ err = demo->fpGetSurfaceInfoWSI(demo->device,
+ (VkSurfaceDescriptionWSI *) &demo->surface_description,
+ VK_SURFACE_INFO_TYPE_FORMATS_WSI,
+ &formatsSize, surfFormats);
+ assert(!err);
+ // If the format list includes just one entry of VK_FORMAT_UNDEFINED,
+ // the surface has no preferred format. Otherwise, at least one
+ // supported format will be returned.
+ size_t formatCount = formatsSize / sizeof(VkSurfaceFormatPropertiesWSI);
+ if (formatCount == 1 && surfFormats[0].format == VK_FORMAT_UNDEFINED)
+ {
+ demo->format = VK_FORMAT_B8G8R8A8_UNORM;
+ }
+ else
+ {
+ assert(formatCount >= 1);
+ demo->format = surfFormats[0].format;
+ }
// Get Memory information and properties
err = vkGetPhysicalDeviceMemoryProperties(demo->gpu, &demo->memory_properties);
@@ -1828,7 +2106,8 @@ static void demo_cleanup(struct demo *demo)
vkDestroyImage(demo->device, demo->depth.image);
vkFreeMemory(demo->device, demo->depth.mem);
- demo->fpDestroySwapChainWSI(demo->swap_chain);
+ demo->fpDestroySwapChainWSI(demo->device, demo->swap_chain);
+ free(demo->buffers);
vkDestroyDevice(demo->device);
vkDestroyInstance(demo->inst);
diff --git a/demos/vulkaninfo.c b/demos/vulkaninfo.c
index b05d632f..b6a66faa 100644
--- a/demos/vulkaninfo.c
+++ b/demos/vulkaninfo.c
@@ -33,6 +33,9 @@
#include <io.h>
#endif
+#include "vk_wsi_swapchain.h"
+#include "vk_wsi_device_swapchain.h"
+
#include <vulkan.h>
#define ERR(err) printf("%s:%d: failed with %s\n", \
@@ -424,8 +427,7 @@ static void app_dev_init(struct app_dev *dev, struct app_gpu *gpu)
VkResult U_ASSERT_ONLY err;
// Extensions to enable
static const char *known_extensions[] = {
- //TODO add WSI device extension WSI swapchain, WSI_LUNARG is a global extension
- ""
+ VK_WSI_DEVICE_SWAPCHAIN_EXTENSION_NAME,
};
uint32_t count = 0;
@@ -568,7 +570,7 @@ static void app_create_instance(struct app_instance *inst)
VkResult U_ASSERT_ONLY err;
// Global Extensions to enable
static char *known_extensions[] = {
- "VK_WSI_LunarG",
+ "VK_WSI_swapchain",
};
uint32_t global_extension_count = 0;