119 lines
4.6 KiB
Rust
119 lines
4.6 KiB
Rust
use crate::mmio::MmioAccess;
|
|
use crate::queue::{Descriptor, VirtioQueue};
|
|
use libkos::Window;
|
|
use types::address::{ByteOffset, PhysicalAddress};
|
|
use types::display::Dimension;
|
|
|
|
/// The command page: commands go out from its start, responses come back
|
|
/// at `RESPONSE`.
|
|
pub struct GpuDmaAddrs {
|
|
pub cmd_pa: PhysicalAddress,
|
|
pub cmd: Window,
|
|
pub resp_pa: PhysicalAddress,
|
|
}
|
|
|
|
pub const RESPONSE: ByteOffset = ByteOffset::new(512);
|
|
|
|
/// Command fields (virtio spec 5.7.6.7): a 24-byte header, then the body.
|
|
const TYPE: ByteOffset = ByteOffset::new(0);
|
|
const BODY: ByteOffset = ByteOffset::new(24);
|
|
/// Most bodies start with a rectangle: x, y, width, height.
|
|
const RECT_X: ByteOffset = ByteOffset::new(24);
|
|
const RECT_Y: ByteOffset = ByteOffset::new(28);
|
|
const RECT_W: ByteOffset = ByteOffset::new(32);
|
|
const RECT_H: ByteOffset = ByteOffset::new(36);
|
|
/// The 24 bytes of header and 16 of rectangle in a display-info response.
|
|
const DISPLAY_W: ByteOffset = ByteOffset::new(24 + 8);
|
|
const DISPLAY_H: ByteOffset = ByteOffset::new(24 + 12);
|
|
|
|
pub fn create_2d(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, width: Dimension, height: Dimension) -> bool {
|
|
write_cmd_header(&dma.cmd, 0x0101);
|
|
// Resource id, format (134: R8G8B8X8, a window's own byte order, so
|
|
// its rows are copied as they are), width, height.
|
|
dma.cmd.write(BODY, resource_id);
|
|
dma.cmd.write(BODY + 4, 134u32);
|
|
dma.cmd.write(BODY + 8, width.raw() as u32);
|
|
dma.cmd.write(BODY + 12, height.raw() as u32);
|
|
submit_cmd(mmio, queue, dma, 40)
|
|
}
|
|
|
|
pub fn attach_backing(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, fb_pa: PhysicalAddress, fb_size: u32) -> bool {
|
|
write_cmd_header(&dma.cmd, 0x0106);
|
|
// Resource id, one memory entry: its address and length.
|
|
dma.cmd.write(BODY, resource_id);
|
|
dma.cmd.write(BODY + 4, 1u32);
|
|
dma.cmd.write(BODY + 8, fb_pa.raw() as u64);
|
|
dma.cmd.write(BODY + 16, fb_size);
|
|
submit_cmd(mmio, queue, dma, 48)
|
|
}
|
|
|
|
pub fn set_scanout(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, scanout_id: u32, resource_id: u32, width: Dimension, height: Dimension) -> bool {
|
|
write_cmd_header(&dma.cmd, 0x0103);
|
|
// The rectangle (from 0, 0), then scanout and resource ids.
|
|
dma.cmd.write(RECT_W, width.raw() as u32);
|
|
dma.cmd.write(RECT_H, height.raw() as u32);
|
|
dma.cmd.write(BODY + 16, scanout_id);
|
|
dma.cmd.write(BODY + 20, resource_id);
|
|
submit_cmd(mmio, queue, dma, 48)
|
|
}
|
|
|
|
/// A rectangle of a resource, in pixels.
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub struct Rect {
|
|
pub x: u32,
|
|
pub y: u32,
|
|
pub w: u32,
|
|
pub h: u32,
|
|
}
|
|
|
|
/// Copies `rect` of the backing to the host; `offset` is where its top
|
|
/// left pixel is in the backing, in bytes.
|
|
pub fn transfer_to_host(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, rect: Rect, offset: u64) -> bool {
|
|
write_cmd_header(&dma.cmd, 0x0105);
|
|
put_rect(&dma.cmd, rect);
|
|
// Offset into the resource's memory, then the resource id.
|
|
dma.cmd.write(BODY + 16, offset);
|
|
dma.cmd.write(BODY + 24, resource_id);
|
|
submit_cmd(mmio, queue, dma, 56)
|
|
}
|
|
|
|
pub fn resource_flush(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, rect: Rect) -> bool {
|
|
write_cmd_header(&dma.cmd, 0x0104);
|
|
put_rect(&dma.cmd, rect);
|
|
dma.cmd.write(BODY + 16, resource_id);
|
|
submit_cmd(mmio, queue, dma, 48)
|
|
}
|
|
|
|
fn write_cmd_header(cmd: &Window, cmd_type: u32) {
|
|
cmd.fill_u32(ByteOffset::ZERO, 128, 0);
|
|
cmd.write(TYPE, cmd_type);
|
|
}
|
|
|
|
fn put_rect(cmd: &Window, r: Rect) {
|
|
cmd.write(RECT_X, r.x);
|
|
cmd.write(RECT_Y, r.y);
|
|
cmd.write(RECT_W, r.w);
|
|
cmd.write(RECT_H, r.h);
|
|
}
|
|
|
|
pub fn get_display_info(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs) -> Option<(u32, u32)> {
|
|
write_cmd_header(&dma.cmd, 0x0100);
|
|
let descs = [
|
|
Descriptor { addr: dma.cmd_pa.raw() as u64, len: 24, writable: false },
|
|
Descriptor { addr: dma.resp_pa.raw() as u64, len: 408, writable: true },
|
|
];
|
|
if !queue.submit(mmio, &descs) { return None; }
|
|
if dma.cmd.read::<u32>(RESPONSE) != 0x1101 { return None; }
|
|
let w: u32 = dma.cmd.read(RESPONSE + DISPLAY_W.raw());
|
|
let h: u32 = dma.cmd.read(RESPONSE + DISPLAY_H.raw());
|
|
if w > 0 && h > 0 { Some((w, h)) } else { None }
|
|
}
|
|
|
|
fn submit_cmd(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, cmd_len: u32) -> bool {
|
|
let descs = [
|
|
Descriptor { addr: dma.cmd_pa.raw() as u64, len: cmd_len, writable: false },
|
|
Descriptor { addr: dma.resp_pa.raw() as u64, len: 24, writable: true },
|
|
];
|
|
queue.submit(mmio, &descs)
|
|
}
|