nuclear@3: #include nuclear@3: #include nuclear@3: #include nuclear@4: #include nuclear@3: #include "vku.h" nuclear@3: nuclear@3: static const char *get_device_name(VkPhysicalDeviceType type); nuclear@3: static const char *get_mem_prop_flag_string(VkMemoryPropertyFlags flags); nuclear@3: static const char *get_queue_flag_string(VkQueueFlagBits flags); nuclear@3: static int ver_major(uint32_t ver); nuclear@3: static int ver_minor(uint32_t ver); nuclear@3: static int ver_patch(uint32_t ver); nuclear@3: static const char *mem_size_str(long sz); nuclear@3: nuclear@15: static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback_thunk(VkDebugReportFlagsEXT flags, nuclear@15: VkDebugReportObjectTypeEXT otype, uint64_t obj, size_t loc, int32_t code, nuclear@15: const char *layer_prefix, const char *msg, void *udata); nuclear@15: nuclear@3: VkInstance vk; nuclear@3: VkDevice vkdev; nuclear@3: VkQueue vkq; nuclear@3: nuclear@4: static VkPhysicalDevice *phys_devices; nuclear@4: static int sel_dev, sel_qfamily; nuclear@4: nuclear@4: static VkExtensionProperties *vkext, *vkdevext; nuclear@4: static uint32_t vkext_count, vkdevext_count; nuclear@4: nuclear@15: static VkDebugReportCallbackEXT debug_callback_obj; nuclear@15: static VkResult (*vk_create_debug_report_callback)(VkInstance, nuclear@15: const VkDebugReportCallbackCreateInfoEXT*, const VkAllocationCallbacks*, nuclear@15: VkDebugReportCallbackEXT*); nuclear@15: static void (*user_dbg_callback)(const char*, void*); nuclear@15: static void *user_dbg_callback_data; nuclear@15: nuclear@4: nuclear@4: int vku_have_extension(const char *name) nuclear@4: { nuclear@4: int i; nuclear@4: nuclear@4: if(!vkext) { nuclear@4: vkext_count = 0; nuclear@4: vkEnumerateInstanceExtensionProperties(0, &vkext_count, 0); nuclear@4: if(vkext_count) { nuclear@4: if(!(vkext = malloc(vkext_count * sizeof *vkext))) { nuclear@4: perror("failed to allocate instance extension list"); nuclear@4: return 0; nuclear@4: } nuclear@4: vkEnumerateInstanceExtensionProperties(0, &vkext_count, vkext); nuclear@4: nuclear@4: printf("instance extensions:\n"); nuclear@4: for(i=0; i<(int)vkext_count; i++) { nuclear@4: printf(" %s (ver: %u)\n", vkext[i].extensionName, (unsigned int)vkext[i].specVersion); nuclear@4: } nuclear@4: } nuclear@4: } nuclear@4: nuclear@4: for(i=0; i<(int)vkext_count; i++) { nuclear@4: if(strcmp(vkext[i].extensionName, name) == 0) { nuclear@4: return 1; nuclear@4: } nuclear@4: } nuclear@4: return 0; nuclear@4: } nuclear@4: nuclear@4: int vku_have_device_extension(const char *name) nuclear@4: { nuclear@4: int i; nuclear@4: nuclear@4: if(sel_dev < 0) return 0; nuclear@4: nuclear@4: if(!vkdevext) { nuclear@4: vkdevext_count = 0; nuclear@4: vkEnumerateDeviceExtensionProperties(phys_devices[sel_dev], 0, &vkdevext_count, 0); nuclear@4: if(vkdevext_count) { nuclear@4: if(!(vkdevext = malloc(vkdevext_count * sizeof *vkdevext))) { nuclear@4: perror("failed to allocate device extension list"); nuclear@4: return 0; nuclear@4: } nuclear@4: vkEnumerateDeviceExtensionProperties(phys_devices[sel_dev], 0, &vkdevext_count, vkdevext); nuclear@4: nuclear@4: printf("selected device extensions:\n"); nuclear@4: for(i=0; i<(int)vkdevext_count; i++) { nuclear@4: printf(" %s (ver: %u)\n", vkdevext[i].extensionName, (unsigned int)vkdevext[i].specVersion); nuclear@4: } nuclear@4: } nuclear@4: } nuclear@4: nuclear@4: for(i=0; i<(int)vkdevext_count; i++) { nuclear@4: if(strcmp(vkdevext[i].extensionName, name) == 0) { nuclear@4: return 1; nuclear@4: } nuclear@4: } nuclear@4: return 0; nuclear@4: } nuclear@4: nuclear@15: void vku_set_debug_callback(void (*func)(const char*, void*), void *cls) nuclear@15: { nuclear@15: if(!debug_callback_obj && vk_create_debug_report_callback) { nuclear@15: VkDebugReportCallbackCreateInfoEXT foo; nuclear@15: nuclear@15: memset(&foo, 0, sizeof foo); nuclear@15: foo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; nuclear@15: foo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; nuclear@15: foo.pfnCallback = debug_callback_thunk; nuclear@15: nuclear@15: vk_create_debug_report_callback(vk, &foo, 0, &debug_callback_obj); nuclear@15: } nuclear@15: nuclear@15: user_dbg_callback = func; nuclear@15: user_dbg_callback_data = cls; nuclear@15: } nuclear@15: nuclear@15: nuclear@3: int vku_create_dev(void) nuclear@3: { nuclear@3: int i, j; nuclear@15: uint32_t nlayers; nuclear@3: VkInstanceCreateInfo inst_info; nuclear@15: VkLayerProperties *layers; nuclear@3: VkDeviceCreateInfo dev_info; nuclear@3: VkDeviceQueueCreateInfo queue_info; nuclear@3: VkCommandPoolCreateInfo cmdpool_info; nuclear@3: uint32_t num_devices; nuclear@3: float qprio = 0.0f; nuclear@3: nuclear@4: static const char *ext_names[] = { nuclear@4: #ifdef VK_USE_PLATFORM_XLIB_KHR nuclear@4: "VK_KHR_xlib_surface", nuclear@4: #endif nuclear@15: "VK_KHR_surface", nuclear@15: "VK_EXT_debug_report" nuclear@4: }; nuclear@5: static const char *devext_names[] = { nuclear@5: "VK_KHR_swapchain" nuclear@5: }; nuclear@15: static const char *layer_names[] = { nuclear@16: "VK_LAYER_LUNARG_standard_validation", nuclear@16: "VK_LAYER_LUNARG_parameter_validation", nuclear@16: "VK_LAYER_LUNARG_core_validation" nuclear@15: }; nuclear@4: nuclear@4: sel_dev = -1; nuclear@4: sel_qfamily = -1; nuclear@4: nuclear@4: for(i=0; ibuf) != 0) { nuclear@3: fprintf(stderr, "failed to create %d byte buffer (usage: %x)\n", sz, usage); nuclear@3: return 0; nuclear@3: } nuclear@3: // TODO back with memory nuclear@3: return buf; nuclear@3: } nuclear@3: nuclear@4: void vku_destroy_buffer(struct vku_buffer *buf) nuclear@3: { nuclear@3: if(buf) { nuclear@3: vkDestroyBuffer(vkdev, buf->buf, 0); nuclear@3: free(buf); nuclear@3: } nuclear@3: } nuclear@3: nuclear@4: void vku_cmd_copybuf(VkCommandBuffer cmdbuf, VkBuffer dest, int doffs, nuclear@4: VkBuffer src, int soffs, int size) nuclear@4: { nuclear@4: VkBufferCopy copy; nuclear@4: copy.size = size; nuclear@4: copy.srcOffset = soffs; nuclear@4: copy.dstOffset = doffs; nuclear@4: nuclear@4: vkCmdCopyBuffer(cmdbuf, src, dest, 1, ©); nuclear@4: } nuclear@4: nuclear@12: nuclear@13: VkRenderPass vku_create_renderpass(VkFormat cfmt, VkFormat dsfmt) nuclear@13: { nuclear@13: int count = 1; /* always assume we have a color attachment for now */ nuclear@13: VkAttachmentDescription at[2]; nuclear@13: VkAttachmentReference colref, dsref; nuclear@13: VkSubpassDescription subpass; nuclear@13: VkRenderPass pass; nuclear@13: VkRenderPassCreateInfo rpinf; nuclear@13: nuclear@13: colref.attachment = 0; nuclear@13: colref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; nuclear@13: dsref.attachment = 1; nuclear@13: dsref.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; nuclear@13: nuclear@13: memset(&subpass, 0, sizeof subpass); nuclear@13: subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; nuclear@13: subpass.colorAttachmentCount = 1; nuclear@13: subpass.pColorAttachments = &colref; nuclear@13: nuclear@13: at[0].format = cfmt; nuclear@13: at[0].samples = VK_SAMPLE_COUNT_1_BIT; /* TODO multisampling */ nuclear@13: at[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; nuclear@13: at[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; nuclear@13: at[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; nuclear@13: at[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; nuclear@13: at[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; nuclear@13: at[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; nuclear@13: nuclear@13: if(dsfmt != VK_FORMAT_UNDEFINED) { nuclear@13: at[1].format = dsfmt; nuclear@13: at[1].samples = VK_SAMPLE_COUNT_1_BIT; nuclear@13: at[1].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; nuclear@13: at[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE; nuclear@13: at[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; nuclear@13: at[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; nuclear@13: at[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; nuclear@13: at[1].finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; nuclear@13: nuclear@13: subpass.pDepthStencilAttachment = &dsref; nuclear@13: count++; nuclear@13: } nuclear@13: nuclear@13: memset(&rpinf, 0, sizeof rpinf); nuclear@13: rpinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; nuclear@13: rpinf.attachmentCount = count; nuclear@13: rpinf.pAttachments = at; nuclear@13: rpinf.subpassCount = 1; nuclear@13: rpinf.pSubpasses = &subpass; nuclear@13: nuclear@13: if(vkCreateRenderPass(vkdev, &rpinf, 0, &pass) != 0) { nuclear@13: fprintf(stderr, "vku_create_renderpass: failed to create renderpass\n"); nuclear@13: return 0; nuclear@13: } nuclear@13: nuclear@13: return pass; nuclear@13: } nuclear@13: nuclear@13: void vku_destroy_renderpass(VkRenderPass rpass) nuclear@13: { nuclear@13: vkDestroyRenderPass(vkdev, rpass, 0); nuclear@13: } nuclear@13: nuclear@15: void vku_begin_renderpass(VkCommandBuffer cmdbuf, VkRenderPass rpass, VkFramebuffer fb, nuclear@15: VkSubpassContents cont) nuclear@15: { nuclear@15: VkRenderPassBeginInfo rpinf; nuclear@15: nuclear@15: memset(&rpinf, 0, sizeof rpinf); nuclear@15: rpinf.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; nuclear@15: rpinf.renderPass = rpass; nuclear@15: rpinf.framebuffer = fb; nuclear@15: rpinf.renderArea.offset.x = vkvport.x; nuclear@15: rpinf.renderArea.offset.y = vkvport.y; nuclear@15: rpinf.renderArea.extent.width = vkvport.width; nuclear@15: rpinf.renderArea.extent.height = vkvport.height; nuclear@15: nuclear@15: vkCmdBeginRenderPass(cmdbuf, &rpinf, cont); nuclear@15: } nuclear@15: nuclear@15: void vku_end_renderpass(VkCommandBuffer cmdbuf) nuclear@15: { nuclear@15: vkCmdEndRenderPass(cmdbuf); nuclear@15: } nuclear@13: nuclear@4: #ifdef VK_USE_PLATFORM_XLIB_KHR nuclear@4: int vku_xlib_usable_visual(Display *dpy, VisualID vid) nuclear@4: { nuclear@4: return vkGetPhysicalDeviceXlibPresentationSupportKHR(phys_devices[sel_dev], nuclear@4: sel_qfamily, dpy, vid); nuclear@4: } nuclear@5: nuclear@5: VkSurfaceKHR vku_xlib_create_surface(Display *dpy, Window win) nuclear@5: { nuclear@5: VkSurfaceKHR surf; nuclear@5: VkXlibSurfaceCreateInfoKHR inf; nuclear@5: nuclear@5: memset(&inf, 0, sizeof inf); nuclear@5: inf.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; nuclear@5: inf.dpy = dpy; nuclear@5: inf.window = win; nuclear@5: nuclear@5: if(vkCreateXlibSurfaceKHR(vk, &inf, 0, &surf) != 0) { nuclear@5: return 0; nuclear@5: } nuclear@5: return surf; nuclear@5: } nuclear@5: nuclear@4: #endif /* VK_USE_PLATFORM_XLIB_KHR */ nuclear@4: nuclear@3: static const char *get_device_name(VkPhysicalDeviceType type) nuclear@3: { nuclear@3: switch(type) { nuclear@3: case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: nuclear@3: return "integrated GPU"; nuclear@3: case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: nuclear@3: return "discrete GPU"; nuclear@3: case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: nuclear@3: return "virtual GPU"; nuclear@3: case VK_PHYSICAL_DEVICE_TYPE_CPU: nuclear@3: return "CPU"; nuclear@3: default: nuclear@3: break; nuclear@3: } nuclear@3: return "unknown"; nuclear@3: } nuclear@3: nuclear@3: static const char *get_mem_prop_flag_string(VkMemoryPropertyFlags flags) nuclear@3: { nuclear@3: static char str[128]; nuclear@3: nuclear@3: str[0] = 0; nuclear@3: if(flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { nuclear@3: strcat(str, "device-local "); nuclear@3: } nuclear@3: if(flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { nuclear@3: strcat(str, "host-visible "); nuclear@3: } nuclear@3: if(flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { nuclear@3: strcat(str, "host-coherent "); nuclear@3: } nuclear@3: if(flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { nuclear@3: strcat(str, "host-cached "); nuclear@3: } nuclear@3: if(flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) { nuclear@3: strcat(str, "lazily-allocated "); nuclear@3: } nuclear@3: nuclear@3: if(!*str) { nuclear@3: strcat(str, "-"); nuclear@3: } nuclear@3: return str; nuclear@3: } nuclear@3: nuclear@3: static const char *get_queue_flag_string(VkQueueFlagBits flags) nuclear@3: { nuclear@3: static char str[128]; nuclear@3: nuclear@3: str[0] = 0; nuclear@3: if(flags & VK_QUEUE_GRAPHICS_BIT) { nuclear@3: strcat(str, "graphics "); nuclear@3: } nuclear@3: if(flags & VK_QUEUE_COMPUTE_BIT) { nuclear@3: strcat(str, "compute "); nuclear@3: } nuclear@3: if(flags & VK_QUEUE_TRANSFER_BIT) { nuclear@3: strcat(str, "transfer "); nuclear@3: } nuclear@3: if(flags & VK_QUEUE_SPARSE_BINDING_BIT) { nuclear@3: strcat(str, "sparse-binding "); nuclear@3: } nuclear@3: if(!*str) { nuclear@3: strcat(str, "-"); nuclear@3: } nuclear@3: return str; nuclear@3: } nuclear@3: nuclear@3: static int ver_major(uint32_t ver) nuclear@3: { nuclear@3: return (ver >> 22) & 0x3ff; nuclear@3: } nuclear@3: nuclear@3: static int ver_minor(uint32_t ver) nuclear@3: { nuclear@3: return (ver >> 12) & 0x3ff; nuclear@3: } nuclear@3: nuclear@3: static int ver_patch(uint32_t ver) nuclear@3: { nuclear@3: return ver & 0xfff; nuclear@3: } nuclear@3: nuclear@3: static const char *mem_size_str(long sz) nuclear@3: { nuclear@3: static char str[64]; nuclear@3: static const char *unitstr[] = { "bytes", "KB", "MB", "GB", "TB", "PB", 0 }; nuclear@3: int uidx = 0; nuclear@3: sz *= 10; nuclear@3: nuclear@3: while(sz >= 10240 && unitstr[uidx + 1]) { nuclear@3: sz /= 1024; nuclear@3: ++uidx; nuclear@3: } nuclear@3: sprintf(str, "%ld.%ld %s", sz / 10, sz % 10, unitstr[uidx]); nuclear@3: return str; nuclear@3: } nuclear@15: nuclear@15: static VKAPI_ATTR VkBool32 VKAPI_CALL debug_callback_thunk(VkDebugReportFlagsEXT flags, nuclear@15: VkDebugReportObjectTypeEXT otype, uint64_t obj, size_t loc, int32_t code, nuclear@15: const char *layer_prefix, const char *msg, void *udata) nuclear@15: { nuclear@15: if(user_dbg_callback) { nuclear@15: user_dbg_callback(msg, user_dbg_callback_data); nuclear@15: } else { nuclear@15: fprintf(stderr, "VK DEBUG (%s): %s\n", layer_prefix, msg); nuclear@15: } nuclear@15: nuclear@15: return VK_TRUE; nuclear@15: }