1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use std::error;
use std::fmt;
use std::sync::Arc;
use command_buffer::CommandAddError;
use command_buffer::cb::AddCommand;
use command_buffer::cb::UnsafeCommandBufferBuilder;
use command_buffer::pool::CommandPool;
use descriptor::pipeline_layout::PipelineLayoutAbstract;
use descriptor::pipeline_layout::PipelineLayoutPushConstantsCompatible;
use device::Device;
use device::DeviceOwned;
use VulkanObject;
use VulkanPointers;
pub struct CmdPushConstants<Pc, Pl> {
device: Arc<Device>,
push_constants: Pc,
pipeline_layout: Pl,
}
impl<Pc, Pl> CmdPushConstants<Pc, Pl>
where Pl: PipelineLayoutAbstract
{
#[inline]
pub fn new(pipeline_layout: Pl, push_constants: Pc)
-> Result<CmdPushConstants<Pc, Pl>, CmdPushConstantsError>
{
if !PipelineLayoutPushConstantsCompatible::is_compatible(&pipeline_layout, &push_constants) {
return Err(CmdPushConstantsError::IncompatibleData);
}
let device = pipeline_layout.device().clone();
Ok(CmdPushConstants {
device: device,
push_constants: push_constants,
pipeline_layout: pipeline_layout,
})
}
}
unsafe impl<Pc, Pl> DeviceOwned for CmdPushConstants<Pc, Pl> {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
unsafe impl<'a, P, Pc, Pl> AddCommand<&'a CmdPushConstants<Pc, Pl>> for UnsafeCommandBufferBuilder<P>
where P: CommandPool,
Pl: PipelineLayoutAbstract
{
type Out = UnsafeCommandBufferBuilder<P>;
#[inline]
fn add(self, command: &'a CmdPushConstants<Pc, Pl>) -> Result<Self::Out, CommandAddError> {
unsafe {
let vk = self.device().pointers();
let cmd = self.internal_object();
let data_raw = &command.push_constants as *const Pc as *const u8;
for num_range in 0 .. command.pipeline_layout.num_push_constants_ranges() {
let range = match command.pipeline_layout.push_constants_range(num_range) {
Some(r) => r,
None => continue
};
debug_assert_eq!(range.offset % 4, 0);
debug_assert_eq!(range.size % 4, 0);
vk.CmdPushConstants(cmd, command.pipeline_layout.sys().internal_object(),
range.stages.into(), range.offset as u32, range.size as u32,
data_raw.offset(range.offset as isize) as *const _);
}
}
Ok(self)
}
}
#[derive(Debug, Copy, Clone)]
pub enum CmdPushConstantsError {
IncompatibleData,
}
impl error::Error for CmdPushConstantsError {
#[inline]
fn description(&self) -> &str {
match *self {
CmdPushConstantsError::IncompatibleData => {
"the push constants are not compatible with the pipeline layout"
},
}
}
}
impl fmt::Display for CmdPushConstantsError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}