From df1f62477c778c64a2a4dfbe1b3fdc49787b9522 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 18 Jul 2025 15:11:49 +0800 Subject: [PATCH 1/8] add amd gpu version support --- crates/gpui/build.rs | 57 +++++++++++-- crates/gpui/libs/README.md | 10 +++ crates/gpui/libs/amd_ags_x64_2022_MT.lib | Bin 0 -> 153528 bytes crates/gpui/libs/amd_ags_x86_2022_MT.lib | Bin 0 -> 81484 bytes .../src/platform/windows/directx_renderer.rs | 80 +++++++++++++++++- 5 files changed, 137 insertions(+), 10 deletions(-) create mode 100644 crates/gpui/libs/README.md create mode 100644 crates/gpui/libs/amd_ags_x64_2022_MT.lib create mode 100644 crates/gpui/libs/amd_ags_x86_2022_MT.lib diff --git a/crates/gpui/build.rs b/crates/gpui/build.rs index b9496cc01426485cbef625c7e697bbf6082d1a67..6bb63ee67fd2b33675f864f22620988325666636 100644 --- a/crates/gpui/build.rs +++ b/crates/gpui/build.rs @@ -9,7 +9,10 @@ fn main() { let target = env::var("CARGO_CFG_TARGET_OS"); 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")), + feature = "macos-blade" + ))] check_wgsl_shaders(); match target.as_deref() { @@ -17,15 +20,9 @@ fn main() { #[cfg(target_os = "macos")] macos::build(); } - #[cfg(all(target_os = "windows", feature = "windows-manifest"))] Ok("windows") => { - 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(); + #[cfg(target_os = "windows")] + windows::build(); } _ => (), }; @@ -242,3 +239,45 @@ mod macos { } } } + +#[cfg(target_os = "windows")] +mod windows { + use std::path::PathBuf; + + pub(super) fn build() { + // Link the AMD AGS library + link_amd_ags(); + + // Embed the Windows manifest and resource file + #[cfg(feature = "windows-manifest")] + embed_resource(); + } + + fn link_amd_ags() { + // We can not use relative paths in `cargo:rustc-link-search`, so we need to use the absolute path. + // See: https://stackoverflow.com/questions/41917096/how-do-i-make-rustc-link-search-relative-to-the-project-location + let lib_dir = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()).join("libs"); + #[cfg(target_pointer_width = "64")] + let lib_name = "amd_ags_x64_2022_MT"; + #[cfg(target_pointer_width = "32")] + let lib_name = "amd_ags_x86_2022_MT"; + println!("cargo:rustc-link-lib=static={}", lib_name); + println!("cargo:rustc-link-search=native={}", lib_dir.display()); + println!( + "cargo:rerun-if-changed={}/{}.lib", + lib_dir.display(), + lib_name + ); + } + + #[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(); + } +} diff --git a/crates/gpui/libs/README.md b/crates/gpui/libs/README.md new file mode 100644 index 0000000000000000000000000000000000000000..2be286ee5352c21dc2bb5e2d1ca04cf25b8f746d --- /dev/null +++ b/crates/gpui/libs/README.md @@ -0,0 +1,10 @@ +The files in this folder are required for the Windows platform support in the gpui library. + + +#### amd_ags_x64.lib & amd_ags_x86.lib + +These libraries are used for AMD GPU support, currently only used on Windows, mainly for retrieving GPU information and capabilities. They are linked against the AMD AGS (AMD GPU Services) library. + +The official AMD AGS documentation can be found [here](https://gpuopen.com/amd-gpu-services-ags-library). And these two files are grabbed from the [official AMD AGS repository](https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK), currently at version 6.3.0. + +If you want to update these files, don't forget to update the value of `AGS_CURRENT_VERSION` in `gpui/src/platform/windows/directx_renderer.rs` as well. diff --git a/crates/gpui/libs/amd_ags_x64_2022_MT.lib b/crates/gpui/libs/amd_ags_x64_2022_MT.lib new file mode 100644 index 0000000000000000000000000000000000000000..a25d772160ddadcc98ce777c0e73a57e9f05a59a GIT binary patch literal 153528 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 literal 0 HcmV?d00001 diff --git a/crates/gpui/libs/amd_ags_x86_2022_MT.lib b/crates/gpui/libs/amd_ags_x86_2022_MT.lib new file mode 100644 index 0000000000000000000000000000000000000000..cdb1305378fa058b0e3ffcdeeca8d4ee4e28318b GIT binary patch literal 81484 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%0Au=#L?1Euy4H;s10>w{%DPd0 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
uq8_}zow zQvAM*-|O&u*zi>hZqxSz-c~MNXmT7L?AFCYa0j0%JP1<9J0<2djQ8($Ua<2eY%Z{I z!WpdoY~Y0KllLGd`|ftcq;R+&^^s@46^T8Hn3S#YiKj>@S=)vf=S|5PpLiMLtc+r& zWQ|Web$;+hVc59a`+ECh!Rxv&?wa;LKfUX3Tm9F+`I|r7S@-Mx`_9|*@w8#y6_56P zX5w{k{Op^z78~QoO&UG#?I}%FkL+A#K1s=F_vH@Uk64yl!+|a|vE`InUMfl`~Fax@y4oWUkzjRP|UGF+5v<*ET zp&+8scGL{A&hs4<`}aU8i{rgwxb)U3t2A|;(3w?S#6bRIliLuFJ)m)P2HK@6v5S9c zXbF^BxB!xyPX-~bnI_~X&h^@9Xqiy9VXdjeZk7c?Im4kT0n{gRK0d>le{n~bZQIPK zf@D&jmm(hucyMLhM60oDm8xfPd*h;b^~5I6Cle6nZt%HB*K}y{+rN5xO4d6*+M)VpV2L+h&yl!IEp0x91mxEwpgVA{&w@Rvj@D$ zaBu%V`4=`-D+@!dttWQ^Y@%ygR$`O!mh7UFZxANUkrYGD=`wgufniohcU$YKIW57C zP*)RnE^8M0ou{y;n3GW`Zx*z-7c@1s1W%hA#ag_4T;9ju^Z48JuM}@Z6xs>`GtYp0 z3v+EO5^AwJ3Q8NqcCnENw%6G>fJ?;(@`yosc>C?3Xx)YDw(nsi%d6EH`CS(dhQ`2T zn>$I&8LZ1Q_Ve3mgZmEpYqRKS4m#&>v{4r`%7{h!nXAP$j?%1Jq&w*U=vsIkrCGHY z?-#oAIC*x;f))>>_(a-K$6uV^L!06IV%=u^E|4=MOE zbWRT#=GESbC`S_ea!F2-P0VG-*5}1yhJnYWb6UVK_otJ$N(@uH9tLZ9GFcLE#$1e4 zD~h!kS*R&;B zW*0)x?T-`*^e(Ix`b>%-=HOkyuBHiDX1^3#dRu^fPd%jU310lqlsGO*MIh$S3S-i| zz_FXc+(=tP;y+)nQYmC+cC|nk7K$X=B>eFjGF*Qgwzs_U8_kc7yZ+LQqb=_)yZp)( zf7>?mYkl9XPa5azIQ%O)kMaXtWX+@M+LktVtbkIezcNtYzVyZ~<`)+E3jLmfDZaw1 z@~7lxUsX6IFE`ger8vJ}TDH%hUsUMx+?3h9q*I%sT{9{LEo3cxMnX^WPhZAX%^ZKV_7m;eQCicA<}=@D8n!QHu7R$OMex*B-H@%Bx@4wzR&qBiMc2 zwA^}Xy*4fHM#E>ayx5>~J4DLa);iDW;{IgCp$|i6Dpg?iH#3mN;dH3BWe8;=wOX~- zfTJHStgGSVdbTzT>6thd3-{L0l}`G@-`EdaLcYR#!eLz#-{tt5gnzaINYXw=PtcKH zH#X~N)0RSOwHUwcS_^Vss%F48U7;p+-eSYngXy#G8TlzOBt#0CXt z8%pX1R|l{R1<11qyd_va&c$yvkX^QXGq6)s8|vGIdUS~$!suN&#g=!i;0W6CoQ67h z@Rue2AX|dPt&V(J&^nE18(wiI@?wiEf<9?C>JdxJz*FhdE=QemkW&s?jbV|sRQ+HIGo&NRYitBOa8GTjJ*HnbM=;%#smDoE@RZfm^H8{)r8pKsMI@*0$()W_A zsnQ_6OtQauTU#2tGqbWrfmc%OBeV`G{QE_BL3oF=MrWRM>DS>%v=!_lGsha}z{TV< OVU83FkxO6%`~Ly#?{l{R literal 0 HcmV?d00001 diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 54478e9b02dc4a982e72d0fdd487cea158d7dae7..4e804e74dcb2b99a566a727a3826bb47886fcfb1 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -413,7 +413,7 @@ impl DirectXRenderer { }; let driver_version = match desc.VendorId { 0x10DE => nvidia::get_driver_version(), - 0x1002 => Err(anyhow::anyhow!("AMD driver info not implemented yet")), + 0x1002 => amd::get_driver_version(), 0x8086 => intel::get_driver_version(&self.devices.adapter), _ => Err(anyhow::anyhow!("Unknown vendor detected.")), } @@ -1438,6 +1438,84 @@ mod nvidia { } } +mod amd { + use std::os::raw::{c_char, c_int, c_void}; + + // https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/blob/5d8812d703d0335741b6f7ffc37838eeb8b967f7/ags_lib/inc/amd_ags.h#L145 + const AGS_CURRENT_VERSION: i32 = (6 << 22) | (3 << 12) | 0; + + // https://github.com/GPUOpen-LibrariesAndSDKs/AGS_SDK/blob/5d8812d703d0335741b6f7ffc37838eeb8b967f7/ags_lib/inc/amd_ags.h#L204 + // This is an opaque type, using struct to represent it properly for FFI + #[repr(C)] + struct AGSContext { + _private: [u8; 0], + } + + #[repr(C)] + pub struct AGSGPUInfo { + pub driver_version: *const c_char, + pub radeon_software_version: *const c_char, + pub num_devices: c_int, + pub devices: *mut c_void, + } + + unsafe extern "C" { + fn agsInitialize( + version: c_int, + config: *const c_void, + context: *mut *mut AGSContext, + gpu_info: *mut AGSGPUInfo, + ) -> c_int; + + fn agsDeInitialize(context: *mut AGSContext) -> c_int; + } + + pub(super) fn get_driver_version() -> anyhow::Result { + unsafe { + let mut context: *mut AGSContext = std::ptr::null_mut(); + let mut gpu_info: AGSGPUInfo = AGSGPUInfo { + driver_version: std::ptr::null(), + radeon_software_version: std::ptr::null(), + num_devices: 0, + devices: std::ptr::null_mut(), + }; + + let result = agsInitialize( + AGS_CURRENT_VERSION, + std::ptr::null(), + &mut context, + &mut gpu_info, + ); + if result != 0 { + return Err(anyhow::anyhow!( + "Failed to initialize AGS, error code: {}", + result + )); + } + + // Vulkan acctually returns this as the driver version + let software_version = if !gpu_info.radeon_software_version.is_null() { + std::ffi::CStr::from_ptr(gpu_info.radeon_software_version) + .to_string_lossy() + .into_owned() + } else { + "Unknown Radeon Software Version".to_string() + }; + + let driver_version = if !gpu_info.driver_version.is_null() { + std::ffi::CStr::from_ptr(gpu_info.driver_version) + .to_string_lossy() + .into_owned() + } else { + "Unknown Radeon Driver Version".to_string() + }; + + agsDeInitialize(context); + Ok(format!("{} ({})", software_version, driver_version)) + } + } +} + mod intel { use windows::{ Win32::Graphics::Dxgi::{IDXGIAdapter1, IDXGIDevice}, From 636a0573733ba4f3525b25499edb5a64ff0cd8d0 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 18 Jul 2025 16:46:34 +0800 Subject: [PATCH 2/8] allow to compile shader at building --- crates/gpui/build.rs | 179 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 178 insertions(+), 1 deletion(-) diff --git a/crates/gpui/build.rs b/crates/gpui/build.rs index 6bb63ee67fd2b33675f864f22620988325666636..077be5e683f51df84b209d8b81420eb0152eda72 100644 --- a/crates/gpui/build.rs +++ b/crates/gpui/build.rs @@ -242,12 +242,19 @@ mod macos { #[cfg(target_os = "windows")] mod windows { - use std::path::PathBuf; + use std::{ + io::Write, + path::{Path, PathBuf}, + process::{self, Command}, + }; pub(super) fn build() { // Link the AMD AGS library link_amd_ags(); + // Compile HLSL shaders + compile_shaders(); + // Embed the Windows manifest and resource file #[cfg(feature = "windows-manifest")] embed_resource(); @@ -280,4 +287,174 @@ mod windows { .manifest_required() .unwrap(); } + + fn compile_shaders() { + use std::fs; + use std::process::{self, Command}; + + 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", + "paths", + "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, + ); + } + println!( + "cargo:warning=Successfully compiled shaders. Output written to: {}", + rust_binding_path + ); + } + + fn find_fxc_compiler() -> String { + // Try to find in PATH + if let Ok(output) = std::process::Command::new("where").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(); + } + + // Check environment variable + if let Ok(path) = std::env::var("GPUI_FXC_PATH") { + if Path::new(&path).exists() { + return path; + } + } + + 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_5_0", + ); + 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_5_0", + ); + 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, + shader_path, + ]) + .output(); + + match output { + Ok(result) => { + if result.status.success() { + return; + } + eprintln!( + "Pixel 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 = + std::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 = std::fs::OpenOptions::new() + .write(true) + .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"); + } } From 154705e72966fa28dcbaf1be39cfe0cb84de7a2c Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 18 Jul 2025 17:08:44 +0800 Subject: [PATCH 3/8] checkpoint --- crates/gpui/build.rs | 1 + .../src/platform/windows/directx_renderer.rs | 177 +++++++++++------- 2 files changed, 113 insertions(+), 65 deletions(-) diff --git a/crates/gpui/build.rs b/crates/gpui/build.rs index 077be5e683f51df84b209d8b81420eb0152eda72..c593c2ff45eac1054465e077dbaac41ca7dcace6 100644 --- a/crates/gpui/build.rs +++ b/crates/gpui/build.rs @@ -288,6 +288,7 @@ mod windows { .unwrap(); } + /// You can set the `GPUI_FXC_PATH` environment variable to specify the path to the fxc.exe compiler. fn compile_shaders() { use std::fs; use std::process::{self, Command}; diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 4e804e74dcb2b99a566a727a3826bb47886fcfb1..7959e2d90f04ebf45ce0c117d1edd0ce9d18d866 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -13,7 +13,12 @@ use windows::Win32::{ #[cfg(not(feature = "enable-renderdoc"))] use windows::{Win32::Graphics::DirectComposition::*, core::Interface}; -use crate::*; +use crate::{ + platform::windows::directx_renderer::shader_resources::{ + RawShaderBytes, ShaderModule, ShaderTarget, + }, + *, +}; const RENDER_TARGET_FORMAT: DXGI_FORMAT = DXGI_FORMAT_B8G8R8A8_UNORM; // This configuration is used for MSAA rendering, and it's guaranteed to be supported by DirectX 11. @@ -481,35 +486,22 @@ impl DirectXResources { impl DirectXRenderPipelines { pub fn new(device: &ID3D11Device) -> Result { - let shadow_pipeline = PipelineState::new( - device, - "shadow_pipeline", - "shadow_vertex", - "shadow_fragment", - 4, - )?; - let quad_pipeline = - PipelineState::new(device, "quad_pipeline", "quad_vertex", "quad_fragment", 64)?; + let shadow_pipeline = + PipelineState::new(device, "shadow_pipeline", ShaderModule::Shadow, 4)?; + let quad_pipeline = PipelineState::new(device, "quad_pipeline", ShaderModule::Quad, 64)?; let paths_pipeline = PathsPipelineState::new(device)?; - let underline_pipeline = PipelineState::new( - device, - "underline_pipeline", - "underline_vertex", - "underline_fragment", - 4, - )?; + let underline_pipeline = + PipelineState::new(device, "underline_pipeline", ShaderModule::Underline, 4)?; let mono_sprites = PipelineState::new( device, "monochrome_sprite_pipeline", - "monochrome_sprite_vertex", - "monochrome_sprite_fragment", + ShaderModule::MonochromeSprite, 512, )?; let poly_sprites = PipelineState::new( device, "polychrome_sprite_pipeline", - "polychrome_sprite_vertex", - "polychrome_sprite_fragment", + ShaderModule::PolychromeSprite, 16, )?; @@ -625,29 +617,16 @@ impl PipelineState { fn new( device: &ID3D11Device, label: &'static str, - vertex_entry: &str, - fragment_entry: &str, + shader_module: ShaderModule, buffer_size: usize, ) -> Result { let vertex = { - let shader_blob = shader_resources::build_shader_blob(vertex_entry, "vs_5_0")?; - let bytes = unsafe { - std::slice::from_raw_parts( - shader_blob.GetBufferPointer() as *mut u8, - shader_blob.GetBufferSize(), - ) - }; - create_vertex_shader(device, bytes)? + let raw_shader = RawShaderBytes::new(shader_module, ShaderTarget::Vertex)?; + create_vertex_shader(device, raw_shader.as_bytes())? }; let fragment = { - let shader_blob = shader_resources::build_shader_blob(fragment_entry, "ps_5_0")?; - let bytes = unsafe { - std::slice::from_raw_parts( - shader_blob.GetBufferPointer() as *mut u8, - shader_blob.GetBufferSize(), - ) - }; - create_fragment_shader(device, bytes)? + let raw_shader = RawShaderBytes::new(shader_module, ShaderTarget::Fragment)?; + create_fragment_shader(device, raw_shader.as_bytes())? }; let buffer = create_buffer(device, std::mem::size_of::(), buffer_size)?; let view = create_buffer_view(device, &buffer)?; @@ -740,24 +719,15 @@ impl PipelineState { impl PathsPipelineState { fn new(device: &ID3D11Device) -> Result { let (vertex, vertex_shader) = { - let shader_blob = shader_resources::build_shader_blob("paths_vertex", "vs_5_0")?; - let bytes = unsafe { - std::slice::from_raw_parts( - shader_blob.GetBufferPointer() as *mut u8, - shader_blob.GetBufferSize(), - ) - }; - (create_vertex_shader(device, bytes)?, shader_blob) + let raw_vertex_shader = RawShaderBytes::new(ShaderModule::Paths, ShaderTarget::Vertex)?; + ( + create_vertex_shader(device, raw_vertex_shader.as_bytes())?, + raw_vertex_shader, + ) }; let fragment = { - let shader_blob = shader_resources::build_shader_blob("paths_fragment", "ps_5_0")?; - let bytes = unsafe { - std::slice::from_raw_parts( - shader_blob.GetBufferPointer() as *mut u8, - shader_blob.GetBufferSize(), - ) - }; - create_fragment_shader(device, bytes)? + let raw_shader = RawShaderBytes::new(ShaderModule::Paths, ShaderTarget::Fragment)?; + create_fragment_shader(device, raw_shader.as_bytes())? }; let buffer = create_buffer(device, std::mem::size_of::(), 32)?; let view = create_buffer_view(device, &buffer)?; @@ -769,10 +739,6 @@ impl PathsPipelineState { let indirect_draw_buffer = create_indirect_draw_buffer(device, 32)?; // Create input layout let input_layout = unsafe { - let shader_bytes = std::slice::from_raw_parts( - vertex_shader.GetBufferPointer() as *const u8, - vertex_shader.GetBufferSize(), - ); let mut layout = None; device.CreateInputLayout( &[ @@ -813,7 +779,7 @@ impl PathsPipelineState { InstanceDataStepRate: 0, }, ], - shader_bytes, + vertex_shader.as_bytes(), Some(&mut layout), )?; layout.unwrap() @@ -1316,12 +1282,73 @@ const BUFFER_COUNT: usize = 3; mod shader_resources { use anyhow::Result; - use windows::Win32::Graphics::Direct3D::{ - Fxc::{D3DCOMPILE_DEBUG, D3DCOMPILE_SKIP_OPTIMIZATION, D3DCompileFromFile}, - ID3DBlob, - }; - use windows_core::{HSTRING, PCSTR}; + // use windows::Win32::Graphics::Direct3D::{ + // Fxc::{D3DCOMPILE_DEBUG, D3DCOMPILE_SKIP_OPTIMIZATION, D3DCompileFromFile}, + // ID3DBlob, + // }; + // use windows_core::{HSTRING, PCSTR}; + + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + pub(super) enum ShaderModule { + Quad, + Shadow, + Underline, + Paths, + MonochromeSprite, + PolychromeSprite, + } + + #[derive(Copy, Clone, Debug, Eq, PartialEq)] + pub(super) enum ShaderTarget { + Vertex, + Fragment, + } + pub(super) struct RawShaderBytes<'t> { + inner: &'t [u8], + } + + impl<'t> RawShaderBytes<'t> { + pub(super) fn new(module: ShaderModule, target: ShaderTarget) -> Result { + Ok(Self::from_bytes(module, target)) + } + + pub(super) fn as_bytes(&self) -> &'t [u8] { + self.inner + } + + fn from_bytes(module: ShaderModule, target: ShaderTarget) -> Self { + let bytes = match module { + ShaderModule::Quad => match target { + ShaderTarget::Vertex => QUAD_VERTEX_BYTES, + ShaderTarget::Fragment => QUAD_FRAGMENT_BYTES, + }, + ShaderModule::Shadow => match target { + ShaderTarget::Vertex => SHADOW_VERTEX_BYTES, + ShaderTarget::Fragment => SHADOW_FRAGMENT_BYTES, + }, + ShaderModule::Underline => match target { + ShaderTarget::Vertex => UNDERLINE_VERTEX_BYTES, + ShaderTarget::Fragment => UNDERLINE_FRAGMENT_BYTES, + }, + ShaderModule::Paths => match target { + ShaderTarget::Vertex => PATHS_VERTEX_BYTES, + ShaderTarget::Fragment => PATHS_FRAGMENT_BYTES, + }, + ShaderModule::MonochromeSprite => match target { + ShaderTarget::Vertex => MONOCHROME_SPRITE_VERTEX_BYTES, + ShaderTarget::Fragment => MONOCHROME_SPRITE_FRAGMENT_BYTES, + }, + ShaderModule::PolychromeSprite => match target { + ShaderTarget::Vertex => POLYCHROME_SPRITE_VERTEX_BYTES, + ShaderTarget::Fragment => POLYCHROME_SPRITE_FRAGMENT_BYTES, + }, + }; + Self { inner: bytes } + } + } + + #[cfg(not(debug_assertions))] pub(super) fn build_shader_blob(entry: &str, target: &str) -> Result { unsafe { let mut entry = entry.to_owned(); @@ -1368,6 +1395,26 @@ mod shader_resources { Ok(compile_blob.unwrap()) } } + + include!(concat!(env!("OUT_DIR"), "/shaders_bytes.rs")); + + impl ShaderModule { + pub fn as_str(&self) -> &'static str { + match self { + ShaderModule::Quad => "quad", + ShaderModule::Shadow => "shadow", + ShaderModule::Underline => "underline", + ShaderModule::Paths => "paths", + ShaderModule::MonochromeSprite => "monochrome_sprite", + ShaderModule::PolychromeSprite => "polychrome_sprite", + } + } + } + + // pub fn quad_vertex_shader() -> &'static [u8] { + // unsafe { + // std::slice::from_raw_parts(g_quad_vertex.as_ptr() as *const u8, g_quad_vertex.len()) + // } } mod nvidia { From 825ee6233ba112a09adbb5971203115d22a40df4 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 18 Jul 2025 17:43:01 +0800 Subject: [PATCH 4/8] add runtime shader --- crates/gpui/build.rs | 1 + .../src/platform/windows/directx_renderer.rs | 88 ++++++++++++------- 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/crates/gpui/build.rs b/crates/gpui/build.rs index c593c2ff45eac1054465e077dbaac41ca7dcace6..dbbb8687fd129bed8c5f668354cc0c606b6e7ac0 100644 --- a/crates/gpui/build.rs +++ b/crates/gpui/build.rs @@ -253,6 +253,7 @@ mod windows { link_amd_ags(); // Compile HLSL shaders + #[cfg(not(debug_assertions))] compile_shaders(); // Embed the Windows manifest and resource file diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index 7959e2d90f04ebf45ce0c117d1edd0ce9d18d866..acc3faa91b2043bb084ebb7c6e6188f6190d16d9 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -1282,11 +1282,15 @@ const BUFFER_COUNT: usize = 3; mod shader_resources { use anyhow::Result; - // use windows::Win32::Graphics::Direct3D::{ - // Fxc::{D3DCOMPILE_DEBUG, D3DCOMPILE_SKIP_OPTIMIZATION, D3DCompileFromFile}, - // ID3DBlob, - // }; - // use windows_core::{HSTRING, PCSTR}; + + #[cfg(debug_assertions)] + use windows::{ + Win32::Graphics::Direct3D::{ + Fxc::{D3DCOMPILE_DEBUG, D3DCOMPILE_SKIP_OPTIMIZATION, D3DCompileFromFile}, + ID3DBlob, + }, + core::{HSTRING, PCSTR}, + }; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub(super) enum ShaderModule { @@ -1306,17 +1310,35 @@ mod shader_resources { pub(super) struct RawShaderBytes<'t> { inner: &'t [u8], + + #[cfg(debug_assertions)] + _blob: ID3DBlob, } impl<'t> RawShaderBytes<'t> { pub(super) fn new(module: ShaderModule, target: ShaderTarget) -> Result { - Ok(Self::from_bytes(module, target)) + #[cfg(not(debug_assertions))] + { + Ok(Self::from_bytes(module, target)) + } + #[cfg(debug_assertions)] + { + let blob = build_shader_blob(module, target)?; + let inner = unsafe { + std::slice::from_raw_parts( + blob.GetBufferPointer() as *const u8, + blob.GetBufferSize(), + ) + }; + Ok(Self { inner, _blob: blob }) + } } - pub(super) fn as_bytes(&self) -> &'t [u8] { + pub(super) fn as_bytes(&'t self) -> &'t [u8] { self.inner } + #[cfg(not(debug_assertions))] fn from_bytes(module: ShaderModule, target: ShaderTarget) -> Self { let bytes = match module { ShaderModule::Quad => match target { @@ -1348,32 +1370,38 @@ mod shader_resources { } } - #[cfg(not(debug_assertions))] - pub(super) fn build_shader_blob(entry: &str, target: &str) -> Result { + #[cfg(debug_assertions)] + pub(super) fn build_shader_blob(entry: ShaderModule, target: ShaderTarget) -> Result { unsafe { - let mut entry = entry.to_owned(); - let mut target = target.to_owned(); + let entry = format!( + "{}_{}\0", + entry.as_str(), + match target { + ShaderTarget::Vertex => "vertex", + ShaderTarget::Fragment => "fragment", + } + ); + let target = match target { + ShaderTarget::Vertex => "vs_5_0\0", + ShaderTarget::Fragment => "ps_5_0\0", + }; + let mut compile_blob = None; let mut error_blob = None; let shader_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) .join("src/platform/windows/shaders.hlsl") - .canonicalize() - .unwrap(); - entry.push_str("\0"); - target.push_str("\0"); + .canonicalize()?; + let entry_point = PCSTR::from_raw(entry.as_ptr()); let target_cstr = PCSTR::from_raw(target.as_ptr()); - #[cfg(debug_assertions)] - let compile_flag = D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION; - #[cfg(not(debug_assertions))] - let compile_flag = 0; + let ret = D3DCompileFromFile( &HSTRING::from(shader_path.to_str().unwrap()), None, None, entry_point, target_cstr, - compile_flag, + D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION, 0, &mut compile_blob, Some(&mut error_blob), @@ -1382,13 +1410,10 @@ mod shader_resources { let Some(error_blob) = error_blob else { return Err(anyhow::anyhow!("{ret:?}")); }; - let string_len = error_blob.GetBufferSize(); - let error_string_encode = Vec::from_raw_parts( - error_blob.GetBufferPointer() as *mut u8, - string_len, - string_len, - ); - let error_string = String::from_utf8_lossy(&error_string_encode).to_string(); + + let error_string = + std::ffi::CStr::from_ptr(error_blob.GetBufferPointer() as *const i8) + .to_string_lossy(); log::error!("Shader compile error: {}", error_string); return Err(anyhow::anyhow!("Compile error: {}", error_string)); } @@ -1396,10 +1421,12 @@ mod shader_resources { } } + #[cfg(not(debug_assertions))] include!(concat!(env!("OUT_DIR"), "/shaders_bytes.rs")); + #[cfg(debug_assertions)] impl ShaderModule { - pub fn as_str(&self) -> &'static str { + pub fn as_str(&self) -> &str { match self { ShaderModule::Quad => "quad", ShaderModule::Shadow => "shadow", @@ -1410,11 +1437,6 @@ mod shader_resources { } } } - - // pub fn quad_vertex_shader() -> &'static [u8] { - // unsafe { - // std::slice::from_raw_parts(g_quad_vertex.as_ptr() as *const u8, g_quad_vertex.len()) - // } } mod nvidia { From b0e48d01cec6e8261f6ffd758b9f723dc4d64904 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 18 Jul 2025 17:48:05 +0800 Subject: [PATCH 5/8] add x86 support for nvidia --- crates/gpui/src/platform/windows/directx_renderer.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/crates/gpui/src/platform/windows/directx_renderer.rs b/crates/gpui/src/platform/windows/directx_renderer.rs index acc3faa91b2043bb084ebb7c6e6188f6190d16d9..2cad807ae1f882c00c36c2ccfa4d6fab1266bea2 100644 --- a/crates/gpui/src/platform/windows/directx_renderer.rs +++ b/crates/gpui/src/platform/windows/directx_renderer.rs @@ -1468,7 +1468,13 @@ mod nvidia { pub(super) fn get_driver_version() -> Result { unsafe { // Try to load the NVIDIA driver DLL - let nvidia_dll = LoadLibraryA(s!("nvapi64.dll")).context("Can't load nvapi64.dll")?; + #[cfg(target_pointer_width = "64")] + let nvidia_dll = + LoadLibraryA(s!("nvapi64.dll")).context(format!("Can't load nvapi64.dll"))?; + #[cfg(target_pointer_width = "32")] + let nvidia_dll = + LoadLibraryA(s!("nvapi.dll")).context(format!("Can't load nvapi.dll"))?; + let nvapi_query_addr = GetProcAddress(nvidia_dll, s!("nvapi_QueryInterface")) .ok_or_else(|| anyhow::anyhow!("Failed to get nvapi_QueryInterface address"))?; let nvapi_query: extern "C" fn(u32) -> *mut () = std::mem::transmute(nvapi_query_addr); From e87ee91d8ec32cbae1e61d3ac1ce47ef99754d1d Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 18 Jul 2025 17:53:45 +0800 Subject: [PATCH 6/8] enable `O3` optimization for fxc --- crates/gpui/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/gpui/build.rs b/crates/gpui/build.rs index dbbb8687fd129bed8c5f668354cc0c606b6e7ac0..46dbdb0199044b3fe581574ad358d0ecf81c60b6 100644 --- a/crates/gpui/build.rs +++ b/crates/gpui/build.rs @@ -292,7 +292,6 @@ mod windows { /// You can set the `GPUI_FXC_PATH` environment variable to specify the path to the fxc.exe compiler. fn compile_shaders() { use std::fs; - use std::process::{self, Command}; let shader_path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()) .join("src/platform/windows/shaders.hlsl"); @@ -412,6 +411,7 @@ mod windows { output_path, "/Vn", var_name, + "/O3", shader_path, ]) .output(); From 788865e892c7d10e4886600bd67e864e8271c929 Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 18 Jul 2025 17:54:26 +0800 Subject: [PATCH 7/8] remove debug print --- crates/gpui/build.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/crates/gpui/build.rs b/crates/gpui/build.rs index 46dbdb0199044b3fe581574ad358d0ecf81c60b6..3c958528ffa2ad9b7f3c0b61e49361134d0d29a1 100644 --- a/crates/gpui/build.rs +++ b/crates/gpui/build.rs @@ -326,10 +326,6 @@ mod windows { &rust_binding_path, ); } - println!( - "cargo:warning=Successfully compiled shaders. Output written to: {}", - rust_binding_path - ); } fn find_fxc_compiler() -> String { From 9f200ebf5a242b1f73280791d6cc0c5488b241fb Mon Sep 17 00:00:00 2001 From: Junkui Zhang <364772080@qq.com> Date: Fri, 18 Jul 2025 17:56:46 +0800 Subject: [PATCH 8/8] fix --- crates/gpui/build.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/gpui/build.rs b/crates/gpui/build.rs index 3c958528ffa2ad9b7f3c0b61e49361134d0d29a1..54409177c4ad0848758eabd4be4931b996104baa 100644 --- a/crates/gpui/build.rs +++ b/crates/gpui/build.rs @@ -243,6 +243,7 @@ mod macos { #[cfg(target_os = "windows")] mod windows { use std::{ + fs, io::Write, path::{Path, PathBuf}, process::{self, Command}, @@ -269,6 +270,7 @@ mod windows { let lib_name = "amd_ags_x64_2022_MT"; #[cfg(target_pointer_width = "32")] let lib_name = "amd_ags_x86_2022_MT"; + println!("cargo:rustc-link-lib=static={}", lib_name); println!("cargo:rustc-link-search=native={}", lib_dir.display()); println!( @@ -291,8 +293,6 @@ mod windows { /// You can set the `GPUI_FXC_PATH` environment variable to specify the path to the fxc.exe compiler. fn compile_shaders() { - use std::fs; - 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(); @@ -317,7 +317,7 @@ mod windows { fs::remove_file(&rust_binding_path) .expect("Failed to remove existing Rust binding file"); } - for module in &modules { + for module in modules { compile_shader_for_module( module, &out_dir, @@ -328,6 +328,7 @@ mod windows { } } + /// You can set the `GPUI_FXC_PATH` environment variable to specify the path to the fxc.exe compiler. fn find_fxc_compiler() -> String { // Try to find in PATH if let Ok(output) = std::process::Command::new("where").arg("fxc.exe").output() { @@ -432,8 +433,7 @@ mod windows { } fn generate_rust_binding(const_name: &str, head_file: &str, output_path: &str) { - let header_content = - std::fs::read_to_string(head_file).expect("Failed to read header file"); + 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..]; @@ -445,7 +445,7 @@ mod windows { const_name, const_definition.replace('{', "[").replace('}', "]") ); - let mut options = std::fs::OpenOptions::new() + let mut options = fs::OpenOptions::new() .write(true) .create(true) .append(true)