let cd = unsafe { &*callback_data_ptr }; let user_data = unsafe { &*user_data.cast::<super::DebugUtilsMessengerUserData>() };
const VUID_VKCMDENDDEBUGUTILSLABELEXT_COMMANDBUFFER_01912: i32 = 0x56146426; if cd.message_id_number == VUID_VKCMDENDDEBUGUTILSLABELEXT_COMMANDBUFFER_01912 { // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/5671 // Versions 1.3.240 through 1.3.250 return a spurious error here if // the debug range start and end appear in different command buffers. const KHRONOS_VALIDATION_LAYER: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Khronos Validation Layer\0") }; iflet Some(layer_properties) = user_data.validation_layer_properties.as_ref() { if layer_properties.layer_description.as_ref() == KHRONOS_VALIDATION_LAYER
&& layer_properties.layer_spec_version >= vk::make_api_version(0, 1, 3, 240)
&& layer_properties.layer_spec_version <= vk::make_api_version(0, 1, 3, 250)
{ return vk::FALSE;
}
}
}
// Silence Vulkan Validation error "VUID-VkSwapchainCreateInfoKHR-pNext-07781" // This happens when a surface is configured with a size outside the allowed extent. // It's a false positive due to the inherent racy-ness of surface resizing. const VUID_VKSWAPCHAINCREATEINFOKHR_PNEXT_07781: i32 = 0x4c8929c1; if cd.message_id_number == VUID_VKSWAPCHAINCREATEINFOKHR_PNEXT_07781 { return vk::FALSE;
}
// Silence Vulkan Validation error "VUID-VkRenderPassBeginInfo-framebuffer-04627" // if the OBS layer is enabled. This is a bug in the OBS layer. As the OBS layer // does not have a version number they increment, there is no way to qualify the // suppression of the error to a specific version of the OBS layer. // // See https://github.com/obsproject/obs-studio/issues/9353 const VUID_VKRENDERPASSBEGININFO_FRAMEBUFFER_04627: i32 = 0x45125641; if cd.message_id_number == VUID_VKRENDERPASSBEGININFO_FRAMEBUFFER_04627
&& user_data.has_obs_layer
{ return vk::FALSE;
}
if cd.object_count != 0 { let labels = unsafe { slice::from_raw_parts(cd.p_objects, cd.object_count as usize) }; //TODO: use color fields of `vk::DebugUtilsLabelExt`? let names = labels
.iter()
.map(|obj_info| { let name = unsafe { obj_info.object_name_as_c_str() }
.map_or(Cow::Borrowed("?"), CStr::to_string_lossy);
implsuper::Swapchain { /// # Safety /// /// - The device must have been made idle before calling this function. unsafefn release_resources(mutself, device: &ash::Device) -> Self {
profiling::scope!("Swapchain::release_resources");
{
profiling::scope!("vkDeviceWaitIdle"); // We need to also wait until all presentation work is done. Because there is no way to portably wait until // the presentation work is done, we are forced to wait until the device is idle. let _ = unsafe {
device
.device_wait_idle()
.map_err(super::map_host_device_oom_and_lost_err)
};
};
// We cannot take this by value, as the function returns `self`. for semaphore inself.surface_semaphores.drain(..) { let arc_removed = Arc::into_inner(semaphore).expect( "Trying to destroy a SurfaceSemaphores that is still in use by a SurfaceTexture",
); let mutex_removed = arc_removed.into_inner();
/// Return the instance extension names wgpu would like to enable. /// /// Return a vector of the names of instance extensions actually available /// on `entry` that wgpu would like to enable. /// /// The `instance_api_version` argument should be the instance's Vulkan API /// version, as obtained from `vkEnumerateInstanceVersion`. This is the same /// space of values as the `VK_API_VERSION` constants. /// /// Note that wgpu can function without many of these extensions (for /// example, `VK_KHR_wayland_surface` is certainly not going to be available /// everywhere), but if one of these extensions is available at all, wgpu /// assumes that it has been enabled. pubfn desired_extensions(
entry: &ash::Entry,
_instance_api_version: u32,
flags: wgt::InstanceFlags,
) -> Result<Vec<&'static CStr>, crate::InstanceError> { let instance_extensions = Self::enumerate_instance_extension_properties(entry, None)?;
// Check our extensions against the available extensions letmut extensions: Vec<&'static CStr> = Vec::new();
if flags.contains(wgt::InstanceFlags::DEBUG) { // VK_EXT_debug_utils
extensions.push(ext::debug_utils::NAME);
}
// VK_EXT_swapchain_colorspace // Provides wide color gamut
extensions.push(ext::swapchain_colorspace::NAME);
// VK_KHR_get_physical_device_properties2 // Even though the extension was promoted to Vulkan 1.1, we still require the extension // so that we don't have to conditionally use the functions provided by the 1.1 instance
extensions.push(khr::get_physical_device_properties2::NAME);
// Only keep available extensions.
extensions.retain(|&ext| { if instance_extensions
.iter()
.any(|inst_ext| inst_ext.extension_name_as_c_str() == Ok(ext))
{ true
} else {
log::warn!("Unable to find extension: {}", ext.to_string_lossy()); false
}
});
Ok(extensions)
}
/// # Safety /// /// - `raw_instance` must be created from `entry` /// - `raw_instance` must be created respecting `instance_api_version`, `extensions` and `flags` /// - `extensions` must be a superset of `desired_extensions()` and must be created from the /// same entry, `instance_api_version`` and flags. /// - `android_sdk_version` is ignored and can be `0` for all platforms besides Android /// - If `drop_callback` is [`None`], wgpu-hal will take ownership of `raw_instance`. If /// `drop_callback` is [`Some`], `raw_instance` must be valid until the callback is called. /// /// If `debug_utils_user_data` is `Some`, then the validation layer is /// available, so create a [`vk::DebugUtilsMessengerEXT`]. #[allow(clippy::too_many_arguments)] pubunsafefn from_raw(
entry: ash::Entry,
raw_instance: ash::Instance,
instance_api_version: u32,
android_sdk_version: u32,
debug_utils_create_info: Option<super::DebugUtilsCreateInfo>,
extensions: Vec<&'static CStr>,
flags: wgt::InstanceFlags,
has_nv_optimus: bool,
drop_callback: Option<crate::DropCallback>,
) -> Result<Self, crate::InstanceError> {
log::debug!("Instance version: 0x{:x}", instance_api_version);
let debug_utils = iflet Some(debug_utils_create_info) = debug_utils_create_info { if extensions.contains(&ext::debug_utils::NAME) {
log::info!("Enabling debug utils");
let extension = ext::debug_utils::Instance::new(&entry, &raw_instance); let vk_info = debug_utils_create_info.to_vk_create_info(); let messenger = unsafe { extension.create_debug_utils_messenger(&vk_info, None) }.unwrap();
Some(super::DebugUtils {
extension,
messenger,
callback_data: debug_utils_create_info.callback_data,
})
} else {
log::debug!("Debug utils not enabled: extension not listed");
None
}
} else {
log::debug!( "Debug utils not enabled: \
debug_utils_user_data not passed to Instance::from_raw"
);
None
};
let get_physical_device_properties = if extensions.contains(&khr::get_physical_device_properties2::NAME) {
log::debug!("Enabling device properties2");
Some(khr::get_physical_device_properties2::Instance::new(
&entry,
&raw_instance,
))
} else {
None
};
let drop_guard = crate::DropGuard::from_option(drop_callback);
fn create_surface_from_xlib(
&self,
dpy: *mut vk::Display,
window: vk::Window,
) -> Result<super::Surface, crate::InstanceError> { if !self.shared.extensions.contains(&khr::xlib_surface::NAME) { return Err(crate::InstanceError::new(String::from( "Vulkan driver does not support VK_KHR_xlib_surface",
)));
}
let surface = { let xlib_loader =
khr::xlib_surface::Instance::new(&self.shared.entry, &tyle='color:red'>self.shared.raw); let info = vk::XlibSurfaceCreateInfoKHR::default()
.flags(vk::XlibSurfaceCreateFlagsKHR::empty())
.window(window)
.dpy(dpy);
fn create_surface_from_xcb(
&self,
connection: *mut vk::xcb_connection_t,
window: vk::xcb_window_t,
) -> Result<super::Surface, crate::InstanceError> { if !self.shared.extensions.contains(&khr::xcb_surface::NAME) { return Err(crate::InstanceError::new(String::from( "Vulkan driver does not support VK_KHR_xcb_surface",
)));
}
let surface = { let xcb_loader = khr::xcb_surface::Instance::new(&self.shared.entry, &self.shared.raw); let info = vk::XcbSurfaceCreateInfoKHR::default()
.flags(vk::XcbSurfaceCreateFlagsKHR::empty())
.window(window)
.connection(connection);
fn create_surface_from_wayland(
&self,
display: *mut vk::wl_display,
surface: *mut vk::wl_surface,
) -> Result<super::Surface, crate::InstanceError> { if !self.shared.extensions.contains(&khr::wayland_surface::NAME) { return Err(crate::InstanceError::new(String::from( "Vulkan driver does not support VK_KHR_wayland_surface",
)));
}
let surface = { let w_loader =
khr::wayland_surface::Instance::new(&self.shared.entry, &n style='color:red'>self.shared.raw); let info = vk::WaylandSurfaceCreateInfoKHR::default()
.flags(vk::WaylandSurfaceCreateFlagsKHR::empty())
.display(display)
.surface(surface);
fn create_surface_android(
&self,
window: *mut vk::ANativeWindow,
) -> Result<super::Surface, crate::InstanceError> { if !self.shared.extensions.contains(&khr::android_surface::NAME) { return Err(crate::InstanceError::new(String::from( "Vulkan driver does not support VK_KHR_android_surface",
)));
}
let surface = { let a_loader =
khr::android_surface::Instance::new(&self.shared.entry, &n style='color:red'>self.shared.raw); let info = vk::AndroidSurfaceCreateInfoKHR::default()
.flags(vk::AndroidSurfaceCreateFlagsKHR::empty())
.window(window);
#[cfg(metal)] fn create_surface_from_view(
&self,
view: std::ptr::NonNull<c_void>,
) -> Result<super::Surface, crate::InstanceError> { if !self.shared.extensions.contains(&ext::metal_surface::NAME) { return Err(crate::InstanceError::new(String::from( "Vulkan driver does not support VK_EXT_metal_surface",
)));
}
let layer = unsafe { crate::metal::Surface::get_metal_layer(view.cast()) }; // NOTE: The layer is retained by Vulkan's `vkCreateMetalSurfaceEXT`, // so no need to retain it beyond the scope of this function. let layer_ptr = (*layer).cast();
let surface = { let metal_loader =
ext::metal_surface::Instance::new(&self.shared.entry, &style='color:red'>self.shared.raw); let vk_info = vk::MetalSurfaceCreateInfoEXT::default()
.flags(vk::MetalSurfaceCreateFlagsEXT::empty())
.layer(layer_ptr);
let entry = unsafe {
profiling::scope!("Load vk library");
ash::Entry::load()
}
.map_err(|err| { crate::InstanceError::with_source(String::from("missing Vulkan entry points"), err)
})?; let version = {
profiling::scope!("vkEnumerateInstanceVersion"); unsafe { entry.try_enumerate_instance_version() }
}; let instance_api_version = match version { // Vulkan 1.1+
Ok(Some(version)) => version,
Ok(None) => vk::API_VERSION_1_0,
Err(err) => { return Err(crate::InstanceError::with_source(
String::from("try_enumerate_instance_version() failed"),
err,
));
}
};
let app_name = CString::new(desc.name).unwrap(); let app_info = vk::ApplicationInfo::default()
.application_name(app_name.as_c_str())
.application_version(1)
.engine_name(CStr::from_bytes_with_nul(b"wgpu-hal\0").unwrap())
.engine_version(2)
.api_version( // Vulkan 1.0 doesn't like anything but 1.0 passed in here... if instance_api_version < vk::API_VERSION_1_1 {
vk::API_VERSION_1_0
} else { // This is the max Vulkan API version supported by `wgpu-hal`. // // If we want to increment this, there are some things that must be done first: // - Audit the behavioral differences between the previous and new API versions. // - Audit all extensions used by this backend: // - If any were promoted in the new API version and the behavior has changed, we must handle the new behavior in addition to the old behavior. // - If any were obsoleted in the new API version, we must implement a fallback for the new API version // - If any are non-KHR-vendored, we must ensure the new behavior is still correct (since backwards-compatibility is not guaranteed).
vk::API_VERSION_1_3
},
);
let extensions = Self::desired_extensions(&entry, instance_api_version, desc.flags)?;
let instance_layers = {
profiling::scope!("vkEnumerateInstanceLayerProperties"); unsafe { entry.enumerate_instance_layer_properties() }
}; let instance_layers = instance_layers.map_err(|e| {
log::debug!("enumerate_instance_layer_properties: {:?}", e); crate::InstanceError::with_source(
String::from("enumerate_instance_layer_properties() failed"),
e,
)
})?;
let validation_layer_name =
CStr::from_bytes_with_nul(b"VK_LAYER_KHRONOS_validation\0").unwrap(); let validation_layer_properties = find_layer(&instance_layers, validation_layer_name);
// Determine if VK_EXT_validation_features is available, so we can enable // GPU assisted validation and synchronization validation. let validation_features_are_enabled = if validation_layer_properties.is_some() { // Get the all the instance extension properties. let exts = Self::enumerate_instance_extension_properties(&entry, Some(validation_layer_name))?; // Convert all the names of the extensions into an iterator of CStrs. letmut ext_names = exts
.iter()
.filter_map(|ext| ext.extension_name_as_c_str().ok()); // Find the validation features extension.
ext_names.any(|ext_name| ext_name == ext::validation_features::NAME)
} else { false
};
let should_enable_gpu_based_validation = desc
.flags
.intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
&& validation_features_are_enabled;
let nv_optimus_layer = CStr::from_bytes_with_nul(b"VK_LAYER_NV_optimus\0").unwrap(); let has_nv_optimus = find_layer(&instance_layers, nv_optimus_layer).is_some();
let obs_layer = CStr::from_bytes_with_nul(b"VK_LAYER_OBS_HOOK\0").unwrap(); let has_obs_layer = find_layer(&instance_layers, obs_layer).is_some();
letmut layers: Vec<&'static CStr> = Vec::new();
let has_debug_extension = extensions.contains(&ext::debug_utils::NAME); letmut debug_user_data = has_debug_extension.then(|| { // Put the callback data on the heap, to ensure it will never be // moved. Box::new(super::DebugUtilsMessengerUserData {
validation_layer_properties: None,
has_obs_layer,
})
});
// Request validation layer if asked. if desc.flags.intersects(wgt::InstanceFlags::VALIDATION)
|| should_enable_gpu_based_validation
{ iflet Some(layer_properties) = validation_layer_properties {
layers.push(validation_layer_name);
// Avoid VUID-VkInstanceCreateInfo-flags-06559: Only ask the instance to // enumerate incomplete Vulkan implementations (which we need on Mac) if // we managed to find the extension that provides the flag. if extensions.contains(&khr::portability_enumeration::NAME) {
flags |= vk::InstanceCreateFlags::ENUMERATE_PORTABILITY_KHR;
} let vk_instance = { let str_pointers = layers
.iter()
.chain(extensions.iter())
.map(|&s: &&'static _| { // Safe because `layers` and `extensions` entries have static lifetime.
s.as_ptr()
})
.collect::<Vec<_>>();
// Enable explicit validation features if available letmut validation_features; letmut validation_feature_list: ArrayVec<_, 3>; if validation_features_are_enabled {
validation_feature_list = ArrayVec::new();
// Only enable GPU assisted validation if requested. if should_enable_gpu_based_validation {
validation_feature_list.push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED);
validation_feature_list
.push(vk::ValidationFeatureEnableEXT::GPU_ASSISTED_RESERVE_BINDING_SLOT);
}
let swapchain_semaphores_arc = swapchain.get_surface_semaphores(); // Nothing should be using this, so we don't block, but panic if we fail to lock. let locked_swapchain_semaphores = swapchain_semaphores_arc
.try_lock()
.expect("Failed to lock a SwapchainSemaphores.");
// Wait for all commands writing to the previously acquired image to // complete. // // Almost all the steps in the usual acquire-draw-present flow are // asynchronous: they get something started on the presentation engine // or the GPU, but on the CPU, control returns immediately. Without some // sort of intervention, the CPU could crank out frames much faster than // the presentation engine can display them. // // This is the intervention: if any submissions drew on this image, and // thus waited for `locked_swapchain_semaphores.acquire`, wait for all // of them to finish, thus ensuring that it's okay to pass `acquire` to // `vkAcquireNextImageKHR` again.
swapchain.device.wait_for_fence(
fence,
locked_swapchain_semaphores.previously_used_submission_index,
timeout_ns,
)?;
// will block if no image is available let (index, suboptimal) = matchunsafe {
profiling::scope!("vkAcquireNextImageKHR");
swapchain.functor.acquire_next_image(
swapchain.raw,
timeout_ns,
locked_swapchain_semaphores.acquire,
vk::Fence::null(),
)
} { // We treat `VK_SUBOPTIMAL_KHR` as `VK_SUCCESS` on Android. // See the comment in `Queue::present`. #[cfg(target_os = "android")]
Ok((index, _)) => (index, false), #[cfg(not(target_os = "android"))]
Ok(pair) => pair,
Err(error) => { returnmatch error {
vk::Result::TIMEOUT => Ok(None),
vk::Result::NOT_READY | vk::Result::ERROR_OUT_OF_DATE_KHR => {
Err(crate::SurfaceError::Outdated)
}
vk::Result::ERROR_SURFACE_LOST_KHR => Err(crate::SurfaceError::Lost), // We don't use VK_EXT_full_screen_exclusive // VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT
other => Err(super::map_host_device_oom_and_lost_err(other).into()),
};
}
};
drop(locked_swapchain_semaphores); // We only advance the surface semaphores if we successfully acquired an image, otherwise // we should try to re-acquire using the same semaphores.
swapchain.advance_surface_semaphores();
// special case for Intel Vulkan returning bizarre values (ugh) if swapchain.device.vendor_id == crate::auxil::db::intel::VENDOR && index > 0x100 { return Err(crate::SurfaceError::Outdated);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.