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");
|
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")),
|
||||||
|
feature = "macos-blade"
|
||||||
|
))]
|
||||||
check_wgsl_shaders();
|
check_wgsl_shaders();
|
||||||
|
|
||||||
match target.as_deref() {
|
match target.as_deref() {
|
||||||
|
@ -17,15 +20,9 @@ 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();
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
|
@ -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;
|
float2 texcoord : TEXCOORD0;
|
||||||
};
|
};
|
||||||
|
|
||||||
RasterVertexOutput vertex(uint vertexID : SV_VERTEXID)
|
RasterVertexOutput emoji_rasterization_vertex(uint vertexID : SV_VERTEXID)
|
||||||
{
|
{
|
||||||
RasterVertexOutput output;
|
RasterVertexOutput output;
|
||||||
output.texcoord = float2((vertexID << 1) & 2, vertexID & 2);
|
output.texcoord = float2((vertexID << 1) & 2, vertexID & 2);
|
||||||
|
@ -31,7 +31,7 @@ cbuffer GlyphLayerTextureParams : register(b0) {
|
||||||
float4 run_color;
|
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;
|
float3 sampled = t_layer.Sample(s_layer, input.texcoord.xy).rgb;
|
||||||
float alpha = (sampled.r + sampled.g + sampled.b) / 3;
|
float alpha = (sampled.r + sampled.g + sampled.b) / 3;
|
||||||
|
|
||||||
|
|
|
@ -184,30 +184,22 @@ impl GPUState {
|
||||||
};
|
};
|
||||||
|
|
||||||
let vertex_shader = {
|
let vertex_shader = {
|
||||||
let source =
|
let source = shader_resources::RawShaderBytes::new(
|
||||||
shader_resources::build_shader_blob("color_text_raster", "vertex", "vs_5_0")?;
|
shader_resources::ShaderModule::EmojiRasterization,
|
||||||
let bytes = unsafe {
|
shader_resources::ShaderTarget::Vertex,
|
||||||
std::slice::from_raw_parts(
|
)?;
|
||||||
source.GetBufferPointer() as *mut u8,
|
|
||||||
source.GetBufferSize(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let mut shader = None;
|
let mut shader = None;
|
||||||
unsafe { device.CreateVertexShader(bytes, None, Some(&mut shader)) }?;
|
unsafe { device.CreateVertexShader(source.as_bytes(), None, Some(&mut shader)) }?;
|
||||||
shader.unwrap()
|
shader.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
let pixel_shader = {
|
let pixel_shader = {
|
||||||
let source =
|
let source = shader_resources::RawShaderBytes::new(
|
||||||
shader_resources::build_shader_blob("color_text_raster", "pixel", "ps_5_0")?;
|
shader_resources::ShaderModule::EmojiRasterization,
|
||||||
let bytes = unsafe {
|
shader_resources::ShaderTarget::Fragment,
|
||||||
std::slice::from_raw_parts(
|
)?;
|
||||||
source.GetBufferPointer() as *mut u8,
|
|
||||||
source.GetBufferSize(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let mut shader = None;
|
let mut shader = None;
|
||||||
unsafe { device.CreatePixelShader(bytes, None, Some(&mut shader)) }?;
|
unsafe { device.CreatePixelShader(source.as_bytes(), None, Some(&mut shader)) }?;
|
||||||
shader.unwrap()
|
shader.unwrap()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,12 @@ use windows::Win32::{
|
||||||
#[cfg(not(feature = "enable-renderdoc"))]
|
#[cfg(not(feature = "enable-renderdoc"))]
|
||||||
use windows::{Win32::Graphics::DirectComposition::*, core::Interface};
|
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;
|
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.
|
// 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 {
|
let driver_version = match desc.VendorId {
|
||||||
0x10DE => nvidia::get_driver_version(),
|
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),
|
0x8086 => intel::get_driver_version(&self.devices.adapter),
|
||||||
_ => Err(anyhow::anyhow!("Unknown vendor detected.")),
|
_ => Err(anyhow::anyhow!("Unknown vendor detected.")),
|
||||||
}
|
}
|
||||||
|
@ -481,35 +486,22 @@ impl DirectXResources {
|
||||||
|
|
||||||
impl DirectXRenderPipelines {
|
impl DirectXRenderPipelines {
|
||||||
pub fn new(device: &ID3D11Device) -> Result<Self> {
|
pub fn new(device: &ID3D11Device) -> Result<Self> {
|
||||||
let shadow_pipeline = PipelineState::new(
|
let shadow_pipeline =
|
||||||
device,
|
PipelineState::new(device, "shadow_pipeline", ShaderModule::Shadow, 4)?;
|
||||||
"shadow_pipeline",
|
let quad_pipeline = PipelineState::new(device, "quad_pipeline", ShaderModule::Quad, 64)?;
|
||||||
"shadow_vertex",
|
|
||||||
"shadow_fragment",
|
|
||||||
4,
|
|
||||||
)?;
|
|
||||||
let quad_pipeline =
|
|
||||||
PipelineState::new(device, "quad_pipeline", "quad_vertex", "quad_fragment", 64)?;
|
|
||||||
let paths_pipeline = PathsPipelineState::new(device)?;
|
let paths_pipeline = PathsPipelineState::new(device)?;
|
||||||
let underline_pipeline = PipelineState::new(
|
let underline_pipeline =
|
||||||
device,
|
PipelineState::new(device, "underline_pipeline", ShaderModule::Underline, 4)?;
|
||||||
"underline_pipeline",
|
|
||||||
"underline_vertex",
|
|
||||||
"underline_fragment",
|
|
||||||
4,
|
|
||||||
)?;
|
|
||||||
let mono_sprites = PipelineState::new(
|
let mono_sprites = PipelineState::new(
|
||||||
device,
|
device,
|
||||||
"monochrome_sprite_pipeline",
|
"monochrome_sprite_pipeline",
|
||||||
"monochrome_sprite_vertex",
|
ShaderModule::MonochromeSprite,
|
||||||
"monochrome_sprite_fragment",
|
|
||||||
512,
|
512,
|
||||||
)?;
|
)?;
|
||||||
let poly_sprites = PipelineState::new(
|
let poly_sprites = PipelineState::new(
|
||||||
device,
|
device,
|
||||||
"polychrome_sprite_pipeline",
|
"polychrome_sprite_pipeline",
|
||||||
"polychrome_sprite_vertex",
|
ShaderModule::PolychromeSprite,
|
||||||
"polychrome_sprite_fragment",
|
|
||||||
16,
|
16,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -625,31 +617,16 @@ impl<T> PipelineState<T> {
|
||||||
fn new(
|
fn new(
|
||||||
device: &ID3D11Device,
|
device: &ID3D11Device,
|
||||||
label: &'static str,
|
label: &'static str,
|
||||||
vertex_entry: &str,
|
shader_module: ShaderModule,
|
||||||
fragment_entry: &str,
|
|
||||||
buffer_size: usize,
|
buffer_size: usize,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let vertex = {
|
let vertex = {
|
||||||
let shader_blob =
|
let raw_shader = RawShaderBytes::new(shader_module, ShaderTarget::Vertex)?;
|
||||||
shader_resources::build_shader_blob("shaders", vertex_entry, "vs_5_0")?;
|
create_vertex_shader(device, raw_shader.as_bytes())?
|
||||||
let bytes = unsafe {
|
|
||||||
std::slice::from_raw_parts(
|
|
||||||
shader_blob.GetBufferPointer() as *mut u8,
|
|
||||||
shader_blob.GetBufferSize(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
create_vertex_shader(device, bytes)?
|
|
||||||
};
|
};
|
||||||
let fragment = {
|
let fragment = {
|
||||||
let shader_blob =
|
let raw_shader = RawShaderBytes::new(shader_module, ShaderTarget::Fragment)?;
|
||||||
shader_resources::build_shader_blob("shaders", fragment_entry, "ps_5_0")?;
|
create_fragment_shader(device, raw_shader.as_bytes())?
|
||||||
let bytes = unsafe {
|
|
||||||
std::slice::from_raw_parts(
|
|
||||||
shader_blob.GetBufferPointer() as *mut u8,
|
|
||||||
shader_blob.GetBufferSize(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
create_fragment_shader(device, bytes)?
|
|
||||||
};
|
};
|
||||||
let buffer = create_buffer(device, std::mem::size_of::<T>(), buffer_size)?;
|
let buffer = create_buffer(device, std::mem::size_of::<T>(), buffer_size)?;
|
||||||
let view = create_buffer_view(device, &buffer)?;
|
let view = create_buffer_view(device, &buffer)?;
|
||||||
|
@ -742,26 +719,15 @@ impl<T> PipelineState<T> {
|
||||||
impl PathsPipelineState {
|
impl PathsPipelineState {
|
||||||
fn new(device: &ID3D11Device) -> Result<Self> {
|
fn new(device: &ID3D11Device) -> Result<Self> {
|
||||||
let (vertex, vertex_shader) = {
|
let (vertex, vertex_shader) = {
|
||||||
let shader_blob =
|
let raw_vertex_shader = RawShaderBytes::new(ShaderModule::Paths, ShaderTarget::Vertex)?;
|
||||||
shader_resources::build_shader_blob("shaders", "paths_vertex", "vs_5_0")?;
|
(
|
||||||
let bytes = unsafe {
|
create_vertex_shader(device, raw_vertex_shader.as_bytes())?,
|
||||||
std::slice::from_raw_parts(
|
raw_vertex_shader,
|
||||||
shader_blob.GetBufferPointer() as *mut u8,
|
)
|
||||||
shader_blob.GetBufferSize(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
(create_vertex_shader(device, bytes)?, shader_blob)
|
|
||||||
};
|
};
|
||||||
let fragment = {
|
let fragment = {
|
||||||
let shader_blob =
|
let raw_shader = RawShaderBytes::new(ShaderModule::Paths, ShaderTarget::Fragment)?;
|
||||||
shader_resources::build_shader_blob("shaders", "paths_fragment", "ps_5_0")?;
|
create_fragment_shader(device, raw_shader.as_bytes())?
|
||||||
let bytes = unsafe {
|
|
||||||
std::slice::from_raw_parts(
|
|
||||||
shader_blob.GetBufferPointer() as *mut u8,
|
|
||||||
shader_blob.GetBufferSize(),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
create_fragment_shader(device, bytes)?
|
|
||||||
};
|
};
|
||||||
let buffer = create_buffer(device, std::mem::size_of::<PathSprite>(), 32)?;
|
let buffer = create_buffer(device, std::mem::size_of::<PathSprite>(), 32)?;
|
||||||
let view = create_buffer_view(device, &buffer)?;
|
let view = create_buffer_view(device, &buffer)?;
|
||||||
|
@ -773,10 +739,6 @@ impl PathsPipelineState {
|
||||||
let indirect_draw_buffer = create_indirect_draw_buffer(device, 32)?;
|
let indirect_draw_buffer = create_indirect_draw_buffer(device, 32)?;
|
||||||
// Create input layout
|
// Create input layout
|
||||||
let input_layout = unsafe {
|
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;
|
let mut layout = None;
|
||||||
device.CreateInputLayout(
|
device.CreateInputLayout(
|
||||||
&[
|
&[
|
||||||
|
@ -817,7 +779,7 @@ impl PathsPipelineState {
|
||||||
InstanceDataStepRate: 0,
|
InstanceDataStepRate: 0,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
shader_bytes,
|
vertex_shader.as_bytes(),
|
||||||
Some(&mut layout),
|
Some(&mut layout),
|
||||||
)?;
|
)?;
|
||||||
layout.unwrap()
|
layout.unwrap()
|
||||||
|
@ -1320,37 +1282,138 @@ const BUFFER_COUNT: usize = 3;
|
||||||
|
|
||||||
pub(crate) mod shader_resources {
|
pub(crate) mod shader_resources {
|
||||||
use anyhow::Result;
|
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 {
|
unsafe {
|
||||||
let mut entry = entry.to_owned();
|
let shader_name = if matches!(entry, ShaderModule::EmojiRasterization) {
|
||||||
let mut target = target.to_owned();
|
"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 compile_blob = None;
|
||||||
let mut error_blob = None;
|
let mut error_blob = None;
|
||||||
|
|
||||||
let shader_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
let shader_path = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
||||||
.join(&format!("src/platform/windows/{}.hlsl", filename))
|
.join(&format!("src/platform/windows/{}", shader_name))
|
||||||
.canonicalize()
|
.canonicalize()?;
|
||||||
.unwrap();
|
|
||||||
entry.push_str("\0");
|
|
||||||
target.push_str("\0");
|
|
||||||
let entry_point = PCSTR::from_raw(entry.as_ptr());
|
let entry_point = PCSTR::from_raw(entry.as_ptr());
|
||||||
let target_cstr = PCSTR::from_raw(target.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(
|
let ret = D3DCompileFromFile(
|
||||||
&HSTRING::from(shader_path.to_str().unwrap()),
|
&HSTRING::from(shader_path.to_str().unwrap()),
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
entry_point,
|
entry_point,
|
||||||
target_cstr,
|
target_cstr,
|
||||||
compile_flag,
|
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION,
|
||||||
0,
|
0,
|
||||||
&mut compile_blob,
|
&mut compile_blob,
|
||||||
Some(&mut error_blob),
|
Some(&mut error_blob),
|
||||||
|
@ -1359,19 +1422,34 @@ pub(crate) mod shader_resources {
|
||||||
let Some(error_blob) = error_blob else {
|
let Some(error_blob) = error_blob else {
|
||||||
return Err(anyhow::anyhow!("{ret:?}"));
|
return Err(anyhow::anyhow!("{ret:?}"));
|
||||||
};
|
};
|
||||||
let string_len = error_blob.GetBufferSize();
|
|
||||||
let error_string_encode = Vec::from_raw_parts(
|
let error_string =
|
||||||
error_blob.GetBufferPointer() as *mut u8,
|
std::ffi::CStr::from_ptr(error_blob.GetBufferPointer() as *const i8)
|
||||||
string_len,
|
.to_string_lossy();
|
||||||
string_len,
|
|
||||||
);
|
|
||||||
let error_string = String::from_utf8_lossy(&error_string_encode).to_string();
|
|
||||||
log::error!("Shader compile error: {}", error_string);
|
log::error!("Shader compile error: {}", error_string);
|
||||||
return Err(anyhow::anyhow!("Compile error: {}", error_string));
|
return Err(anyhow::anyhow!("Compile error: {}", error_string));
|
||||||
}
|
}
|
||||||
Ok(compile_blob.unwrap())
|
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 {
|
mod nvidia {
|
||||||
|
@ -1403,7 +1481,13 @@ mod nvidia {
|
||||||
pub(super) fn get_driver_version() -> Result<String> {
|
pub(super) fn get_driver_version() -> Result<String> {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Try to load the NVIDIA driver DLL
|
// 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"))
|
let nvapi_query_addr = GetProcAddress(nvidia_dll, s!("nvapi_QueryInterface"))
|
||||||
.ok_or_else(|| anyhow::anyhow!("Failed to get nvapi_QueryInterface address"))?;
|
.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);
|
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 {
|
mod intel {
|
||||||
use windows::{
|
use windows::{
|
||||||
Win32::Graphics::Dxgi::{IDXGIAdapter1, IDXGIDevice},
|
Win32::Graphics::Dxgi::{IDXGIAdapter1, IDXGIDevice},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue