mirror of https://github.com/wayvr-org/wayvr.git
subsurfaces use srgb
This commit is contained in:
parent
8b873060b7
commit
0e69eec769
|
|
@ -2,7 +2,13 @@ use glam::{Affine2, Affine3A, Quat, Vec2, Vec3, vec2, vec3};
|
|||
use smithay::{
|
||||
desktop::PopupManager,
|
||||
reexports::wayland_server::{Resource, backend::ObjectId, protocol::wl_surface::WlSurface},
|
||||
wayland::{compositor::with_states, shell::xdg::XdgPopupSurfaceData},
|
||||
utils::{Logical, Point},
|
||||
wayland::{
|
||||
compositor::{
|
||||
SubsurfaceCachedState, TraversalAction, with_states, with_surface_tree_upward,
|
||||
},
|
||||
shell::xdg::XdgPopupSurfaceData,
|
||||
},
|
||||
};
|
||||
use std::{mem, ops::RangeInclusive, sync::Arc};
|
||||
use vulkano::{
|
||||
|
|
@ -102,21 +108,25 @@ pub fn create_wl_window_overlay(
|
|||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct RenderedPopup {
|
||||
struct RenderedSurface {
|
||||
surface: WlSurface,
|
||||
surface_id: ObjectId,
|
||||
image: Arc<ImageView>,
|
||||
pos: Vec2,
|
||||
size: Vec2,
|
||||
dmabuf: bool,
|
||||
}
|
||||
|
||||
enum WvrHitTarget {
|
||||
Panel(input::PointerHit),
|
||||
|
||||
Toplevel {
|
||||
pos: Vec2,
|
||||
},
|
||||
|
||||
Surface {
|
||||
surface: WlSurface,
|
||||
global_pos: Vec2,
|
||||
surface_origin: Vec2,
|
||||
},
|
||||
Popup {
|
||||
surface: WlSurface,
|
||||
global_pos: Vec2,
|
||||
|
|
@ -128,11 +138,12 @@ pub struct WvrWindowBackend {
|
|||
name: Arc<str>,
|
||||
icon: Arc<str>,
|
||||
pipeline: Option<ScreenPipeline>,
|
||||
popups_pipeline: Arc<WGfxPipeline<Vert2Uv>>,
|
||||
subsurface_pipeline: Arc<WGfxPipeline<Vert2Uv>>,
|
||||
popup_outside_button: Option<wayvr::MouseIndex>,
|
||||
interaction_transform: Option<Affine2>,
|
||||
window: WindowHandle,
|
||||
popups: Vec<RenderedPopup>,
|
||||
popups: Vec<RenderedSurface>,
|
||||
surfaces: Vec<RenderedSurface>,
|
||||
just_resumed: bool,
|
||||
meta: Option<FrameMeta>,
|
||||
mouse: Option<MouseMeta>,
|
||||
|
|
@ -154,7 +165,7 @@ impl WvrWindowBackend {
|
|||
window: wayvr::window::WindowHandle,
|
||||
icon: Arc<str>,
|
||||
) -> anyhow::Result<Self> {
|
||||
let popups_pipeline = app.gfx.create_pipeline(
|
||||
let subsurface_pipeline = app.gfx.create_pipeline(
|
||||
app.gfx_extras.shaders.get("vert_quad").unwrap(), // want panic
|
||||
app.gfx_extras.shaders.get("frag_simple").unwrap(), // want panic
|
||||
WPipelineCreateInfo::new(app.gfx.surface_format).use_blend(AttachmentBlend::alpha()),
|
||||
|
|
@ -230,7 +241,8 @@ impl WvrWindowBackend {
|
|||
pipeline: None,
|
||||
window,
|
||||
popups: vec![],
|
||||
popups_pipeline,
|
||||
surfaces: vec![],
|
||||
subsurface_pipeline,
|
||||
popup_outside_button: None,
|
||||
interaction_transform: None,
|
||||
just_resumed: false,
|
||||
|
|
@ -342,8 +354,7 @@ impl WvrWindowBackend {
|
|||
let transformed = self.transformed_uv_from_hit(hit);
|
||||
let client_pos = self.client_pos_from_transformed_uv(transformed);
|
||||
|
||||
// Important: popups are checked before the panel/client bounds.
|
||||
// Real xdg_popups may extend outside the parent toplevel rect.
|
||||
// popups are checked before the panel/client bounds.
|
||||
if let Some((surface, surface_origin)) = self.popup_hit_at_client_pos(client_pos) {
|
||||
return Some(WvrHitTarget::Popup {
|
||||
surface,
|
||||
|
|
@ -356,6 +367,20 @@ impl WvrWindowBackend {
|
|||
return self.panel_hit_from_hit(hit).map(WvrHitTarget::Panel);
|
||||
}
|
||||
|
||||
let hit_surface = self.surfaces.iter().rev().find(|s| {
|
||||
let local = client_pos - s.pos;
|
||||
|
||||
local.x >= 0.0 && local.y >= 0.0 && local.x < s.size.x && local.y < s.size.y
|
||||
});
|
||||
|
||||
if let Some(surface) = hit_surface {
|
||||
return Some(WvrHitTarget::Surface {
|
||||
surface: surface.surface.clone(),
|
||||
global_pos: client_pos,
|
||||
surface_origin: surface.pos,
|
||||
});
|
||||
}
|
||||
|
||||
let clamped = transformed.clamp(Vec2::ZERO, Vec2::ONE);
|
||||
let pos = self.client_pos_from_transformed_uv(clamped);
|
||||
|
||||
|
|
@ -370,6 +395,50 @@ impl WvrWindowBackend {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn render_subsurface(
|
||||
&self,
|
||||
app: &mut AppState,
|
||||
rdr: &mut RenderResources,
|
||||
s: &RenderedSurface,
|
||||
) -> anyhow::Result<()> {
|
||||
let meta = self.meta.as_ref().unwrap();
|
||||
let extentf = [meta.extent[0] as f32, meta.extent[1] as f32];
|
||||
|
||||
let mut buf_vert = app
|
||||
.gfx
|
||||
.empty_buffer(BufferUsage::TRANSFER_DST | BufferUsage::VERTEX_BUFFER, 4)?;
|
||||
|
||||
upload_quad_vertices(
|
||||
&mut buf_vert,
|
||||
extentf[0],
|
||||
extentf[1],
|
||||
s.pos.x,
|
||||
s.pos.y,
|
||||
s.size.x,
|
||||
s.size.y,
|
||||
)?;
|
||||
|
||||
let set0 =
|
||||
self.subsurface_pipeline
|
||||
.uniform_sampler(0, s.image.clone(), app.gfx.texture_filter)?;
|
||||
|
||||
let pass = self.subsurface_pipeline.create_pass(
|
||||
extentf,
|
||||
[BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _],
|
||||
buf_vert,
|
||||
0..4,
|
||||
0..1,
|
||||
vec![set0],
|
||||
&Default::default(),
|
||||
)?;
|
||||
|
||||
for buf in &mut rdr.cmd_bufs {
|
||||
buf.run_ref(&pass)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl OverlayBackend for WvrWindowBackend {
|
||||
|
|
@ -388,8 +457,6 @@ impl OverlayBackend for WvrWindowBackend {
|
|||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn should_render(&mut self, app: &mut AppState) -> anyhow::Result<ShouldRender> {
|
||||
let should_render_panel = self.panel.should_render(app)?;
|
||||
|
||||
let Some(toplevel) = app
|
||||
.wvr_server
|
||||
.as_ref()
|
||||
|
|
@ -403,15 +470,34 @@ impl OverlayBackend for WvrWindowBackend {
|
|||
return Ok(ShouldRender::Unable);
|
||||
};
|
||||
|
||||
let surface_id = toplevel.wl_surface().id();
|
||||
let has_pending_callbacks = app
|
||||
.wvr_server
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.manager
|
||||
.state
|
||||
.has_pending_frame_callbacks(surface_id);
|
||||
let force_render = mem::take(&mut self.just_resumed) | has_pending_callbacks;
|
||||
let surfaces = collect_rendered_surface_tree(toplevel.wl_surface());
|
||||
|
||||
let has_pending_callbacks = surfaces.iter().any(|s| {
|
||||
app.wvr_server
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.manager
|
||||
.state
|
||||
.has_pending_frame_callbacks(s.surface_id.clone())
|
||||
});
|
||||
|
||||
let subtree_dirty = rendered_surfaces_dirty(&self.surfaces, &surfaces)
|
||||
|| surfaces.iter().any(|s| {
|
||||
app.wvr_server
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.manager
|
||||
.state
|
||||
.redraw_requests
|
||||
.contains(&s.surface_id)
|
||||
});
|
||||
|
||||
self.surfaces = surfaces;
|
||||
|
||||
let should_render_panel = self.panel.should_render(app)?;
|
||||
|
||||
let force_render =
|
||||
has_pending_callbacks || subtree_dirty || mem::take(&mut self.just_resumed);
|
||||
|
||||
let popups = PopupManager::popups_for_surface(toplevel.wl_surface())
|
||||
.filter_map(|(popup, point)| {
|
||||
|
|
@ -432,12 +518,13 @@ impl OverlayBackend for WvrWindowBackend {
|
|||
let image = surf.image;
|
||||
let size = image.extent_f32();
|
||||
|
||||
Some(RenderedPopup {
|
||||
Some(RenderedSurface {
|
||||
surface: popup.wl_surface().clone(),
|
||||
surface_id: popup.wl_surface().id(),
|
||||
image,
|
||||
pos: vec2(point.x as _, point.y as _),
|
||||
size: vec2(size[0], size[1]),
|
||||
dmabuf: false,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
|
@ -511,7 +598,7 @@ impl OverlayBackend for WvrWindowBackend {
|
|||
y: (m.y as f32) / (inner_extent[1] as f32),
|
||||
});
|
||||
|
||||
let dirty = self.mouse != mouse || rendered_popups_dirty(&self.popups, &popups);
|
||||
let dirty = self.mouse != mouse || rendered_surfaces_dirty(&self.popups, &popups);
|
||||
self.mouse = mouse;
|
||||
self.popups = popups;
|
||||
self.meta = Some(meta);
|
||||
|
|
@ -559,64 +646,35 @@ impl OverlayBackend for WvrWindowBackend {
|
|||
}
|
||||
|
||||
let image = self.cur_image.as_ref().unwrap().clone();
|
||||
let mut callback_surfaces = Vec::with_capacity(self.surfaces.len() + self.popups.len());
|
||||
|
||||
self.pipeline
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.render(image, self.mouse.as_ref(), app, rdr)?;
|
||||
|
||||
for popup in &self.popups {
|
||||
let meta = self.meta.as_ref().unwrap();
|
||||
let extentf = [meta.extent[0] as f32, meta.extent[1] as f32];
|
||||
|
||||
let mut buf_vert = app
|
||||
.gfx
|
||||
.empty_buffer(BufferUsage::TRANSFER_DST | BufferUsage::VERTEX_BUFFER, 4)?;
|
||||
|
||||
upload_quad_vertices(
|
||||
&mut buf_vert,
|
||||
extentf[0],
|
||||
extentf[1],
|
||||
popup.pos.x,
|
||||
popup.pos.y,
|
||||
popup.size.x,
|
||||
popup.size.y,
|
||||
)?;
|
||||
|
||||
let set0 = self.popups_pipeline.uniform_sampler(
|
||||
0,
|
||||
popup.image.clone(),
|
||||
app.gfx.texture_filter,
|
||||
)?;
|
||||
let pass = self.popups_pipeline.create_pass(
|
||||
extentf,
|
||||
[BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _],
|
||||
buf_vert,
|
||||
0..4,
|
||||
0..1,
|
||||
vec![set0],
|
||||
&Default::default(),
|
||||
)?;
|
||||
|
||||
for buf in &mut rdr.cmd_bufs {
|
||||
buf.run_ref(&pass)?;
|
||||
}
|
||||
|
||||
app.wvr_server
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.manager
|
||||
.state
|
||||
.send_frame_callbacks_for_surface_id(&popup.surface_id);
|
||||
for surface in &self.surfaces {
|
||||
self.render_subsurface(app, rdr, surface)?;
|
||||
callback_surfaces.push(&surface.surface_id);
|
||||
}
|
||||
|
||||
for popup in &self.popups {
|
||||
self.render_subsurface(app, rdr, popup)?;
|
||||
callback_surfaces.push(&popup.surface_id);
|
||||
}
|
||||
|
||||
// frame callbacks for toplevel + subsurf + popup
|
||||
if let Some(wvr_server) = app.wvr_server.as_mut() {
|
||||
let state = &mut wvr_server.manager.state;
|
||||
if let Some(window) = wvr_server.wm.windows.get(&self.window) {
|
||||
let surface_id = window.toplevel.wl_surface().id();
|
||||
wvr_server
|
||||
.manager
|
||||
.state
|
||||
.send_frame_callbacks_for_surface_id(&surface_id);
|
||||
state.send_frame_callbacks_for_surface_id(&surface_id);
|
||||
}
|
||||
for surface in &self.surfaces {
|
||||
state.send_frame_callbacks_for_surface_id(&surface.surface_id);
|
||||
}
|
||||
for popup in &self.popups {
|
||||
state.send_frame_callbacks_for_surface_id(&popup.surface_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -663,6 +721,11 @@ impl OverlayBackend for WvrWindowBackend {
|
|||
surface,
|
||||
global_pos,
|
||||
surface_origin,
|
||||
})
|
||||
| Some(WvrHitTarget::Surface {
|
||||
surface,
|
||||
global_pos,
|
||||
surface_origin,
|
||||
}) => {
|
||||
if self.panel_hovered {
|
||||
self.panel.on_left(app, hit.pointer);
|
||||
|
|
@ -773,6 +836,11 @@ impl OverlayBackend for WvrWindowBackend {
|
|||
surface,
|
||||
global_pos,
|
||||
surface_origin,
|
||||
})
|
||||
| Some(WvrHitTarget::Surface {
|
||||
surface,
|
||||
global_pos,
|
||||
surface_origin,
|
||||
}) => {
|
||||
let wvr_server = app.wvr_server.as_mut().unwrap();
|
||||
|
||||
|
|
@ -862,15 +930,59 @@ impl OverlayBackend for WvrWindowBackend {
|
|||
}
|
||||
}
|
||||
|
||||
fn rendered_popups_dirty(a: &[RenderedPopup], b: &[RenderedPopup]) -> bool {
|
||||
if a.len() != b.len() {
|
||||
fn rendered_surfaces_dirty(old: &[RenderedSurface], new: &[RenderedSurface]) -> bool {
|
||||
if old.len() != new.len() {
|
||||
return true;
|
||||
}
|
||||
|
||||
a.iter().zip(b).any(|(a, b)| {
|
||||
old.iter().zip(new).any(|(a, b)| {
|
||||
a.surface_id != b.surface_id
|
||||
|| !Arc::ptr_eq(&a.image, &b.image)
|
||||
|| a.pos != b.pos
|
||||
|| a.size != b.size
|
||||
|| *a.image.image() != *b.image.image()
|
||||
})
|
||||
}
|
||||
|
||||
fn surface_location(states: &smithay::wayland::compositor::SurfaceData) -> Point<i32, Logical> {
|
||||
if states.role == Some("wl_subsurface") {
|
||||
let mut guard = states.cached_state.get::<SubsurfaceCachedState>();
|
||||
guard.current().location
|
||||
} else {
|
||||
(0, 0).into()
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_rendered_surface_tree(root: &WlSurface) -> Vec<RenderedSurface> {
|
||||
let mut out = Vec::new();
|
||||
|
||||
with_surface_tree_upward(
|
||||
root,
|
||||
Point::<i32, Logical>::from((0, 0)),
|
||||
|_, states, parent_pos| {
|
||||
let pos = *parent_pos + surface_location(states);
|
||||
|
||||
// do not skip even though no buffer; children might have buffer
|
||||
TraversalAction::DoChildren(pos)
|
||||
},
|
||||
|surface, states, parent_pos| {
|
||||
let pos = *parent_pos + surface_location(states);
|
||||
|
||||
if let Some(surf) = SurfaceBufWithImage::get_from_surface(states) {
|
||||
let extent = surf.image.extent_f32();
|
||||
let scale = surf.scale.max(1) as f32;
|
||||
|
||||
out.push(RenderedSurface {
|
||||
surface: surface.clone(),
|
||||
surface_id: surface.id(),
|
||||
image: surf.image,
|
||||
pos: vec2(pos.x as f32, pos.y as f32),
|
||||
size: vec2(extent[0] / scale, extent[1] / scale),
|
||||
dmabuf: surf.dmabuf,
|
||||
});
|
||||
}
|
||||
},
|
||||
|_, _, _| true,
|
||||
);
|
||||
|
||||
out
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,5 +9,11 @@ layout (set = 0, binding = 0) uniform sampler2D in_texture;
|
|||
void main()
|
||||
{
|
||||
out_color = texture(in_texture, in_uv);
|
||||
|
||||
bvec4 cutoff = lessThan(out_color, vec4(0.04045));
|
||||
vec4 higher = pow((out_color + vec4(0.055))/vec4(1.055), vec4(2.4));
|
||||
vec4 lower = out_color/vec4(12.92);
|
||||
|
||||
out_color = mix(higher, lower, cutoff);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue