diff --git a/Cargo.lock b/Cargo.lock index 47c302543..4fa0162a7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2673,6 +2673,7 @@ version = "0.5.0" dependencies = [ "anyhow", "async-trait", + "bytes", "ironrdp-acceptor", "ironrdp-ainput", "ironrdp-async", diff --git a/crates/ironrdp-bench/benches/bench.rs b/crates/ironrdp-bench/benches/bench.rs index 428493c5c..1d8a38306 100644 --- a/crates/ironrdp-bench/benches/bench.rs +++ b/crates/ironrdp-bench/benches/bench.rs @@ -10,13 +10,12 @@ pub fn rfx_enc_tile_bench(c: &mut Criterion) { let quant = rfx::Quant::default(); let algo = rfx::EntropyAlgorithm::Rlgr3; let bitmap = BitmapUpdate { - top: 0, - left: 0, + x: 0, + y: 0, width: NonZero::new(64).unwrap(), height: NonZero::new(64).unwrap(), format: ironrdp_server::PixelFormat::ARgb32, - data: vec![0; 64 * 64 * 4], - order: ironrdp_server::PixelOrder::BottomToTop, + data: vec![0; 64 * 64 * 4].into(), stride: 64 * 4, }; c.bench_function("rfx_enc_tile", |b| b.iter(|| rfx_enc_tile(&bitmap, &quant, algo, 0, 0))); @@ -26,13 +25,12 @@ pub fn rfx_enc_bench(c: &mut Criterion) { let quant = rfx::Quant::default(); let algo = rfx::EntropyAlgorithm::Rlgr3; let bitmap = BitmapUpdate { - top: 0, - left: 0, + x: 0, + y: 0, width: NonZero::new(2048).unwrap(), height: NonZero::new(2048).unwrap(), format: ironrdp_server::PixelFormat::ARgb32, - data: vec![0; 2048 * 2048 * 4], - order: ironrdp_server::PixelOrder::BottomToTop, + data: vec![0; 2048 * 2048 * 4].into(), stride: 64 * 4, }; c.bench_function("rfx_enc", |b| b.iter(|| rfx_enc(&bitmap, &quant, algo))); diff --git a/crates/ironrdp-server/Cargo.toml b/crates/ironrdp-server/Cargo.toml index aba6e3d33..e2a26728e 100644 --- a/crates/ironrdp-server/Cargo.toml +++ b/crates/ironrdp-server/Cargo.toml @@ -45,6 +45,7 @@ tracing = { version = "0.1", features = ["log"] } x509-cert = { version = "0.2.5", optional = true } rustls-pemfile = { version = "2.2.0", optional = true } rayon = { version = "1.10.0", optional = true } +bytes = "1" [dev-dependencies] tokio = { version = "1", features = ["sync"] } diff --git a/crates/ironrdp-server/src/display.rs b/crates/ironrdp-server/src/display.rs index 1f825e5e2..4101aedc0 100644 --- a/crates/ironrdp-server/src/display.rs +++ b/crates/ironrdp-server/src/display.rs @@ -1,6 +1,7 @@ use core::num::NonZeroU16; use anyhow::Result; +use bytes::{Bytes, BytesMut}; use ironrdp_displaycontrol::pdu::DisplayControlMonitorLayout; use ironrdp_pdu::pointer::PointerPositionAttribute; @@ -24,12 +25,6 @@ pub enum DisplayUpdate { DefaultPointer, } -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum PixelOrder { - TopToBottom, - BottomToTop, -} - #[derive(Clone)] pub struct RGBAPointer { pub width: u16, @@ -61,6 +56,30 @@ pub struct ColorPointer { pub xor_mask: Vec, } +pub struct Framebuffer { + pub width: NonZeroU16, + pub height: NonZeroU16, + pub format: PixelFormat, + pub data: BytesMut, + pub stride: usize, +} + +impl TryInto for BitmapUpdate { + type Error = &'static str; + + fn try_into(self) -> Result { + assert_eq!(self.x, 0); + assert_eq!(self.y, 0); + Ok(Framebuffer { + width: self.width, + height: self.height, + format: self.format, + data: self.data.try_into_mut().map_err(|_| "BitmapUpdate is shared")?, + stride: self.stride, + }) + } +} + /// Bitmap Display Update /// /// Bitmap updates are encoded using RDP 6.0 compression, fragmented and sent using @@ -68,25 +87,80 @@ pub struct ColorPointer { /// #[derive(Clone)] pub struct BitmapUpdate { - pub top: u16, - pub left: u16, + pub x: u16, + pub y: u16, pub width: NonZeroU16, pub height: NonZeroU16, pub format: PixelFormat, - pub order: PixelOrder, - pub data: Vec, + pub data: Bytes, pub stride: usize, } +impl BitmapUpdate { + /// Extracts a sub-region of the bitmap update. + /// + /// # Parameters + /// + /// - `x`: The x-coordinate of the top-left corner of the sub-region. + /// - `y`: The y-coordinate of the top-left corner of the sub-region. + /// - `width`: The width of the sub-region. + /// - `height`: The height of the sub-region. + /// + /// # Returns + /// + /// An `Option` containing a new `BitmapUpdate` representing the sub-region if the specified + /// dimensions are within the bounds of the original bitmap update, otherwise `None`. + /// + /// # Example + /// + /// ``` + /// # use core::num::NonZeroU16; + /// # use bytes::Bytes; + /// # use ironrdp_graphics::image_processing::PixelFormat; + /// # use ironrdp_server::BitmapUpdate; + /// let original = BitmapUpdate { + /// x: 0, + /// y: 0, + /// width: NonZeroU16::new(100).unwrap(), + /// height: NonZeroU16::new(100).unwrap(), + /// format: PixelFormat::ARgb32, + /// data: Bytes::from(vec![0; 40000]), + /// stride: 400, + /// }; + /// + /// let sub_region = original.sub(10, 10, NonZeroU16::new(50).unwrap(), NonZeroU16::new(50).unwrap()); + /// assert!(sub_region.is_some()); + /// ``` + #[must_use] + pub fn sub(&self, x: u16, y: u16, width: NonZeroU16, height: NonZeroU16) -> Option { + if x + width.get() > self.width.get() || y + height.get() > self.height.get() { + None + } else { + let bpp = usize::from(self.format.bytes_per_pixel()); + let start = usize::from(y) * self.stride + usize::from(x) * bpp; + let end = start + usize::from(height.get() - 1) * self.stride + usize::from(width.get()) * bpp; + Some(Self { + x: self.x + x, + y: self.y + y, + width, + height, + format: self.format, + data: self.data.slice(start..end), + stride: self.stride, + }) + } + } +} + impl core::fmt::Debug for BitmapUpdate { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("BitmapUpdate") - .field("top", &self.top) - .field("left", &self.left) + .field("x", &self.x) + .field("y", &self.y) .field("width", &self.width) .field("height", &self.height) .field("format", &self.format) - .field("order", &self.order) + .field("stride", &self.stride) .finish() } } diff --git a/crates/ironrdp-server/src/encoder/bitmap.rs b/crates/ironrdp-server/src/encoder/bitmap.rs index c502cdf34..71a1ec17a 100644 --- a/crates/ironrdp-server/src/encoder/bitmap.rs +++ b/crates/ironrdp-server/src/encoder/bitmap.rs @@ -4,7 +4,7 @@ use ironrdp_graphics::rdp6::{ABgrChannels, ARgbChannels, BgrAChannels, BitmapStr use ironrdp_pdu::bitmap::{self, BitmapData, BitmapUpdateData, Compression}; use ironrdp_pdu::geometry::InclusiveRectangle; -use crate::{BitmapUpdate, PixelOrder}; +use crate::BitmapUpdate; // PERF: we could also remove the need for this buffer pub(crate) struct BitmapEncoder { @@ -39,31 +39,25 @@ impl BitmapEncoder { for (i, chunk) in chunks.enumerate() { let height = chunk.len() / bitmap.stride; - let top = usize::from(bitmap.top) + i * chunk_height; + let top = usize::from(bitmap.y) + i * chunk_height; let encoder = BitmapStreamEncoder::new(usize::from(bitmap.width.get()), height); - let len = match bitmap.order { - PixelOrder::BottomToTop => { - Self::encode_slice(encoder, bitmap.format, &chunk[..row_len], self.buffer.as_mut_slice()) - } + let len = { + let pixels = chunk + .chunks(bitmap.stride) + .map(|row| &row[..row_len]) + .rev() + .flat_map(|row| row.chunks(bytes_per_pixel)); - PixelOrder::TopToBottom => { - let pixels = chunk - .chunks(bitmap.stride) - .map(|row| &row[..row_len]) - .rev() - .flat_map(|row| row.chunks(bytes_per_pixel)); - - Self::encode_iter(encoder, bitmap.format, pixels, self.buffer.as_mut_slice()) - } + Self::encode_iter(encoder, bitmap.format, pixels, self.buffer.as_mut_slice()) }; let data = BitmapData { rectangle: InclusiveRectangle { - left: bitmap.left, + left: bitmap.x, top: u16::try_from(top).unwrap(), - right: bitmap.left + bitmap.width.get() - 1, + right: bitmap.x + bitmap.width.get() - 1, bottom: u16::try_from(top + height - 1).unwrap(), }, width: u16::from(bitmap.width), @@ -84,15 +78,6 @@ impl BitmapEncoder { Ok(cursor.pos()) } - fn encode_slice(mut encoder: BitmapStreamEncoder, format: PixelFormat, src: &[u8], dst: &mut [u8]) -> usize { - match format { - PixelFormat::ARgb32 | PixelFormat::XRgb32 => encoder.encode_bitmap::(src, dst, true).unwrap(), - PixelFormat::RgbA32 | PixelFormat::RgbX32 => encoder.encode_bitmap::(src, dst, true).unwrap(), - PixelFormat::ABgr32 | PixelFormat::XBgr32 => encoder.encode_bitmap::(src, dst, true).unwrap(), - PixelFormat::BgrA32 | PixelFormat::BgrX32 => encoder.encode_bitmap::(src, dst, true).unwrap(), - } - } - fn encode_iter<'a, P>(mut encoder: BitmapStreamEncoder, format: PixelFormat, src: P, dst: &mut [u8]) -> usize where P: Iterator + Clone, diff --git a/crates/ironrdp-server/src/encoder/mod.rs b/crates/ironrdp-server/src/encoder/mod.rs index 9fa7f29a7..fffddea3f 100644 --- a/crates/ironrdp-server/src/encoder/mod.rs +++ b/crates/ironrdp-server/src/encoder/mod.rs @@ -1,9 +1,10 @@ mod bitmap; pub(crate) mod rfx; -use core::{cmp, mem}; +use core::{cmp, fmt}; use anyhow::{Context, Result}; +use ironrdp_acceptor::DesktopSize; use ironrdp_core::{Encode, WriteCursor}; use ironrdp_pdu::fast_path::{EncryptionFlags, FastPathHeader, FastPathUpdatePdu, Fragmentation, UpdateCode}; use ironrdp_pdu::geometry::ExclusiveRectangle; @@ -14,7 +15,7 @@ use ironrdp_pdu::surface_commands::{ExtendedBitmapDataPdu, SurfaceBitsPdu, Surfa use self::bitmap::BitmapEncoder; use self::rfx::RfxEncoder; use super::BitmapUpdate; -use crate::{ColorPointer, PixelOrder, RGBAPointer}; +use crate::{ColorPointer, Framebuffer, RGBAPointer}; #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(u8)] @@ -28,45 +29,43 @@ const MAX_FASTPATH_UPDATE_SIZE: usize = 16_374; const FASTPATH_HEADER_SIZE: usize = 6; pub(crate) struct UpdateEncoder { - buffer: Vec, - bitmap: BitmapEncoder, - remotefx: Option<(RfxEncoder, u8)>, - update: for<'a> fn(&'a mut UpdateEncoder, BitmapUpdate) -> Result>, + desktop_size: DesktopSize, + // FIXME: draw updates on the framebuffer + framebuffer: Option, + pdu_encoder: PduEncoder, + bitmap_updater: BitmapUpdater, +} + +impl fmt::Debug for UpdateEncoder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("UpdateEncoder") + .field("bitmap_update", &self.bitmap_updater) + .finish() + } } impl UpdateEncoder { - pub(crate) fn new(surface_flags: CmdFlags, remotefx: Option<(EntropyBits, u8)>) -> Self { - let update = if !surface_flags.contains(CmdFlags::SET_SURFACE_BITS) { - Self::bitmap_update + pub(crate) fn new(desktop_size: DesktopSize, surface_flags: CmdFlags, remotefx: Option<(EntropyBits, u8)>) -> Self { + let pdu_encoder = PduEncoder::new(); + let bitmap_updater = if !surface_flags.contains(CmdFlags::SET_SURFACE_BITS) { + BitmapUpdater::Bitmap(BitmapHandler::new()) } else if remotefx.is_some() { - Self::remotefx_update + let (algo, id) = remotefx.unwrap(); + BitmapUpdater::RemoteFx(RemoteFxHandler::new(algo, id)) } else { - Self::none_update + BitmapUpdater::None(NoneHandler) }; Self { - buffer: vec![0; 16384], - bitmap: BitmapEncoder::new(), - remotefx: remotefx.map(|(algo, id)| (RfxEncoder::new(algo), id)), - update, + desktop_size, + framebuffer: None, + pdu_encoder, + bitmap_updater, } } - fn encode_pdu(&mut self, pdu: impl Encode) -> Result { - loop { - let mut cursor = WriteCursor::new(self.buffer.as_mut_slice()); - match pdu.encode(&mut cursor) { - Err(e) => match e.kind() { - ironrdp_core::EncodeErrorKind::NotEnoughBytes { .. } => { - self.buffer.resize(self.buffer.len() * 2, 0); - debug!("encoder buffer resized to: {}", self.buffer.len() * 2); - } - - _ => Err(e).context("PDU encode error")?, - }, - Ok(()) => return Ok(cursor.pos()), - } - } + pub(crate) fn set_desktop_size(&mut self, size: DesktopSize) { + self.desktop_size = size; } pub(crate) fn rgba_pointer(&mut self, ptr: RGBAPointer) -> Result> { @@ -88,8 +87,8 @@ impl UpdateEncoder { xor_bpp: 32, color_pointer, }; - let len = self.encode_pdu(ptr)?; - Ok(UpdateFragmenter::new(UpdateCode::NewPointer, &self.buffer[..len])) + let buf = self.pdu_encoder.encode(ptr)?; + Ok(UpdateFragmenter::new(UpdateCode::NewPointer, buf)) } pub(crate) fn color_pointer(&mut self, ptr: ColorPointer) -> Result> { @@ -105,8 +104,8 @@ impl UpdateEncoder { xor_mask: &ptr.xor_mask, and_mask: &ptr.and_mask, }; - let len = self.encode_pdu(ptr)?; - Ok(UpdateFragmenter::new(UpdateCode::ColorPointer, &self.buffer[..len])) + let buf = self.pdu_encoder.encode(ptr)?; + Ok(UpdateFragmenter::new(UpdateCode::ColorPointer, buf)) } #[allow(clippy::unused_self)] @@ -120,31 +119,95 @@ impl UpdateEncoder { } pub(crate) fn pointer_position(&mut self, pos: PointerPositionAttribute) -> Result> { - let len = self.encode_pdu(pos)?; - Ok(UpdateFragmenter::new(UpdateCode::PositionPointer, &self.buffer[..len])) + let buf = self.pdu_encoder.encode(pos)?; + Ok(UpdateFragmenter::new(UpdateCode::PositionPointer, buf)) } pub(crate) fn bitmap(&mut self, bitmap: BitmapUpdate) -> Result> { - let update = self.update; - - update(self, bitmap) + let res = self.bitmap_updater.handle(&bitmap, &mut self.pdu_encoder); + if bitmap.x == 0 + && bitmap.y == 0 + && bitmap.width.get() == self.desktop_size.width + && bitmap.height.get() == self.desktop_size.height + { + match bitmap.try_into() { + Ok(framebuffer) => self.framebuffer = Some(framebuffer), + Err(err) => warn!("Failed to convert bitmap to framebuffer: {}", err), + } + } + res } pub(crate) fn fragmenter_from_owned(&self, res: UpdateFragmenterOwned) -> UpdateFragmenter<'_> { UpdateFragmenter { code: res.code, index: res.index, - data: &self.buffer[0..res.len], + data: &self.pdu_encoder.buffer[0..res.len], } } +} + +#[derive(Debug)] +enum BitmapUpdater { + None(NoneHandler), + Bitmap(BitmapHandler), + RemoteFx(RemoteFxHandler), +} + +impl BitmapUpdater { + fn handle<'a>(&mut self, bitmap: &BitmapUpdate, encoder: &'a mut PduEncoder) -> Result> { + match self { + Self::None(up) => up.handle(bitmap, encoder), + Self::Bitmap(up) => up.handle(bitmap, encoder), + Self::RemoteFx(up) => up.handle(bitmap, encoder), + } + } +} - fn bitmap_update(&mut self, bitmap: BitmapUpdate) -> Result> { +trait BitmapUpdateHandler { + fn handle<'a>(&mut self, bitmap: &BitmapUpdate, encoder: &'a mut PduEncoder) -> Result>; +} + +#[derive(Debug)] +struct NoneHandler; + +impl BitmapUpdateHandler for NoneHandler { + fn handle<'a>(&mut self, bitmap: &BitmapUpdate, encoder: &'a mut PduEncoder) -> Result> { + let stride = usize::from(bitmap.format.bytes_per_pixel()) * usize::from(bitmap.width.get()); + let mut data = Vec::with_capacity(stride * usize::from(bitmap.height.get())); + for row in bitmap.data.chunks(bitmap.stride).rev() { + data.extend_from_slice(&row[..stride]); + } + encoder.set_surface(bitmap, CodecId::None as u8, &data) + } +} + +struct BitmapHandler { + bitmap: BitmapEncoder, +} + +impl fmt::Debug for BitmapHandler { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("BitmapHandler").finish() + } +} + +impl BitmapHandler { + fn new() -> Self { + Self { + bitmap: BitmapEncoder::new(), + } + } +} + +impl BitmapUpdateHandler for BitmapHandler { + fn handle<'a>(&mut self, bitmap: &BitmapUpdate, encoder: &'a mut PduEncoder) -> Result> { let len = loop { - match self.bitmap.encode(&bitmap, self.buffer.as_mut_slice()) { + match self.bitmap.encode(bitmap, encoder.buffer.as_mut_slice()) { Err(e) => match e.kind() { ironrdp_core::EncodeErrorKind::NotEnoughBytes { .. } => { - self.buffer.resize(self.buffer.len() * 2, 0); - debug!("encoder buffer resized to: {}", self.buffer.len() * 2); + encoder.buffer.resize(encoder.buffer.len() * 2, 0); + debug!("encoder buffer resized to: {}", encoder.buffer.len() * 2); } _ => Err(e).context("bitmap encode error")?, @@ -153,43 +216,34 @@ impl UpdateEncoder { } }; - Ok(UpdateFragmenter::new(UpdateCode::Bitmap, &self.buffer[..len])) + Ok(UpdateFragmenter::new(UpdateCode::Bitmap, &encoder.buffer[..len])) } +} - fn set_surface(&mut self, bitmap: BitmapUpdate, codec_id: u8, data: &[u8]) -> Result> { - let destination = ExclusiveRectangle { - left: bitmap.left, - top: bitmap.top, - right: bitmap.left + bitmap.width.get(), - bottom: bitmap.top + bitmap.height.get(), - }; - let extended_bitmap_data = ExtendedBitmapDataPdu { - bpp: bitmap.format.bytes_per_pixel() * 8, - width: bitmap.width.get(), - height: bitmap.height.get(), +#[derive(Debug)] +struct RemoteFxHandler { + remotefx: RfxEncoder, + codec_id: u8, +} + +impl RemoteFxHandler { + fn new(algo: EntropyBits, codec_id: u8) -> Self { + Self { + remotefx: RfxEncoder::new(algo), codec_id, - header: None, - data, - }; - let pdu = SurfaceBitsPdu { - destination, - extended_bitmap_data, - }; - let cmd = SurfaceCommand::SetSurfaceBits(pdu); - let len = self.encode_pdu(cmd)?; - Ok(UpdateFragmenter::new(UpdateCode::SurfaceCommands, &self.buffer[..len])) + } } +} - fn remotefx_update(&mut self, bitmap: BitmapUpdate) -> Result> { - let (remotefx, codec_id) = self.remotefx.as_mut().unwrap(); - let codec_id = *codec_id; +impl BitmapUpdateHandler for RemoteFxHandler { + fn handle<'a>(&mut self, bitmap: &BitmapUpdate, encoder: &'a mut PduEncoder) -> Result> { let mut buffer = vec![0; bitmap.data.len()]; let len = loop { - match remotefx.encode(&bitmap, buffer.as_mut_slice()) { + match self.remotefx.encode(bitmap, buffer.as_mut_slice()) { Err(e) => match e.kind() { ironrdp_core::EncodeErrorKind::NotEnoughBytes { .. } => { buffer.resize(buffer.len() * 2, 0); - debug!("encoder buffer resized to: {}", self.buffer.len() * 2); + debug!("encoder buffer resized to: {}", buffer.len() * 2); } _ => Err(e).context("RemoteFX encode error")?, @@ -198,33 +252,60 @@ impl UpdateEncoder { } }; - self.set_surface(bitmap, codec_id, &buffer[..len]) + encoder.set_surface(bitmap, self.codec_id, &buffer[..len]) } +} - fn none_update(&mut self, mut bitmap: BitmapUpdate) -> Result> { - let stride = usize::from(bitmap.format.bytes_per_pixel()) * usize::from(bitmap.width.get()); - let data = match bitmap.order { - PixelOrder::BottomToTop => { - if stride == bitmap.stride { - mem::take(&mut bitmap.data) - } else { - let mut data = Vec::with_capacity(stride * usize::from(bitmap.height.get())); - for row in bitmap.data.chunks(bitmap.stride) { - data.extend_from_slice(&row[..stride]); +struct PduEncoder { + buffer: Vec, +} + +impl PduEncoder { + fn new() -> Self { + Self { buffer: vec![0; 16384] } + } + + fn encode(&mut self, pdu: impl Encode) -> Result<&[u8]> { + let pos = loop { + let mut cursor = WriteCursor::new(self.buffer.as_mut_slice()); + match pdu.encode(&mut cursor) { + Err(e) => match e.kind() { + ironrdp_core::EncodeErrorKind::NotEnoughBytes { .. } => { + self.buffer.resize(self.buffer.len() * 2, 0); + debug!("encoder buffer resized to: {}", self.buffer.len() * 2); } - data - } - } - PixelOrder::TopToBottom => { - let mut data = Vec::with_capacity(stride * usize::from(bitmap.height.get())); - for row in bitmap.data.chunks(bitmap.stride).rev() { - data.extend_from_slice(&row[..stride]); - } - data + + _ => Err(e).context("PDU encode error")?, + }, + Ok(()) => break cursor.pos(), } }; - self.set_surface(bitmap, CodecId::None as u8, &data) + Ok(&self.buffer[..pos]) + } + + fn set_surface(&mut self, bitmap: &BitmapUpdate, codec_id: u8, data: &[u8]) -> Result> { + let destination = ExclusiveRectangle { + left: bitmap.x, + top: bitmap.y, + right: bitmap.x + bitmap.width.get(), + bottom: bitmap.y + bitmap.height.get(), + }; + let extended_bitmap_data = ExtendedBitmapDataPdu { + bpp: bitmap.format.bytes_per_pixel() * 8, + width: bitmap.width.get(), + height: bitmap.height.get(), + codec_id, + header: None, + data, + }; + let pdu = SurfaceBitsPdu { + destination, + extended_bitmap_data, + }; + let cmd = SurfaceCommand::SetSurfaceBits(pdu); + let buf = self.encode(cmd)?; + Ok(UpdateFragmenter::new(UpdateCode::SurfaceCommands, buf)) } } @@ -240,6 +321,14 @@ pub(crate) struct UpdateFragmenter<'a> { data: &'a [u8], } +impl fmt::Debug for UpdateFragmenter<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("UpdateFragmenter") + .field("len", &self.data.len()) + .finish() + } +} + impl<'a> UpdateFragmenter<'a> { pub(crate) fn new(code: UpdateCode, data: &'a [u8]) -> Self { Self { code, index: 0, data } diff --git a/crates/ironrdp-server/src/server.rs b/crates/ironrdp-server/src/server.rs index 854b0923f..402dfa35b 100644 --- a/crates/ironrdp-server/src/server.rs +++ b/crates/ironrdp-server/src/server.rs @@ -436,6 +436,7 @@ impl RdpServer { DisplayUpdate::PointerPosition(pos) => encoder.pointer_position(pos), DisplayUpdate::Resize(desktop_size) => { debug!(?desktop_size, "Display resize"); + encoder.set_desktop_size(desktop_size); deactivate_all(io_channel_id, user_channel_id, writer).await?; return Ok((RunState::DeactivationReactivation { desktop_size }, encoder)); } @@ -741,7 +742,8 @@ impl RdpServer { } } - let encoder = UpdateEncoder::new(surface_flags, rfxcodec); + let desktop_size = self.display.lock().await.size().await; + let encoder = UpdateEncoder::new(desktop_size, surface_flags, rfxcodec); let state = self .client_loop(reader, writer, result.io_channel_id, result.user_channel_id, encoder) diff --git a/crates/ironrdp/examples/server.rs b/crates/ironrdp/examples/server.rs index 7d0453cea..873158b58 100644 --- a/crates/ironrdp/examples/server.rs +++ b/crates/ironrdp/examples/server.rs @@ -20,8 +20,8 @@ use ironrdp::server::tokio::sync::mpsc::UnboundedSender; use ironrdp::server::tokio::time::{self, sleep, Duration}; use ironrdp::server::{ tokio, BitmapUpdate, CliprdrServerFactory, Credentials, DisplayUpdate, KeyboardEvent, MouseEvent, PixelFormat, - PixelOrder, RdpServer, RdpServerDisplay, RdpServerDisplayUpdates, RdpServerInputHandler, ServerEvent, - ServerEventSender, SoundServerFactory, TlsIdentityCtx, + RdpServer, RdpServerDisplay, RdpServerDisplayUpdates, RdpServerInputHandler, ServerEvent, ServerEventSender, + SoundServerFactory, TlsIdentityCtx, }; use ironrdp_cliprdr_native::StubCliprdrBackend; use rand::prelude::*; @@ -159,10 +159,10 @@ impl RdpServerDisplayUpdates for DisplayUpdates { sleep(Duration::from_millis(100)).await; let mut rng = thread_rng(); - let top: u16 = rng.gen_range(0..HEIGHT); - let height = NonZeroU16::new(rng.gen_range(1..=HEIGHT.checked_sub(top).unwrap())).unwrap(); - let left: u16 = rng.gen_range(0..WIDTH); - let width = NonZeroU16::new(rng.gen_range(1..=WIDTH.checked_sub(left).unwrap())).unwrap(); + let y: u16 = rng.gen_range(0..HEIGHT); + let height = NonZeroU16::new(rng.gen_range(1..=HEIGHT.checked_sub(y).unwrap())).unwrap(); + let x: u16 = rng.gen_range(0..WIDTH); + let width = NonZeroU16::new(rng.gen_range(1..=WIDTH.checked_sub(x).unwrap())).unwrap(); let capacity = usize::from(width.get()) .checked_mul(usize::from(height.get())) .unwrap() @@ -176,15 +176,14 @@ impl RdpServerDisplayUpdates for DisplayUpdates { data.push(255); } - info!("get_update +{left}+{top} {width}x{height}"); + info!("get_update +{x}+{y} {width}x{height}"); let bitmap = BitmapUpdate { - top, - left, + x, + y, width, height, format: PixelFormat::BgrA32, - order: PixelOrder::TopToBottom, - data, + data: data.into(), stride: usize::from(width.get()).checked_mul(4).unwrap(), }; Some(DisplayUpdate::Bitmap(bitmap))