Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions crates/ironrdp-egfx/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.1.0] - 2024-XX-XX

### Added

- Initial release
- MS-RDPEGFX PDU types (all 23 PDUs)
- Client-side DVC processor
- Server-side implementation with:
- Multi-surface management (Offscreen Surfaces ADM element)
- Frame tracking with flow control (Unacknowledged Frames ADM element)
- V8/V8.1/V10/V10.1-V10.7 capability negotiation
- AVC420 and AVC444 frame sending
- QoE metrics processing
- Cache import handling
- Resize coordination
28 changes: 28 additions & 0 deletions crates/ironrdp-egfx/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "ironrdp-egfx"
version = "0.1.0"
readme = "README.md"
description = "Graphics pipeline dynamic channel extension implementation"
edition.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true
authors.workspace = true
keywords.workspace = true
categories.workspace = true

[lib]
doctest = false
# test = false

[dependencies]
bit_field = "0.10"
bitflags = "2.4"
ironrdp-core = { path = "../ironrdp-core", version = "0.1" } # public
ironrdp-dvc = { path = "../ironrdp-dvc", version = "0.4" } # public
ironrdp-graphics = { path = "../ironrdp-graphics", version = "0.6" } # public
ironrdp-pdu = { path = "../ironrdp-pdu", version = "0.6" } # public
tracing = { version = "0.1", features = ["log"] }

[lints]
workspace = true
1 change: 1 addition & 0 deletions crates/ironrdp-egfx/LICENSE-APACHE
1 change: 1 addition & 0 deletions crates/ironrdp-egfx/LICENSE-MIT
8 changes: 8 additions & 0 deletions crates/ironrdp-egfx/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# ironrdp-egfx

Graphics Pipeline Extension ([MS-RDPEGFX]) implementation for IronRDP.

Provides PDU types and client/server processors for the Display Pipeline Virtual
Channel Extension, including H.264/AVC420 and AVC444 video streaming support.

[MS-RDPEGFX]: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rdpegfx/da5c75f9-cd99-450c-98c4-014a496942b0
74 changes: 74 additions & 0 deletions crates/ironrdp-egfx/src/client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use ironrdp_core::{impl_as_any, ReadCursor};
use ironrdp_dvc::{DvcClientProcessor, DvcMessage, DvcProcessor};
use ironrdp_graphics::zgfx;
use ironrdp_pdu::{decode_cursor, decode_err, PduResult};
use tracing::trace;

use crate::{
pdu::{CapabilitiesAdvertisePdu, CapabilitiesV8Flags, CapabilitySet, GfxPdu},
CHANNEL_NAME,
};

/// Max capacity to keep for decompressed buffer when cleared.
const MAX_DECOMPRESSED_BUFFER_CAPACITY: usize = 16384; // 16 KiB

pub trait GraphicsPipelineHandler: Send {
fn capabilities(&self) -> Vec<CapabilitySet> {
vec![CapabilitySet::V8 {
flags: CapabilitiesV8Flags::empty(),
}]
}

fn handle_pdu(&mut self, pdu: GfxPdu) {
trace!(?pdu);
}
}

/// A client for the Graphics Pipeline Virtual Channel.
pub struct GraphicsPipelineClient {
handler: Box<dyn GraphicsPipelineHandler>,
decompressor: zgfx::Decompressor,
decompressed_buffer: Vec<u8>,
}

impl GraphicsPipelineClient {
pub fn new(handler: Box<dyn GraphicsPipelineHandler>) -> Self {
Self {
handler,
decompressor: zgfx::Decompressor::new(),
decompressed_buffer: Vec::new(),
}
}
}

impl_as_any!(GraphicsPipelineClient);

impl DvcProcessor for GraphicsPipelineClient {
fn channel_name(&self) -> &str {
CHANNEL_NAME
}

fn start(&mut self, _channel_id: u32) -> PduResult<Vec<DvcMessage>> {
let pdu = GfxPdu::CapabilitiesAdvertise(CapabilitiesAdvertisePdu(self.handler.capabilities()));

Ok(vec![Box::new(pdu)])
}

fn process(&mut self, _channel_id: u32, payload: &[u8]) -> PduResult<Vec<DvcMessage>> {
self.decompressed_buffer.clear();
self.decompressed_buffer.shrink_to(MAX_DECOMPRESSED_BUFFER_CAPACITY);
self.decompressor
.decompress(payload, &mut self.decompressed_buffer)
.map_err(|e| decode_err!(e))?;

let mut cursor = ReadCursor::new(self.decompressed_buffer.as_slice());
while !cursor.is_empty() {
let pdu = decode_cursor(&mut cursor).map_err(|e| decode_err!(e))?;
self.handler.handle_pdu(pdu);
}

Ok(vec![])
}
}

impl DvcClientProcessor for GraphicsPipelineClient {}
8 changes: 8 additions & 0 deletions crates/ironrdp-egfx/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#![cfg_attr(doc, doc = include_str!("../README.md"))]
#![doc(html_logo_url = "https://cdnweb.devolutions.net/images/projects/devolutions/logos/devolutions-icon-shadow.svg")]

pub(crate) const CHANNEL_NAME: &str = "Microsoft::Windows::RDS::Graphics";

pub mod client;
pub mod pdu;
pub mod server;
Loading
Loading