fix(renderer): handle u32::MAX swapchain extent

Fixed a crash where the renderer would attempt to create a swapchain with u32::MAX dimensions when the OS didn't provide a preferred extent. Updated Renderer::new to accept window dimensions and use them as a fallback. Also renamed InstanceCreateFailed to VulkanError for better generality.
This commit is contained in:
Serkyo 2026-04-30 15:16:55 +02:00
parent 76450da41f
commit 636c44b29f
4 changed files with 30 additions and 7 deletions

1
Cargo.lock generated
View file

@ -1054,6 +1054,7 @@ name = "renderer"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ash", "ash",
"ash-window",
"raw-window-handle", "raw-window-handle",
"thiserror 2.0.18", "thiserror 2.0.18",
"tracing", "tracing",

View file

@ -31,8 +31,15 @@ impl ApplicationHandler for App {
let required_extensions = ash_window::enumerate_required_extensions(display_handle) let required_extensions = ash_window::enumerate_required_extensions(display_handle)
.expect("Failed to enumerate required extensions"); .expect("Failed to enumerate required extensions");
let renderer = renderer::Renderer::new(display_handle, window_handle, required_extensions) let size = self.window.as_ref().unwrap().inner_size();
.expect("Failed to initialize Vulkan renderer"); let renderer = renderer::Renderer::new(
display_handle,
window_handle,
size.width,
size.height,
required_extensions,
)
.expect("Failed to initialize Vulkan renderer");
self.renderer = Some(renderer); self.renderer = Some(renderer);
} }

View file

@ -4,8 +4,8 @@ use thiserror::Error;
pub enum RendererError { pub enum RendererError {
#[error("Failed to load Vulkan library")] #[error("Failed to load Vulkan library")]
LoadFailed(#[from] ash::LoadingError), LoadFailed(#[from] ash::LoadingError),
#[error("Failed to create Vulkan instance")] #[error("Vulkan error")]
InstanceCreateFailed(#[from] ash::vk::Result), VulkanError(#[from] ash::vk::Result),
#[error("No suitable GPU found")] #[error("No suitable GPU found")]
NoSuitableGpu, NoSuitableGpu,
} }

View file

@ -1,7 +1,7 @@
pub mod error; pub mod error;
use std::ffi::{CStr, c_char}; use std::ffi::{CStr, c_char};
use ash::{Device, Entry, Instance, ext, khr, vk::{self, SurfaceKHR}}; use ash::{Device, Entry, Instance, ext, khr, vk};
use raw_window_handle::{RawDisplayHandle, RawWindowHandle}; use raw_window_handle::{RawDisplayHandle, RawWindowHandle};
use tracing::{debug, error, info, warn}; use tracing::{debug, error, info, warn};
@ -52,6 +52,8 @@ impl Renderer {
pub fn new( pub fn new(
display_handle: RawDisplayHandle, display_handle: RawDisplayHandle,
window_handle: RawWindowHandle, window_handle: RawWindowHandle,
width: u32,
height: u32,
required_extensions: &[*const c_char], required_extensions: &[*const c_char],
) -> Result<Self, RendererError> { ) -> Result<Self, RendererError> {
let entry = unsafe { Entry::load() }?; let entry = unsafe { Entry::load() }?;
@ -117,7 +119,9 @@ impl Renderer {
// Create the logical device // Create the logical device
let (device, graphics_queue) = Self::create_logical_device(&instance, physical_device, graphics_queue_index)?; let (device, graphics_queue) = Self::create_logical_device(&instance, physical_device, graphics_queue_index)?;
let (swapchain_loader, swapchain, swapchain_images, swapchain_format, swapchain_extent) = Self::create_swapchain(&instance, physical_device, &device, &surface_loader, surface)?; // Create the swapchain
let (swapchain_loader, swapchain, swapchain_images, swapchain_format, swapchain_extent) =
Self::create_swapchain(&instance, physical_device, &device, &surface_loader, surface, width, height)?;
Ok(Self { Ok(Self {
_entry: entry, _entry: entry,
@ -242,6 +246,8 @@ impl Renderer {
device: &Device, device: &Device,
surface_loader: &khr::surface::Instance, surface_loader: &khr::surface::Instance,
surface: vk::SurfaceKHR, surface: vk::SurfaceKHR,
width: u32,
height: u32,
) -> Result< ) -> Result<
(khr::swapchain::Device, vk::SwapchainKHR, Vec<vk::Image>, vk::Format, vk::Extent2D), (khr::swapchain::Device, vk::SwapchainKHR, Vec<vk::Image>, vk::Format, vk::Extent2D),
RendererError, RendererError,
@ -262,7 +268,16 @@ impl Renderer {
.find(|&m| m == vk::PresentModeKHR::MAILBOX) .find(|&m| m == vk::PresentModeKHR::MAILBOX)
.unwrap_or(vk::PresentModeKHR::FIFO); .unwrap_or(vk::PresentModeKHR::FIFO);
let extent = surface_capabilities.current_extent; // 3. Match the window resolution
// If the surface says u32::MAX, it means we can pick any size within bounds.
let extent = if surface_capabilities.current_extent.width != u32::MAX {
surface_capabilities.current_extent
} else {
vk::Extent2D {
width: width.clamp(surface_capabilities.min_image_extent.width, surface_capabilities.max_image_extent.width),
height: height.clamp(surface_capabilities.min_image_extent.height, surface_capabilities.max_image_extent.height),
}
};
let mut image_count = surface_capabilities.min_image_count + 1; let mut image_count = surface_capabilities.min_image_count + 1;