diff --git a/client/include/gpu.h b/client/include/gpu.h index 90274a9..0a6792c 100644 --- a/client/include/gpu.h +++ b/client/include/gpu.h @@ -139,6 +139,11 @@ typedef struct RenderContextStruct { VkExtent2D swapchain_extent; VkSwapchainKHR swapchain; + // Latest framebuffer size in pixels, updated by the GLFW framebuffer-size + // callback. Used by choose_swapchain_extent when the surface reports + // currentExtent = 0xFFFFFFFF (Wayland). + VkExtent2D framebuffer_size; + uint32_t swapchain_image_count; VkImage* swapchain_images; VkImageView* swapchain_image_views; diff --git a/client/src/engine.c b/client/src/engine.c index 5098218..94f47ff 100644 --- a/client/src/engine.c +++ b/client/src/engine.c @@ -4,6 +4,12 @@ #include "draw.h" #include +void framebuffer_size_callback(GLFWwindow* window, int width, int height) { + ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window); + context->render.framebuffer_size.width = (uint32_t)width; + context->render.framebuffer_size.height = (uint32_t)height; +} + void text_callback(GLFWwindow* window, unsigned int codepoint) { ClientContext* context = (ClientContext*)glfwGetWindowUserPointer(window); if(context->ui.active_container != NULL @@ -288,6 +294,7 @@ int run_app( glfwSetScrollCallback(context->window, scroll_callback); glfwSetCursorPosCallback(context->window, cursor_callback); glfwSetCharCallback(context->window, text_callback); + glfwSetFramebufferSizeCallback(context->window, framebuffer_size_callback); if(init_vulkan(context->window, &context->render) != VK_SUCCESS) return -2; diff --git a/client/src/gpu.c b/client/src/gpu.c index 8ebae6d..8fdd7f3 100644 --- a/client/src/gpu.c +++ b/client/src/gpu.c @@ -277,7 +277,7 @@ VkResult create_logical_device( graphics_queue->family = idx; graphics_queue->index = 0; } else if (present_support && (present_queue->family == 0xFFFFFFFF)) { - graphics_queue->family = idx; + present_queue->family = idx; present_queue->index = 0; } } @@ -358,10 +358,10 @@ VkResult create_logical_device( queue_create_info[1].queueCount = 1; queue_create_info[1].pQueuePriorities = &default_queue_priority; - queue_create_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queue_create_info[1].queueFamilyIndex = transfer_queue->family; - queue_create_info[1].queueCount = 1; - queue_create_info[1].pQueuePriorities = &default_queue_priority; + queue_create_info[2].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queue_create_info[2].queueFamilyIndex = transfer_queue->family; + queue_create_info[2].queueCount = 1; + queue_create_info[2].pQueuePriorities = &default_queue_priority; } VkPhysicalDeviceDynamicRenderingFeatures dynamic_rendering = { @@ -538,8 +538,20 @@ VkPresentModeKHR choose_present_mode(SwapchainDetails swapchain_details) { return VK_PRESENT_MODE_FIFO_KHR; } -VkExtent2D choose_swapchain_extent(SwapchainDetails swapchain_details) { - return swapchain_details.capabilities.currentExtent; +VkExtent2D choose_swapchain_extent(SwapchainDetails swapchain_details, VkExtent2D framebuffer_size) { + VkSurfaceCapabilitiesKHR caps = swapchain_details.capabilities; + // 0xFFFFFFFF means "app chooses" (common on Wayland). Fall back to the + // caller-supplied framebuffer size and clamp to the surface's allowed range. + if(caps.currentExtent.width != 0xFFFFFFFF) { + return caps.currentExtent; + } + + VkExtent2D extent = framebuffer_size; + if(extent.width < caps.minImageExtent.width) extent.width = caps.minImageExtent.width; + if(extent.height < caps.minImageExtent.height) extent.height = caps.minImageExtent.height; + if(extent.width > caps.maxImageExtent.width) extent.width = caps.maxImageExtent.width; + if(extent.height > caps.maxImageExtent.height) extent.height = caps.maxImageExtent.height; + return extent; } VkResult create_swapchain( @@ -570,7 +582,7 @@ VkResult create_swapchain( .imageArrayLayers = 1, .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, .preTransform = capabilities.currentTransform, - .compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, .presentMode = present_mode, .clipped = VK_TRUE, .oldSwapchain = old_swapchain, @@ -874,6 +886,11 @@ VkResult init_vulkan(GLFWwindow* window, RenderContext* context) { GLFWmonitor** monitors = glfwGetMonitors(&monitor_count); glfwGetMonitorContentScale(monitors[0], &context->window_scale[0], &context->window_scale[1]); + int fb_width, fb_height; + glfwGetFramebufferSize(window, &fb_width, &fb_height); + context->framebuffer_size.width = (uint32_t)fb_width; + context->framebuffer_size.height = (uint32_t)fb_height; + VK_RESULT(create_instance(&context->instance)); VK_RESULT(create_debug_messenger(context->instance, &context->debug_messenger)); @@ -916,7 +933,7 @@ VkResult init_vulkan(GLFWwindow* window, RenderContext* context) { context->swapchain_format = choose_swapchain_format(context->swapchain_details); context->swapchain_present_mode = choose_present_mode(context->swapchain_details); - context->swapchain_extent = choose_swapchain_extent(context->swapchain_details); + context->swapchain_extent = choose_swapchain_extent(context->swapchain_details, context->framebuffer_size); context->framebuffer_recreated = true; context->swapchain = VK_NULL_HANDLE; VK_RESULT(create_swapchain( @@ -1277,7 +1294,7 @@ VkResult recreate_framebuffer(RenderContext* gpu) { &gpu->swapchain_details)) gpu->swapchain_format = choose_swapchain_format(gpu->swapchain_details); gpu->swapchain_present_mode = choose_present_mode(gpu->swapchain_details); - gpu->swapchain_extent = choose_swapchain_extent(gpu->swapchain_details); + gpu->swapchain_extent = choose_swapchain_extent(gpu->swapchain_details, gpu->framebuffer_size); VK_RESULT(create_swapchain( gpu->device, gpu->swapchain_format,