#include #include #include #include #include #include #include #define W 1260 #define H 720 #define CK(x) do { VkResult _r = (x); if (_r != VK_SUCCESS) { \ fprintf(stderr, "FAIL %s -> %d\n", #x, _r); exit(1); } } while (0) int main() { Display *dpy = XOpenDisplay( NULL ); if (!dpy) { fprintf( stderr, "no display\n" ); return 1; } Window win = XCreateSimpleWindow( dpy, DefaultRootWindow( dpy ), 10, 10, W, H, 0, 0, 0 ); XStoreName( dpy, win, "vktest" ); XMapWindow( dpy, win ); XFlush( dpy ); const char *iexts[] = { "VK_KHR_surface", "VK_KHR_xlib_surface" }; VkApplicationInfo ai = { VK_STRUCTURE_TYPE_APPLICATION_INFO }; ai.apiVersion = VK_API_VERSION_1_1; VkInstanceCreateInfo ici = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; ici.pApplicationInfo = &ai; ici.enabledExtensionCount = 2; ici.ppEnabledExtensionNames = iexts; VkInstance inst; CK( vkCreateInstance(&ici, NULL, &inst )); uint32_t n = 1; VkPhysicalDevice phys; vkEnumeratePhysicalDevices( inst, &n, &phys ); VkSurfaceKHR surf; VkXlibSurfaceCreateInfoKHR sci = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR }; sci.dpy = dpy; sci.window = win; CK( vkCreateXlibSurfaceKHR( inst, &sci, NULL, &surf ) ); uint32_t nfam = 0; vkGetPhysicalDeviceQueueFamilyProperties( phys, &nfam, NULL ); VkQueueFamilyProperties fam[8]; if( nfam > 8 ) nfam = 8; vkGetPhysicalDeviceQueueFamilyProperties( phys, &nfam, fam ); uint32_t qf = UINT32_MAX; for( uint32_t i = 0; i < nfam; i++ ) { VkBool32 pres = VK_FALSE; vkGetPhysicalDeviceSurfaceSupportKHR( phys, i, surf, &pres ); if( (fam[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && pres ) { qf = i; break; } } if( qf == UINT32_MAX ) { fprintf( stderr, "no queue\n" ); return 1; } float prio = 1.0f; VkDeviceQueueCreateInfo qci = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO }; qci.queueFamilyIndex = qf; qci.queueCount = 1; qci.pQueuePriorities = &prio; const char *dexts[] = { "VK_KHR_swapchain" }; VkDeviceCreateInfo dci = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO }; dci.queueCreateInfoCount = 1; dci.pQueueCreateInfos = &qci; dci.enabledExtensionCount = 1; dci.ppEnabledExtensionNames = dexts; VkDevice dev; CK( vkCreateDevice( phys, &dci, NULL, &dev ) ); VkQueue q; vkGetDeviceQueue( dev, qf, 0, &q ); VkSurfaceFormatKHR fmts[16]; uint32_t nfmt = 16; vkGetPhysicalDeviceSurfaceFormatsKHR( phys, surf, &nfmt, fmts ); VkSurfaceCapabilitiesKHR caps; vkGetPhysicalDeviceSurfaceCapabilitiesKHR( phys, surf, &caps ); VkSwapchainCreateInfoKHR scci = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR }; scci.surface = surf; scci.minImageCount = caps.minImageCount; scci.imageFormat = fmts[0].format; scci.imageColorSpace = fmts[0].colorSpace; scci.imageExtent.width = W; scci.imageExtent.height = H; scci.imageArrayLayers = 1; scci.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; scci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; scci.preTransform = caps.currentTransform; scci.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; scci.presentMode = VK_PRESENT_MODE_FIFO_KHR; scci.clipped = VK_TRUE; VkSwapchainKHR sc; CK( vkCreateSwapchainKHR( dev, &scci, NULL, &sc ) ); printf( "swapchain format: %d\n", fmts[0].format ); uint32_t nimg = 8; VkImage imgs[8]; vkGetSwapchainImagesKHR( dev, sc, &nimg, imgs ); VkCommandPoolCreateInfo cpci = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO }; cpci.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; cpci.queueFamilyIndex = qf; VkCommandPool pool; CK( vkCreateCommandPool( dev, &cpci, NULL, &pool )); VkCommandBufferAllocateInfo cbai = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO }; cbai.commandPool = pool; cbai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; cbai.commandBufferCount = 1; VkCommandBuffer cb; CK( vkAllocateCommandBuffers( dev, &cbai, &cb ) ); VkSemaphoreCreateInfo semci = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; VkSemaphore acq, ren; CK( vkCreateSemaphore( dev, &semci, NULL, &acq ) ); CK( vkCreateSemaphore( dev, &semci, NULL, &ren ) ); VkFenceCreateInfo fci = { VK_STRUCTURE_TYPE_FENCE_CREATE_INFO }; VkFence fence; CK( vkCreateFence(dev, &fci, NULL, &fence )); VkBufferCreateInfo bci = { VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO }; bci.size = (VkDeviceSize)W * H * 4; bci.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; VkBuffer rb; CK( vkCreateBuffer( dev, &bci, NULL, &rb ) ); VkMemoryRequirements mr; vkGetBufferMemoryRequirements( dev, rb, &mr ); VkPhysicalDeviceMemoryProperties mp; vkGetPhysicalDeviceMemoryProperties( phys, &mp ); uint32_t type = 0; for( uint32_t i = 0; i < mp.memoryTypeCount; i++ ) { if( (mr.memoryTypeBits & (1u << i)) && (mp.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) ) { type = i; break; } } VkMemoryAllocateInfo mai = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; mai.allocationSize = mr.size; mai.memoryTypeIndex = type; VkDeviceMemory rmem; CK( vkAllocateMemory(dev, &mai, NULL, &rmem ) ); CK( vkBindBufferMemory(dev, rb, rmem, 0 ) ); VkImageSubresourceRange range; memset( &range, 0, sizeof( range )); range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; range.levelCount = 1; range.layerCount = 1; for( ;; ) { uint32_t idx; CK( vkAcquireNextImageKHR(dev, sc, UINT64_MAX, acq, VK_NULL_HANDLE, &idx ) ); VkCommandBufferBeginInfo bi = { VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; CK( vkBeginCommandBuffer( cb, &bi ) ); VkImageMemoryBarrier b = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; b.srcAccessMask = 0; b.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; b.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; b.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; b.srcQueueFamilyIndex = b.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; b.image = imgs[idx]; b.subresourceRange = range; vkCmdPipelineBarrier( cb, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, &b ); VkClearColorValue col = { { 0.05f, 0.10f, 0.20f, 1.0f } }; vkCmdClearColorImage( cb, imgs[idx], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &col, 1, &range ); b.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; b.dstAccessMask = 0; b.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; b.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; vkCmdPipelineBarrier( cb, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, NULL, 0, NULL, 1, &b ); CK( vkEndCommandBuffer( cb ) ); VkPipelineStageFlags wait = VK_PIPELINE_STAGE_TRANSFER_BIT; VkSubmitInfo si = { VK_STRUCTURE_TYPE_SUBMIT_INFO }; si.waitSemaphoreCount = 1; si.pWaitSemaphores = &acq; si.pWaitDstStageMask = &wait; si.commandBufferCount = 1; si.pCommandBuffers = &cb; si.signalSemaphoreCount = 1; si.pSignalSemaphores = &ren; CK( vkQueueSubmit(q, 1, &si, VK_NULL_HANDLE ) ); VkPresentInfoKHR pi = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR }; pi.waitSemaphoreCount = 1; pi.pWaitSemaphores = &ren; pi.swapchainCount = 1; pi.pSwapchains = ≻ pi.pImageIndices = &idx; CK( vkQueuePresentKHR( q, &pi ) ); vkQueueWaitIdle( q ); usleep( 1 ); } return 0; }