windows: Port to DirectX 11 (#34374)
Closes #16713 Closes #19739 Closes #33191 Closes #26692 Closes #17374 Closes #35077 Closes https://github.com/zed-industries/zed/issues/35205 Closes https://github.com/zed-industries/zed/issues/35262 Compared to the current Vulkan implementation, this PR brings several improvements: - Fewer weird bugs - Better hardware compatibility - VSync support - More accurate colors - Lower memory usage - Graceful handling of device loss --- **TODO:** - [x] Don’t use AGS binaries directly - [ ] The message loop is using too much CPU when ths app is idle - [x] There’s a [bug](https://github.com/zed-industries/zed/issues/33191#issuecomment-3109306630) in how `Path` is being rendered. --- Release Notes: - N/A --------- Co-authored-by: Kate <kate@zed.dev> Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
parent
0d9715325c
commit
15ad986329
17 changed files with 3577 additions and 180 deletions
|
@ -680,8 +680,13 @@ features = [
|
||||||
"Win32_Globalization",
|
"Win32_Globalization",
|
||||||
"Win32_Graphics_Direct2D",
|
"Win32_Graphics_Direct2D",
|
||||||
"Win32_Graphics_Direct2D_Common",
|
"Win32_Graphics_Direct2D_Common",
|
||||||
|
"Win32_Graphics_Direct3D",
|
||||||
|
"Win32_Graphics_Direct3D11",
|
||||||
|
"Win32_Graphics_Direct3D_Fxc",
|
||||||
|
"Win32_Graphics_DirectComposition",
|
||||||
"Win32_Graphics_DirectWrite",
|
"Win32_Graphics_DirectWrite",
|
||||||
"Win32_Graphics_Dwm",
|
"Win32_Graphics_Dwm",
|
||||||
|
"Win32_Graphics_Dxgi",
|
||||||
"Win32_Graphics_Dxgi_Common",
|
"Win32_Graphics_Dxgi_Common",
|
||||||
"Win32_Graphics_Gdi",
|
"Win32_Graphics_Gdi",
|
||||||
"Win32_Graphics_Imaging",
|
"Win32_Graphics_Imaging",
|
||||||
|
|
|
@ -216,10 +216,6 @@ xim = { git = "https://github.com/XDeme1/xim-rs", rev = "d50d461764c2213655cd9cf
|
||||||
x11-clipboard = { version = "0.9.3", optional = true }
|
x11-clipboard = { version = "0.9.3", optional = true }
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
blade-util.workspace = true
|
|
||||||
bytemuck = "1"
|
|
||||||
blade-graphics.workspace = true
|
|
||||||
blade-macros.workspace = true
|
|
||||||
flume = "0.11"
|
flume = "0.11"
|
||||||
rand.workspace = true
|
rand.workspace = true
|
||||||
windows.workspace = true
|
windows.workspace = true
|
||||||
|
@ -240,7 +236,6 @@ util = { workspace = true, features = ["test-support"] }
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.build-dependencies]
|
[target.'cfg(target_os = "windows")'.build-dependencies]
|
||||||
embed-resource = "3.0"
|
embed-resource = "3.0"
|
||||||
naga.workspace = true
|
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.build-dependencies]
|
[target.'cfg(target_os = "macos")'.build-dependencies]
|
||||||
bindgen = "0.71"
|
bindgen = "0.71"
|
||||||
|
|
|
@ -9,7 +9,10 @@ fn main() {
|
||||||
let target = env::var("CARGO_CFG_TARGET_OS");
|
let target = env::var("CARGO_CFG_TARGET_OS");
|
||||||
println!("cargo::rustc-check-cfg=cfg(gles)");
|
println!("cargo::rustc-check-cfg=cfg(gles)");
|
||||||
|
|
||||||
#[cfg(any(not(target_os = "macos"), feature = "macos-blade"))]
|
#[cfg(any(
|
||||||
|
not(any(target_os = "macos", target_os = "windows")),
|
||||||
|
all(target_os = "macos", feature = "macos-blade")
|
||||||
|
))]
|
||||||
check_wgsl_shaders();
|
check_wgsl_shaders();
|
||||||
|
|
||||||
match target.as_deref() {
|
match target.as_deref() {
|
||||||
|
@ -17,21 +20,18 @@ fn main() {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
macos::build();
|
macos::build();
|
||||||
}
|
}
|
||||||
#[cfg(all(target_os = "windows", feature = "windows-manifest"))]
|
|
||||||
Ok("windows") => {
|
Ok("windows") => {
|
||||||
let manifest = std::path::Path::new("resources/windows/gpui.manifest.xml");
|
#[cfg(target_os = "windows")]
|
||||||
let rc_file = std::path::Path::new("resources/windows/gpui.rc");
|
windows::build();
|
||||||
println!("cargo:rerun-if-changed={}", manifest.display());
|
|
||||||
println!("cargo:rerun-if-changed={}", rc_file.display());
|
|
||||||
embed_resource::compile(rc_file, embed_resource::NONE)
|
|
||||||
.manifest_required()
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[cfg(any(
|
||||||
|
not(any(target_os = "macos", target_os = "windows")),
|
||||||
|
all(target_os = "macos", feature = "macos-blade")
|
||||||
|
))]
|
||||||
fn check_wgsl_shaders() {
|
fn check_wgsl_shaders() {
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process;
|
use std::process;
|
||||||
|
@ -243,3 +243,203 @@ mod macos {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
mod windows {
|
||||||
|
use std::{
|
||||||
|
fs,
|
||||||
|
io::Write,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
process::{self, Command},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(super) fn build() {
|
||||||
|
// Compile HLSL shaders
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
compile_shaders();
|
||||||
|
|
||||||
|
// Embed the Windows manifest and resource file
|
||||||
|
#[cfg(feature = "windows-manifest")]
|
||||||
|
embed_resource();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "windows-manifest")]
|
||||||
|
fn embed_resource() {
|
||||||
|
let manifest = std::path::Path::new("resources/windows/gpui.manifest.xml");
|
||||||
|
let rc_file = std::path::Path::new("resources/windows/gpui.rc");
|
||||||
|
println!("cargo:rerun-if-changed={}", manifest.display());
|
||||||
|
println!("cargo:rerun-if-changed={}", rc_file.display());
|
||||||
|
embed_resource::compile(rc_file, embed_resource::NONE)
|
||||||
|
.manifest_required()
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// You can set the `GPUI_FXC_PATH` environment variable to specify the path to the fxc.exe compiler.
|
||||||
|
fn compile_shaders() {
|
||||||
|
let shader_path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap())
|
||||||
|
.join("src/platform/windows/shaders.hlsl");
|
||||||
|
let out_dir = std::env::var("OUT_DIR").unwrap();
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed={}", shader_path.display());
|
||||||
|
|
||||||
|
// Check if fxc.exe is available
|
||||||
|
let fxc_path = find_fxc_compiler();
|
||||||
|
|
||||||
|
// Define all modules
|
||||||
|
let modules = [
|
||||||
|
"quad",
|
||||||
|
"shadow",
|
||||||
|
"path_rasterization",
|
||||||
|
"path_sprite",
|
||||||
|
"underline",
|
||||||
|
"monochrome_sprite",
|
||||||
|
"polychrome_sprite",
|
||||||
|
];
|
||||||
|
|
||||||
|
let rust_binding_path = format!("{}/shaders_bytes.rs", out_dir);
|
||||||
|
if Path::new(&rust_binding_path).exists() {
|
||||||
|
fs::remove_file(&rust_binding_path)
|
||||||
|
.expect("Failed to remove existing Rust binding file");
|
||||||
|
}
|
||||||
|
for module in modules {
|
||||||
|
compile_shader_for_module(
|
||||||
|
module,
|
||||||
|
&out_dir,
|
||||||
|
&fxc_path,
|
||||||
|
shader_path.to_str().unwrap(),
|
||||||
|
&rust_binding_path,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// You can set the `GPUI_FXC_PATH` environment variable to specify the path to the fxc.exe compiler.
|
||||||
|
fn find_fxc_compiler() -> String {
|
||||||
|
// Check environment variable
|
||||||
|
if let Ok(path) = std::env::var("GPUI_FXC_PATH") {
|
||||||
|
if Path::new(&path).exists() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find in PATH
|
||||||
|
// NOTE: This has to be `where.exe` on Windows, not `where`, it must be ended with `.exe`
|
||||||
|
if let Ok(output) = std::process::Command::new("where.exe")
|
||||||
|
.arg("fxc.exe")
|
||||||
|
.output()
|
||||||
|
{
|
||||||
|
if output.status.success() {
|
||||||
|
let path = String::from_utf8_lossy(&output.stdout);
|
||||||
|
return path.trim().to_string();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the default path
|
||||||
|
if Path::new(r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\fxc.exe")
|
||||||
|
.exists()
|
||||||
|
{
|
||||||
|
return r"C:\Program Files (x86)\Windows Kits\10\bin\10.0.26100.0\x64\fxc.exe"
|
||||||
|
.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
panic!("Failed to find fxc.exe");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_shader_for_module(
|
||||||
|
module: &str,
|
||||||
|
out_dir: &str,
|
||||||
|
fxc_path: &str,
|
||||||
|
shader_path: &str,
|
||||||
|
rust_binding_path: &str,
|
||||||
|
) {
|
||||||
|
// Compile vertex shader
|
||||||
|
let output_file = format!("{}/{}_vs.h", out_dir, module);
|
||||||
|
let const_name = format!("{}_VERTEX_BYTES", module.to_uppercase());
|
||||||
|
compile_shader_impl(
|
||||||
|
fxc_path,
|
||||||
|
&format!("{module}_vertex"),
|
||||||
|
&output_file,
|
||||||
|
&const_name,
|
||||||
|
shader_path,
|
||||||
|
"vs_4_1",
|
||||||
|
);
|
||||||
|
generate_rust_binding(&const_name, &output_file, &rust_binding_path);
|
||||||
|
|
||||||
|
// Compile fragment shader
|
||||||
|
let output_file = format!("{}/{}_ps.h", out_dir, module);
|
||||||
|
let const_name = format!("{}_FRAGMENT_BYTES", module.to_uppercase());
|
||||||
|
compile_shader_impl(
|
||||||
|
fxc_path,
|
||||||
|
&format!("{module}_fragment"),
|
||||||
|
&output_file,
|
||||||
|
&const_name,
|
||||||
|
shader_path,
|
||||||
|
"ps_4_1",
|
||||||
|
);
|
||||||
|
generate_rust_binding(&const_name, &output_file, &rust_binding_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compile_shader_impl(
|
||||||
|
fxc_path: &str,
|
||||||
|
entry_point: &str,
|
||||||
|
output_path: &str,
|
||||||
|
var_name: &str,
|
||||||
|
shader_path: &str,
|
||||||
|
target: &str,
|
||||||
|
) {
|
||||||
|
let output = Command::new(fxc_path)
|
||||||
|
.args([
|
||||||
|
"/T",
|
||||||
|
target,
|
||||||
|
"/E",
|
||||||
|
entry_point,
|
||||||
|
"/Fh",
|
||||||
|
output_path,
|
||||||
|
"/Vn",
|
||||||
|
var_name,
|
||||||
|
"/O3",
|
||||||
|
shader_path,
|
||||||
|
])
|
||||||
|
.output();
|
||||||
|
|
||||||
|
match output {
|
||||||
|
Ok(result) => {
|
||||||
|
if result.status.success() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
eprintln!(
|
||||||
|
"Shader compilation failed for {}:\n{}",
|
||||||
|
entry_point,
|
||||||
|
String::from_utf8_lossy(&result.stderr)
|
||||||
|
);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Failed to run fxc for {}: {}", entry_point, e);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_rust_binding(const_name: &str, head_file: &str, output_path: &str) {
|
||||||
|
let header_content = fs::read_to_string(head_file).expect("Failed to read header file");
|
||||||
|
let const_definition = {
|
||||||
|
let global_var_start = header_content.find("const BYTE").unwrap();
|
||||||
|
let global_var = &header_content[global_var_start..];
|
||||||
|
let equal = global_var.find('=').unwrap();
|
||||||
|
global_var[equal + 1..].trim()
|
||||||
|
};
|
||||||
|
let rust_binding = format!(
|
||||||
|
"const {}: &[u8] = &{}\n",
|
||||||
|
const_name,
|
||||||
|
const_definition.replace('{', "[").replace('}', "]")
|
||||||
|
);
|
||||||
|
let mut options = fs::OpenOptions::new()
|
||||||
|
.create(true)
|
||||||
|
.append(true)
|
||||||
|
.open(output_path)
|
||||||
|
.expect("Failed to open Rust binding file");
|
||||||
|
options
|
||||||
|
.write_all(rust_binding.as_bytes())
|
||||||
|
.expect("Failed to write Rust binding file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -13,8 +13,7 @@ mod mac;
|
||||||
any(target_os = "linux", target_os = "freebsd"),
|
any(target_os = "linux", target_os = "freebsd"),
|
||||||
any(feature = "x11", feature = "wayland")
|
any(feature = "x11", feature = "wayland")
|
||||||
),
|
),
|
||||||
target_os = "windows",
|
all(target_os = "macos", feature = "macos-blade")
|
||||||
feature = "macos-blade"
|
|
||||||
))]
|
))]
|
||||||
mod blade;
|
mod blade;
|
||||||
|
|
||||||
|
@ -448,6 +447,8 @@ impl Tiling {
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Default)]
|
||||||
pub(crate) struct RequestFrameOptions {
|
pub(crate) struct RequestFrameOptions {
|
||||||
pub(crate) require_presentation: bool,
|
pub(crate) require_presentation: bool,
|
||||||
|
/// Force refresh of all rendering states when true
|
||||||
|
pub(crate) force_render: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
|
pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
|
||||||
|
|
|
@ -1795,6 +1795,7 @@ impl X11ClientState {
|
||||||
drop(state);
|
drop(state);
|
||||||
window.refresh(RequestFrameOptions {
|
window.refresh(RequestFrameOptions {
|
||||||
require_presentation: expose_event_received,
|
require_presentation: expose_event_received,
|
||||||
|
force_render: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
xcb_connection
|
xcb_connection
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
mod clipboard;
|
mod clipboard;
|
||||||
mod destination_list;
|
mod destination_list;
|
||||||
mod direct_write;
|
mod direct_write;
|
||||||
|
mod directx_atlas;
|
||||||
|
mod directx_renderer;
|
||||||
mod dispatcher;
|
mod dispatcher;
|
||||||
mod display;
|
mod display;
|
||||||
mod events;
|
mod events;
|
||||||
|
@ -14,6 +16,8 @@ mod wrapper;
|
||||||
pub(crate) use clipboard::*;
|
pub(crate) use clipboard::*;
|
||||||
pub(crate) use destination_list::*;
|
pub(crate) use destination_list::*;
|
||||||
pub(crate) use direct_write::*;
|
pub(crate) use direct_write::*;
|
||||||
|
pub(crate) use directx_atlas::*;
|
||||||
|
pub(crate) use directx_renderer::*;
|
||||||
pub(crate) use dispatcher::*;
|
pub(crate) use dispatcher::*;
|
||||||
pub(crate) use display::*;
|
pub(crate) use display::*;
|
||||||
pub(crate) use events::*;
|
pub(crate) use events::*;
|
||||||
|
|
309
crates/gpui/src/platform/windows/directx_atlas.rs
Normal file
309
crates/gpui/src/platform/windows/directx_atlas.rs
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
use collections::FxHashMap;
|
||||||
|
use etagere::BucketedAtlasAllocator;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use windows::Win32::Graphics::{
|
||||||
|
Direct3D11::{
|
||||||
|
D3D11_BIND_SHADER_RESOURCE, D3D11_BOX, D3D11_CPU_ACCESS_WRITE, D3D11_TEXTURE2D_DESC,
|
||||||
|
D3D11_USAGE_DEFAULT, ID3D11Device, ID3D11DeviceContext, ID3D11ShaderResourceView,
|
||||||
|
ID3D11Texture2D,
|
||||||
|
},
|
||||||
|
Dxgi::Common::{DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SAMPLE_DESC},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
AtlasKey, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, DevicePixels, PlatformAtlas,
|
||||||
|
Point, Size, platform::AtlasTextureList,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(crate) struct DirectXAtlas(Mutex<DirectXAtlasState>);
|
||||||
|
|
||||||
|
struct DirectXAtlasState {
|
||||||
|
device: ID3D11Device,
|
||||||
|
device_context: ID3D11DeviceContext,
|
||||||
|
monochrome_textures: AtlasTextureList<DirectXAtlasTexture>,
|
||||||
|
polychrome_textures: AtlasTextureList<DirectXAtlasTexture>,
|
||||||
|
tiles_by_key: FxHashMap<AtlasKey, AtlasTile>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DirectXAtlasTexture {
|
||||||
|
id: AtlasTextureId,
|
||||||
|
bytes_per_pixel: u32,
|
||||||
|
allocator: BucketedAtlasAllocator,
|
||||||
|
texture: ID3D11Texture2D,
|
||||||
|
view: [Option<ID3D11ShaderResourceView>; 1],
|
||||||
|
live_atlas_keys: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DirectXAtlas {
|
||||||
|
pub(crate) fn new(device: &ID3D11Device, device_context: &ID3D11DeviceContext) -> Self {
|
||||||
|
DirectXAtlas(Mutex::new(DirectXAtlasState {
|
||||||
|
device: device.clone(),
|
||||||
|
device_context: device_context.clone(),
|
||||||
|
monochrome_textures: Default::default(),
|
||||||
|
polychrome_textures: Default::default(),
|
||||||
|
tiles_by_key: Default::default(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_texture_view(
|
||||||
|
&self,
|
||||||
|
id: AtlasTextureId,
|
||||||
|
) -> [Option<ID3D11ShaderResourceView>; 1] {
|
||||||
|
let lock = self.0.lock();
|
||||||
|
let tex = lock.texture(id);
|
||||||
|
tex.view.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn handle_device_lost(
|
||||||
|
&self,
|
||||||
|
device: &ID3D11Device,
|
||||||
|
device_context: &ID3D11DeviceContext,
|
||||||
|
) {
|
||||||
|
let mut lock = self.0.lock();
|
||||||
|
lock.device = device.clone();
|
||||||
|
lock.device_context = device_context.clone();
|
||||||
|
lock.monochrome_textures = AtlasTextureList::default();
|
||||||
|
lock.polychrome_textures = AtlasTextureList::default();
|
||||||
|
lock.tiles_by_key.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlatformAtlas for DirectXAtlas {
|
||||||
|
fn get_or_insert_with<'a>(
|
||||||
|
&self,
|
||||||
|
key: &AtlasKey,
|
||||||
|
build: &mut dyn FnMut() -> anyhow::Result<
|
||||||
|
Option<(Size<DevicePixels>, std::borrow::Cow<'a, [u8]>)>,
|
||||||
|
>,
|
||||||
|
) -> anyhow::Result<Option<AtlasTile>> {
|
||||||
|
let mut lock = self.0.lock();
|
||||||
|
if let Some(tile) = lock.tiles_by_key.get(key) {
|
||||||
|
Ok(Some(tile.clone()))
|
||||||
|
} else {
|
||||||
|
let Some((size, bytes)) = build()? else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
let tile = lock
|
||||||
|
.allocate(size, key.texture_kind())
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("failed to allocate"))?;
|
||||||
|
let texture = lock.texture(tile.texture_id);
|
||||||
|
texture.upload(&lock.device_context, tile.bounds, &bytes);
|
||||||
|
lock.tiles_by_key.insert(key.clone(), tile.clone());
|
||||||
|
Ok(Some(tile))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove(&self, key: &AtlasKey) {
|
||||||
|
let mut lock = self.0.lock();
|
||||||
|
|
||||||
|
let Some(id) = lock.tiles_by_key.remove(key).map(|tile| tile.texture_id) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let textures = match id.kind {
|
||||||
|
AtlasTextureKind::Monochrome => &mut lock.monochrome_textures,
|
||||||
|
AtlasTextureKind::Polychrome => &mut lock.polychrome_textures,
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(texture_slot) = textures.textures.get_mut(id.index as usize) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(mut texture) = texture_slot.take() {
|
||||||
|
texture.decrement_ref_count();
|
||||||
|
if texture.is_unreferenced() {
|
||||||
|
textures.free_list.push(texture.id.index as usize);
|
||||||
|
lock.tiles_by_key.remove(key);
|
||||||
|
} else {
|
||||||
|
*texture_slot = Some(texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DirectXAtlasState {
|
||||||
|
fn allocate(
|
||||||
|
&mut self,
|
||||||
|
size: Size<DevicePixels>,
|
||||||
|
texture_kind: AtlasTextureKind,
|
||||||
|
) -> Option<AtlasTile> {
|
||||||
|
{
|
||||||
|
let textures = match texture_kind {
|
||||||
|
AtlasTextureKind::Monochrome => &mut self.monochrome_textures,
|
||||||
|
AtlasTextureKind::Polychrome => &mut self.polychrome_textures,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(tile) = textures
|
||||||
|
.iter_mut()
|
||||||
|
.rev()
|
||||||
|
.find_map(|texture| texture.allocate(size))
|
||||||
|
{
|
||||||
|
return Some(tile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let texture = self.push_texture(size, texture_kind)?;
|
||||||
|
texture.allocate(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_texture(
|
||||||
|
&mut self,
|
||||||
|
min_size: Size<DevicePixels>,
|
||||||
|
kind: AtlasTextureKind,
|
||||||
|
) -> Option<&mut DirectXAtlasTexture> {
|
||||||
|
const DEFAULT_ATLAS_SIZE: Size<DevicePixels> = Size {
|
||||||
|
width: DevicePixels(1024),
|
||||||
|
height: DevicePixels(1024),
|
||||||
|
};
|
||||||
|
// Max texture size for DirectX. See:
|
||||||
|
// https://learn.microsoft.com/en-us/windows/win32/direct3d11/overviews-direct3d-11-resources-limits
|
||||||
|
const MAX_ATLAS_SIZE: Size<DevicePixels> = Size {
|
||||||
|
width: DevicePixels(16384),
|
||||||
|
height: DevicePixels(16384),
|
||||||
|
};
|
||||||
|
let size = min_size.min(&MAX_ATLAS_SIZE).max(&DEFAULT_ATLAS_SIZE);
|
||||||
|
let pixel_format;
|
||||||
|
let bind_flag;
|
||||||
|
let bytes_per_pixel;
|
||||||
|
match kind {
|
||||||
|
AtlasTextureKind::Monochrome => {
|
||||||
|
pixel_format = DXGI_FORMAT_A8_UNORM;
|
||||||
|
bind_flag = D3D11_BIND_SHADER_RESOURCE;
|
||||||
|
bytes_per_pixel = 1;
|
||||||
|
}
|
||||||
|
AtlasTextureKind::Polychrome => {
|
||||||
|
pixel_format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||||
|
bind_flag = D3D11_BIND_SHADER_RESOURCE;
|
||||||
|
bytes_per_pixel = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let texture_desc = D3D11_TEXTURE2D_DESC {
|
||||||
|
Width: size.width.0 as u32,
|
||||||
|
Height: size.height.0 as u32,
|
||||||
|
MipLevels: 1,
|
||||||
|
ArraySize: 1,
|
||||||
|
Format: pixel_format,
|
||||||
|
SampleDesc: DXGI_SAMPLE_DESC {
|
||||||
|
Count: 1,
|
||||||
|
Quality: 0,
|
||||||
|
},
|
||||||
|
Usage: D3D11_USAGE_DEFAULT,
|
||||||
|
BindFlags: bind_flag.0 as u32,
|
||||||
|
CPUAccessFlags: D3D11_CPU_ACCESS_WRITE.0 as u32,
|
||||||
|
MiscFlags: 0,
|
||||||
|
};
|
||||||
|
let mut texture: Option<ID3D11Texture2D> = None;
|
||||||
|
unsafe {
|
||||||
|
// This only returns None if the device is lost, which we will recreate later.
|
||||||
|
// So it's ok to return None here.
|
||||||
|
self.device
|
||||||
|
.CreateTexture2D(&texture_desc, None, Some(&mut texture))
|
||||||
|
.ok()?;
|
||||||
|
}
|
||||||
|
let texture = texture.unwrap();
|
||||||
|
|
||||||
|
let texture_list = match kind {
|
||||||
|
AtlasTextureKind::Monochrome => &mut self.monochrome_textures,
|
||||||
|
AtlasTextureKind::Polychrome => &mut self.polychrome_textures,
|
||||||
|
};
|
||||||
|
let index = texture_list.free_list.pop();
|
||||||
|
let view = unsafe {
|
||||||
|
let mut view = None;
|
||||||
|
self.device
|
||||||
|
.CreateShaderResourceView(&texture, None, Some(&mut view))
|
||||||
|
.ok()?;
|
||||||
|
[view]
|
||||||
|
};
|
||||||
|
let atlas_texture = DirectXAtlasTexture {
|
||||||
|
id: AtlasTextureId {
|
||||||
|
index: index.unwrap_or(texture_list.textures.len()) as u32,
|
||||||
|
kind,
|
||||||
|
},
|
||||||
|
bytes_per_pixel,
|
||||||
|
allocator: etagere::BucketedAtlasAllocator::new(size.into()),
|
||||||
|
texture,
|
||||||
|
view,
|
||||||
|
live_atlas_keys: 0,
|
||||||
|
};
|
||||||
|
if let Some(ix) = index {
|
||||||
|
texture_list.textures[ix] = Some(atlas_texture);
|
||||||
|
texture_list.textures.get_mut(ix).unwrap().as_mut()
|
||||||
|
} else {
|
||||||
|
texture_list.textures.push(Some(atlas_texture));
|
||||||
|
texture_list.textures.last_mut().unwrap().as_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn texture(&self, id: AtlasTextureId) -> &DirectXAtlasTexture {
|
||||||
|
let textures = match id.kind {
|
||||||
|
crate::AtlasTextureKind::Monochrome => &self.monochrome_textures,
|
||||||
|
crate::AtlasTextureKind::Polychrome => &self.polychrome_textures,
|
||||||
|
};
|
||||||
|
textures[id.index as usize].as_ref().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DirectXAtlasTexture {
|
||||||
|
fn allocate(&mut self, size: Size<DevicePixels>) -> Option<AtlasTile> {
|
||||||
|
let allocation = self.allocator.allocate(size.into())?;
|
||||||
|
let tile = AtlasTile {
|
||||||
|
texture_id: self.id,
|
||||||
|
tile_id: allocation.id.into(),
|
||||||
|
bounds: Bounds {
|
||||||
|
origin: allocation.rectangle.min.into(),
|
||||||
|
size,
|
||||||
|
},
|
||||||
|
padding: 0,
|
||||||
|
};
|
||||||
|
self.live_atlas_keys += 1;
|
||||||
|
Some(tile)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upload(
|
||||||
|
&self,
|
||||||
|
device_context: &ID3D11DeviceContext,
|
||||||
|
bounds: Bounds<DevicePixels>,
|
||||||
|
bytes: &[u8],
|
||||||
|
) {
|
||||||
|
unsafe {
|
||||||
|
device_context.UpdateSubresource(
|
||||||
|
&self.texture,
|
||||||
|
0,
|
||||||
|
Some(&D3D11_BOX {
|
||||||
|
left: bounds.left().0 as u32,
|
||||||
|
top: bounds.top().0 as u32,
|
||||||
|
front: 0,
|
||||||
|
right: bounds.right().0 as u32,
|
||||||
|
bottom: bounds.bottom().0 as u32,
|
||||||
|
back: 1,
|
||||||
|
}),
|
||||||
|
bytes.as_ptr() as _,
|
||||||
|
bounds.size.width.to_bytes(self.bytes_per_pixel as u8),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn decrement_ref_count(&mut self) {
|
||||||
|
self.live_atlas_keys -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_unreferenced(&mut self) -> bool {
|
||||||
|
self.live_atlas_keys == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Size<DevicePixels>> for etagere::Size {
|
||||||
|
fn from(size: Size<DevicePixels>) -> Self {
|
||||||
|
etagere::Size::new(size.width.into(), size.height.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<etagere::Point> for Point<DevicePixels> {
|
||||||
|
fn from(value: etagere::Point) -> Self {
|
||||||
|
Point {
|
||||||
|
x: DevicePixels::from(value.x),
|
||||||
|
y: DevicePixels::from(value.y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1777
crates/gpui/src/platform/windows/directx_renderer.rs
Normal file
1777
crates/gpui/src/platform/windows/directx_renderer.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -23,6 +23,7 @@ pub(crate) const WM_GPUI_CURSOR_STYLE_CHANGED: u32 = WM_USER + 1;
|
||||||
pub(crate) const WM_GPUI_CLOSE_ONE_WINDOW: u32 = WM_USER + 2;
|
pub(crate) const WM_GPUI_CLOSE_ONE_WINDOW: u32 = WM_USER + 2;
|
||||||
pub(crate) const WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD: u32 = WM_USER + 3;
|
pub(crate) const WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD: u32 = WM_USER + 3;
|
||||||
pub(crate) const WM_GPUI_DOCK_MENU_ACTION: u32 = WM_USER + 4;
|
pub(crate) const WM_GPUI_DOCK_MENU_ACTION: u32 = WM_USER + 4;
|
||||||
|
pub(crate) const WM_GPUI_FORCE_UPDATE_WINDOW: u32 = WM_USER + 5;
|
||||||
|
|
||||||
const SIZE_MOVE_LOOP_TIMER_ID: usize = 1;
|
const SIZE_MOVE_LOOP_TIMER_ID: usize = 1;
|
||||||
const AUTO_HIDE_TASKBAR_THICKNESS_PX: i32 = 1;
|
const AUTO_HIDE_TASKBAR_THICKNESS_PX: i32 = 1;
|
||||||
|
@ -37,6 +38,7 @@ pub(crate) fn handle_msg(
|
||||||
let handled = match msg {
|
let handled = match msg {
|
||||||
WM_ACTIVATE => handle_activate_msg(wparam, state_ptr),
|
WM_ACTIVATE => handle_activate_msg(wparam, state_ptr),
|
||||||
WM_CREATE => handle_create_msg(handle, state_ptr),
|
WM_CREATE => handle_create_msg(handle, state_ptr),
|
||||||
|
WM_DEVICECHANGE => handle_device_change_msg(handle, wparam, state_ptr),
|
||||||
WM_MOVE => handle_move_msg(handle, lparam, state_ptr),
|
WM_MOVE => handle_move_msg(handle, lparam, state_ptr),
|
||||||
WM_SIZE => handle_size_msg(wparam, lparam, state_ptr),
|
WM_SIZE => handle_size_msg(wparam, lparam, state_ptr),
|
||||||
WM_GETMINMAXINFO => handle_get_min_max_info_msg(lparam, state_ptr),
|
WM_GETMINMAXINFO => handle_get_min_max_info_msg(lparam, state_ptr),
|
||||||
|
@ -48,7 +50,7 @@ pub(crate) fn handle_msg(
|
||||||
WM_DISPLAYCHANGE => handle_display_change_msg(handle, state_ptr),
|
WM_DISPLAYCHANGE => handle_display_change_msg(handle, state_ptr),
|
||||||
WM_NCHITTEST => handle_hit_test_msg(handle, msg, wparam, lparam, state_ptr),
|
WM_NCHITTEST => handle_hit_test_msg(handle, msg, wparam, lparam, state_ptr),
|
||||||
WM_PAINT => handle_paint_msg(handle, state_ptr),
|
WM_PAINT => handle_paint_msg(handle, state_ptr),
|
||||||
WM_CLOSE => handle_close_msg(handle, state_ptr),
|
WM_CLOSE => handle_close_msg(state_ptr),
|
||||||
WM_DESTROY => handle_destroy_msg(handle, state_ptr),
|
WM_DESTROY => handle_destroy_msg(handle, state_ptr),
|
||||||
WM_MOUSEMOVE => handle_mouse_move_msg(handle, lparam, wparam, state_ptr),
|
WM_MOUSEMOVE => handle_mouse_move_msg(handle, lparam, wparam, state_ptr),
|
||||||
WM_MOUSELEAVE | WM_NCMOUSELEAVE => handle_mouse_leave_msg(state_ptr),
|
WM_MOUSELEAVE | WM_NCMOUSELEAVE => handle_mouse_leave_msg(state_ptr),
|
||||||
|
@ -96,6 +98,7 @@ pub(crate) fn handle_msg(
|
||||||
WM_SETTINGCHANGE => handle_system_settings_changed(handle, wparam, lparam, state_ptr),
|
WM_SETTINGCHANGE => handle_system_settings_changed(handle, wparam, lparam, state_ptr),
|
||||||
WM_INPUTLANGCHANGE => handle_input_language_changed(lparam, state_ptr),
|
WM_INPUTLANGCHANGE => handle_input_language_changed(lparam, state_ptr),
|
||||||
WM_GPUI_CURSOR_STYLE_CHANGED => handle_cursor_changed(lparam, state_ptr),
|
WM_GPUI_CURSOR_STYLE_CHANGED => handle_cursor_changed(lparam, state_ptr),
|
||||||
|
WM_GPUI_FORCE_UPDATE_WINDOW => draw_window(handle, true, state_ptr),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(n) = handled {
|
if let Some(n) = handled {
|
||||||
|
@ -181,11 +184,9 @@ fn handle_size_msg(
|
||||||
let new_size = size(DevicePixels(width), DevicePixels(height));
|
let new_size = size(DevicePixels(width), DevicePixels(height));
|
||||||
let scale_factor = lock.scale_factor;
|
let scale_factor = lock.scale_factor;
|
||||||
if lock.restore_from_minimized.is_some() {
|
if lock.restore_from_minimized.is_some() {
|
||||||
lock.renderer
|
|
||||||
.update_drawable_size_even_if_unchanged(new_size);
|
|
||||||
lock.callbacks.request_frame = lock.restore_from_minimized.take();
|
lock.callbacks.request_frame = lock.restore_from_minimized.take();
|
||||||
} else {
|
} else {
|
||||||
lock.renderer.update_drawable_size(new_size);
|
lock.renderer.resize(new_size).log_err();
|
||||||
}
|
}
|
||||||
let new_size = new_size.to_pixels(scale_factor);
|
let new_size = new_size.to_pixels(scale_factor);
|
||||||
lock.logical_size = new_size;
|
lock.logical_size = new_size;
|
||||||
|
@ -238,40 +239,14 @@ fn handle_timer_msg(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_paint_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
|
fn handle_paint_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
|
||||||
let mut lock = state_ptr.state.borrow_mut();
|
draw_window(handle, false, state_ptr)
|
||||||
if let Some(mut request_frame) = lock.callbacks.request_frame.take() {
|
|
||||||
drop(lock);
|
|
||||||
request_frame(Default::default());
|
|
||||||
state_ptr.state.borrow_mut().callbacks.request_frame = Some(request_frame);
|
|
||||||
}
|
|
||||||
unsafe { ValidateRect(Some(handle), None).ok().log_err() };
|
|
||||||
Some(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_close_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
|
fn handle_close_msg(state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
|
||||||
let mut lock = state_ptr.state.borrow_mut();
|
let mut callback = state_ptr.state.borrow_mut().callbacks.should_close.take()?;
|
||||||
let output = if let Some(mut callback) = lock.callbacks.should_close.take() {
|
let should_close = callback();
|
||||||
drop(lock);
|
state_ptr.state.borrow_mut().callbacks.should_close = Some(callback);
|
||||||
let should_close = callback();
|
if should_close { None } else { Some(0) }
|
||||||
state_ptr.state.borrow_mut().callbacks.should_close = Some(callback);
|
|
||||||
if should_close { None } else { Some(0) }
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
// Workaround as window close animation is not played with `WS_EX_LAYERED` enabled.
|
|
||||||
if output.is_none() {
|
|
||||||
unsafe {
|
|
||||||
let current_style = get_window_long(handle, GWL_EXSTYLE);
|
|
||||||
set_window_long(
|
|
||||||
handle,
|
|
||||||
GWL_EXSTYLE,
|
|
||||||
current_style & !WS_EX_LAYERED.0 as isize,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_destroy_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
|
fn handle_destroy_msg(handle: HWND, state_ptr: Rc<WindowsWindowStatePtr>) -> Option<isize> {
|
||||||
|
@ -1223,6 +1198,53 @@ fn handle_input_language_changed(
|
||||||
Some(0)
|
Some(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_device_change_msg(
|
||||||
|
handle: HWND,
|
||||||
|
wparam: WPARAM,
|
||||||
|
state_ptr: Rc<WindowsWindowStatePtr>,
|
||||||
|
) -> Option<isize> {
|
||||||
|
if wparam.0 == DBT_DEVNODES_CHANGED as usize {
|
||||||
|
// The reason for sending this message is to actually trigger a redraw of the window.
|
||||||
|
unsafe {
|
||||||
|
PostMessageW(
|
||||||
|
Some(handle),
|
||||||
|
WM_GPUI_FORCE_UPDATE_WINDOW,
|
||||||
|
WPARAM(0),
|
||||||
|
LPARAM(0),
|
||||||
|
)
|
||||||
|
.log_err();
|
||||||
|
}
|
||||||
|
// If the GPU device is lost, this redraw will take care of recreating the device context.
|
||||||
|
// The WM_GPUI_FORCE_UPDATE_WINDOW message will take care of redrawing the window, after
|
||||||
|
// the device context has been recreated.
|
||||||
|
draw_window(handle, true, state_ptr)
|
||||||
|
} else {
|
||||||
|
// Other device change messages are not handled.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn draw_window(
|
||||||
|
handle: HWND,
|
||||||
|
force_render: bool,
|
||||||
|
state_ptr: Rc<WindowsWindowStatePtr>,
|
||||||
|
) -> Option<isize> {
|
||||||
|
let mut request_frame = state_ptr
|
||||||
|
.state
|
||||||
|
.borrow_mut()
|
||||||
|
.callbacks
|
||||||
|
.request_frame
|
||||||
|
.take()?;
|
||||||
|
request_frame(RequestFrameOptions {
|
||||||
|
require_presentation: false,
|
||||||
|
force_render,
|
||||||
|
});
|
||||||
|
state_ptr.state.borrow_mut().callbacks.request_frame = Some(request_frame);
|
||||||
|
unsafe { ValidateRect(Some(handle), None).ok().log_err() };
|
||||||
|
Some(0)
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn parse_char_message(wparam: WPARAM, state_ptr: &Rc<WindowsWindowStatePtr>) -> Option<String> {
|
fn parse_char_message(wparam: WPARAM, state_ptr: &Rc<WindowsWindowStatePtr>) -> Option<String> {
|
||||||
let code_point = wparam.loword();
|
let code_point = wparam.loword();
|
||||||
|
|
|
@ -28,13 +28,12 @@ use windows::{
|
||||||
core::*,
|
core::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{platform::blade::BladeContext, *};
|
use crate::*;
|
||||||
|
|
||||||
pub(crate) struct WindowsPlatform {
|
pub(crate) struct WindowsPlatform {
|
||||||
state: RefCell<WindowsPlatformState>,
|
state: RefCell<WindowsPlatformState>,
|
||||||
raw_window_handles: RwLock<SmallVec<[HWND; 4]>>,
|
raw_window_handles: RwLock<SmallVec<[HWND; 4]>>,
|
||||||
// The below members will never change throughout the entire lifecycle of the app.
|
// The below members will never change throughout the entire lifecycle of the app.
|
||||||
gpu_context: BladeContext,
|
|
||||||
icon: HICON,
|
icon: HICON,
|
||||||
main_receiver: flume::Receiver<Runnable>,
|
main_receiver: flume::Receiver<Runnable>,
|
||||||
background_executor: BackgroundExecutor,
|
background_executor: BackgroundExecutor,
|
||||||
|
@ -111,13 +110,11 @@ impl WindowsPlatform {
|
||||||
let icon = load_icon().unwrap_or_default();
|
let icon = load_icon().unwrap_or_default();
|
||||||
let state = RefCell::new(WindowsPlatformState::new());
|
let state = RefCell::new(WindowsPlatformState::new());
|
||||||
let raw_window_handles = RwLock::new(SmallVec::new());
|
let raw_window_handles = RwLock::new(SmallVec::new());
|
||||||
let gpu_context = BladeContext::new().context("Unable to init GPU context")?;
|
|
||||||
let windows_version = WindowsVersion::new().context("Error retrieve windows version")?;
|
let windows_version = WindowsVersion::new().context("Error retrieve windows version")?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
state,
|
state,
|
||||||
raw_window_handles,
|
raw_window_handles,
|
||||||
gpu_context,
|
|
||||||
icon,
|
icon,
|
||||||
main_receiver,
|
main_receiver,
|
||||||
background_executor,
|
background_executor,
|
||||||
|
@ -343,27 +340,11 @@ impl Platform for WindowsPlatform {
|
||||||
|
|
||||||
fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) {
|
fn run(&self, on_finish_launching: Box<dyn 'static + FnOnce()>) {
|
||||||
on_finish_launching();
|
on_finish_launching();
|
||||||
let vsync_event = unsafe { Owned::new(CreateEventW(None, false, false, None).unwrap()) };
|
loop {
|
||||||
begin_vsync(*vsync_event);
|
if self.handle_events() {
|
||||||
'a: loop {
|
break;
|
||||||
let wait_result = unsafe {
|
|
||||||
MsgWaitForMultipleObjects(Some(&[*vsync_event]), false, INFINITE, QS_ALLINPUT)
|
|
||||||
};
|
|
||||||
|
|
||||||
match wait_result {
|
|
||||||
// compositor clock ticked so we should draw a frame
|
|
||||||
WAIT_EVENT(0) => self.redraw_all(),
|
|
||||||
// Windows thread messages are posted
|
|
||||||
WAIT_EVENT(1) => {
|
|
||||||
if self.handle_events() {
|
|
||||||
break 'a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
log::error!("Something went wrong while waiting {:?}", wait_result);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
self.redraw_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref mut callback) = self.state.borrow_mut().callbacks.quit {
|
if let Some(ref mut callback) = self.state.borrow_mut().callbacks.quit {
|
||||||
|
@ -455,12 +436,7 @@ impl Platform for WindowsPlatform {
|
||||||
handle: AnyWindowHandle,
|
handle: AnyWindowHandle,
|
||||||
options: WindowParams,
|
options: WindowParams,
|
||||||
) -> Result<Box<dyn PlatformWindow>> {
|
) -> Result<Box<dyn PlatformWindow>> {
|
||||||
let window = WindowsWindow::new(
|
let window = WindowsWindow::new(handle, options, self.generate_creation_info())?;
|
||||||
handle,
|
|
||||||
options,
|
|
||||||
self.generate_creation_info(),
|
|
||||||
&self.gpu_context,
|
|
||||||
)?;
|
|
||||||
let handle = window.get_raw_handle();
|
let handle = window.get_raw_handle();
|
||||||
self.raw_window_handles.write().push(handle);
|
self.raw_window_handles.write().push(handle);
|
||||||
|
|
||||||
|
@ -846,16 +822,6 @@ fn file_save_dialog(directory: PathBuf, window: Option<HWND>) -> Result<Option<P
|
||||||
Ok(Some(PathBuf::from(file_path_string)))
|
Ok(Some(PathBuf::from(file_path_string)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn begin_vsync(vsync_event: HANDLE) {
|
|
||||||
let event: SafeHandle = vsync_event.into();
|
|
||||||
std::thread::spawn(move || unsafe {
|
|
||||||
loop {
|
|
||||||
windows::Win32::Graphics::Dwm::DwmFlush().log_err();
|
|
||||||
SetEvent(*event).log_err();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_icon() -> Result<HICON> {
|
fn load_icon() -> Result<HICON> {
|
||||||
let module = unsafe { GetModuleHandleW(None).context("unable to get module handle")? };
|
let module = unsafe { GetModuleHandleW(None).context("unable to get module handle")? };
|
||||||
let handle = unsafe {
|
let handle = unsafe {
|
||||||
|
|
1160
crates/gpui/src/platform/windows/shaders.hlsl
Normal file
1160
crates/gpui/src/platform/windows/shaders.hlsl
Normal file
File diff suppressed because it is too large
Load diff
|
@ -26,7 +26,6 @@ use windows::{
|
||||||
core::*,
|
core::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::platform::blade::{BladeContext, BladeRenderer};
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
|
||||||
pub(crate) struct WindowsWindow(pub Rc<WindowsWindowStatePtr>);
|
pub(crate) struct WindowsWindow(pub Rc<WindowsWindowStatePtr>);
|
||||||
|
@ -49,7 +48,7 @@ pub struct WindowsWindowState {
|
||||||
pub system_key_handled: bool,
|
pub system_key_handled: bool,
|
||||||
pub hovered: bool,
|
pub hovered: bool,
|
||||||
|
|
||||||
pub renderer: BladeRenderer,
|
pub renderer: DirectXRenderer,
|
||||||
|
|
||||||
pub click_state: ClickState,
|
pub click_state: ClickState,
|
||||||
pub system_settings: WindowsSystemSettings,
|
pub system_settings: WindowsSystemSettings,
|
||||||
|
@ -80,13 +79,12 @@ pub(crate) struct WindowsWindowStatePtr {
|
||||||
impl WindowsWindowState {
|
impl WindowsWindowState {
|
||||||
fn new(
|
fn new(
|
||||||
hwnd: HWND,
|
hwnd: HWND,
|
||||||
transparent: bool,
|
|
||||||
cs: &CREATESTRUCTW,
|
cs: &CREATESTRUCTW,
|
||||||
current_cursor: Option<HCURSOR>,
|
current_cursor: Option<HCURSOR>,
|
||||||
display: WindowsDisplay,
|
display: WindowsDisplay,
|
||||||
gpu_context: &BladeContext,
|
|
||||||
min_size: Option<Size<Pixels>>,
|
min_size: Option<Size<Pixels>>,
|
||||||
appearance: WindowAppearance,
|
appearance: WindowAppearance,
|
||||||
|
disable_direct_composition: bool,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let scale_factor = {
|
let scale_factor = {
|
||||||
let monitor_dpi = unsafe { GetDpiForWindow(hwnd) } as f32;
|
let monitor_dpi = unsafe { GetDpiForWindow(hwnd) } as f32;
|
||||||
|
@ -103,7 +101,8 @@ impl WindowsWindowState {
|
||||||
};
|
};
|
||||||
let border_offset = WindowBorderOffset::default();
|
let border_offset = WindowBorderOffset::default();
|
||||||
let restore_from_minimized = None;
|
let restore_from_minimized = None;
|
||||||
let renderer = windows_renderer::init(gpu_context, hwnd, transparent)?;
|
let renderer = DirectXRenderer::new(hwnd, disable_direct_composition)
|
||||||
|
.context("Creating DirectX renderer")?;
|
||||||
let callbacks = Callbacks::default();
|
let callbacks = Callbacks::default();
|
||||||
let input_handler = None;
|
let input_handler = None;
|
||||||
let pending_surrogate = None;
|
let pending_surrogate = None;
|
||||||
|
@ -206,13 +205,12 @@ impl WindowsWindowStatePtr {
|
||||||
fn new(context: &WindowCreateContext, hwnd: HWND, cs: &CREATESTRUCTW) -> Result<Rc<Self>> {
|
fn new(context: &WindowCreateContext, hwnd: HWND, cs: &CREATESTRUCTW) -> Result<Rc<Self>> {
|
||||||
let state = RefCell::new(WindowsWindowState::new(
|
let state = RefCell::new(WindowsWindowState::new(
|
||||||
hwnd,
|
hwnd,
|
||||||
context.transparent,
|
|
||||||
cs,
|
cs,
|
||||||
context.current_cursor,
|
context.current_cursor,
|
||||||
context.display,
|
context.display,
|
||||||
context.gpu_context,
|
|
||||||
context.min_size,
|
context.min_size,
|
||||||
context.appearance,
|
context.appearance,
|
||||||
|
context.disable_direct_composition,
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
Ok(Rc::new_cyclic(|this| Self {
|
Ok(Rc::new_cyclic(|this| Self {
|
||||||
|
@ -329,12 +327,11 @@ pub(crate) struct Callbacks {
|
||||||
pub(crate) appearance_changed: Option<Box<dyn FnMut()>>,
|
pub(crate) appearance_changed: Option<Box<dyn FnMut()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WindowCreateContext<'a> {
|
struct WindowCreateContext {
|
||||||
inner: Option<Result<Rc<WindowsWindowStatePtr>>>,
|
inner: Option<Result<Rc<WindowsWindowStatePtr>>>,
|
||||||
handle: AnyWindowHandle,
|
handle: AnyWindowHandle,
|
||||||
hide_title_bar: bool,
|
hide_title_bar: bool,
|
||||||
display: WindowsDisplay,
|
display: WindowsDisplay,
|
||||||
transparent: bool,
|
|
||||||
is_movable: bool,
|
is_movable: bool,
|
||||||
min_size: Option<Size<Pixels>>,
|
min_size: Option<Size<Pixels>>,
|
||||||
executor: ForegroundExecutor,
|
executor: ForegroundExecutor,
|
||||||
|
@ -343,9 +340,9 @@ struct WindowCreateContext<'a> {
|
||||||
drop_target_helper: IDropTargetHelper,
|
drop_target_helper: IDropTargetHelper,
|
||||||
validation_number: usize,
|
validation_number: usize,
|
||||||
main_receiver: flume::Receiver<Runnable>,
|
main_receiver: flume::Receiver<Runnable>,
|
||||||
gpu_context: &'a BladeContext,
|
|
||||||
main_thread_id_win32: u32,
|
main_thread_id_win32: u32,
|
||||||
appearance: WindowAppearance,
|
appearance: WindowAppearance,
|
||||||
|
disable_direct_composition: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowsWindow {
|
impl WindowsWindow {
|
||||||
|
@ -353,7 +350,6 @@ impl WindowsWindow {
|
||||||
handle: AnyWindowHandle,
|
handle: AnyWindowHandle,
|
||||||
params: WindowParams,
|
params: WindowParams,
|
||||||
creation_info: WindowCreationInfo,
|
creation_info: WindowCreationInfo,
|
||||||
gpu_context: &BladeContext,
|
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let WindowCreationInfo {
|
let WindowCreationInfo {
|
||||||
icon,
|
icon,
|
||||||
|
@ -379,14 +375,20 @@ impl WindowsWindow {
|
||||||
.map(|title| title.as_ref())
|
.map(|title| title.as_ref())
|
||||||
.unwrap_or(""),
|
.unwrap_or(""),
|
||||||
);
|
);
|
||||||
let (dwexstyle, mut dwstyle) = if params.kind == WindowKind::PopUp {
|
let disable_direct_composition = std::env::var(DISABLE_DIRECT_COMPOSITION)
|
||||||
(WS_EX_TOOLWINDOW | WS_EX_LAYERED, WINDOW_STYLE(0x0))
|
.is_ok_and(|value| value == "true" || value == "1");
|
||||||
|
|
||||||
|
let (mut dwexstyle, dwstyle) = if params.kind == WindowKind::PopUp {
|
||||||
|
(WS_EX_TOOLWINDOW, WINDOW_STYLE(0x0))
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
WS_EX_APPWINDOW | WS_EX_LAYERED,
|
WS_EX_APPWINDOW,
|
||||||
WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
|
WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
if !disable_direct_composition {
|
||||||
|
dwexstyle |= WS_EX_NOREDIRECTIONBITMAP;
|
||||||
|
}
|
||||||
|
|
||||||
let hinstance = get_module_handle();
|
let hinstance = get_module_handle();
|
||||||
let display = if let Some(display_id) = params.display_id {
|
let display = if let Some(display_id) = params.display_id {
|
||||||
|
@ -401,7 +403,6 @@ impl WindowsWindow {
|
||||||
handle,
|
handle,
|
||||||
hide_title_bar,
|
hide_title_bar,
|
||||||
display,
|
display,
|
||||||
transparent: true,
|
|
||||||
is_movable: params.is_movable,
|
is_movable: params.is_movable,
|
||||||
min_size: params.window_min_size,
|
min_size: params.window_min_size,
|
||||||
executor,
|
executor,
|
||||||
|
@ -410,9 +411,9 @@ impl WindowsWindow {
|
||||||
drop_target_helper,
|
drop_target_helper,
|
||||||
validation_number,
|
validation_number,
|
||||||
main_receiver,
|
main_receiver,
|
||||||
gpu_context,
|
|
||||||
main_thread_id_win32,
|
main_thread_id_win32,
|
||||||
appearance,
|
appearance,
|
||||||
|
disable_direct_composition,
|
||||||
};
|
};
|
||||||
let lpparam = Some(&context as *const _ as *const _);
|
let lpparam = Some(&context as *const _ as *const _);
|
||||||
let creation_result = unsafe {
|
let creation_result = unsafe {
|
||||||
|
@ -453,14 +454,6 @@ impl WindowsWindow {
|
||||||
state: WindowOpenState::Windowed,
|
state: WindowOpenState::Windowed,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// The render pipeline will perform compositing on the GPU when the
|
|
||||||
// swapchain is configured correctly (see downstream of
|
|
||||||
// update_transparency).
|
|
||||||
// The following configuration is a one-time setup to ensure that the
|
|
||||||
// window is going to be composited with per-pixel alpha, but the render
|
|
||||||
// pipeline is responsible for effectively calling UpdateLayeredWindow
|
|
||||||
// at the appropriate time.
|
|
||||||
unsafe { SetLayeredWindowAttributes(hwnd, COLORREF(0), 255, LWA_ALPHA)? };
|
|
||||||
|
|
||||||
Ok(Self(state_ptr))
|
Ok(Self(state_ptr))
|
||||||
}
|
}
|
||||||
|
@ -485,7 +478,6 @@ impl rwh::HasDisplayHandle for WindowsWindow {
|
||||||
|
|
||||||
impl Drop for WindowsWindow {
|
impl Drop for WindowsWindow {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.0.state.borrow_mut().renderer.destroy();
|
|
||||||
// clone this `Rc` to prevent early release of the pointer
|
// clone this `Rc` to prevent early release of the pointer
|
||||||
let this = self.0.clone();
|
let this = self.0.clone();
|
||||||
self.0
|
self.0
|
||||||
|
@ -705,24 +697,21 @@ impl PlatformWindow for WindowsWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
|
fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
|
||||||
let mut window_state = self.0.state.borrow_mut();
|
let hwnd = self.0.hwnd;
|
||||||
window_state
|
|
||||||
.renderer
|
|
||||||
.update_transparency(background_appearance != WindowBackgroundAppearance::Opaque);
|
|
||||||
|
|
||||||
match background_appearance {
|
match background_appearance {
|
||||||
WindowBackgroundAppearance::Opaque => {
|
WindowBackgroundAppearance::Opaque => {
|
||||||
// ACCENT_DISABLED
|
// ACCENT_DISABLED
|
||||||
set_window_composition_attribute(window_state.hwnd, None, 0);
|
set_window_composition_attribute(hwnd, None, 0);
|
||||||
}
|
}
|
||||||
WindowBackgroundAppearance::Transparent => {
|
WindowBackgroundAppearance::Transparent => {
|
||||||
// Use ACCENT_ENABLE_TRANSPARENTGRADIENT for transparent background
|
// Use ACCENT_ENABLE_TRANSPARENTGRADIENT for transparent background
|
||||||
set_window_composition_attribute(window_state.hwnd, None, 2);
|
set_window_composition_attribute(hwnd, None, 2);
|
||||||
}
|
}
|
||||||
WindowBackgroundAppearance::Blurred => {
|
WindowBackgroundAppearance::Blurred => {
|
||||||
// Enable acrylic blur
|
// Enable acrylic blur
|
||||||
// ACCENT_ENABLE_ACRYLICBLURBEHIND
|
// ACCENT_ENABLE_ACRYLICBLURBEHIND
|
||||||
set_window_composition_attribute(window_state.hwnd, Some((0, 0, 0, 0)), 4);
|
set_window_composition_attribute(hwnd, Some((0, 0, 0, 0)), 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -794,11 +783,11 @@ impl PlatformWindow for WindowsWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&self, scene: &Scene) {
|
fn draw(&self, scene: &Scene) {
|
||||||
self.0.state.borrow_mut().renderer.draw(scene)
|
self.0.state.borrow_mut().renderer.draw(scene).log_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
|
fn sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
|
||||||
self.0.state.borrow().renderer.sprite_atlas().clone()
|
self.0.state.borrow().renderer.sprite_atlas()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_raw_handle(&self) -> HWND {
|
fn get_raw_handle(&self) -> HWND {
|
||||||
|
@ -806,11 +795,11 @@ impl PlatformWindow for WindowsWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gpu_specs(&self) -> Option<GpuSpecs> {
|
fn gpu_specs(&self) -> Option<GpuSpecs> {
|
||||||
Some(self.0.state.borrow().renderer.gpu_specs())
|
self.0.state.borrow().renderer.gpu_specs().log_err()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_ime_position(&self, _bounds: Bounds<ScaledPixels>) {
|
fn update_ime_position(&self, _bounds: Bounds<ScaledPixels>) {
|
||||||
// todo(windows)
|
// There is no such thing on Windows.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1306,52 +1295,6 @@ fn set_window_composition_attribute(hwnd: HWND, color: Option<Color>, state: u32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod windows_renderer {
|
|
||||||
use crate::platform::blade::{BladeContext, BladeRenderer, BladeSurfaceConfig};
|
|
||||||
use raw_window_handle as rwh;
|
|
||||||
use std::num::NonZeroIsize;
|
|
||||||
use windows::Win32::{Foundation::HWND, UI::WindowsAndMessaging::GWLP_HINSTANCE};
|
|
||||||
|
|
||||||
use crate::{get_window_long, show_error};
|
|
||||||
|
|
||||||
pub(super) fn init(
|
|
||||||
context: &BladeContext,
|
|
||||||
hwnd: HWND,
|
|
||||||
transparent: bool,
|
|
||||||
) -> anyhow::Result<BladeRenderer> {
|
|
||||||
let raw = RawWindow { hwnd };
|
|
||||||
let config = BladeSurfaceConfig {
|
|
||||||
size: Default::default(),
|
|
||||||
transparent,
|
|
||||||
};
|
|
||||||
BladeRenderer::new(context, &raw, config)
|
|
||||||
.inspect_err(|err| show_error("Failed to initialize BladeRenderer", err.to_string()))
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RawWindow {
|
|
||||||
hwnd: HWND,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl rwh::HasWindowHandle for RawWindow {
|
|
||||||
fn window_handle(&self) -> Result<rwh::WindowHandle<'_>, rwh::HandleError> {
|
|
||||||
Ok(unsafe {
|
|
||||||
let hwnd = NonZeroIsize::new_unchecked(self.hwnd.0 as isize);
|
|
||||||
let mut handle = rwh::Win32WindowHandle::new(hwnd);
|
|
||||||
let hinstance = get_window_long(self.hwnd, GWLP_HINSTANCE);
|
|
||||||
handle.hinstance = NonZeroIsize::new(hinstance);
|
|
||||||
rwh::WindowHandle::borrow_raw(handle.into())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl rwh::HasDisplayHandle for RawWindow {
|
|
||||||
fn display_handle(&self) -> Result<rwh::DisplayHandle<'_>, rwh::HandleError> {
|
|
||||||
let handle = rwh::WindowsDisplayHandle::new();
|
|
||||||
Ok(unsafe { rwh::DisplayHandle::borrow_raw(handle.into()) })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::ClickState;
|
use super::ClickState;
|
||||||
|
|
|
@ -1020,7 +1020,7 @@ impl Window {
|
||||||
|| (active.get()
|
|| (active.get()
|
||||||
&& last_input_timestamp.get().elapsed() < Duration::from_secs(1));
|
&& last_input_timestamp.get().elapsed() < Duration::from_secs(1));
|
||||||
|
|
||||||
if invalidator.is_dirty() {
|
if invalidator.is_dirty() || request_frame_options.force_render {
|
||||||
measure("frame duration", || {
|
measure("frame duration", || {
|
||||||
handle
|
handle
|
||||||
.update(&mut cx, |_, window, cx| {
|
.update(&mut cx, |_, window, cx| {
|
||||||
|
|
|
@ -62,6 +62,7 @@ Source: "{#ResourcesDir}\Zed.exe"; DestDir: "{code:GetInstallDir}"; Flags: ignor
|
||||||
Source: "{#ResourcesDir}\bin\*"; DestDir: "{code:GetInstallDir}\bin"; Flags: ignoreversion
|
Source: "{#ResourcesDir}\bin\*"; DestDir: "{code:GetInstallDir}\bin"; Flags: ignoreversion
|
||||||
Source: "{#ResourcesDir}\tools\*"; DestDir: "{app}\tools"; Flags: ignoreversion
|
Source: "{#ResourcesDir}\tools\*"; DestDir: "{app}\tools"; Flags: ignoreversion
|
||||||
Source: "{#ResourcesDir}\appx\*"; DestDir: "{app}\appx"; BeforeInstall: RemoveAppxPackage; AfterInstall: AddAppxPackage; Flags: ignoreversion; Check: IsWindows11OrLater
|
Source: "{#ResourcesDir}\appx\*"; DestDir: "{app}\appx"; BeforeInstall: RemoveAppxPackage; AfterInstall: AddAppxPackage; Flags: ignoreversion; Check: IsWindows11OrLater
|
||||||
|
Source: "{#ResourcesDir}\amd_ags_x64.dll"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
|
|
||||||
[Icons]
|
[Icons]
|
||||||
Name: "{group}\{#AppName}"; Filename: "{app}\{#AppExeName}.exe"; AppUserModelID: "{#AppUserId}"
|
Name: "{group}\{#AppName}"; Filename: "{app}\{#AppExeName}.exe"; AppUserModelID: "{#AppUserId}"
|
||||||
|
|
|
@ -136,11 +136,22 @@ function SignZedAndItsFriends {
|
||||||
& "$innoDir\sign.ps1" $files
|
& "$innoDir\sign.ps1" $files
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function DownloadAMDGpuServices {
|
||||||
|
# If you update the AGS SDK version, please also update the version in `crates/gpui/src/platform/windows/directx_renderer.rs`
|
||||||
|
$url = "https://codeload.github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/zip/refs/tags/v6.3.0"
|
||||||
|
$zipPath = ".\AGS_SDK_v6.3.0.zip"
|
||||||
|
# Download the AGS SDK zip file
|
||||||
|
Invoke-WebRequest -Uri $url -OutFile $zipPath
|
||||||
|
# Extract the AGS SDK zip file
|
||||||
|
Expand-Archive -Path $zipPath -DestinationPath "." -Force
|
||||||
|
}
|
||||||
|
|
||||||
function CollectFiles {
|
function CollectFiles {
|
||||||
Move-Item -Path "$innoDir\zed_explorer_command_injector.appx" -Destination "$innoDir\appx\zed_explorer_command_injector.appx" -Force
|
Move-Item -Path "$innoDir\zed_explorer_command_injector.appx" -Destination "$innoDir\appx\zed_explorer_command_injector.appx" -Force
|
||||||
Move-Item -Path "$innoDir\zed_explorer_command_injector.dll" -Destination "$innoDir\appx\zed_explorer_command_injector.dll" -Force
|
Move-Item -Path "$innoDir\zed_explorer_command_injector.dll" -Destination "$innoDir\appx\zed_explorer_command_injector.dll" -Force
|
||||||
Move-Item -Path "$innoDir\cli.exe" -Destination "$innoDir\bin\zed.exe" -Force
|
Move-Item -Path "$innoDir\cli.exe" -Destination "$innoDir\bin\zed.exe" -Force
|
||||||
Move-Item -Path "$innoDir\auto_update_helper.exe" -Destination "$innoDir\tools\auto_update_helper.exe" -Force
|
Move-Item -Path "$innoDir\auto_update_helper.exe" -Destination "$innoDir\tools\auto_update_helper.exe" -Force
|
||||||
|
Move-Item -Path ".\AGS_SDK-6.3.0\ags_lib\lib\amd_ags_x64.dll" -Destination "$innoDir\amd_ags_x64.dll" -Force
|
||||||
}
|
}
|
||||||
|
|
||||||
function BuildInstaller {
|
function BuildInstaller {
|
||||||
|
@ -211,7 +222,6 @@ function BuildInstaller {
|
||||||
# Windows runner 2022 default has iscc in PATH, https://github.com/actions/runner-images/blob/main/images/windows/Windows2022-Readme.md
|
# Windows runner 2022 default has iscc in PATH, https://github.com/actions/runner-images/blob/main/images/windows/Windows2022-Readme.md
|
||||||
# Currently, we are using Windows 2022 runner.
|
# Currently, we are using Windows 2022 runner.
|
||||||
# Windows runner 2025 doesn't have iscc in PATH for now, https://github.com/actions/runner-images/issues/11228
|
# Windows runner 2025 doesn't have iscc in PATH for now, https://github.com/actions/runner-images/issues/11228
|
||||||
# $innoSetupPath = "iscc.exe"
|
|
||||||
$innoSetupPath = "C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
|
$innoSetupPath = "C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
|
||||||
|
|
||||||
$definitions = @{
|
$definitions = @{
|
||||||
|
@ -268,6 +278,7 @@ BuildZedAndItsFriends
|
||||||
MakeAppx
|
MakeAppx
|
||||||
SignZedAndItsFriends
|
SignZedAndItsFriends
|
||||||
ZipZedAndItsFriendsDebug
|
ZipZedAndItsFriendsDebug
|
||||||
|
DownloadAMDGpuServices
|
||||||
CollectFiles
|
CollectFiles
|
||||||
BuildInstaller
|
BuildInstaller
|
||||||
|
|
||||||
|
|
|
@ -558,7 +558,6 @@ getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-f
|
||||||
getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-features = false, features = ["js", "rdrand"] }
|
getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-features = false, features = ["js", "rdrand"] }
|
||||||
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
||||||
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
||||||
naga = { version = "25", features = ["spv-out", "wgsl-in"] }
|
|
||||||
ring = { version = "0.17", features = ["std"] }
|
ring = { version = "0.17", features = ["std"] }
|
||||||
rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38", features = ["event"] }
|
rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38", features = ["event"] }
|
||||||
scopeguard = { version = "1" }
|
scopeguard = { version = "1" }
|
||||||
|
@ -582,7 +581,6 @@ getrandom-468e82937335b1c9 = { package = "getrandom", version = "0.3", default-f
|
||||||
getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-features = false, features = ["js", "rdrand"] }
|
getrandom-6f8ce4dd05d13bba = { package = "getrandom", version = "0.2", default-features = false, features = ["js", "rdrand"] }
|
||||||
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
hyper-rustls = { version = "0.27", default-features = false, features = ["http1", "http2", "native-tokio", "ring", "tls12"] }
|
||||||
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
itertools-5ef9efb8ec2df382 = { package = "itertools", version = "0.12" }
|
||||||
naga = { version = "25", features = ["spv-out", "wgsl-in"] }
|
|
||||||
proc-macro2 = { version = "1", default-features = false, features = ["span-locations"] }
|
proc-macro2 = { version = "1", default-features = false, features = ["span-locations"] }
|
||||||
ring = { version = "0.17", features = ["std"] }
|
ring = { version = "0.17", features = ["std"] }
|
||||||
rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38", features = ["event"] }
|
rustix-d585fab2519d2d1 = { package = "rustix", version = "0.38", features = ["event"] }
|
||||||
|
|
|
@ -71,6 +71,10 @@ extend-ignore-re = [
|
||||||
# Not an actual typo but an intentionally invalid color, in `color_extractor`
|
# Not an actual typo but an intentionally invalid color, in `color_extractor`
|
||||||
"#fof",
|
"#fof",
|
||||||
# Stripped version of reserved keyword `type`
|
# Stripped version of reserved keyword `type`
|
||||||
"typ"
|
"typ",
|
||||||
|
# AMD GPU Services
|
||||||
|
"ags",
|
||||||
|
# AMD GPU Services
|
||||||
|
"AGS"
|
||||||
]
|
]
|
||||||
check-filename = true
|
check-filename = true
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue