Merge branch 'windows/dx11' into HEAD
This commit is contained in:
commit
c1eaf3317d
9 changed files with 1364 additions and 889 deletions
|
@ -666,6 +666,7 @@ features = [
|
|||
"Win32_Graphics_Direct3D",
|
||||
"Win32_Graphics_Direct3D11",
|
||||
"Win32_Graphics_Direct3D_Fxc",
|
||||
"Win32_Graphics_DirectComposition",
|
||||
"Win32_Graphics_DirectWrite",
|
||||
"Win32_Graphics_Dwm",
|
||||
"Win32_Graphics_Dxgi",
|
||||
|
|
|
@ -71,6 +71,7 @@ screen-capture = [
|
|||
"scap",
|
||||
]
|
||||
windows-manifest = []
|
||||
enable-renderdoc = []
|
||||
|
||||
[lib]
|
||||
path = "src/gpui.rs"
|
||||
|
|
|
@ -13,7 +13,6 @@ mod mac;
|
|||
any(target_os = "linux", target_os = "freebsd"),
|
||||
any(feature = "x11", feature = "wayland")
|
||||
),
|
||||
target_os = "windows",
|
||||
feature = "macos-blade"
|
||||
))]
|
||||
mod blade;
|
||||
|
|
|
@ -12,7 +12,7 @@ use windows::Win32::Graphics::{
|
|||
|
||||
use crate::{
|
||||
AtlasKey, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, DevicePixels, PlatformAtlas,
|
||||
Size, platform::AtlasTextureList,
|
||||
Point, Size, platform::AtlasTextureList,
|
||||
};
|
||||
|
||||
pub(crate) struct DirectXAtlas(Mutex<DirectXAtlasState>);
|
||||
|
@ -53,25 +53,6 @@ impl DirectXAtlas {
|
|||
let tex = lock.texture(id);
|
||||
tex.view.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn allocate(
|
||||
&self,
|
||||
size: Size<DevicePixels>,
|
||||
texture_kind: AtlasTextureKind,
|
||||
) -> Option<AtlasTile> {
|
||||
self.0.lock().allocate(size, texture_kind)
|
||||
}
|
||||
|
||||
pub(crate) fn clear_textures(&self, texture_kind: AtlasTextureKind) {
|
||||
let mut lock = self.0.lock();
|
||||
let textures = match texture_kind {
|
||||
AtlasTextureKind::Monochrome => &mut lock.monochrome_textures,
|
||||
AtlasTextureKind::Polychrome => &mut lock.polychrome_textures,
|
||||
};
|
||||
for texture in textures.iter_mut() {
|
||||
texture.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformAtlas for DirectXAtlas {
|
||||
|
@ -249,10 +230,6 @@ impl DirectXAtlasState {
|
|||
}
|
||||
|
||||
impl DirectXAtlasTexture {
|
||||
fn clear(&mut self) {
|
||||
self.allocator.clear();
|
||||
}
|
||||
|
||||
fn allocate(&mut self, size: Size<DevicePixels>) -> Option<AtlasTile> {
|
||||
let allocation = self.allocator.allocate(size.into())?;
|
||||
let tile = AtlasTile {
|
||||
|
@ -301,3 +278,18 @@ impl DirectXAtlasTexture {
|
|||
self.live_atlas_keys == 0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Size<DevicePixels>> for etagere::Size {
|
||||
fn from(size: Size<DevicePixels>) -> Self {
|
||||
etagere::Size::new(size.width.into(), size.height.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<etagere::Point> for Point<DevicePixels> {
|
||||
fn from(value: etagere::Point) -> Self {
|
||||
Point {
|
||||
x: DevicePixels::from(value.x),
|
||||
y: DevicePixels::from(value.y),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -181,12 +181,8 @@ fn handle_size_msg(
|
|||
let new_size = size(DevicePixels(width), DevicePixels(height));
|
||||
let scale_factor = lock.scale_factor;
|
||||
if lock.restore_from_minimized.is_some() {
|
||||
// lock.renderer
|
||||
// .update_drawable_size_even_if_unchanged(new_size);
|
||||
lock.renderer.resize(new_size).log_err();
|
||||
lock.callbacks.request_frame = lock.restore_from_minimized.take();
|
||||
} else {
|
||||
// lock.renderer.update_drawable_size(new_size);
|
||||
lock.renderer.resize(new_size).log_err();
|
||||
}
|
||||
let new_size = new_size.to_pixels(scale_factor);
|
||||
|
|
|
@ -28,13 +28,12 @@ use windows::{
|
|||
core::*,
|
||||
};
|
||||
|
||||
use crate::{platform::blade::BladeContext, *};
|
||||
use crate::*;
|
||||
|
||||
pub(crate) struct WindowsPlatform {
|
||||
state: RefCell<WindowsPlatformState>,
|
||||
raw_window_handles: RwLock<SmallVec<[HWND; 4]>>,
|
||||
// The below members will never change throughout the entire lifecycle of the app.
|
||||
// gpu_context: BladeContext,
|
||||
directx_devices: DirectXDevices,
|
||||
icon: HICON,
|
||||
main_receiver: flume::Receiver<Runnable>,
|
||||
|
@ -112,7 +111,6 @@ impl WindowsPlatform {
|
|||
let icon = load_icon().unwrap_or_default();
|
||||
let state = RefCell::new(WindowsPlatformState::new());
|
||||
let raw_window_handles = RwLock::new(SmallVec::new());
|
||||
// let gpu_context = BladeContext::new().context("Unable to init GPU context")?;
|
||||
let directx_devices = DirectXDevices::new().context("Unable to init directx devices.")?;
|
||||
let windows_version = WindowsVersion::new().context("Error retrieve windows version")?;
|
||||
|
||||
|
@ -462,7 +460,8 @@ impl Platform for WindowsPlatform {
|
|||
options,
|
||||
self.generate_creation_info(),
|
||||
&self.directx_devices,
|
||||
)?;
|
||||
)
|
||||
.inspect_err(|err| show_error("Failed to open new window", err.to_string()))?;
|
||||
let handle = window.get_raw_handle();
|
||||
self.raw_window_handles.write().push(handle);
|
||||
|
||||
|
|
|
@ -93,10 +93,9 @@ float4 to_device_position(float2 unit_vertex, Bounds bounds) {
|
|||
}
|
||||
|
||||
float4 distance_from_clip_rect_impl(float2 position, Bounds clip_bounds) {
|
||||
return float4(position.x - clip_bounds.origin.x,
|
||||
clip_bounds.origin.x + clip_bounds.size.x - position.x,
|
||||
position.y - clip_bounds.origin.y,
|
||||
clip_bounds.origin.y + clip_bounds.size.y - position.y);
|
||||
float2 tl = position - clip_bounds.origin;
|
||||
float2 br = clip_bounds.origin + clip_bounds.size - position;
|
||||
return float4(tl.x, br.x, tl.y, br.y);
|
||||
}
|
||||
|
||||
float4 distance_from_clip_rect(float2 unit_vertex, Bounds bounds, Bounds clip_bounds) {
|
||||
|
@ -240,6 +239,23 @@ float2 to_tile_position(float2 unit_vertex, AtlasTile tile) {
|
|||
return (float2(tile.bounds.origin) + unit_vertex * float2(tile.bounds.size)) / atlas_size;
|
||||
}
|
||||
|
||||
// Selects corner radius based on quadrant.
|
||||
float pick_corner_radius(float2 center_to_point, Corners corner_radii) {
|
||||
if (center_to_point.x < 0.) {
|
||||
if (center_to_point.y < 0.) {
|
||||
return corner_radii.top_left;
|
||||
} else {
|
||||
return corner_radii.bottom_left;
|
||||
}
|
||||
} else {
|
||||
if (center_to_point.y < 0.) {
|
||||
return corner_radii.top_right;
|
||||
} else {
|
||||
return corner_radii.bottom_right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float4 to_device_position_transformed(float2 unit_vertex, Bounds bounds,
|
||||
TransformationMatrix transformation) {
|
||||
float2 position = unit_vertex * bounds.size + bounds.origin;
|
||||
|
@ -248,48 +264,48 @@ float4 to_device_position_transformed(float2 unit_vertex, Bounds bounds,
|
|||
return float4(device_position, 0.0, 1.0);
|
||||
}
|
||||
|
||||
// Implementation of quad signed distance field
|
||||
float quad_sdf_impl(float2 corner_center_to_point, float corner_radius) {
|
||||
if (corner_radius == 0.0) {
|
||||
// Fast path for unrounded corners
|
||||
return max(corner_center_to_point.x, corner_center_to_point.y);
|
||||
} else {
|
||||
// Signed distance of the point from a quad that is inset by corner_radius
|
||||
// It is negative inside this quad, and positive outside
|
||||
float signed_distance_to_inset_quad =
|
||||
// 0 inside the inset quad, and positive outside
|
||||
length(max(float2(0.0, 0.0), corner_center_to_point)) +
|
||||
// 0 outside the inset quad, and negative inside
|
||||
min(0.0, max(corner_center_to_point.x, corner_center_to_point.y));
|
||||
|
||||
return signed_distance_to_inset_quad - corner_radius;
|
||||
}
|
||||
}
|
||||
|
||||
float quad_sdf(float2 pt, Bounds bounds, Corners corner_radii) {
|
||||
float2 half_size = bounds.size / 2.;
|
||||
float2 center = bounds.origin + half_size;
|
||||
float2 center_to_point = pt - center;
|
||||
float corner_radius;
|
||||
if (center_to_point.x < 0.) {
|
||||
if (center_to_point.y < 0.) {
|
||||
corner_radius = corner_radii.top_left;
|
||||
} else {
|
||||
corner_radius = corner_radii.bottom_left;
|
||||
}
|
||||
} else {
|
||||
if (center_to_point.y < 0.) {
|
||||
corner_radius = corner_radii.top_right;
|
||||
} else {
|
||||
corner_radius = corner_radii.bottom_right;
|
||||
}
|
||||
}
|
||||
|
||||
float2 rounded_edge_to_point = abs(center_to_point) - half_size + corner_radius;
|
||||
float distance =
|
||||
length(max(0., rounded_edge_to_point)) +
|
||||
min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) -
|
||||
corner_radius;
|
||||
|
||||
return distance;
|
||||
float corner_radius = pick_corner_radius(center_to_point, corner_radii);
|
||||
float2 corner_to_point = abs(center_to_point) - half_size;
|
||||
float2 corner_center_to_point = corner_to_point + corner_radius;
|
||||
return quad_sdf_impl(corner_center_to_point, corner_radius);
|
||||
}
|
||||
|
||||
GradientColor prepare_gradient_color(uint tag, uint color_space, Hsla solid, Hsla color0, Hsla color1) {
|
||||
GradientColor prepare_gradient_color(uint tag, uint color_space, Hsla solid, LinearColorStop colors[2]) {
|
||||
GradientColor output;
|
||||
if (tag == 0) {
|
||||
if (tag == 0 || tag == 2) {
|
||||
output.solid = hsla_to_rgba(solid);
|
||||
} else if (tag == 1) {
|
||||
output.color0 = hsla_to_rgba(color0);
|
||||
output.color1 = hsla_to_rgba(color1);
|
||||
output.color0 = hsla_to_rgba(colors[0].color);
|
||||
output.color1 = hsla_to_rgba(colors[1].color);
|
||||
|
||||
// Prepare color space in vertex for avoid conversion
|
||||
// in fragment shader for performance reasons
|
||||
if (color_space == 1) {
|
||||
// Oklab
|
||||
output.color0 = srgb_to_oklab(output.color0);
|
||||
output.color1 = srgb_to_oklab(output.color1);
|
||||
// Oklab
|
||||
output.color0 = srgb_to_oklab(output.color0);
|
||||
output.color1 = srgb_to_oklab(output.color1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,8 +342,8 @@ float4 gradient_color(Background background,
|
|||
}
|
||||
|
||||
// Get the t value for the linear gradient with the color stop percentages.
|
||||
float2 half_size = float2(bounds.size.x, bounds.size.y) / 2.;
|
||||
float2 center = float2(bounds.origin.x, bounds.origin.y) + half_size;
|
||||
float2 half_size = bounds.size * 0.5;
|
||||
float2 center = bounds.origin + half_size;
|
||||
float2 center_to_point = position - center;
|
||||
float t = dot(center_to_point, direction) / length(direction);
|
||||
// Check the direct to determine the use x or y
|
||||
|
@ -376,25 +392,410 @@ float4 gradient_color(Background background,
|
|||
return color;
|
||||
}
|
||||
|
||||
// Returns the dash velocity of a corner given the dash velocity of the two
|
||||
// sides, by returning the slower velocity (larger dashes).
|
||||
//
|
||||
// Since 0 is used for dash velocity when the border width is 0 (instead of
|
||||
// +inf), this returns the other dash velocity in that case.
|
||||
//
|
||||
// An alternative to this might be to appropriately interpolate the dash
|
||||
// velocity around the corner, but that seems overcomplicated.
|
||||
float corner_dash_velocity(float dv1, float dv2) {
|
||||
if (dv1 == 0.0) {
|
||||
return dv2;
|
||||
} else if (dv2 == 0.0) {
|
||||
return dv1;
|
||||
} else {
|
||||
return min(dv1, dv2);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns alpha used to render antialiased dashes.
|
||||
// `t` is within the dash when `fmod(t, period) < length`.
|
||||
float dash_alpha(
|
||||
float t, float period, float length, float dash_velocity,
|
||||
float antialias_threshold
|
||||
) {
|
||||
float half_period = period / 2.0;
|
||||
float half_length = length / 2.0;
|
||||
// Value in [-half_period, half_period]
|
||||
// The dash is in [-half_length, half_length]
|
||||
float centered = fmod(t + half_period - half_length, period) - half_period;
|
||||
// Signed distance for the dash, negative values are inside the dash
|
||||
float signed_distance = abs(centered) - half_length;
|
||||
// Antialiased alpha based on the signed distance
|
||||
return saturate(antialias_threshold - signed_distance / dash_velocity);
|
||||
}
|
||||
|
||||
// This approximates distance to the nearest point to a quarter ellipse in a way
|
||||
// that is sufficient for anti-aliasing when the ellipse is not very eccentric.
|
||||
// The components of `point` are expected to be positive.
|
||||
//
|
||||
// Negative on the outside and positive on the inside.
|
||||
float quarter_ellipse_sdf(float2 pt, float2 radii) {
|
||||
// Scale the space to treat the ellipse like a unit circle
|
||||
float2 circle_vec = pt / radii;
|
||||
float unit_circle_sdf = length(circle_vec) - 1.0;
|
||||
// Approximate up-scaling of the length by using the average of the radii.
|
||||
//
|
||||
// TODO: A better solution would be to use the gradient of the implicit
|
||||
// function for an ellipse to approximate a scaling factor.
|
||||
return unit_circle_sdf * (radii.x + radii.y) * -0.5;
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
** Quads
|
||||
**
|
||||
*/
|
||||
|
||||
struct Quad {
|
||||
uint order;
|
||||
uint border_style;
|
||||
Bounds bounds;
|
||||
Bounds content_mask;
|
||||
Background background;
|
||||
Hsla border_color;
|
||||
Corners corner_radii;
|
||||
Edges border_widths;
|
||||
};
|
||||
|
||||
struct QuadVertexOutput {
|
||||
nointerpolation uint quad_id: TEXCOORD0;
|
||||
float4 position: SV_Position;
|
||||
nointerpolation float4 border_color: COLOR0;
|
||||
nointerpolation float4 background_solid: COLOR1;
|
||||
nointerpolation float4 background_color0: COLOR2;
|
||||
nointerpolation float4 background_color1: COLOR3;
|
||||
float4 clip_distance: SV_ClipDistance;
|
||||
};
|
||||
|
||||
struct QuadFragmentInput {
|
||||
nointerpolation uint quad_id: TEXCOORD0;
|
||||
float4 position: SV_Position;
|
||||
nointerpolation float4 border_color: COLOR0;
|
||||
nointerpolation float4 background_solid: COLOR1;
|
||||
nointerpolation float4 background_color0: COLOR2;
|
||||
nointerpolation float4 background_color1: COLOR3;
|
||||
};
|
||||
|
||||
StructuredBuffer<Quad> quads: register(t1);
|
||||
|
||||
QuadVertexOutput quad_vertex(uint vertex_id: SV_VertexID, uint quad_id: SV_InstanceID) {
|
||||
float2 unit_vertex = float2(float(vertex_id & 1u), 0.5 * float(vertex_id & 2u));
|
||||
Quad quad = quads[quad_id];
|
||||
float4 device_position = to_device_position(unit_vertex, quad.bounds);
|
||||
|
||||
GradientColor gradient = prepare_gradient_color(
|
||||
quad.background.tag,
|
||||
quad.background.color_space,
|
||||
quad.background.solid,
|
||||
quad.background.colors
|
||||
);
|
||||
float4 clip_distance = distance_from_clip_rect(unit_vertex, quad.bounds, quad.content_mask);
|
||||
float4 border_color = hsla_to_rgba(quad.border_color);
|
||||
|
||||
QuadVertexOutput output;
|
||||
output.position = device_position;
|
||||
output.border_color = border_color;
|
||||
output.quad_id = quad_id;
|
||||
output.background_solid = gradient.solid;
|
||||
output.background_color0 = gradient.color0;
|
||||
output.background_color1 = gradient.color1;
|
||||
output.clip_distance = clip_distance;
|
||||
return output;
|
||||
}
|
||||
|
||||
float4 quad_fragment(QuadFragmentInput input): SV_Target {
|
||||
Quad quad = quads[input.quad_id];
|
||||
float4 background_color = gradient_color(quad.background, input.position.xy, quad.bounds,
|
||||
input.background_solid, input.background_color0, input.background_color1);
|
||||
|
||||
bool unrounded = quad.corner_radii.top_left == 0.0 &&
|
||||
quad.corner_radii.top_right == 0.0 &&
|
||||
quad.corner_radii.bottom_left == 0.0 &&
|
||||
quad.corner_radii.bottom_right == 0.0;
|
||||
|
||||
// Fast path when the quad is not rounded and doesn't have any border
|
||||
if (quad.border_widths.top == 0.0 &&
|
||||
quad.border_widths.left == 0.0 &&
|
||||
quad.border_widths.right == 0.0 &&
|
||||
quad.border_widths.bottom == 0.0 &&
|
||||
unrounded) {
|
||||
return background_color;
|
||||
}
|
||||
|
||||
float2 size = quad.bounds.size;
|
||||
float2 half_size = size / 2.;
|
||||
float2 the_point = input.position.xy - quad.bounds.origin;
|
||||
float2 center_to_point = the_point - half_size;
|
||||
|
||||
// Signed distance field threshold for inclusion of pixels. 0.5 is the
|
||||
// minimum distance between the center of the pixel and the edge.
|
||||
const float antialias_threshold = 0.5;
|
||||
|
||||
// Radius of the nearest corner
|
||||
float corner_radius = pick_corner_radius(center_to_point, quad.corner_radii);
|
||||
|
||||
float2 border = float2(
|
||||
center_to_point.x < 0.0 ? quad.border_widths.left : quad.border_widths.right,
|
||||
center_to_point.y < 0.0 ? quad.border_widths.top : quad.border_widths.bottom
|
||||
);
|
||||
|
||||
// 0-width borders are reduced so that `inner_sdf >= antialias_threshold`.
|
||||
// The purpose of this is to not draw antialiasing pixels in this case.
|
||||
float2 reduced_border = float2(
|
||||
border.x == 0.0 ? -antialias_threshold : border.x,
|
||||
border.y == 0.0 ? -antialias_threshold : border.y
|
||||
);
|
||||
|
||||
// Vector from the corner of the quad bounds to the point, after mirroring
|
||||
// the point into the bottom right quadrant. Both components are <= 0.
|
||||
float2 corner_to_point = abs(center_to_point) - half_size;
|
||||
|
||||
// Vector from the point to the center of the rounded corner's circle, also
|
||||
// mirrored into bottom right quadrant.
|
||||
float2 corner_center_to_point = corner_to_point + corner_radius;
|
||||
|
||||
// Whether the nearest point on the border is rounded
|
||||
bool is_near_rounded_corner =
|
||||
corner_center_to_point.x >= 0.0 &&
|
||||
corner_center_to_point.y >= 0.0;
|
||||
|
||||
// Vector from straight border inner corner to point.
|
||||
//
|
||||
// 0-width borders are turned into width -1 so that inner_sdf is > 1.0 near
|
||||
// the border. Without this, antialiasing pixels would be drawn.
|
||||
float2 straight_border_inner_corner_to_point = corner_to_point + reduced_border;
|
||||
|
||||
// Whether the point is beyond the inner edge of the straight border
|
||||
bool is_beyond_inner_straight_border =
|
||||
straight_border_inner_corner_to_point.x > 0.0 ||
|
||||
straight_border_inner_corner_to_point.y > 0.0;
|
||||
|
||||
// Whether the point is far enough inside the quad, such that the pixels are
|
||||
// not affected by the straight border.
|
||||
bool is_within_inner_straight_border =
|
||||
straight_border_inner_corner_to_point.x < -antialias_threshold &&
|
||||
straight_border_inner_corner_to_point.y < -antialias_threshold;
|
||||
|
||||
// Fast path for points that must be part of the background
|
||||
if (is_within_inner_straight_border && !is_near_rounded_corner) {
|
||||
return background_color;
|
||||
}
|
||||
|
||||
// Signed distance of the point to the outside edge of the quad's border
|
||||
float outer_sdf = quad_sdf_impl(corner_center_to_point, corner_radius);
|
||||
|
||||
// Approximate signed distance of the point to the inside edge of the quad's
|
||||
// border. It is negative outside this edge (within the border), and
|
||||
// positive inside.
|
||||
//
|
||||
// This is not always an accurate signed distance:
|
||||
// * The rounded portions with varying border width use an approximation of
|
||||
// nearest-point-on-ellipse.
|
||||
// * When it is quickly known to be outside the edge, -1.0 is used.
|
||||
float inner_sdf = 0.0;
|
||||
if (corner_center_to_point.x <= 0.0 || corner_center_to_point.y <= 0.0) {
|
||||
// Fast paths for straight borders
|
||||
inner_sdf = -max(straight_border_inner_corner_to_point.x,
|
||||
straight_border_inner_corner_to_point.y);
|
||||
} else if (is_beyond_inner_straight_border) {
|
||||
// Fast path for points that must be outside the inner edge
|
||||
inner_sdf = -1.0;
|
||||
} else if (reduced_border.x == reduced_border.y) {
|
||||
// Fast path for circular inner edge.
|
||||
inner_sdf = -(outer_sdf + reduced_border.x);
|
||||
} else {
|
||||
float2 ellipse_radii = max(float2(0.0, 0.0), float2(corner_radius, corner_radius) - reduced_border);
|
||||
inner_sdf = quarter_ellipse_sdf(corner_center_to_point, ellipse_radii);
|
||||
}
|
||||
|
||||
// Negative when inside the border
|
||||
float border_sdf = max(inner_sdf, outer_sdf);
|
||||
|
||||
float4 color = background_color;
|
||||
if (border_sdf < antialias_threshold) {
|
||||
float4 border_color = input.border_color;
|
||||
// Dashed border logic when border_style == 1
|
||||
if (quad.border_style == 1) {
|
||||
// Position along the perimeter in "dash space", where each dash
|
||||
// period has length 1
|
||||
float t = 0.0;
|
||||
|
||||
// Total number of dash periods, so that the dash spacing can be
|
||||
// adjusted to evenly divide it
|
||||
float max_t = 0.0;
|
||||
|
||||
// Border width is proportional to dash size. This is the behavior
|
||||
// used by browsers, but also avoids dashes from different segments
|
||||
// overlapping when dash size is smaller than the border width.
|
||||
//
|
||||
// Dash pattern: (2 * border width) dash, (1 * border width) gap
|
||||
const float dash_length_per_width = 2.0;
|
||||
const float dash_gap_per_width = 1.0;
|
||||
const float dash_period_per_width = dash_length_per_width + dash_gap_per_width;
|
||||
|
||||
// Since the dash size is determined by border width, the density of
|
||||
// dashes varies. Multiplying a pixel distance by this returns a
|
||||
// position in dash space - it has units (dash period / pixels). So
|
||||
// a dash velocity of (1 / 10) is 1 dash every 10 pixels.
|
||||
float dash_velocity = 0.0;
|
||||
|
||||
// Dividing this by the border width gives the dash velocity
|
||||
const float dv_numerator = 1.0 / dash_period_per_width;
|
||||
|
||||
if (unrounded) {
|
||||
// When corners aren't rounded, the dashes are separately laid
|
||||
// out on each straight line, rather than around the whole
|
||||
// perimeter. This way each line starts and ends with a dash.
|
||||
bool is_horizontal = corner_center_to_point.x < corner_center_to_point.y;
|
||||
float border_width = is_horizontal ? border.x : border.y;
|
||||
dash_velocity = dv_numerator / border_width;
|
||||
t = is_horizontal ? the_point.x : the_point.y;
|
||||
t *= dash_velocity;
|
||||
max_t = is_horizontal ? size.x : size.y;
|
||||
max_t *= dash_velocity;
|
||||
} else {
|
||||
// When corners are rounded, the dashes are laid out clockwise
|
||||
// around the whole perimeter.
|
||||
|
||||
float r_tr = quad.corner_radii.top_right;
|
||||
float r_br = quad.corner_radii.bottom_right;
|
||||
float r_bl = quad.corner_radii.bottom_left;
|
||||
float r_tl = quad.corner_radii.top_left;
|
||||
|
||||
float w_t = quad.border_widths.top;
|
||||
float w_r = quad.border_widths.right;
|
||||
float w_b = quad.border_widths.bottom;
|
||||
float w_l = quad.border_widths.left;
|
||||
|
||||
// Straight side dash velocities
|
||||
float dv_t = w_t <= 0.0 ? 0.0 : dv_numerator / w_t;
|
||||
float dv_r = w_r <= 0.0 ? 0.0 : dv_numerator / w_r;
|
||||
float dv_b = w_b <= 0.0 ? 0.0 : dv_numerator / w_b;
|
||||
float dv_l = w_l <= 0.0 ? 0.0 : dv_numerator / w_l;
|
||||
|
||||
// Straight side lengths in dash space
|
||||
float s_t = (size.x - r_tl - r_tr) * dv_t;
|
||||
float s_r = (size.y - r_tr - r_br) * dv_r;
|
||||
float s_b = (size.x - r_br - r_bl) * dv_b;
|
||||
float s_l = (size.y - r_bl - r_tl) * dv_l;
|
||||
|
||||
float corner_dash_velocity_tr = corner_dash_velocity(dv_t, dv_r);
|
||||
float corner_dash_velocity_br = corner_dash_velocity(dv_b, dv_r);
|
||||
float corner_dash_velocity_bl = corner_dash_velocity(dv_b, dv_l);
|
||||
float corner_dash_velocity_tl = corner_dash_velocity(dv_t, dv_l);
|
||||
|
||||
// Corner lengths in dash space
|
||||
float c_tr = r_tr * (M_PI_F / 2.0) * corner_dash_velocity_tr;
|
||||
float c_br = r_br * (M_PI_F / 2.0) * corner_dash_velocity_br;
|
||||
float c_bl = r_bl * (M_PI_F / 2.0) * corner_dash_velocity_bl;
|
||||
float c_tl = r_tl * (M_PI_F / 2.0) * corner_dash_velocity_tl;
|
||||
|
||||
// Cumulative dash space upto each segment
|
||||
float upto_tr = s_t;
|
||||
float upto_r = upto_tr + c_tr;
|
||||
float upto_br = upto_r + s_r;
|
||||
float upto_b = upto_br + c_br;
|
||||
float upto_bl = upto_b + s_b;
|
||||
float upto_l = upto_bl + c_bl;
|
||||
float upto_tl = upto_l + s_l;
|
||||
max_t = upto_tl + c_tl;
|
||||
|
||||
if (is_near_rounded_corner) {
|
||||
float radians = atan2(corner_center_to_point.y, corner_center_to_point.x);
|
||||
float corner_t = radians * corner_radius;
|
||||
|
||||
if (center_to_point.x >= 0.0) {
|
||||
if (center_to_point.y < 0.0) {
|
||||
dash_velocity = corner_dash_velocity_tr;
|
||||
// Subtracted because radians is pi/2 to 0 when
|
||||
// going clockwise around the top right corner,
|
||||
// since the y axis has been flipped
|
||||
t = upto_r - corner_t * dash_velocity;
|
||||
} else {
|
||||
dash_velocity = corner_dash_velocity_br;
|
||||
// Added because radians is 0 to pi/2 when going
|
||||
// clockwise around the bottom-right corner
|
||||
t = upto_br + corner_t * dash_velocity;
|
||||
}
|
||||
} else {
|
||||
if (center_to_point.y >= 0.0) {
|
||||
dash_velocity = corner_dash_velocity_bl;
|
||||
// Subtracted because radians is pi/1 to 0 when
|
||||
// going clockwise around the bottom-left corner,
|
||||
// since the x axis has been flipped
|
||||
t = upto_l - corner_t * dash_velocity;
|
||||
} else {
|
||||
dash_velocity = corner_dash_velocity_tl;
|
||||
// Added because radians is 0 to pi/2 when going
|
||||
// clockwise around the top-left corner, since both
|
||||
// axis were flipped
|
||||
t = upto_tl + corner_t * dash_velocity;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Straight borders
|
||||
bool is_horizontal = corner_center_to_point.x < corner_center_to_point.y;
|
||||
if (is_horizontal) {
|
||||
if (center_to_point.y < 0.0) {
|
||||
dash_velocity = dv_t;
|
||||
t = (the_point.x - r_tl) * dash_velocity;
|
||||
} else {
|
||||
dash_velocity = dv_b;
|
||||
t = upto_bl - (the_point.x - r_bl) * dash_velocity;
|
||||
}
|
||||
} else {
|
||||
if (center_to_point.x < 0.0) {
|
||||
dash_velocity = dv_l;
|
||||
t = upto_tl - (the_point.y - r_tl) * dash_velocity;
|
||||
} else {
|
||||
dash_velocity = dv_r;
|
||||
t = upto_r + (the_point.y - r_tr) * dash_velocity;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
float dash_length = dash_length_per_width / dash_period_per_width;
|
||||
float desired_dash_gap = dash_gap_per_width / dash_period_per_width;
|
||||
|
||||
// Straight borders should start and end with a dash, so max_t is
|
||||
// reduced to cause this.
|
||||
max_t -= unrounded ? dash_length : 0.0;
|
||||
if (max_t >= 1.0) {
|
||||
// Adjust dash gap to evenly divide max_t
|
||||
float dash_count = floor(max_t);
|
||||
float dash_period = max_t / dash_count;
|
||||
border_color.a *= dash_alpha(t, dash_period, dash_length, dash_velocity, antialias_threshold);
|
||||
} else if (unrounded) {
|
||||
// When there isn't enough space for the full gap between the
|
||||
// two start / end dashes of a straight border, reduce gap to
|
||||
// make them fit.
|
||||
float dash_gap = max_t - dash_length;
|
||||
if (dash_gap > 0.0) {
|
||||
float dash_period = dash_length + dash_gap;
|
||||
border_color.a *= dash_alpha(t, dash_period, dash_length, dash_velocity, antialias_threshold);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Blend the border on top of the background and then linearly interpolate
|
||||
// between the two as we slide inside the background.
|
||||
float4 blended_border = over(background_color, border_color);
|
||||
color = lerp(background_color, blended_border,
|
||||
saturate(antialias_threshold - inner_sdf));
|
||||
}
|
||||
|
||||
return color * float4(1.0, 1.0, 1.0, saturate(antialias_threshold - outer_sdf));
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
** Shadows
|
||||
**
|
||||
*/
|
||||
|
||||
struct ShadowVertexOutput {
|
||||
float4 position: SV_Position;
|
||||
float4 color: COLOR;
|
||||
uint shadow_id: FLAT;
|
||||
float4 clip_distance: SV_ClipDistance;
|
||||
};
|
||||
|
||||
struct ShadowFragmentInput {
|
||||
float4 position: SV_Position;
|
||||
float4 color: COLOR;
|
||||
uint shadow_id: FLAT;
|
||||
};
|
||||
|
||||
struct Shadow {
|
||||
uint order;
|
||||
float blur_radius;
|
||||
|
@ -404,6 +805,19 @@ struct Shadow {
|
|||
Hsla color;
|
||||
};
|
||||
|
||||
struct ShadowVertexOutput {
|
||||
nointerpolation uint shadow_id: TEXCOORD0;
|
||||
float4 position: SV_Position;
|
||||
nointerpolation float4 color: COLOR;
|
||||
float4 clip_distance: SV_ClipDistance;
|
||||
};
|
||||
|
||||
struct ShadowFragmentInput {
|
||||
nointerpolation uint shadow_id: TEXCOORD0;
|
||||
float4 position: SV_Position;
|
||||
nointerpolation float4 color: COLOR;
|
||||
};
|
||||
|
||||
StructuredBuffer<Shadow> shadows: register(t1);
|
||||
|
||||
ShadowVertexOutput shadow_vertex(uint vertex_id: SV_VertexID, uint shadow_id: SV_InstanceID) {
|
||||
|
@ -434,20 +848,7 @@ float4 shadow_fragment(ShadowFragmentInput input): SV_TARGET {
|
|||
float2 half_size = shadow.bounds.size / 2.;
|
||||
float2 center = shadow.bounds.origin + half_size;
|
||||
float2 point0 = input.position.xy - center;
|
||||
float corner_radius;
|
||||
if (point0.x < 0.) {
|
||||
if (point0.y < 0.) {
|
||||
corner_radius = shadow.corner_radii.top_left;
|
||||
} else {
|
||||
corner_radius = shadow.corner_radii.bottom_left;
|
||||
}
|
||||
} else {
|
||||
if (point0.y < 0.) {
|
||||
corner_radius = shadow.corner_radii.top_right;
|
||||
} else {
|
||||
corner_radius = shadow.corner_radii.bottom_right;
|
||||
}
|
||||
}
|
||||
float corner_radius = pick_corner_radius(point0, shadow.corner_radii);
|
||||
|
||||
// The signal is only non-zero in a limited range, so don't waste samples
|
||||
float low = point0.y - half_size.y;
|
||||
|
@ -469,145 +870,18 @@ float4 shadow_fragment(ShadowFragmentInput input): SV_TARGET {
|
|||
return input.color * float4(1., 1., 1., alpha);
|
||||
}
|
||||
|
||||
/*
|
||||
**
|
||||
** Quads
|
||||
**
|
||||
*/
|
||||
|
||||
struct Quad {
|
||||
uint order;
|
||||
uint pad;
|
||||
Bounds bounds;
|
||||
Bounds content_mask;
|
||||
Background background;
|
||||
Hsla border_color;
|
||||
Corners corner_radii;
|
||||
Edges border_widths;
|
||||
};
|
||||
|
||||
struct QuadVertexOutput {
|
||||
float4 position: SV_Position;
|
||||
nointerpolation float4 border_color: COLOR0;
|
||||
nointerpolation uint quad_id: TEXCOORD0;
|
||||
nointerpolation float4 background_solid: COLOR1;
|
||||
nointerpolation float4 background_color0: COLOR2;
|
||||
nointerpolation float4 background_color1: COLOR3;
|
||||
float4 clip_distance: SV_ClipDistance;
|
||||
};
|
||||
|
||||
struct QuadFragmentInput {
|
||||
nointerpolation uint quad_id: TEXCOORD0;
|
||||
float4 position: SV_Position;
|
||||
nointerpolation float4 border_color: COLOR0;
|
||||
nointerpolation float4 background_solid: COLOR1;
|
||||
nointerpolation float4 background_color0: COLOR2;
|
||||
nointerpolation float4 background_color1: COLOR3;
|
||||
};
|
||||
|
||||
StructuredBuffer<Quad> quads: register(t1);
|
||||
|
||||
QuadVertexOutput quad_vertex(uint vertex_id: SV_VertexID, uint quad_id: SV_InstanceID) {
|
||||
float2 unit_vertex = float2(float(vertex_id & 1u), 0.5 * float(vertex_id & 2u));
|
||||
Quad quad = quads[quad_id];
|
||||
float4 device_position = to_device_position(unit_vertex, quad.bounds);
|
||||
float4 clip_distance = distance_from_clip_rect(unit_vertex, quad.bounds, quad.content_mask);
|
||||
float4 border_color = hsla_to_rgba(quad.border_color);
|
||||
|
||||
GradientColor gradient = prepare_gradient_color(
|
||||
quad.background.tag,
|
||||
quad.background.color_space,
|
||||
quad.background.solid,
|
||||
quad.background.colors[0].color,
|
||||
quad.background.colors[1].color
|
||||
);
|
||||
|
||||
QuadVertexOutput output;
|
||||
output.position = device_position;
|
||||
output.border_color = border_color;
|
||||
output.quad_id = quad_id;
|
||||
output.background_solid = gradient.solid;
|
||||
output.background_color0 = gradient.color0;
|
||||
output.background_color1 = gradient.color1;
|
||||
output.clip_distance = clip_distance;
|
||||
return output;
|
||||
}
|
||||
|
||||
float4 quad_fragment(QuadFragmentInput input): SV_Target {
|
||||
Quad quad = quads[input.quad_id];
|
||||
float2 half_size = quad.bounds.size / 2.;
|
||||
float2 center = quad.bounds.origin + half_size;
|
||||
float2 center_to_point = input.position.xy - center;
|
||||
float4 color = gradient_color(quad.background, input.position.xy, quad.bounds,
|
||||
input.background_solid, input.background_color0, input.background_color1);
|
||||
|
||||
// Fast path when the quad is not rounded and doesn't have any border.
|
||||
if (quad.corner_radii.top_left == 0. && quad.corner_radii.bottom_left == 0. &&
|
||||
quad.corner_radii.top_right == 0. &&
|
||||
quad.corner_radii.bottom_right == 0. && quad.border_widths.top == 0. &&
|
||||
quad.border_widths.left == 0. && quad.border_widths.right == 0. &&
|
||||
quad.border_widths.bottom == 0.) {
|
||||
return color;
|
||||
}
|
||||
|
||||
float corner_radius;
|
||||
if (center_to_point.x < 0.) {
|
||||
if (center_to_point.y < 0.) {
|
||||
corner_radius = quad.corner_radii.top_left;
|
||||
} else {
|
||||
corner_radius = quad.corner_radii.bottom_left;
|
||||
}
|
||||
} else {
|
||||
if (center_to_point.y < 0.) {
|
||||
corner_radius = quad.corner_radii.top_right;
|
||||
} else {
|
||||
corner_radius = quad.corner_radii.bottom_right;
|
||||
}
|
||||
}
|
||||
|
||||
float2 rounded_edge_to_point = abs(center_to_point) - half_size + corner_radius;
|
||||
float distance =
|
||||
length(max(0., rounded_edge_to_point)) +
|
||||
min(0., max(rounded_edge_to_point.x, rounded_edge_to_point.y)) -
|
||||
corner_radius;
|
||||
|
||||
float vertical_border = center_to_point.x <= 0. ? quad.border_widths.left
|
||||
: quad.border_widths.right;
|
||||
float horizontal_border = center_to_point.y <= 0. ? quad.border_widths.top
|
||||
: quad.border_widths.bottom;
|
||||
float2 inset_size = half_size - corner_radius - float2(vertical_border, horizontal_border);
|
||||
float2 point_to_inset_corner = abs(center_to_point) - inset_size;
|
||||
float border_width;
|
||||
if (point_to_inset_corner.x < 0. && point_to_inset_corner.y < 0.) {
|
||||
border_width = 0.;
|
||||
} else if (point_to_inset_corner.y > point_to_inset_corner.x) {
|
||||
border_width = horizontal_border;
|
||||
} else {
|
||||
border_width = vertical_border;
|
||||
}
|
||||
|
||||
if (border_width != 0.) {
|
||||
float inset_distance = distance + border_width;
|
||||
// Blend the border on top of the background and then linearly interpolate
|
||||
// between the two as we slide inside the background.
|
||||
float4 blended_border = over(color, input.border_color);
|
||||
color = lerp(blended_border, color, saturate(0.5 - inset_distance));
|
||||
}
|
||||
|
||||
return color * float4(1., 1., 1., saturate(0.5 - distance));
|
||||
}
|
||||
|
||||
struct PathVertex {
|
||||
float2 xy_position;
|
||||
Bounds content_mask;
|
||||
};
|
||||
|
||||
/*
|
||||
**
|
||||
** Paths
|
||||
**
|
||||
*/
|
||||
|
||||
struct PathVertex {
|
||||
float2 xy_position: POSITION;
|
||||
Bounds content_mask: TEXCOORD;
|
||||
uint idx: GLOBALIDX;
|
||||
};
|
||||
|
||||
struct PathSprite {
|
||||
Bounds bounds;
|
||||
Background color;
|
||||
|
@ -615,31 +889,36 @@ struct PathSprite {
|
|||
|
||||
struct PathVertexOutput {
|
||||
float4 position: SV_Position;
|
||||
nointerpolation uint sprite_id: TEXCOORD0;
|
||||
nointerpolation float4 solid_color: COLOR0;
|
||||
nointerpolation float4 color0: COLOR1;
|
||||
nointerpolation float4 color1: COLOR2;
|
||||
float4 clip_distance: SV_ClipDistance;
|
||||
};
|
||||
|
||||
struct PathFragmentInput {
|
||||
float4 position: SV_Position;
|
||||
nointerpolation uint sprite_id: TEXCOORD0;
|
||||
nointerpolation float4 solid_color: COLOR0;
|
||||
nointerpolation float4 color0: COLOR1;
|
||||
nointerpolation float4 color1: COLOR2;
|
||||
};
|
||||
|
||||
StructuredBuffer<PathVertex> path_vertices: register(t1);
|
||||
StructuredBuffer<PathSprite> path_sprites: register(t2);
|
||||
StructuredBuffer<PathSprite> path_sprites: register(t1);
|
||||
|
||||
PathVertexOutput paths_vertex(uint vertex_id: SV_VertexID, uint instance_id: SV_InstanceID) {
|
||||
PathVertex v = path_vertices[vertex_id];
|
||||
PathSprite sprite = path_sprites[instance_id];
|
||||
PathVertexOutput paths_vertex(PathVertex input) {
|
||||
PathSprite sprite = path_sprites[input.idx];
|
||||
|
||||
PathVertexOutput output;
|
||||
output.position = to_device_position_impl(v.xy_position);
|
||||
output.clip_distance = distance_from_clip_rect_impl(v.xy_position, v.content_mask);
|
||||
output.sprite_id = instance_id;
|
||||
output.position = to_device_position_impl(input.xy_position);
|
||||
output.clip_distance = distance_from_clip_rect_impl(input.xy_position, input.content_mask);
|
||||
output.sprite_id = input.idx;
|
||||
|
||||
GradientColor gradient = prepare_gradient_color(
|
||||
sprite.color.tag,
|
||||
sprite.color.color_space,
|
||||
sprite.color.solid,
|
||||
sprite.color.colors[0].color,
|
||||
sprite.color.colors[1].color
|
||||
sprite.color.colors
|
||||
);
|
||||
|
||||
output.solid_color = gradient.solid;
|
||||
|
@ -648,12 +927,7 @@ PathVertexOutput paths_vertex(uint vertex_id: SV_VertexID, uint instance_id: SV_
|
|||
return output;
|
||||
}
|
||||
|
||||
float4 paths_fragment(PathVertexOutput input): SV_Target {
|
||||
float4 zero = 0.0;
|
||||
if (any(input.clip_distance < zero)) {
|
||||
return zero;
|
||||
}
|
||||
|
||||
float4 paths_fragment(PathFragmentInput input): SV_Target {
|
||||
PathSprite sprite = path_sprites[input.sprite_id];
|
||||
Background background = sprite.color;
|
||||
float4 color = gradient_color(background, input.position.xy, sprite.bounds,
|
||||
|
@ -678,16 +952,16 @@ struct Underline {
|
|||
};
|
||||
|
||||
struct UnderlineVertexOutput {
|
||||
nointerpolation uint underline_id: TEXCOORD0;
|
||||
float4 position: SV_Position;
|
||||
float4 color: COLOR;
|
||||
uint underline_id: FLAT;
|
||||
nointerpolation float4 color: COLOR;
|
||||
float4 clip_distance: SV_ClipDistance;
|
||||
};
|
||||
|
||||
struct UnderlineFragmentInput {
|
||||
nointerpolation uint underline_id: TEXCOORD0;
|
||||
float4 position: SV_Position;
|
||||
float4 color: COLOR;
|
||||
uint underline_id: FLAT;
|
||||
nointerpolation float4 color: COLOR;
|
||||
};
|
||||
|
||||
StructuredBuffer<Underline> underlines: register(t1);
|
||||
|
@ -712,10 +986,8 @@ float4 underline_fragment(UnderlineFragmentInput input): SV_Target {
|
|||
Underline underline = underlines[input.underline_id];
|
||||
if (underline.wavy) {
|
||||
float half_thickness = underline.thickness * 0.5;
|
||||
float2 origin =
|
||||
float2(underline.bounds.origin.x, underline.bounds.origin.y);
|
||||
float2 st = ((input.position.xy - origin) / underline.bounds.size.y) -
|
||||
float2(0., 0.5);
|
||||
float2 origin = underline.bounds.origin;
|
||||
float2 st = ((input.position.xy - origin) / underline.bounds.size.y) - float2(0., 0.5);
|
||||
float frequency = (M_PI_F * (3. * underline.thickness)) / 8.;
|
||||
float amplitude = 1. / (2. * underline.thickness);
|
||||
float sine = sin(st.x * frequency) * amplitude;
|
||||
|
@ -751,14 +1023,14 @@ struct MonochromeSprite {
|
|||
struct MonochromeSpriteVertexOutput {
|
||||
float4 position: SV_Position;
|
||||
float2 tile_position: POSITION;
|
||||
float4 color: COLOR;
|
||||
nointerpolation float4 color: COLOR;
|
||||
float4 clip_distance: SV_ClipDistance;
|
||||
};
|
||||
|
||||
struct MonochromeSpriteFragmentInput {
|
||||
float4 position: SV_Position;
|
||||
float2 tile_position: POSITION;
|
||||
float4 color: COLOR;
|
||||
nointerpolation float4 color: COLOR;
|
||||
};
|
||||
|
||||
StructuredBuffer<MonochromeSprite> mono_sprites: register(t1);
|
||||
|
@ -795,7 +1067,9 @@ float4 monochrome_sprite_fragment(MonochromeSpriteFragmentInput input): SV_Targe
|
|||
|
||||
struct PolychromeSprite {
|
||||
uint order;
|
||||
uint pad;
|
||||
uint grayscale;
|
||||
float opacity;
|
||||
Bounds bounds;
|
||||
Bounds content_mask;
|
||||
Corners corner_radii;
|
||||
|
@ -803,16 +1077,16 @@ struct PolychromeSprite {
|
|||
};
|
||||
|
||||
struct PolychromeSpriteVertexOutput {
|
||||
nointerpolation uint sprite_id: TEXCOORD0;
|
||||
float4 position: SV_Position;
|
||||
float2 tile_position: POSITION;
|
||||
uint sprite_id: FLAT;
|
||||
float4 clip_distance: SV_ClipDistance;
|
||||
};
|
||||
|
||||
struct PolychromeSpriteFragmentInput {
|
||||
nointerpolation uint sprite_id: TEXCOORD0;
|
||||
float4 position: SV_Position;
|
||||
float2 tile_position: POSITION;
|
||||
uint sprite_id: FLAT;
|
||||
};
|
||||
|
||||
StructuredBuffer<PolychromeSprite> poly_sprites: register(t1);
|
||||
|
@ -843,6 +1117,6 @@ float4 polychrome_sprite_fragment(PolychromeSpriteFragmentInput input): SV_Targe
|
|||
float3 grayscale = dot(color.rgb, GRAYSCALE_FACTORS);
|
||||
color = float4(grayscale, sample.a);
|
||||
}
|
||||
color.a *= saturate(0.5 - distance);
|
||||
color.a *= sprite.opacity * saturate(0.5 - distance);
|
||||
return color;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ use windows::{
|
|||
core::*,
|
||||
};
|
||||
|
||||
use crate::platform::blade::{BladeContext, BladeRenderer};
|
||||
use crate::*;
|
||||
|
||||
pub(crate) struct WindowsWindow(pub Rc<WindowsWindowStatePtr>);
|
||||
|
@ -80,7 +79,6 @@ pub(crate) struct WindowsWindowStatePtr {
|
|||
impl WindowsWindowState {
|
||||
fn new(
|
||||
hwnd: HWND,
|
||||
transparent: bool,
|
||||
cs: &CREATESTRUCTW,
|
||||
current_cursor: Option<HCURSOR>,
|
||||
display: WindowsDisplay,
|
||||
|
@ -103,8 +101,7 @@ impl WindowsWindowState {
|
|||
};
|
||||
let border_offset = WindowBorderOffset::default();
|
||||
let restore_from_minimized = None;
|
||||
// let renderer = windows_renderer::init(gpu_context, hwnd, transparent)?;
|
||||
let renderer = DirectXRenderer::new(gpu_context, hwnd, transparent)?;
|
||||
let renderer = DirectXRenderer::new(gpu_context, hwnd)?;
|
||||
let callbacks = Callbacks::default();
|
||||
let input_handler = None;
|
||||
let pending_surrogate = None;
|
||||
|
@ -207,7 +204,6 @@ impl WindowsWindowStatePtr {
|
|||
fn new(context: &WindowCreateContext, hwnd: HWND, cs: &CREATESTRUCTW) -> Result<Rc<Self>> {
|
||||
let state = RefCell::new(WindowsWindowState::new(
|
||||
hwnd,
|
||||
context.transparent,
|
||||
cs,
|
||||
context.current_cursor,
|
||||
context.display,
|
||||
|
@ -335,7 +331,6 @@ struct WindowCreateContext<'a> {
|
|||
handle: AnyWindowHandle,
|
||||
hide_title_bar: bool,
|
||||
display: WindowsDisplay,
|
||||
transparent: bool,
|
||||
is_movable: bool,
|
||||
min_size: Option<Size<Pixels>>,
|
||||
executor: ForegroundExecutor,
|
||||
|
@ -381,10 +376,13 @@ impl WindowsWindow {
|
|||
.unwrap_or(""),
|
||||
);
|
||||
let (dwexstyle, mut dwstyle) = if params.kind == WindowKind::PopUp {
|
||||
(WS_EX_TOOLWINDOW | WS_EX_LAYERED, WINDOW_STYLE(0x0))
|
||||
(
|
||||
WS_EX_TOOLWINDOW | WS_EX_NOREDIRECTIONBITMAP,
|
||||
WINDOW_STYLE(0x0),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
WS_EX_APPWINDOW | WS_EX_LAYERED,
|
||||
WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP,
|
||||
WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
|
||||
)
|
||||
};
|
||||
|
@ -402,7 +400,6 @@ impl WindowsWindow {
|
|||
handle,
|
||||
hide_title_bar,
|
||||
display,
|
||||
transparent: true,
|
||||
is_movable: params.is_movable,
|
||||
min_size: params.window_min_size,
|
||||
executor,
|
||||
|
@ -454,14 +451,6 @@ impl WindowsWindow {
|
|||
state: WindowOpenState::Windowed,
|
||||
});
|
||||
}
|
||||
// The render pipeline will perform compositing on the GPU when the
|
||||
// swapchain is configured correctly (see downstream of
|
||||
// update_transparency).
|
||||
// The following configuration is a one-time setup to ensure that the
|
||||
// window is going to be composited with per-pixel alpha, but the render
|
||||
// pipeline is responsible for effectively calling UpdateLayeredWindow
|
||||
// at the appropriate time.
|
||||
unsafe { SetLayeredWindowAttributes(hwnd, COLORREF(0), 255, LWA_ALPHA)? };
|
||||
|
||||
Ok(Self(state_ptr))
|
||||
}
|
||||
|
@ -486,7 +475,6 @@ impl rwh::HasDisplayHandle for WindowsWindow {
|
|||
|
||||
impl Drop for WindowsWindow {
|
||||
fn drop(&mut self) {
|
||||
// self.0.state.borrow_mut().renderer.destroy();
|
||||
// clone this `Rc` to prevent early release of the pointer
|
||||
let this = self.0.clone();
|
||||
self.0
|
||||
|
@ -706,25 +694,21 @@ impl PlatformWindow for WindowsWindow {
|
|||
}
|
||||
|
||||
fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
|
||||
let mut window_state = self.0.state.borrow_mut();
|
||||
// todo(zjk)
|
||||
// window_state
|
||||
// .renderer
|
||||
// .update_transparency(background_appearance != WindowBackgroundAppearance::Opaque);
|
||||
let hwnd = self.0.hwnd;
|
||||
|
||||
match background_appearance {
|
||||
WindowBackgroundAppearance::Opaque => {
|
||||
// ACCENT_DISABLED
|
||||
set_window_composition_attribute(window_state.hwnd, None, 0);
|
||||
set_window_composition_attribute(hwnd, None, 0);
|
||||
}
|
||||
WindowBackgroundAppearance::Transparent => {
|
||||
// Use ACCENT_ENABLE_TRANSPARENTGRADIENT for transparent background
|
||||
set_window_composition_attribute(window_state.hwnd, None, 2);
|
||||
set_window_composition_attribute(hwnd, None, 2);
|
||||
}
|
||||
WindowBackgroundAppearance::Blurred => {
|
||||
// Enable acrylic blur
|
||||
// ACCENT_ENABLE_ACRYLICBLURBEHIND
|
||||
set_window_composition_attribute(window_state.hwnd, Some((0, 0, 0, 0)), 4);
|
||||
set_window_composition_attribute(hwnd, Some((0, 0, 0, 0)), 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -808,13 +792,11 @@ impl PlatformWindow for WindowsWindow {
|
|||
}
|
||||
|
||||
fn gpu_specs(&self) -> Option<GpuSpecs> {
|
||||
// todo(zjk)
|
||||
// Some(self.0.state.borrow().renderer.gpu_specs())
|
||||
None
|
||||
self.0.state.borrow().renderer.gpu_specs().log_err()
|
||||
}
|
||||
|
||||
fn update_ime_position(&self, _bounds: Bounds<ScaledPixels>) {
|
||||
// todo(windows)
|
||||
// There is no such thing on Windows.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1310,52 +1292,6 @@ fn set_window_composition_attribute(hwnd: HWND, color: Option<Color>, state: u32
|
|||
}
|
||||
}
|
||||
|
||||
mod windows_renderer {
|
||||
use crate::platform::blade::{BladeContext, BladeRenderer, BladeSurfaceConfig};
|
||||
use raw_window_handle as rwh;
|
||||
use std::num::NonZeroIsize;
|
||||
use windows::Win32::{Foundation::HWND, UI::WindowsAndMessaging::GWLP_HINSTANCE};
|
||||
|
||||
use crate::{get_window_long, show_error};
|
||||
|
||||
pub(super) fn init(
|
||||
context: &BladeContext,
|
||||
hwnd: HWND,
|
||||
transparent: bool,
|
||||
) -> anyhow::Result<BladeRenderer> {
|
||||
let raw = RawWindow { hwnd };
|
||||
let config = BladeSurfaceConfig {
|
||||
size: Default::default(),
|
||||
transparent,
|
||||
};
|
||||
BladeRenderer::new(context, &raw, config)
|
||||
.inspect_err(|err| show_error("Failed to initialize BladeRenderer", err.to_string()))
|
||||
}
|
||||
|
||||
struct RawWindow {
|
||||
hwnd: HWND,
|
||||
}
|
||||
|
||||
impl rwh::HasWindowHandle for RawWindow {
|
||||
fn window_handle(&self) -> Result<rwh::WindowHandle<'_>, rwh::HandleError> {
|
||||
Ok(unsafe {
|
||||
let hwnd = NonZeroIsize::new_unchecked(self.hwnd.0 as isize);
|
||||
let mut handle = rwh::Win32WindowHandle::new(hwnd);
|
||||
let hinstance = get_window_long(self.hwnd, GWLP_HINSTANCE);
|
||||
handle.hinstance = NonZeroIsize::new(hinstance);
|
||||
rwh::WindowHandle::borrow_raw(handle.into())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl rwh::HasDisplayHandle for RawWindow {
|
||||
fn display_handle(&self) -> Result<rwh::DisplayHandle<'_>, rwh::HandleError> {
|
||||
let handle = rwh::WindowsDisplayHandle::new();
|
||||
Ok(unsafe { rwh::DisplayHandle::borrow_raw(handle.into()) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::ClickState;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue