Merge branch 'windows/dx11' into windows/remove-d2d
This commit is contained in:
commit
21e14b5f9a
4 changed files with 500 additions and 120 deletions
|
@ -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,232 @@ mod macos {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
mod windows {
|
||||
use std::{
|
||||
fs,
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
process::{self, Command},
|
||||
};
|
||||
|
||||
pub(super) fn build() {
|
||||
// Link the AMD AGS library
|
||||
link_amd_ags();
|
||||
|
||||
// Compile HLSL shaders
|
||||
#[cfg(not(debug_assertions))]
|
||||
compile_shaders();
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
/// 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",
|
||||
"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,
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
let shader_path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap())
|
||||
.join("src/platform/windows/color_text_raster.hlsl");
|
||||
compile_shader_for_module(
|
||||
"emoji_rasterization",
|
||||
&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 {
|
||||
// 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,
|
||||
"/O3",
|
||||
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 = 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()
|
||||
.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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ struct RasterVertexOutput {
|
|||
float2 texcoord : TEXCOORD0;
|
||||
};
|
||||
|
||||
RasterVertexOutput vertex(uint vertexID : SV_VERTEXID)
|
||||
RasterVertexOutput emoji_rasterization_vertex(uint vertexID : SV_VERTEXID)
|
||||
{
|
||||
RasterVertexOutput output;
|
||||
output.texcoord = float2((vertexID << 1) & 2, vertexID & 2);
|
||||
|
@ -31,7 +31,7 @@ cbuffer GlyphLayerTextureParams : register(b0) {
|
|||
float4 run_color;
|
||||
};
|
||||
|
||||
float4 pixel(PixelInput input): SV_Target {
|
||||
float4 emoji_rasterization_fragment(PixelInput input): SV_Target {
|
||||
float3 sampled = t_layer.Sample(s_layer, input.texcoord.xy).rgb;
|
||||
float alpha = (sampled.r + sampled.g + sampled.b) / 3;
|
||||
|
||||
|
|
|
@ -184,30 +184,22 @@ impl GPUState {
|
|||
};
|
||||
|
||||
let vertex_shader = {
|
||||
let source =
|
||||
shader_resources::build_shader_blob("color_text_raster", "vertex", "vs_5_0")?;
|
||||
let bytes = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
source.GetBufferPointer() as *mut u8,
|
||||
source.GetBufferSize(),
|
||||
)
|
||||
};
|
||||
let source = shader_resources::RawShaderBytes::new(
|
||||
shader_resources::ShaderModule::EmojiRasterization,
|
||||
shader_resources::ShaderTarget::Vertex,
|
||||
)?;
|
||||
let mut shader = None;
|
||||
unsafe { device.CreateVertexShader(bytes, None, Some(&mut shader)) }?;
|
||||
unsafe { device.CreateVertexShader(source.as_bytes(), None, Some(&mut shader)) }?;
|
||||
shader.unwrap()
|
||||
};
|
||||
|
||||
let pixel_shader = {
|
||||
let source =
|
||||
shader_resources::build_shader_blob("color_text_raster", "pixel", "ps_5_0")?;
|
||||
let bytes = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
source.GetBufferPointer() as *mut u8,
|
||||
source.GetBufferSize(),
|
||||
)
|
||||
};
|
||||
let source = shader_resources::RawShaderBytes::new(
|
||||
shader_resources::ShaderModule::EmojiRasterization,
|
||||
shader_resources::ShaderTarget::Fragment,
|
||||
)?;
|
||||
let mut shader = None;
|
||||
unsafe { device.CreatePixelShader(bytes, None, Some(&mut shader)) }?;
|
||||
unsafe { device.CreatePixelShader(source.as_bytes(), None, Some(&mut shader)) }?;
|
||||
shader.unwrap()
|
||||
};
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
@ -413,7 +418,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.")),
|
||||
}
|
||||
|
@ -481,35 +486,22 @@ impl DirectXResources {
|
|||
|
||||
impl DirectXRenderPipelines {
|
||||
pub fn new(device: &ID3D11Device) -> Result<Self> {
|
||||
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,31 +617,16 @@ impl<T> PipelineState<T> {
|
|||
fn new(
|
||||
device: &ID3D11Device,
|
||||
label: &'static str,
|
||||
vertex_entry: &str,
|
||||
fragment_entry: &str,
|
||||
shader_module: ShaderModule,
|
||||
buffer_size: usize,
|
||||
) -> Result<Self> {
|
||||
let vertex = {
|
||||
let shader_blob =
|
||||
shader_resources::build_shader_blob("shaders", 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("shaders", 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::<T>(), buffer_size)?;
|
||||
let view = create_buffer_view(device, &buffer)?;
|
||||
|
@ -742,26 +719,15 @@ impl<T> PipelineState<T> {
|
|||
impl PathsPipelineState {
|
||||
fn new(device: &ID3D11Device) -> Result<Self> {
|
||||
let (vertex, vertex_shader) = {
|
||||
let shader_blob =
|
||||
shader_resources::build_shader_blob("shaders", "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("shaders", "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::<PathSprite>(), 32)?;
|
||||
let view = create_buffer_view(device, &buffer)?;
|
||||
|
@ -773,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(
|
||||
&[
|
||||
|
@ -817,7 +779,7 @@ impl PathsPipelineState {
|
|||
InstanceDataStepRate: 0,
|
||||
},
|
||||
],
|
||||
shader_bytes,
|
||||
vertex_shader.as_bytes(),
|
||||
Some(&mut layout),
|
||||
)?;
|
||||
layout.unwrap()
|
||||
|
@ -1320,37 +1282,138 @@ const BUFFER_COUNT: usize = 3;
|
|||
|
||||
pub(crate) mod shader_resources {
|
||||
use anyhow::Result;
|
||||
use windows::Win32::Graphics::Direct3D::{
|
||||
Fxc::{D3DCOMPILE_DEBUG, D3DCOMPILE_SKIP_OPTIMIZATION, D3DCompileFromFile},
|
||||
ID3DBlob,
|
||||
};
|
||||
use windows_core::{HSTRING, PCSTR};
|
||||
|
||||
pub(crate) fn build_shader_blob(filename: &str, entry: &str, target: &str) -> Result<ID3DBlob> {
|
||||
#[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(crate) enum ShaderModule {
|
||||
Quad,
|
||||
Shadow,
|
||||
Underline,
|
||||
Paths,
|
||||
MonochromeSprite,
|
||||
PolychromeSprite,
|
||||
EmojiRasterization,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub(crate) enum ShaderTarget {
|
||||
Vertex,
|
||||
Fragment,
|
||||
}
|
||||
|
||||
pub(crate) struct RawShaderBytes<'t> {
|
||||
inner: &'t [u8],
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
_blob: ID3DBlob,
|
||||
}
|
||||
|
||||
impl<'t> RawShaderBytes<'t> {
|
||||
pub(crate) fn new(module: ShaderModule, target: ShaderTarget) -> Result<Self> {
|
||||
#[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(crate) 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 {
|
||||
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,
|
||||
},
|
||||
ShaderModule::EmojiRasterization => match target {
|
||||
ShaderTarget::Vertex => EMOJI_RASTERIZATION_VERTEX_BYTES,
|
||||
ShaderTarget::Fragment => EMOJI_RASTERIZATION_FRAGMENT_BYTES,
|
||||
},
|
||||
};
|
||||
Self { inner: bytes }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
pub(super) fn build_shader_blob(entry: ShaderModule, target: ShaderTarget) -> Result<ID3DBlob> {
|
||||
unsafe {
|
||||
let mut entry = entry.to_owned();
|
||||
let mut target = target.to_owned();
|
||||
let shader_name = if matches!(entry, ShaderModule::EmojiRasterization) {
|
||||
"color_text_raster.hlsl"
|
||||
} else {
|
||||
"shaders.hlsl"
|
||||
};
|
||||
|
||||
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(&format!("src/platform/windows/{}.hlsl", filename))
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
entry.push_str("\0");
|
||||
target.push_str("\0");
|
||||
.join(&format!("src/platform/windows/{}", shader_name))
|
||||
.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),
|
||||
|
@ -1359,19 +1422,34 @@ pub(crate) 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));
|
||||
}
|
||||
Ok(compile_blob.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
include!(concat!(env!("OUT_DIR"), "/shaders_bytes.rs"));
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
impl ShaderModule {
|
||||
pub fn as_str(&self) -> &str {
|
||||
match self {
|
||||
ShaderModule::Quad => "quad",
|
||||
ShaderModule::Shadow => "shadow",
|
||||
ShaderModule::Underline => "underline",
|
||||
ShaderModule::Paths => "paths",
|
||||
ShaderModule::MonochromeSprite => "monochrome_sprite",
|
||||
ShaderModule::PolychromeSprite => "polychrome_sprite",
|
||||
ShaderModule::EmojiRasterization => "emoji_rasterization",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod nvidia {
|
||||
|
@ -1403,7 +1481,13 @@ mod nvidia {
|
|||
pub(super) fn get_driver_version() -> Result<String> {
|
||||
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);
|
||||
|
@ -1442,6 +1526,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<String> {
|
||||
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},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue