use crate::buffer::Buffer;
use crate::error::{Error, Result};
use crate::ffi::Array;
use crate::render_pass::RenderPass;
use crate::subobject::Owner;
use crate::types::*;
use crate::vk::BufferUsageFlags;
use super::{
Bindings, CommandRecording, ExternalRenderPassRecording,
RenderPassRecording, SecondaryCommandBuffer, SecondaryCommandRecording,
};
impl<'a> RenderPassRecording<'a> {
#[doc = crate::man_link!(vkCmdSetViewport)]
pub fn set_viewport(&mut self, viewport: &Viewport) {
self.rec.set_viewport(viewport)
}
}
impl<'a> SecondaryCommandRecording<'a> {
#[doc = crate::man_link!(vkCmdSetViewport)]
pub fn set_viewport(&mut self, viewport: &Viewport) {
self.rec.set_viewport(viewport)
}
}
impl<'a> CommandRecording<'a> {
#[doc = crate::man_link!(vkCmdSetViewport)]
pub fn set_viewport(&mut self, viewport: &Viewport) {
unsafe {
(self.pool.device.fun.cmd_set_viewport)(
self.buffer.handle.borrow_mut(),
0,
1,
std::array::from_ref(viewport).into(),
)
}
}
}
impl<'a> RenderPassRecording<'a> {
#[doc = crate::man_link!(vkCmdSetScissor)]
pub fn set_scissor(&mut self, scissor: &Rect2D) {
self.rec.set_scissor(scissor)
}
}
impl<'a> SecondaryCommandRecording<'a> {
#[doc = crate::man_link!(vkCmdSetScissor)]
pub fn set_scissor(&mut self, scissor: &Rect2D) {
self.rec.set_scissor(scissor)
}
}
impl<'a> CommandRecording<'a> {
#[doc = crate::man_link!(vkCmdSetScissor)]
pub fn set_scissor(&mut self, scissor: &Rect2D) {
unsafe {
(self.pool.device.fun.cmd_set_scissor)(
self.buffer.handle.borrow_mut(),
0,
1,
std::array::from_ref(scissor).into(),
)
}
}
}
impl<'a> Bindings<'a> {
fn check(&self) -> Result<()> {
if let Some(pipeline) = self.pipeline.as_ref() {
let layouts = &pipeline.layout().layouts();
if self.layout.get(0..layouts.len()) == Some(layouts)
&& self.inited.iter().take_while(|b| **b).count()
>= layouts.len()
{
return Ok(());
}
}
Err(Error::InvalidState)
}
fn check_render_pass(&self, pass: &RenderPass, subpass: u32) -> Result<()> {
if let Some(pipeline) = self.pipeline.as_ref() {
if pipeline.is_compatible_with(pass, subpass) {
return Ok(());
}
}
Err(Error::InvalidState)
}
}
macro_rules! draw_state {
() => {
"Returns [`Error::InvalidState`] if the bound pipeline is not compatible
with the current render pass and subpass, if the bound descriptor sets
and bound graphics pipeline do not have a compatible layout, or if a
descriptor set mentioned in the pipeline's layout is not bound."
}
}
impl<'a> RenderPassRecording<'a> {
#[doc = draw_state!()]
#[doc = crate::man_link!(vkCmdDraw)]
pub fn draw(
&mut self, vertex_count: u32, instance_count: u32, first_vertex: u32,
first_instance: u32,
) -> Result<()> {
self.rec.graphics.check_render_pass(&self.pass, self.subpass)?;
self.rec.draw(
vertex_count,
instance_count,
first_vertex,
first_instance,
)
}
#[doc = draw_state!()]
#[doc = crate::man_link!(vkCmdDrawIndirect)]
pub fn draw_indirect(
&mut self, buffer: &Arc<Buffer>, offset: u64, draw_count: u32,
stride: u32,
) -> Result<()> {
self.rec.graphics.check_render_pass(&self.pass, self.subpass)?;
self.rec.draw_indirect(buffer, offset, draw_count, stride)
}
#[doc = draw_state!()]
#[doc = crate::man_link!(vkCmdDrawIndexed)]
pub fn draw_indexed(
&mut self, index_count: u32, instance_count: u32, first_index: u32,
vertex_offset: i32, first_instance: u32,
) -> Result<()> {
self.rec.graphics.check_render_pass(&self.pass, self.subpass)?;
self.rec.draw_indexed(
index_count,
instance_count,
first_index,
vertex_offset,
first_instance,
)
}
#[doc = draw_state!()]
#[doc = crate::man_link!(vkCmdDrawIndexedIndirect)]
pub fn draw_indexed_indirect(
&mut self, buffer: &Arc<Buffer>, offset: u64, draw_count: u32,
stride: u32,
) -> Result<()> {
self.rec.graphics.check_render_pass(&self.pass, self.subpass)?;
self.rec.draw_indexed_indirect(buffer, offset, draw_count, stride)
}
}
impl<'a> SecondaryCommandRecording<'a> {
#[doc = draw_state!()]
#[doc = crate::man_link!(vkCmdDraw)]
pub fn draw(
&mut self, vertex_count: u32, instance_count: u32, first_vertex: u32,
first_instance: u32,
) -> Result<()> {
self.rec.graphics.check_render_pass(&self.pass, self.subpass)?;
self.rec.draw(
vertex_count,
instance_count,
first_vertex,
first_instance,
)
}
#[doc = draw_state!()]
#[doc = crate::man_link!(vkCmdDrawIndirect)]
pub fn draw_indirect(
&mut self, buffer: &Arc<Buffer>, offset: u64, draw_count: u32,
stride: u32,
) -> Result<()> {
self.rec.graphics.check_render_pass(&self.pass, self.subpass)?;
self.rec.draw_indirect(buffer, offset, draw_count, stride)
}
#[doc = draw_state!()]
#[doc = crate::man_link!(vkCmdDrawIndexed)]
pub fn draw_indexed(
&mut self, index_count: u32, instance_count: u32, first_index: u32,
vertex_offset: i32, first_instance: u32,
) -> Result<()> {
self.rec.graphics.check_render_pass(&self.pass, self.subpass)?;
self.rec.draw_indexed(
index_count,
instance_count,
first_index,
vertex_offset,
first_instance,
)
}
#[doc = draw_state!()]
#[doc = crate::man_link!(vkCmdDrawIndexedIndirect)]
pub fn draw_indexed_indirect(
&mut self, buffer: &Arc<Buffer>, offset: u64, draw_count: u32,
stride: u32,
) -> Result<()> {
self.rec.graphics.check_render_pass(&self.pass, self.subpass)?;
self.rec.draw_indexed_indirect(buffer, offset, draw_count, stride)
}
}
fn bounds_check_n(
count: u32, size: u32, mut stride: u32, buf: &Arc<Buffer>, offset: u64,
) -> Result<()> {
if count < 2 {
stride = size;
}
if stride < size || offset & 3 != 0 {
return Err(Error::InvalidArgument);
}
let len =
(count as u64).checked_mul(stride as u64).ok_or(Error::OutOfBounds)?;
if !buf.bounds_check(offset, len) {
return Err(Error::OutOfBounds);
}
Ok(())
}
impl<'a> CommandRecording<'a> {
fn draw(
&mut self, vertex_count: u32, instance_count: u32, first_vertex: u32,
first_instance: u32,
) -> Result<()> {
self.graphics.check()?;
unsafe {
(self.pool.device.fun.cmd_draw)(
self.buffer.handle.borrow_mut(),
vertex_count,
instance_count,
first_vertex,
first_instance,
)
}
Ok(())
}
fn draw_indirect(
&mut self, buffer: &Arc<Buffer>, offset: u64, draw_count: u32,
stride: u32,
) -> Result<()> {
if !buffer.usage().contains(BufferUsageFlags::INDIRECT_BUFFER) {
return Err(Error::InvalidArgument);
}
bounds_check_n(draw_count, 16, stride, buffer, offset)?;
self.graphics.check()?;
self.add_resource(buffer.clone());
unsafe {
(self.pool.device.fun.cmd_draw_indirect)(
self.buffer.handle.borrow_mut(),
buffer.handle(),
offset,
draw_count,
stride,
)
}
Ok(())
}
fn draw_indexed(
&mut self, index_count: u32, instance_count: u32, first_index: u32,
vertex_offset: i32, first_instance: u32,
) -> Result<()> {
self.graphics.check()?;
unsafe {
(self.pool.device.fun.cmd_draw_indexed)(
self.buffer.handle.borrow_mut(),
index_count,
instance_count,
first_index,
vertex_offset,
first_instance,
)
}
Ok(())
}
fn draw_indexed_indirect(
&mut self, buffer: &Arc<Buffer>, offset: u64, draw_count: u32,
stride: u32,
) -> Result<()> {
bounds_check_n(draw_count, 20, stride, buffer, offset)?;
if !buffer.usage().contains(BufferUsageFlags::INDIRECT_BUFFER) {
return Err(Error::InvalidArgument);
}
self.graphics.check()?;
self.add_resource(buffer.clone());
unsafe {
(self.pool.device.fun.cmd_draw_indexed_indirect)(
self.buffer.handle.borrow_mut(),
buffer.handle(),
offset,
draw_count,
stride,
)
}
Ok(())
}
}
impl<'a> CommandRecording<'a> {
#[doc = crate::man_link!(vkCmdDispatch)]
pub fn dispatch(
&mut self, group_count_x: u32, group_count_y: u32, group_count_z: u32,
) -> Result<()> {
self.compute.check()?;
unsafe {
(self.pool.device.fun.cmd_dispatch)(
self.buffer.handle.borrow_mut(),
group_count_x,
group_count_y,
group_count_z,
);
}
Ok(())
}
#[doc = crate::man_link!(vkCmdDispatchIndirect)]
pub fn dispatch_indirect(
&mut self, buffer: &Arc<Buffer>, offset: u64,
) -> Result<()> {
self.compute.check()?;
self.add_resource(buffer.clone());
unsafe {
(self.pool.device.fun.cmd_dispatch_indirect)(
self.buffer.handle.borrow_mut(),
buffer.handle(),
offset,
);
}
Ok(())
}
}
impl<'a> ExternalRenderPassRecording<'a> {
#[doc = crate::man_link!(vkCmdExecuteCommands)]
pub fn execute_commands(
&mut self, commands: &mut [&mut SecondaryCommandBuffer],
) -> Result<()> {
let mut resources = bumpalo::vec![in self.rec.scratch];
let mut handles = bumpalo::vec![in self.rec.scratch];
for command in commands.iter_mut() {
if !self.pass.compatible(command.pass.as_deref().unwrap())
|| self.subpass != command.subpass
{
return Err(Error::InvalidArgument);
}
let res = command.lock_resources().ok_or(Error::InvalidArgument)?;
if !Owner::ptr_eq(self.rec.pool, &command.buf.pool) {
resources.push(res as Arc<_>);
}
handles.push(command.mut_handle()?);
}
unsafe {
(self.rec.pool.device.fun.cmd_execute_commands)(
self.rec.buffer.handle.borrow_mut(),
handles.len() as u32,
Array::from_slice(&handles).ok_or(Error::InvalidArgument)?,
)
}
drop(handles);
self.rec.pool.resources.extend(resources);
for command in commands {
self.rec.pool.resources.push(command.lock_self());
}
Ok(())
}
}