mirror of
https://github.com/zed-industries/zed.git
synced 2026-06-01 03:14:56 +07:00
Introduces a `win-legacy-compat` Cargo feature (forwarded from `gpui_platform`) that gates all Windows Server 2016 / pre-Windows 10 1809 workarounds behind a compile-time flag, preserving exact upstream behaviour and performance when the flag is absent. Changes when `win-legacy-compat` is enabled: - directx_devices.rs: use IDXGIFactory2 (DXGI 1.2, Win8+) instead of IDXGIFactory6 - direct_write.rs: use IDWriteFactory4 + IDWriteFontSetBuilder (Server 2016) instead of Factory5 + in-memory font loader; fall back to temp files for custom font loading - directx_renderer.rs: runtime is_pre_1809 check gates SRV FirstElement workaround; draw_* functions accept scene: &Scene for per-batch buffer re-upload on pre-1809; standard alpha blend replaces dual-source SRC1_COLOR for subpixel pipeline; MSAA quality 0 replaces D3D11_STANDARD_MULTISAMPLE_PATTERN (D3D11.1 sentinel); SM_REMOTESESSION check disables DirectComposition on RDP sessions - shaders.hlsl: #ifdef WIN_LEGACY_COMPAT collapses per-channel ClearType mask to scalar alpha for standard SRC_ALPHA/INV_SRC_ALPHA blending - build.rs: pass /D WIN_LEGACY_COMPAT to fxc (release); pass D3D_SHADER_MACRO define to D3DCompileFromFile (debug); fix /D argument order (must precede input filename); add rerun-if-env-changed for CARGO_FEATURE_WIN_LEGACY_COMPAT - gpui_platform/Cargo.toml: forward win-legacy-compat → gpui_windows/win-legacy-compat
203 lines
6.3 KiB
Rust
203 lines
6.3 KiB
Rust
use anyhow::{Context, Result};
|
|
use itertools::Itertools;
|
|
use util::ResultExt;
|
|
use windows::Win32::{
|
|
Foundation::HMODULE,
|
|
Graphics::{
|
|
Direct3D::{
|
|
D3D_DRIVER_TYPE_UNKNOWN, D3D_FEATURE_LEVEL, D3D_FEATURE_LEVEL_10_1,
|
|
D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1,
|
|
},
|
|
Direct3D11::{
|
|
D3D11_CREATE_DEVICE_BGRA_SUPPORT, D3D11_CREATE_DEVICE_DEBUG,
|
|
D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS, D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS,
|
|
D3D11_SDK_VERSION, D3D11CreateDevice, ID3D11Device, ID3D11DeviceContext,
|
|
},
|
|
Dxgi::{
|
|
CreateDXGIFactory2, DXGI_CREATE_FACTORY_DEBUG, DXGI_CREATE_FACTORY_FLAGS,
|
|
IDXGIAdapter1,
|
|
},
|
|
},
|
|
};
|
|
use windows::core::Interface;
|
|
#[cfg(not(feature = "win-legacy-compat"))]
|
|
use windows::Win32::Graphics::Dxgi::IDXGIFactory6;
|
|
#[cfg(feature = "win-legacy-compat")]
|
|
use windows::Win32::Graphics::Dxgi::IDXGIFactory2;
|
|
|
|
#[cfg(not(feature = "win-legacy-compat"))]
|
|
pub(crate) type DxgiFactory = IDXGIFactory6;
|
|
#[cfg(feature = "win-legacy-compat")]
|
|
pub(crate) type DxgiFactory = IDXGIFactory2;
|
|
|
|
pub(crate) fn try_to_recover_from_device_lost<T>(mut f: impl FnMut() -> Result<T>) -> Result<T> {
|
|
(0..5)
|
|
.map(|i| {
|
|
if i > 0 {
|
|
// Add a small delay before retrying
|
|
std::thread::sleep(std::time::Duration::from_millis(100 + i * 10));
|
|
}
|
|
f()
|
|
})
|
|
.find_or_last(Result::is_ok)
|
|
.unwrap()
|
|
.context("DirectXRenderer failed to recover from lost device after multiple attempts")
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub(crate) struct DirectXDevices {
|
|
pub(crate) adapter: IDXGIAdapter1,
|
|
pub(crate) dxgi_factory: DxgiFactory,
|
|
pub(crate) device: ID3D11Device,
|
|
pub(crate) device_context: ID3D11DeviceContext,
|
|
}
|
|
|
|
impl DirectXDevices {
|
|
pub(crate) fn new() -> Result<Self> {
|
|
let debug_layer_available = check_debug_layer_available();
|
|
let dxgi_factory =
|
|
get_dxgi_factory(debug_layer_available).context("Creating DXGI factory")?;
|
|
let (adapter, device, device_context, feature_level) =
|
|
get_adapter(&dxgi_factory, debug_layer_available).context("Getting DXGI adapter")?;
|
|
match feature_level {
|
|
D3D_FEATURE_LEVEL_11_1 => {
|
|
log::info!("Created device with Direct3D 11.1 feature level.")
|
|
}
|
|
D3D_FEATURE_LEVEL_11_0 => {
|
|
log::info!("Created device with Direct3D 11.0 feature level.")
|
|
}
|
|
D3D_FEATURE_LEVEL_10_1 => {
|
|
log::info!("Created device with Direct3D 10.1 feature level.")
|
|
}
|
|
_ => unreachable!(),
|
|
}
|
|
|
|
Ok(Self {
|
|
adapter,
|
|
dxgi_factory,
|
|
device,
|
|
device_context,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
fn check_debug_layer_available() -> bool {
|
|
#[cfg(debug_assertions)]
|
|
{
|
|
use windows::Win32::Graphics::Dxgi::{DXGIGetDebugInterface1, IDXGIInfoQueue};
|
|
|
|
unsafe { DXGIGetDebugInterface1::<IDXGIInfoQueue>(0) }
|
|
.log_err()
|
|
.is_some()
|
|
}
|
|
#[cfg(not(debug_assertions))]
|
|
{
|
|
false
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
fn get_dxgi_factory(debug_layer_available: bool) -> Result<DxgiFactory> {
|
|
let factory_flag = if debug_layer_available {
|
|
DXGI_CREATE_FACTORY_DEBUG
|
|
} else {
|
|
#[cfg(debug_assertions)]
|
|
log::warn!(
|
|
"Failed to get DXGI debug interface. DirectX debugging features will be disabled."
|
|
);
|
|
DXGI_CREATE_FACTORY_FLAGS::default()
|
|
};
|
|
unsafe { Ok(CreateDXGIFactory2(factory_flag)?) }
|
|
}
|
|
|
|
#[inline]
|
|
fn get_adapter(
|
|
dxgi_factory: &DxgiFactory,
|
|
debug_layer_available: bool,
|
|
) -> Result<(
|
|
IDXGIAdapter1,
|
|
ID3D11Device,
|
|
ID3D11DeviceContext,
|
|
D3D_FEATURE_LEVEL,
|
|
)> {
|
|
for adapter_index in 0.. {
|
|
let adapter: IDXGIAdapter1 = unsafe { dxgi_factory.EnumAdapters(adapter_index)?.cast()? };
|
|
if let Ok(desc) = unsafe { adapter.GetDesc1() } {
|
|
let gpu_name = String::from_utf16_lossy(&desc.Description)
|
|
.trim_matches(char::from(0))
|
|
.to_string();
|
|
log::info!("Using GPU: {}", gpu_name);
|
|
}
|
|
// Check to see whether the adapter supports Direct3D 11 and create
|
|
// the device if it does.
|
|
let mut context: Option<ID3D11DeviceContext> = None;
|
|
let mut feature_level = D3D_FEATURE_LEVEL::default();
|
|
if let Some(device) = get_device(
|
|
&adapter,
|
|
Some(&mut context),
|
|
Some(&mut feature_level),
|
|
debug_layer_available,
|
|
)
|
|
.log_err()
|
|
{
|
|
return Ok((adapter, device, context.unwrap(), feature_level));
|
|
}
|
|
}
|
|
|
|
unreachable!()
|
|
}
|
|
|
|
#[inline]
|
|
fn get_device(
|
|
adapter: &IDXGIAdapter1,
|
|
context: Option<*mut Option<ID3D11DeviceContext>>,
|
|
feature_level: Option<*mut D3D_FEATURE_LEVEL>,
|
|
debug_layer_available: bool,
|
|
) -> Result<ID3D11Device> {
|
|
let mut device: Option<ID3D11Device> = None;
|
|
let device_flags = if debug_layer_available {
|
|
D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_DEBUG
|
|
} else {
|
|
D3D11_CREATE_DEVICE_BGRA_SUPPORT
|
|
};
|
|
unsafe {
|
|
D3D11CreateDevice(
|
|
adapter,
|
|
D3D_DRIVER_TYPE_UNKNOWN,
|
|
HMODULE::default(),
|
|
device_flags,
|
|
// 4x MSAA is required for Direct3D Feature Level 10.1 or better
|
|
Some(&[
|
|
D3D_FEATURE_LEVEL_11_1,
|
|
D3D_FEATURE_LEVEL_11_0,
|
|
D3D_FEATURE_LEVEL_10_1,
|
|
]),
|
|
D3D11_SDK_VERSION,
|
|
Some(&mut device),
|
|
feature_level,
|
|
context,
|
|
)?;
|
|
}
|
|
let device = device.unwrap();
|
|
let mut data = D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS::default();
|
|
unsafe {
|
|
device
|
|
.CheckFeatureSupport(
|
|
D3D11_FEATURE_D3D10_X_HARDWARE_OPTIONS,
|
|
&mut data as *mut _ as _,
|
|
std::mem::size_of::<D3D11_FEATURE_DATA_D3D10_X_HARDWARE_OPTIONS>() as u32,
|
|
)
|
|
.context("Checking GPU device feature support")?;
|
|
}
|
|
if data
|
|
.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x
|
|
.as_bool()
|
|
{
|
|
Ok(device)
|
|
} else {
|
|
Err(anyhow::anyhow!(
|
|
"Required feature StructuredBuffer is not supported by GPU/driver"
|
|
))
|
|
}
|
|
}
|