(width: f64, height: f64, title_ptr: *const u8, fullscreen: f64)
| 292 | |
| 293 | #[no_mangle] |
| 294 | pub extern "C" fn bloom_init_window(width: f64, height: f64, title_ptr: *const u8, fullscreen: f64) { |
| 295 | let title = str_from_header(title_ptr); |
| 296 | |
| 297 | #[cfg(windows)] |
| 298 | { |
| 299 | let (hwnd, phys_w, phys_h) = win32::create_window(width, height, title); |
| 300 | |
| 301 | let instance = wgpu::Instance::new(wgpu::InstanceDescriptor { |
| 302 | backends: wgpu::Backends::DX12 | wgpu::Backends::VULKAN, |
| 303 | ..wgpu::InstanceDescriptor::new_without_display_handle() |
| 304 | }); |
| 305 | |
| 306 | let surface = unsafe { |
| 307 | let mut handle = raw_window_handle::Win32WindowHandle::new( |
| 308 | std::num::NonZeroIsize::new(hwnd.0 as isize).unwrap() |
| 309 | ); |
| 310 | let raw = raw_window_handle::RawWindowHandle::Win32(handle); |
| 311 | instance.create_surface_unsafe(wgpu::SurfaceTargetUnsafe::RawHandle { |
| 312 | raw_display_handle: Some(raw_window_handle::RawDisplayHandle::Windows( |
| 313 | raw_window_handle::WindowsDisplayHandle::new() |
| 314 | )), |
| 315 | raw_window_handle: raw, |
| 316 | }).expect("Failed to create surface") |
| 317 | }; |
| 318 | |
| 319 | let adapter = pollster_block_on(instance.request_adapter(&wgpu::RequestAdapterOptions { |
| 320 | compatible_surface: Some(&surface), |
| 321 | power_preference: wgpu::PowerPreference::HighPerformance, |
| 322 | ..Default::default() |
| 323 | })).expect("No adapter found"); |
| 324 | |
| 325 | // Ticket 007b: HW ray-query via DXR 1.1 / VK_KHR_ray_query. |
| 326 | let supported = adapter.features(); |
| 327 | let force_sw_gi = std::env::var("BLOOM_FORCE_SW_GI") |
| 328 | .map(|v| v == "1" || v.eq_ignore_ascii_case("true")) |
| 329 | .unwrap_or(false); |
| 330 | let rt_mask = wgpu::Features::EXPERIMENTAL_RAY_QUERY; |
| 331 | let mut required_features = wgpu::Features::empty(); |
| 332 | // Ticket 011: request TIMESTAMP_QUERY when supported so the profiler |
| 333 | // can record GPU timings. Optional — profiler falls back to CPU-only |
| 334 | // when the adapter doesn't grant it. |
| 335 | if supported.contains(wgpu::Features::TIMESTAMP_QUERY) { |
| 336 | required_features |= wgpu::Features::TIMESTAMP_QUERY; |
| 337 | } |
| 338 | if !force_sw_gi && supported.contains(rt_mask) { |
| 339 | required_features |= rt_mask; |
| 340 | } |
| 341 | let experimental_features = if required_features.intersects(rt_mask) { |
| 342 | unsafe { wgpu::ExperimentalFeatures::enabled() } |
| 343 | } else { |
| 344 | wgpu::ExperimentalFeatures::disabled() |
| 345 | }; |
| 346 | let mut required_limits = wgpu::Limits::default(); |
| 347 | // Phase 1c: the material ABI declares 5 bind groups (PerFrame, |
| 348 | // PerView, PerMaterial, PerDraw, SceneInputs). wgpu's default |
| 349 | // limit is 4. Metal / Vulkan / D3D12 support at least 7, so 5 is |
| 350 | // safely within every real backend's capabilities. |
| 351 | required_limits.max_bind_groups = 5; |
nothing calls this directly
no test coverage detected