mirror of
https://github.com/zed-industries/zed.git
synced 2026-06-01 03:14:56 +07:00
Merge 70d099fa0a into 09165c15dc
This commit is contained in:
commit
7bdf9e610e
8 changed files with 433 additions and 27 deletions
|
|
@ -16,6 +16,7 @@ default = []
|
||||||
font-kit = ["gpui_macos/font-kit"]
|
font-kit = ["gpui_macos/font-kit"]
|
||||||
test-support = ["gpui/test-support", "gpui_macos/test-support"]
|
test-support = ["gpui/test-support", "gpui_macos/test-support"]
|
||||||
screen-capture = ["gpui/screen-capture", "gpui_macos/screen-capture", "gpui_windows/screen-capture", "gpui_linux/screen-capture"]
|
screen-capture = ["gpui/screen-capture", "gpui_macos/screen-capture", "gpui_windows/screen-capture", "gpui_linux/screen-capture"]
|
||||||
|
win-legacy-compat = ["gpui_windows/win-legacy-compat"]
|
||||||
runtime_shaders = ["gpui_macos/runtime_shaders"]
|
runtime_shaders = ["gpui_macos/runtime_shaders"]
|
||||||
wayland = ["gpui_linux/wayland"]
|
wayland = ["gpui_linux/wayland"]
|
||||||
x11 = ["gpui_linux/x11"]
|
x11 = ["gpui_linux/x11"]
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,11 @@ path = "src/gpui_windows.rs"
|
||||||
default = ["gpui/default"]
|
default = ["gpui/default"]
|
||||||
test-support = ["gpui/test-support"]
|
test-support = ["gpui/test-support"]
|
||||||
screen-capture = ["gpui/screen-capture", "scap"]
|
screen-capture = ["gpui/screen-capture", "scap"]
|
||||||
|
# Enable compatibility workarounds for Windows Server 2016 / Windows 10 builds
|
||||||
|
# before 1809 (build 17763). Without this flag the crate behaves exactly like
|
||||||
|
# upstream: Factory6/Factory5 APIs, dual-source ClearType blending, standard
|
||||||
|
# MSAA quality sentinel, and no RDP/WDDM-1.x runtime detection.
|
||||||
|
win-legacy-compat = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
gpui.workspace = true
|
gpui.workspace = true
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,20 @@ mod shader_compilation {
|
||||||
let out_dir = std::env::var("OUT_DIR").unwrap();
|
let out_dir = std::env::var("OUT_DIR").unwrap();
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed={}", shader_path.display());
|
println!("cargo:rerun-if-changed={}", shader_path.display());
|
||||||
|
// Rerun when the feature flag changes so cached shader bytes are invalidated.
|
||||||
|
println!("cargo:rerun-if-env-changed=CARGO_FEATURE_WIN_LEGACY_COMPAT");
|
||||||
|
|
||||||
// Check if fxc.exe is available
|
// Check if fxc.exe is available
|
||||||
let fxc_path = find_fxc_compiler();
|
let fxc_path = find_fxc_compiler();
|
||||||
|
|
||||||
|
// Propagate Cargo feature to HLSL preprocessor so #ifdef WIN_LEGACY_COMPAT works.
|
||||||
|
let extra_defines: Vec<&str> =
|
||||||
|
if std::env::var("CARGO_FEATURE_WIN_LEGACY_COMPAT").is_ok() {
|
||||||
|
vec!["WIN_LEGACY_COMPAT"]
|
||||||
|
} else {
|
||||||
|
vec![]
|
||||||
|
};
|
||||||
|
|
||||||
// Define all modules
|
// Define all modules
|
||||||
let modules = [
|
let modules = [
|
||||||
"quad",
|
"quad",
|
||||||
|
|
@ -52,6 +62,7 @@ mod shader_compilation {
|
||||||
&fxc_path,
|
&fxc_path,
|
||||||
shader_path.to_str().unwrap(),
|
shader_path.to_str().unwrap(),
|
||||||
&rust_binding_path,
|
&rust_binding_path,
|
||||||
|
&extra_defines,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,6 +75,7 @@ mod shader_compilation {
|
||||||
&fxc_path,
|
&fxc_path,
|
||||||
shader_path.to_str().unwrap(),
|
shader_path.to_str().unwrap(),
|
||||||
&rust_binding_path,
|
&rust_binding_path,
|
||||||
|
&extra_defines,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -144,6 +156,7 @@ mod shader_compilation {
|
||||||
fxc_path: &str,
|
fxc_path: &str,
|
||||||
shader_path: &str,
|
shader_path: &str,
|
||||||
rust_binding_path: &str,
|
rust_binding_path: &str,
|
||||||
|
extra_defines: &[&str],
|
||||||
) {
|
) {
|
||||||
// Compile vertex shader
|
// Compile vertex shader
|
||||||
let output_file = format!("{}/{}_vs.h", out_dir, module);
|
let output_file = format!("{}/{}_vs.h", out_dir, module);
|
||||||
|
|
@ -155,6 +168,7 @@ mod shader_compilation {
|
||||||
&const_name,
|
&const_name,
|
||||||
shader_path,
|
shader_path,
|
||||||
"vs_4_1",
|
"vs_4_1",
|
||||||
|
extra_defines,
|
||||||
);
|
);
|
||||||
generate_rust_binding(&const_name, &output_file, rust_binding_path);
|
generate_rust_binding(&const_name, &output_file, rust_binding_path);
|
||||||
|
|
||||||
|
|
@ -168,6 +182,7 @@ mod shader_compilation {
|
||||||
&const_name,
|
&const_name,
|
||||||
shader_path,
|
shader_path,
|
||||||
"ps_4_1",
|
"ps_4_1",
|
||||||
|
extra_defines,
|
||||||
);
|
);
|
||||||
generate_rust_binding(&const_name, &output_file, rust_binding_path);
|
generate_rust_binding(&const_name, &output_file, rust_binding_path);
|
||||||
}
|
}
|
||||||
|
|
@ -179,20 +194,23 @@ mod shader_compilation {
|
||||||
var_name: &str,
|
var_name: &str,
|
||||||
shader_path: &str,
|
shader_path: &str,
|
||||||
target: &str,
|
target: &str,
|
||||||
|
extra_defines: &[&str],
|
||||||
) {
|
) {
|
||||||
let output = Command::new(fxc_path)
|
// All options (including /D defines) must come before the input filename.
|
||||||
.args([
|
let mut args = vec![
|
||||||
"/T",
|
"/T", target,
|
||||||
target,
|
"/E", entry_point,
|
||||||
"/E",
|
"/Fh", output_path,
|
||||||
entry_point,
|
"/Vn", var_name,
|
||||||
"/Fh",
|
|
||||||
output_path,
|
|
||||||
"/Vn",
|
|
||||||
var_name,
|
|
||||||
"/O3",
|
"/O3",
|
||||||
shader_path,
|
];
|
||||||
])
|
for define in extra_defines {
|
||||||
|
args.push("/D");
|
||||||
|
args.push(define);
|
||||||
|
}
|
||||||
|
args.push(shader_path);
|
||||||
|
let output = Command::new(fxc_path)
|
||||||
|
.args(&args)
|
||||||
.output();
|
.output();
|
||||||
|
|
||||||
match output {
|
match output {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,19 @@ use windows_numerics::Vector2;
|
||||||
use crate::*;
|
use crate::*;
|
||||||
use gpui::*;
|
use gpui::*;
|
||||||
|
|
||||||
|
/// DWrite factory: IDWriteFactory5 on upstream builds (Win10 1703+ for in-memory font loader),
|
||||||
|
/// IDWriteFactory4 when `win-legacy-compat` is enabled (Win10 1607 / Server 2016+).
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
|
type DWriteFactory = IDWriteFactory5;
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
type DWriteFactory = IDWriteFactory4;
|
||||||
|
|
||||||
|
/// Font-set builder: IDWriteFontSetBuilder1 (upstream) vs IDWriteFontSetBuilder (legacy).
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
|
type DWriteFontSetBuilder = IDWriteFontSetBuilder1;
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
type DWriteFontSetBuilder = IDWriteFontSetBuilder;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct FontInfo {
|
struct FontInfo {
|
||||||
font_family_h: HSTRING,
|
font_family_h: HSTRING,
|
||||||
|
|
@ -42,14 +55,16 @@ pub(crate) struct DirectWriteTextSystem {
|
||||||
|
|
||||||
struct DirectWriteComponents {
|
struct DirectWriteComponents {
|
||||||
locale: HSTRING,
|
locale: HSTRING,
|
||||||
factory: IDWriteFactory5,
|
factory: DWriteFactory,
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
in_memory_loader: IDWriteInMemoryFontFileLoader,
|
in_memory_loader: IDWriteInMemoryFontFileLoader,
|
||||||
builder: IDWriteFontSetBuilder1,
|
builder: DWriteFontSetBuilder,
|
||||||
text_renderer: TextRendererWrapper,
|
text_renderer: TextRendererWrapper,
|
||||||
system_ui_font_name: SharedString,
|
system_ui_font_name: SharedString,
|
||||||
system_subpixel_rendering: bool,
|
system_subpixel_rendering: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
impl Drop for DirectWriteComponents {
|
impl Drop for DirectWriteComponents {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -77,6 +92,8 @@ struct DirectWriteState {
|
||||||
font_to_font_id: HashMap<Font, FontId>,
|
font_to_font_id: HashMap<Font, FontId>,
|
||||||
font_info_cache: HashMap<usize, FontId>,
|
font_info_cache: HashMap<usize, FontId>,
|
||||||
layout_line_scratch: Vec<u16>,
|
layout_line_scratch: Vec<u16>,
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
temp_font_files: Vec<std::path::PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUState {
|
impl GPUState {
|
||||||
|
|
@ -164,11 +181,13 @@ impl GPUState {
|
||||||
|
|
||||||
impl DirectWriteTextSystem {
|
impl DirectWriteTextSystem {
|
||||||
pub(crate) fn new(directx_devices: &DirectXDevices) -> Result<Self> {
|
pub(crate) fn new(directx_devices: &DirectXDevices) -> Result<Self> {
|
||||||
let factory: IDWriteFactory5 = unsafe { DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED)? };
|
let factory: DWriteFactory = unsafe { DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED)? };
|
||||||
// The `IDWriteInMemoryFontFileLoader` here is supported starting from
|
// The `IDWriteInMemoryFontFileLoader` here is supported starting from
|
||||||
// Windows 10 Creators Update, which consequently requires the entire
|
// Windows 10 Creators Update, which consequently requires the entire
|
||||||
// `DirectWriteTextSystem` to run on `win10 1703`+.
|
// `DirectWriteTextSystem` to run on `win10 1703`+.
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
let in_memory_loader = unsafe { factory.CreateInMemoryFontFileLoader()? };
|
let in_memory_loader = unsafe { factory.CreateInMemoryFontFileLoader()? };
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
unsafe { factory.RegisterFontFileLoader(&in_memory_loader)? };
|
unsafe { factory.RegisterFontFileLoader(&in_memory_loader)? };
|
||||||
let builder = unsafe { factory.CreateFontSetBuilder()? };
|
let builder = unsafe { factory.CreateFontSetBuilder()? };
|
||||||
let mut locale = [0u16; LOCALE_NAME_MAX_LENGTH as usize];
|
let mut locale = [0u16; LOCALE_NAME_MAX_LENGTH as usize];
|
||||||
|
|
@ -183,6 +202,7 @@ impl DirectWriteTextSystem {
|
||||||
let components = DirectWriteComponents {
|
let components = DirectWriteComponents {
|
||||||
locale,
|
locale,
|
||||||
factory,
|
factory,
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
in_memory_loader,
|
in_memory_loader,
|
||||||
builder,
|
builder,
|
||||||
text_renderer,
|
text_renderer,
|
||||||
|
|
@ -214,6 +234,8 @@ impl DirectWriteTextSystem {
|
||||||
font_to_font_id: HashMap::default(),
|
font_to_font_id: HashMap::default(),
|
||||||
font_info_cache: HashMap::default(),
|
font_info_cache: HashMap::default(),
|
||||||
layout_line_scratch: Vec::new(),
|
layout_line_scratch: Vec::new(),
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
temp_font_files: Vec::new(),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -347,6 +369,7 @@ impl DirectWriteState {
|
||||||
Some(font_id)
|
Some(font_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
fn add_fonts(
|
fn add_fonts(
|
||||||
&mut self,
|
&mut self,
|
||||||
components: &DirectWriteComponents,
|
components: &DirectWriteComponents,
|
||||||
|
|
@ -385,9 +408,57 @@ impl DirectWriteState {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
fn add_fonts(
|
||||||
|
&mut self,
|
||||||
|
components: &DirectWriteComponents,
|
||||||
|
fonts: Vec<Cow<'static, [u8]>>,
|
||||||
|
) -> Result<()> {
|
||||||
|
for font_data in fonts {
|
||||||
|
let mut temp_path = std::env::temp_dir();
|
||||||
|
temp_path.push(format!(
|
||||||
|
"gpui_font_{}_{}.ttf",
|
||||||
|
std::process::id(),
|
||||||
|
self.temp_font_files.len()
|
||||||
|
));
|
||||||
|
std::fs::write(&temp_path, font_data.as_ref())?;
|
||||||
|
unsafe {
|
||||||
|
let path_hstr =
|
||||||
|
HSTRING::from(temp_path.to_str().context("non-UTF8 temp font path")?);
|
||||||
|
let font_file = components.factory.CreateFontFileReference(&path_hstr, None)?;
|
||||||
|
let mut is_supported = BOOL(0);
|
||||||
|
let mut _file_type = DWRITE_FONT_FILE_TYPE::default();
|
||||||
|
let mut face_count = 0u32;
|
||||||
|
font_file.Analyze(
|
||||||
|
&mut is_supported,
|
||||||
|
&mut _file_type,
|
||||||
|
None,
|
||||||
|
&mut face_count,
|
||||||
|
)?;
|
||||||
|
if is_supported.as_bool() {
|
||||||
|
for face_index in 0..face_count {
|
||||||
|
let face_ref = components.factory.CreateFontFaceReference2(
|
||||||
|
&path_hstr,
|
||||||
|
None,
|
||||||
|
face_index,
|
||||||
|
DWRITE_FONT_SIMULATIONS_NONE,
|
||||||
|
)?;
|
||||||
|
components.builder.AddFontFaceReference2(&face_ref)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.temp_font_files.push(temp_path);
|
||||||
|
}
|
||||||
|
let set = unsafe { components.builder.CreateFontSet()? };
|
||||||
|
let collection = unsafe { components.factory.CreateFontCollectionFromFontSet(&set)? };
|
||||||
|
self.custom_font_collection = collection;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_font_fallbacks(
|
fn generate_font_fallbacks(
|
||||||
fallbacks: &FontFallbacks,
|
fallbacks: &FontFallbacks,
|
||||||
factory: &IDWriteFactory5,
|
factory: &DWriteFactory,
|
||||||
system_font_collection: &IDWriteFontCollection1,
|
system_font_collection: &IDWriteFontCollection1,
|
||||||
) -> Result<Option<IDWriteFontFallback>> {
|
) -> Result<Option<IDWriteFontFallback>> {
|
||||||
let fallback_list = fallbacks.fallback_list();
|
let fallback_list = fallbacks.fallback_list();
|
||||||
|
|
@ -444,7 +515,7 @@ impl DirectWriteState {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn generate_font_features(
|
unsafe fn generate_font_features(
|
||||||
factory: &IDWriteFactory5,
|
factory: &DWriteFactory,
|
||||||
font_features: &FontFeatures,
|
font_features: &FontFeatures,
|
||||||
) -> Result<IDWriteTypography> {
|
) -> Result<IDWriteTypography> {
|
||||||
let direct_write_features = unsafe { factory.CreateTypography()? };
|
let direct_write_features = unsafe { factory.CreateTypography()? };
|
||||||
|
|
@ -461,7 +532,7 @@ impl DirectWriteState {
|
||||||
style,
|
style,
|
||||||
}: &Font,
|
}: &Font,
|
||||||
collection: &IDWriteFontCollection1,
|
collection: &IDWriteFontCollection1,
|
||||||
factory: &IDWriteFactory5,
|
factory: &DWriteFactory,
|
||||||
system_font_collection: &IDWriteFontCollection1,
|
system_font_collection: &IDWriteFontCollection1,
|
||||||
system_ui_font_name: &SharedString,
|
system_ui_font_name: &SharedString,
|
||||||
) -> Option<FontInfo> {
|
) -> Option<FontInfo> {
|
||||||
|
|
@ -1842,7 +1913,7 @@ fn get_system_ui_font_name() -> SharedString {
|
||||||
fn is_color_glyph(
|
fn is_color_glyph(
|
||||||
font_face: &IDWriteFontFace3,
|
font_face: &IDWriteFontFace3,
|
||||||
glyph_id: GlyphId,
|
glyph_id: GlyphId,
|
||||||
factory: &IDWriteFactory5,
|
factory: &DWriteFactory,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let glyph_run = DWRITE_GLYPH_RUN {
|
let glyph_run = DWRITE_GLYPH_RUN {
|
||||||
fontFace: ManuallyDrop::new(Some(unsafe { std::ptr::read(&****font_face) })),
|
fontFace: ManuallyDrop::new(Some(unsafe { std::ptr::read(&****font_face) })),
|
||||||
|
|
|
||||||
|
|
@ -15,11 +15,20 @@ use windows::Win32::{
|
||||||
},
|
},
|
||||||
Dxgi::{
|
Dxgi::{
|
||||||
CreateDXGIFactory2, DXGI_CREATE_FACTORY_DEBUG, DXGI_CREATE_FACTORY_FLAGS,
|
CreateDXGIFactory2, DXGI_CREATE_FACTORY_DEBUG, DXGI_CREATE_FACTORY_FLAGS,
|
||||||
IDXGIAdapter1, IDXGIFactory6,
|
IDXGIAdapter1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use windows::core::Interface;
|
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> {
|
pub(crate) fn try_to_recover_from_device_lost<T>(mut f: impl FnMut() -> Result<T>) -> Result<T> {
|
||||||
(0..5)
|
(0..5)
|
||||||
|
|
@ -38,7 +47,7 @@ pub(crate) fn try_to_recover_from_device_lost<T>(mut f: impl FnMut() -> Result<T
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct DirectXDevices {
|
pub(crate) struct DirectXDevices {
|
||||||
pub(crate) adapter: IDXGIAdapter1,
|
pub(crate) adapter: IDXGIAdapter1,
|
||||||
pub(crate) dxgi_factory: IDXGIFactory6,
|
pub(crate) dxgi_factory: DxgiFactory,
|
||||||
pub(crate) device: ID3D11Device,
|
pub(crate) device: ID3D11Device,
|
||||||
pub(crate) device_context: ID3D11DeviceContext,
|
pub(crate) device_context: ID3D11DeviceContext,
|
||||||
}
|
}
|
||||||
|
|
@ -89,7 +98,7 @@ fn check_debug_layer_available() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_dxgi_factory(debug_layer_available: bool) -> Result<IDXGIFactory6> {
|
fn get_dxgi_factory(debug_layer_available: bool) -> Result<DxgiFactory> {
|
||||||
let factory_flag = if debug_layer_available {
|
let factory_flag = if debug_layer_available {
|
||||||
DXGI_CREATE_FACTORY_DEBUG
|
DXGI_CREATE_FACTORY_DEBUG
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -104,7 +113,7 @@ fn get_dxgi_factory(debug_layer_available: bool) -> Result<IDXGIFactory6> {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_adapter(
|
fn get_adapter(
|
||||||
dxgi_factory: &IDXGIFactory6,
|
dxgi_factory: &DxgiFactory,
|
||||||
debug_layer_available: bool,
|
debug_layer_available: bool,
|
||||||
) -> Result<(
|
) -> Result<(
|
||||||
IDXGIAdapter1,
|
IDXGIAdapter1,
|
||||||
|
|
|
||||||
|
|
@ -53,13 +53,20 @@ pub(crate) struct DirectXRenderer {
|
||||||
/// In that case we want to discard the first frame that we draw as we got reset in the middle of a frame
|
/// In that case we want to discard the first frame that we draw as we got reset in the middle of a frame
|
||||||
/// meaning we lost all the allocated gpu textures and scene resources.
|
/// meaning we lost all the allocated gpu textures and scene resources.
|
||||||
skip_draws: bool,
|
skip_draws: bool,
|
||||||
|
|
||||||
|
/// True on Windows builds < 17763 (Server 2016 / Windows 10 pre-1809).
|
||||||
|
/// On these builds, D3D11_BUFFER_SRV FirstElement is unreliable on WDDM 1.x
|
||||||
|
/// drivers; each batch's data must be re-uploaded to buffer offset 0 and drawn
|
||||||
|
/// with first_instance=0 instead of relying on SRV range offsets.
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
is_pre_1809: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Direct3D objects
|
/// Direct3D objects
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct DirectXRendererDevices {
|
pub(crate) struct DirectXRendererDevices {
|
||||||
pub(crate) adapter: IDXGIAdapter1,
|
pub(crate) adapter: IDXGIAdapter1,
|
||||||
pub(crate) dxgi_factory: IDXGIFactory6,
|
pub(crate) dxgi_factory: DxgiFactory,
|
||||||
pub(crate) device: ID3D11Device,
|
pub(crate) device: ID3D11Device,
|
||||||
pub(crate) device_context: ID3D11DeviceContext,
|
pub(crate) device_context: ID3D11DeviceContext,
|
||||||
dxgi_device: Option<IDXGIDevice>,
|
dxgi_device: Option<IDXGIDevice>,
|
||||||
|
|
@ -148,6 +155,8 @@ impl DirectXRenderer {
|
||||||
.context("Creating DirectX resources")?;
|
.context("Creating DirectX resources")?;
|
||||||
let globals = DirectXGlobalElements::new(&devices.device)
|
let globals = DirectXGlobalElements::new(&devices.device)
|
||||||
.context("Creating DirectX global elements")?;
|
.context("Creating DirectX global elements")?;
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
let is_pre_1809 = is_pre_1809_build();
|
||||||
let pipelines = DirectXRenderPipelines::new(&devices.device)
|
let pipelines = DirectXRenderPipelines::new(&devices.device)
|
||||||
.context("Creating DirectX render pipelines")?;
|
.context("Creating DirectX render pipelines")?;
|
||||||
|
|
||||||
|
|
@ -174,6 +183,8 @@ impl DirectXRenderer {
|
||||||
width: 1,
|
width: 1,
|
||||||
height: 1,
|
height: 1,
|
||||||
skip_draws: false,
|
skip_draws: false,
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
is_pre_1809,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -272,6 +283,8 @@ impl DirectXRenderer {
|
||||||
.context("Creating DirectX resources")?;
|
.context("Creating DirectX resources")?;
|
||||||
let globals = DirectXGlobalElements::new(&devices.device)
|
let globals = DirectXGlobalElements::new(&devices.device)
|
||||||
.context("Creating DirectXGlobalElements")?;
|
.context("Creating DirectXGlobalElements")?;
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
let is_pre_1809 = is_pre_1809_build();
|
||||||
let pipelines = DirectXRenderPipelines::new(&devices.device)
|
let pipelines = DirectXRenderPipelines::new(&devices.device)
|
||||||
.context("Creating DirectXRenderPipelines")?;
|
.context("Creating DirectXRenderPipelines")?;
|
||||||
|
|
||||||
|
|
@ -297,6 +310,8 @@ impl DirectXRenderer {
|
||||||
self.globals = globals;
|
self.globals = globals;
|
||||||
self.pipelines = pipelines;
|
self.pipelines = pipelines;
|
||||||
self.direct_composition = direct_composition;
|
self.direct_composition = direct_composition;
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
{ self.is_pre_1809 = is_pre_1809; }
|
||||||
self.skip_draws = true;
|
self.skip_draws = true;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -320,23 +335,47 @@ impl DirectXRenderer {
|
||||||
|
|
||||||
for batch in scene.batches() {
|
for batch in scene.batches() {
|
||||||
match batch {
|
match batch {
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
PrimitiveBatch::Shadows(range) => self.draw_shadows(range.start, range.len()),
|
PrimitiveBatch::Shadows(range) => self.draw_shadows(range.start, range.len()),
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
PrimitiveBatch::Shadows(range) => self.draw_shadows(scene, range.start, range.len()),
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
PrimitiveBatch::Quads(range) => self.draw_quads(range.start, range.len()),
|
PrimitiveBatch::Quads(range) => self.draw_quads(range.start, range.len()),
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
PrimitiveBatch::Quads(range) => self.draw_quads(scene, range.start, range.len()),
|
||||||
PrimitiveBatch::Paths(range) => {
|
PrimitiveBatch::Paths(range) => {
|
||||||
let paths = &scene.paths[range];
|
let paths = &scene.paths[range];
|
||||||
self.draw_paths_to_intermediate(paths)?;
|
self.draw_paths_to_intermediate(paths)?;
|
||||||
self.draw_paths_from_intermediate(paths)
|
self.draw_paths_from_intermediate(paths)
|
||||||
}
|
}
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
PrimitiveBatch::Underlines(range) => self.draw_underlines(range.start, range.len()),
|
PrimitiveBatch::Underlines(range) => self.draw_underlines(range.start, range.len()),
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
PrimitiveBatch::Underlines(range) => self.draw_underlines(scene, range.start, range.len()),
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
PrimitiveBatch::MonochromeSprites { texture_id, range } => {
|
PrimitiveBatch::MonochromeSprites { texture_id, range } => {
|
||||||
self.draw_monochrome_sprites(texture_id, range.start, range.len())
|
self.draw_monochrome_sprites(texture_id, range.start, range.len())
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
PrimitiveBatch::MonochromeSprites { texture_id, range } => {
|
||||||
|
self.draw_monochrome_sprites(scene, texture_id, range.start, range.len())
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
PrimitiveBatch::SubpixelSprites { texture_id, range } => {
|
PrimitiveBatch::SubpixelSprites { texture_id, range } => {
|
||||||
self.draw_subpixel_sprites(texture_id, range.start, range.len())
|
self.draw_subpixel_sprites(texture_id, range.start, range.len())
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
PrimitiveBatch::SubpixelSprites { texture_id, range } => {
|
||||||
|
self.draw_subpixel_sprites(scene, texture_id, range.start, range.len())
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
PrimitiveBatch::PolychromeSprites { texture_id, range } => {
|
PrimitiveBatch::PolychromeSprites { texture_id, range } => {
|
||||||
self.draw_polychrome_sprites(texture_id, range.start, range.len())
|
self.draw_polychrome_sprites(texture_id, range.start, range.len())
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
PrimitiveBatch::PolychromeSprites { texture_id, range } => {
|
||||||
|
self.draw_polychrome_sprites(scene, texture_id, range.start, range.len())
|
||||||
|
}
|
||||||
PrimitiveBatch::Surfaces(range) => self.draw_surfaces(&scene.surfaces[range]),
|
PrimitiveBatch::Surfaces(range) => self.draw_surfaces(&scene.surfaces[range]),
|
||||||
}
|
}
|
||||||
.context(format!(
|
.context(format!(
|
||||||
|
|
@ -453,6 +492,7 @@ impl DirectXRenderer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
fn draw_shadows(&mut self, start: usize, len: usize) -> Result<()> {
|
fn draw_shadows(&mut self, start: usize, len: usize) -> Result<()> {
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -475,6 +515,33 @@ impl DirectXRenderer {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
fn draw_shadows(&mut self, scene: &Scene, start: usize, len: usize) -> Result<()> {
|
||||||
|
if len == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let devices = self.devices.as_ref().context("devices missing")?;
|
||||||
|
if self.is_pre_1809 {
|
||||||
|
self.pipelines.shadow_pipeline.update_buffer(&devices.device, &devices.device_context, &scene.shadows[start..start + len])?;
|
||||||
|
}
|
||||||
|
self.pipelines.shadow_pipeline.draw_range(
|
||||||
|
&devices.device,
|
||||||
|
&devices.device_context,
|
||||||
|
slice::from_ref(
|
||||||
|
&self
|
||||||
|
.resources
|
||||||
|
.as_ref()
|
||||||
|
.context("resources missing")?
|
||||||
|
.viewport,
|
||||||
|
),
|
||||||
|
slice::from_ref(&self.globals.global_params_buffer),
|
||||||
|
4,
|
||||||
|
if !self.is_pre_1809 { start as u32 } else { 0 },
|
||||||
|
len as u32,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
fn draw_quads(&mut self, start: usize, len: usize) -> Result<()> {
|
fn draw_quads(&mut self, start: usize, len: usize) -> Result<()> {
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -497,6 +564,32 @@ impl DirectXRenderer {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
fn draw_quads(&mut self, scene: &Scene, start: usize, len: usize) -> Result<()> {
|
||||||
|
if len == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let devices = self.devices.as_ref().context("devices missing")?;
|
||||||
|
if self.is_pre_1809 {
|
||||||
|
self.pipelines.quad_pipeline.update_buffer(&devices.device, &devices.device_context, &scene.quads[start..start + len])?;
|
||||||
|
}
|
||||||
|
self.pipelines.quad_pipeline.draw_range(
|
||||||
|
&devices.device,
|
||||||
|
&devices.device_context,
|
||||||
|
slice::from_ref(
|
||||||
|
&self
|
||||||
|
.resources
|
||||||
|
.as_ref()
|
||||||
|
.context("resources missing")?
|
||||||
|
.viewport,
|
||||||
|
),
|
||||||
|
slice::from_ref(&self.globals.global_params_buffer),
|
||||||
|
4,
|
||||||
|
if !self.is_pre_1809 { start as u32 } else { 0 },
|
||||||
|
len as u32,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn draw_paths_to_intermediate(&mut self, paths: &[Path<ScaledPixels>]) -> Result<()> {
|
fn draw_paths_to_intermediate(&mut self, paths: &[Path<ScaledPixels>]) -> Result<()> {
|
||||||
if paths.is_empty() {
|
if paths.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -608,6 +701,7 @@ impl DirectXRenderer {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
fn draw_underlines(&mut self, start: usize, len: usize) -> Result<()> {
|
fn draw_underlines(&mut self, start: usize, len: usize) -> Result<()> {
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -625,6 +719,28 @@ impl DirectXRenderer {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
fn draw_underlines(&mut self, scene: &Scene, start: usize, len: usize) -> Result<()> {
|
||||||
|
if len == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let devices = self.devices.as_ref().context("devices missing")?;
|
||||||
|
if self.is_pre_1809 {
|
||||||
|
self.pipelines.underline_pipeline.update_buffer(&devices.device, &devices.device_context, &scene.underlines[start..start + len])?;
|
||||||
|
}
|
||||||
|
let resources = self.resources.as_ref().context("resources missing")?;
|
||||||
|
self.pipelines.underline_pipeline.draw_range(
|
||||||
|
&devices.device,
|
||||||
|
&devices.device_context,
|
||||||
|
slice::from_ref(&resources.viewport),
|
||||||
|
slice::from_ref(&self.globals.global_params_buffer),
|
||||||
|
4,
|
||||||
|
if !self.is_pre_1809 { start as u32 } else { 0 },
|
||||||
|
len as u32,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
fn draw_monochrome_sprites(
|
fn draw_monochrome_sprites(
|
||||||
&mut self,
|
&mut self,
|
||||||
texture_id: AtlasTextureId,
|
texture_id: AtlasTextureId,
|
||||||
|
|
@ -649,6 +765,36 @@ impl DirectXRenderer {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
fn draw_monochrome_sprites(
|
||||||
|
&mut self,
|
||||||
|
scene: &Scene,
|
||||||
|
texture_id: AtlasTextureId,
|
||||||
|
start: usize,
|
||||||
|
len: usize,
|
||||||
|
) -> Result<()> {
|
||||||
|
if len == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let devices = self.devices.as_ref().context("devices missing")?;
|
||||||
|
if self.is_pre_1809 {
|
||||||
|
self.pipelines.mono_sprites.update_buffer(&devices.device, &devices.device_context, &scene.monochrome_sprites[start..start + len])?;
|
||||||
|
}
|
||||||
|
let resources = self.resources.as_ref().context("resources missing")?;
|
||||||
|
let texture_view = self.atlas.get_texture_view(texture_id);
|
||||||
|
self.pipelines.mono_sprites.draw_range_with_texture(
|
||||||
|
&devices.device,
|
||||||
|
&devices.device_context,
|
||||||
|
&texture_view,
|
||||||
|
slice::from_ref(&resources.viewport),
|
||||||
|
slice::from_ref(&self.globals.global_params_buffer),
|
||||||
|
slice::from_ref(&self.globals.sampler),
|
||||||
|
if !self.is_pre_1809 { start as u32 } else { 0 },
|
||||||
|
len as u32,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
fn draw_subpixel_sprites(
|
fn draw_subpixel_sprites(
|
||||||
&mut self,
|
&mut self,
|
||||||
texture_id: AtlasTextureId,
|
texture_id: AtlasTextureId,
|
||||||
|
|
@ -673,6 +819,36 @@ impl DirectXRenderer {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
fn draw_subpixel_sprites(
|
||||||
|
&mut self,
|
||||||
|
scene: &Scene,
|
||||||
|
texture_id: AtlasTextureId,
|
||||||
|
start: usize,
|
||||||
|
len: usize,
|
||||||
|
) -> Result<()> {
|
||||||
|
if len == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let devices = self.devices.as_ref().context("devices missing")?;
|
||||||
|
if self.is_pre_1809 {
|
||||||
|
self.pipelines.subpixel_sprites.update_buffer(&devices.device, &devices.device_context, &scene.subpixel_sprites[start..start + len])?;
|
||||||
|
}
|
||||||
|
let resources = self.resources.as_ref().context("resources missing")?;
|
||||||
|
let texture_view = self.atlas.get_texture_view(texture_id);
|
||||||
|
self.pipelines.subpixel_sprites.draw_range_with_texture(
|
||||||
|
&devices.device,
|
||||||
|
&devices.device_context,
|
||||||
|
&texture_view,
|
||||||
|
slice::from_ref(&resources.viewport),
|
||||||
|
slice::from_ref(&self.globals.global_params_buffer),
|
||||||
|
slice::from_ref(&self.globals.sampler),
|
||||||
|
if !self.is_pre_1809 { start as u32 } else { 0 },
|
||||||
|
len as u32,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
fn draw_polychrome_sprites(
|
fn draw_polychrome_sprites(
|
||||||
&mut self,
|
&mut self,
|
||||||
texture_id: AtlasTextureId,
|
texture_id: AtlasTextureId,
|
||||||
|
|
@ -697,6 +873,35 @@ impl DirectXRenderer {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
fn draw_polychrome_sprites(
|
||||||
|
&mut self,
|
||||||
|
scene: &Scene,
|
||||||
|
texture_id: AtlasTextureId,
|
||||||
|
start: usize,
|
||||||
|
len: usize,
|
||||||
|
) -> Result<()> {
|
||||||
|
if len == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
let devices = self.devices.as_ref().context("devices missing")?;
|
||||||
|
if self.is_pre_1809 {
|
||||||
|
self.pipelines.poly_sprites.update_buffer(&devices.device, &devices.device_context, &scene.polychrome_sprites[start..start + len])?;
|
||||||
|
}
|
||||||
|
let resources = self.resources.as_ref().context("resources missing")?;
|
||||||
|
let texture_view = self.atlas.get_texture_view(texture_id);
|
||||||
|
self.pipelines.poly_sprites.draw_range_with_texture(
|
||||||
|
&devices.device,
|
||||||
|
&devices.device_context,
|
||||||
|
&texture_view,
|
||||||
|
slice::from_ref(&resources.viewport),
|
||||||
|
slice::from_ref(&self.globals.global_params_buffer),
|
||||||
|
slice::from_ref(&self.globals.sampler),
|
||||||
|
if !self.is_pre_1809 { start as u32 } else { 0 },
|
||||||
|
len as u32,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn draw_surfaces(&mut self, surfaces: &[PaintSurface]) -> Result<()> {
|
fn draw_surfaces(&mut self, surfaces: &[PaintSurface]) -> Result<()> {
|
||||||
if surfaces.is_empty() {
|
if surfaces.is_empty() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -737,7 +942,10 @@ impl DirectXRenderer {
|
||||||
pub(crate) fn get_font_info() -> &'static FontInfo {
|
pub(crate) fn get_font_info() -> &'static FontInfo {
|
||||||
static CACHED_FONT_INFO: OnceLock<FontInfo> = OnceLock::new();
|
static CACHED_FONT_INFO: OnceLock<FontInfo> = OnceLock::new();
|
||||||
CACHED_FONT_INFO.get_or_init(|| unsafe {
|
CACHED_FONT_INFO.get_or_init(|| unsafe {
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
let factory: IDWriteFactory5 = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED).unwrap();
|
let factory: IDWriteFactory5 = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED).unwrap();
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
let factory: IDWriteFactory4 = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED).unwrap();
|
||||||
let render_params: IDWriteRenderingParams1 =
|
let render_params: IDWriteRenderingParams1 =
|
||||||
factory.CreateRenderingParams().unwrap().cast().unwrap();
|
factory.CreateRenderingParams().unwrap().cast().unwrap();
|
||||||
FontInfo {
|
FontInfo {
|
||||||
|
|
@ -872,6 +1080,11 @@ impl DirectXRenderPipelines {
|
||||||
"subpixel_sprite_pipeline",
|
"subpixel_sprite_pipeline",
|
||||||
ShaderModule::SubpixelSprite,
|
ShaderModule::SubpixelSprite,
|
||||||
512,
|
512,
|
||||||
|
// win-legacy-compat: standard alpha blending (dual-source broken on WDDM 1.x).
|
||||||
|
// Upstream: dual-source (D3D11_BLEND_SRC1_COLOR) for per-channel ClearType.
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
create_blend_state(device)?,
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
create_blend_state_for_subpixel_rendering(device)?,
|
create_blend_state_for_subpixel_rendering(device)?,
|
||||||
)?;
|
)?;
|
||||||
let poly_sprites = PipelineState::new(
|
let poly_sprites = PipelineState::new(
|
||||||
|
|
@ -1080,6 +1293,7 @@ impl<T> PipelineState<T> {
|
||||||
);
|
);
|
||||||
unsafe {
|
unsafe {
|
||||||
device_context.PSSetSamplers(0, Some(sampler));
|
device_context.PSSetSamplers(0, Some(sampler));
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
device_context.VSSetShaderResources(0, Some(texture));
|
device_context.VSSetShaderResources(0, Some(texture));
|
||||||
device_context.PSSetShaderResources(0, Some(texture));
|
device_context.PSSetShaderResources(0, Some(texture));
|
||||||
|
|
||||||
|
|
@ -1177,7 +1391,7 @@ fn get_comp_device(dxgi_device: &IDXGIDevice) -> Result<IDCompositionDevice> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_swap_chain_for_composition(
|
fn create_swap_chain_for_composition(
|
||||||
dxgi_factory: &IDXGIFactory6,
|
dxgi_factory: &DxgiFactory,
|
||||||
device: &ID3D11Device,
|
device: &ID3D11Device,
|
||||||
width: u32,
|
width: u32,
|
||||||
height: u32,
|
height: u32,
|
||||||
|
|
@ -1203,7 +1417,7 @@ fn create_swap_chain_for_composition(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_swap_chain(
|
fn create_swap_chain(
|
||||||
dxgi_factory: &IDXGIFactory6,
|
dxgi_factory: &DxgiFactory,
|
||||||
device: &ID3D11Device,
|
device: &ID3D11Device,
|
||||||
hwnd: HWND,
|
hwnd: HWND,
|
||||||
width: u32,
|
width: u32,
|
||||||
|
|
@ -1326,7 +1540,10 @@ fn create_path_intermediate_msaa_texture_and_view(
|
||||||
Format: RENDER_TARGET_FORMAT,
|
Format: RENDER_TARGET_FORMAT,
|
||||||
SampleDesc: DXGI_SAMPLE_DESC {
|
SampleDesc: DXGI_SAMPLE_DESC {
|
||||||
Count: PATH_MULTISAMPLE_COUNT,
|
Count: PATH_MULTISAMPLE_COUNT,
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
Quality: D3D11_STANDARD_MULTISAMPLE_PATTERN.0 as u32,
|
Quality: D3D11_STANDARD_MULTISAMPLE_PATTERN.0 as u32,
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
Quality: 0, // quality 0 is universally supported; D3D11_STANDARD_MULTISAMPLE_PATTERN requires D3D11.1
|
||||||
},
|
},
|
||||||
Usage: D3D11_USAGE_DEFAULT,
|
Usage: D3D11_USAGE_DEFAULT,
|
||||||
BindFlags: D3D11_BIND_RENDER_TARGET.0 as u32,
|
BindFlags: D3D11_BIND_RENDER_TARGET.0 as u32,
|
||||||
|
|
@ -1398,6 +1615,7 @@ fn create_blend_state(device: &ID3D11Device) -> Result<ID3D11BlendState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
fn create_blend_state_for_subpixel_rendering(device: &ID3D11Device) -> Result<ID3D11BlendState> {
|
fn create_blend_state_for_subpixel_rendering(device: &ID3D11Device) -> Result<ID3D11BlendState> {
|
||||||
let mut desc = D3D11_BLEND_DESC::default();
|
let mut desc = D3D11_BLEND_DESC::default();
|
||||||
desc.RenderTarget[0].BlendEnable = true.into();
|
desc.RenderTarget[0].BlendEnable = true.into();
|
||||||
|
|
@ -1587,6 +1805,7 @@ pub(crate) mod shader_resources {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
use windows::{
|
use windows::{
|
||||||
Win32::Graphics::Direct3D::{
|
Win32::Graphics::Direct3D::{
|
||||||
|
D3D_SHADER_MACRO,
|
||||||
Fxc::{D3DCOMPILE_DEBUG, D3DCOMPILE_SKIP_OPTIMIZATION, D3DCompileFromFile},
|
Fxc::{D3DCOMPILE_DEBUG, D3DCOMPILE_SKIP_OPTIMIZATION, D3DCompileFromFile},
|
||||||
ID3DBlob,
|
ID3DBlob,
|
||||||
},
|
},
|
||||||
|
|
@ -1726,9 +1945,23 @@ pub(crate) mod shader_resources {
|
||||||
D3D_COMPILE_STANDARD_FILE_INCLUDE as usize,
|
D3D_COMPILE_STANDARD_FILE_INCLUDE as usize,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Build a null-terminated D3D_SHADER_MACRO list for any active features.
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
let defines_storage = [
|
||||||
|
D3D_SHADER_MACRO {
|
||||||
|
Name: windows::core::s!("WIN_LEGACY_COMPAT"),
|
||||||
|
Definition: windows::core::s!("1"),
|
||||||
|
},
|
||||||
|
D3D_SHADER_MACRO { Name: PCSTR::null(), Definition: PCSTR::null() },
|
||||||
|
];
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
let defines_ptr: Option<*const D3D_SHADER_MACRO> = Some(defines_storage.as_ptr());
|
||||||
|
#[cfg(not(feature = "win-legacy-compat"))]
|
||||||
|
let defines_ptr: Option<*const D3D_SHADER_MACRO> = None;
|
||||||
|
|
||||||
let ret = D3DCompileFromFile(
|
let ret = D3DCompileFromFile(
|
||||||
&HSTRING::from(shader_path.to_str().unwrap()),
|
&HSTRING::from(shader_path.to_str().unwrap()),
|
||||||
None,
|
defines_ptr,
|
||||||
include_handler,
|
include_handler,
|
||||||
entry_point,
|
entry_point,
|
||||||
target_cstr,
|
target_cstr,
|
||||||
|
|
@ -1955,3 +2188,60 @@ mod dxgi {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
/// Returns true on Windows builds before 17763 (Windows 10 1809 / Windows Server 2019).
|
||||||
|
///
|
||||||
|
/// On these older builds, D3D11_BUFFER_SRV FirstElement and DrawInstanced
|
||||||
|
/// StartInstanceLocation are unreliable on WDDM 1.x virtual GPU drivers
|
||||||
|
/// (e.g. Windows Server 2016 RDP WARP). Re-uploading each batch at buffer
|
||||||
|
/// offset 0 and drawing with first_instance=0 works around the issue.
|
||||||
|
///
|
||||||
|
/// Uses RtlGetVersion via ntdll.dll to bypass the GetVersionEx lie introduced
|
||||||
|
/// in Windows 8.1 (manifested applications always see 6.2 without this).
|
||||||
|
fn is_pre_1809_build() -> bool {
|
||||||
|
use std::mem;
|
||||||
|
use windows::Win32::System::LibraryLoader::{GetModuleHandleA, GetProcAddress};
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
struct OsVersionInfoExW {
|
||||||
|
dw_size: u32,
|
||||||
|
dw_major_version: u32,
|
||||||
|
dw_minor_version: u32,
|
||||||
|
dw_build_number: u32,
|
||||||
|
dw_platform_id: u32,
|
||||||
|
sz_csd_version: [u16; 128],
|
||||||
|
w_service_pack_major: u16,
|
||||||
|
w_service_pack_minor: u16,
|
||||||
|
w_suite_mask: u16,
|
||||||
|
w_product_type: u8,
|
||||||
|
w_reserved: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let ntdll = GetModuleHandleA(windows::core::s!("ntdll.dll"));
|
||||||
|
let Ok(ntdll) = ntdll else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let proc = GetProcAddress(ntdll, windows::core::s!("RtlGetVersion"));
|
||||||
|
let Some(proc) = proc else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
type RtlGetVersionFn = unsafe extern "system" fn(*mut OsVersionInfoExW) -> i32;
|
||||||
|
let rtl_get_version: RtlGetVersionFn = mem::transmute(proc);
|
||||||
|
|
||||||
|
let mut info: OsVersionInfoExW = mem::zeroed();
|
||||||
|
info.dw_size = mem::size_of::<OsVersionInfoExW>() as u32;
|
||||||
|
rtl_get_version(&mut info);
|
||||||
|
|
||||||
|
let is_pre_1809 = info.dw_build_number < 17763;
|
||||||
|
if is_pre_1809 {
|
||||||
|
log::info!(
|
||||||
|
"OS build {} < 17763: enabling WDDM 1.x SRV FirstElement workaround.",
|
||||||
|
info.dw_build_number
|
||||||
|
);
|
||||||
|
}
|
||||||
|
is_pre_1809
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,9 @@ impl WindowsPlatform {
|
||||||
|
|
||||||
let disable_direct_composition = std::env::var(DISABLE_DIRECT_COMPOSITION)
|
let disable_direct_composition = std::env::var(DISABLE_DIRECT_COMPOSITION)
|
||||||
.is_ok_and(|value| value == "true" || value == "1");
|
.is_ok_and(|value| value == "true" || value == "1");
|
||||||
|
#[cfg(feature = "win-legacy-compat")]
|
||||||
|
let disable_direct_composition =
|
||||||
|
disable_direct_composition || unsafe { GetSystemMetrics(SM_REMOTESESSION) != 0 };
|
||||||
let background_executor = BackgroundExecutor::new(dispatcher.clone());
|
let background_executor = BackgroundExecutor::new(dispatcher.clone());
|
||||||
let foreground_executor = ForegroundExecutor::new(dispatcher);
|
let foreground_executor = ForegroundExecutor::new(dispatcher);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1190,8 +1190,17 @@ SubpixelSpriteFragmentOutput subpixel_sprite_fragment(MonochromeSpriteFragmentIn
|
||||||
float3 alpha_corrected = apply_contrast_and_gamma_correction3(sample, input.color.rgb, subpixel_enhanced_contrast, gamma_ratios);
|
float3 alpha_corrected = apply_contrast_and_gamma_correction3(sample, input.color.rgb, subpixel_enhanced_contrast, gamma_ratios);
|
||||||
|
|
||||||
SubpixelSpriteFragmentOutput output;
|
SubpixelSpriteFragmentOutput output;
|
||||||
|
#ifdef WIN_LEGACY_COMPAT
|
||||||
|
// Scalar alpha blending: collapses per-channel ClearType mask to a luminance
|
||||||
|
// scalar for use with standard SRC_ALPHA / INV_SRC_ALPHA blending.
|
||||||
|
// Required on pre-1809 WARP/virtual GPU where dual-source blending is broken.
|
||||||
|
float scalar_alpha = dot(alpha_corrected, float3(1.0f / 3.0f, 1.0f / 3.0f, 1.0f / 3.0f));
|
||||||
|
output.foreground = float4(input.color.rgb, input.color.a * scalar_alpha);
|
||||||
|
output.alpha = float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
#else
|
||||||
output.foreground = float4(input.color.rgb, 1.0f);
|
output.foreground = float4(input.color.rgb, 1.0f);
|
||||||
output.alpha = float4(input.color.a * alpha_corrected, 1.0f);
|
output.alpha = float4(input.color.a * alpha_corrected, 1.0f);
|
||||||
|
#endif
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue