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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
|
#![allow(unsafe_code)]
use crate::error::*;
use std::mem::size_of;
use std::ptr::copy_nonoverlapping;
use vulkanalia::{ Device, Instance };
use vulkanalia::vk::{ self, Handle, HasBuilder, InstanceV1_0, DeviceV1_0 };
#[allow(unsafe_code)]
pub fn init_buffer<T>(instance: &Instance, device: &Device, queue: &vk::Queue,
command_pool: &vk::CommandPool,
usage: vk::BufferUsageFlags, contents: &[T])
-> Result<(vk::Buffer, vk::DeviceMemory)>
{
let (staging_buffer, staging_memory, size)
= stage_in_buffer(instance, device, contents)?;
let final_usage = vk::BufferUsageFlags::TRANSFER_DST | usage;
let final_memory_flags = vk::MemoryPropertyFlags::DEVICE_LOCAL;
let (final_buffer, device_memory)
= allocate_buffer(instance, device, size as vk::DeviceSize,
final_usage, final_memory_flags)?;
copy_buffer(device, queue, command_pool, &staging_buffer, &final_buffer,
size as vk::DeviceSize)?;
unsafe { device.destroy_buffer(staging_buffer, None) };
unsafe { device.free_memory(staging_memory, None) };
Ok((final_buffer, device_memory))
}
pub fn stage_in_buffer<T>(instance: &Instance, device: &Device,
contents: &[T])
-> Result<(vk::Buffer, vk::DeviceMemory, usize)>
{
let size = size_of::<T>() * contents.len();
let staging_usage = vk::BufferUsageFlags::TRANSFER_SRC;
let staging_memory_flags = vk::MemoryPropertyFlags::HOST_COHERENT
| vk::MemoryPropertyFlags::HOST_VISIBLE;
let (staging_buffer, staging_memory)
= allocate_buffer(instance, device, size as vk::DeviceSize,
staging_usage, staging_memory_flags)?;
let host_memory = unsafe {
device.map_memory(staging_memory, 0, size as vk::DeviceSize,
vk::MemoryMapFlags::empty())
}?;
unsafe {
copy_nonoverlapping(contents.as_ptr(), host_memory.cast(), contents.len())
};
unsafe { device.unmap_memory(staging_memory) };
Ok((staging_buffer, staging_memory, size))
}
#[allow(unsafe_code)]
pub fn allocate_buffer(instance: &Instance, device: &Device,
size: vk::DeviceSize, usage: vk::BufferUsageFlags,
memory_flags: vk::MemoryPropertyFlags)
-> Result<(vk::Buffer, vk::DeviceMemory)>
{
let physical_device = device.physical_device();
let buffer_info = vk::BufferCreateInfo::builder()
.size(size)
.usage(usage)
.sharing_mode(vk::SharingMode::EXCLUSIVE);
let buffer = unsafe { device.create_buffer(&buffer_info, None) }?;
// The requirements are mostly what you'd think: size and alignment. The
// bits field is something special; see pick_memory_type() for the
// explanation. Despite the simplicity of this data, Vulkan wants to be the
// one to tell us about it, and we let it.
let requirements = unsafe { device.get_buffer_memory_requirements(buffer) };
let type_index = pick_memory_type(instance, &physical_device,
&memory_flags, &requirements)?;
let memory_info = vk::MemoryAllocateInfo::builder()
.allocation_size(requirements.size)
.memory_type_index(type_index);
let device_memory = unsafe { device.allocate_memory(&memory_info, None) }?;
unsafe { device.bind_buffer_memory(buffer, device_memory, 0) }?;
Ok((buffer, device_memory))
}
#[allow(unsafe_code)]
pub fn copy_buffer(device: &Device, queue: &vk::Queue,
command_pool: &vk::CommandPool, source: &vk::Buffer,
destination: &vk::Buffer, size: vk::DeviceSize)
-> Result<()>
{
let command_buffer = begin_transient_commands(device, command_pool)?;
let copy_info = vk::BufferCopy::builder().size(size);
unsafe {
device.cmd_copy_buffer(command_buffer, *source, *destination,
&[copy_info])
};
end_transient_commands(command_buffer, device, queue, command_pool)?;
Ok(())
}
#[allow(unsafe_code)]
pub fn pick_memory_type(instance: &Instance,
physical_device: &vk::PhysicalDevice,
properties: &vk::MemoryPropertyFlags,
requirements: &vk::MemoryRequirements)
-> Result<u32>
{
let memory_map = unsafe {
instance.get_physical_device_memory_properties(*physical_device)
};
// So. The memory_type_bits field is a map of which indices are suitable,
// based on the buffer our caller passed to
// get_buffer_memory_requirements(). Yes, that means there's a hard cap on
// how many memory types there can be, based on the size of the bitfield.
for index in 0 .. memory_map.memory_type_count {
if requirements.memory_type_bits & (1 << index) == 0 {
continue;
}
let memory_type = memory_map.memory_types[index as usize];
if memory_type.property_flags.contains(*properties) {
return Ok(index);
}
}
Err(Error {
message: "The system has no suitable memory for a buffer.".to_string()
})
}
#[allow(unsafe_code)]
pub fn allocate_image(instance: &Instance, device: &Device, width: u32,
height: u32, mip_count: u32,
sample_count: vk::SampleCountFlags, format: vk::Format,
tiling: vk::ImageTiling, usage: vk::ImageUsageFlags,
memory_flags: vk::MemoryPropertyFlags)
-> Result<(vk::Image, vk::DeviceMemory)>
{
let physical_device = device.physical_device();
let image_info = vk::ImageCreateInfo::builder()
.image_type(vk::ImageType::_2D)
.extent(vk::Extent3D { width, height, depth: 1 })
.mip_levels(mip_count)
.samples(sample_count)
.array_layers(1)
.format(format)
.tiling(tiling)
.initial_layout(vk::ImageLayout::UNDEFINED)
.usage(usage)
.sharing_mode(vk::SharingMode::EXCLUSIVE)
.flags(vk::ImageCreateFlags::empty());
let image = unsafe { device.create_image(&image_info, None) }?;
let requirements = unsafe { device.get_image_memory_requirements(image) };
let type_index = pick_memory_type(instance, &physical_device,
&memory_flags, &requirements)?;
let image_memory_info = vk::MemoryAllocateInfo::builder()
.allocation_size(requirements.size)
.memory_type_index(type_index);
let image_memory = unsafe {
device.allocate_memory(&image_memory_info, None)
}?;
unsafe { device.bind_image_memory(image, image_memory, 0) }?;
Ok((image, image_memory))
}
#[allow(unsafe_code)]
pub fn init_image_view(device: &Device, image: &vk::Image, mip_count: u32,
format: vk::Format, aspects: vk::ImageAspectFlags)
-> Result<vk::ImageView>
{
// Component mapping is only for color components (not, for example, depth
// or stencil components), so we always just want it like this.
let components = vk::ComponentMapping::builder()
.r(vk::ComponentSwizzle::IDENTITY)
.g(vk::ComponentSwizzle::IDENTITY)
.b(vk::ComponentSwizzle::IDENTITY)
.a(vk::ComponentSwizzle::IDENTITY);
let subresource_range = vk::ImageSubresourceRange::builder()
.aspect_mask(aspects)
.base_mip_level(0)
.level_count(mip_count)
.base_array_layer(0)
.layer_count(1);
let view_info = vk::ImageViewCreateInfo::builder()
.image(*image)
.view_type(vk::ImageViewType::_2D)
.format(format)
.components(components)
.subresource_range(subresource_range);
let view = unsafe {
device.create_image_view(&view_info, None)
}?;
Ok(view)
}
#[allow(unsafe_code)]
pub fn begin_transient_commands(device: &Device,
command_pool: &vk::CommandPool)
-> Result<vk::CommandBuffer>
{
let command_buffer_allocation_info
= vk::CommandBufferAllocateInfo::builder()
.command_pool(*command_pool)
.level(vk::CommandBufferLevel::PRIMARY)
.command_buffer_count(1);
let command_buffer = unsafe {
device.allocate_command_buffers(&command_buffer_allocation_info)
}?[0];
let command_buffer_begin_info = vk::CommandBufferBeginInfo::builder()
.flags(vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT);
unsafe {
device.begin_command_buffer(command_buffer, &command_buffer_begin_info)
}?;
Ok(command_buffer)
}
#[allow(unsafe_code)]
pub fn end_transient_commands(command_buffer: vk::CommandBuffer,
device: &Device, queue: &vk::Queue,
command_pool: &vk::CommandPool)
-> Result<()>
{
unsafe { device.end_command_buffer(command_buffer) }?;
let command_buffers = [command_buffer];
let submit_info = vk::SubmitInfo::builder()
.command_buffers(&command_buffers);
unsafe { device.queue_submit(*queue, &[submit_info], vk::Fence::null()) }?;
unsafe { device.queue_wait_idle(*queue) }?;
unsafe { device.free_command_buffers(*command_pool, &command_buffers) };
Ok(())
}
|