blob: 57b04c3178b6ec8141582b4b527315bdc4a98d04 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::mem::size_of;
use std::os::raw::c_void;
use std::slice::{from_raw_parts, from_raw_parts_mut};
use generated::virgl_protocol::*;
use Resource;
/// Helper struct for making a virgl command buffer.
#[derive(Default)]
pub struct CommandBufferBuilder {
cbuf: Vec<u32>,
}
impl AsRef<[u8]> for CommandBufferBuilder {
fn as_ref(&self) -> &[u8] {
// Safe because the returned slice is a trivial reinterpretation of the same number of
// bytes.
unsafe {
from_raw_parts(self.cbuf.as_ptr() as *const u8,
self.cbuf.len() * size_of::<u32>())
}
}
}
impl AsMut<[u8]> for CommandBufferBuilder {
fn as_mut(&mut self) -> &mut [u8] {
// Safe because the returned slice is a trivial reinterpretation of the same number of
// bytes.
unsafe {
from_raw_parts_mut(self.cbuf.as_mut_ptr() as *mut u8,
self.cbuf.len() * size_of::<u32>())
}
}
}
impl CommandBufferBuilder {
/// Constructs an empty command
pub fn new() -> CommandBufferBuilder {
Default::default()
}
fn push(&mut self, dw: u32) {
self.cbuf.push(dw);
}
fn push_qw(&mut self, qw: u64) {
self.cbuf.push(qw as u32);
self.cbuf.push((qw >> 32) as u32);
}
fn push_cmd(&mut self, cmd: u32, obj_type: u32, len: u32) {
self.cbuf.push((cmd & 0xff) | ((obj_type & 0xff) << 8) | ((len & 0xffff) << 16));
}
/// Gets the command buffer as a pointer to the beginning.
pub fn as_mut_ptr(&mut self) -> *mut c_void {
self.cbuf.as_mut_ptr() as *mut c_void
}
/// Gets the size of the command buffer content in dwords.
pub fn dword_count(&self) -> usize {
self.cbuf.len()
}
/// Clears the command buffer content.
pub fn clear(&mut self) {
self.cbuf.clear();
}
/// Checks that the command buffer is well formed.
pub fn is_valid(&self) -> bool {
let mut i = 0;
while i < self.cbuf.len() {
i += 1 + (self.cbuf[i] >> 16) as usize;
}
i == self.cbuf.len()
}
/// Pushes a clear command to this command buffer.
pub fn e_clear(&mut self, buffers: u32, color: [f32; 4], depth: f64, stencil: u32) {
self.push_cmd(VIRGL_CCMD_CLEAR, 0, VIRGL_OBJ_CLEAR_SIZE);
self.push(buffers);
for &c in color.iter() {
self.push(c.to_bits())
}
self.push_qw(depth.to_bits());
self.push(stencil);
assert!(self.is_valid());
}
/// Pushes a create surface command to this command buffer.
pub fn e_create_surface(&mut self,
new_id: u32,
res: &Resource,
format: u32,
level: u32,
first_layer: u32,
last_layer: u32) {
self.push_cmd(VIRGL_CCMD_CREATE_OBJECT,
VIRGL_OBJECT_SURFACE,
VIRGL_OBJ_SURFACE_SIZE);
self.push(new_id);
self.push(res.id());
self.push(format);
self.push(level);
self.push(first_layer | (last_layer << 16));
assert!(self.is_valid());
}
/// Pushes a set framebuffer state command to this command buffer.
pub fn e_set_fb_state(&mut self, surface_handles: &[u32], zbuf: Option<u32>) {
fn cmd_set_fb_state_size(surface_count: u32) -> u32 {
2 + surface_count
}
self.push_cmd(VIRGL_CCMD_SET_FRAMEBUFFER_STATE,
0,
cmd_set_fb_state_size(surface_handles.len() as u32));
self.push(surface_handles.len() as u32);
self.push(zbuf.unwrap_or(0));
for &surface_handle in surface_handles {
self.push(surface_handle);
}
assert!(self.is_valid());
}
}