Skip to content

Instantly share code, notes, and snippets.

@paroj
Created September 8, 2021 14:56
Show Gist options
  • Save paroj/4afe6e771d9fc4af83f537d675c0287d to your computer and use it in GitHub Desktop.
Save paroj/4afe6e771d9fc4af83f537d675c0287d to your computer and use it in GitHub Desktop.
minimal vulkan.hpp with SDL2
#include <SDL2/SDL.h>
#include <SDL2/SDL_vulkan.h>
#include <vulkan/vulkan.hpp>
#include <algorithm>
VkBool32 debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData)
{
auto types = vk::to_string((vk::DebugUtilsMessageTypeFlagsEXT)messageTypes);
auto severity = vk::to_string((vk::DebugUtilsMessageSeverityFlagBitsEXT)messageSeverity);
printf("%s%s: %s\n", severity.c_str(), types.c_str(), pCallbackData->pMessage);
return VK_FALSE;
}
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO);
auto wpos = SDL_WINDOWPOS_CENTERED;
auto win = SDL_CreateWindow("vulkantest", wpos, wpos, 800, 600, SDL_WINDOW_VULKAN);
vk::InstanceCreateInfo createInfo;
SDL_Vulkan_GetInstanceExtensions(win, &createInfo.enabledExtensionCount, nullptr);
std::vector<const char*> extensions(createInfo.enabledExtensionCount);
SDL_Vulkan_GetInstanceExtensions(win, &createInfo.enabledExtensionCount, extensions.data());
extensions.push_back("VK_EXT_debug_utils");
extensions.push_back("VK_EXT_debug_report");
createInfo.enabledExtensionCount = extensions.size();
createInfo.ppEnabledExtensionNames = extensions.data();
createInfo.enabledLayerCount = 1;
const char* validationLayers[] = {"VK_LAYER_KHRONOS_validation"};
createInfo.ppEnabledLayerNames = validationLayers;
#if 0
printf("requested extensions\n");
for(auto e : extensions)
printf("\t%s\n", e);
printf("available layers\n");
auto instanceLayers = vk::enumerateInstanceLayerProperties();
for(auto l : instanceLayers)
printf("\t%s\n", l.layerName);
printf("available extensions\n");
auto exts = vk::enumerateInstanceExtensionProperties();
for(auto e : exts)
printf("\t%s\n", e.extensionName);
#endif
vk::DebugUtilsMessengerCreateInfoEXT messengerInfo(
{},
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError,
vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance |
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation,
debug_callback);
createInfo.pNext = &messengerInfo;
VkSurfaceKHR surface;
auto instance = vk::createInstanceUnique(createInfo);
{ // dummy scope for auto memory management
vk::DispatchLoaderDynamic loader(*instance, vk::Device());
auto debugUtilsMessenger =
instance->createDebugUtilsMessengerEXTUnique(messengerInfo, nullptr, loader);
auto pdevice = instance->enumeratePhysicalDevices().front();
auto properties = pdevice.getProperties();
auto qproperties = pdevice.getQueueFamilyProperties();
printf("device: %s | %s\n", properties.deviceName, vk::to_string(properties.deviceType).c_str());
// find device graphics queue
uint32_t graphicsQidx = std::distance(
qproperties.begin(),
std::find_if(qproperties.begin(), qproperties.end(), [](const vk::QueueFamilyProperties& fp) {
return fp.queueFlags & vk::QueueFlagBits::eGraphics;
}));
// create logical device
float queuePriority = 1.0f;
vk::DeviceQueueCreateInfo deviceQInfo({}, graphicsQidx, 1, &queuePriority);
vk::DeviceCreateInfo deviceInfo({}, 1, &deviceQInfo);
deviceInfo.enabledExtensionCount = 1;
const char* dextensions[] = {"VK_KHR_swapchain"};
deviceInfo.ppEnabledExtensionNames = dextensions;
auto device = pdevice.createDeviceUnique(deviceInfo);
auto graphicsQueue = device->getQueue(graphicsQidx, 0);
SDL_Vulkan_CreateSurface(win, VkInstance(*instance), &surface);
uint32_t presentQidx = -1;
if (pdevice.getSurfaceSupportKHR(graphicsQidx, surface))
presentQidx = graphicsQidx;
if(presentQidx != graphicsQidx)
{
printf("different queues are not handled!\n");
return -1;
}
#if 0
auto formats = pdevice.getSurfaceFormatsKHR(surface);
for(auto f : formats)
printf("\t%s - %s\n", vk::to_string(f.format).c_str(), vk::to_string(f.colorSpace).c_str());
#endif
// create swapchain
auto surfaceCaps = pdevice.getSurfaceCapabilitiesKHR(surface);
vk::Extent2D swapchainExtent;
SDL_Vulkan_GetDrawableSize(win, (int*)&swapchainExtent.width, (int*)&swapchainExtent.height);
printf("%d x %d\n", swapchainExtent.width, swapchainExtent.height);
vk::SwapchainCreateInfoKHR swapChainInfo({}, surface, surfaceCaps.minImageCount,
vk::Format::eB8G8R8A8Srgb);
swapChainInfo.imageExtent = swapchainExtent;
swapChainInfo.presentMode = vk::PresentModeKHR::eFifo;
swapChainInfo.imageArrayLayers = 1;
swapChainInfo.imageUsage =
vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferDst;
swapChainInfo.imageSharingMode = vk::SharingMode::eExclusive;
swapChainInfo.preTransform = vk::SurfaceTransformFlagBitsKHR::eIdentity;
auto swapChain = device->createSwapchainKHRUnique(swapChainInfo);
auto images = device->getSwapchainImagesKHR(*swapChain);
// create command buffer
auto commandPool = device->createCommandPoolUnique({{}, graphicsQidx});
auto commandBuffers = device->allocateCommandBuffersUnique(
{commandPool.get(), vk::CommandBufferLevel::ePrimary, uint32_t(images.size())});
vk::CommandBufferBeginInfo cmdInfo(vk::CommandBufferUsageFlagBits::eSimultaneousUse);
vk::ClearColorValue clearCol(std::array<float, 4>{1, 0, 0, 0});
vk::ImageSubresourceRange imgRange(vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1);
vk::ImageMemoryBarrier imgBarrier;
imgBarrier.subresourceRange = imgRange;
for (size_t i = 0; i < commandBuffers.size(); i++)
{
auto& cb = commandBuffers[i];
cb->begin(cmdInfo);
// transition to General layout
imgBarrier.image = images[i];
imgBarrier.oldLayout = vk::ImageLayout::eUndefined; // i.e. discard contents
imgBarrier.newLayout = vk::ImageLayout::eGeneral;
cb->pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer,
vk::DependencyFlags(), 0, nullptr, 0, nullptr, 1, &imgBarrier);
cb->clearColorImage(images[i], vk::ImageLayout::eGeneral, &clearCol, 1, &imgRange);
// transition to present layout
imgBarrier.oldLayout = vk::ImageLayout::eGeneral;
imgBarrier.newLayout = vk::ImageLayout::ePresentSrcKHR;
cb->pipelineBarrier(vk::PipelineStageFlagBits::eTransfer,
vk::PipelineStageFlagBits::eBottomOfPipe, vk::DependencyFlags(), 0, nullptr,
0, nullptr, 1, &imgBarrier);
cb->end();
}
auto imgSemaphore = device->createSemaphoreUnique({});
vk::PipelineStageFlags waitStages[] = {vk::PipelineStageFlagBits::eColorAttachmentOutput};
// render loop
for (int i = 0; i < 30; i++)
{
auto imgIdx = device->acquireNextImageKHR(*swapChain, -1, *imgSemaphore, vk::Fence());
vk::SubmitInfo submit;
submit.waitSemaphoreCount = 1;
submit.pWaitSemaphores = &imgSemaphore.get();
submit.commandBufferCount = 1;
submit.pCommandBuffers = &commandBuffers[imgIdx.value].get();
submit.pWaitDstStageMask = waitStages;
graphicsQueue.submit(1, &submit, vk::Fence());
vk::PresentInfoKHR present;
present.swapchainCount = 1;
present.pSwapchains = &swapChain.get();
present.pImageIndices = &imgIdx.value;
graphicsQueue.presentKHR(present);
}
device->waitIdle();
}
instance->destroySurfaceKHR(surface);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment