mirror of
https://github.com/pinnacle-comp/pinnacle.git
synced 2025-01-18 22:26:12 +01:00
Default back to linear scaling and add config options to set
This commit is contained in:
parent
7496ebd697
commit
d52192a2ba
15 changed files with 360 additions and 63 deletions
|
@ -92,16 +92,24 @@ require("pinnacle").setup(function(Pinnacle)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
Input.keybind({ mod_key }, "=", function()
|
Input.keybind({ mod_key, "shift" }, "=", function()
|
||||||
Output.get_focused():increase_scale(0.25)
|
Output.get_focused():increase_scale(0.25)
|
||||||
layout_outputs_in_line()
|
layout_outputs_in_line()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
Input.keybind({ mod_key }, "-", function()
|
Input.keybind({ mod_key, "shift" }, "-", function()
|
||||||
Output.get_focused():decrease_scale(0.25)
|
Output.get_focused():decrease_scale(0.25)
|
||||||
layout_outputs_in_line()
|
layout_outputs_in_line()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
Input.keybind({ mod_key }, "u", function()
|
||||||
|
Pinnacle.render.set_upscale_filter("nearest_neighbor")
|
||||||
|
end)
|
||||||
|
|
||||||
|
Input.keybind({ mod_key }, "d", function()
|
||||||
|
Pinnacle.render.set_upscale_filter("bilinear")
|
||||||
|
end)
|
||||||
|
|
||||||
--------------------
|
--------------------
|
||||||
-- Tags --
|
-- Tags --
|
||||||
--------------------
|
--------------------
|
||||||
|
|
|
@ -28,5 +28,6 @@ build = {
|
||||||
["pinnacle.util"] = "pinnacle/util.lua",
|
["pinnacle.util"] = "pinnacle/util.lua",
|
||||||
["pinnacle.signal"] = "pinnacle/signal.lua",
|
["pinnacle.signal"] = "pinnacle/signal.lua",
|
||||||
["pinnacle.layout"] = "pinnacle/layout.lua",
|
["pinnacle.layout"] = "pinnacle/layout.lua",
|
||||||
|
["pinnacle.render"] = "pinnacle/render.lua",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ local client = require("pinnacle.grpc.client")
|
||||||
|
|
||||||
---The entry point to configuration.
|
---The entry point to configuration.
|
||||||
---
|
---
|
||||||
---This module contains one function: `setup`, which is how you'll access all the ways to configure Pinnacle.
|
---This module contains the `setup` function, which is how you'll access all the ways to configure Pinnacle.
|
||||||
---@class Pinnacle
|
---@class Pinnacle
|
||||||
local pinnacle = {
|
local pinnacle = {
|
||||||
---@type Input
|
---@type Input
|
||||||
|
@ -23,6 +23,8 @@ local pinnacle = {
|
||||||
util = require("pinnacle.util"),
|
util = require("pinnacle.util"),
|
||||||
---@type Layout
|
---@type Layout
|
||||||
layout = require("pinnacle.layout"),
|
layout = require("pinnacle.layout"),
|
||||||
|
---@type Render
|
||||||
|
render = require("pinnacle.render"),
|
||||||
}
|
}
|
||||||
|
|
||||||
---Quit Pinnacle.
|
---Quit Pinnacle.
|
||||||
|
@ -50,6 +52,8 @@ end
|
||||||
function pinnacle.setup(config_fn)
|
function pinnacle.setup(config_fn)
|
||||||
require("pinnacle.grpc.protobuf").build_protos()
|
require("pinnacle.grpc.protobuf").build_protos()
|
||||||
|
|
||||||
|
-- This function ensures a config won't run forever if Pinnacle is killed
|
||||||
|
-- and doesn't kill configs on drop.
|
||||||
client.loop:wrap(function()
|
client.loop:wrap(function()
|
||||||
while true do
|
while true do
|
||||||
require("cqueues").sleep(60)
|
require("cqueues").sleep(60)
|
||||||
|
|
|
@ -19,6 +19,7 @@ function protobuf.build_protos()
|
||||||
PINNACLE_PROTO_DIR .. "/pinnacle/window/" .. version .. "/window.proto",
|
PINNACLE_PROTO_DIR .. "/pinnacle/window/" .. version .. "/window.proto",
|
||||||
PINNACLE_PROTO_DIR .. "/pinnacle/signal/" .. version .. "/signal.proto",
|
PINNACLE_PROTO_DIR .. "/pinnacle/signal/" .. version .. "/signal.proto",
|
||||||
PINNACLE_PROTO_DIR .. "/pinnacle/layout/" .. version .. "/layout.proto",
|
PINNACLE_PROTO_DIR .. "/pinnacle/layout/" .. version .. "/layout.proto",
|
||||||
|
PINNACLE_PROTO_DIR .. "/pinnacle/render/" .. version .. "/render.proto",
|
||||||
PINNACLE_PROTO_DIR .. "/google/protobuf/empty.proto",
|
PINNACLE_PROTO_DIR .. "/google/protobuf/empty.proto",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
69
api/lua/pinnacle/render.lua
Normal file
69
api/lua/pinnacle/render.lua
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
-- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
-- file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
|
local client = require("pinnacle.grpc.client")
|
||||||
|
|
||||||
|
---The protobuf absolute path prefix
|
||||||
|
local prefix = "pinnacle.render." .. client.version .. "."
|
||||||
|
local service = prefix .. "RenderService"
|
||||||
|
|
||||||
|
---@type table<string, { request_type: string?, response_type: string? }>
|
||||||
|
---@enum (key) RenderServiceMethod
|
||||||
|
local rpc_types = {
|
||||||
|
SetUpscaleFilter = {},
|
||||||
|
SetDownscaleFilter = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
---Build GrpcRequestParams
|
||||||
|
---@param method RenderServiceMethod
|
||||||
|
---@param data table
|
||||||
|
---@return GrpcRequestParams
|
||||||
|
local function build_grpc_request_params(method, data)
|
||||||
|
local req_type = rpc_types[method].request_type
|
||||||
|
local resp_type = rpc_types[method].response_type
|
||||||
|
|
||||||
|
---@type GrpcRequestParams
|
||||||
|
return {
|
||||||
|
service = service,
|
||||||
|
method = method,
|
||||||
|
request_type = req_type and prefix .. req_type or prefix .. method .. "Request",
|
||||||
|
response_type = resp_type and prefix .. resp_type,
|
||||||
|
data = data,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
---Rendering management.
|
||||||
|
---
|
||||||
|
---@class Render
|
||||||
|
local render = {}
|
||||||
|
|
||||||
|
---@alias ScalingFilter
|
||||||
|
---| "bilinear"
|
||||||
|
---| "nearest_neighbor"
|
||||||
|
|
||||||
|
---@type table<ScalingFilter, integer>
|
||||||
|
local filter_name_to_filter_value = {
|
||||||
|
bilinear = 1,
|
||||||
|
nearest_neighbor = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
---Set the upscale filter the renderer will use to upscale buffers.
|
||||||
|
---
|
||||||
|
---@param filter ScalingFilter
|
||||||
|
function render.set_upscale_filter(filter)
|
||||||
|
client.unary_request(
|
||||||
|
build_grpc_request_params("SetUpscaleFilter", { filter = filter_name_to_filter_value[filter] })
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
---Set the downscale filter the renderer will use to downscale buffers.
|
||||||
|
---
|
||||||
|
---@param filter ScalingFilter
|
||||||
|
function render.set_downscale_filter(filter)
|
||||||
|
client.unary_request(
|
||||||
|
build_grpc_request_params("SetDownscaleFilter", { filter = filter_name_to_filter_value[filter] })
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
return render
|
35
api/protocol/pinnacle/render/v0alpha1/render.proto
Normal file
35
api/protocol/pinnacle/render/v0alpha1/render.proto
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package pinnacle.render.v0alpha1;
|
||||||
|
|
||||||
|
import "google/protobuf/empty.proto";
|
||||||
|
|
||||||
|
// The filtering method.
|
||||||
|
enum Filter {
|
||||||
|
FILTER_UNSPECIFIED = 0;
|
||||||
|
// Bilinear filtering.
|
||||||
|
//
|
||||||
|
// This will cause up- and downscaling to be blurry.
|
||||||
|
FILTER_BILINEAR = 1;
|
||||||
|
// Nearest neighbor filtering.
|
||||||
|
//
|
||||||
|
// This will cause edges to become pixelated when scaling.
|
||||||
|
FILTER_NEAREST_NEIGHBOR = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SetUpscaleFilterRequest {
|
||||||
|
// The filter that will be used.
|
||||||
|
optional Filter filter = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SetDownscaleFilterRequest {
|
||||||
|
// The filter that will be used.
|
||||||
|
optional Filter filter = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
service RenderService {
|
||||||
|
// Set the upscaling filter the renderer will use when upscaling buffers.
|
||||||
|
rpc SetUpscaleFilter(SetUpscaleFilterRequest) returns (google.protobuf.Empty);
|
||||||
|
// Set the downscaling filter the renderer will use when downscaling buffers.
|
||||||
|
rpc SetDownscaleFilter(SetDownscaleFilterRequest) returns (google.protobuf.Empty);
|
||||||
|
}
|
|
@ -88,6 +88,7 @@ use layout::Layout;
|
||||||
use output::Output;
|
use output::Output;
|
||||||
use pinnacle::Pinnacle;
|
use pinnacle::Pinnacle;
|
||||||
use process::Process;
|
use process::Process;
|
||||||
|
use render::Render;
|
||||||
use signal::SignalState;
|
use signal::SignalState;
|
||||||
use tag::Tag;
|
use tag::Tag;
|
||||||
use tokio::sync::{
|
use tokio::sync::{
|
||||||
|
@ -104,6 +105,7 @@ pub mod layout;
|
||||||
pub mod output;
|
pub mod output;
|
||||||
pub mod pinnacle;
|
pub mod pinnacle;
|
||||||
pub mod process;
|
pub mod process;
|
||||||
|
pub mod render;
|
||||||
pub mod signal;
|
pub mod signal;
|
||||||
pub mod tag;
|
pub mod tag;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
|
@ -121,6 +123,7 @@ static OUTPUT: OnceLock<Output> = OnceLock::new();
|
||||||
static TAG: OnceLock<Tag> = OnceLock::new();
|
static TAG: OnceLock<Tag> = OnceLock::new();
|
||||||
static SIGNAL: OnceLock<RwLock<SignalState>> = OnceLock::new();
|
static SIGNAL: OnceLock<RwLock<SignalState>> = OnceLock::new();
|
||||||
static LAYOUT: OnceLock<Layout> = OnceLock::new();
|
static LAYOUT: OnceLock<Layout> = OnceLock::new();
|
||||||
|
static RENDER: OnceLock<Render> = OnceLock::new();
|
||||||
|
|
||||||
/// A struct containing static references to all of the configuration structs.
|
/// A struct containing static references to all of the configuration structs.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -139,6 +142,8 @@ pub struct ApiModules {
|
||||||
pub tag: &'static Tag,
|
pub tag: &'static Tag,
|
||||||
/// The [`Layout`] struct
|
/// The [`Layout`] struct
|
||||||
pub layout: &'static Layout,
|
pub layout: &'static Layout,
|
||||||
|
/// The [`Render`] struct
|
||||||
|
pub render: &'static Render,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Connects to Pinnacle and builds the configuration structs.
|
/// Connects to Pinnacle and builds the configuration structs.
|
||||||
|
@ -166,6 +171,7 @@ pub async fn connect(
|
||||||
let tag = TAG.get_or_init(|| Tag::new(channel.clone()));
|
let tag = TAG.get_or_init(|| Tag::new(channel.clone()));
|
||||||
let output = OUTPUT.get_or_init(|| Output::new(channel.clone()));
|
let output = OUTPUT.get_or_init(|| Output::new(channel.clone()));
|
||||||
let layout = LAYOUT.get_or_init(|| Layout::new(channel.clone()));
|
let layout = LAYOUT.get_or_init(|| Layout::new(channel.clone()));
|
||||||
|
let render = RENDER.get_or_init(|| Render::new(channel.clone()));
|
||||||
|
|
||||||
SIGNAL
|
SIGNAL
|
||||||
.set(RwLock::new(SignalState::new(
|
.set(RwLock::new(SignalState::new(
|
||||||
|
@ -182,6 +188,7 @@ pub async fn connect(
|
||||||
output,
|
output,
|
||||||
tag,
|
tag,
|
||||||
layout,
|
layout,
|
||||||
|
render,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok((modules, fut_recv))
|
Ok((modules, fut_recv))
|
||||||
|
|
52
api/rust/src/render.rs
Normal file
52
api/rust/src/render.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
//! Rendering management.
|
||||||
|
|
||||||
|
use pinnacle_api_defs::pinnacle::render::v0alpha1::{
|
||||||
|
render_service_client::RenderServiceClient, SetDownscaleFilterRequest, SetUpscaleFilterRequest,
|
||||||
|
};
|
||||||
|
use tonic::transport::Channel;
|
||||||
|
|
||||||
|
use crate::block_on_tokio;
|
||||||
|
|
||||||
|
/// A struct that allows you to manage rendering.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Render {
|
||||||
|
client: RenderServiceClient<Channel>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// What filter to use when scaling.
|
||||||
|
pub enum ScalingFilter {
|
||||||
|
/// Use a bilinear filter.
|
||||||
|
///
|
||||||
|
/// This will make up- and downscaling blurry.
|
||||||
|
Bilinear,
|
||||||
|
/// Use a nearest neighbor filter.
|
||||||
|
///
|
||||||
|
/// This will cause scaling to look pixelated.
|
||||||
|
NearestNeighbor,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Render {
|
||||||
|
pub(crate) fn new(channel: Channel) -> Self {
|
||||||
|
Self {
|
||||||
|
client: RenderServiceClient::new(channel),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the upscaling filter that will be used for rendering.
|
||||||
|
pub fn set_upscale_filter(&self, filter: ScalingFilter) {
|
||||||
|
let mut client = self.client.clone();
|
||||||
|
block_on_tokio(client.set_upscale_filter(SetUpscaleFilterRequest {
|
||||||
|
filter: Some(filter as i32),
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the downscaling filter that will be used for rendering.
|
||||||
|
pub fn set_downscale_filter(&self, filter: ScalingFilter) {
|
||||||
|
let mut client = self.client.clone();
|
||||||
|
block_on_tokio(client.set_downscale_filter(SetDownscaleFilterRequest {
|
||||||
|
filter: Some(filter as i32),
|
||||||
|
}))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ fn main() {
|
||||||
formatcp!("../api/protocol/pinnacle/window/{VERSION}/window.proto"),
|
formatcp!("../api/protocol/pinnacle/window/{VERSION}/window.proto"),
|
||||||
formatcp!("../api/protocol/pinnacle/signal/{VERSION}/signal.proto"),
|
formatcp!("../api/protocol/pinnacle/signal/{VERSION}/signal.proto"),
|
||||||
formatcp!("../api/protocol/pinnacle/layout/{VERSION}/layout.proto"),
|
formatcp!("../api/protocol/pinnacle/layout/{VERSION}/layout.proto"),
|
||||||
|
formatcp!("../api/protocol/pinnacle/render/{VERSION}/render.proto"),
|
||||||
];
|
];
|
||||||
|
|
||||||
let descriptor_path = PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("pinnacle.bin");
|
let descriptor_path = PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("pinnacle.bin");
|
||||||
|
|
|
@ -74,6 +74,12 @@ pub mod pinnacle {
|
||||||
tonic::include_proto!("pinnacle.layout.v0alpha1");
|
tonic::include_proto!("pinnacle.layout.v0alpha1");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod render {
|
||||||
|
pub mod v0alpha1 {
|
||||||
|
tonic::include_proto!("pinnacle.render.v0alpha1");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const FILE_DESCRIPTOR_SET: &[u8] = tonic::include_file_descriptor_set!("pinnacle");
|
pub const FILE_DESCRIPTOR_SET: &[u8] = tonic::include_file_descriptor_set!("pinnacle");
|
||||||
|
|
68
src/api.rs
68
src/api.rs
|
@ -20,6 +20,9 @@ use pinnacle_api_defs::pinnacle::{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
process::v0alpha1::{process_service_server, SetEnvRequest, SpawnRequest, SpawnResponse},
|
process::v0alpha1::{process_service_server, SetEnvRequest, SpawnRequest, SpawnResponse},
|
||||||
|
render::v0alpha1::{
|
||||||
|
render_service_server, Filter, SetDownscaleFilterRequest, SetUpscaleFilterRequest,
|
||||||
|
},
|
||||||
tag::{
|
tag::{
|
||||||
self,
|
self,
|
||||||
v0alpha1::{
|
v0alpha1::{
|
||||||
|
@ -30,6 +33,7 @@ use pinnacle_api_defs::pinnacle::{
|
||||||
v0alpha1::{pinnacle_service_server, PingRequest, PingResponse, QuitRequest, SetOrToggle},
|
v0alpha1::{pinnacle_service_server, PingRequest, PingResponse, QuitRequest, SetOrToggle},
|
||||||
};
|
};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
|
backend::renderer::TextureFilter,
|
||||||
desktop::layer_map_for_output,
|
desktop::layer_map_for_output,
|
||||||
input::keyboard::XkbConfig,
|
input::keyboard::XkbConfig,
|
||||||
output::Scale,
|
output::Scale,
|
||||||
|
@ -46,6 +50,7 @@ use tonic::{Request, Response, Status, Streaming};
|
||||||
use tracing::{debug, error, warn};
|
use tracing::{debug, error, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
backend::BackendData,
|
||||||
config::ConnectorSavedState,
|
config::ConnectorSavedState,
|
||||||
input::ModifierMask,
|
input::ModifierMask,
|
||||||
output::OutputName,
|
output::OutputName,
|
||||||
|
@ -1135,3 +1140,66 @@ impl output_service_server::OutputService for OutputService {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct RenderService {
|
||||||
|
sender: StateFnSender,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RenderService {
|
||||||
|
pub fn new(sender: StateFnSender) -> Self {
|
||||||
|
Self { sender }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tonic::async_trait]
|
||||||
|
impl render_service_server::RenderService for RenderService {
|
||||||
|
async fn set_upscale_filter(
|
||||||
|
&self,
|
||||||
|
request: Request<SetUpscaleFilterRequest>,
|
||||||
|
) -> Result<Response<()>, Status> {
|
||||||
|
let request = request.into_inner();
|
||||||
|
if let Filter::Unspecified = request.filter() {
|
||||||
|
return Err(Status::invalid_argument("unspecified filter"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let filter = match request.filter() {
|
||||||
|
Filter::Bilinear => TextureFilter::Linear,
|
||||||
|
Filter::NearestNeighbor => TextureFilter::Nearest,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
run_unary_no_response(&self.sender, move |state| {
|
||||||
|
state.backend.set_upscale_filter(filter);
|
||||||
|
for output in state.space.outputs().cloned().collect::<Vec<_>>() {
|
||||||
|
state.backend.reset_buffers(&output);
|
||||||
|
state.schedule_render(&output);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_downscale_filter(
|
||||||
|
&self,
|
||||||
|
request: Request<SetDownscaleFilterRequest>,
|
||||||
|
) -> Result<Response<()>, Status> {
|
||||||
|
let request = request.into_inner();
|
||||||
|
if let Filter::Unspecified = request.filter() {
|
||||||
|
return Err(Status::invalid_argument("unspecified filter"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let filter = match request.filter() {
|
||||||
|
Filter::Bilinear => TextureFilter::Linear,
|
||||||
|
Filter::NearestNeighbor => TextureFilter::Nearest,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
run_unary_no_response(&self.sender, move |state| {
|
||||||
|
state.backend.set_downscale_filter(filter);
|
||||||
|
for output in state.space.outputs().cloned().collect::<Vec<_>>() {
|
||||||
|
state.backend.reset_buffers(&output);
|
||||||
|
state.schedule_render(&output);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use smithay::{
|
||||||
default_primary_scanout_output_compare, utils::select_dmabuf_feedback,
|
default_primary_scanout_output_compare, utils::select_dmabuf_feedback,
|
||||||
RenderElementStates,
|
RenderElementStates,
|
||||||
},
|
},
|
||||||
ImportDma,
|
ImportDma, Renderer, TextureFilter,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
delegate_dmabuf,
|
delegate_dmabuf,
|
||||||
|
@ -26,6 +26,7 @@ use smithay::{
|
||||||
fractional_scale::with_fractional_scale,
|
fractional_scale::with_fractional_scale,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
state::{State, SurfaceDmabufFeedback},
|
state::{State, SurfaceDmabufFeedback},
|
||||||
|
@ -51,6 +52,32 @@ pub enum Backend {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
|
pub fn set_upscale_filter(&mut self, filter: TextureFilter) {
|
||||||
|
match self {
|
||||||
|
Backend::Winit(winit) => {
|
||||||
|
if let Err(err) = winit.backend.renderer().upscale_filter(filter) {
|
||||||
|
error!("Failed to set winit upscale filter: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Backend::Udev(udev) => udev.upscale_filter = filter,
|
||||||
|
#[cfg(feature = "testing")]
|
||||||
|
Backend::Dummy(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_downscale_filter(&mut self, filter: TextureFilter) {
|
||||||
|
match self {
|
||||||
|
Backend::Winit(winit) => {
|
||||||
|
if let Err(err) = winit.backend.renderer().downscale_filter(filter) {
|
||||||
|
error!("Failed to set winit upscale filter: {err}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Backend::Udev(udev) => udev.downscale_filter = filter,
|
||||||
|
#[cfg(feature = "testing")]
|
||||||
|
Backend::Dummy(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn seat_name(&self) -> String {
|
pub fn seat_name(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Backend::Winit(winit) => winit.seat_name(),
|
Backend::Winit(winit) => winit.seat_name(),
|
||||||
|
@ -86,7 +113,6 @@ impl Backend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait defining common methods for each available backend: winit and tty-udev
|
|
||||||
pub trait BackendData: 'static {
|
pub trait BackendData: 'static {
|
||||||
fn seat_name(&self) -> String;
|
fn seat_name(&self) -> String;
|
||||||
fn reset_buffers(&mut self, output: &Output);
|
fn reset_buffers(&mut self, output: &Output);
|
||||||
|
@ -95,6 +121,35 @@ pub trait BackendData: 'static {
|
||||||
fn early_import(&mut self, surface: &WlSurface);
|
fn early_import(&mut self, surface: &WlSurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BackendData for Backend {
|
||||||
|
fn seat_name(&self) -> String {
|
||||||
|
match self {
|
||||||
|
Backend::Winit(winit) => winit.seat_name(),
|
||||||
|
Backend::Udev(udev) => udev.seat_name(),
|
||||||
|
#[cfg(feature = "testing")]
|
||||||
|
Backend::Dummy(dummy) => dummy.seat_name(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset_buffers(&mut self, output: &Output) {
|
||||||
|
match self {
|
||||||
|
Backend::Winit(winit) => winit.reset_buffers(output),
|
||||||
|
Backend::Udev(udev) => udev.reset_buffers(output),
|
||||||
|
#[cfg(feature = "testing")]
|
||||||
|
Backend::Dummy(dummy) => dummy.reset_buffers(output),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn early_import(&mut self, surface: &WlSurface) {
|
||||||
|
match self {
|
||||||
|
Backend::Winit(winit) => winit.early_import(surface),
|
||||||
|
Backend::Udev(udev) => udev.early_import(surface),
|
||||||
|
#[cfg(feature = "testing")]
|
||||||
|
Backend::Dummy(dummy) => dummy.early_import(surface),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Update surface primary scanout outputs and send frames and dmabuf feedback to visible windows
|
/// Update surface primary scanout outputs and send frames and dmabuf feedback to visible windows
|
||||||
/// and layers.
|
/// and layers.
|
||||||
pub fn post_repaint(
|
pub fn post_repaint(
|
||||||
|
|
|
@ -29,9 +29,9 @@ use smithay::{
|
||||||
renderer::{
|
renderer::{
|
||||||
damage,
|
damage,
|
||||||
element::{texture::TextureBuffer, RenderElement, RenderElementStates},
|
element::{texture::TextureBuffer, RenderElement, RenderElementStates},
|
||||||
gles::{GlesRenderer, GlesTexture},
|
gles::GlesRenderer,
|
||||||
multigpu::{gbm::GbmGlesBackend, GpuManager, MultiRenderer, MultiTexture},
|
multigpu::{gbm::GbmGlesBackend, GpuManager, MultiRenderer, MultiTexture},
|
||||||
Bind, ExportMem, ImportDma, ImportEgl, ImportMemWl, Offscreen, Renderer, TextureFilter,
|
Bind, ImportDma, ImportEgl, ImportMemWl, Renderer, TextureFilter,
|
||||||
},
|
},
|
||||||
session::{
|
session::{
|
||||||
self,
|
self,
|
||||||
|
@ -52,10 +52,7 @@ use smithay::{
|
||||||
reexports::{
|
reexports::{
|
||||||
ash::vk::ExtPhysicalDeviceDrmFn,
|
ash::vk::ExtPhysicalDeviceDrmFn,
|
||||||
calloop::{EventLoop, Idle, LoopHandle, RegistrationToken},
|
calloop::{EventLoop, Idle, LoopHandle, RegistrationToken},
|
||||||
drm::{
|
drm::control::{connector, crtc, ModeTypeFlags},
|
||||||
control::{connector, crtc, ModeTypeFlags},
|
|
||||||
Device,
|
|
||||||
},
|
|
||||||
input::Libinput,
|
input::Libinput,
|
||||||
rustix::fs::OFlags,
|
rustix::fs::OFlags,
|
||||||
wayland_protocols::wp::{
|
wayland_protocols::wp::{
|
||||||
|
@ -122,6 +119,9 @@ pub struct Udev {
|
||||||
pointer_images: Vec<(xcursor::parser::Image, TextureBuffer<MultiTexture>)>,
|
pointer_images: Vec<(xcursor::parser::Image, TextureBuffer<MultiTexture>)>,
|
||||||
pointer_element: PointerElement<MultiTexture>,
|
pointer_element: PointerElement<MultiTexture>,
|
||||||
pointer_image: crate::cursor::Cursor,
|
pointer_image: crate::cursor::Cursor,
|
||||||
|
|
||||||
|
pub(super) upscale_filter: TextureFilter,
|
||||||
|
pub(super) downscale_filter: TextureFilter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
|
@ -320,6 +320,9 @@ pub fn setup_udev(
|
||||||
pointer_image: crate::cursor::Cursor::load(),
|
pointer_image: crate::cursor::Cursor::load(),
|
||||||
pointer_images: Vec::new(),
|
pointer_images: Vec::new(),
|
||||||
pointer_element: PointerElement::default(),
|
pointer_element: PointerElement::default(),
|
||||||
|
|
||||||
|
upscale_filter: TextureFilter::Linear,
|
||||||
|
downscale_filter: TextureFilter::Linear,
|
||||||
};
|
};
|
||||||
|
|
||||||
let display_handle = display.handle();
|
let display_handle = display.handle();
|
||||||
|
@ -721,14 +724,14 @@ struct SurfaceCompositorRenderResult {
|
||||||
/// Render a frame with the given elements.
|
/// Render a frame with the given elements.
|
||||||
///
|
///
|
||||||
/// This frame needs to be queued for scanout afterwards.
|
/// This frame needs to be queued for scanout afterwards.
|
||||||
fn render_frame<R, E, Target>(
|
fn render_frame<R, E>(
|
||||||
compositor: &mut GbmDrmCompositor,
|
compositor: &mut GbmDrmCompositor,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
elements: &[E],
|
elements: &[E],
|
||||||
clear_color: [f32; 4],
|
clear_color: [f32; 4],
|
||||||
) -> Result<SurfaceCompositorRenderResult, SwapBuffersError>
|
) -> Result<SurfaceCompositorRenderResult, SwapBuffersError>
|
||||||
where
|
where
|
||||||
R: Renderer + Bind<Dmabuf> + Bind<Target> + Offscreen<Target> + ExportMem,
|
R: Renderer + Bind<Dmabuf>,
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
<R as Renderer>::Error: Into<SwapBuffersError>,
|
<R as Renderer>::Error: Into<SwapBuffersError>,
|
||||||
E: RenderElement<R>,
|
E: RenderElement<R>,
|
||||||
|
@ -942,30 +945,12 @@ impl State {
|
||||||
};
|
};
|
||||||
|
|
||||||
let compositor = {
|
let compositor = {
|
||||||
let driver = match device.drm.get_driver() {
|
|
||||||
Ok(driver) => driver,
|
|
||||||
Err(err) => {
|
|
||||||
warn!("Failed to query drm driver: {}", err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut planes = surface.planes().clone();
|
let mut planes = surface.planes().clone();
|
||||||
|
|
||||||
// Using an overlay plane on a nvidia card breaks
|
// INFO: We are disabling overlay planes because it seems that any elements on
|
||||||
if driver
|
// | overlay planes don't get up/downscaled according to the set filter;
|
||||||
.name()
|
// | it always defaults to linear.
|
||||||
.to_string_lossy()
|
planes.overlay.clear();
|
||||||
.to_lowercase()
|
|
||||||
.contains("nvidia")
|
|
||||||
|| driver
|
|
||||||
.description()
|
|
||||||
.to_string_lossy()
|
|
||||||
.to_lowercase()
|
|
||||||
.contains("nvidia")
|
|
||||||
{
|
|
||||||
planes.overlay = vec![];
|
|
||||||
}
|
|
||||||
|
|
||||||
match DrmCompositor::new(
|
match DrmCompositor::new(
|
||||||
&output,
|
&output,
|
||||||
|
@ -1238,9 +1223,11 @@ impl State {
|
||||||
assert!(matches!(surface.render_state, RenderState::Scheduled(_)));
|
assert!(matches!(surface.render_state, RenderState::Scheduled(_)));
|
||||||
|
|
||||||
// TODO get scale from the rendersurface when supporting HiDPI
|
// TODO get scale from the rendersurface when supporting HiDPI
|
||||||
let frame = udev
|
let frame = udev.pointer_image.get_image(
|
||||||
.pointer_image
|
1,
|
||||||
.get_image(1 /*scale*/, self.clock.now().into());
|
// output.current_scale().integer_scale() as u32,
|
||||||
|
self.clock.now().into(),
|
||||||
|
);
|
||||||
|
|
||||||
let render_node = surface.render_node;
|
let render_node = surface.render_node;
|
||||||
let primary_gpu = udev.primary_gpu;
|
let primary_gpu = udev.primary_gpu;
|
||||||
|
@ -1253,9 +1240,8 @@ impl State {
|
||||||
}
|
}
|
||||||
.expect("failed to create MultiRenderer");
|
.expect("failed to create MultiRenderer");
|
||||||
|
|
||||||
// TODO: set from config
|
let _ = renderer.upscale_filter(udev.upscale_filter);
|
||||||
let _ = renderer.upscale_filter(TextureFilter::Nearest);
|
let _ = renderer.downscale_filter(udev.downscale_filter);
|
||||||
let _ = renderer.downscale_filter(TextureFilter::Nearest);
|
|
||||||
|
|
||||||
let pointer_images = &mut udev.pointer_images;
|
let pointer_images = &mut udev.pointer_images;
|
||||||
let pointer_image = pointer_images
|
let pointer_image = pointer_images
|
||||||
|
@ -1360,7 +1346,7 @@ fn render_surface(
|
||||||
Some(pointer_image),
|
Some(pointer_image),
|
||||||
);
|
);
|
||||||
|
|
||||||
let res = render_frame::<_, _, GlesTexture>(
|
let res = render_frame(
|
||||||
&mut surface.compositor,
|
&mut surface.compositor,
|
||||||
renderer,
|
renderer,
|
||||||
&output_render_elements,
|
&output_render_elements,
|
||||||
|
|
|
@ -8,13 +8,13 @@ use smithay::{
|
||||||
renderer::{
|
renderer::{
|
||||||
damage::{self, OutputDamageTracker},
|
damage::{self, OutputDamageTracker},
|
||||||
gles::{GlesRenderer, GlesTexture},
|
gles::{GlesRenderer, GlesTexture},
|
||||||
ImportDma, ImportEgl, ImportMemWl, Renderer, TextureFilter,
|
ImportDma, ImportEgl, ImportMemWl,
|
||||||
},
|
},
|
||||||
winit::{self, WinitEvent, WinitGraphicsBackend},
|
winit::{self, WinitEvent, WinitGraphicsBackend},
|
||||||
},
|
},
|
||||||
desktop::utils::send_frames_surface_tree,
|
desktop::{layer_map_for_output, utils::send_frames_surface_tree},
|
||||||
input::pointer::CursorImageStatus,
|
input::pointer::CursorImageStatus,
|
||||||
output::{Output, Subpixel},
|
output::{Output, Scale, Subpixel},
|
||||||
reexports::{
|
reexports::{
|
||||||
calloop::{
|
calloop::{
|
||||||
timer::{TimeoutAction, Timer},
|
timer::{TimeoutAction, Timer},
|
||||||
|
@ -30,6 +30,7 @@ use smithay::{
|
||||||
utils::{IsAlive, Transform},
|
utils::{IsAlive, Transform},
|
||||||
wayland::dmabuf::{DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufState},
|
wayland::dmabuf::{DmabufFeedback, DmabufFeedbackBuilder, DmabufGlobal, DmabufState},
|
||||||
};
|
};
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
render::{pointer::PointerElement, take_presentation_feedback},
|
render::{pointer::PointerElement, take_presentation_feedback},
|
||||||
|
@ -88,14 +89,6 @@ pub fn setup_winit(
|
||||||
Err(err) => anyhow::bail!("Failed to init winit backend: {err}"),
|
Err(err) => anyhow::bail!("Failed to init winit backend: {err}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: set from config
|
|
||||||
winit_backend
|
|
||||||
.renderer()
|
|
||||||
.upscale_filter(TextureFilter::Nearest)?;
|
|
||||||
winit_backend
|
|
||||||
.renderer()
|
|
||||||
.downscale_filter(TextureFilter::Nearest)?;
|
|
||||||
|
|
||||||
let mode = smithay::output::Mode {
|
let mode = smithay::output::Mode {
|
||||||
size: winit_backend.window_size(),
|
size: winit_backend.window_size(),
|
||||||
refresh: 144_000,
|
refresh: 144_000,
|
||||||
|
@ -206,7 +199,7 @@ pub fn setup_winit(
|
||||||
true,
|
true,
|
||||||
|_| {},
|
|_| {},
|
||||||
) {
|
) {
|
||||||
tracing::error!("Failed to start XWayland: {err}");
|
error!("Failed to start XWayland: {err}");
|
||||||
}
|
}
|
||||||
|
|
||||||
let insert_ret =
|
let insert_ret =
|
||||||
|
@ -214,17 +207,25 @@ pub fn setup_winit(
|
||||||
.loop_handle
|
.loop_handle
|
||||||
.insert_source(Timer::immediate(), move |_instant, _metadata, state| {
|
.insert_source(Timer::immediate(), move |_instant, _metadata, state| {
|
||||||
let status = winit_evt_loop.dispatch_new_events(|event| match event {
|
let status = winit_evt_loop.dispatch_new_events(|event| match event {
|
||||||
WinitEvent::Resized {
|
WinitEvent::Resized { size, scale_factor } => {
|
||||||
size,
|
|
||||||
scale_factor: _,
|
|
||||||
} => {
|
|
||||||
let mode = smithay::output::Mode {
|
let mode = smithay::output::Mode {
|
||||||
size,
|
size,
|
||||||
refresh: 144_000,
|
refresh: 144_000,
|
||||||
};
|
};
|
||||||
state.resize_output(&output, mode);
|
output.change_current_state(
|
||||||
|
Some(mode),
|
||||||
|
None,
|
||||||
|
Some(Scale::Fractional(scale_factor)),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
layer_map_for_output(&output).arrange();
|
||||||
|
state.request_layout(&output);
|
||||||
|
}
|
||||||
|
WinitEvent::Focus(focused) => {
|
||||||
|
if focused {
|
||||||
|
state.backend.winit_mut().reset_buffers(&output);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
WinitEvent::Focus(_) => {}
|
|
||||||
WinitEvent::Input(input_evt) => {
|
WinitEvent::Input(input_evt) => {
|
||||||
state.process_input_event(input_evt);
|
state.process_input_event(input_evt);
|
||||||
}
|
}
|
||||||
|
@ -315,7 +316,7 @@ impl State {
|
||||||
let has_rendered = render_output_result.damage.is_some();
|
let has_rendered = render_output_result.damage.is_some();
|
||||||
if let Some(damage) = render_output_result.damage {
|
if let Some(damage) = render_output_result.damage {
|
||||||
if let Err(err) = winit.backend.submit(Some(&damage)) {
|
if let Err(err) = winit.backend.submit(Some(&damage)) {
|
||||||
tracing::warn!("{}", err);
|
error!("{}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
api::{
|
api::{
|
||||||
layout::LayoutService, signal::SignalService, window::WindowService, InputService,
|
layout::LayoutService, signal::SignalService, window::WindowService, InputService,
|
||||||
OutputService, PinnacleService, ProcessService, TagService,
|
OutputService, PinnacleService, ProcessService, RenderService, TagService,
|
||||||
},
|
},
|
||||||
input::ModifierMask,
|
input::ModifierMask,
|
||||||
output::OutputName,
|
output::OutputName,
|
||||||
|
@ -20,6 +20,7 @@ use pinnacle_api_defs::pinnacle::{
|
||||||
layout::v0alpha1::layout_service_server::LayoutServiceServer,
|
layout::v0alpha1::layout_service_server::LayoutServiceServer,
|
||||||
output::v0alpha1::output_service_server::OutputServiceServer,
|
output::v0alpha1::output_service_server::OutputServiceServer,
|
||||||
process::v0alpha1::process_service_server::ProcessServiceServer,
|
process::v0alpha1::process_service_server::ProcessServiceServer,
|
||||||
|
render::v0alpha1::render_service_server::RenderServiceServer,
|
||||||
signal::v0alpha1::signal_service_server::SignalServiceServer,
|
signal::v0alpha1::signal_service_server::SignalServiceServer,
|
||||||
tag::v0alpha1::tag_service_server::TagServiceServer,
|
tag::v0alpha1::tag_service_server::TagServiceServer,
|
||||||
v0alpha1::pinnacle_service_server::PinnacleServiceServer,
|
v0alpha1::pinnacle_service_server::PinnacleServiceServer,
|
||||||
|
@ -479,6 +480,7 @@ impl State {
|
||||||
let window_service = WindowService::new(grpc_sender.clone());
|
let window_service = WindowService::new(grpc_sender.clone());
|
||||||
let signal_service = SignalService::new(grpc_sender.clone());
|
let signal_service = SignalService::new(grpc_sender.clone());
|
||||||
let layout_service = LayoutService::new(grpc_sender.clone());
|
let layout_service = LayoutService::new(grpc_sender.clone());
|
||||||
|
let render_service = RenderService::new(grpc_sender.clone());
|
||||||
|
|
||||||
let refl_service = tonic_reflection::server::Builder::configure()
|
let refl_service = tonic_reflection::server::Builder::configure()
|
||||||
.register_encoded_file_descriptor_set(pinnacle_api_defs::FILE_DESCRIPTOR_SET)
|
.register_encoded_file_descriptor_set(pinnacle_api_defs::FILE_DESCRIPTOR_SET)
|
||||||
|
@ -498,7 +500,8 @@ impl State {
|
||||||
.add_service(OutputServiceServer::new(output_service))
|
.add_service(OutputServiceServer::new(output_service))
|
||||||
.add_service(WindowServiceServer::new(window_service))
|
.add_service(WindowServiceServer::new(window_service))
|
||||||
.add_service(SignalServiceServer::new(signal_service))
|
.add_service(SignalServiceServer::new(signal_service))
|
||||||
.add_service(LayoutServiceServer::new(layout_service));
|
.add_service(LayoutServiceServer::new(layout_service))
|
||||||
|
.add_service(RenderServiceServer::new(render_service));
|
||||||
|
|
||||||
match self.xdisplay.as_ref() {
|
match self.xdisplay.as_ref() {
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
|
|
Loading…
Reference in a new issue