Skip to content

Instantly share code, notes, and snippets.

@TheBuzzSaw
Created February 22, 2016 07:08
Show Gist options
  • Save TheBuzzSaw/9f54493b83b27fe36818 to your computer and use it in GitHub Desktop.
Save TheBuzzSaw/9f54493b83b27fe36818 to your computer and use it in GitHub Desktop.
WIP -- SDL2 + Vulkan sample program
#include <SDL.h>
#include <SDL_syswm.h>
#define VK_USE_PLATFORM_WIN32_KHR
#include <vulkan/vulkan.h>
#include <iostream>
#include <cassert>
using namespace std;
#define ArraySize(a) (sizeof(a)/sizeof(*a))
void SetImageLayout(
VkCommandBuffer commandBuffer,
VkImage image,
VkImageAspectFlags aspectMask,
VkImageLayout oldLayout,
VkImageLayout newLayout)
{
VkImageMemoryBarrier imb = {};
imb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
imb.pNext = nullptr;
imb.srcAccessMask = 0;
imb.dstAccessMask = 0;
imb.oldLayout = oldLayout;
imb.newLayout = newLayout;
imb.image = image;
imb.subresourceRange.aspectMask = aspectMask;
imb.subresourceRange.baseMipLevel = 0;
imb.subresourceRange.levelCount = 1;
imb.subresourceRange.layerCount = 1;
if (oldLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
imb.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
if (newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
imb.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
if (newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
{
imb.srcAccessMask =
VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
imb.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
}
if (newLayout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
imb.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
if (newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
imb.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
0,
0,
nullptr,
0,
nullptr,
1,
&imb);
}
int main(int argc, char** argv)
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window* window = SDL_CreateWindow(
"SDL Vulkan",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
1024,
768,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
const char* instanceExtensionNames[] = {
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_WIN32_SURFACE_EXTENSION_NAME
};
VkApplicationInfo ai = {};
ai.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
ai.pNext = nullptr;
ai.pApplicationName = "SDL Vulkan";
ai.applicationVersion = 1;
ai.pEngineName = "SDLV";
ai.engineVersion = 1;
ai.apiVersion = VK_API_VERSION;
VkInstanceCreateInfo ici = {};
ici.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
ici.pNext = nullptr;
ici.flags = 0;
ici.pApplicationInfo = &ai;
ici.enabledLayerCount = 0;
ici.ppEnabledLayerNames = nullptr;
ici.enabledExtensionCount = 0;
ici.ppEnabledExtensionNames = nullptr;
VkInstance instance;
assert(vkCreateInstance(&ici, nullptr, &instance) == VK_SUCCESS);
VkPhysicalDevice physicalDevices[8];
uint32_t physicalDeviceCount = ArraySize(physicalDevices);
assert(
vkEnumeratePhysicalDevices(
instance,
&physicalDeviceCount,
physicalDevices)
== VK_SUCCESS);
cout << physicalDeviceCount << " physical device";
if (physicalDeviceCount != 1) cout << 's';
cout << '\n';
assert(physicalDeviceCount > 0);
VkQueueFamilyProperties queueFamilyProperties[8];
uint32_t queueFamilyPropertiesCount = ArraySize(queueFamilyProperties);
vkGetPhysicalDeviceQueueFamilyProperties(
physicalDevices[0],
&queueFamilyPropertiesCount,
queueFamilyProperties);
cout << queueFamilyPropertiesCount << " queue family property set";
if (queueFamilyPropertiesCount != 1) cout << 's';
cout << '\n';
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
assert(SDL_GetWindowWMInfo(window, &info) == SDL_TRUE);
VkWin32SurfaceCreateInfoKHR w32sci = {};
w32sci.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
w32sci.pNext = NULL;
w32sci.hinstance = GetModuleHandle(NULL);
w32sci.hwnd = info.info.win.window;
VkSurfaceKHR surface;
assert(
vkCreateWin32SurfaceKHR(
instance,
&w32sci,
nullptr,
&surface)
== VK_SUCCESS);
VkBool32 supportsPresent[8];
for (uint32_t i = 0; i < queueFamilyPropertiesCount; ++i)
{
vkGetPhysicalDeviceSurfaceSupportKHR(
physicalDevices[i],
i,
surface,
supportsPresent + i);
}
bool foundQueue = false;
uint32_t queueIndex;
for (uint32_t i = 0; i < queueFamilyPropertiesCount; ++i)
{
if ((queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) &&
supportsPresent[i] == VK_TRUE)
{
foundQueue = true;
queueIndex = i;
}
}
assert(foundQueue);
cout << "queue index " << queueIndex << '\n';
VkSurfaceFormatKHR formats[8];
uint32_t formatCount = ArraySize(formats);
assert(
vkGetPhysicalDeviceSurfaceFormatsKHR(
physicalDevices[0],
surface,
&formatCount,
formats)
== VK_SUCCESS);
cout << formatCount << " format";
if (formatCount != 1) cout << 's';
cout << '\n';
assert(formatCount > 0);
VkFormat format = formats[0].format;
if (formatCount == 1 && formats[0].format == VK_FORMAT_UNDEFINED)
format = VK_FORMAT_B8G8R8A8_UNORM;
float queuePriority = 0.0f;
VkDeviceQueueCreateInfo dqci = {};
dqci.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
dqci.pNext = nullptr;
dqci.queueCount = 1;
dqci.pQueuePriorities = &queuePriority;
dqci.queueFamilyIndex = queueIndex;
const char* deviceExtensionNames[] = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
VkDeviceCreateInfo dci = {};
dci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
dci.pNext = nullptr;
dci.queueCreateInfoCount = 1;
dci.pQueueCreateInfos = &dqci;
dci.enabledExtensionCount = ArraySize(deviceExtensionNames);
dci.ppEnabledExtensionNames = deviceExtensionNames;
VkDevice device;
assert(
vkCreateDevice(physicalDevices[0], &dci, nullptr, &device) ==
VK_SUCCESS);
VkCommandPoolCreateInfo cpci = {};
cpci.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
cpci.pNext = nullptr;
cpci.queueFamilyIndex = queueIndex;
cpci.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
VkCommandPool commandPool;
assert(
vkCreateCommandPool(device, &cpci, nullptr, &commandPool) ==
VK_SUCCESS);
VkCommandBufferAllocateInfo cbai = {};
cbai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
cbai.pNext = nullptr;
cbai.commandPool = commandPool;
cbai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
cbai.commandBufferCount = 1;
VkCommandBuffer commandBuffer;
assert(
vkAllocateCommandBuffers(device, &cbai, &commandBuffer) == VK_SUCCESS);
VkCommandBufferBeginInfo cbbi = {};
cbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
cbbi.pNext = nullptr;
cbbi.flags = 0;
cbbi.pInheritanceInfo = nullptr;
assert(vkBeginCommandBuffer(commandBuffer, &cbbi) == VK_SUCCESS);
VkQueue queue;
vkGetDeviceQueue(device, queueIndex, 0, &queue);
VkSurfaceCapabilitiesKHR surfaceCapabilities;
assert(
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
physicalDevices[0],
surface,
&surfaceCapabilities)
== VK_SUCCESS);
VkPresentModeKHR presentModes[8];
uint32_t presentModeCount = ArraySize(presentModes);
assert(
vkGetPhysicalDeviceSurfacePresentModesKHR(
physicalDevices[0],
surface,
&presentModeCount,
presentModes) == VK_SUCCESS);
cout << presentModeCount << " present mode";
if (presentModeCount != 1) cout << 's';
cout << '\n';
VkExtent2D swapChainExtent = surfaceCapabilities.currentExtent;
if (swapChainExtent.width == ~uint32_t(0))
{
cout << "surface size undefined\n";
int w;
int h;
SDL_GetWindowSize(window, &w, &h);
swapChainExtent.width = w;
swapChainExtent.height = h;
}
cout << swapChainExtent.width << "x" << swapChainExtent.height << '\n';
VkPresentModeKHR swapChainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
for (uint32_t i = 0; i < presentModeCount; ++i)
{
if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
{
swapChainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
break;
}
if (swapChainPresentMode != VK_PRESENT_MODE_MAILBOX_KHR &&
presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)
{
swapChainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
}
}
uint32_t desiredSwapChainImageCount = surfaceCapabilities.minImageCount + 1;
if (surfaceCapabilities.maxImageCount > 0 &&
desiredSwapChainImageCount > surfaceCapabilities.maxImageCount)
{
desiredSwapChainImageCount = surfaceCapabilities.maxImageCount;
}
VkSurfaceTransformFlagBitsKHR preTransform =
surfaceCapabilities.currentTransform;
if (surfaceCapabilities.supportedTransforms &
VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
{
preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
}
VkSwapchainCreateInfoKHR scci = {};
scci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
scci.pNext = nullptr;
scci.surface = surface;
scci.minImageCount = desiredSwapChainImageCount;
scci.imageFormat = format;
scci.imageExtent = swapChainExtent;
scci.preTransform = preTransform;
scci.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
scci.imageArrayLayers = 1;
scci.presentMode = swapChainPresentMode;
scci.oldSwapchain = VK_NULL_HANDLE;
scci.clipped = VK_TRUE;
scci.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
scci.imageUsage =
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT;
scci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
scci.queueFamilyIndexCount = 0;
scci.pQueueFamilyIndices = nullptr;
VkSwapchainKHR swapChain;
assert(
vkCreateSwapchainKHR(device, &scci, nullptr, &swapChain) == VK_SUCCESS);
VkImage swapChainImages[8];
uint32_t swapChainImageCount = ArraySize(swapChainImages);
assert(
vkGetSwapchainImagesKHR(
device,
swapChain,
&swapChainImageCount,
swapChainImages)
== VK_SUCCESS);
cout << swapChainImageCount << " swap chain image";
if (swapChainImageCount != 1) cout << 's';
cout << '\n';
struct { VkImage image; VkImageView view; } swapChainBuffers[8];
for (uint32_t i = 0; i < swapChainImageCount; ++i)
{
VkImageViewCreateInfo ivci = {};
ivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
ivci.pNext = nullptr;
ivci.format = format;
ivci.components.r = VK_COMPONENT_SWIZZLE_R;
ivci.components.g = VK_COMPONENT_SWIZZLE_G;
ivci.components.b = VK_COMPONENT_SWIZZLE_B;
ivci.components.a = VK_COMPONENT_SWIZZLE_A;
ivci.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
ivci.subresourceRange.baseMipLevel = 0;
ivci.subresourceRange.levelCount = 1;
ivci.subresourceRange.baseArrayLayer = 0;
ivci.subresourceRange.layerCount = 1;
ivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
ivci.flags = 0;
swapChainBuffers[i].image = swapChainImages[i];
SetImageLayout(
commandBuffer,
swapChainBuffers[i].image,
VK_IMAGE_ASPECT_COLOR_BIT,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
ivci.image = swapChainBuffers[i].image;
assert(
vkCreateImageView(
device,
&ivci,
nullptr,
&swapChainBuffers[i].view)
== VK_SUCCESS);
}
struct
{
VkFormat format;
VkImage image;
VkDeviceMemory memory;
VkImageView view;
} depth;
depth.format = VK_FORMAT_D16_UNORM;
VkFormatProperties formatProperties;
vkGetPhysicalDeviceFormatProperties(
physicalDevices[0],
VK_FORMAT_D16_UNORM,
&formatProperties);
VkImageCreateInfo ici2 = {};
if (formatProperties.linearTilingFeatures &
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
{
ici2.tiling = VK_IMAGE_TILING_LINEAR;
}
else if (formatProperties.optimalTilingFeatures &
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
{
ici2.tiling = VK_IMAGE_TILING_OPTIMAL;
}
else
{
assert(false);
}
// util_init.cpp line 605
/// /// /// Display Window /// /// ///
bool running = true;
while (running)
{
SDL_Event event;
while (SDL_PollEvent(&event))
{
if (event.type == SDL_KEYDOWN) running = false;
if (event.type == SDL_QUIT) running = false;
}
SDL_Delay(1);
}
vkDestroyInstance(instance, nullptr);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
@cappah
Copy link

cappah commented May 28, 2016

Does this actually work? I keep getting thrown exceptions for vulkan-1.dll

@TheBuzzSaw
Copy link
Author

@cappah Oh I never saw this comment. I'm sure you've moved on by now, but no, at the time, this was not a working sample. I was unrolling another tutorial. However, it did build and run. It properly enumerated Vulkan devices and whatnot. I didn't have any lib problems.

@baryluk
Copy link

baryluk commented Dec 1, 2018

It would be nice if this example is not Windows specific.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment