@@ -864,6 +864,31 @@ pub struct GraphicsPipelineServer {
864864 compression_mode : CompressionMode ,
865865}
866866
867+ /// Payload for a single tile within a mixed-codec frame.
868+ ///
869+ /// Each variant corresponds to a different EGFX codec. Used with
870+ /// [`GraphicsPipelineServer::send_mixed_frame()`] to pack multiple codec
871+ /// types into a single `StartFrame`/`EndFrame` pair.
872+ pub enum MixedTilePayload {
873+ /// Lossless ClearCodec tile (text, UI elements, icons).
874+ /// `bitmap_data` is a pre-encoded ClearCodec bitmap stream.
875+ ClearCodec {
876+ destination : InclusiveRectangle ,
877+ bitmap_data : Vec < u8 > ,
878+ } ,
879+ /// RemoteFX Progressive tile (photos, gradients).
880+ /// `progressive_data` is a valid progressive block stream.
881+ RemoteFxProgressive {
882+ codec_context_id : u32 ,
883+ progressive_data : Vec < u8 > ,
884+ } ,
885+ /// H.264 AVC420 tile (video, high-motion content).
886+ Avc420 {
887+ regions : Vec < Avc420Region > ,
888+ h264_data : Vec < u8 > ,
889+ } ,
890+ }
891+
867892impl GraphicsPipelineServer {
868893 /// Create a new GraphicsPipelineServer
869894 pub fn new ( handler : Box < dyn GraphicsPipelineHandler > ) -> Self {
@@ -1455,6 +1480,91 @@ impl GraphicsPipelineServer {
14551480 Some ( frame_id)
14561481 }
14571482
1483+ // ========================================================================
1484+ // Mixed-Codec Frame Support
1485+ // ========================================================================
1486+
1487+ /// Queue a mixed-codec frame containing tiles encoded with different codecs.
1488+ ///
1489+ /// This is the core of multi-codec EGFX: a single frame update can contain
1490+ /// ClearCodec tiles (lossless text), Progressive tiles (photos), and H.264
1491+ /// tiles (video), all sent between one `StartFrame`/`EndFrame` pair.
1492+ ///
1493+ /// This matches how Azure VDI achieves its visual quality — each tile uses
1494+ /// the codec best suited to its content type.
1495+ ///
1496+ /// Returns `Some(frame_id)` if queued, `None` if not ready or backpressured.
1497+ pub fn send_mixed_frame (
1498+ & mut self ,
1499+ surface_id : u16 ,
1500+ tiles : Vec < MixedTilePayload > ,
1501+ timestamp_ms : u32 ,
1502+ ) -> Option < u32 > {
1503+ if !self . is_ready ( ) {
1504+ return None ;
1505+ }
1506+ if self . should_backpressure ( ) {
1507+ return None ;
1508+ }
1509+ if tiles. is_empty ( ) {
1510+ return None ;
1511+ }
1512+
1513+ let surface = self . surfaces . get ( surface_id) ?;
1514+ let pixel_format = surface. pixel_format ;
1515+
1516+ let timestamp = Self :: make_timestamp ( timestamp_ms) ;
1517+ let frame_id = self . frames . begin_frame ( timestamp) ;
1518+
1519+ self . output_queue
1520+ . push_back ( GfxPdu :: StartFrame ( StartFramePdu { timestamp, frame_id } ) ) ;
1521+
1522+ for tile in tiles {
1523+ match tile {
1524+ MixedTilePayload :: ClearCodec {
1525+ destination,
1526+ bitmap_data,
1527+ } => {
1528+ self . output_queue . push_back ( GfxPdu :: WireToSurface1 ( WireToSurface1Pdu {
1529+ surface_id,
1530+ codec_id : Codec1Type :: ClearCodec ,
1531+ pixel_format,
1532+ destination_rectangle : destination,
1533+ bitmap_data,
1534+ } ) ) ;
1535+ }
1536+ MixedTilePayload :: RemoteFxProgressive {
1537+ codec_context_id,
1538+ progressive_data,
1539+ } => {
1540+ self . output_queue . push_back ( GfxPdu :: WireToSurface2 ( WireToSurface2Pdu {
1541+ surface_id,
1542+ codec_id : Codec2Type :: RemoteFxProgressive ,
1543+ codec_context_id,
1544+ pixel_format,
1545+ bitmap_data : progressive_data,
1546+ } ) ) ;
1547+ }
1548+ MixedTilePayload :: Avc420 { regions, h264_data } => {
1549+ let encoded_stream = encode_avc420_bitmap_stream ( & regions, & h264_data) ;
1550+ let target_rect = Self :: compute_dest_rect ( & regions, surface. width , surface. height ) ;
1551+
1552+ self . output_queue . push_back ( GfxPdu :: WireToSurface1 ( WireToSurface1Pdu {
1553+ surface_id,
1554+ codec_id : Codec1Type :: Avc420 ,
1555+ pixel_format,
1556+ destination_rectangle : target_rect,
1557+ bitmap_data : encoded_stream,
1558+ } ) ) ;
1559+ }
1560+ }
1561+ }
1562+
1563+ self . output_queue . push_back ( GfxPdu :: EndFrame ( EndFramePdu { frame_id } ) ) ;
1564+
1565+ Some ( frame_id)
1566+ }
1567+
14581568 // ========================================================================
14591569 // Output Management
14601570 // ========================================================================
0 commit comments