-
Notifications
You must be signed in to change notification settings - Fork 1.2k
[d3d12] add support for optional adapter telemetry #8576
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,6 +58,7 @@ impl super::Adapter { | |
| &self.raw | ||
| } | ||
|
|
||
| #[allow(clippy::too_many_arguments)] | ||
| pub(super) fn expose( | ||
| adapter: DxgiAdapter, | ||
| library: &Arc<D3D12Lib>, | ||
|
|
@@ -66,19 +67,62 @@ impl super::Adapter { | |
| memory_budget_thresholds: wgt::MemoryBudgetThresholds, | ||
| compiler_container: Arc<shader_compilation::CompilerContainer>, | ||
| backend_options: wgt::Dx12BackendOptions, | ||
| telemetry: Option<crate::Telemetry>, | ||
| ) -> Option<crate::ExposedAdapter<super::Api>> { | ||
| let desc = unsafe { adapter.GetDesc2() }.unwrap(); | ||
| let driver_version = | ||
| unsafe { adapter.CheckInterfaceSupport(&Dxgi::IDXGIDevice::IID) }.unwrap() as u64; | ||
| let driver_version = [ | ||
| (driver_version >> 48) as u16, | ||
| (driver_version >> 32) as u16, | ||
| (driver_version >> 16) as u16, | ||
| driver_version as u16, | ||
| ]; | ||
|
|
||
| let get_telemetry_key = || { | ||
| // The key must be under 111 bytes: | ||
| // - backend identifier 'D' = 1 byte | ||
| // - 4 * u32's formatted as hex = 4 * 8 = 32 bytes | ||
| // - 4 * u16's formatted as dec = 4 * 5 = 20 bytes | ||
| // - separators = 8 bytes | ||
| // total = 61 bytes | ||
| format!( | ||
| "D:{:X}:{:X}:{:X}:{:X}:{}.{}.{}.{}", | ||
| desc.VendorId, | ||
| desc.DeviceId, | ||
| desc.SubSysId, | ||
| desc.Revision, | ||
| driver_version[0], | ||
| driver_version[1], | ||
| driver_version[2], | ||
| driver_version[3], | ||
| ) | ||
| }; | ||
|
|
||
| // Create the device so that we can get the capabilities. | ||
| let device = { | ||
| let res = { | ||
| profiling::scope!("ID3D12Device::create_device"); | ||
| library | ||
| .create_device(&adapter, Direct3D::D3D_FEATURE_LEVEL_11_0) | ||
| .ok()?? | ||
| library.create_device(&adapter, Direct3D::D3D_FEATURE_LEVEL_11_0) | ||
| }; | ||
| if let Some(telemetry) = telemetry { | ||
| if let Err(ref err) = res { | ||
| let category = match err { | ||
| crate::dx12::CreateDeviceError::GetProcAddress => "NONE:GetProcAddress", | ||
| crate::dx12::CreateDeviceError::D3D12CreateDevice(hresult) => { | ||
| &format!("NONE:D3D12CreateDevice:{:X}", hresult.0) | ||
| } | ||
| crate::dx12::CreateDeviceError::RetDeviceIsNull => "NONE:RetDeviceIsNull", | ||
| }; | ||
| (telemetry.expose_adapter)(&get_telemetry_key(), category); | ||
| } | ||
| } | ||
| let device = res.ok()?; | ||
|
|
||
| profiling::scope!("feature queries"); | ||
|
|
||
| // Detect the highest supported feature level. | ||
| let d3d_feature_level = [ | ||
| Direct3D::D3D_FEATURE_LEVEL_12_2, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know D3D12, but does this change belong in this PR? |
||
| Direct3D::D3D_FEATURE_LEVEL_12_1, | ||
| Direct3D::D3D_FEATURE_LEVEL_12_0, | ||
| Direct3D::D3D_FEATURE_LEVEL_11_1, | ||
|
|
@@ -99,10 +143,6 @@ impl super::Adapter { | |
| .unwrap(); | ||
| let max_feature_level = device_levels.MaxSupportedFeatureLevel; | ||
|
|
||
| // We have found a possible adapter. | ||
| // Acquire the device information. | ||
| let desc = unsafe { adapter.GetDesc2() }.unwrap(); | ||
|
|
||
| let device_name = auxil::dxgi::conv::map_adapter_name(desc.Description); | ||
|
|
||
| let mut features_architecture = Direct3D12::D3D12_FEATURE_DATA_ARCHITECTURE::default(); | ||
|
|
@@ -116,14 +156,6 @@ impl super::Adapter { | |
| } | ||
| .unwrap(); | ||
|
|
||
| let driver_version = unsafe { adapter.CheckInterfaceSupport(&Dxgi::IDXGIDevice::IID) } | ||
| .ok() | ||
| .map(|i| { | ||
| const MASK: i64 = 0xFFFF; | ||
| (i >> 48, (i >> 32) & MASK, (i >> 16) & MASK, i & MASK) | ||
| }) | ||
| .unwrap_or((0, 0, 0, 0)); | ||
|
|
||
| let mut workarounds = super::Workarounds::default(); | ||
|
|
||
| let is_warp = device_name.contains("Microsoft Basic Render Driver"); | ||
|
|
@@ -132,7 +164,7 @@ impl super::Adapter { | |
| // use a version that starts with 10.x.x.x. Versions that ship from Nuget use 1.0.x.x. | ||
| // | ||
| // As far as we know, this is only an issue on the Nuget versions. | ||
| if is_warp && driver_version >= (1, 0, 13, 0) && driver_version.0 < 10 { | ||
| if is_warp && driver_version >= [1, 0, 13, 0] && driver_version[0] < 10 { | ||
| workarounds.avoid_shader_debug_info = true; | ||
| } | ||
|
|
||
|
|
@@ -153,7 +185,7 @@ impl super::Adapter { | |
| device_pci_bus_id: get_adapter_pci_info(desc.VendorId, desc.DeviceId), | ||
| driver: format!( | ||
| "{}.{}.{}.{}", | ||
| driver_version.0, driver_version.1, driver_version.2, driver_version.3 | ||
| driver_version[0], driver_version[1], driver_version[2], driver_version[3] | ||
| ), | ||
| driver_info: String::new(), | ||
| transient_saves_memory: false, | ||
|
|
@@ -170,6 +202,10 @@ impl super::Adapter { | |
| .unwrap(); | ||
|
|
||
| if options.ResourceBindingTier.0 < Direct3D12::D3D12_RESOURCE_BINDING_TIER_2.0 { | ||
| if let Some(telemetry) = telemetry { | ||
| let category = "NONE:REQ_RBT2"; | ||
| (telemetry.expose_adapter)(&get_telemetry_key(), category); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps these other categories could be handled with separate functions in the |
||
| } | ||
| // We require Tier 2 or higher for the ability to make samplers bindless in all cases. | ||
| return None; | ||
| } | ||
|
|
@@ -263,6 +299,40 @@ impl super::Adapter { | |
| } | ||
| }; | ||
|
|
||
| let mut all_shader_models = [ | ||
| Direct3D12::D3D_SHADER_MODEL_6_9, | ||
| Direct3D12::D3D_SHADER_MODEL_6_8, | ||
| Direct3D12::D3D_SHADER_MODEL_6_7, | ||
| Direct3D12::D3D_SHADER_MODEL_6_6, | ||
| Direct3D12::D3D_SHADER_MODEL_6_5, | ||
| Direct3D12::D3D_SHADER_MODEL_6_4, | ||
| Direct3D12::D3D_SHADER_MODEL_6_3, | ||
| Direct3D12::D3D_SHADER_MODEL_6_2, | ||
| Direct3D12::D3D_SHADER_MODEL_6_1, | ||
| Direct3D12::D3D_SHADER_MODEL_6_0, | ||
| ] | ||
| .iter(); | ||
| let highest_shader_model = loop { | ||
| if let Some(&sm) = all_shader_models.next() { | ||
| let mut sm = Direct3D12::D3D12_FEATURE_DATA_SHADER_MODEL { | ||
| HighestShaderModel: sm, | ||
| }; | ||
| if unsafe { | ||
| device.CheckFeatureSupport( | ||
| Direct3D12::D3D12_FEATURE_SHADER_MODEL, | ||
| <*mut _>::cast(&mut sm), | ||
| size_of_val(&sm) as u32, | ||
| ) | ||
| } | ||
| .is_ok() | ||
| { | ||
| break sm.HighestShaderModel; | ||
| } | ||
| } else { | ||
| break Direct3D12::D3D_SHADER_MODEL_5_1; | ||
| } | ||
| }; | ||
|
|
||
| let shader_model = if let Some(max_shader_model) = compiler_container.max_shader_model() { | ||
| let max_shader_model = match max_shader_model { | ||
| wgt::DxcShaderModel::V6_0 => Direct3D12::D3D_SHADER_MODEL_6_0, | ||
|
|
@@ -275,42 +345,18 @@ impl super::Adapter { | |
| wgt::DxcShaderModel::V6_7 => Direct3D12::D3D_SHADER_MODEL_6_7, | ||
| }; | ||
|
|
||
| let mut versions = [ | ||
| Direct3D12::D3D_SHADER_MODEL_6_7, | ||
| Direct3D12::D3D_SHADER_MODEL_6_6, | ||
| Direct3D12::D3D_SHADER_MODEL_6_5, | ||
| Direct3D12::D3D_SHADER_MODEL_6_4, | ||
| Direct3D12::D3D_SHADER_MODEL_6_3, | ||
| Direct3D12::D3D_SHADER_MODEL_6_2, | ||
| Direct3D12::D3D_SHADER_MODEL_6_1, | ||
| Direct3D12::D3D_SHADER_MODEL_6_0, | ||
| ] | ||
| .iter() | ||
| .filter(|shader_model| shader_model.0 <= max_shader_model.0); | ||
|
|
||
| let highest_shader_model = loop { | ||
| if let Some(&sm) = versions.next() { | ||
| let mut sm = Direct3D12::D3D12_FEATURE_DATA_SHADER_MODEL { | ||
| HighestShaderModel: sm, | ||
| }; | ||
| if unsafe { | ||
| device.CheckFeatureSupport( | ||
| Direct3D12::D3D12_FEATURE_SHADER_MODEL, | ||
| <*mut _>::cast(&mut sm), | ||
| size_of_val(&sm) as u32, | ||
| ) | ||
| } | ||
| .is_ok() | ||
| { | ||
| break sm.HighestShaderModel; | ||
| let shader_model = | ||
| Direct3D12::D3D_SHADER_MODEL(highest_shader_model.0.min(max_shader_model.0)); | ||
|
|
||
| match shader_model { | ||
| Direct3D12::D3D_SHADER_MODEL_5_1 => { | ||
| if let Some(telemetry) = telemetry { | ||
| let category = "NONE:REQ_SM6"; | ||
| (telemetry.expose_adapter)(&get_telemetry_key(), category); | ||
| } | ||
| } else { | ||
| break Direct3D12::D3D_SHADER_MODEL_5_1; | ||
| // don't expose this adapter if it doesn't support DXIL | ||
| return None; | ||
| } | ||
| }; | ||
|
|
||
| match highest_shader_model { | ||
| Direct3D12::D3D_SHADER_MODEL_5_1 => return None, // don't expose this adapter if it doesn't support DXIL | ||
| Direct3D12::D3D_SHADER_MODEL_6_0 => naga::back::hlsl::ShaderModel::V6_0, | ||
| Direct3D12::D3D_SHADER_MODEL_6_1 => naga::back::hlsl::ShaderModel::V6_1, | ||
| Direct3D12::D3D_SHADER_MODEL_6_2 => naga::back::hlsl::ShaderModel::V6_2, | ||
|
|
@@ -646,6 +692,33 @@ impl super::Adapter { | |
| // See https://microsoft.github.io/DirectX-Specs/d3d/ViewInstancing.html#maximum-viewinstancecount | ||
| let max_multiview_view_count = if view_instancing { 4 } else { 0 }; | ||
|
|
||
| if let Some(telemetry) = telemetry { | ||
| let fl = match max_feature_level { | ||
| Direct3D::D3D_FEATURE_LEVEL_12_2 => "12_2", | ||
| Direct3D::D3D_FEATURE_LEVEL_12_1 => "12_1", | ||
| Direct3D::D3D_FEATURE_LEVEL_12_0 => "12_0", | ||
| Direct3D::D3D_FEATURE_LEVEL_11_1 => "11_1", | ||
| Direct3D::D3D_FEATURE_LEVEL_11_0 => "11_0", | ||
| _ => unreachable!(), | ||
| }; | ||
| let sm = match highest_shader_model { | ||
| Direct3D12::D3D_SHADER_MODEL_6_9 => "6.9", | ||
| Direct3D12::D3D_SHADER_MODEL_6_8 => "6.8", | ||
| Direct3D12::D3D_SHADER_MODEL_6_7 => "6.7", | ||
| Direct3D12::D3D_SHADER_MODEL_6_6 => "6.6", | ||
| Direct3D12::D3D_SHADER_MODEL_6_5 => "6.5", | ||
| Direct3D12::D3D_SHADER_MODEL_6_4 => "6.4", | ||
| Direct3D12::D3D_SHADER_MODEL_6_3 => "6.3", | ||
| Direct3D12::D3D_SHADER_MODEL_6_2 => "6.2", | ||
| Direct3D12::D3D_SHADER_MODEL_6_1 => "6.1", | ||
| Direct3D12::D3D_SHADER_MODEL_6_0 => "6.0", | ||
| Direct3D12::D3D_SHADER_MODEL_5_1 => "5.1", | ||
| _ => unreachable!(), | ||
| }; | ||
| let category = &format!("SOME:FL{fl}:SM{sm}"); | ||
| (telemetry.expose_adapter)(&get_telemetry_key(), category); | ||
| } | ||
|
|
||
| Some(crate::ExposedAdapter { | ||
| adapter: super::Adapter { | ||
| raw: adapter, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is a pretty long function already, it would be nice if we could isolate this in a function elsewhere - perhaps in a new
telemetrymodule.It seems like we should be able to collect
res, and then have something like:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, wait - now I see that
descanddriver_versionare all used later in the function. But it does still seem better to have at least the error analysis out of the way. And simply seeing a name liketelemetry::expose_adapter(blah blah blah)will help people skip this code more quickly.