demo_vk/graphics/vulkan/raii/
device_resources.rs

1use {
2    crate::{graphics::vulkan::raii, trace},
3    anyhow::{Context, Result},
4    ash::vk::{self, Handle},
5    std::{ffi::CString, sync::Arc},
6};
7
8macro_rules! resource {
9    (
10        $name: ident,
11        $raw_type: ty,
12        $object_type: expr,
13        $create_info_type: ty,
14        $create: ident,
15        $destroy: ident
16    ) => {
17        resource_constructor!(
18            $name,
19            $raw_type,
20            $create_info_type,
21            $create,
22            $destroy
23        );
24        resource_impl!($name, $raw_type, $object_type, $destroy);
25    };
26}
27
28macro_rules! resource_constructor {
29    (
30        $name: ident,
31        $raw_type: ty,
32        $create_info_type: ty,
33        $create: ident,
34        $destroy: ident
35    ) => {
36        impl $name {
37            #[doc = "Creates a new instance."]
38            pub fn new(
39                name: impl Into<String>,
40                device: Arc<raii::Device>,
41                create_info: &$create_info_type,
42            ) -> Result<Self> {
43                let raw = unsafe { device.$create(&create_info, None)? };
44                let instance = Self { device, raw };
45                instance.set_debug_name(name)?;
46                Ok(instance)
47            }
48        }
49    };
50}
51
52macro_rules! resource_impl {
53    (
54        $name: ident,
55        $raw_type: ty,
56        $object_type: expr,
57        $destroy: ident
58    ) => {
59        /// RAII wrapper that destroys itself when Dropped.
60        ///
61        /// The owner is responsible for dropping Vulkan resources in the
62        /// correct order.
63        pub struct $name {
64            pub raw: $raw_type,
65            pub device: Arc<raii::Device>,
66        }
67
68        impl $name {
69            #[doc = "Sets the debug name used for validation layer logging."]
70            pub fn set_debug_name(
71                &self,
72                name: impl Into<String>,
73            ) -> Result<()> {
74                let object_type = $object_type;
75                let name =
76                    CString::new(format!("{:?}: {}", object_type, name.into()))
77                        .unwrap();
78
79                self.device
80                    .set_debug_name(&vk::DebugUtilsObjectNameInfoEXT {
81                        object_type,
82                        object_handle: self.raw.as_raw(),
83                        p_object_name: name.as_ptr(),
84                        ..Default::default()
85                    })
86            }
87        }
88
89        impl std::fmt::Debug for $name {
90            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91                f.debug_struct(stringify!($name))
92                    .field("raw", &self.raw)
93                    .field("device", &self.device)
94                    .finish()
95            }
96        }
97
98        impl std::ops::Deref for $name {
99            type Target = $raw_type;
100
101            fn deref(&self) -> &Self::Target {
102                &self.raw
103            }
104        }
105
106        impl Drop for $name {
107            fn drop(&mut self) {
108                unsafe { self.device.$destroy(self.raw, None) }
109            }
110        }
111    };
112}
113
114resource!(
115    Sampler,
116    vk::Sampler,
117    vk::Sampler::TYPE,
118    vk::SamplerCreateInfo,
119    create_sampler,
120    destroy_sampler
121);
122
123resource!(
124    Image,
125    vk::Image,
126    vk::Image::TYPE,
127    vk::ImageCreateInfo,
128    create_image,
129    destroy_image
130);
131
132resource!(
133    Fence,
134    vk::Fence,
135    vk::Fence::TYPE,
136    vk::FenceCreateInfo,
137    create_fence,
138    destroy_fence
139);
140
141resource!(
142    DeviceMemory,
143    vk::DeviceMemory,
144    vk::DeviceMemory::TYPE,
145    vk::MemoryAllocateInfo,
146    allocate_memory,
147    free_memory
148);
149
150resource!(
151    Buffer,
152    vk::Buffer,
153    vk::Buffer::TYPE,
154    vk::BufferCreateInfo,
155    create_buffer,
156    destroy_buffer
157);
158
159resource!(
160    DescriptorPool,
161    vk::DescriptorPool,
162    vk::DescriptorPool::TYPE,
163    vk::DescriptorPoolCreateInfo,
164    create_descriptor_pool,
165    destroy_descriptor_pool
166);
167
168resource!(
169    DescriptorSetLayout,
170    vk::DescriptorSetLayout,
171    vk::DescriptorSetLayout::TYPE,
172    vk::DescriptorSetLayoutCreateInfo,
173    create_descriptor_set_layout,
174    destroy_descriptor_set_layout
175);
176
177resource!(
178    ImageView,
179    vk::ImageView,
180    vk::ImageView::TYPE,
181    vk::ImageViewCreateInfo,
182    create_image_view,
183    destroy_image_view
184);
185
186resource!(
187    Semaphore,
188    vk::Semaphore,
189    vk::Semaphore::TYPE,
190    vk::SemaphoreCreateInfo,
191    create_semaphore,
192    destroy_semaphore
193);
194
195resource!(
196    CommandPool,
197    vk::CommandPool,
198    vk::CommandPool::TYPE,
199    vk::CommandPoolCreateInfo,
200    create_command_pool,
201    destroy_command_pool
202);
203
204resource!(
205    RenderPass,
206    vk::RenderPass,
207    vk::RenderPass::TYPE,
208    vk::RenderPassCreateInfo,
209    create_render_pass,
210    destroy_render_pass
211);
212
213resource!(
214    Framebuffer,
215    vk::Framebuffer,
216    vk::Framebuffer::TYPE,
217    vk::FramebufferCreateInfo,
218    create_framebuffer,
219    destroy_framebuffer
220);
221
222resource!(
223    ShaderModule,
224    vk::ShaderModule,
225    vk::ShaderModule::TYPE,
226    vk::ShaderModuleCreateInfo,
227    create_shader_module,
228    destroy_shader_module
229);
230
231resource!(
232    PipelineLayout,
233    vk::PipelineLayout,
234    vk::PipelineLayout::TYPE,
235    vk::PipelineLayoutCreateInfo,
236    create_pipeline_layout,
237    destroy_pipeline_layout
238);
239
240// Pipeline is a special case because there are separate create infos for each
241// kind of pipeline.
242resource_impl!(Pipeline, vk::Pipeline, vk::Pipeline::TYPE, destroy_pipeline);
243
244impl Pipeline {
245    pub fn new_graphics_pipeline(
246        device: Arc<raii::Device>,
247        create_info: &vk::GraphicsPipelineCreateInfo,
248    ) -> Result<Self> {
249        let result = unsafe {
250            device.create_graphics_pipelines(
251                vk::PipelineCache::null(),
252                &[*create_info],
253                None,
254            )
255        };
256        let raw = match result {
257            Ok(pipelines) => pipelines[0],
258            Err((_, result)) => {
259                return Err(result).with_context(trace!(
260                    "Error while creating graphics pipeline!"
261                ));
262            }
263        };
264        Ok(Self { device, raw })
265    }
266
267    pub fn new_compute_pipeline(
268        device: Arc<raii::Device>,
269        create_info: &vk::ComputePipelineCreateInfo,
270    ) -> Result<Self> {
271        let result = unsafe {
272            device.create_compute_pipelines(
273                vk::PipelineCache::null(),
274                &[*create_info],
275                None,
276            )
277        };
278        let raw = match result {
279            Ok(pipelines) => pipelines[0],
280            Err((_, result)) => {
281                return Err(result).with_context(trace!(
282                    "Error while creating compute pipeline!"
283                ));
284            }
285        };
286        Ok(Self { device, raw })
287    }
288}