From: Eleni Maria Stea Date: Mon, 23 Aug 2021 05:53:59 +0000 (+0300) Subject: many changes: Makefile, util, fixed indent, fixes in swapchain X-Git-Url: https://eleni.mutantstargoat.com/git/?a=commitdiff_plain;h=9c5fa12eb2c6db6c8a3fbd280bab8951cf51f0a0;p=vkrt many changes: Makefile, util, fixed indent, fixes in swapchain - changed the Makefile to compile the shaders - added a util.[hc] - fixed the indentation - changed the swapchain to be separated from context and rendering => creating image views with separate functions => modified existing code too. --- diff --git a/.vimrc b/.vimrc new file mode 100644 index 0000000..fa29808 --- /dev/null +++ b/.vimrc @@ -0,0 +1,3 @@ +set ts=4 +set sw=4 +set expandtab diff --git a/Makefile b/Makefile index 470cf95..0e3b0b4 100644 --- a/Makefile +++ b/Makefile @@ -1,22 +1,32 @@ src = $(wildcard src/*.c) obj = $(src:.c=.o) dep = $(obj:.o=.d) +vsdr = $(wildcard data/*.vert) +fsdr = $(wildcard data/*.frag) +spv = $(subst .vert,.vert.spv,$(vsdr)) \ + $(subst .frag,.frag.spv,$(fsdr)) bin = rt dbg = -g CC = gcc -CFLAGS = -pedantic -Wall $(dbg) $(pkg-config --cflags glfw3) -LDFLAGS = -lvulkan -lglfw #$(pkg-config --libs glfw3) +CFLAGS = -pedantic -Wall $(dbg) -MMD +LDFLAGS = -lvulkan -lglfw + +.PHONY: all +all: $(bin) $(spv) $(bin): $(obj) $(CC) -o $@ $(obj) $(LDFLAGS) --include $(dep) +%.vert.spv: %.vert + glslangValidator -V $< -o $@ -%.d: %.c - @$(CC) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@ +%.frag.spv: %.frag + glslangValidator -V $< -o $@ + +-include $(dep) .PHONY: clean clean: - rm -f $(obj) $(bin) $(dep) + rm -f $(obj) $(bin) $(dep) $(spv) diff --git a/src/main.c b/src/main.c index 07af1ef..b0a5ec4 100644 --- a/src/main.c +++ b/src/main.c @@ -6,6 +6,7 @@ #include #include "vk.h" +#include "util.h" /* static glfw callbacks */ @@ -36,7 +37,15 @@ static int win_w = 800; static int win_h = 600; static struct vk_ctx vk_core; -static struct vk_swapchain vk_swap; +static VkSurfaceKHR vk_surf; +static int vsz, fsz; +static struct vk_renderer vk_rnd; +static struct vk_swapchain vk_chain; + +static struct vk_semaphores vk_sema; + +/* empty for as long as we hardcode the vertices in the vertex shader */ +static struct vk_vertex_info vk_vert_info; int main(int argc, char** argv) { @@ -66,6 +75,8 @@ int main(int argc, char** argv) static bool init() { + char *vsdr, *fsdr; + /* initialize GLFW */ if (!glfwInit()) { @@ -78,15 +89,6 @@ init() return false; } - /* initialize Vulkan context */ - - if (!vk_init_ctx_for_rendering(&vk_core)) { - fprintf(stderr, "Failed to initialize Vulkan context.\n"); - return false; - } - - memset(&vk_swap, 0, sizeof vk_swap); - /* create window */ glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); @@ -97,24 +99,41 @@ init() return false; } + /* initialize Vulkan context (instance) */ + + if (!vk_init_ctx_for_rendering(&vk_core)) { + fprintf(stderr, "Failed to initialize Vulkan context.\n"); + return false; + } + /* create (Xcb) surface */ glfwGetFramebufferSize(win, &win_h, &win_h); - if (glfwCreateWindowSurface(vk_core.inst, win, 0, &vk_swap.surface) + if (glfwCreateWindowSurface(vk_core.inst, win, 0, &vk_surf) != VK_SUCCESS) { fprintf(stderr, "Failed to create XCB surface.\n"); + glfwTerminate(); + return false; } - /* create Vulkan swapchain */ + /* create semaphores */ + vk_create_semaphores(&vk_core, false, &vk_sema); - /* aquire images? */ + /* create swapchain */ + vk_create_swapchain(&vk_core, win_w, win_h, false, vk_surf, VK_NULL_HANDLE, &vk_chain); /* create shaders */ - - /* create semaphores? */ + vsdr = sdr_load("data/main.vert.spv", &vsz); + fsdr = sdr_load("data/main.frag.spv", &fsz); /* create renderer */ + if (!vk_create_renderer(&vk_core, vsdr, vsz, fsdr, fsz, + false, false, 0, 0, + &vk_vert_info, &vk_rnd)) { + fprintf(stderr, "Failed to create renderer.\n"); + return false; + } /* set GLFW callbacks */ @@ -137,7 +156,10 @@ display() static void cleanup() { + vk_destroy_renderer(&vk_core, &vk_rnd); + vk_cleanup_ctx(&vk_core); + glfwTerminate(); } diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..7d33134 --- /dev/null +++ b/src/util.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include + +#include "util.h" + +char * +sdr_load(const char *fname, int *sz) +{ + FILE *fp; + char *sdr_text; + struct stat sp; + size_t filesz; + + if (!(fp = fopen(fname, "r"))) { + fprintf(stderr, "Failed to open shader file: %s: %s.\n", fname, strerror(errno)); + return 0; + } + + fstat(fileno(fp), &sp); + filesz = sp.st_size; + + if (!(sdr_text = malloc(filesz + 1))) { + fclose(fp); + return 0; + } + + fread(sdr_text, 1, filesz, fp); + sdr_text[filesz] = 0; + fclose(fp); + + if (!sdr_text) + fprintf(stderr, "Failed to load shader source code from: %s.\n", fname); + + *sz = filesz; + return sdr_text; + +} + +bool +img_dump_rgba(const char *fname, + int w, int h, + unsigned char *data) +{ + return true; +} diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..97abe8a --- /dev/null +++ b/src/util.h @@ -0,0 +1,14 @@ +#ifndef UTIL_H +#define UTIL_H + +#include + +char * +sdr_load(const char *fname, int *sz); + +bool +img_dump_rgba(const char *fname, + int w, int h, + unsigned char *data); + +#endif /* UTIL_H */ diff --git a/src/vk.c b/src/vk.c index 81e0f51..de807a4 100644 --- a/src/vk.c +++ b/src/vk.c @@ -6,6 +6,7 @@ #include "vk.h" /* static variables */ + static VkViewport viewport; static VkRect2D scissor; static bool enable_layers = true; @@ -15,85 +16,85 @@ static bool enable_layers = true; static VkSampleCountFlagBits get_num_samples(uint32_t num_samples) { - switch(num_samples) { - case 64: - return VK_SAMPLE_COUNT_64_BIT; - case 32: - return VK_SAMPLE_COUNT_32_BIT; - case 16: - return VK_SAMPLE_COUNT_16_BIT; - case 8: - return VK_SAMPLE_COUNT_8_BIT; - case 4: - return VK_SAMPLE_COUNT_4_BIT; - case 2: - return VK_SAMPLE_COUNT_2_BIT; - case 1: - break; - default: - fprintf(stderr, "Invalid number of samples in VkSampleCountFlagBits. Using one sample.\n"); - break; - } - return VK_SAMPLE_COUNT_1_BIT; + switch(num_samples) { + case 64: + return VK_SAMPLE_COUNT_64_BIT; + case 32: + return VK_SAMPLE_COUNT_32_BIT; + case 16: + return VK_SAMPLE_COUNT_16_BIT; + case 8: + return VK_SAMPLE_COUNT_8_BIT; + case 4: + return VK_SAMPLE_COUNT_4_BIT; + case 2: + return VK_SAMPLE_COUNT_2_BIT; + case 1: + break; + default: + fprintf(stderr, "Invalid number of samples in VkSampleCountFlagBits. Using one sample.\n"); + break; + } + return VK_SAMPLE_COUNT_1_BIT; } static VkAccessFlagBits get_access_mask(const VkImageLayout layout) { - /* dstAccessMask of barriers must be supported from the pipeline - * stage, see also access scopes and this table: - * https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#synchronization-access-types-supported - */ - switch (layout) { - case VK_IMAGE_LAYOUT_UNDEFINED: - return 0; - case VK_IMAGE_LAYOUT_GENERAL: - return VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; - case VK_IMAGE_LAYOUT_PREINITIALIZED: - return VK_ACCESS_HOST_WRITE_BIT; - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | - VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - return VK_ACCESS_TRANSFER_READ_BIT; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - return VK_ACCESS_TRANSFER_WRITE_BIT; - case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: - return 0; - default: - return 0; - }; - - return 0; + /* dstAccessMask of barriers must be supported from the pipeline + * stage, see also access scopes and this table: + * https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#synchronization-access-types-supported + */ + switch (layout) { + case VK_IMAGE_LAYOUT_UNDEFINED: + return 0; + case VK_IMAGE_LAYOUT_GENERAL: + return VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT; + case VK_IMAGE_LAYOUT_PREINITIALIZED: + return VK_ACCESS_HOST_WRITE_BIT; + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + return VK_ACCESS_TRANSFER_READ_BIT; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + return VK_ACCESS_TRANSFER_WRITE_BIT; + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + return 0; + default: + return 0; + }; + + return 0; } static void enable_validation_layers(VkInstanceCreateInfo *info) { - int i; - uint32_t num_layers; - VkLayerProperties *layers; - static const char *layer_names[] = { - "VK_LAYER_KHRONOS_validation", - }; - - vkEnumerateInstanceLayerProperties(&num_layers, 0); - layers = alloca(num_layers * sizeof *layers); - vkEnumerateInstanceLayerProperties(&num_layers, layers); - - if (num_layers) { - printf("Available validation layers:\n"); - for(i = 0; i < (int)num_layers; i++) { - printf(" %s\n", layers[i].layerName); - } - - info->ppEnabledLayerNames = layer_names; - info->enabledLayerCount = sizeof layer_names / sizeof *layer_names; - } else { - fprintf(stderr, "Vulkan validation layers not found.\n"); - } + int i; + uint32_t num_layers; + VkLayerProperties *layers; + static const char *layer_names[] = { + "VK_LAYER_KHRONOS_validation", + }; + + vkEnumerateInstanceLayerProperties(&num_layers, 0); + layers = alloca(num_layers * sizeof *layers); + vkEnumerateInstanceLayerProperties(&num_layers, layers); + + if (num_layers) { + printf("Available validation layers:\n"); + for(i = 0; i < (int)num_layers; i++) { + printf(" %s\n", layers[i].layerName); + } + + info->ppEnabledLayerNames = layer_names; + info->enabledLayerCount = sizeof layer_names / sizeof *layer_names; + } else { + fprintf(stderr, "Vulkan validation layers not found.\n"); + } } static void @@ -129,138 +130,138 @@ enable_extensions(VkInstanceCreateInfo *info) static VkInstance create_instance(bool enable_layers) { - VkApplicationInfo app_info; - VkInstanceCreateInfo inst_info; - VkInstance inst; + VkApplicationInfo app_info; + VkInstanceCreateInfo inst_info; + VkInstance inst; /* VkApplicationInfo */ - memset(&app_info, 0, sizeof app_info); - app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - app_info.pApplicationName = "vktest"; - app_info.apiVersion = VK_API_VERSION_1_1; + memset(&app_info, 0, sizeof app_info); + app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + app_info.pApplicationName = "vktest"; + app_info.apiVersion = VK_API_VERSION_1_1; /* VkInstanceCreateInfo */ - memset(&inst_info, 0, sizeof inst_info); - inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - inst_info.pApplicationInfo = &app_info; + memset(&inst_info, 0, sizeof inst_info); + inst_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + inst_info.pApplicationInfo = &app_info; enable_extensions(&inst_info); - if (enable_layers) { - enable_validation_layers(&inst_info); + if (enable_layers) { + enable_validation_layers(&inst_info); } - if (vkCreateInstance(&inst_info, 0, &inst) != VK_SUCCESS) - return 0; + if (vkCreateInstance(&inst_info, 0, &inst) != VK_SUCCESS) + return 0; - return inst; + return inst; } static VkPhysicalDevice select_physical_device(VkInstance inst) { - VkResult res = VK_SUCCESS; - uint32_t dev_count = 0; - VkPhysicalDevice *pdevices; - VkPhysicalDevice pdevice0; + VkResult res = VK_SUCCESS; + uint32_t dev_count = 0; + VkPhysicalDevice *pdevices; + VkPhysicalDevice pdevice0; - if ((res = - vkEnumeratePhysicalDevices(inst, &dev_count, 0)) != VK_SUCCESS) - return 0; + if ((res = + vkEnumeratePhysicalDevices(inst, &dev_count, 0)) != VK_SUCCESS) + return 0; - pdevices = malloc(dev_count * sizeof(VkPhysicalDevice)); - if (vkEnumeratePhysicalDevices(inst, &dev_count, pdevices) != - VK_SUCCESS) - return 0; + pdevices = malloc(dev_count * sizeof(VkPhysicalDevice)); + if (vkEnumeratePhysicalDevices(inst, &dev_count, pdevices) != + VK_SUCCESS) + return 0; - pdevice0 = pdevices[0]; - free(pdevices); + pdevice0 = pdevices[0]; + free(pdevices); - return pdevice0; + return pdevice0; } static VkDevice create_device(struct vk_ctx *ctx, VkPhysicalDevice pdev) { - const char *deviceExtensions[] = { "VK_KHR_swapchain" }; - VkDeviceQueueCreateInfo dev_queue_info; - VkDeviceCreateInfo dev_info; - VkDevice dev; - uint32_t prop_count; - VkQueueFamilyProperties *fam_props; - uint32_t i; - float qprio = 0; - - ctx->qfam_idx = -1; - vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, 0); - if (prop_count < 0) { - fprintf(stderr, "Invalid queue family properties.\n"); - return 0; - } - - fam_props = malloc(prop_count * sizeof *fam_props); - vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, fam_props); - - for (i = 0; i < prop_count; i++) { - if (fam_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { - ctx->qfam_idx = i; - break; - } - } - free(fam_props); - - memset(&dev_queue_info, 0, sizeof dev_queue_info); - dev_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - dev_queue_info.queueFamilyIndex = ctx->qfam_idx; - dev_queue_info.queueCount = 1; - dev_queue_info.pQueuePriorities = &qprio; - - memset(&dev_info, 0, sizeof dev_info); - dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - dev_info.queueCreateInfoCount = 1; - dev_info.pQueueCreateInfos = &dev_queue_info; - dev_info.enabledExtensionCount = ARRAY_SIZE(deviceExtensions); - dev_info.ppEnabledExtensionNames = deviceExtensions; - - if (vkCreateDevice(pdev, &dev_info, 0, &dev) != VK_SUCCESS) - return 0; - - return dev; + const char *deviceExtensions[] = { "VK_KHR_swapchain" }; + VkDeviceQueueCreateInfo dev_queue_info; + VkDeviceCreateInfo dev_info; + VkDevice dev; + uint32_t prop_count; + VkQueueFamilyProperties *fam_props; + uint32_t i; + float qprio = 0; + + ctx->qfam_idx = -1; + vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, 0); + if (prop_count < 0) { + fprintf(stderr, "Invalid queue family properties.\n"); + return 0; + } + + fam_props = malloc(prop_count * sizeof *fam_props); + vkGetPhysicalDeviceQueueFamilyProperties(pdev, &prop_count, fam_props); + + for (i = 0; i < prop_count; i++) { + if (fam_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { + ctx->qfam_idx = i; + break; + } + } + free(fam_props); + + memset(&dev_queue_info, 0, sizeof dev_queue_info); + dev_queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + dev_queue_info.queueFamilyIndex = ctx->qfam_idx; + dev_queue_info.queueCount = 1; + dev_queue_info.pQueuePriorities = &qprio; + + memset(&dev_info, 0, sizeof dev_info); + dev_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + dev_info.queueCreateInfoCount = 1; + dev_info.pQueueCreateInfos = &dev_queue_info; + dev_info.enabledExtensionCount = ARRAY_SIZE(deviceExtensions); + dev_info.ppEnabledExtensionNames = deviceExtensions; + + if (vkCreateDevice(pdev, &dev_info, 0, &dev) != VK_SUCCESS) + return 0; + + return dev; } static void fill_uuid(VkPhysicalDevice pdev, uint8_t *deviceUUID, uint8_t *driverUUID) { - VkPhysicalDeviceIDProperties devProp; - VkPhysicalDeviceProperties2 prop2; + VkPhysicalDeviceIDProperties devProp; + VkPhysicalDeviceProperties2 prop2; - memset(&devProp, 0, sizeof devProp); - devProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES; + memset(&devProp, 0, sizeof devProp); + devProp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES; - memset(&prop2, 0, sizeof prop2); - prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; - prop2.pNext = &devProp; + memset(&prop2, 0, sizeof prop2); + prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; + prop2.pNext = &devProp; - vkGetPhysicalDeviceProperties2(pdev, &prop2); - memcpy(deviceUUID, devProp.deviceUUID, VK_UUID_SIZE); - memcpy(driverUUID, devProp.driverUUID, VK_UUID_SIZE); + vkGetPhysicalDeviceProperties2(pdev, &prop2); + memcpy(deviceUUID, devProp.deviceUUID, VK_UUID_SIZE); + memcpy(driverUUID, devProp.driverUUID, VK_UUID_SIZE); } static VkCommandPool create_cmd_pool(struct vk_ctx *ctx) { - VkCommandPoolCreateInfo cmd_pool_info; - VkCommandPool cmd_pool; - VkDevice dev = ctx->dev; + VkCommandPoolCreateInfo cmd_pool_info; + VkCommandPool cmd_pool; + VkDevice dev = ctx->dev; - memset(&cmd_pool_info, 0, sizeof cmd_pool_info); - cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - cmd_pool_info.queueFamilyIndex = ctx->qfam_idx; - cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + memset(&cmd_pool_info, 0, sizeof cmd_pool_info); + cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + cmd_pool_info.queueFamilyIndex = ctx->qfam_idx; + cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - if (vkCreateCommandPool(dev, &cmd_pool_info, 0, &cmd_pool) != VK_SUCCESS) - return 0; + if (vkCreateCommandPool(dev, &cmd_pool_info, 0, &cmd_pool) != VK_SUCCESS) + return 0; - return cmd_pool; + return cmd_pool; } static VkRenderPass @@ -268,281 +269,305 @@ create_renderpass(struct vk_ctx *ctx, struct vk_image_props *color_img_props, struct vk_image_props *depth_img_props) { - uint32_t num_attachments = 2; - VkAttachmentDescription att_dsc[2]; - VkAttachmentReference att_rfc[2]; - VkSubpassDescription subpass_dsc[1]; - VkRenderPassCreateInfo rpass_info; - - /* VkAttachmentDescription */ - memset(att_dsc, 0, num_attachments * sizeof att_dsc[0]); - - att_dsc[0].samples = get_num_samples(color_img_props->num_samples); - att_dsc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - att_dsc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - att_dsc[0].initialLayout = color_img_props->in_layout; - att_dsc[0].finalLayout = color_img_props->end_layout; - att_dsc[0].format = color_img_props->format; - att_dsc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - att_dsc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - - att_dsc[1].samples = get_num_samples(depth_img_props->num_samples); - - /* We might want to reuse a depth buffer */ - if (depth_img_props->in_layout != VK_IMAGE_LAYOUT_UNDEFINED) { - att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - } - else { - att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - } - - att_dsc[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - att_dsc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; - att_dsc[1].initialLayout = depth_img_props->in_layout; - att_dsc[1].finalLayout = depth_img_props->end_layout; - att_dsc[1].format = depth_img_props->format; - - /* VkAttachmentReference */ - memset(att_rfc, 0, num_attachments * sizeof att_rfc[0]); - - att_rfc[0].layout = color_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL; - att_rfc[0].attachment = 0; - - att_rfc[1].layout = depth_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL; - att_rfc[1].attachment = 1; - - /* VkSubpassDescription */ - memset(&subpass_dsc, 0, sizeof subpass_dsc); - subpass_dsc[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass_dsc[0].colorAttachmentCount = 1; - subpass_dsc[0].pColorAttachments = &att_rfc[0]; - subpass_dsc[0].pDepthStencilAttachment = &att_rfc[1]; - - /* VkRenderPassCreateInfo */ - memset(&rpass_info, 0, sizeof rpass_info); - rpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - rpass_info.attachmentCount = num_attachments; - rpass_info.pAttachments = att_dsc; - rpass_info.subpassCount = 1; - rpass_info.pSubpasses = subpass_dsc; - - VkRenderPass rpass; - if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, &rpass) != VK_SUCCESS) { - fprintf(stderr, "Failed to create renderpass.\n"); - rpass = VK_NULL_HANDLE; - } - - return rpass; + uint32_t num_attachments = 2; + VkAttachmentDescription att_dsc[2]; + VkAttachmentReference att_rfc[2]; + VkSubpassDescription subpass_dsc[1]; + VkRenderPassCreateInfo rpass_info; + + /* VkAttachmentDescription */ + memset(att_dsc, 0, num_attachments * sizeof att_dsc[0]); + + att_dsc[0].samples = get_num_samples(color_img_props->num_samples); + att_dsc[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + att_dsc[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + att_dsc[0].initialLayout = color_img_props->in_layout; + att_dsc[0].finalLayout = color_img_props->end_layout; + att_dsc[0].format = color_img_props->format; + att_dsc[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + att_dsc[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + + att_dsc[1].samples = get_num_samples(depth_img_props->num_samples); + + /* We might want to reuse a depth buffer */ + if (depth_img_props->in_layout != VK_IMAGE_LAYOUT_UNDEFINED) { + att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + } + else { + att_dsc[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + att_dsc[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + } + + att_dsc[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + att_dsc[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + att_dsc[1].initialLayout = depth_img_props->in_layout; + att_dsc[1].finalLayout = depth_img_props->end_layout; + att_dsc[1].format = depth_img_props->format; + + /* VkAttachmentReference */ + memset(att_rfc, 0, num_attachments * sizeof att_rfc[0]); + + att_rfc[0].layout = color_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL; + att_rfc[0].attachment = 0; + + att_rfc[1].layout = depth_img_props->tiling == VK_IMAGE_TILING_OPTIMAL ? VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL; + att_rfc[1].attachment = 1; + + /* VkSubpassDescription */ + memset(&subpass_dsc, 0, sizeof subpass_dsc); + subpass_dsc[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass_dsc[0].colorAttachmentCount = 1; + subpass_dsc[0].pColorAttachments = &att_rfc[0]; + subpass_dsc[0].pDepthStencilAttachment = &att_rfc[1]; + + /* VkRenderPassCreateInfo */ + memset(&rpass_info, 0, sizeof rpass_info); + rpass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + rpass_info.attachmentCount = num_attachments; + rpass_info.pAttachments = att_dsc; + rpass_info.subpassCount = 1; + rpass_info.pSubpasses = subpass_dsc; + + VkRenderPass rpass; + if (vkCreateRenderPass(ctx->dev, &rpass_info, 0, &rpass) != VK_SUCCESS) { + fprintf(stderr, "Failed to create renderpass.\n"); + rpass = VK_NULL_HANDLE; + } + + return rpass; } static inline VkImageType get_image_type(uint32_t h, uint32_t d) { - if (h == 1) - return VK_IMAGE_TYPE_1D; + if (h == 1) + return VK_IMAGE_TYPE_1D; - if (d > 1) - return VK_IMAGE_TYPE_3D; + if (d > 1) + return VK_IMAGE_TYPE_3D; - return VK_IMAGE_TYPE_2D; + return VK_IMAGE_TYPE_2D; } static VkImageViewType get_image_view_type(struct vk_image_props *props) { - VkImageType type = get_image_type(props->h, props->depth); - switch(type) { - case VK_IMAGE_TYPE_1D: - return props->num_layers > 1 ? - VK_IMAGE_VIEW_TYPE_1D_ARRAY : - VK_IMAGE_VIEW_TYPE_1D; - case VK_IMAGE_TYPE_2D: - if (props->num_layers == 1) - return VK_IMAGE_VIEW_TYPE_2D; - if (props->num_layers == 6) - return VK_IMAGE_VIEW_TYPE_CUBE; - if (props->num_layers % 6 == 0) - return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; - if (props->num_layers > 1) - return VK_IMAGE_VIEW_TYPE_2D_ARRAY; - case VK_IMAGE_TYPE_3D: - if (props->num_layers == 1) - return VK_IMAGE_VIEW_TYPE_3D; - if ((props->num_layers == 1) && - (props->num_levels == 1)) - return VK_IMAGE_VIEW_TYPE_2D; - if ((props->num_levels == 1) && - (props->num_layers > 1)) - return VK_IMAGE_VIEW_TYPE_2D_ARRAY; - default: - return VK_IMAGE_VIEW_TYPE_2D; - } + VkImageType type = get_image_type(props->h, props->depth); + switch(type) { + case VK_IMAGE_TYPE_1D: + return props->num_layers > 1 ? + VK_IMAGE_VIEW_TYPE_1D_ARRAY : + VK_IMAGE_VIEW_TYPE_1D; + case VK_IMAGE_TYPE_2D: + if (props->num_layers == 1) + return VK_IMAGE_VIEW_TYPE_2D; + if (props->num_layers == 6) + return VK_IMAGE_VIEW_TYPE_CUBE; + if (props->num_layers % 6 == 0) + return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY; + if (props->num_layers > 1) + return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + case VK_IMAGE_TYPE_3D: + if (props->num_layers == 1) + return VK_IMAGE_VIEW_TYPE_3D; + if ((props->num_layers == 1) && + (props->num_levels == 1)) + return VK_IMAGE_VIEW_TYPE_2D; + if ((props->num_levels == 1) && + (props->num_layers > 1)) + return VK_IMAGE_VIEW_TYPE_2D_ARRAY; + default: + return VK_IMAGE_VIEW_TYPE_2D; + } } static VkImageAspectFlagBits get_aspect_from_depth_format(VkFormat depth_format) { - switch (depth_format) { - case VK_FORMAT_D16_UNORM: - case VK_FORMAT_X8_D24_UNORM_PACK32: - case VK_FORMAT_D32_SFLOAT: - return VK_IMAGE_ASPECT_DEPTH_BIT; - case VK_FORMAT_S8_UINT: - return VK_IMAGE_ASPECT_STENCIL_BIT; - case VK_FORMAT_D16_UNORM_S8_UINT: - case VK_FORMAT_D24_UNORM_S8_UINT: - case VK_FORMAT_D32_SFLOAT_S8_UINT: - return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - default: - break; - } - return 0; + switch (depth_format) { + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_X8_D24_UNORM_PACK32: + case VK_FORMAT_D32_SFLOAT: + return VK_IMAGE_ASPECT_DEPTH_BIT; + case VK_FORMAT_S8_UINT: + return VK_IMAGE_ASPECT_STENCIL_BIT; + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + default: + break; + } + return 0; } static VkPipelineStageFlags get_pipeline_stage_flags(const VkImageLayout layout) { - switch (layout) { - case VK_IMAGE_LAYOUT_UNDEFINED: - return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; - case VK_IMAGE_LAYOUT_GENERAL: - return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; - case VK_IMAGE_LAYOUT_PREINITIALIZED: - return VK_PIPELINE_STAGE_HOST_BIT; - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - return VK_PIPELINE_STAGE_TRANSFER_BIT; - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | - VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; - case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: - return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; - default: + switch (layout) { + case VK_IMAGE_LAYOUT_UNDEFINED: + return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT; + case VK_IMAGE_LAYOUT_GENERAL: + return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; + case VK_IMAGE_LAYOUT_PREINITIALIZED: + return VK_PIPELINE_STAGE_HOST_BIT; + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + return VK_PIPELINE_STAGE_TRANSFER_BIT; + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | + VK_PIPELINE_STAGE_VERTEX_SHADER_BIT; + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + default: break; - } - return 0; + } + return 0; +} + +static bool +create_image_view(struct vk_ctx *ctx, + VkImage image, + VkImageViewType view_type, + VkFormat format, + VkImageSubresourceRange sr, + bool is_swapchain, + VkImageView *image_view) +{ + VkImageViewCreateInfo info; + + memset(&info, 0, sizeof info); + info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + info.image = image; + info.viewType = view_type; + info.viewType = VK_IMAGE_VIEW_TYPE_2D; + info.format = format; + info.subresourceRange = sr; + + if (is_swapchain) { + info.components.r = VK_COMPONENT_SWIZZLE_R; + info.components.g = VK_COMPONENT_SWIZZLE_G; + info.components.b = VK_COMPONENT_SWIZZLE_B; + info.components.a = VK_COMPONENT_SWIZZLE_A; + } + + if (vkCreateImageView(ctx->dev, &info, 0, image_view) != VK_SUCCESS) { + fprintf(stderr, "Failed to create image view.\n"); + image_view = VK_NULL_HANDLE; + + return false; + } + + return true; } static void create_framebuffer(struct vk_ctx *ctx, - struct vk_image_att *color_att, - struct vk_image_att *depth_att, - struct vk_renderer *renderer) + struct vk_image_att *color_att, + struct vk_image_att *depth_att, + struct vk_renderer *renderer) { - VkImageSubresourceRange sr; - VkImageViewCreateInfo color_info; - VkImageViewCreateInfo depth_info; - VkFramebufferCreateInfo fb_info; - VkImageView atts[2]; - VkImageViewType view_type = get_image_view_type(&color_att->props); - - if (!color_att->obj.img || !depth_att->obj.img) { - fprintf(stderr, "Invalid framebuffer attachment image.\n"); - goto fail; - } - - /* create image views */ - - /* VKImageSubresourceRange */ - memset(&sr, 0, sizeof sr); - sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - /* If an application wants to use all mip levels - * or layers in an image after the baseMipLevel - * or baseArrayLayer, it can set levelCount and - * layerCount to the special values - * VK_REMAINING_MIP_LEVELS and - * VK_REMAINING_ARRAY_LAYERS without knowing the - * exact number of mip levels or layers. - */ - sr.baseMipLevel = 0; - sr.levelCount = color_att->props.num_levels; - sr.baseArrayLayer = 0; - sr.layerCount = color_att->props.num_layers; - - /* color view */ - memset(&color_info, 0, sizeof color_info); - color_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - color_info.image = color_att->obj.img; - color_info.viewType = view_type; - color_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - color_info.format = color_att->props.format; - color_info.subresourceRange = sr; - - if (vkCreateImageView(ctx->dev, &color_info, 0, &color_att->obj.img_view) != VK_SUCCESS) { - fprintf(stderr, "Failed to create color image view for framebuffer.\n"); - vk_destroy_image(ctx, &color_att->obj); - goto fail; - } - - /* depth view */ - memset(&sr, 0, sizeof sr); - sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format); - sr.baseMipLevel = 0; - sr.levelCount = depth_att->props.num_levels ? depth_att->props.num_levels : 1; - sr.baseArrayLayer = 0; - sr.layerCount = depth_att->props.num_layers ? depth_att->props.num_layers : 1; - - memset(&depth_info, 0, sizeof depth_info); - depth_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - depth_info.image = depth_att->obj.img; - depth_info.viewType = depth_att->props.num_layers > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D; - depth_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - depth_info.format = depth_att->props.format; - depth_info.subresourceRange = sr; - - if (vkCreateImageView(ctx->dev, &depth_info, 0, &depth_att->obj.img_view) != VK_SUCCESS) { - - fprintf(stderr, "Failed to create depth image view for framebuffer.\n"); - vk_destroy_image(ctx, &depth_att->obj); - goto fail; - } + VkImageSubresourceRange sr; + VkFramebufferCreateInfo fb_info; + VkImageView atts[2]; + VkImageViewType view_type = get_image_view_type(&color_att->props); + + if (!color_att->obj.img || !depth_att->obj.img) { + fprintf(stderr, "Invalid framebuffer attachment image.\n"); + goto fail; + } + + /* create image views */ + + /* VKImageSubresourceRange */ + memset(&sr, 0, sizeof sr); + sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + /* If an application wants to use all mip levels + * or layers in an image after the baseMipLevel + * or baseArrayLayer, it can set levelCount and + * layerCount to the special values + * VK_REMAINING_MIP_LEVELS and + * VK_REMAINING_ARRAY_LAYERS without knowing the + * exact number of mip levels or layers. + */ + sr.baseMipLevel = 0; + sr.levelCount = color_att->props.num_levels; + sr.baseArrayLayer = 0; + sr.layerCount = color_att->props.num_layers; + + /* color view */ + if (!create_image_view(ctx, color_att->obj.img, view_type, color_att->props.format, sr, false, &color_att->obj.img_view)) { + fprintf(stderr, "Failed to create color image view for framebuffer.\n"); + vk_destroy_image(ctx, &color_att->obj); + goto fail; + } + + /* depth view */ + memset(&sr, 0, sizeof sr); + sr.aspectMask = get_aspect_from_depth_format(depth_att->props.format); + sr.baseMipLevel = 0; + sr.levelCount = depth_att->props.num_levels ? depth_att->props.num_levels : 1; + sr.baseArrayLayer = 0; + sr.layerCount = depth_att->props.num_layers ? depth_att->props.num_layers : 1; + + if (!create_image_view(ctx, depth_att->obj.img, + depth_att->props.num_layers > 1 ? + VK_IMAGE_VIEW_TYPE_2D_ARRAY : + VK_IMAGE_VIEW_TYPE_2D, + depth_att->props.format, + sr, + false, + &depth_att->obj.img_view)) { + fprintf(stderr, "Failed to create depth image view for framebuffer.\n"); + vk_destroy_image(ctx, &depth_att->obj); + goto fail; + } atts[0] = color_att->obj.img_view; - atts[1] = depth_att->obj.img_view; + atts[1] = depth_att->obj.img_view; - memset(&fb_info, 0, sizeof fb_info); - fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fb_info.renderPass = renderer->renderpass; - fb_info.width = color_att->props.w; - fb_info.height = color_att->props.h; - fb_info.layers = color_att->props.num_layers ? color_att->props.num_layers : 1; - fb_info.attachmentCount = 2; - fb_info.pAttachments = atts; + memset(&fb_info, 0, sizeof fb_info); + fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fb_info.renderPass = renderer->renderpass; + fb_info.width = color_att->props.w; + fb_info.height = color_att->props.h; + fb_info.layers = color_att->props.num_layers ? color_att->props.num_layers : 1; + fb_info.attachmentCount = 2; + fb_info.pAttachments = atts; - if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS) - goto fail; + if (vkCreateFramebuffer(ctx->dev, &fb_info, 0, &renderer->fb) != VK_SUCCESS) + goto fail; - return; + return; fail: - fprintf(stderr, "Failed to create framebuffer.\n"); - renderer->fb = VK_NULL_HANDLE; + fprintf(stderr, "Failed to create framebuffer.\n"); + renderer->fb = VK_NULL_HANDLE; } static VkShaderModule create_shader_module(struct vk_ctx *ctx, - const char *src, - unsigned int size) + const char *src, + unsigned int size) { - VkShaderModuleCreateInfo sm_info; - VkShaderModule sm; - - /* VkShaderModuleCreateInfo */ - memset(&sm_info, 0, sizeof sm_info); - sm_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - sm_info.codeSize = size; - sm_info.pCode = (void*)src; - - if (vkCreateShaderModule(ctx->dev, &sm_info, 0, &sm) != VK_SUCCESS) { - fprintf(stderr, "Failed to create shader module.\n"); - sm = VK_NULL_HANDLE; - } + VkShaderModuleCreateInfo sm_info; + VkShaderModule sm; + + /* VkShaderModuleCreateInfo */ + memset(&sm_info, 0, sizeof sm_info); + sm_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + sm_info.codeSize = size; + sm_info.pCode = (void*)src; + + if (vkCreateShaderModule(ctx->dev, &sm_info, 0, &sm) != VK_SUCCESS) { + fprintf(stderr, "Failed to create shader module.\n"); + sm = VK_NULL_HANDLE; + } - return sm; + return sm; } static void @@ -554,259 +579,259 @@ create_pipeline(struct vk_ctx *ctx, bool enable_stencil, struct vk_renderer *renderer) { - VkVertexInputBindingDescription vert_bind_dsc[1]; - VkVertexInputAttributeDescription vert_att_dsc[1]; - - VkPipelineColorBlendAttachmentState cb_att_state[1]; - VkPipelineVertexInputStateCreateInfo vert_input_info; - VkPipelineInputAssemblyStateCreateInfo asm_info; - VkPipelineViewportStateCreateInfo viewport_info; - VkPipelineRasterizationStateCreateInfo rs_info; - VkPipelineMultisampleStateCreateInfo ms_info; - VkPipelineDepthStencilStateCreateInfo ds_info; - VkPipelineColorBlendStateCreateInfo cb_info; - VkPipelineShaderStageCreateInfo sdr_stages[2]; - VkPipelineLayoutCreateInfo layout_info; - VkGraphicsPipelineCreateInfo pipeline_info; - VkFormat format; - VkFormatProperties fmt_props; - VkPushConstantRange pc_range[1]; - - VkStencilOpState front; - VkStencilOpState back; - int i; - VkPipelineLayout pipeline_layout; - uint32_t stride; - - /* format of vertex attributes: - * we have 2D vectors so we need a RG format: - * R for x, G for y - * the stride (distance between 2 consecutive elements) - * must be 8 because we use 32 bit floats and - * 32bits = 8bytes */ - format = VK_FORMAT_R32G32_SFLOAT; - vkGetPhysicalDeviceFormatProperties(ctx->pdev, format, &fmt_props); - assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT); - stride = 8; - - /* VkVertexInputAttributeDescription */ - memset(&vert_att_dsc, 0, sizeof vert_att_dsc); - vert_att_dsc[0].location = 0; - vert_att_dsc[0].binding = 0; - vert_att_dsc[0].format = format; /* see comment */ - vert_att_dsc[0].offset = 0; - - /* VkVertexInputBindingDescription */ - memset(&vert_bind_dsc, 0, sizeof vert_bind_dsc); - vert_bind_dsc[0].binding = 0; - vert_bind_dsc[0].stride = stride; - vert_bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + VkVertexInputBindingDescription vert_bind_dsc[1]; + VkVertexInputAttributeDescription vert_att_dsc[1]; + + VkPipelineColorBlendAttachmentState cb_att_state[1]; + VkPipelineVertexInputStateCreateInfo vert_input_info; + VkPipelineInputAssemblyStateCreateInfo asm_info; + VkPipelineViewportStateCreateInfo viewport_info; + VkPipelineRasterizationStateCreateInfo rs_info; + VkPipelineMultisampleStateCreateInfo ms_info; + VkPipelineDepthStencilStateCreateInfo ds_info; + VkPipelineColorBlendStateCreateInfo cb_info; + VkPipelineShaderStageCreateInfo sdr_stages[2]; + VkPipelineLayoutCreateInfo layout_info; + VkGraphicsPipelineCreateInfo pipeline_info; + VkFormat format; + VkFormatProperties fmt_props; + VkPushConstantRange pc_range[1]; + + VkStencilOpState front; + VkStencilOpState back; + int i; + VkPipelineLayout pipeline_layout; + uint32_t stride; + + /* format of vertex attributes: + * we have 2D vectors so we need a RG format: + * R for x, G for y + * the stride (distance between 2 consecutive elements) + * must be 8 because we use 32 bit floats and + * 32bits = 8bytes */ + format = VK_FORMAT_R32G32_SFLOAT; + vkGetPhysicalDeviceFormatProperties(ctx->pdev, format, &fmt_props); + assert(fmt_props.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT); + stride = 8; + + /* VkVertexInputAttributeDescription */ + memset(&vert_att_dsc, 0, sizeof vert_att_dsc); + vert_att_dsc[0].location = 0; + vert_att_dsc[0].binding = 0; + vert_att_dsc[0].format = format; /* see comment */ + vert_att_dsc[0].offset = 0; + + /* VkVertexInputBindingDescription */ + memset(&vert_bind_dsc, 0, sizeof vert_bind_dsc); + vert_bind_dsc[0].binding = 0; + vert_bind_dsc[0].stride = stride; + vert_bind_dsc[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; /* If using vbo, we have setup vertex_info in the renderer. */ - bool use_vbo = renderer->vertex_info.num_verts > 0; - - /* VkPipelineVertexInputStateCreateInfo */ - memset(&vert_input_info, 0, sizeof vert_input_info); - vert_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vert_input_info.vertexBindingDescriptionCount = use_vbo ? 1 : 0; - vert_input_info.pVertexBindingDescriptions = vert_bind_dsc; - vert_input_info.vertexAttributeDescriptionCount = use_vbo ? 1 : 0; - vert_input_info.pVertexAttributeDescriptions = vert_att_dsc; - - /* VkPipelineInputAssemblyStateCreateInfo */ - memset(&asm_info, 0, sizeof asm_info); - asm_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - asm_info.topology = renderer->vertex_info.topology ? + bool use_vbo = renderer->vertex_info.num_verts > 0; + + /* VkPipelineVertexInputStateCreateInfo */ + memset(&vert_input_info, 0, sizeof vert_input_info); + vert_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vert_input_info.vertexBindingDescriptionCount = use_vbo ? 1 : 0; + vert_input_info.pVertexBindingDescriptions = vert_bind_dsc; + vert_input_info.vertexAttributeDescriptionCount = use_vbo ? 1 : 0; + vert_input_info.pVertexAttributeDescriptions = vert_att_dsc; + + /* VkPipelineInputAssemblyStateCreateInfo */ + memset(&asm_info, 0, sizeof asm_info); + asm_info.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + asm_info.topology = renderer->vertex_info.topology ? renderer->vertex_info.topology : VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; - asm_info.primitiveRestartEnable = false; - - /* VkViewport */ - viewport.x = viewport.y = 0; - viewport.width = width; - viewport.height = height; - viewport.minDepth = 0; - viewport.maxDepth = 1; - - /* VkRect2D scissor */ - scissor.offset.x = scissor.offset.y = 0; - scissor.extent.width = width; - scissor.extent.height = height; - - /* VkPipelineViewportStateCreateInfo */ - memset(&viewport_info, 0, sizeof viewport_info); - viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewport_info.viewportCount = 1; - viewport_info.pViewports = &viewport; - viewport_info.scissorCount = 1; - viewport_info.pScissors = &scissor; - - /* VkPipelineRasterizationStateCreateInfo */ - memset(&rs_info, 0, sizeof rs_info); - rs_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rs_info.polygonMode = VK_POLYGON_MODE_FILL; - rs_info.cullMode = VK_CULL_MODE_NONE; - rs_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; - rs_info.lineWidth = 1.0; - - /* VkPipelineMultisampleStateCreateInfo */ - memset(&ms_info, 0, sizeof ms_info); - ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - ms_info.rasterizationSamples = num_samples; - - /* VkStencilOpState */ - /* The default values for ES are taken by Topi Pohjolainen's code */ - /* defaults in OpenGL ES 3.1 */ - memset(&front, 0, sizeof front); - front.compareMask = ~0; - front.writeMask = ~0; - front.reference = 0; - - memset(&back, 0, sizeof back); - back.compareMask = ~0; - back.writeMask = ~0; - back.reference = 0; - - /* VkPipelineDepthStencilStateCreateInfo */ - memset(&ds_info, 0, sizeof ds_info); - ds_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - ds_info.front = front; - ds_info.back = back; - /* defaults in OpenGL ES 3.1 */ - ds_info.minDepthBounds = 0; - ds_info.maxDepthBounds = 1; - /* z buffer, stencil buffer */ - if (enable_depth) { - ds_info.depthTestEnable = VK_TRUE; - ds_info.depthWriteEnable = VK_TRUE; - ds_info.depthCompareOp = VK_COMPARE_OP_LESS; - } - if (enable_stencil) { - ds_info.stencilTestEnable = VK_TRUE; - ds_info.depthTestEnable = VK_FALSE; - ds_info.depthWriteEnable = VK_TRUE; - } - - /* we only care about the passOp here */ - ds_info.back.compareOp = VK_COMPARE_OP_ALWAYS; - ds_info.back.failOp = VK_STENCIL_OP_REPLACE; - ds_info.back.depthFailOp = VK_STENCIL_OP_REPLACE; - ds_info.back.passOp = VK_STENCIL_OP_REPLACE; - ds_info.back.compareMask = 0xffffffff; - ds_info.back.writeMask = 0xffffffff; - ds_info.back.reference = 1; - ds_info.front = ds_info.back; - - /* VkPipelineColorBlendAttachmentState */ - memset(&cb_att_state[0], 0, sizeof cb_att_state[0]); - cb_att_state[0].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT | + asm_info.primitiveRestartEnable = false; + + /* VkViewport */ + viewport.x = viewport.y = 0; + viewport.width = width; + viewport.height = height; + viewport.minDepth = 0; + viewport.maxDepth = 1; + + /* VkRect2D scissor */ + scissor.offset.x = scissor.offset.y = 0; + scissor.extent.width = width; + scissor.extent.height = height; + + /* VkPipelineViewportStateCreateInfo */ + memset(&viewport_info, 0, sizeof viewport_info); + viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewport_info.viewportCount = 1; + viewport_info.pViewports = &viewport; + viewport_info.scissorCount = 1; + viewport_info.pScissors = &scissor; + + /* VkPipelineRasterizationStateCreateInfo */ + memset(&rs_info, 0, sizeof rs_info); + rs_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rs_info.polygonMode = VK_POLYGON_MODE_FILL; + rs_info.cullMode = VK_CULL_MODE_NONE; + rs_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rs_info.lineWidth = 1.0; + + /* VkPipelineMultisampleStateCreateInfo */ + memset(&ms_info, 0, sizeof ms_info); + ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + ms_info.rasterizationSamples = num_samples; + + /* VkStencilOpState */ + /* The default values for ES are taken by Topi Pohjolainen's code */ + /* defaults in OpenGL ES 3.1 */ + memset(&front, 0, sizeof front); + front.compareMask = ~0; + front.writeMask = ~0; + front.reference = 0; + + memset(&back, 0, sizeof back); + back.compareMask = ~0; + back.writeMask = ~0; + back.reference = 0; + + /* VkPipelineDepthStencilStateCreateInfo */ + memset(&ds_info, 0, sizeof ds_info); + ds_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + ds_info.front = front; + ds_info.back = back; + /* defaults in OpenGL ES 3.1 */ + ds_info.minDepthBounds = 0; + ds_info.maxDepthBounds = 1; + /* z buffer, stencil buffer */ + if (enable_depth) { + ds_info.depthTestEnable = VK_TRUE; + ds_info.depthWriteEnable = VK_TRUE; + ds_info.depthCompareOp = VK_COMPARE_OP_LESS; + } + if (enable_stencil) { + ds_info.stencilTestEnable = VK_TRUE; + ds_info.depthTestEnable = VK_FALSE; + ds_info.depthWriteEnable = VK_TRUE; + } + + /* we only care about the passOp here */ + ds_info.back.compareOp = VK_COMPARE_OP_ALWAYS; + ds_info.back.failOp = VK_STENCIL_OP_REPLACE; + ds_info.back.depthFailOp = VK_STENCIL_OP_REPLACE; + ds_info.back.passOp = VK_STENCIL_OP_REPLACE; + ds_info.back.compareMask = 0xffffffff; + ds_info.back.writeMask = 0xffffffff; + ds_info.back.reference = 1; + ds_info.front = ds_info.back; + + /* VkPipelineColorBlendAttachmentState */ + memset(&cb_att_state[0], 0, sizeof cb_att_state[0]); + cb_att_state[0].colorWriteMask = (VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT); - /* VkPipelineColorBlendStateCreateInfo */ - memset(&cb_info, 0, sizeof cb_info); - cb_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - cb_info.attachmentCount = 1; - cb_info.pAttachments = cb_att_state; - /* default in ES 3.1 */ - for (i = 0; i < 4; i++) { - cb_info.blendConstants[i] = 0.0f; - } - - /* VkPipelineShaderStageCreateInfo */ - memset(sdr_stages, 0, 2 * sizeof sdr_stages[0]); - - sdr_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - sdr_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; - sdr_stages[0].module = renderer->vs; - sdr_stages[0].pName = "main"; - - sdr_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - sdr_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; - sdr_stages[1].module = renderer->fs; - sdr_stages[1].pName = "main"; - - /* VkPushConstantRange */ - memset(pc_range, 0, sizeof pc_range[0]); - pc_range[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - pc_range[0].size = sizeof (struct vk_dims); /* w, h */ - - /* VkPipelineLayoutCreateInfo */ - memset(&layout_info, 0, sizeof layout_info); - layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - layout_info.pushConstantRangeCount = 1; - layout_info.pPushConstantRanges = pc_range; - - if (vkCreatePipelineLayout(ctx->dev, &layout_info, 0, &pipeline_layout) != VK_SUCCESS) { - fprintf(stderr, "Failed to create pipeline layout\n"); - renderer->pipeline = VK_NULL_HANDLE; - return; - } - - renderer->pipeline_layout = pipeline_layout; - - /* VkGraphicsPipelineCreateInfo */ - memset(&pipeline_info, 0, sizeof pipeline_info); - pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - pipeline_info.layout = pipeline_layout; - pipeline_info.renderPass = renderer->renderpass; - pipeline_info.pVertexInputState = &vert_input_info; - pipeline_info.pInputAssemblyState = &asm_info; - pipeline_info.pViewportState = &viewport_info; - pipeline_info.pRasterizationState = &rs_info; - pipeline_info.pMultisampleState = &ms_info; - pipeline_info.pDepthStencilState = &ds_info; - pipeline_info.pColorBlendState = &cb_info; - pipeline_info.stageCount = 2; - pipeline_info.pStages = sdr_stages; - - if (vkCreateGraphicsPipelines(ctx->dev, 0, 1, + /* VkPipelineColorBlendStateCreateInfo */ + memset(&cb_info, 0, sizeof cb_info); + cb_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + cb_info.attachmentCount = 1; + cb_info.pAttachments = cb_att_state; + /* default in ES 3.1 */ + for (i = 0; i < 4; i++) { + cb_info.blendConstants[i] = 0.0f; + } + + /* VkPipelineShaderStageCreateInfo */ + memset(sdr_stages, 0, 2 * sizeof sdr_stages[0]); + + sdr_stages[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + sdr_stages[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + sdr_stages[0].module = renderer->vs; + sdr_stages[0].pName = "main"; + + sdr_stages[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + sdr_stages[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + sdr_stages[1].module = renderer->fs; + sdr_stages[1].pName = "main"; + + /* VkPushConstantRange */ + memset(pc_range, 0, sizeof pc_range[0]); + pc_range[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + pc_range[0].size = sizeof (struct vk_dims); /* w, h */ + + /* VkPipelineLayoutCreateInfo */ + memset(&layout_info, 0, sizeof layout_info); + layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + layout_info.pushConstantRangeCount = 1; + layout_info.pPushConstantRanges = pc_range; + + if (vkCreatePipelineLayout(ctx->dev, &layout_info, 0, &pipeline_layout) != VK_SUCCESS) { + fprintf(stderr, "Failed to create pipeline layout\n"); + renderer->pipeline = VK_NULL_HANDLE; + return; + } + + renderer->pipeline_layout = pipeline_layout; + + /* VkGraphicsPipelineCreateInfo */ + memset(&pipeline_info, 0, sizeof pipeline_info); + pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipeline_info.layout = pipeline_layout; + pipeline_info.renderPass = renderer->renderpass; + pipeline_info.pVertexInputState = &vert_input_info; + pipeline_info.pInputAssemblyState = &asm_info; + pipeline_info.pViewportState = &viewport_info; + pipeline_info.pRasterizationState = &rs_info; + pipeline_info.pMultisampleState = &ms_info; + pipeline_info.pDepthStencilState = &ds_info; + pipeline_info.pColorBlendState = &cb_info; + pipeline_info.stageCount = 2; + pipeline_info.pStages = sdr_stages; + + if (vkCreateGraphicsPipelines(ctx->dev, 0, 1, &pipeline_info, 0, &renderer->pipeline) != VK_SUCCESS) { - fprintf(stderr, "Failed to create graphics pipeline.\n"); - renderer->pipeline = VK_NULL_HANDLE; - } + fprintf(stderr, "Failed to create graphics pipeline.\n"); + renderer->pipeline = VK_NULL_HANDLE; + } } static VkCommandBuffer create_cmd_buf(VkDevice dev, VkCommandPool cmd_pool) { - VkCommandBuffer cmd_buf; - VkCommandBufferAllocateInfo alloc_info; + VkCommandBuffer cmd_buf; + VkCommandBufferAllocateInfo alloc_info; - memset(&alloc_info, 0, sizeof alloc_info); - alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - alloc_info.commandBufferCount = 1; - alloc_info.commandPool = cmd_pool; + memset(&alloc_info, 0, sizeof alloc_info); + alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + alloc_info.commandBufferCount = 1; + alloc_info.commandPool = cmd_pool; - if (vkAllocateCommandBuffers(dev, &alloc_info, &cmd_buf) != VK_SUCCESS) - return 0; + if (vkAllocateCommandBuffers(dev, &alloc_info, &cmd_buf) != VK_SUCCESS) + return 0; - return cmd_buf; + return cmd_buf; } static uint32_t get_memory_type_idx(VkPhysicalDevice pdev, - const VkMemoryRequirements *mem_reqs, - VkMemoryPropertyFlagBits prop_flags) + const VkMemoryRequirements *mem_reqs, + VkMemoryPropertyFlagBits prop_flags) { - VkPhysicalDeviceMemoryProperties pdev_mem_props; - uint32_t i; + VkPhysicalDeviceMemoryProperties pdev_mem_props; + uint32_t i; - vkGetPhysicalDeviceMemoryProperties(pdev, &pdev_mem_props); + vkGetPhysicalDeviceMemoryProperties(pdev, &pdev_mem_props); - for (i = 0; i < pdev_mem_props.memoryTypeCount; i++) { - const VkMemoryType *type = &pdev_mem_props.memoryTypes[i]; + for (i = 0; i < pdev_mem_props.memoryTypeCount; i++) { + const VkMemoryType *type = &pdev_mem_props.memoryTypes[i]; - if ((mem_reqs->memoryTypeBits & (1 << i)) && - (type->propertyFlags & prop_flags) == prop_flags) { - return i; - break; - } - } - return UINT32_MAX; + if ((mem_reqs->memoryTypeBits & (1 << i)) && + (type->propertyFlags & prop_flags) == prop_flags) { + return i; + break; + } + } + return UINT32_MAX; } static VkDeviceMemory @@ -817,10 +842,10 @@ alloc_memory(struct vk_ctx *ctx, VkBuffer buffer, VkMemoryPropertyFlagBits prop_flags) { - VkExportMemoryAllocateInfo exp_mem_info; - VkMemoryAllocateInfo mem_alloc_info; - VkDeviceMemory mem; - VkMemoryDedicatedAllocateInfoKHR ded_info; + VkExportMemoryAllocateInfo exp_mem_info; + VkMemoryAllocateInfo mem_alloc_info; + VkDeviceMemory mem; + VkMemoryDedicatedAllocateInfoKHR ded_info; if (is_external) { memset(&exp_mem_info, 0, sizeof exp_mem_info); @@ -829,56 +854,56 @@ alloc_memory(struct vk_ctx *ctx, VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; } - memset(&mem_alloc_info, 0, sizeof mem_alloc_info); - mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - mem_alloc_info.pNext = &exp_mem_info; - mem_alloc_info.allocationSize = mem_reqs->size; - mem_alloc_info.memoryTypeIndex = - get_memory_type_idx(ctx->pdev, mem_reqs, prop_flags); + memset(&mem_alloc_info, 0, sizeof mem_alloc_info); + mem_alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + mem_alloc_info.pNext = &exp_mem_info; + mem_alloc_info.allocationSize = mem_reqs->size; + mem_alloc_info.memoryTypeIndex = + get_memory_type_idx(ctx->pdev, mem_reqs, prop_flags); - if (mem_alloc_info.memoryTypeIndex == UINT32_MAX) { - fprintf(stderr, "No suitable memory type index found.\n"); - return 0; - } + if (mem_alloc_info.memoryTypeIndex == UINT32_MAX) { + fprintf(stderr, "No suitable memory type index found.\n"); + return 0; + } - if (image || buffer) { - memset(&ded_info, 0, sizeof ded_info); - ded_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO; - ded_info.image = image; - ded_info.buffer = buffer; + if (image || buffer) { + memset(&ded_info, 0, sizeof ded_info); + ded_info.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO; + ded_info.image = image; + ded_info.buffer = buffer; - exp_mem_info.pNext = &ded_info; - } + exp_mem_info.pNext = &ded_info; + } - if (vkAllocateMemory(ctx->dev, &mem_alloc_info, 0, &mem) != - VK_SUCCESS) - return 0; + if (vkAllocateMemory(ctx->dev, &mem_alloc_info, 0, &mem) != + VK_SUCCESS) + return 0; - return mem; + return mem; } static bool alloc_image_memory(struct vk_ctx *ctx, struct vk_image_obj *img_obj) { - VkMemoryDedicatedRequirements ded_reqs; - VkImageMemoryRequirementsInfo2 req_info2; - VkMemoryRequirements2 mem_reqs2; + VkMemoryDedicatedRequirements ded_reqs; + VkImageMemoryRequirementsInfo2 req_info2; + VkMemoryRequirements2 mem_reqs2; - memset(&ded_reqs, 0, sizeof ded_reqs); - ded_reqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS; + memset(&ded_reqs, 0, sizeof ded_reqs); + ded_reqs.sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS; - /* VkImageMemoryRequirementsInfo2 */ - memset(&req_info2, 0, sizeof req_info2); - req_info2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2; - req_info2.image = img_obj->img; + /* VkImageMemoryRequirementsInfo2 */ + memset(&req_info2, 0, sizeof req_info2); + req_info2.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2; + req_info2.image = img_obj->img; - /* VkMemoryRequirements2 */ - memset(&mem_reqs2, 0, sizeof mem_reqs2); - mem_reqs2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; - mem_reqs2.pNext = &ded_reqs; + /* VkMemoryRequirements2 */ + memset(&mem_reqs2, 0, sizeof mem_reqs2); + mem_reqs2.sType = VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2; + mem_reqs2.pNext = &ded_reqs; - vkGetImageMemoryRequirements2(ctx->dev, &req_info2, &mem_reqs2); - img_obj->mobj.mem = alloc_memory(ctx, + vkGetImageMemoryRequirements2(ctx->dev, &req_info2, &mem_reqs2); + img_obj->mobj.mem = alloc_memory(ctx, true, /* is_external = FIXME */ &mem_reqs2.memoryRequirements, ded_reqs.requiresDedicatedAllocation ? @@ -887,172 +912,282 @@ alloc_image_memory(struct vk_ctx *ctx, struct vk_image_obj *img_obj) mem_reqs2.memoryRequirements.memoryTypeBits & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - img_obj->mobj.mem_sz = mem_reqs2.memoryRequirements.size; - img_obj->mobj.dedicated = ded_reqs.requiresDedicatedAllocation; - if (img_obj->mobj.mem == VK_NULL_HANDLE) { - fprintf(stderr, "Failed to allocate image memory.\n"); - return false; - } + img_obj->mobj.mem_sz = mem_reqs2.memoryRequirements.size; + img_obj->mobj.dedicated = ded_reqs.requiresDedicatedAllocation; + if (img_obj->mobj.mem == VK_NULL_HANDLE) { + fprintf(stderr, "Failed to allocate image memory.\n"); + return false; + } - if (vkBindImageMemory(ctx->dev, img_obj->img, img_obj->mobj.mem, 0) != + if (vkBindImageMemory(ctx->dev, img_obj->img, img_obj->mobj.mem, 0) != VK_SUCCESS) { - fprintf(stderr, "Failed to bind image memory.\n"); - return false; - } + fprintf(stderr, "Failed to bind image memory.\n"); + return false; + } - return true; + return true; } static bool are_props_supported(struct vk_ctx *ctx, struct vk_image_props *props) { VkPhysicalDeviceExternalImageFormatInfo ext_img_fmt_info; - VkExternalImageFormatProperties ext_img_fmt_props; - - int i; - VkPhysicalDeviceImageFormatInfo2 img_fmt_info; - VkImageFormatProperties2 img_fmt_props; - VkImageUsageFlagBits all_flags[] = { - VK_IMAGE_USAGE_TRANSFER_SRC_BIT, - VK_IMAGE_USAGE_TRANSFER_DST_BIT, - VK_IMAGE_USAGE_SAMPLED_BIT, - VK_IMAGE_USAGE_STORAGE_BIT, - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, - /* Shouldn't be used together with COLOR, DEPTH_STENCIL - * attachment bits: - * VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, - * Provided by VK_EXT_fragment_density_map - * VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT, - * Provided by VK_NV_shading_rate_image - * VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, - * Provided by VK_KHR_fragment_shading_rate - * VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, - */ - }; - VkImageUsageFlagBits flags = 0; - - VkExternalMemoryFeatureFlagBits export_feature_flags = - VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT; - VkExternalMemoryHandleTypeFlagBits handle_type = - VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; - - memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info); - ext_img_fmt_info.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO; - ext_img_fmt_info.handleType = handle_type; - - memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props); - ext_img_fmt_props.sType = - VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES; - - memset(&img_fmt_props, 0, sizeof img_fmt_props); - img_fmt_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; - img_fmt_props.pNext = &ext_img_fmt_props; - - memset(&img_fmt_info, 0, sizeof img_fmt_info); - img_fmt_info.sType = - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2; - img_fmt_info.pNext = &ext_img_fmt_info; - img_fmt_info.format = props->format; - img_fmt_info.type = get_image_type(props->h, props->depth); - img_fmt_info.tiling = props->tiling; - - for (i = 0; i < ARRAY_SIZE(all_flags); i++) { - img_fmt_info.usage = all_flags[i]; - if (vkGetPhysicalDeviceImageFormatProperties2(ctx->pdev, - &img_fmt_info, - &img_fmt_props) == VK_SUCCESS) { - flags |= all_flags[i]; - } - } - - /* usage can't be null */ - if (flags) { - img_fmt_info.usage = flags; - } - else { - fprintf(stderr, "Unsupported Vulkan format properties: usage.\n"); - return false; - } - - if (vkGetPhysicalDeviceImageFormatProperties2 - (ctx->pdev, &img_fmt_info, &img_fmt_props) != VK_SUCCESS) { - fprintf(stderr, - "Unsupported Vulkan format properties.\n"); - return false; - } - props->usage = flags; - - if (props->need_export && - !(ext_img_fmt_props.externalMemoryProperties.externalMemoryFeatures - & export_feature_flags)) { - fprintf(stderr, "Unsupported Vulkan external memory features.\n"); - return false; - } - - return true; + VkExternalImageFormatProperties ext_img_fmt_props; + + int i; + VkPhysicalDeviceImageFormatInfo2 img_fmt_info; + VkImageFormatProperties2 img_fmt_props; + VkImageUsageFlagBits all_flags[] = { + VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + VK_IMAGE_USAGE_TRANSFER_DST_BIT, + VK_IMAGE_USAGE_SAMPLED_BIT, + VK_IMAGE_USAGE_STORAGE_BIT, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT, + /* Shouldn't be used together with COLOR, DEPTH_STENCIL + * attachment bits: + * VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, + * Provided by VK_EXT_fragment_density_map + * VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT, + * Provided by VK_NV_shading_rate_image + * VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, + * Provided by VK_KHR_fragment_shading_rate + * VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR, + */ + }; + VkImageUsageFlagBits flags = 0; + + VkExternalMemoryFeatureFlagBits export_feature_flags = + VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT; + VkExternalMemoryHandleTypeFlagBits handle_type = + VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + + memset(&ext_img_fmt_info, 0, sizeof ext_img_fmt_info); + ext_img_fmt_info.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO; + ext_img_fmt_info.handleType = handle_type; + + memset(&ext_img_fmt_props, 0, sizeof ext_img_fmt_props); + ext_img_fmt_props.sType = + VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES; + + memset(&img_fmt_props, 0, sizeof img_fmt_props); + img_fmt_props.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; + img_fmt_props.pNext = &ext_img_fmt_props; + + memset(&img_fmt_info, 0, sizeof img_fmt_info); + img_fmt_info.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2; + img_fmt_info.pNext = &ext_img_fmt_info; + img_fmt_info.format = props->format; + img_fmt_info.type = get_image_type(props->h, props->depth); + img_fmt_info.tiling = props->tiling; + + for (i = 0; i < ARRAY_SIZE(all_flags); i++) { + img_fmt_info.usage = all_flags[i]; + if (vkGetPhysicalDeviceImageFormatProperties2(ctx->pdev, + &img_fmt_info, + &img_fmt_props) == VK_SUCCESS) { + flags |= all_flags[i]; + } + } + + /* usage can't be null */ + if (flags) { + img_fmt_info.usage = flags; + } + else { + fprintf(stderr, "Unsupported Vulkan format properties: usage.\n"); + return false; + } + + if (vkGetPhysicalDeviceImageFormatProperties2 + (ctx->pdev, &img_fmt_info, &img_fmt_props) != VK_SUCCESS) { + fprintf(stderr, + "Unsupported Vulkan format properties.\n"); + return false; + } + props->usage = flags; + + if (props->need_export && + !(ext_img_fmt_props.externalMemoryProperties.externalMemoryFeatures + & export_feature_flags)) { + fprintf(stderr, "Unsupported Vulkan external memory features.\n"); + return false; + } + + return true; +} + +/* static swapchain / surf related functions */ + +static bool +sc_validate_surface(struct vk_ctx *ctx, + VkSurfaceKHR surf) +{ + VkBool32 supported; + if (!surf) { + fprintf(stderr, "No surface!\n"); + return false; + } + + if(vkGetPhysicalDeviceSurfaceSupportKHR(ctx->pdev, ctx->qfam_idx, surf, &supported) != VK_SUCCESS) { + fprintf(stderr, "Failed to validate surface.\n"); + return false; + } + + if (!supported) { + fprintf(stderr, "Invalid surface! Check if the surface with queue family index: %d supports presentation.\n", (int)ctx->qfam_idx); + return false; + } + + return true; +} + +static bool +sc_select_format(struct vk_ctx *ctx, + VkSurfaceKHR surf, + VkSwapchainCreateInfoKHR *s_info) +{ + VkSurfaceFormatKHR *formats; + uint32_t num_formats; + + if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats, 0) != VK_SUCCESS) { + fprintf(stderr, "Failed to get the number of surface formats.\n"); + return false; + } + + if (!num_formats) { + fprintf(stderr, "No surface formats found.\n"); + return false; + } + + formats = malloc(num_formats * sizeof *formats); + + if (vkGetPhysicalDeviceSurfaceFormatsKHR(ctx->pdev, surf, &num_formats, formats) != VK_SUCCESS) { + fprintf(stderr, "Failed to get the supported surface formats.\n"); + return false; + } + + if ((num_formats == 1) && (formats[0].format == VK_FORMAT_UNDEFINED)) { + s_info->imageFormat = VK_FORMAT_B8G8R8A8_UNORM; + s_info->imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + } else { + s_info->imageFormat = formats[0].format; + s_info->imageColorSpace = formats[0].colorSpace; + } + free(formats); + + return true; } +static bool +sc_select_supported_present_modes(struct vk_ctx *ctx, + VkSurfaceKHR surf, + bool has_vsync, + VkSwapchainCreateInfoKHR *s_info) +{ + VkPresentModeKHR *present_modes; + uint32_t num_present_modes; + int i; + + /* find supported present modes */ + if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, 0) != VK_SUCCESS || !num_present_modes) { + fprintf(stderr, "Failed to get the number of the supported presentation modes.\n"); + return false; + } + + present_modes = malloc(num_present_modes * sizeof *present_modes); + if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, present_modes) != VK_SUCCESS) { + fprintf(stderr, "Failed to get the number of supported presentation modes.\n"); + return false; + } + if (vkGetPhysicalDeviceSurfacePresentModesKHR(ctx->pdev, surf, &num_present_modes, + present_modes) != VK_SUCCESS) { + fprintf(stderr, "Failed to get the supported presentation modes.\n"); + return false; + } + + s_info->presentMode = VK_PRESENT_MODE_FIFO_KHR; + if (!has_vsync) { + for (i = 0; i < num_present_modes; i++) { + if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { + s_info->presentMode = present_modes[i]; + goto success; + } + if (present_modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) { + s_info->presentMode = present_modes[i]; + goto success; + } + } + } + +success: + free(present_modes); + return true; +} + +/* end of static functions */ + /* exposed Vulkan functions */ bool vk_init_ctx(struct vk_ctx *ctx) { - if ((ctx->inst = create_instance(enable_layers)) == VK_NULL_HANDLE) { - fprintf(stderr, "Failed to create Vulkan instance.\n"); - goto fail; - } + if ((ctx->inst = create_instance(enable_layers)) == VK_NULL_HANDLE) { + fprintf(stderr, "Failed to create Vulkan instance.\n"); + goto fail; + } - if ((ctx->pdev = select_physical_device(ctx->inst)) == VK_NULL_HANDLE) { - fprintf(stderr, "Failed to find suitable physical device.\n"); - goto fail; - } + if ((ctx->pdev = select_physical_device(ctx->inst)) == VK_NULL_HANDLE) { + fprintf(stderr, "Failed to find suitable physical device.\n"); + goto fail; + } - if ((ctx->dev = create_device(ctx, ctx->pdev)) == VK_NULL_HANDLE) { - fprintf(stderr, "Failed to create Vulkan device.\n"); - goto fail; - } + if ((ctx->dev = create_device(ctx, ctx->pdev)) == VK_NULL_HANDLE) { + fprintf(stderr, "Failed to create Vulkan device.\n"); + goto fail; + } - fill_uuid(ctx->pdev, ctx->deviceUUID, ctx->driverUUID); - return true; + fill_uuid(ctx->pdev, ctx->deviceUUID, ctx->driverUUID); + return true; fail: - vk_cleanup_ctx(ctx); - return false; + vk_cleanup_ctx(ctx); + return false; } bool vk_init_ctx_for_rendering(struct vk_ctx *ctx) { - if (!vk_init_ctx(ctx)) { - fprintf(stderr, "Failed to initialize Vulkan.\n"); - return false; - } + if (!vk_init_ctx(ctx)) { + fprintf(stderr, "Failed to initialize Vulkan.\n"); + return false; + } - if ((ctx->cmd_pool = create_cmd_pool(ctx)) == VK_NULL_HANDLE) { - fprintf(stderr, "Failed to create command pool.\n"); - goto fail; - } + if ((ctx->cmd_pool = create_cmd_pool(ctx)) == VK_NULL_HANDLE) { + fprintf(stderr, "Failed to create command pool.\n"); + goto fail; + } - if ((ctx->cmd_buf = create_cmd_buf(ctx->dev, ctx->cmd_pool)) == + if ((ctx->cmd_buf = create_cmd_buf(ctx->dev, ctx->cmd_pool)) == VK_NULL_HANDLE) { - fprintf(stderr, "Failed to create command buffer.\n"); - goto fail; - } + fprintf(stderr, "Failed to create command buffer.\n"); + goto fail; + } - vkGetDeviceQueue(ctx->dev, ctx->qfam_idx, 0, &ctx->queue); - if (!ctx->queue) { - fprintf(stderr, "Failed to get command queue.\n"); - goto fail; - } + vkGetDeviceQueue(ctx->dev, ctx->qfam_idx, 0, &ctx->queue); + if (!ctx->queue) { + fprintf(stderr, "Failed to get command queue.\n"); + goto fail; + } - return true; + return true; fail: - vk_cleanup_ctx(ctx); - return false; + vk_cleanup_ctx(ctx); + return false; } void @@ -1063,132 +1198,132 @@ vk_cleanup_ctx(struct vk_ctx *ctx) } if (ctx->cmd_buf != VK_NULL_HANDLE) { - vkResetCommandBuffer(ctx->cmd_buf, + vkResetCommandBuffer(ctx->cmd_buf, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); - vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, 1, &ctx->cmd_buf); - ctx->cmd_buf = VK_NULL_HANDLE; - } + vkFreeCommandBuffers(ctx->dev, ctx->cmd_pool, 1, &ctx->cmd_buf); + ctx->cmd_buf = VK_NULL_HANDLE; + } - if (ctx->cmd_pool != VK_NULL_HANDLE) { - vkResetCommandPool(ctx->dev, ctx->cmd_pool, + if (ctx->cmd_pool != VK_NULL_HANDLE) { + vkResetCommandPool(ctx->dev, ctx->cmd_pool, VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT); - vkDestroyCommandPool(ctx->dev, ctx->cmd_pool, 0); - ctx->cmd_pool = VK_NULL_HANDLE; - } - - if (ctx->dev != VK_NULL_HANDLE) { - vkDestroyDevice(ctx->dev, 0); - ctx->dev = VK_NULL_HANDLE; - } - - if (ctx->inst != VK_NULL_HANDLE) { - vkDestroyInstance(ctx->inst, 0); - ctx->inst = VK_NULL_HANDLE; - } + vkDestroyCommandPool(ctx->dev, ctx->cmd_pool, 0); + ctx->cmd_pool = VK_NULL_HANDLE; + } + + if (ctx->dev != VK_NULL_HANDLE) { + vkDestroyDevice(ctx->dev, 0); + ctx->dev = VK_NULL_HANDLE; + } + + if (ctx->inst != VK_NULL_HANDLE) { + vkDestroyInstance(ctx->inst, 0); + ctx->inst = VK_NULL_HANDLE; + } } bool vk_create_image(struct vk_ctx *ctx, - struct vk_image_props *props, - struct vk_image_obj *img) + struct vk_image_props *props, + struct vk_image_obj *img) { - VkImageCreateInfo img_info; - - memset(&img_info, 0, sizeof img_info); - img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - img_info.pNext = 0; /* do something if external */ - img_info.imageType = get_image_type(props->h, props->depth); - img_info.format = props->format; - img_info.extent.width = props->w; - img_info.extent.height = props->h; - img_info.extent.depth = props->depth; - img_info.mipLevels = props->num_levels ? props->num_levels : 1; - img_info.arrayLayers = props->num_layers ? + VkImageCreateInfo img_info; + + memset(&img_info, 0, sizeof img_info); + img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + img_info.pNext = 0; /* do something if external */ + img_info.imageType = get_image_type(props->h, props->depth); + img_info.format = props->format; + img_info.extent.width = props->w; + img_info.extent.height = props->h; + img_info.extent.depth = props->depth; + img_info.mipLevels = props->num_levels ? props->num_levels : 1; + img_info.arrayLayers = props->num_layers ? props->num_layers : VK_SAMPLE_COUNT_1_BIT; - img_info.samples = get_num_samples(props->num_samples); - img_info.tiling = props->tiling; - img_info.usage = props->usage ? + img_info.samples = get_num_samples(props->num_samples); + img_info.tiling = props->tiling; + img_info.usage = props->usage ? props->usage : VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS) - goto fail; + if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS) + goto fail; - if(!alloc_image_memory(ctx, img)) - goto fail; + if(!alloc_image_memory(ctx, img)) + goto fail; - return true; + return true; fail: - fprintf(stderr, "Failed to create external image.\n"); - vk_destroy_image(ctx, img); - img->img = VK_NULL_HANDLE; - img->mobj.mem = VK_NULL_HANDLE; - return false; + fprintf(stderr, "Failed to create external image.\n"); + vk_destroy_image(ctx, img); + img->img = VK_NULL_HANDLE; + img->mobj.mem = VK_NULL_HANDLE; + return false; } void vk_destroy_image(struct vk_ctx *ctx, struct vk_image_obj *img_obj) { - if (img_obj->img != VK_NULL_HANDLE) { - vkDestroyImage(ctx->dev, img_obj->img, 0); - img_obj->img = VK_NULL_HANDLE; - } - - if (img_obj->mobj.mem != VK_NULL_HANDLE) { - vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0); - img_obj->mobj.mem = VK_NULL_HANDLE; - } + if (img_obj->img != VK_NULL_HANDLE) { + vkDestroyImage(ctx->dev, img_obj->img, 0); + img_obj->img = VK_NULL_HANDLE; + } + + if (img_obj->mobj.mem != VK_NULL_HANDLE) { + vkFreeMemory(ctx->dev, img_obj->mobj.mem, 0); + img_obj->mobj.mem = VK_NULL_HANDLE; + } } bool vk_create_ext_image(struct vk_ctx *ctx, - struct vk_image_props *props, struct vk_image_obj *img) + struct vk_image_props *props, struct vk_image_obj *img) { - VkExternalMemoryImageCreateInfo ext_img_info; - VkImageCreateInfo img_info; - - memset(&ext_img_info, 0, sizeof ext_img_info); - ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; - ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; - - memset(&img_info, 0, sizeof img_info); - img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - img_info.pNext = &ext_img_info; - img_info.imageType = get_image_type(props->h, props->depth); - img_info.format = props->format; - img_info.extent.width = props->w; - img_info.extent.height = props->h; - img_info.extent.depth = props->depth; - img_info.mipLevels = props->num_levels ? props->num_levels : 1; - img_info.arrayLayers = props->num_layers ? props->num_layers : VK_SAMPLE_COUNT_1_BIT; - img_info.samples = get_num_samples(props->num_samples); - img_info.tiling = props->tiling; - img_info.usage = props->usage; - img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - /* issue 17 of EXT_external_objects - * Required in OpenGL implementations that support - * ARB_texture_view, OES_texture_view, EXT_texture_view, - * or OpenGL 4.3 and above. - */ - img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; - - if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS) - goto fail; - - if(!alloc_image_memory(ctx, img)) - goto fail; - - return true; + VkExternalMemoryImageCreateInfo ext_img_info; + VkImageCreateInfo img_info; + + memset(&ext_img_info, 0, sizeof ext_img_info); + ext_img_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO; + ext_img_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + + memset(&img_info, 0, sizeof img_info); + img_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + img_info.pNext = &ext_img_info; + img_info.imageType = get_image_type(props->h, props->depth); + img_info.format = props->format; + img_info.extent.width = props->w; + img_info.extent.height = props->h; + img_info.extent.depth = props->depth; + img_info.mipLevels = props->num_levels ? props->num_levels : 1; + img_info.arrayLayers = props->num_layers ? props->num_layers : VK_SAMPLE_COUNT_1_BIT; + img_info.samples = get_num_samples(props->num_samples); + img_info.tiling = props->tiling; + img_info.usage = props->usage; + img_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + img_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + /* issue 17 of EXT_external_objects + * Required in OpenGL implementations that support + * ARB_texture_view, OES_texture_view, EXT_texture_view, + * or OpenGL 4.3 and above. + */ + img_info.flags = VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + + if (vkCreateImage(ctx->dev, &img_info, 0, &img->img) != VK_SUCCESS) + goto fail; + + if(!alloc_image_memory(ctx, img)) + goto fail; + + return true; fail: - fprintf(stderr, "Failed to create external image.\n"); - vk_destroy_image(ctx, img); - img->img = VK_NULL_HANDLE; - img->mobj.mem = VK_NULL_HANDLE; - return false; + fprintf(stderr, "Failed to create external image.\n"); + vk_destroy_image(ctx, img); + img->img = VK_NULL_HANDLE; + img->mobj.mem = VK_NULL_HANDLE; + return false; } bool @@ -1206,25 +1341,25 @@ vk_fill_ext_image_props(struct vk_ctx *ctx, bool need_export, struct vk_image_props *props) { - props->w = w; - props->h = h; - props->depth = d; + props->w = w; + props->h = h; + props->depth = d; - props->num_samples = num_samples; - props->num_levels = num_levels; - props->num_layers = num_layers; + props->num_samples = num_samples; + props->num_levels = num_levels; + props->num_layers = num_layers; - props->format = format; - props->tiling = tiling; + props->format = format; + props->tiling = tiling; - props->in_layout = in_layout; - props->end_layout = end_layout; + props->in_layout = in_layout; + props->end_layout = end_layout; props->need_export = need_export; - if (!are_props_supported(ctx, props)) - return false; + if (!are_props_supported(ctx, props)) + return false; - return true; + return true; } bool @@ -1240,40 +1375,45 @@ vk_create_renderer(struct vk_ctx *ctx, struct vk_vertex_info *vert_info, struct vk_renderer *renderer) { - memset(&renderer->vertex_info, 0, sizeof renderer->vertex_info); - if (vert_info) - renderer->vertex_info = *vert_info; + memset(&renderer->vertex_info, 0, sizeof renderer->vertex_info); + if (vert_info) + renderer->vertex_info = *vert_info; + + if (!color_att || depth_att) { + fprintf(stderr, "Empty attachment.\n"); + goto fail; + } - renderer->renderpass = create_renderpass(ctx, &color_att->props, + renderer->renderpass = create_renderpass(ctx, &color_att->props, &depth_att->props); - if (renderer->renderpass == VK_NULL_HANDLE) - goto fail; + if (renderer->renderpass == VK_NULL_HANDLE) + goto fail; - create_framebuffer(ctx, color_att, depth_att, renderer); - if (renderer->fb == VK_NULL_HANDLE) - goto fail; + create_framebuffer(ctx, color_att, depth_att, renderer); + if (renderer->fb == VK_NULL_HANDLE) + goto fail; - renderer->vs = create_shader_module(ctx, vs_src, vs_size); - if (renderer->vs == VK_NULL_HANDLE) - goto fail; + renderer->vs = create_shader_module(ctx, vs_src, vs_size); + if (renderer->vs == VK_NULL_HANDLE) + goto fail; - renderer->fs = create_shader_module(ctx, fs_src, fs_size); - if (renderer->fs == VK_NULL_HANDLE) - goto fail; + renderer->fs = create_shader_module(ctx, fs_src, fs_size); + if (renderer->fs == VK_NULL_HANDLE) + goto fail; - create_pipeline(ctx, color_att->props.w, color_att->props.h, + create_pipeline(ctx, color_att->props.w, color_att->props.h, color_att->props.num_samples, enable_depth, enable_stencil, renderer); - if (renderer->pipeline == VK_NULL_HANDLE) - goto fail; + if (renderer->pipeline == VK_NULL_HANDLE) + goto fail; - return true; + return true; fail: - fprintf(stderr, "Failed to create graphics pipeline.\n"); - vk_destroy_renderer(ctx, renderer); - return false; + fprintf(stderr, "Failed to create graphics pipeline.\n"); + vk_destroy_renderer(ctx, renderer); + return false; } void @@ -1281,34 +1421,34 @@ vk_destroy_renderer(struct vk_ctx *ctx, struct vk_renderer *renderer) { if (renderer->renderpass != VK_NULL_HANDLE) { - vkDestroyRenderPass(ctx->dev, renderer->renderpass, 0); - renderer->renderpass = VK_NULL_HANDLE; - } - - if (renderer->vs != VK_NULL_HANDLE) { - vkDestroyShaderModule(ctx->dev, renderer->vs, 0); - renderer->vs = VK_NULL_HANDLE; - } - - if (renderer->fs != VK_NULL_HANDLE) { - vkDestroyShaderModule(ctx->dev, renderer->fs, 0); - renderer->fs = VK_NULL_HANDLE; - } - - if (renderer->fb != VK_NULL_HANDLE) { - vkDestroyFramebuffer(ctx->dev, renderer->fb, 0); - renderer->fb = VK_NULL_HANDLE; - } - - if (renderer->pipeline != VK_NULL_HANDLE) { - vkDestroyPipeline(ctx->dev, renderer->pipeline, 0); - renderer->pipeline = VK_NULL_HANDLE; - } - - if (renderer->pipeline_layout != VK_NULL_HANDLE) { - vkDestroyPipelineLayout(ctx->dev, renderer->pipeline_layout, 0); - renderer->pipeline_layout = VK_NULL_HANDLE; - } + vkDestroyRenderPass(ctx->dev, renderer->renderpass, 0); + renderer->renderpass = VK_NULL_HANDLE; + } + + if (renderer->vs != VK_NULL_HANDLE) { + vkDestroyShaderModule(ctx->dev, renderer->vs, 0); + renderer->vs = VK_NULL_HANDLE; + } + + if (renderer->fs != VK_NULL_HANDLE) { + vkDestroyShaderModule(ctx->dev, renderer->fs, 0); + renderer->fs = VK_NULL_HANDLE; + } + + if (renderer->fb != VK_NULL_HANDLE) { + vkDestroyFramebuffer(ctx->dev, renderer->fb, 0); + renderer->fb = VK_NULL_HANDLE; + } + + if (renderer->pipeline != VK_NULL_HANDLE) { + vkDestroyPipeline(ctx->dev, renderer->pipeline, 0); + renderer->pipeline = VK_NULL_HANDLE; + } + + if (renderer->pipeline_layout != VK_NULL_HANDLE) { + vkDestroyPipelineLayout(ctx->dev, renderer->pipeline_layout, 0); + renderer->pipeline_layout = VK_NULL_HANDLE; + } } bool @@ -1317,271 +1457,271 @@ vk_create_ext_buffer(struct vk_ctx *ctx, VkBufferUsageFlagBits usage, struct vk_buf *bo) { - VkExternalMemoryBufferCreateInfo ext_bo_info; + VkExternalMemoryBufferCreateInfo ext_bo_info; - memset(&ext_bo_info, 0, sizeof ext_bo_info); - ext_bo_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO; - ext_bo_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; + memset(&ext_bo_info, 0, sizeof ext_bo_info); + ext_bo_info.sType = VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO; + ext_bo_info.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR; - if (!vk_create_buffer(ctx, true, sz, usage, &ext_bo_info, bo)) { - fprintf(stderr, "Failed to allocate external buffer.\n"); - return false; - } + if (!vk_create_buffer(ctx, true, sz, usage, &ext_bo_info, bo)) { + fprintf(stderr, "Failed to allocate external buffer.\n"); + return false; + } - return true; + return true; } bool vk_create_buffer(struct vk_ctx *ctx, bool is_external, - uint32_t sz, - VkBufferUsageFlagBits usage, - void *pnext, - struct vk_buf *bo) + uint32_t sz, + VkBufferUsageFlagBits usage, + void *pnext, + struct vk_buf *bo) { - VkBufferCreateInfo buf_info; - VkMemoryRequirements mem_reqs; - - bo->mobj.mem = VK_NULL_HANDLE; - bo->buf = VK_NULL_HANDLE; - - /* VkBufferCreateInfo */ - memset(&buf_info, 0, sizeof buf_info); - buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - buf_info.size = sz; - buf_info.usage = usage; - buf_info.pNext = pnext; - buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - if (vkCreateBuffer(ctx->dev, &buf_info, 0, &bo->buf) != VK_SUCCESS) - goto fail; - - /* allocate buffer */ - vkGetBufferMemoryRequirements(ctx->dev, bo->buf, &mem_reqs); - /* VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the - * host cache management commands vkFlushMappedMemoryRanges and - * vkInvalidateMappedMemoryRanges are not needed to flush host - * writes to the device or make device writes visible to the - * host, respectively. */ - bo->mobj.mem = alloc_memory(ctx, is_external, &mem_reqs, VK_NULL_HANDLE, + VkBufferCreateInfo buf_info; + VkMemoryRequirements mem_reqs; + + bo->mobj.mem = VK_NULL_HANDLE; + bo->buf = VK_NULL_HANDLE; + + /* VkBufferCreateInfo */ + memset(&buf_info, 0, sizeof buf_info); + buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + buf_info.size = sz; + buf_info.usage = usage; + buf_info.pNext = pnext; + buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + if (vkCreateBuffer(ctx->dev, &buf_info, 0, &bo->buf) != VK_SUCCESS) + goto fail; + + /* allocate buffer */ + vkGetBufferMemoryRequirements(ctx->dev, bo->buf, &mem_reqs); + /* VK_MEMORY_PROPERTY_HOST_COHERENT_BIT bit specifies that the + * host cache management commands vkFlushMappedMemoryRanges and + * vkInvalidateMappedMemoryRanges are not needed to flush host + * writes to the device or make device writes visible to the + * host, respectively. */ + bo->mobj.mem = alloc_memory(ctx, is_external, &mem_reqs, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); - if (bo->mobj.mem == VK_NULL_HANDLE) - goto fail; + if (bo->mobj.mem == VK_NULL_HANDLE) + goto fail; - bo->mobj.mem_sz = sz; + bo->mobj.mem_sz = sz; - if (vkBindBufferMemory(ctx->dev, bo->buf, bo->mobj.mem, 0) != VK_SUCCESS) { - fprintf(stderr, "Failed to bind buffer memory.\n"); - goto fail; - } + if (vkBindBufferMemory(ctx->dev, bo->buf, bo->mobj.mem, 0) != VK_SUCCESS) { + fprintf(stderr, "Failed to bind buffer memory.\n"); + goto fail; + } - return true; + return true; fail: - fprintf(stderr, "Failed to allocate buffer.\n"); - vk_destroy_buffer(ctx, bo); - return false; + fprintf(stderr, "Failed to allocate buffer.\n"); + vk_destroy_buffer(ctx, bo); + return false; } bool vk_update_buffer_data(struct vk_ctx *ctx, - void *data, - uint32_t data_sz, - struct vk_buf *bo) + void *data, + uint32_t data_sz, + struct vk_buf *bo) { - void *map; + void *map; - if (vkMapMemory(ctx->dev, bo->mobj.mem, 0, data_sz, 0, &map) != VK_SUCCESS) { - fprintf(stderr, "Failed to map buffer memory.\n"); - goto fail; - } + if (vkMapMemory(ctx->dev, bo->mobj.mem, 0, data_sz, 0, &map) != VK_SUCCESS) { + fprintf(stderr, "Failed to map buffer memory.\n"); + goto fail; + } - memcpy(map, data, data_sz); + memcpy(map, data, data_sz); - vkUnmapMemory(ctx->dev, bo->mobj.mem); - return true; + vkUnmapMemory(ctx->dev, bo->mobj.mem); + return true; fail: - fprintf(stderr, "Failed to update buffer data. Destroying the buffer.\n"); - vk_destroy_buffer(ctx, bo); + fprintf(stderr, "Failed to update buffer data. Destroying the buffer.\n"); + vk_destroy_buffer(ctx, bo); - return false; + return false; } void vk_destroy_buffer(struct vk_ctx *ctx, - struct vk_buf *bo) + struct vk_buf *bo) { - if (bo->buf != VK_NULL_HANDLE) - vkDestroyBuffer(ctx->dev, bo->buf, 0); + if (bo->buf != VK_NULL_HANDLE) + vkDestroyBuffer(ctx->dev, bo->buf, 0); - if (bo->mobj.mem != VK_NULL_HANDLE) - vkFreeMemory(ctx->dev, bo->mobj.mem, 0); + if (bo->mobj.mem != VK_NULL_HANDLE) + vkFreeMemory(ctx->dev, bo->mobj.mem, 0); - bo->mobj.mem_sz = 0; - bo->buf = VK_NULL_HANDLE; - bo->mobj.mem = VK_NULL_HANDLE; + bo->mobj.mem_sz = 0; + bo->buf = VK_NULL_HANDLE; + bo->mobj.mem = VK_NULL_HANDLE; } void vk_draw(struct vk_ctx *ctx, - struct vk_buf *vbo, - struct vk_renderer *renderer, - float *vk_fb_color, - uint32_t vk_fb_color_count, - struct vk_semaphores *semaphores, - struct vk_image_att *attachments, - uint32_t n_attachments, - float x, float y, - float w, float h) + struct vk_buf *vbo, + struct vk_renderer *renderer, + float *vk_fb_color, + uint32_t vk_fb_color_count, + struct vk_semaphores *semaphores, + struct vk_image_att *attachments, + uint32_t n_attachments, + float x, float y, + float w, float h) { - VkCommandBufferBeginInfo cmd_begin_info; - VkRenderPassBeginInfo rp_begin_info; - VkRect2D rp_area; - VkClearValue clear_values[2]; - VkSubmitInfo submit_info; - VkDeviceSize offsets[] = {0}; - VkPipelineStageFlagBits stage_flags; - struct vk_dims img_size; - - assert(vk_fb_color_count == 4); - - /* VkCommandBufferBeginInfo */ - memset(&cmd_begin_info, 0, sizeof cmd_begin_info); - cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; - - /* VkRect2D render area */ - memset(&rp_area, 0, sizeof rp_area); - rp_area.extent.width = (uint32_t)w; - rp_area.extent.height = (uint32_t)h; - rp_area.offset.x = x; - rp_area.offset.y = y; - - /* VkClearValue */ - memset(&clear_values[0], 0, sizeof clear_values[0]); - clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */ - clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */ - clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */ - clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */ - - memset(&clear_values[1], 0, sizeof clear_values[1]); - clear_values[1].depthStencil.depth = 1.0; - clear_values[1].depthStencil.stencil = 0; - - /* VkRenderPassBeginInfo */ - memset(&rp_begin_info, 0, sizeof rp_begin_info); - rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - rp_begin_info.renderPass = renderer->renderpass; - rp_begin_info.framebuffer = renderer->fb; - rp_begin_info.renderArea = rp_area; - rp_begin_info.clearValueCount = 2; - rp_begin_info.pClearValues = clear_values; - - /* VkSubmitInfo */ - stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - - memset(&submit_info, 0, sizeof submit_info); - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &ctx->cmd_buf; - - /* semaphores */ - if (semaphores) { - assert(semaphores->frame_ready); - assert(semaphores->frame_done); - - submit_info.pWaitDstStageMask = &stage_flags; - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = &semaphores->frame_done; - - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = &semaphores->frame_ready; - } - - vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info); - vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE); - - viewport.x = x; - viewport.y = y; - viewport.width = w; - viewport.height = h; - - scissor.offset.x = x; - scissor.offset.y = y; - scissor.extent.width = w; - scissor.extent.height = h; - - vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport); - vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor); - - img_size.w = (float)w; - img_size.h = (float)h; - vkCmdPushConstants(ctx->cmd_buf, - renderer->pipeline_layout, - VK_SHADER_STAGE_FRAGMENT_BIT, - 0, sizeof (struct vk_dims), - &img_size); - - if (vbo) { - vkCmdBindVertexBuffers(ctx->cmd_buf, 0, 1, &vbo->buf, offsets); - } - vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline); - - int num_vertices = vbo ? renderer->vertex_info.num_verts : 4; - vkCmdDraw(ctx->cmd_buf, num_vertices, 1, 0, 0); - vkCmdEndRenderPass(ctx->cmd_buf); + VkCommandBufferBeginInfo cmd_begin_info; + VkRenderPassBeginInfo rp_begin_info; + VkRect2D rp_area; + VkClearValue clear_values[2]; + VkSubmitInfo submit_info; + VkDeviceSize offsets[] = {0}; + VkPipelineStageFlagBits stage_flags; + struct vk_dims img_size; + + assert(vk_fb_color_count == 4); + + /* VkCommandBufferBeginInfo */ + memset(&cmd_begin_info, 0, sizeof cmd_begin_info); + cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + + /* VkRect2D render area */ + memset(&rp_area, 0, sizeof rp_area); + rp_area.extent.width = (uint32_t)w; + rp_area.extent.height = (uint32_t)h; + rp_area.offset.x = x; + rp_area.offset.y = y; + + /* VkClearValue */ + memset(&clear_values[0], 0, sizeof clear_values[0]); + clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */ + clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */ + clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */ + clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */ + + memset(&clear_values[1], 0, sizeof clear_values[1]); + clear_values[1].depthStencil.depth = 1.0; + clear_values[1].depthStencil.stencil = 0; + + /* VkRenderPassBeginInfo */ + memset(&rp_begin_info, 0, sizeof rp_begin_info); + rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rp_begin_info.renderPass = renderer->renderpass; + rp_begin_info.framebuffer = renderer->fb; + rp_begin_info.renderArea = rp_area; + rp_begin_info.clearValueCount = 2; + rp_begin_info.pClearValues = clear_values; + + /* VkSubmitInfo */ + stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + + memset(&submit_info, 0, sizeof submit_info); + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &ctx->cmd_buf; + + /* semaphores */ + if (semaphores) { + assert(semaphores->frame_ready); + assert(semaphores->frame_done); + + submit_info.pWaitDstStageMask = &stage_flags; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &semaphores->frame_done; + + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &semaphores->frame_ready; + } + + vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info); + vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE); + + viewport.x = x; + viewport.y = y; + viewport.width = w; + viewport.height = h; + + scissor.offset.x = x; + scissor.offset.y = y; + scissor.extent.width = w; + scissor.extent.height = h; + + vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport); + vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor); + + img_size.w = (float)w; + img_size.h = (float)h; + vkCmdPushConstants(ctx->cmd_buf, + renderer->pipeline_layout, + VK_SHADER_STAGE_FRAGMENT_BIT, + 0, sizeof (struct vk_dims), + &img_size); + + if (vbo) { + vkCmdBindVertexBuffers(ctx->cmd_buf, 0, 1, &vbo->buf, offsets); + } + vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline); + + int num_vertices = vbo ? renderer->vertex_info.num_verts : 4; + vkCmdDraw(ctx->cmd_buf, num_vertices, 1, 0, 0); + vkCmdEndRenderPass(ctx->cmd_buf); if (attachments) { - VkImageMemoryBarrier *barriers = - calloc(n_attachments, sizeof(VkImageMemoryBarrier)); - VkImageMemoryBarrier *barrier = barriers; - for (uint32_t n = 0; n < n_attachments; n++, barrier++) { - struct vk_image_att *att = &attachments[n]; - VkImageAspectFlagBits depth_stencil_flags = - get_aspect_from_depth_format(att->props.format); - bool is_depth = (depth_stencil_flags != 0); - - /* Insert barrier to mark ownership transfer. */ - barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier->oldLayout = is_depth ? - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL; - barrier->srcAccessMask = get_access_mask(barrier->oldLayout); - barrier->dstAccessMask = get_access_mask(barrier->newLayout); - barrier->srcQueueFamilyIndex = ctx->qfam_idx; - barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL; - barrier->image = att->obj.img; - barrier->subresourceRange.aspectMask = is_depth ? - depth_stencil_flags : - VK_IMAGE_ASPECT_COLOR_BIT; - barrier->subresourceRange.baseMipLevel = 0; - barrier->subresourceRange.levelCount = 1; - barrier->subresourceRange.baseArrayLayer = 0; - barrier->subresourceRange.layerCount = 1; - } - - vkCmdPipelineBarrier(ctx->cmd_buf, - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - 0, - 0, NULL, - 0, NULL, - n_attachments, barriers); - free(barriers); - } - - vkEndCommandBuffer(ctx->cmd_buf); - - if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) { - fprintf(stderr, "Failed to submit queue.\n"); - } - - if (!semaphores) - vkQueueWaitIdle(ctx->queue); + VkImageMemoryBarrier *barriers = + calloc(n_attachments, sizeof(VkImageMemoryBarrier)); + VkImageMemoryBarrier *barrier = barriers; + for (uint32_t n = 0; n < n_attachments; n++, barrier++) { + struct vk_image_att *att = &attachments[n]; + VkImageAspectFlagBits depth_stencil_flags = + get_aspect_from_depth_format(att->props.format); + bool is_depth = (depth_stencil_flags != 0); + + /* Insert barrier to mark ownership transfer. */ + barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier->oldLayout = is_depth ? + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL; + barrier->srcAccessMask = get_access_mask(barrier->oldLayout); + barrier->dstAccessMask = get_access_mask(barrier->newLayout); + barrier->srcQueueFamilyIndex = ctx->qfam_idx; + barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL; + barrier->image = att->obj.img; + barrier->subresourceRange.aspectMask = is_depth ? + depth_stencil_flags : + VK_IMAGE_ASPECT_COLOR_BIT; + barrier->subresourceRange.baseMipLevel = 0; + barrier->subresourceRange.levelCount = 1; + barrier->subresourceRange.baseArrayLayer = 0; + barrier->subresourceRange.layerCount = 1; + } + + vkCmdPipelineBarrier(ctx->cmd_buf, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, + 0, NULL, + 0, NULL, + n_attachments, barriers); + free(barriers); + } + + vkEndCommandBuffer(ctx->cmd_buf); + + if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) { + fprintf(stderr, "Failed to submit queue.\n"); + } + + if (!semaphores) + vkQueueWaitIdle(ctx->queue); } void @@ -1597,194 +1737,239 @@ vk_clear_color(struct vk_ctx *ctx, float x, float y, float w, float h) { - VkCommandBufferBeginInfo cmd_begin_info; - VkRenderPassBeginInfo rp_begin_info; - VkRect2D rp_area; - VkClearValue clear_values[2]; - VkSubmitInfo submit_info; - VkPipelineStageFlagBits stage_flags; - VkImageSubresourceRange img_range; - - assert(vk_fb_color_count == 4); - - /* VkCommandBufferBeginInfo */ - memset(&cmd_begin_info, 0, sizeof cmd_begin_info); - cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - /* VkRect2D render area */ - memset(&rp_area, 0, sizeof rp_area); - rp_area.extent.width = (uint32_t)w; - rp_area.extent.height = (uint32_t)h; - rp_area.offset.x = x; - rp_area.offset.y = y; - - /* VkClearValue */ - memset(&clear_values[0], 0, sizeof clear_values[0]); - clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */ - clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */ - clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */ - clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */ - - memset(&clear_values[1], 0, sizeof clear_values[1]); - clear_values[1].depthStencil.depth = 1.0; - clear_values[1].depthStencil.stencil = 0; - - /* VkRenderPassBeginInfo */ - memset(&rp_begin_info, 0, sizeof rp_begin_info); - rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - rp_begin_info.renderPass = renderer->renderpass; - rp_begin_info.framebuffer = renderer->fb; - rp_begin_info.renderArea = rp_area; - rp_begin_info.clearValueCount = 2; - rp_begin_info.pClearValues = clear_values; - - /* VkSubmitInfo */ - stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; - - memset(&submit_info, 0, sizeof submit_info); - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &ctx->cmd_buf; + VkCommandBufferBeginInfo cmd_begin_info; + VkRenderPassBeginInfo rp_begin_info; + VkRect2D rp_area; + VkClearValue clear_values[2]; + VkSubmitInfo submit_info; + VkPipelineStageFlagBits stage_flags; + VkImageSubresourceRange img_range; + + assert(vk_fb_color_count == 4); + + /* VkCommandBufferBeginInfo */ + memset(&cmd_begin_info, 0, sizeof cmd_begin_info); + cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + /* VkRect2D render area */ + memset(&rp_area, 0, sizeof rp_area); + rp_area.extent.width = (uint32_t)w; + rp_area.extent.height = (uint32_t)h; + rp_area.offset.x = x; + rp_area.offset.y = y; + + /* VkClearValue */ + memset(&clear_values[0], 0, sizeof clear_values[0]); + clear_values[0].color.float32[0] = vk_fb_color[0]; /* red */ + clear_values[0].color.float32[1] = vk_fb_color[1]; /* green */ + clear_values[0].color.float32[2] = vk_fb_color[2]; /* blue */ + clear_values[0].color.float32[3] = vk_fb_color[3]; /* alpha */ + + memset(&clear_values[1], 0, sizeof clear_values[1]); + clear_values[1].depthStencil.depth = 1.0; + clear_values[1].depthStencil.stencil = 0; + + /* VkRenderPassBeginInfo */ + memset(&rp_begin_info, 0, sizeof rp_begin_info); + rp_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rp_begin_info.renderPass = renderer->renderpass; + rp_begin_info.framebuffer = renderer->fb; + rp_begin_info.renderArea = rp_area; + rp_begin_info.clearValueCount = 2; + rp_begin_info.pClearValues = clear_values; + + /* VkSubmitInfo */ + stage_flags = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT; + + memset(&submit_info, 0, sizeof submit_info); + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &ctx->cmd_buf; /* FIXME */ - if (has_wait) { - submit_info.pWaitDstStageMask = &stage_flags; - submit_info.waitSemaphoreCount = 1; - submit_info.pWaitSemaphores = &semaphores->frame_done; - } - - if (has_signal) { - submit_info.signalSemaphoreCount = 1; - submit_info.pSignalSemaphores = &semaphores->frame_ready; - } - - img_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - img_range.baseMipLevel = 0; - img_range.levelCount = 1; - img_range.baseArrayLayer = 0; - img_range.layerCount = 1; - - vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info); - vk_transition_image_layout(&attachments[0], - ctx->cmd_buf, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_GENERAL, - VK_QUEUE_FAMILY_EXTERNAL, - ctx->qfam_idx); - vkCmdClearColorImage(ctx->cmd_buf, - attachments[0].obj.img, - VK_IMAGE_LAYOUT_GENERAL, - &clear_values[0].color, - 1, - &img_range); - - vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE); - - viewport.x = x; - viewport.y = y; - viewport.width = w; - viewport.height = h; - - scissor.offset.x = x; - scissor.offset.y = y; - scissor.extent.width = w; - scissor.extent.height = h; - - vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport); - vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor); - - vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline); - - vkCmdEndRenderPass(ctx->cmd_buf); - - if (attachments) { - VkImageMemoryBarrier *barriers = - calloc(n_attachments, sizeof(VkImageMemoryBarrier)); - VkImageMemoryBarrier *barrier = barriers; - - for (uint32_t n = 0; n < n_attachments; n++, barrier++) { - struct vk_image_att *att = &attachments[n]; - - /* Insert barrier to mark ownership transfer. */ - barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - - bool is_depth = - get_aspect_from_depth_format(att->props.format) != VK_NULL_HANDLE; - - barrier->oldLayout = is_depth ? - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL; - barrier->srcAccessMask = get_access_mask(barrier->oldLayout); - barrier->dstAccessMask = get_access_mask(barrier->newLayout); - barrier->srcQueueFamilyIndex = ctx->qfam_idx; - barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL; - barrier->image = att->obj.img; - barrier->subresourceRange.aspectMask = is_depth ? - VK_IMAGE_ASPECT_DEPTH_BIT : - VK_IMAGE_ASPECT_COLOR_BIT; - barrier->subresourceRange.baseMipLevel = 0; - barrier->subresourceRange.levelCount = 1; - barrier->subresourceRange.baseArrayLayer = 0; - barrier->subresourceRange.layerCount = 1; - } - - vkCmdPipelineBarrier(ctx->cmd_buf, - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, - VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, - 0, - 0, NULL, - 0, NULL, - n_attachments, barriers); - free(barriers); - } - - vkEndCommandBuffer(ctx->cmd_buf); - - if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) { - fprintf(stderr, "Failed to submit queue.\n"); - } - - if (!semaphores && !has_wait && !has_signal) - vkQueueWaitIdle(ctx->queue); + if (has_wait) { + submit_info.pWaitDstStageMask = &stage_flags; + submit_info.waitSemaphoreCount = 1; + submit_info.pWaitSemaphores = &semaphores->frame_done; + } + + if (has_signal) { + submit_info.signalSemaphoreCount = 1; + submit_info.pSignalSemaphores = &semaphores->frame_ready; + } + + img_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + img_range.baseMipLevel = 0; + img_range.levelCount = 1; + img_range.baseArrayLayer = 0; + img_range.layerCount = 1; + + vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info); + vk_transition_image_layout(&attachments[0], + ctx->cmd_buf, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_GENERAL, + VK_QUEUE_FAMILY_EXTERNAL, + ctx->qfam_idx); + vkCmdClearColorImage(ctx->cmd_buf, + attachments[0].obj.img, + VK_IMAGE_LAYOUT_GENERAL, + &clear_values[0].color, + 1, + &img_range); + + vkCmdBeginRenderPass(ctx->cmd_buf, &rp_begin_info, VK_SUBPASS_CONTENTS_INLINE); + + viewport.x = x; + viewport.y = y; + viewport.width = w; + viewport.height = h; + + scissor.offset.x = x; + scissor.offset.y = y; + scissor.extent.width = w; + scissor.extent.height = h; + + vkCmdSetViewport(ctx->cmd_buf, 0, 1, &viewport); + vkCmdSetScissor(ctx->cmd_buf, 0, 1, &scissor); + + vkCmdBindPipeline(ctx->cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, renderer->pipeline); + + vkCmdEndRenderPass(ctx->cmd_buf); + + if (attachments) { + VkImageMemoryBarrier *barriers = + calloc(n_attachments, sizeof(VkImageMemoryBarrier)); + VkImageMemoryBarrier *barrier = barriers; + + for (uint32_t n = 0; n < n_attachments; n++, barrier++) { + struct vk_image_att *att = &attachments[n]; + + /* Insert barrier to mark ownership transfer. */ + barrier->sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + + bool is_depth = + get_aspect_from_depth_format(att->props.format) != VK_NULL_HANDLE; + + barrier->oldLayout = is_depth ? + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL : + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barrier->newLayout = VK_IMAGE_LAYOUT_GENERAL; + barrier->srcAccessMask = get_access_mask(barrier->oldLayout); + barrier->dstAccessMask = get_access_mask(barrier->newLayout); + barrier->srcQueueFamilyIndex = ctx->qfam_idx; + barrier->dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL; + barrier->image = att->obj.img; + barrier->subresourceRange.aspectMask = is_depth ? + VK_IMAGE_ASPECT_DEPTH_BIT : + VK_IMAGE_ASPECT_COLOR_BIT; + barrier->subresourceRange.baseMipLevel = 0; + barrier->subresourceRange.levelCount = 1; + barrier->subresourceRange.baseArrayLayer = 0; + barrier->subresourceRange.layerCount = 1; + } + + vkCmdPipelineBarrier(ctx->cmd_buf, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, + 0, + 0, NULL, + 0, NULL, + n_attachments, barriers); + free(barriers); + } + + vkEndCommandBuffer(ctx->cmd_buf); + + if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) { + fprintf(stderr, "Failed to submit queue.\n"); + } + + if (!semaphores && !has_wait && !has_signal) + vkQueueWaitIdle(ctx->queue); } bool vk_create_swapchain(struct vk_ctx *ctx, int width, int height, - int num_qfam, + bool has_vsync, + VkSurfaceKHR surf, + struct vk_swapchain *old_swapchain, struct vk_swapchain *swapchain) { + VkSurfaceCapabilitiesKHR surf_cap; VkSwapchainCreateInfoKHR s_info; VkExtent2D extent; + VkImageSubresourceRange sr; + VkImage *s_images; + int i; - extent.width = width; - extent.height = height; + if (!sc_validate_surface(ctx, surf)) { + fprintf(stderr, "Failed to validate surface!\n"); + return false; + } - memset(&s_info, 0, sizeof s_info); + /* get pdevice capabilities + * will need that to determine the swapchain number of images + */ + if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(ctx->pdev, surf, &surf_cap) != VK_SUCCESS) { + fprintf(stderr, "Failed to query surface capabilities.\n"); + return false; + } + + /* allocate and init an empty struct vk_swapchain */ + swapchain = malloc(sizeof *swapchain); + memset(swapchain, 0, sizeof *swapchain); + + swapchain->surface = surf; + memset(&s_info, 0, sizeof s_info); s_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; s_info.flags = 0; - s_info.surface = swapchain->surface; - s_info.minImageCount = 2; - s_info.imageFormat = VK_FORMAT_R32G32B32A32_SFLOAT; - s_info.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + /* surface format */ + if (!sc_select_format(ctx, surf, &s_info)) { + fprintf(stderr, "Failed to determine the surface format.\n"); + return false; + } + s_info.surface = surf; + + /* number of images */ + s_info.minImageCount = surf_cap.minImageCount; + /* swapchain images dims */ + { + extent.width = width; + extent.height = height; + } + if (!sc_select_supported_present_modes(ctx, surf, has_vsync, &s_info)) { + s_info.presentMode = VK_PRESENT_MODE_FIFO_KHR; + } s_info.imageExtent = extent; s_info.imageArrayLayers = 1; - s_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT; - - s_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - s_info.queueFamilyIndexCount = num_qfam; /* how many queue families */ - - s_info.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + /* enable color attachment bit and transfer src and transfer dst bits + * too if they are supported */ + { + s_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + if (surf_cap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) + s_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + if (surf_cap.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) + s_info.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } + s_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + s_info.queueFamilyIndexCount = ctx->qfam_idx; + + /* we might want to use this function when we recreate the swapchain too */ + s_info.preTransform = surf_cap.supportedTransforms & + VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ? + VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : + surf_cap.currentTransform; + + /* we could also write a sc_select_supported_composite_alpha + * later but VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR is universally + * supported */ s_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - s_info.presentMode = VK_PRESENT_MODE_FIFO_KHR; s_info.clipped = VK_TRUE; - s_info.oldSwapchain = VK_NULL_HANDLE; + s_info.oldSwapchain = old_swapchain ? old_swapchain->swapchain : 0; if (vkCreateSwapchainKHR(ctx->dev, &s_info, 0, &swapchain->swapchain) != VK_SUCCESS) { @@ -1792,6 +1977,55 @@ vk_create_swapchain(struct vk_ctx *ctx, return false; } + /* if an existing swapchain is recreated we need to destroy + * the old swapchain and clean up the images */ + if (old_swapchain) { + for (i = 0; i < old_swapchain->num_images; i++) { + vkDestroyImageView(ctx->dev, old_swapchain->images[i].image_view, 0); + } + vk_destroy_swapchain(ctx, old_swapchain); + } + + /* get the number of swapchain images and the swapchain images + * and store the new swapchain images + */ + vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_images, 0); + printf("number of swapchain images: %d\n", swapchain->num_images); + + /* create images */ + s_images = malloc(swapchain->num_images * sizeof(VkImage)); + vkGetSwapchainImagesKHR(ctx->dev, swapchain->swapchain, &swapchain->num_images, s_images); + + swapchain->image_fmt = s_info.imageFormat; + swapchain->images = malloc(swapchain->num_images * sizeof(struct vk_swap_image_obj)); + + memset(&sr, 0, sizeof sr); + sr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + sr.levelCount = 1; + sr.layerCount = 1; + + for (i = 0; i < swapchain->num_images; i++) { + swapchain->images[i].image = s_images[i]; + if (!(create_image_view(ctx, + swapchain->images[i].image, + VK_IMAGE_VIEW_TYPE_2D, + swapchain->image_fmt, + sr, + true, + &swapchain->images[i].image_view))) { + fprintf(stderr, "Fail to create an image view from the swapchain image: i=%d\n", i); + break; + } + if (i < swapchain->num_images - 1) { + int j; + for (j = 0; j < i; j++) { + vkDestroyImageView(ctx->dev, swapchain->images[i].image_view, 0); + } + return false; + } + } + + free(s_images); return true; } @@ -1801,6 +2035,9 @@ vk_destroy_swapchain(struct vk_ctx *ctx, { vkDestroySwapchainKHR(ctx->dev, swapchain->swapchain, 0); vkDestroySurfaceKHR(ctx->inst, swapchain->surface, 0); + + free(swapchain); + swapchain = 0; } void @@ -1809,151 +2046,154 @@ vk_copy_image_to_buffer(struct vk_ctx *ctx, struct vk_buf *dst_bo, float w, float h) { - VkCommandBufferBeginInfo cmd_begin_info; - VkSubmitInfo submit_info; - VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(src_img->props.format); - - /* VkCommandBufferBeginInfo */ - memset(&cmd_begin_info, 0, sizeof cmd_begin_info); - cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - memset(&submit_info, 0, sizeof submit_info); - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &ctx->cmd_buf; - - vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info); - if (src_img->props.end_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && dst_bo) { - vk_transition_image_layout(src_img, + VkCommandBufferBeginInfo cmd_begin_info; + VkSubmitInfo submit_info; + VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(src_img->props.format); + + /* VkCommandBufferBeginInfo */ + memset(&cmd_begin_info, 0, sizeof cmd_begin_info); + cmd_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmd_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + memset(&submit_info, 0, sizeof submit_info); + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &ctx->cmd_buf; + + vkBeginCommandBuffer(ctx->cmd_buf, &cmd_begin_info); + if (src_img->props.end_layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && dst_bo) { + vk_transition_image_layout(src_img, ctx->cmd_buf, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_QUEUE_FAMILY_EXTERNAL, ctx->qfam_idx); - /* copy image to buf */ - VkBufferImageCopy copy_region = { - .bufferOffset = 0, - .bufferRowLength = w, - .bufferImageHeight = h, - .imageSubresource = { - .aspectMask = aspect_mask ? aspect_mask + /* copy image to buf */ + VkBufferImageCopy copy_region = { + .bufferOffset = 0, + .bufferRowLength = w, + .bufferImageHeight = h, + .imageSubresource = { + .aspectMask = aspect_mask ? aspect_mask : VK_IMAGE_ASPECT_COLOR_BIT, - .mipLevel = 0, - .baseArrayLayer = 0, - .layerCount = 1, - }, - .imageOffset = { 0, 0, 0 }, - .imageExtent = { w, h, 1 } + .mipLevel = 0, + .baseArrayLayer = 0, + .layerCount = 1, + }, + .imageOffset = { 0, 0, 0 }, + .imageExtent = { w, h, 1 } }; - vkCmdCopyImageToBuffer(ctx->cmd_buf, + vkCmdCopyImageToBuffer(ctx->cmd_buf, src_img->obj.img, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, dst_bo->buf, 1, ©_region); - vk_transition_image_layout(src_img, + vk_transition_image_layout(src_img, ctx->cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_QUEUE_FAMILY_EXTERNAL, ctx->qfam_idx); - VkBufferMemoryBarrier write_finish_buffer_memory_barrier = { - .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, - .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, - .dstAccessMask = VK_ACCESS_HOST_READ_BIT, - .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL, - .dstQueueFamilyIndex = ctx->qfam_idx, - .buffer = dst_bo->buf, - .offset = 0, - .size = VK_WHOLE_SIZE - }; - - vkCmdPipelineBarrier(ctx->cmd_buf, + VkBufferMemoryBarrier write_finish_buffer_memory_barrier = { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_HOST_READ_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL, + .dstQueueFamilyIndex = ctx->qfam_idx, + .buffer = dst_bo->buf, + .offset = 0, + .size = VK_WHOLE_SIZE + }; + + vkCmdPipelineBarrier(ctx->cmd_buf, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_HOST_BIT, (VkDependencyFlags) 0, 0, NULL, 1, &write_finish_buffer_memory_barrier, 0, NULL); } - vkEndCommandBuffer(ctx->cmd_buf); + vkEndCommandBuffer(ctx->cmd_buf); - if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) { - fprintf(stderr, "Failed to submit queue.\n"); - } - vkQueueWaitIdle(ctx->queue); + if (vkQueueSubmit(ctx->queue, 1, &submit_info, VK_NULL_HANDLE) != VK_SUCCESS) { + fprintf(stderr, "Failed to submit queue.\n"); + } + vkQueueWaitIdle(ctx->queue); } // FIXME: external bool vk_create_semaphores(struct vk_ctx *ctx, - struct vk_semaphores *semaphores) + bool is_external, + struct vk_semaphores *semaphores) { - VkSemaphoreCreateInfo sema_info; - VkExportSemaphoreCreateInfo exp_sema_info; - - /* VkExportSemaphoreCreateInfo */ - memset(&exp_sema_info, 0, sizeof exp_sema_info); - exp_sema_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO; - exp_sema_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; - - /* VkSemaphoreCreateInfo */ - memset(&sema_info, 0, sizeof sema_info); - sema_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - sema_info.pNext = &exp_sema_info; - - if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_ready) != VK_SUCCESS) { - fprintf(stderr, "Failed to create semaphore frame_ready.\n"); - return false; - } - - if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_done) != VK_SUCCESS) { - fprintf(stderr, "Failed to create semaphore frame_done.\n"); - return false; - } - - return true; + VkSemaphoreCreateInfo sema_info; + VkExportSemaphoreCreateInfo exp_sema_info; + + if (is_external) { + /* VkExportSemaphoreCreateInfo */ + memset(&exp_sema_info, 0, sizeof exp_sema_info); + exp_sema_info.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO; + exp_sema_info.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; + } + + /* VkSemaphoreCreateInfo */ + memset(&sema_info, 0, sizeof sema_info); + sema_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + sema_info.pNext = is_external ? &exp_sema_info : 0; + + if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_ready) != VK_SUCCESS) { + fprintf(stderr, "Failed to create semaphore frame_ready.\n"); + return false; + } + + if (vkCreateSemaphore(ctx->dev, &sema_info, 0, &semaphores->frame_done) != VK_SUCCESS) { + fprintf(stderr, "Failed to create semaphore frame_done.\n"); + return false; + } + + return true; } void vk_destroy_semaphores(struct vk_ctx *ctx, - struct vk_semaphores *semaphores) + struct vk_semaphores *semaphores) { - if (semaphores->frame_ready) - vkDestroySemaphore(ctx->dev, semaphores->frame_ready, 0); - if (semaphores->frame_done) - vkDestroySemaphore(ctx->dev, semaphores->frame_done, 0); + if (semaphores->frame_ready) + vkDestroySemaphore(ctx->dev, semaphores->frame_ready, 0); + if (semaphores->frame_done) + vkDestroySemaphore(ctx->dev, semaphores->frame_done, 0); } void vk_transition_image_layout(struct vk_image_att *img_att, - VkCommandBuffer cmd_buf, - VkImageLayout old_layout, - VkImageLayout new_layout, - uint32_t src_queue_fam_idx, - uint32_t dst_queue_fam_idx) + VkCommandBuffer cmd_buf, + VkImageLayout old_layout, + VkImageLayout new_layout, + uint32_t src_queue_fam_idx, + uint32_t dst_queue_fam_idx) { - VkImageMemoryBarrier barrier; - struct vk_image_props props = img_att->props; - VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(props.format); - - memset(&barrier, 0, sizeof barrier); - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.srcAccessMask = get_access_mask(old_layout); - barrier.dstAccessMask = get_access_mask(new_layout); - barrier.oldLayout = old_layout; - barrier.newLayout = new_layout; - barrier.srcQueueFamilyIndex = src_queue_fam_idx; - barrier.dstQueueFamilyIndex = dst_queue_fam_idx; - barrier.image = img_att->obj.img; - barrier.subresourceRange.aspectMask = aspect_mask ? aspect_mask : + VkImageMemoryBarrier barrier; + struct vk_image_props props = img_att->props; + VkImageAspectFlagBits aspect_mask = get_aspect_from_depth_format(props.format); + + memset(&barrier, 0, sizeof barrier); + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.srcAccessMask = get_access_mask(old_layout); + barrier.dstAccessMask = get_access_mask(new_layout); + barrier.oldLayout = old_layout; + barrier.newLayout = new_layout; + barrier.srcQueueFamilyIndex = src_queue_fam_idx; + barrier.dstQueueFamilyIndex = dst_queue_fam_idx; + barrier.image = img_att->obj.img; + barrier.subresourceRange.aspectMask = aspect_mask ? aspect_mask : VK_IMAGE_ASPECT_COLOR_BIT; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.layerCount = 1; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.layerCount = 1; - vkCmdPipelineBarrier(cmd_buf, + vkCmdPipelineBarrier(cmd_buf, get_pipeline_stage_flags(old_layout), get_pipeline_stage_flags(new_layout), 0, 0, VK_NULL_HANDLE, 0, VK_NULL_HANDLE, 1, &barrier); diff --git a/src/vk.h b/src/vk.h index 140f525..ff5c025 100644 --- a/src/vk.h +++ b/src/vk.h @@ -7,18 +7,24 @@ #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) struct vk_ctx { - VkInstance inst; - VkPhysicalDevice pdev; - VkDevice dev; + VkInstance inst; + VkPhysicalDevice pdev; + VkDevice dev; - VkCommandPool cmd_pool; - VkCommandBuffer cmd_buf; + VkCommandPool cmd_pool; + VkCommandBuffer cmd_buf; - VkQueue queue; - int qfam_idx; + VkQueue queue; + int qfam_idx; - uint8_t deviceUUID[VK_UUID_SIZE]; - uint8_t driverUUID[VK_UUID_SIZE]; + uint8_t deviceUUID[VK_UUID_SIZE]; + uint8_t driverUUID[VK_UUID_SIZE]; +}; + +struct vk_swap_image_obj +{ + VkImage image; + VkImageView image_view; }; struct vk_swapchain @@ -26,83 +32,90 @@ struct vk_swapchain VkSwapchainKHR swapchain; VkSurfaceKHR surface; VkSurfaceFormatKHR surf_fmt; - uint32_t num_images; + + /* image properties */ + VkFormat image_fmt; VkExtent2D extent2d; + + uint32_t num_images; + struct vk_swap_image_obj *images; }; struct vk_image_props { - uint32_t w; - uint32_t h; - uint32_t depth; + uint32_t w; + uint32_t h; + uint32_t depth; - uint32_t num_samples; - uint32_t num_levels; - uint32_t num_layers; + uint32_t num_samples; + uint32_t num_levels; + uint32_t num_layers; - VkFormat format; - VkImageUsageFlagBits usage; - VkImageTiling tiling; + VkFormat format; + VkImageUsageFlagBits usage; + VkImageTiling tiling; - VkImageLayout in_layout; - VkImageLayout end_layout; + VkImageLayout in_layout; + VkImageLayout end_layout; bool need_export; }; struct vk_mem_obj { - VkDeviceMemory mem; - VkDeviceSize mem_sz; - bool dedicated; + VkDeviceMemory mem; + VkDeviceSize mem_sz; + + bool dedicated; }; struct vk_image_obj { - VkImage img; + VkImage img; VkImageView img_view; - struct vk_mem_obj mobj; + + struct vk_mem_obj mobj; }; struct vk_image_att { - struct vk_image_obj obj; - struct vk_image_props props; + struct vk_image_obj obj; + struct vk_image_props props; }; struct vk_vertex_info { - int num_verts; - int num_components; + int num_verts; + int num_components; - VkPrimitiveTopology topology; + VkPrimitiveTopology topology; }; struct vk_buf { - VkBuffer buf; - struct vk_mem_obj mobj; + VkBuffer buf; + struct vk_mem_obj mobj; }; struct vk_renderer { - VkPipeline pipeline; - VkPipelineLayout pipeline_layout; - VkRenderPass renderpass; - VkShaderModule vs; - VkShaderModule fs; - VkFramebuffer fb; - - struct vk_vertex_info vertex_info; + VkPipeline pipeline; + VkPipelineLayout pipeline_layout; + VkRenderPass renderpass; + VkShaderModule vs; + VkShaderModule fs; + VkFramebuffer fb; + + struct vk_vertex_info vertex_info; }; struct vk_dims { - float w; - float h; + float w; + float h; }; struct vk_semaphores { - VkSemaphore frame_ready; - VkSemaphore frame_done; + VkSemaphore frame_ready; + VkSemaphore frame_done; }; /* context */ @@ -115,92 +128,99 @@ void vk_cleanup_ctx(struct vk_ctx *ctx); bool vk_create_image(struct vk_ctx *ctx, - struct vk_image_props *props, - struct vk_image_obj *img_obj); + struct vk_image_props *props, + struct vk_image_obj *img_obj); void vk_destroy_image(struct vk_ctx *ctx, - struct vk_image_obj *img_obj); - + struct vk_image_obj *img_obj); bool vk_fill_ext_image_props(struct vk_ctx *ctx, - uint32_t w, uint32_t h, - uint32_t depth, - uint32_t num_samples, - uint32_t num_levels, - uint32_t num_layers, - VkFormat format, - VkImageTiling tiling, - VkImageLayout in_layout, - VkImageLayout end_layout, + uint32_t w, uint32_t h, + uint32_t depth, + uint32_t num_samples, + uint32_t num_levels, + uint32_t num_layers, + VkFormat format, + VkImageTiling tiling, + VkImageLayout in_layout, + VkImageLayout end_layout, bool need_export, - struct vk_image_props *props); + struct vk_image_props *props); + +bool +vk_create_attachment_from_swapchain_image(struct vk_ctx *ctx, + VkImage *swapchain_img, + VkImageView *swapchain_view, + struct vk_image_props *swapchain_props, + struct vk_image_att *color_att); /* buffers */ bool vk_create_buffer(struct vk_ctx *ctx, bool is_external, - uint32_t sz, - VkBufferUsageFlagBits usage, - void *pnext, - struct vk_buf *bo); + uint32_t sz, + VkBufferUsageFlagBits usage, + void *pnext, + struct vk_buf *bo); void vk_destroy_buffer(struct vk_ctx *ctx, - struct vk_buf *bo); + struct vk_buf *bo); bool vk_update_buffer_data(struct vk_ctx *ctx, - void *data, - uint32_t data_sz, - struct vk_buf *bo); + void *data, + uint32_t data_sz, + struct vk_buf *bo); bool vk_create_ext_buffer(struct vk_ctx *ctx, - uint32_t sz, - VkBufferUsageFlagBits usage, - struct vk_buf *bo); + uint32_t sz, + VkBufferUsageFlagBits usage, + struct vk_buf *bo); /* semaphores */ bool vk_create_semaphores(struct vk_ctx *ctx, - struct vk_semaphores *semaphores); + bool is_external, + struct vk_semaphores *semaphores); void vk_destroy_semaphores(struct vk_ctx *ctx, - struct vk_semaphores *semaphores); + struct vk_semaphores *semaphores); /* renderer */ bool vk_create_renderer(struct vk_ctx *ctx, - const char *vs_src, - unsigned int vs_size, - const char *fs_src, - unsigned int fs_size, - bool enable_depth, - bool enable_stencil, - struct vk_image_att *color_att, - struct vk_image_att *depth_att, - struct vk_vertex_info *vert_info, - struct vk_renderer *renderer); + const char *vs_src, + unsigned int vs_size, + const char *fs_src, + unsigned int fs_size, + bool enable_depth, + bool enable_stencil, + struct vk_image_att *color_att, + struct vk_image_att *depth_att, + struct vk_vertex_info *vert_info, + struct vk_renderer *renderer); void vk_destroy_renderer(struct vk_ctx *ctx, - struct vk_renderer *pipeline); + struct vk_renderer *pipeline); /* draw */ void vk_draw(struct vk_ctx *ctx, - struct vk_buf *vbo, - struct vk_renderer *renderer, - float *vk_fb_color, - uint32_t vk_fb_color_count, - struct vk_semaphores *semaphores, - struct vk_image_att *attachments, - uint32_t n_attachments, - float x, float y, float w, float h); + struct vk_buf *vbo, + struct vk_renderer *renderer, + float *vk_fb_color, + uint32_t vk_fb_color_count, + struct vk_semaphores *semaphores, + struct vk_image_att *attachments, + uint32_t n_attachments, + float x, float y, float w, float h); void vk_clear_color(struct vk_ctx *ctx, @@ -219,7 +239,9 @@ vk_clear_color(struct vk_ctx *ctx, bool vk_create_swapchain(struct vk_ctx *ctx, int width, int height, - int num_qfam, + bool vsync, + VkSurfaceKHR surf, + struct vk_swapchain *old_swapchain, struct vk_swapchain *swapchain); void vk_destroy_swapchain(struct vk_ctx *ctx, @@ -229,16 +251,16 @@ vk_destroy_swapchain(struct vk_ctx *ctx, void vk_copy_image_to_buffer(struct vk_ctx *ctx, - struct vk_image_att *src_img, - struct vk_buf *dst_bo, - float w, float h); + struct vk_image_att *src_img, + struct vk_buf *dst_bo, + float w, float h); void vk_transition_image_layout(struct vk_image_att *img_att, - VkCommandBuffer cmd_buf, - VkImageLayout old_layout, - VkImageLayout new_layout, - uint32_t src_queue_family_index, - uint32_t dst_queue_family_index); + VkCommandBuffer cmd_buf, + VkImageLayout old_layout, + VkImageLayout new_layout, + uint32_t src_queue_family_index, + uint32_t dst_queue_family_index); #endif /* VK_H */