hwcodec, only process that start ipc server start check process (#8325)

check process send config to ipc server, other process get config from ipc server. Process will save config to toml, and the toml will be used if the config is none.

when start check process: ipc server process start or option changed
from disable to enable

when get config: main window start or option changed from disable to
enable, start_video_audio_threads.

Only windows implements signature, which is used to mark whether the gpu software and hardware information changes. After reboot, the signature doesn't change. https://asawicki.info/news_1773_how_to_programmatically_check_graphics_driver_version, use dxgi way to get software version, it's not consistent with the visible driver version, after updating intel driver with small version change, the signature doesn't change. Linux doesn't use toml file.

Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
21pages 2024-06-12 20:40:35 +08:00 committed by GitHub
parent 0f10a88b23
commit 610009528b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 393 additions and 210 deletions

4
Cargo.lock generated
View File

@ -3037,8 +3037,8 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "hwcodec"
version = "0.4.15"
source = "git+https://github.com/21pages/hwcodec#1d504ee590c15472813fecc22cee4b8149b2b8cd"
version = "0.4.16"
source = "git+https://github.com/21pages/hwcodec#0973290faddc4e22936859dd10f05610eb8d1619"
dependencies = [
"bindgen 0.59.2",
"cc",

View File

@ -1553,40 +1553,6 @@ impl LanPeers {
}
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct HwCodecConfig {
#[serde(default, deserialize_with = "deserialize_string")]
pub ram: String,
#[serde(default, deserialize_with = "deserialize_string")]
pub vram: String,
}
impl HwCodecConfig {
pub fn load() -> HwCodecConfig {
Config::load_::<HwCodecConfig>("_hwcodec")
}
pub fn store(&self) {
Config::store_(self, "_hwcodec");
}
pub fn clear() {
HwCodecConfig::default().store();
}
pub fn clear_ram() {
let mut c = Self::load();
c.ram = Default::default();
c.store();
}
pub fn clear_vram() {
let mut c = Self::load();
c.vram = Default::default();
c.store();
}
}
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct UserDefaultConfig {
#[serde(default, deserialize_with = "deserialize_hashmap_string_string")]
@ -2238,6 +2204,18 @@ pub mod keys {
];
}
pub fn common_load<
T: serde::Serialize + serde::de::DeserializeOwned + Default + std::fmt::Debug,
>(
suffix: &str,
) -> T {
Config::load_::<T>(suffix)
}
pub fn common_store<T: serde::Serialize>(config: &T, suffix: &str) {
Config::store_(config, suffix);
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -144,10 +144,7 @@ impl Encoder {
}),
Err(e) => {
log::error!("new hw encoder failed: {e:?}, clear config");
#[cfg(target_os = "android")]
crate::android::ffi::clear_codec_info();
#[cfg(not(target_os = "android"))]
hbb_common::config::HwCodecConfig::clear_ram();
HwCodecConfig::clear(false, true);
Self::update(EncodingUpdate::Check);
*ENCODE_CODEC_FORMAT.lock().unwrap() = CodecFormat::VP9;
Err(e)
@ -160,7 +157,7 @@ impl Encoder {
}),
Err(e) => {
log::error!("new vram encoder failed: {e:?}, clear config");
hbb_common::config::HwCodecConfig::clear_vram();
HwCodecConfig::clear(true, true);
Self::update(EncodingUpdate::Check);
*ENCODE_CODEC_FORMAT.lock().unwrap() = CodecFormat::VP9;
Err(e)

View File

@ -8,7 +8,6 @@ use crate::{
use hbb_common::{
anyhow::{anyhow, bail, Context},
bytes::Bytes,
config::HwCodecConfig,
log,
message_proto::{EncodedVideoFrame, EncodedVideoFrames, VideoFrame},
serde_derive::{Deserialize, Serialize},
@ -16,7 +15,7 @@ use hbb_common::{
};
use hwcodec::{
common::{
DataFormat,
get_gpu_signature, DataFormat,
Quality::{self, *},
RateControl::{self, *},
},
@ -35,6 +34,12 @@ const DEFAULT_HW_QUALITY: Quality = Quality_Default;
crate::generate_call_macro!(call_yuv, false);
#[cfg(not(target_os = "android"))]
lazy_static::lazy_static! {
static ref CONFIG: std::sync::Arc<std::sync::Mutex<Option<HwCodecConfig>>> = Default::default();
static ref CONFIG_SET_BY_IPC: std::sync::Arc<std::sync::Mutex<bool>> = Default::default();
}
#[derive(Debug, Clone)]
pub struct HwRamEncoderConfig {
pub name: String,
@ -210,21 +215,19 @@ impl EncoderApi for HwRamEncoder {
impl HwRamEncoder {
pub fn try_get(format: CodecFormat) -> Option<CodecInfo> {
let mut info = None;
if let Ok(hw) = get_config().map(|c| c.e) {
let best = CodecInfo::prioritized(hw);
match format {
CodecFormat::H264 => {
if let Some(v) = best.h264 {
info = Some(v);
}
let best = CodecInfo::prioritized(HwCodecConfig::get().ram_encode);
match format {
CodecFormat::H264 => {
if let Some(v) = best.h264 {
info = Some(v);
}
CodecFormat::H265 => {
if let Some(v) = best.h265 {
info = Some(v);
}
}
_ => {}
}
CodecFormat::H265 => {
if let Some(v) = best.h265 {
info = Some(v);
}
}
_ => {}
}
info
}
@ -313,21 +316,19 @@ impl HwRamDecoder {
_ => {}
}
if enable_hwcodec_option() {
if let Ok(hw) = get_config().map(|c| c.d) {
let best = CodecInfo::prioritized(hw);
match format {
CodecFormat::H264 => {
if let Some(v) = best.h264 {
info = Some(v);
}
let best = CodecInfo::prioritized(HwCodecConfig::get().ram_decode);
match format {
CodecFormat::H264 => {
if let Some(v) = best.h264 {
info = Some(v);
}
CodecFormat::H265 => {
if let Some(v) = best.h265 {
info = Some(v);
}
}
_ => {}
}
CodecFormat::H265 => {
if let Some(v) = best.h265 {
info = Some(v);
}
}
_ => {}
}
}
info
@ -347,10 +348,7 @@ impl HwRamDecoder {
match Decoder::new(ctx) {
Ok(decoder) => Ok(HwRamDecoder { decoder, info }),
Err(_) => {
#[cfg(target_os = "android")]
crate::android::ffi::clear_codec_info();
#[cfg(not(target_os = "android"))]
hbb_common::config::HwCodecConfig::clear_ram();
HwCodecConfig::clear(false, false);
Err(anyhow!(format!("Failed to create decoder")))
}
}
@ -467,85 +465,6 @@ impl HwRamDecoderImage<'_> {
}
}
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
struct Available {
e: Vec<CodecInfo>,
d: Vec<CodecInfo>,
}
fn get_config() -> ResultType<Available> {
#[cfg(target_os = "android")]
{
let info = crate::android::ffi::get_codec_info();
log::info!("all codec info: {info:?}");
struct T {
name_prefix: &'static str,
data_format: DataFormat,
}
let ts = vec![
T {
name_prefix: "h264",
data_format: DataFormat::H264,
},
T {
name_prefix: "hevc",
data_format: DataFormat::H265,
},
];
let mut e = vec![];
if let Some(info) = info {
ts.iter().for_each(|t| {
let codecs: Vec<_> = info
.codecs
.iter()
.filter(|c| {
c.is_encoder
&& c.mime_type.as_str() == get_mime_type(t.data_format)
&& c.nv12
&& c.hw == Some(true) //only use hardware codec
})
.collect();
log::debug!("available {:?} encoders: {codecs:?}", t.data_format);
let screen_wh = std::cmp::max(info.w, info.h);
let mut best = None;
if let Some(codec) = codecs
.iter()
.find(|c| c.max_width >= screen_wh && c.max_height >= screen_wh)
{
best = Some(codec.name.clone());
} else {
// find the max resolution
let mut max_area = 0;
for codec in codecs.iter() {
if codec.max_width * codec.max_height > max_area {
best = Some(codec.name.clone());
max_area = codec.max_width * codec.max_height;
}
}
}
if let Some(best) = best {
e.push(CodecInfo {
name: format!("{}_mediacodec", t.name_prefix),
mc_name: Some(best),
format: t.data_format,
hwdevice: hwcodec::ffmpeg::AVHWDeviceType::AV_HWDEVICE_TYPE_NONE,
priority: 0,
});
}
});
}
log::debug!("e: {e:?}");
Ok(Available { e, d: vec![] })
}
#[cfg(not(target_os = "android"))]
{
match serde_json::from_str(&HwCodecConfig::load().ram) {
Ok(v) => Ok(v),
Err(e) => Err(anyhow!("Failed to get config:{e:?}")),
}
}
}
#[cfg(target_os = "android")]
fn get_mime_type(codec: DataFormat) -> &'static str {
match codec {
@ -557,7 +476,181 @@ fn get_mime_type(codec: DataFormat) -> &'static str {
}
}
pub fn check_available_hwcodec() {
#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct HwCodecConfig {
#[serde(default)]
pub signature: u64,
#[serde(default)]
pub ram_encode: Vec<CodecInfo>,
#[serde(default)]
pub ram_decode: Vec<CodecInfo>,
#[cfg(feature = "vram")]
#[serde(default)]
pub vram_encode: Vec<hwcodec::vram::FeatureContext>,
#[cfg(feature = "vram")]
#[serde(default)]
pub vram_decode: Vec<hwcodec::vram::DecodeContext>,
}
// ipc server process start check process once, other process get from ipc server once
// install: --server start check process, check process send to --server, ui get from --server
// portable: ui start check process, check process send to ui
// sciter and unilink: get from ipc server
impl HwCodecConfig {
#[cfg(any(target_os = "windows", target_os = "linux"))]
pub fn set(config: String) {
let config = serde_json::from_str(&config).unwrap_or_default();
log::info!("set hwcodec config");
log::debug!("{config:?}");
#[cfg(windows)]
hbb_common::config::common_store(&config, "_hwcodec");
*CONFIG.lock().unwrap() = Some(config);
*CONFIG_SET_BY_IPC.lock().unwrap() = true;
}
pub fn get() -> HwCodecConfig {
#[cfg(target_os = "android")]
{
let info = crate::android::ffi::get_codec_info();
log::info!("all codec info: {info:?}");
struct T {
name_prefix: &'static str,
data_format: DataFormat,
}
let ts = vec![
T {
name_prefix: "h264",
data_format: DataFormat::H264,
},
T {
name_prefix: "hevc",
data_format: DataFormat::H265,
},
];
let mut e = vec![];
if let Some(info) = info {
ts.iter().for_each(|t| {
let codecs: Vec<_> = info
.codecs
.iter()
.filter(|c| {
c.is_encoder
&& c.mime_type.as_str() == get_mime_type(t.data_format)
&& c.nv12
&& c.hw == Some(true) //only use hardware codec
})
.collect();
let screen_wh = std::cmp::max(info.w, info.h);
let mut best = None;
if let Some(codec) = codecs
.iter()
.find(|c| c.max_width >= screen_wh && c.max_height >= screen_wh)
{
best = Some(codec.name.clone());
} else {
// find the max resolution
let mut max_area = 0;
for codec in codecs.iter() {
if codec.max_width * codec.max_height > max_area {
best = Some(codec.name.clone());
max_area = codec.max_width * codec.max_height;
}
}
}
if let Some(best) = best {
e.push(CodecInfo {
name: format!("{}_mediacodec", t.name_prefix),
mc_name: Some(best),
format: t.data_format,
hwdevice: hwcodec::ffmpeg::AVHWDeviceType::AV_HWDEVICE_TYPE_NONE,
priority: 0,
});
}
});
}
log::debug!("e: {e:?}");
HwCodecConfig {
ram_encode: e,
..Default::default()
}
}
#[cfg(windows)]
{
let config = CONFIG.lock().unwrap().clone();
match config {
Some(c) => c,
None => {
log::info!("try load cached hwcodec config");
let c = hbb_common::config::common_load::<HwCodecConfig>("_hwcodec");
let new_signature = get_gpu_signature();
if c.signature == new_signature {
log::debug!("load cached hwcodec config: {c:?}");
*CONFIG.lock().unwrap() = Some(c.clone());
c
} else {
log::info!(
"gpu signature changed, {} -> {}",
c.signature,
new_signature
);
HwCodecConfig::default()
}
}
}
}
#[cfg(target_os = "linux")]
{
CONFIG.lock().unwrap().clone().unwrap_or_default()
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
{
HwCodecConfig::default()
}
}
#[cfg(any(target_os = "windows", target_os = "linux"))]
pub fn get_set_value() -> Option<HwCodecConfig> {
let set = CONFIG_SET_BY_IPC.lock().unwrap().clone();
if set {
CONFIG.lock().unwrap().clone()
} else {
None
}
}
#[cfg(any(target_os = "windows", target_os = "linux"))]
pub fn already_set() -> bool {
CONFIG_SET_BY_IPC.lock().unwrap().clone()
}
pub fn clear(vram: bool, encode: bool) {
log::info!("clear hwcodec config, vram: {vram}, encode: {encode}");
#[cfg(target_os = "android")]
crate::android::ffi::clear_codec_info();
#[cfg(not(target_os = "android"))]
{
let mut c = CONFIG.lock().unwrap();
if let Some(c) = c.as_mut() {
if vram {
#[cfg(feature = "vram")]
if encode {
c.vram_encode = vec![];
} else {
c.vram_decode = vec![];
}
} else {
if encode {
c.ram_encode = vec![];
} else {
c.ram_decode = vec![];
}
}
}
}
}
}
pub fn check_available_hwcodec() -> String {
let ctx = EncodeContext {
name: String::from(""),
mc_name: None,
@ -575,29 +668,31 @@ pub fn check_available_hwcodec() {
};
#[cfg(feature = "vram")]
let vram = crate::vram::check_available_vram();
#[cfg(feature = "vram")]
let vram_string = vram.2;
#[cfg(not(feature = "vram"))]
let vram = "".to_owned();
let ram = Available {
e: Encoder::available_encoders(ctx, Some(vram.clone())),
d: Decoder::available_decoders(Some(vram.clone())),
let vram_string = "".to_owned();
let c = HwCodecConfig {
ram_encode: Encoder::available_encoders(ctx, Some(vram_string.clone())),
ram_decode: Decoder::available_decoders(Some(vram_string)),
#[cfg(feature = "vram")]
vram_encode: vram.0,
#[cfg(feature = "vram")]
vram_decode: vram.1,
signature: get_gpu_signature(),
};
if let Ok(ram) = serde_json::to_string_pretty(&ram) {
HwCodecConfig { ram, vram }.store();
}
log::debug!("{c:?}");
serde_json::to_string(&c).unwrap_or_default()
}
#[cfg(any(target_os = "windows", target_os = "linux"))]
pub fn start_check_process(force: bool) {
if !force && !enable_hwcodec_option() {
pub fn start_check_process() {
if !enable_hwcodec_option() || HwCodecConfig::already_set() {
return;
}
use hbb_common::allow_err;
use std::sync::Once;
let f = || {
// Clear to avoid checking process errors
// But when the program is just started, the configuration file has not been updated, and the new connection will read an empty configuration
// TODO: --server start multi times on windows startup, which will clear the last config and cause concurrent file writing
HwCodecConfig::clear();
if let Ok(exe) = std::env::current_exe() {
if let Some(_) = exe.file_name().to_owned() {
let arg = "--check-hwcodec-config";
@ -631,11 +726,7 @@ pub fn start_check_process(force: bool) {
};
};
static ONCE: Once = Once::new();
if force && ONCE.is_completed() {
ONCE.call_once(|| {
std::thread::spawn(f);
} else {
ONCE.call_once(|| {
std::thread::spawn(f);
});
}
});
}

View File

@ -6,6 +6,7 @@ use std::{
use crate::{
codec::{base_bitrate, enable_vram_option, EncoderApi, EncoderCfg, Quality},
hwcodec::HwCodecConfig,
AdapterDevice, CodecFormat, EncodeInput, EncodeYuvFormat, Pixfmt,
};
use hbb_common::{
@ -228,9 +229,8 @@ impl VRamEncoder {
CodecFormat::H265 => DataFormat::H265,
_ => return vec![],
};
let v: Vec<_> = get_available_config()
.map(|c| c.e)
.unwrap_or_default()
let v: Vec<_> = crate::hwcodec::HwCodecConfig::get()
.vram_encode
.drain(..)
.filter(|c| c.data_format == data_format)
.collect();
@ -339,9 +339,8 @@ impl VRamDecoder {
CodecFormat::H265 => DataFormat::H265,
_ => return vec![],
};
get_available_config()
.map(|c| c.d)
.unwrap_or_default()
crate::hwcodec::HwCodecConfig::get()
.vram_decode
.drain(..)
.filter(|c| c.data_format == data_format && c.luid == luid && luid != 0)
.collect()
@ -351,7 +350,7 @@ impl VRamDecoder {
if !enable_vram_option() {
return (false, false);
}
let v = get_available_config().map(|c| c.d).unwrap_or_default();
let v = crate::hwcodec::HwCodecConfig::get().vram_decode;
(
v.iter().any(|d| d.data_format == DataFormat::H264),
v.iter().any(|d| d.data_format == DataFormat::H265),
@ -364,7 +363,7 @@ impl VRamDecoder {
match Decoder::new(ctx) {
Ok(decoder) => Ok(Self { decoder }),
Err(_) => {
hbb_common::config::HwCodecConfig::clear_vram();
HwCodecConfig::clear(true, false);
Err(anyhow!(format!(
"Failed to create decoder, format: {:?}",
format
@ -386,15 +385,7 @@ pub struct VRamDecoderImage<'a> {
impl VRamDecoderImage<'_> {}
fn get_available_config() -> ResultType<Available> {
let available = hbb_common::config::HwCodecConfig::load().vram;
match Available::deserialize(&available) {
Ok(v) => Ok(v),
Err(_) => Err(anyhow!("Failed to deserialize:{}", available)),
}
}
pub(crate) fn check_available_vram() -> String {
pub(crate) fn check_available_vram() -> (Vec<FeatureContext>, Vec<DecodeContext>, String) {
let d = DynamicContext {
device: None,
width: 1280,
@ -406,8 +397,12 @@ pub(crate) fn check_available_vram() -> String {
let encoders = encode::available(d);
let decoders = decode::available();
let available = Available {
e: encoders,
d: decoders,
e: encoders.clone(),
d: decoders.clone(),
};
available.serialize().unwrap_or_default()
(
encoders,
decoders,
available.serialize().unwrap_or_default(),
)
}

View File

@ -2132,6 +2132,7 @@ where
std::thread::spawn(move || {
#[cfg(windows)]
sync_cpu_usage();
get_hwcodec_config();
let mut handler_controller_map = HashMap::new();
// let mut count = Vec::new();
// let mut duration = std::time::Duration::ZERO;
@ -2333,6 +2334,27 @@ pub fn start_audio_thread() -> MediaSender {
audio_sender
}
fn get_hwcodec_config() {
// for sciter and unilink
#[cfg(feature = "hwcodec")]
#[cfg(any(target_os = "windows", target_os = "linux"))]
{
use std::sync::Once;
static ONCE: Once = Once::new();
ONCE.call_once(|| {
let start = std::time::Instant::now();
if let Err(e) = crate::ipc::get_hwcodec_config_from_server() {
log::error!(
"failed to get hwcodec config: {e:?}, elapsed: {:?}",
start.elapsed()
);
} else {
log::info!("{:?} used to get hwcodec config", start.elapsed());
}
});
}
}
#[cfg(windows)]
fn sync_cpu_usage() {
use std::sync::Once;

View File

@ -412,7 +412,7 @@ pub fn core_main() -> Option<Vec<String>> {
return None;
} else if args[0] == "--check-hwcodec-config" {
#[cfg(feature = "hwcodec")]
scrap::hwcodec::check_available_hwcodec();
crate::ipc::hwcodec_process();
return None;
} else if args[0] == "--cm" {
// call connection manager to establish connections

View File

@ -239,6 +239,7 @@ pub enum Data {
VideoConnCount(Option<usize>),
// Although the key is not neccessary, it is used to avoid hardcoding the key.
WaylandScreencastRestoreToken((String, String)),
HwCodecConfig(Option<String>),
}
#[tokio::main(flavor = "current_thread")]
@ -523,12 +524,26 @@ async fn handle(data: Data, stream: &mut Connection) {
.await
);
}
Data::CheckHwcodec =>
{
#[cfg(feature = "hwcodec")]
#[cfg(any(target_os = "windows", target_os = "linux"))]
if crate::platform::is_root() {
scrap::hwcodec::start_check_process(true);
#[cfg(feature = "hwcodec")]
#[cfg(any(target_os = "windows", target_os = "linux"))]
Data::CheckHwcodec => {
scrap::hwcodec::start_check_process();
}
#[cfg(feature = "hwcodec")]
#[cfg(any(target_os = "windows", target_os = "linux"))]
Data::HwCodecConfig(c) => {
match c {
None => {
let v = match scrap::hwcodec::HwCodecConfig::get_set_value() {
Some(v) => Some(serde_json::to_string(&v).unwrap_or_default()),
None => None,
};
allow_err!(stream.send(&Data::HwCodecConfig(v)).await);
}
Some(v) => {
// --server and portable
scrap::hwcodec::HwCodecConfig::set(v);
}
}
}
Data::WaylandScreencastRestoreToken((key, value)) => {
@ -1025,6 +1040,83 @@ pub async fn notify_server_to_check_hwcodec() -> ResultType<()> {
Ok(())
}
#[cfg(feature = "hwcodec")]
#[cfg(any(target_os = "windows", target_os = "linux"))]
#[tokio::main(flavor = "current_thread")]
pub async fn get_hwcodec_config_from_server() -> ResultType<()> {
if !scrap::codec::enable_hwcodec_option() || scrap::hwcodec::HwCodecConfig::already_set() {
return Ok(());
}
let mut c = connect(50, "").await?;
c.send(&Data::HwCodecConfig(None)).await?;
if let Some(Data::HwCodecConfig(v)) = c.next_timeout(50).await? {
match v {
Some(v) => {
scrap::hwcodec::HwCodecConfig::set(v);
return Ok(());
}
None => {
bail!("hwcodec config is none");
}
}
}
bail!("failed to get hwcodec config");
}
#[cfg(feature = "hwcodec")]
#[cfg(any(target_os = "windows", target_os = "linux"))]
pub fn client_get_hwcodec_config_thread(wait_sec: u64) {
static ONCE: std::sync::Once = std::sync::Once::new();
if !crate::platform::is_installed()
|| !scrap::codec::enable_hwcodec_option()
|| scrap::hwcodec::HwCodecConfig::already_set()
{
return;
}
ONCE.call_once(move || {
std::thread::spawn(move || {
std::thread::sleep(std::time::Duration::from_secs(1));
let mut intervals: Vec<u64> = vec![wait_sec, 3, 3, 6, 9];
for i in intervals.drain(..) {
if i > 0 {
std::thread::sleep(std::time::Duration::from_secs(i));
}
if get_hwcodec_config_from_server().is_ok() {
break;
}
}
});
});
}
#[cfg(feature = "hwcodec")]
#[tokio::main(flavor = "current_thread")]
pub async fn hwcodec_process() {
let s = scrap::hwcodec::check_available_hwcodec();
for _ in 0..5 {
match crate::ipc::connect(1000, "").await {
Ok(mut conn) => {
match conn
.send(&crate::ipc::Data::HwCodecConfig(Some(s.clone())))
.await
{
Ok(()) => {
log::info!("send ok");
break;
}
Err(e) => {
log::error!("send failed: {e:?}");
}
}
}
Err(e) => {
log::error!("connect failed: {e:?}");
}
}
std::thread::sleep(std::time::Duration::from_secs(1));
}
}
#[tokio::main(flavor = "current_thread")]
pub async fn get_wayland_screencast_restore_token(key: String) -> ResultType<String> {
let v = handle_wayland_screencast_restore_token(key, "get".to_owned()).await?;

View File

@ -459,9 +459,6 @@ pub async fn start_server(is_server: bool) {
log::info!("DISPLAY={:?}", std::env::var("DISPLAY"));
log::info!("XAUTHORITY={:?}", std::env::var("XAUTHORITY"));
}
#[cfg(feature = "hwcodec")]
#[cfg(any(target_os = "windows", target_os = "linux"))]
scrap::hwcodec::start_check_process(false);
#[cfg(windows)]
hbb_common::platform::windows::start_cpu_performance_monitor();
@ -489,6 +486,9 @@ pub async fn start_server(is_server: bool) {
tokio::spawn(async { sync_and_watch_config_dir().await });
#[cfg(target_os = "windows")]
crate::platform::try_kill_broker();
#[cfg(feature = "hwcodec")]
#[cfg(any(target_os = "windows", target_os = "linux"))]
scrap::hwcodec::start_check_process();
crate::RendezvousMediator::start_all().await;
} else {
match crate::ipc::connect(1000, "").await {
@ -509,6 +509,9 @@ pub async fn start_server(is_server: bool) {
}
}
}
#[cfg(feature = "hwcodec")]
#[cfg(any(target_os = "windows", target_os = "linux"))]
crate::ipc::client_get_hwcodec_config_thread(0);
}
Err(err) => {
log::info!("server not started (will try to start): {}", err);

View File

@ -172,15 +172,13 @@ pub fn get_option<T: AsRef<str>>(key: T) -> String {
#[inline]
#[cfg(target_os = "macos")]
pub fn use_texture_render() -> bool {
cfg!(feature = "flutter")
&& LocalConfig::get_option(config::keys::OPTION_TEXTURE_RENDER) == "Y"
cfg!(feature = "flutter") && LocalConfig::get_option(config::keys::OPTION_TEXTURE_RENDER) == "Y"
}
#[inline]
#[cfg(any(target_os = "windows", target_os = "linux"))]
pub fn use_texture_render() -> bool {
cfg!(feature = "flutter")
&& LocalConfig::get_option(config::keys::OPTION_TEXTURE_RENDER) != "N"
cfg!(feature = "flutter") && LocalConfig::get_option(config::keys::OPTION_TEXTURE_RENDER) != "N"
}
#[inline]
@ -1398,9 +1396,16 @@ pub fn check_hwcodec() {
#[cfg(feature = "hwcodec")]
#[cfg(any(target_os = "windows", target_os = "linux"))]
{
scrap::hwcodec::start_check_process(true);
if crate::platform::is_installed() {
ipc::notify_server_to_check_hwcodec().ok();
}
use std::sync::Once;
static ONCE: Once = Once::new();
ONCE.call_once(|| {
if crate::platform::is_installed() {
ipc::notify_server_to_check_hwcodec().ok();
ipc::client_get_hwcodec_config_thread(3);
} else {
scrap::hwcodec::start_check_process();
}
})
}
}