Compare commits

...
Sign in to create a new pull request.

15 commits

Author SHA1 Message Date
Junkui Zhang
a4e8d2501a init 2025-08-01 18:00:12 +08:00
Junkui Zhang
3be48a9813 remove unneeded change 2025-08-01 17:32:48 +08:00
Junkui Zhang
7984e05d35 add comments 2025-08-01 16:59:37 +08:00
Junkui Zhang
88b01e5e31 fix raster_bounds 2025-08-01 16:55:12 +08:00
Junkui Zhang
e599352fc2 remove the use of bitmap scaler 2025-08-01 16:48:36 +08:00
Kate
c3f210eb5e
improve rendering (i think) 2025-07-31 17:24:47 +02:00
Junkui Zhang
d84cf7ef03 update rendering quality of small fonts 2025-07-31 21:30:44 +08:00
Junkui Zhang
aa68b3e8ef revert wrong blend state change 2025-07-31 19:46:17 +08:00
Junkui Zhang
fad7aa6643 fix 2025-07-31 18:41:25 +08:00
Junkui Zhang
d50b3e172e cleanup 2025-07-31 18:16:20 +08:00
Junkui Zhang
a8d3e5530b DXGI_ALPHA_MODE_PREMULTIPLIED 2025-07-31 17:53:40 +08:00
Junkui Zhang
fe096ad205 fix monochrome 2025-07-31 17:48:09 +08:00
Junkui Zhang
30f6699b56 checkpoint 2025-07-31 17:27:06 +08:00
Junkui Zhang
a1001079ba properly calculate bounds 2025-07-31 16:20:58 +08:00
Kate
da83011fda Rasterize glyphs without D2D
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
Co-authored-by: Julia <julia@zed.dev>
2025-07-30 17:08:47 -07:00
10 changed files with 713 additions and 284 deletions

View file

@ -310,6 +310,18 @@ mod windows {
&rust_binding_path, &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. /// You can set the `GPUI_FXC_PATH` environment variable to specify the path to the fxc.exe compiler.

View file

@ -198,7 +198,7 @@ impl RenderOnce for CharacterGrid {
"χ", "ψ", "", "а", "в", "Ж", "ж", "З", "з", "К", "к", "л", "м", "Н", "н", "Р", "р", "χ", "ψ", "", "а", "в", "Ж", "ж", "З", "з", "К", "к", "л", "м", "Н", "н", "Р", "р",
"У", "у", "ф", "ч", "ь", "ы", "Э", "э", "Я", "я", "ij", "öẋ", ".,", "⣝⣑", "~", "*", "У", "у", "ф", "ч", "ь", "ы", "Э", "э", "Я", "я", "ij", "öẋ", ".,", "⣝⣑", "~", "*",
"_", "^", "`", "'", "(", "{", "«", "#", "&", "@", "$", "¢", "%", "|", "?", "", "µ", "_", "^", "`", "'", "(", "{", "«", "#", "&", "@", "$", "¢", "%", "|", "?", "", "µ",
"", "<=", "!=", "==", "--", "++", "=>", "->", "", "<=", "!=", "==", "--", "++", "=>", "->", "🏀", "🎊", "😍", "❤️", "👍", "👎",
]; ];
let columns = 11; let columns = 11;

View file

@ -35,6 +35,7 @@ pub(crate) fn swap_rgba_pa_to_bgra(color: &mut [u8]) {
/// An RGBA color /// An RGBA color
#[derive(PartialEq, Clone, Copy, Default)] #[derive(PartialEq, Clone, Copy, Default)]
#[repr(C)]
pub struct Rgba { pub struct Rgba {
/// The red component of the color, in the range 0.0 to 1.0 /// The red component of the color, in the range 0.0 to 1.0
pub r: f32, pub r: f32,

View file

@ -0,0 +1,39 @@
struct RasterVertexOutput {
float4 position : SV_Position;
float2 texcoord : TEXCOORD0;
};
RasterVertexOutput emoji_rasterization_vertex(uint vertexID : SV_VERTEXID)
{
RasterVertexOutput output;
output.texcoord = float2((vertexID << 1) & 2, vertexID & 2);
output.position = float4(output.texcoord * 2.0f - 1.0f, 0.0f, 1.0f);
output.position.y = -output.position.y;
return output;
}
struct PixelInput {
float4 position: SV_Position;
float2 texcoord : TEXCOORD0;
};
struct Bounds {
int2 origin;
int2 size;
};
Texture2D<float4> t_layer : register(t0);
SamplerState s_layer : register(s0);
cbuffer GlyphLayerTextureParams : register(b0) {
Bounds bounds;
float4 run_color;
};
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;
return float4(run_color.rgb, alpha);
}

File diff suppressed because it is too large Load diff

View file

@ -7,7 +7,7 @@ use windows::Win32::Graphics::{
D3D11_USAGE_DEFAULT, ID3D11Device, ID3D11DeviceContext, ID3D11ShaderResourceView, D3D11_USAGE_DEFAULT, ID3D11Device, ID3D11DeviceContext, ID3D11ShaderResourceView,
ID3D11Texture2D, ID3D11Texture2D,
}, },
Dxgi::Common::{DXGI_FORMAT_A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_SAMPLE_DESC}, Dxgi::Common::*,
}; };
use crate::{ use crate::{
@ -167,7 +167,7 @@ impl DirectXAtlasState {
let bytes_per_pixel; let bytes_per_pixel;
match kind { match kind {
AtlasTextureKind::Monochrome => { AtlasTextureKind::Monochrome => {
pixel_format = DXGI_FORMAT_A8_UNORM; pixel_format = DXGI_FORMAT_R8_UNORM;
bind_flag = D3D11_BIND_SHADER_RESOURCE; bind_flag = D3D11_BIND_SHADER_RESOURCE;
bytes_per_pixel = 1; bytes_per_pixel = 1;
} }

View file

@ -42,8 +42,8 @@ pub(crate) struct DirectXRenderer {
pub(crate) struct DirectXDevices { pub(crate) struct DirectXDevices {
adapter: IDXGIAdapter1, adapter: IDXGIAdapter1,
dxgi_factory: IDXGIFactory6, dxgi_factory: IDXGIFactory6,
device: ID3D11Device, pub(crate) device: ID3D11Device,
device_context: ID3D11DeviceContext, pub(crate) device_context: ID3D11DeviceContext,
dxgi_device: Option<IDXGIDevice>, dxgi_device: Option<IDXGIDevice>,
} }
@ -183,7 +183,7 @@ impl DirectXRenderer {
self.resources.viewport[0].Width, self.resources.viewport[0].Width,
self.resources.viewport[0].Height, self.resources.viewport[0].Height,
], ],
..Default::default() _pad: 0,
}], }],
)?; )?;
unsafe { unsafe {
@ -1423,7 +1423,7 @@ fn report_live_objects(device: &ID3D11Device) -> Result<()> {
const BUFFER_COUNT: usize = 3; const BUFFER_COUNT: usize = 3;
mod shader_resources { pub(crate) mod shader_resources {
use anyhow::Result; use anyhow::Result;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -1436,7 +1436,7 @@ mod shader_resources {
}; };
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(super) enum ShaderModule { pub(crate) enum ShaderModule {
Quad, Quad,
Shadow, Shadow,
Underline, Underline,
@ -1444,15 +1444,16 @@ mod shader_resources {
PathSprite, PathSprite,
MonochromeSprite, MonochromeSprite,
PolychromeSprite, PolychromeSprite,
EmojiRasterization,
} }
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(super) enum ShaderTarget { pub(crate) enum ShaderTarget {
Vertex, Vertex,
Fragment, Fragment,
} }
pub(super) struct RawShaderBytes<'t> { pub(crate) struct RawShaderBytes<'t> {
inner: &'t [u8], inner: &'t [u8],
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -1460,7 +1461,7 @@ mod shader_resources {
} }
impl<'t> RawShaderBytes<'t> { impl<'t> RawShaderBytes<'t> {
pub(super) fn new(module: ShaderModule, target: ShaderTarget) -> Result<Self> { pub(crate) fn new(module: ShaderModule, target: ShaderTarget) -> Result<Self> {
#[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
{ {
Ok(Self::from_bytes(module, target)) Ok(Self::from_bytes(module, target))
@ -1478,7 +1479,7 @@ mod shader_resources {
} }
} }
pub(super) fn as_bytes(&'t self) -> &'t [u8] { pub(crate) fn as_bytes(&'t self) -> &'t [u8] {
self.inner self.inner
} }
@ -1513,6 +1514,10 @@ mod shader_resources {
ShaderTarget::Vertex => POLYCHROME_SPRITE_VERTEX_BYTES, ShaderTarget::Vertex => POLYCHROME_SPRITE_VERTEX_BYTES,
ShaderTarget::Fragment => POLYCHROME_SPRITE_FRAGMENT_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 } Self { inner: bytes }
} }
@ -1521,6 +1526,12 @@ mod shader_resources {
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
pub(super) fn build_shader_blob(entry: ShaderModule, target: ShaderTarget) -> Result<ID3DBlob> { pub(super) fn build_shader_blob(entry: ShaderModule, target: ShaderTarget) -> Result<ID3DBlob> {
unsafe { unsafe {
let shader_name = if matches!(entry, ShaderModule::EmojiRasterization) {
"color_text_raster.hlsl"
} else {
"shaders.hlsl"
};
let entry = format!( let entry = format!(
"{}_{}\0", "{}_{}\0",
entry.as_str(), entry.as_str(),
@ -1537,7 +1548,7 @@ mod shader_resources {
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("src/platform/windows/shaders.hlsl") .join(&format!("src/platform/windows/{}", shader_name))
.canonicalize()?; .canonicalize()?;
let entry_point = PCSTR::from_raw(entry.as_ptr()); let entry_point = PCSTR::from_raw(entry.as_ptr());
@ -1583,6 +1594,7 @@ mod shader_resources {
ShaderModule::PathSprite => "path_sprite", ShaderModule::PathSprite => "path_sprite",
ShaderModule::MonochromeSprite => "monochrome_sprite", ShaderModule::MonochromeSprite => "monochrome_sprite",
ShaderModule::PolychromeSprite => "polychrome_sprite", ShaderModule::PolychromeSprite => "polychrome_sprite",
ShaderModule::EmojiRasterization => "emoji_rasterization",
} }
} }
} }

View file

@ -44,6 +44,7 @@ pub(crate) struct WindowsPlatform {
drop_target_helper: IDropTargetHelper, drop_target_helper: IDropTargetHelper,
validation_number: usize, validation_number: usize,
main_thread_id_win32: u32, main_thread_id_win32: u32,
disable_direct_composition: bool,
} }
pub(crate) struct WindowsPlatformState { pub(crate) struct WindowsPlatformState {
@ -93,14 +94,18 @@ impl WindowsPlatform {
main_thread_id_win32, main_thread_id_win32,
validation_number, validation_number,
)); ));
let disable_direct_composition = std::env::var(DISABLE_DIRECT_COMPOSITION)
.is_ok_and(|value| value == "true" || value == "1");
let background_executor = BackgroundExecutor::new(dispatcher.clone()); let background_executor = BackgroundExecutor::new(dispatcher.clone());
let foreground_executor = ForegroundExecutor::new(dispatcher); let foreground_executor = ForegroundExecutor::new(dispatcher);
let directx_devices = DirectXDevices::new(disable_direct_composition)
.context("Unable to init directx devices.")?;
let bitmap_factory = ManuallyDrop::new(unsafe { let bitmap_factory = ManuallyDrop::new(unsafe {
CoCreateInstance(&CLSID_WICImagingFactory, None, CLSCTX_INPROC_SERVER) CoCreateInstance(&CLSID_WICImagingFactory, None, CLSCTX_INPROC_SERVER)
.context("Error creating bitmap factory.")? .context("Error creating bitmap factory.")?
}); });
let text_system = Arc::new( let text_system = Arc::new(
DirectWriteTextSystem::new(&bitmap_factory) DirectWriteTextSystem::new(&directx_devices, &bitmap_factory)
.context("Error creating DirectWriteTextSystem")?, .context("Error creating DirectWriteTextSystem")?,
); );
let drop_target_helper: IDropTargetHelper = unsafe { let drop_target_helper: IDropTargetHelper = unsafe {
@ -120,6 +125,7 @@ impl WindowsPlatform {
background_executor, background_executor,
foreground_executor, foreground_executor,
text_system, text_system,
disable_direct_composition,
windows_version, windows_version,
bitmap_factory, bitmap_factory,
drop_target_helper, drop_target_helper,
@ -184,6 +190,7 @@ impl WindowsPlatform {
validation_number: self.validation_number, validation_number: self.validation_number,
main_receiver: self.main_receiver.clone(), main_receiver: self.main_receiver.clone(),
main_thread_id_win32: self.main_thread_id_win32, main_thread_id_win32: self.main_thread_id_win32,
disable_direct_composition: self.disable_direct_composition,
} }
} }
@ -715,6 +722,7 @@ pub(crate) struct WindowCreationInfo {
pub(crate) validation_number: usize, pub(crate) validation_number: usize,
pub(crate) main_receiver: flume::Receiver<Runnable>, pub(crate) main_receiver: flume::Receiver<Runnable>,
pub(crate) main_thread_id_win32: u32, pub(crate) main_thread_id_win32: u32,
pub(crate) disable_direct_composition: bool,
} }
fn open_target(target: &str) { fn open_target(target: &str) {

View file

@ -1,6 +1,6 @@
cbuffer GlobalParams: register(b0) { cbuffer GlobalParams: register(b0) {
float2 global_viewport_size; float2 global_viewport_size;
uint2 _global_pad; uint2 _pad;
}; };
Texture2D<float4> t_sprite: register(t0); Texture2D<float4> t_sprite: register(t0);
@ -1069,6 +1069,7 @@ struct MonochromeSpriteFragmentInput {
float4 position: SV_Position; float4 position: SV_Position;
float2 tile_position: POSITION; float2 tile_position: POSITION;
nointerpolation float4 color: COLOR; nointerpolation float4 color: COLOR;
float4 clip_distance: SV_ClipDistance;
}; };
StructuredBuffer<MonochromeSprite> mono_sprites: register(t1); StructuredBuffer<MonochromeSprite> mono_sprites: register(t1);
@ -1091,10 +1092,8 @@ MonochromeSpriteVertexOutput monochrome_sprite_vertex(uint vertex_id: SV_VertexI
} }
float4 monochrome_sprite_fragment(MonochromeSpriteFragmentInput input): SV_Target { float4 monochrome_sprite_fragment(MonochromeSpriteFragmentInput input): SV_Target {
float4 sample = t_sprite.Sample(s_sprite, input.tile_position); float sample = t_sprite.Sample(s_sprite, input.tile_position).r;
float4 color = input.color; return float4(input.color.rgb, input.color.a * sample);
color.a *= sample.a;
return color;
} }
/* /*

View file

@ -360,6 +360,7 @@ impl WindowsWindow {
validation_number, validation_number,
main_receiver, main_receiver,
main_thread_id_win32, main_thread_id_win32,
disable_direct_composition,
} = creation_info; } = creation_info;
let classname = register_wnd_class(icon); let classname = register_wnd_class(icon);
let hide_title_bar = params let hide_title_bar = params
@ -375,8 +376,6 @@ impl WindowsWindow {
.map(|title| title.as_ref()) .map(|title| title.as_ref())
.unwrap_or(""), .unwrap_or(""),
); );
let disable_direct_composition = std::env::var(DISABLE_DIRECT_COMPOSITION)
.is_ok_and(|value| value == "true" || value == "1");
let (mut dwexstyle, dwstyle) = if params.kind == WindowKind::PopUp { let (mut dwexstyle, dwstyle) = if params.kind == WindowKind::PopUp {
(WS_EX_TOOLWINDOW, WINDOW_STYLE(0x0)) (WS_EX_TOOLWINDOW, WINDOW_STYLE(0x0))