Crate virglrenderer

Crate virglrenderer 

Source
Expand description

§Rust bindings for virglrenderer

virglrenderer is a crate that provides safe Rust bindings for libvirglrenderer, a library for hardware-accelerated 3D graphics rendering in virtualized environments. It enables a host-side application to act as a graphics server, processing commands from a guest virtual machine.

Programs that interact with virglrenderer usually react to events from the guest by processing command streams and signaling the completion of operations with fences.

§Getting started

Most programs that interact with virglrenderer will need a few basic objects:

  • A VirglRenderer that manages the global state of the rendering process. This object is responsible for initialization, cleanup, and handling global events.
  • A VirglContext that provides a way to submit rendering commands from the guest. All commands are associated with a specific context.
  • A VirglResource that represents a graphics resource, such as a texture or buffer, which can be created and managed by the renderer.

This is how they can be created:

use virglrenderer::{VirglRenderer, VirglContext, VirglError, FenceHandler, VirglRendererFlags};
use std::os::fd::OwnedFd;

// A simple fence handler that prints the fence ID.
struct MyFenceHandler;

impl FenceHandler for MyFenceHandler {
    fn call(&self, fence_id: u64, ctx_id: u32, _ring_idx: u8) {
        println!("Fence complete: {} on context {}", fence_id, ctx_id);
    }
}

fn main() -> Result<(), VirglError> {
    let flags = VirglRendererFlags::new()
        .use_virgl(true)
        .use_venus(true)
        .use_surfaceless(true)
        .use_external_blob(true)
        .use_async_fence_cb(true)
        .use_thread_sync(true);

    // Initialize the renderer with a fence handler.
    let renderer = VirglRenderer::init(
        flags, // Flags
        Box::new(MyFenceHandler),
        None, // Optional render server file descriptor
    )?;

    // Create a rendering context.
    let ctx = VirglContext::create_context(
        1, // Unique context ID
        0, // Context initialization flags
        Some("my-app-context") // Optional context name
    )?;

    Ok(())
}

§Common Operations

Now you can start creating resources, attaching them to the context, and processing command streams.

use virglrenderer::{VirglRenderer, VirglContext, VirglError, ResourceCreate3D, VirglRendererFlags};
use std::os::fd::OwnedFd;

// A simple fence handler (same as above).

fn main() -> Result<(), VirglError> {
    let flags = VirglRendererFlags::new()
        .use_virgl(true)
        .use_venus(true)
        .use_surfaceless(true)
        .use_external_blob(true)
        .use_async_fence_cb(true)
        .use_thread_sync(true);

    // Initialize the renderer with a fence handler.
    let renderer = VirglRenderer::init(
        flags, // Flags
        Box::new(MyFenceHandler),
        None, // Optional render server file descriptor
    )?;

    // Create a 3D resource, like a texture.
    let resource_create_3d = ResourceCreate3D {
        target: 0x0C,   // Example: GL_TEXTURE_2D
        format: 0x8058, // Example: GL_RGBA8
        bind: 0x01,     // Example: GL_TEXTURE_BINDING
        width: 256,
        height: 256,
        depth: 1,
        array_size: 1,
        last_level: 0,
        nr_samples: 0,
        flags: 0,
    };

    // Create the resource with a unique ID and attach it to the context.
    let mut resource = renderer.create_3d(100, resource_create_3d)?;
    ctx.attach(&mut resource);

    // Here, you would process incoming commands and submit them to the context
    // using `ctx.submit_cmd(...)` and transfer data using `renderer.transfer_write(...)`.

    // Detach the resource when you are done with it.
    ctx.detach(&resource);

    Ok(())
}

Note that resource IDs and context IDs are globally unique and are used to refer to objects in commands from the guest.


§Event Handling and Integration

The virglrenderer library requires periodic event processing to handle incoming commands and dispatch fence callbacks.

You can integrate virglrenderer into your application’s event loop using one of two methods:

  • Direct Polling: Call event_poll() periodically in a loop.
  • File Descriptor Integration (recommended): Use poll_descriptor() to obtain a pollable fd, then register it with your application’s event loop (e.g. epoll, mio, or tokio::AsyncFd).

Here’s an example using the event_poll() method:

use virglrenderer::{VirglRenderer, VirglRendererFlags, FenceHandler, VirglError};

fn main() -> Result<(), VirglError> {
    let flags = VirglRendererFlags::new()
        .use_virgl(true)
        .use_venus(true)
        .use_surfaceless(true)
        .use_external_blob(true)
        .use_async_fence_cb(true)
        .use_thread_sync(true);

    // Initialize the renderer with a fence handler.
    let renderer = VirglRenderer::init(
        flags, // Flags
        Box::new(MyFenceHandler),
        None, // Optional render server file descriptor
    )?;
    loop {
        renderer.event_poll();
        std::thread::sleep(std::time::Duration::from_millis(10));
    }
}

This will continuously process events from the renderer, ensuring commands and fence callbacks are handled correctly.

§Safety Notes

  • virglrenderer is a C library: these bindings wrap unsafe FFI calls in safe Rust APIs.
  • Resource IDs and Context IDs must be unique and guest-driven.
  • Fence callbacks run asynchronously and should avoid blocking.

For more details, see the virglrenderer project.

Re-exports§

pub use flags::VirglRendererFlags;

Modules§

flags

Structs§

Iovec
Resource3DInfo
ResourceCreate3D
ResourceCreateBlob
Transfer3D
VirglBox
VirglContext
VirglHandle
VirglRenderer
VirglResource

Enums§

VirglError

Constants§

VIRGL_HANDLE_TYPE_MEM_DMABUF
VIRGL_HANDLE_TYPE_MEM_OPAQUE_FD
VIRGL_HANDLE_TYPE_MEM_SHM

Traits§

FenceHandler