Commit 2e852b236c45
tarball7 files changed+250-140
@@ -166,11 +166,30 @@ impl State {
166166
let mode = output.current_mode()?;167167
output.current_transform().transform_size(mode.size).into()168168
}169
- Target::Window(id) => self.wm.window(*id)?.geometry().size.into(),169
+ Target::Window(id) => {170
+ let size = self.wm.window(*id)?.geometry().size;171
+ size.to_physical_precise_round::<_, i32>(self.target_scale(target))172
+ .into()173
+ }170174
};171175
(size.0 > 0 && size.1 > 0).then_some(size)172176
}173177
178
+ /// An output's own scale, and a window's is the one of the output it is on.179
+ fn target_scale(&self, target: &Target) -> f64 {180
+ let output = match target {181
+ Target::Output(name) => self.output_named(name).map(|(_, output)| output),182
+ Target::Window(id) => self183
+ .wm184
+ .get(*id)185
+ .and_then(|s| s.placed)186
+ .map(|(_, _, o)| o)187
+ .or_else(|| self.wm.layout.window(*id)?.output)188
+ .and_then(|o| self.backend.output(o)),189
+ };190
+ output.map_or(1.0, |o| o.current_scale().fractional_scale())191
+ }192
+174193
fn constraints(&self, size: (i32, i32)) -> BufferConstraints {175194
let dma = self.backend.render_node().map(|node| {176195
let mut formats: Vec<(Fourcc, Vec<_>)> = Vec::new();@@ -203,6 +222,7 @@ impl State {
203222
frame.fail(CaptureFailureReason::BufferConstraints);204223
return;205224
}225
+ let scale = self.target_scale(&target);206226
let elements = match &target {207227
Target::Output(name) => {208228
let Some((o, output)) = self.output_named(name) else {@@ -225,7 +245,7 @@ impl State {
225245
}226246
Target::Window(id) => match self.wm.window(*id) {227247
Some(_) if self.services.lock.active() => Vec::new(),228
- Some(window) => window_elements(&mut self.renderer, window),248
+ Some(window) => window_elements(&mut self.renderer, window, scale),229249
None => {230250
frame.fail(CaptureFailureReason::Stopped);231251
return;@@ -234,8 +254,8 @@ impl State {
234254
};235255
let buffer = frame.buffer();236256
let result = match get_dmabuf(&buffer) {237
- Ok(dmabuf) => self.capture_dmabuf(dmabuf.clone(), size, &elements),238
- Err(_) => self.capture_shm(&buffer, size, &elements),257
+ Ok(dmabuf) => self.capture_dmabuf(dmabuf.clone(), size, scale, &elements),258
+ Err(_) => self.capture_shm(&buffer, size, scale, &elements),239259
};240260
match result {241261
Ok(()) => {@@ -253,10 +273,11 @@ impl State {
253273
&mut self,254274
mut dmabuf: Dmabuf,255275
size: (i32, i32),276
+ scale: f64,256277
elements: &[Draw],257278
) -> Result<(), Box<dyn std::error::Error>> {258279
let mut fb = self.renderer.bind(&mut dmabuf)?;259
- let mut tracker = OutputDamageTracker::new(size, 1.0, Transform::Normal);280
+ let mut tracker = OutputDamageTracker::new(size, scale, Transform::Normal);260281
let result = tracker.render_output(&mut self.renderer, &mut fb, 0, elements, CLEAR)?;261282
result.sync.wait()?;262283
Ok(())@@ -266,13 +287,14 @@ impl State {
266287
&mut self,267288
buffer: &WlBuffer,268289
size: (i32, i32),290
+ scale: f64,269291
elements: &[Draw],270292
) -> Result<(), Box<dyn std::error::Error>> {271293
let format = with_buffer_contents_mut(buffer, |_, _, data| data.format)?;272294
let fourcc = shm_format_to_fourcc(format).ok_or("unsupported shm format")?;273295
let mut image: VulkanImage = self.renderer.create_buffer(fourcc, size.into())?;274296
let mut fb = self.renderer.bind(&mut image)?;275
- let mut tracker = OutputDamageTracker::new(size, 1.0, Transform::Normal);297
+ let mut tracker = OutputDamageTracker::new(size, scale, Transform::Normal);276298
let result = tracker.render_output(&mut self.renderer, &mut fb, 0, elements, CLEAR)?;277299
result.sync.wait()?;278300
let region = Rectangle::from_size(Size::from(size));@@ -302,10 +324,18 @@ impl State {
302324
}303325
304326
/// A window alone, with its popups, its geometry at the origin.305
-fn window_elements(renderer: &mut VulkanRenderer, window: &smithay::desktop::Window) -> Vec<Draw> {306
- let at = Point::from((-window.geometry().loc.x, -window.geometry().loc.y));327
+fn window_elements(328
+ renderer: &mut VulkanRenderer,329
+ window: &smithay::desktop::Window,330
+ scale: f64,331
+) -> Vec<Draw> {332
+ let inset = window333
+ .geometry()334
+ .loc335
+ .to_physical_precise_round::<_, i32>(scale);336
+ let at = Point::from((-inset.x, -inset.y));307337
let elems: Vec<WaylandSurfaceRenderElement<VulkanRenderer>> =308
- window.render_elements(renderer, at, Scale::from(1.0), 1.0);338
+ window.render_elements(renderer, at, Scale::from(scale), 1.0);309339
elems.into_iter().map(Draw::Surface).collect()310340
}311341
@@ -1,7 +1,7 @@
11
//! The pointer image on bare metal, where nothing else draws one. A client22
//! cursor surface wins, otherwise the xcursor theme's default arrow.33
4
-use crate::scene::Draw;4
+use crate::scene::{Draw, to_physical};55
use monolith_render_vk::VulkanRenderer;66
use smithay::backend::allocator::Fourcc;77
use smithay::backend::renderer::element::memory::{@@ -87,10 +87,11 @@ impl Cursor {
8787
renderer: &mut VulkanRenderer,8888
status: &CursorImageStatus,8989
pos: Point<f64, Logical>,90
+ scale: f64,9091
) -> Vec<Draw> {9192
let at = |hotspot: Point<i32, Logical>| -> Point<i32, Physical> {9293
let p = pos - hotspot.to_f64();93
- (p.x.round() as i32, p.y.round() as i32).into()94
+ to_physical((p.x, p.y), scale)9495
};9596
match status {9697
CursorImageStatus::Hidden => Vec::new(),@@ -105,7 +106,7 @@ impl Cursor {
105106
renderer,106107
surface,107108
at(hotspot),108
- 1.0,109
+ scale,109110
1.0,110111
Kind::Cursor,111112
)@@ -162,13 +163,18 @@ pub struct DndIcon {
162163
163164
impl DndIcon {164165
/// Elements for the icon with the pointer at `pos`, in output-local coordinates.165
- pub fn elements(&self, renderer: &mut VulkanRenderer, pos: Point<f64, Logical>) -> Vec<Draw> {166
+ pub fn elements(167
+ &self,168
+ renderer: &mut VulkanRenderer,169
+ pos: Point<f64, Logical>,170
+ scale: f64,171
+ ) -> Vec<Draw> {166172
let p = pos + self.offset.to_f64();167173
render_elements_from_surface_tree(168174
renderer,169175
&self.surface,170
- (p.x.round() as i32, p.y.round() as i32),171
- 1.0,176
+ to_physical((p.x, p.y), scale),177
+ scale,172178
1.0,173179
Kind::Unspecified,174180
)@@ -38,6 +38,7 @@ pub fn compose(
3838
cursor: bool,3939
) -> Vec<Draw> {4040
let mut elements = Vec::new();41
+ let scale = output.current_scale().fractional_scale();4142
if let Some(area) = ctx.wm.layout.output(o).map(|out| out.area) {4243
let pos = ctx.input.pointer_pos;4344
if area.contains(pos.x, pos.y) {@@ -45,10 +46,14 @@ pub fn compose(
4546
if cursor {4647
let resize = ctx.input.resize_icon().map(CursorImageStatus::Named);4748
let status = resize.as_ref().unwrap_or(&ctx.input.cursor_status);48
- elements.extend(ctx.input.cursor.elements(ctx.renderer, status, local));49
+ elements.extend(50
+ ctx.input51
+ .cursor52
+ .elements(ctx.renderer, status, local, scale),53
+ );4954
}5055
if let Some(icon) = &ctx.input.dnd_icon {51
- elements.extend(icon.elements(ctx.renderer, local));56
+ elements.extend(icon.elements(ctx.renderer, local, scale));5257
}5358
}5459
}@@ -1,7 +1,7 @@
11
//! wlr-layer-shell, for bars, launchers, wallpapers and notifications.22
33
use crate::focus::Focus;4
-use crate::scene::Draw;4
+use crate::scene::{Draw, to_physical};55
use crate::state::State;66
use monolith_layout::{Insets, OutputId};77
use monolith_render_vk::VulkanRenderer;@@ -255,24 +255,25 @@ impl State {
255255
256256
/// Draws an output's layer surfaces on `layer`, front to back.257257
pub fn elements(out: &mut Vec<Draw>, renderer: &mut VulkanRenderer, output: &Output, layer: Layer) {258
+ let scale = output.current_scale().fractional_scale();258259
let map = layer_map_for_output(output);259260
for l in map.layers_on(layer).rev() {260261
let Some(geo) = map.layer_geometry(l) else {261262
continue;262263
};263
- let at = geo.loc.to_physical(1);264
+ let at = to_physical((geo.loc.x.into(), geo.loc.y.into()), scale);264265
let elems: Vec<WaylandSurfaceRenderElement<VulkanRenderer>> =265266
if matches!(layer, Layer::Bottom | Layer::Background) {266267
render_elements_from_surface_tree(267268
renderer,268269
l.wl_surface(),269270
at,270
- 1.0,271
+ scale,271272
1.0,272273
Kind::Unspecified,273274
)274275
} else {275
- l.render_elements(renderer, at, Scale::from(1.0), 1.0)276
+ l.render_elements(renderer, at, Scale::from(scale), 1.0)276277
};277278
out.extend(elems.into_iter().map(Draw::Surface));278279
}@@ -281,11 +282,13 @@ pub fn elements(out: &mut Vec<Draw>, renderer: &mut VulkanRenderer, output: &Out
281282
/// The popups of the layer surfaces below the windows. Those surfaces draw282283
/// without them, so a menu is not hidden by the window it opens over.283284
pub fn lower_popups(out: &mut Vec<Draw>, renderer: &mut VulkanRenderer, output: &Output) {285
+ let scale = output.current_scale().fractional_scale();284286
let map = layer_map_for_output(output);285287
for layer in [Layer::Bottom, Layer::Background] {286288
for l in map.layers_on(layer).rev() {287289
if let Some(geo) = map.layer_geometry(l) {288
- crate::popups::elements(out, renderer, l.wl_surface(), geo.loc, 1.0);290
+ let at = to_physical((geo.loc.x.into(), geo.loc.y.into()), scale);291
+ crate::popups::elements(out, renderer, l.wl_surface(), at, scale, 1.0);289292
}290293
}291294
}@@ -176,7 +176,7 @@ pub fn elements(lock: &Lock, renderer: &mut VulkanRenderer, output: &Output) ->
176176
renderer,177177
surface.wl_surface(),178178
(0, 0),179
- 1.0,179
+ output.current_scale().fractional_scale(),180180
1.0,181181
Kind::Unspecified,182182
)@@ -128,13 +128,15 @@ pub fn placed(
128128
root: &WlSurface,129129
geometry_at: Point<i32, Logical>,130130
) -> Vec<(WlSurface, Point<i32, Logical>)> {131
+ offsets(root)132
+ .into_iter()133
+ .map(|(popup, at)| (popup, geometry_at + at))134
+ .collect()135
+}136
+137
+fn offsets(root: &WlSurface) -> Vec<(WlSurface, Point<i32, Logical>)> {131138
PopupManager::popups_for_surface(root)132
- .map(|(popup, at)| {133
- (134
- popup.wl_surface().clone(),135
- geometry_at + at - popup.geometry().loc,136
- )137
- })139
+ .map(|(popup, at)| (popup.wl_surface().clone(), at - popup.geometry().loc))138140
.collect()139141
}140142
@@ -150,20 +152,28 @@ pub fn hit(
150152
})151153
}152154
153
-/// Draws `root`'s popups with its window geometry at `geometry_at`.155
+/// Draws `root`'s popups with its window geometry at `geometry_at` pixels.154156
pub fn elements(155157
out: &mut Vec<Draw>,156158
renderer: &mut VulkanRenderer,157159
root: &WlSurface,158
- geometry_at: Point<i32, Logical>,160
+ geometry_at: Point<i32, Physical>,161
+ scale: f64,159162
alpha: f32,160163
) {161
- for (popup, at) in placed(root, geometry_at) {162
- let at = Point::<i32, Physical>::from((at.x, at.y));164
+ for (popup, offset) in offsets(root) {165
+ let at = geometry_at + crate::scene::to_physical((offset.x.into(), offset.y.into()), scale);163166
out.extend(164
- render_elements_from_surface_tree(renderer, &popup, at, 1.0, alpha, Kind::Unspecified)165
- .into_iter()166
- .map(Draw::Surface),167
+ render_elements_from_surface_tree(168
+ renderer,169
+ &popup,170
+ at,171
+ scale,172
+ alpha,173
+ Kind::Unspecified,174
+ )175
+ .into_iter()176
+ .map(Draw::Surface),167177
);168178
}169179
}@@ -9,12 +9,11 @@ use smithay::backend::renderer::element::memory::MemoryRenderBufferRenderElement
99
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};1010
use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement;1111
use smithay::backend::renderer::element::surface::render_elements_from_surface_tree;12
-use smithay::backend::renderer::element::texture::TextureRenderElement;1312
use smithay::backend::renderer::element::utils::{CropRenderElement, RescaleRenderElement};1413
use smithay::backend::renderer::element::{AsRenderElements, Element, Id, Kind, RenderElement};1514
use smithay::backend::renderer::utils::with_renderer_surface_state;1615
use smithay::backend::renderer::utils::{CommitCounter, DamageSet, OpaqueRegions};17
-use smithay::backend::renderer::{ContextId, Renderer, Texture};16
+use smithay::backend::renderer::{Frame, Renderer, Texture};1817
use smithay::desktop::Window;1918
use smithay::output::Output;2019
use smithay::utils::user_data::UserDataMap;@@ -26,8 +25,7 @@ smithay::backend::renderer::element::render_elements! {
2625
pub Draw<=VulkanRenderer>;2726
Surface=WaylandSurfaceRenderElement<VulkanRenderer>,2827
Cropped=CropRenderElement<WaylandSurfaceRenderElement<VulkanRenderer>>,29
- Texture=TextureRenderElement<VulkanTexture>,30
- Effect=EffectElement,28
+ Texture=PlacedTexture,3129
Border=SolidColorRenderElement,3230
Memory=MemoryRenderBufferRenderElement<VulkanRenderer>,3331
Rescaled=RescaleRenderElement<WaylandSurfaceRenderElement<VulkanRenderer>>,@@ -54,6 +52,7 @@ pub fn build(
5452
let Some(area) = layout.output(o).map(|out| out.area) else {5553
return Vec::new();5654
};55
+ let scale = output.map_or(1.0, |o| o.current_scale().fractional_scale());5756
let local = |r: Rect| Rect::new(r.x - area.x, r.y - area.y, r.w, r.h);5857
let mut ghosts = Vec::new();5958
let mut tiled = Vec::new();@@ -107,11 +106,21 @@ pub fn build(
107106
continue;108107
};109108
let loc = x.geometry().loc;110
- let at = Point::<i32, Physical>::from((loc.x - area.x as i32, loc.y - area.y as i32));109
+ let at = to_physical(110
+ (f64::from(loc.x) - area.x, f64::from(loc.y) - area.y),111
+ scale,112
+ );111113
out.extend(112
- render_elements_from_surface_tree(renderer, &surface, at, 1.0, 1.0, Kind::Unspecified)113
- .into_iter()114
- .map(Draw::Surface),114
+ render_elements_from_surface_tree(115
+ renderer,116
+ &surface,117
+ at,118
+ scale,119
+ 1.0,120
+ Kind::Unspecified,121
+ )122
+ .into_iter()123
+ .map(Draw::Surface),115124
);116125
}117126
if let Some(output) = output {@@ -128,11 +137,18 @@ pub fn build(
128137
let Some(root) = windows.get(id).and_then(|s| s.window.toplevel()) else {129138
continue;130139
};131
- let Some(((x, y), _)) = pixels(r) else {140
+ let Some(((x, y), _)) = pixels(r, scale) else {132141
continue;133142
};134143
let alpha = anim.effect(id, now).map_or(1.0, |e| e.progress);135
- crate::popups::elements(&mut out, renderer, root.wl_surface(), (x, y).into(), alpha);144
+ crate::popups::elements(145
+ &mut out,146
+ renderer,147
+ root.wl_surface(),148
+ (x, y).into(),149
+ scale,150
+ alpha,151
+ );136152
}137153
if let Some(output) = output138154
&& !fullscreen_at_rest@@ -140,7 +156,13 @@ pub fn build(
140156
crate::layers::lower_popups(&mut out, renderer, output);141157
}142158
for (g, frame, r) in fading.into_iter().rev() {143
- out.extend(ghost_element(frame, r, anim.ghost_effect(g, now), deco));159
+ out.extend(ghost_element(160
+ frame,161
+ r,162
+ anim.ghost_effect(g, now),163
+ deco,164
+ scale,165
+ ));144166
}145167
for (id, r, framed, gliding) in tiled.into_iter().chain(above).rev() {146168
let Some(state) = windows.get_mut(id) else {@@ -148,8 +170,8 @@ pub fn build(
148170
};149171
let effect = anim.effect(id, now);150172
let first = out.len();151
- window_elements(&mut out, renderer, &state.window, r, effect, gliding);152
- let clip = framed.then(|| corner_clip(r, deco)).flatten();173
+ window_elements(&mut out, renderer, &state.window, r, effect, gliding, scale);174
+ let clip = framed.then(|| corner_clip(r, deco, scale)).flatten();153175
if let Some(clip) = clip {154176
clip_window(&mut out, first, clip);155177
}@@ -164,14 +186,20 @@ pub fn build(
164186
let alpha = effect.map_or(1.0, |e| e.progress);165187
let borders = &mut state.borders;166188
let first = out.len();167
- border_elements(&mut out, borders, r, deco, color, alpha);189
+ border_elements(&mut out, borders, r, deco, color, alpha, scale);168190
if let Some(clip) = clip {169
- ring_borders(&mut out, first, clip, deco.border as i32);191
+ ring_borders(&mut out, first, clip, border_width(deco, scale));170192
}171193
}172194
}173195
for (g, frame, r) in ghosts.into_iter().rev() {174
- out.extend(ghost_element(frame, r, anim.ghost_effect(g, now), deco));196
+ out.extend(ghost_element(197
+ frame,198
+ r,199
+ anim.ghost_effect(g, now),200
+ deco,201
+ scale,202
+ ));175203
}176204
if let Some(output) = output {177205
crate::layers::elements(&mut out, renderer, output, Layer::Bottom);@@ -191,42 +219,53 @@ fn window_elements(
191219
r: Rect,192220
effect: Option<Effect>,193221
scaled: bool,222
+ scale: f64,194223
) {195
- let Some(((x, y), (w, h))) = pixels(r) else {224
+ let Some(((x, y), (w, h))) = pixels(r, scale) else {196225
return;197226
};198227
let geo = window.geometry();199
- let loc = Point::<i32, Physical>::from((x - geo.loc.x, y - geo.loc.y));228
+ let inset = geo.loc.to_physical_precise_round::<_, i32>(scale);229
+ let drawn: Size<i32, Physical> = geo.size.to_physical_precise_round(scale);230
+ let loc = Point::<i32, Physical>::from((x - inset.x, y - inset.y));200231
let alpha = effect.map_or(1.0, |e| e.progress);201232
let elems: Vec<WaylandSurfaceRenderElement<VulkanRenderer>> = match window.toplevel() {202233
Some(t) => render_elements_from_surface_tree(203234
renderer,204235
t.wl_surface(),205236
loc,206
- 1.0,237
+ scale,207238
alpha,208239
Kind::Unspecified,209240
),210
- None => window.render_elements(renderer, loc, Scale::from(1.0), alpha),241
+ None => window.render_elements(renderer, loc, Scale::from(scale), alpha),211242
};212243
if let Some(effect) = effect {213
- effect_elements(out, renderer, window, elems, ((x, y), (w, h)), effect);244
+ effect_elements(245
+ out,246
+ renderer,247
+ window,248
+ elems,249
+ ((x, y), (w, h)),250
+ effect,251
+ scale,252
+ );214253
return;215254
}216
- if scaled && geo.size.w > 0 && geo.size.h > 0 {217
- let scale = Scale::from((218
- f64::from(w) / f64::from(geo.size.w),219
- f64::from(h) / f64::from(geo.size.h),255
+ if scaled && drawn.w > 0 && drawn.h > 0 {256
+ let factor = Scale::from((257
+ f64::from(w) / f64::from(drawn.w),258
+ f64::from(h) / f64::from(drawn.h),220259
));221260
let origin = Point::<i32, Physical>::from((x, y));222261
out.extend(223262
elems224263
.into_iter()225
- .map(|e| Draw::Rescaled(RescaleRenderElement::from_element(e, origin, scale))),264
+ .map(|e| Draw::Rescaled(RescaleRenderElement::from_element(e, origin, factor))),226265
);227266
return;228267
}229
- if (w, h) == (geo.size.w, geo.size.h) {268
+ if (w, h) == (drawn.w, drawn.h) {230269
out.extend(elems.into_iter().map(Draw::Surface));231270
return;232271
}@@ -234,14 +273,14 @@ fn window_elements(
234273
out.extend(235274
elems236275
.into_iter()237
- .filter_map(|e| CropRenderElement::from_element(e, 1.0, crop))276
+ .filter_map(|e| CropRenderElement::from_element(e, scale, crop))238277
.map(Draw::Cropped),239278
);240279
let Some(root) = crate::wm::root(window) else {241280
return;242281
};243282
let context = renderer.context_id();244
- let Some((tex, scale, transform)) = with_renderer_surface_state(&root, |s| {283
+ let Some((tex, buffer_scale, transform)) = with_renderer_surface_state(&root, |s| {245284
s.texture::<VulkanTexture>(context.clone())246285
.cloned()247286
.map(|t| (t, s.buffer_scale(), s.buffer_transform()))@@ -249,28 +288,33 @@ fn window_elements(
249288
.flatten() else {250289
return;251290
};252
- let (gw, gh) = (geo.size.w, geo.size.h);291
+ let (gw, gh) = (drawn.w, drawn.h);253292
let (cw, ch) = (w.min(gw), h.min(gh));254
- let (gx, gy) = (geo.loc.x as f64, geo.loc.y as f64);293
+ let (gx, gy) = (f64::from(geo.loc.x), f64::from(geo.loc.y));255294
let mut strip = |src: Rectangle<f64, Logical>, at: (i32, i32), size: (i32, i32)| {256295
if size.0 >= 1 && size.1 >= 1 {257
- out.push(texture(&context, &tex, scale, transform, src, at, size));296
+ let bounds = tex.size().to_logical(buffer_scale, transform).to_f64();297
+ let src = src.to_buffer(f64::from(buffer_scale), transform, &bounds);298
+ out.push(Draw::Texture(PlacedTexture::new(299
+ &tex, transform, src, at, size, None,300
+ )));258301
}259302
};260
- let right = gx + f64::from(gw) - 1.0;261
- let bottom = gy + f64::from(gh) - 1.0;303
+ let pixel = 1.0 / f64::from(buffer_scale);304
+ let right = gx + f64::from(geo.size.w) - pixel;305
+ let bottom = gy + f64::from(geo.size.h) - pixel;262306
strip(263
- Rectangle::new((right, gy).into(), (1.0, f64::from(ch)).into()),307
+ Rectangle::new((right, gy).into(), (pixel, f64::from(ch) / scale).into()),264308
(x + gw, y),265309
(w - gw, ch),266310
);267311
strip(268
- Rectangle::new((gx, bottom).into(), (f64::from(cw), 1.0).into()),312
+ Rectangle::new((gx, bottom).into(), (f64::from(cw) / scale, pixel).into()),269313
(x, y + gh),270314
(cw, h - gh),271315
);272316
strip(273
- Rectangle::new((right, bottom).into(), (1.0, 1.0).into()),317
+ Rectangle::new((right, bottom).into(), (pixel, pixel).into()),274318
(x + gw, y + gh),275319
(w - gw, h - gh),276320
);@@ -286,12 +330,13 @@ fn border_elements(
286330
deco: &Decoration,287331
color: [f32; 4],288332
alpha: f32,333
+ scale: f64,289334
) {290
- let Some(((x, y), (w, h))) = pixels(r) else {335
+ let Some(((x, y), (w, h))) = pixels(r, scale) else {291336
return;292337
};293
- let b = deco.border as i32;294
- let reach = deco.radius.0.into_iter().max().unwrap_or(0) as i32;338
+ let b = border_width(deco, scale);339
+ let reach = (f64::from(deco.radius.0.into_iter().max().unwrap_or(0)) * scale).round() as i32;295340
let reach = reach.min(w / 2).min(h / 2);296341
let strips = [297342
((x - b, y - b), (w + 2 * b, b + reach)),@@ -313,37 +358,25 @@ fn border_elements(
313358
}314359
}315360
316
-/// Snaps a logical rect to whole pixels by rounding its edges, so neighbours317
-/// that share an edge stay flush.318
-fn pixels(r: Rect) -> Option<((i32, i32), (i32, i32))> {319
- let (x, y) = (r.x.round() as i32, r.y.round() as i32);320
- let w = r.right().round() as i32 - x;321
- let h = r.bottom().round() as i32 - y;361
+/// Snaps a logical rect to whole physical pixels by rounding its edges, so362
+/// neighbours that share an edge stay flush.363
+fn pixels(r: Rect, scale: f64) -> Option<((i32, i32), (i32, i32))> {364
+ let (x, y) = ((r.x * scale).round() as i32, (r.y * scale).round() as i32);365
+ let w = (r.right() * scale).round() as i32 - x;366
+ let h = (r.bottom() * scale).round() as i32 - y;322367
(w >= 1 && h >= 1).then_some(((x, y), (w, h)))323368
}324369
325
-fn texture(326
- context: &ContextId<VulkanTexture>,327
- texture: &VulkanTexture,328
- scale: i32,329
- transform: Transform,330
- src: Rectangle<f64, Logical>,331
- at: (i32, i32),332
- size: (i32, i32),333
-) -> Draw {334
- Draw::Texture(TextureRenderElement::from_static_texture(335
- Id::new(),336
- context.clone(),337
- Point::<f64, Physical>::from((f64::from(at.0), f64::from(at.1))),338
- texture.clone(),339
- scale,340
- transform,341
- None,342
- Some(src),343
- Some(Size::from(size)),344
- None,345
- Kind::Unspecified,346
- ))370
+pub fn to_physical(p: (f64, f64), scale: f64) -> Point<i32, Physical> {371
+ ((p.0 * scale).round() as i32, (p.1 * scale).round() as i32).into()372
+}373
+374
+/// The border width in physical pixels, the same on every side of a window.375
+fn border_width(deco: &Decoration, scale: f64) -> i32 {376
+ match deco.border {377
+ 0 => 0,378
+ b => ((f64::from(b) * scale).round() as i32).max(1),379
+ }347380
}348381
349382
/// A window in a spawn transition. Its root surface goes through the effect@@ -355,6 +388,7 @@ fn effect_elements(
355388
elems: Vec<WaylandSurfaceRenderElement<VulkanRenderer>>,356389
(at, size): ((i32, i32), (i32, i32)),357390
effect: Effect,391
+ scale: f64,358392
) {359393
let Some(root) = crate::wm::root(window) else {360394
return;@@ -372,46 +406,52 @@ fn effect_elements(
372406
elems373407
.into_iter()374408
.filter(|e| root_tex.is_none() || *e.id() != root_id)375
- .filter_map(|e| CropRenderElement::from_element(e, 1.0, crop))409
+ .filter_map(|e| CropRenderElement::from_element(e, scale, crop))376410
.map(Draw::Cropped),377411
);378
- if let Some((tex, scale, transform)) = root_tex {412
+ if let Some((tex, buffer_scale, transform)) = root_tex {379413
let geo = window.geometry();380414
let src = Rectangle::new(381415
geo.loc.to_f64(),382
- (f64::from(size.0), f64::from(size.1)).into(),416
+ (f64::from(size.0) / scale, f64::from(size.1) / scale).into(),383417
);384
- out.push(Draw::Effect(EffectElement::new(385
- &tex, scale, transform, src, at, size, effect,418
+ let bounds = tex.size().to_logical(buffer_scale, transform).to_f64();419
+ let src = src.to_buffer(f64::from(buffer_scale), transform, &bounds);420
+ out.push(Draw::Texture(PlacedTexture::new(421
+ &tex,422
+ transform,423
+ src,424
+ at,425
+ size,426
+ Some(effect),386427
)));387428
}388429
}389430
390
-/// A texture drawn through the transition hook in the effect shader.391
-pub struct EffectElement {431
+/// A texture at a physical rectangle, drawn plainly or through the432
+/// transition hook in the effect shader.433
+pub struct PlacedTexture {392434
id: Id,393435
texture: VulkanTexture,394436
src: Rectangle<f64, Buffer>,395437
geometry: Rectangle<i32, Physical>,396438
transform: Transform,397
- effect: Effect,439
+ effect: Option<Effect>,398440
}399441
400
-impl EffectElement {442
+impl PlacedTexture {401443
fn new(402444
texture: &VulkanTexture,403
- scale: i32,404445
transform: Transform,405
- src: Rectangle<f64, Logical>,446
+ src: Rectangle<f64, Buffer>,406447
at: (i32, i32),407448
size: (i32, i32),408
- effect: Effect,449
+ effect: Option<Effect>,409450
) -> Self {410
- let bounds = texture.size().to_logical(scale, transform).to_f64();411451
Self {412452
id: Id::new(),413453
texture: texture.clone(),414
- src: src.to_buffer(f64::from(scale), transform, &bounds),454
+ src,415455
geometry: Rectangle::new(at.into(), size.into()),416456
transform,417457
effect,@@ -419,7 +459,7 @@ impl EffectElement {
419459
}420460
}421461
422
-impl Element for EffectElement {462
+impl Element for PlacedTexture {423463
fn id(&self) -> &Id {424464
&self.id425465
}@@ -441,59 +481,75 @@ impl Element for EffectElement {
441481
}442482
}443483
444
-impl RenderElement<VulkanRenderer> for EffectElement {484
+impl RenderElement<VulkanRenderer> for PlacedTexture {445485
fn draw(446486
&self,447487
frame: &mut VulkanFrame<'_, '_>,448488
src: Rectangle<f64, Buffer>,449489
dst: Rectangle<i32, Physical>,450490
damage: &[Rectangle<i32, Physical>],451
- _opaque_regions: &[Rectangle<i32, Physical>],491
+ opaque_regions: &[Rectangle<i32, Physical>],452492
_cache: Option<&UserDataMap>,453493
) -> Result<(), monolith_render_vk::Error> {454
- frame.render_effect(455
- &self.texture,456
- src,457
- dst,458
- damage,459
- self.transform,460
- 1.0,461
- self.effect,462
- )494
+ match self.effect {495
+ Some(effect) => {496
+ frame.render_effect(&self.texture, src, dst, damage, self.transform, 1.0, effect)497
+ }498
+ None => frame.render_texture_from_to(499
+ &self.texture,500
+ src,501
+ dst,502
+ damage,503
+ opaque_regions,504
+ self.transform,505
+ 1.0,506
+ ),507
+ }463508
}464509
}465510
466
-fn ghost_element(frame: &LastFrame, r: Rect, effect: Effect, deco: &Decoration) -> Option<Draw> {467
- let (at, size) = pixels(r)?;511
+fn ghost_element(512
+ frame: &LastFrame,513
+ r: Rect,514
+ effect: Effect,515
+ deco: &Decoration,516
+ scale: f64,517
+) -> Option<Draw> {518
+ let (at, size) = pixels(r, scale)?;468519
let src = Rectangle::new(469520
frame.geometry.loc.to_f64(),470
- (f64::from(size.0), f64::from(size.1)).into(),521
+ (f64::from(size.0) / scale, f64::from(size.1) / scale).into(),471522
);472
- let ghost = Draw::Effect(EffectElement::new(523
+ let bounds = frame524
+ .texture525
+ .size()526
+ .to_logical(frame.scale, frame.transform)527
+ .to_f64();528
+ let src = src.to_buffer(f64::from(frame.scale), frame.transform, &bounds);529
+ let ghost = Draw::Texture(PlacedTexture::new(473530
&frame.texture,474
- frame.scale,475531
frame.transform,476532
src,477533
at,478534
size,479
- effect,535
+ Some(effect),480536
));481
- Some(match corner_clip(r, deco) {537
+ Some(match corner_clip(r, deco, scale) {482538
Some(clip) => Draw::Clipped(ClipElement::new(ghost, clip)),483539
None => ghost,484540
})485541
}486542
487543
/// The rounded outline of a framed window at `r`, if it has one.488
-fn corner_clip(r: Rect, deco: &Decoration) -> Option<Clip> {544
+fn corner_clip(r: Rect, deco: &Decoration, scale: f64) -> Option<Clip> {489545
let radii = deco.radius.0;490546
if radii == [0; 4] {491547
return None;492548
}493
- let (at, size) = pixels(r)?;549
+ let (at, size) = pixels(r, scale)?;494550
Some(Clip {495551
rect: Rectangle::new(at.into(), size.into()),496
- radii: radii.map(|r| r as f32),552
+ radii: radii.map(|r| r as f32 * scale as f32),497553
ring: 0.0,498554
})499555
}