MXVK Vulkan Framework 0.24.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
mxvk_point_sprite_batch.cpp
Go to the documentation of this file.
2
3#include "mxvk/mxvk.hpp"
6
7#include <array>
8#include <cstddef>
9#include <cstring>
10#include <format>
11
12namespace mxvk {
13
17
19 const std::string &texture_path_value,
20 const std::string &vertex_shader_path_value,
21 const std::string &fragment_shader_path_value,
22 size_t max_vertex_count) {
23 if (window == nullptr) {
24 throw mxvk::Exception("VK_PointSpriteBatch::load called with null window");
25 }
26 if (max_vertex_count == 0) {
27 throw mxvk::Exception("VK_PointSpriteBatch::load requires non-zero vertex capacity");
28 }
29
30 cleanup();
31 context = {
32 .device = window->getDevice(),
33 .physical_device = window->getPhysicalDevice(),
34 .graphics_queue = window->getGraphicsQueue(),
35 .command_pool = window->getCommandPool(),
36 };
37 pipeline_cache = window->getPipelineCache();
38 color_attachment_format = window->getSwapchainFormat();
39 depth_attachment_format = window->getDepthFormat();
40 image_count = window->getSwapchainImageCount();
41 texture_path = texture_path_value;
42 vertex_shader_path = vertex_shader_path_value;
43 fragment_shader_path = fragment_shader_path_value;
44 max_vertices = max_vertex_count;
45
46 if (context.device == VK_NULL_HANDLE || context.physical_device == VK_NULL_HANDLE ||
47 context.graphics_queue == VK_NULL_HANDLE || context.command_pool == VK_NULL_HANDLE) {
48 throw mxvk::Exception("Cannot create point-sprite batch before Vulkan render resources are available");
49 }
50 if (color_attachment_format == VK_FORMAT_UNDEFINED || image_count == 0) {
51 throw mxvk::Exception("Cannot create point-sprite batch before swapchain resources are available");
52 }
53
54 create_texture_from_png(context, texture_path, texture);
55 create_vertex_buffer();
56 create_swapchain_resources();
57 batch_loaded = true;
58 }
59
61 if (!batch_loaded || window == nullptr) {
62 return;
63 }
64
65 context.device = window->getDevice();
66 context.physical_device = window->getPhysicalDevice();
67 context.graphics_queue = window->getGraphicsQueue();
68 context.command_pool = window->getCommandPool();
69 pipeline_cache = window->getPipelineCache();
70 color_attachment_format = window->getSwapchainFormat();
71 depth_attachment_format = window->getDepthFormat();
72 image_count = window->getSwapchainImageCount();
73
74 cleanup_swapchain_resources();
75 create_swapchain_resources();
76 }
77
79 cleanup_swapchain_resources();
80 destroy_vertex_buffer();
81 destroy_texture(context.device, texture);
82 context = {};
83 pipeline_cache = VK_NULL_HANDLE;
84 color_attachment_format = VK_FORMAT_UNDEFINED;
85 depth_attachment_format = VK_FORMAT_UNDEFINED;
86 image_count = 0;
87 texture_path.clear();
88 vertex_shader_path.clear();
89 fragment_shader_path.clear();
90 max_vertices = 0;
91 active_vertices = 0;
92 batch_loaded = false;
93 }
94
95 void VK_PointSpriteBatch::upload_vertices(const PointSpriteVertex *vertices, size_t count) {
96 if (!batch_loaded || vertex_buffer.mapped == nullptr || vertices == nullptr || count == 0) {
97 active_vertices = 0;
98 return;
99 }
100 if (count > max_vertices) {
101 throw mxvk::Exception("VK_PointSpriteBatch::upload_vertices exceeds batch capacity");
102 }
103
104 std::memcpy(vertex_buffer.mapped, vertices, count * sizeof(PointSpriteVertex));
105 active_vertices = count;
106 }
107
108 void VK_PointSpriteBatch::update_mvp(uint32_t image_index, const glm::mat4 &mvp) {
109 if (image_index >= uniform_buffers.size() || uniform_buffers[image_index].mapped == nullptr) {
110 return;
111 }
112
113 UniformBufferObject ubo{};
114 ubo.mvp = mvp;
115 std::memcpy(uniform_buffers[image_index].mapped, &ubo, sizeof(ubo));
116 }
117
118 void VK_PointSpriteBatch::render(VkCommandBuffer cmd, uint32_t image_index) {
119 if (!batch_loaded || active_vertices == 0 || pipeline == VK_NULL_HANDLE || image_index >= descriptor_sets.size()) {
120 return;
121 }
122
123 vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
124 VkBuffer buffers[] = {vertex_buffer.buffer};
125 VkDeviceSize offsets[] = {0};
126 vkCmdBindVertexBuffers(cmd, 0, 1, buffers, offsets);
127 vkCmdBindDescriptorSets(
128 cmd,
129 VK_PIPELINE_BIND_POINT_GRAPHICS,
130 pipeline_layout,
131 0,
132 1,
133 &descriptor_sets[image_index],
134 0,
135 nullptr);
136 vkCmdDraw(cmd, static_cast<uint32_t>(active_vertices), 1, 0, 0);
137 }
138
140 if (additive_blending == enabled) {
141 return;
142 }
143 additive_blending = enabled;
144 if (batch_loaded) {
145 destroy_pipeline();
146 create_pipeline();
147 }
148 }
149
151 if (depth_test_enabled == enabled) {
152 return;
153 }
154 depth_test_enabled = enabled;
155 if (batch_loaded) {
156 destroy_pipeline();
157 create_pipeline();
158 }
159 }
160
162 if (depth_write_enabled == enabled) {
163 return;
164 }
165 depth_write_enabled = enabled;
166 if (batch_loaded) {
167 destroy_pipeline();
168 create_pipeline();
169 }
170 }
171
172 void VK_PointSpriteBatch::create_vertex_buffer() {
174 context,
175 sizeof(PointSpriteVertex) * static_cast<VkDeviceSize>(max_vertices),
176 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
177 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
178 vertex_buffer);
179 map_buffer(context.device, vertex_buffer);
180 }
181
182 void VK_PointSpriteBatch::destroy_vertex_buffer() {
183 destroy_buffer(context.device, vertex_buffer);
184 }
185
186 void VK_PointSpriteBatch::create_swapchain_resources() {
187 create_descriptor_set_layout();
188 create_uniform_buffers();
189 create_descriptor_pool();
190 create_descriptor_sets();
191 create_pipeline();
192 }
193
194 void VK_PointSpriteBatch::cleanup_swapchain_resources() {
195 if (context.device == VK_NULL_HANDLE) {
196 descriptor_sets.clear();
197 uniform_buffers.clear();
198 return;
199 }
200 destroy_pipeline();
201 if (descriptor_pool != VK_NULL_HANDLE) {
202 vkDestroyDescriptorPool(context.device, descriptor_pool, nullptr);
203 descriptor_pool = VK_NULL_HANDLE;
204 }
205 if (descriptor_set_layout != VK_NULL_HANDLE) {
206 vkDestroyDescriptorSetLayout(context.device, descriptor_set_layout, nullptr);
207 descriptor_set_layout = VK_NULL_HANDLE;
208 }
209 destroy_uniform_buffers();
210 descriptor_sets.clear();
211 }
212
213 void VK_PointSpriteBatch::create_descriptor_set_layout() {
214 VkDescriptorSetLayoutBinding sampler_binding{};
215 sampler_binding.binding = 0;
216 sampler_binding.descriptorCount = 1;
217 sampler_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
218 sampler_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
219
220 VkDescriptorSetLayoutBinding ubo_binding{};
221 ubo_binding.binding = 1;
222 ubo_binding.descriptorCount = 1;
223 ubo_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
224 ubo_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
225
226 std::array<VkDescriptorSetLayoutBinding, 2> bindings{sampler_binding, ubo_binding};
227 VkDescriptorSetLayoutCreateInfo layout_info{};
228 layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
229 layout_info.bindingCount = static_cast<uint32_t>(bindings.size());
230 layout_info.pBindings = bindings.data();
231 if (vkCreateDescriptorSetLayout(context.device, &layout_info, nullptr, &descriptor_set_layout) != VK_SUCCESS) {
232 throw mxvk::Exception("failed to create point-sprite descriptor set layout");
233 }
234 }
235
236 void VK_PointSpriteBatch::create_uniform_buffers() {
237 uniform_buffers.resize(image_count);
238 for (auto &buffer : uniform_buffers) {
240 context,
241 sizeof(UniformBufferObject),
242 VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
243 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
244 buffer);
245 map_buffer(context.device, buffer);
246 }
247 }
248
249 void VK_PointSpriteBatch::destroy_uniform_buffers() {
250 for (auto &buffer : uniform_buffers) {
251 destroy_buffer(context.device, buffer);
252 }
253 uniform_buffers.clear();
254 }
255
256 void VK_PointSpriteBatch::create_descriptor_pool() {
257 const uint32_t count = static_cast<uint32_t>(image_count);
258 std::array<VkDescriptorPoolSize, 2> pool_sizes{};
259 pool_sizes[0].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
260 pool_sizes[0].descriptorCount = count;
261 pool_sizes[1].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
262 pool_sizes[1].descriptorCount = count;
263
264 VkDescriptorPoolCreateInfo pool_info{};
265 pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
266 pool_info.poolSizeCount = static_cast<uint32_t>(pool_sizes.size());
267 pool_info.pPoolSizes = pool_sizes.data();
268 pool_info.maxSets = count;
269 if (vkCreateDescriptorPool(context.device, &pool_info, nullptr, &descriptor_pool) != VK_SUCCESS) {
270 throw mxvk::Exception("failed to create point-sprite descriptor pool");
271 }
272 }
273
274 void VK_PointSpriteBatch::create_descriptor_sets() {
275 std::vector<VkDescriptorSetLayout> layouts(image_count, descriptor_set_layout);
276 VkDescriptorSetAllocateInfo alloc_info{};
277 alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
278 alloc_info.descriptorPool = descriptor_pool;
279 alloc_info.descriptorSetCount = static_cast<uint32_t>(image_count);
280 alloc_info.pSetLayouts = layouts.data();
281
282 descriptor_sets.resize(image_count, VK_NULL_HANDLE);
283 if (vkAllocateDescriptorSets(context.device, &alloc_info, descriptor_sets.data()) != VK_SUCCESS) {
284 throw mxvk::Exception("failed to allocate point-sprite descriptor sets");
285 }
286
287 for (size_t i = 0; i < image_count; ++i) {
288 VkDescriptorImageInfo image_info{};
289 image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
290 image_info.imageView = texture.view;
291 image_info.sampler = texture.sampler;
292
293 VkDescriptorBufferInfo buffer_info{};
294 buffer_info.buffer = uniform_buffers[i].buffer;
295 buffer_info.offset = 0;
296 buffer_info.range = sizeof(UniformBufferObject);
297
298 std::array<VkWriteDescriptorSet, 2> writes{};
299 writes[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
300 writes[0].dstSet = descriptor_sets[i];
301 writes[0].dstBinding = 0;
302 writes[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
303 writes[0].descriptorCount = 1;
304 writes[0].pImageInfo = &image_info;
305 writes[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
306 writes[1].dstSet = descriptor_sets[i];
307 writes[1].dstBinding = 1;
308 writes[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
309 writes[1].descriptorCount = 1;
310 writes[1].pBufferInfo = &buffer_info;
311
312 vkUpdateDescriptorSets(context.device, static_cast<uint32_t>(writes.size()), writes.data(), 0, nullptr);
313 }
314 }
315
316 void VK_PointSpriteBatch::create_pipeline() {
317 destroy_pipeline();
318
319 const std::vector<char> vert_code = read_shader_file(vertex_shader_path);
320 const std::vector<char> frag_code = read_shader_file(fragment_shader_path);
321 const VkShaderModule vert_module = mxvk::create_shader_module(context.device, vert_code);
322 VkShaderModule frag_module = VK_NULL_HANDLE;
323
324 try {
325 frag_module = mxvk::create_shader_module(context.device, frag_code);
326
327 VkPipelineShaderStageCreateInfo vert_stage{};
328 vert_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
329 vert_stage.stage = VK_SHADER_STAGE_VERTEX_BIT;
330 vert_stage.module = vert_module;
331 vert_stage.pName = "main";
332
333 VkPipelineShaderStageCreateInfo frag_stage{};
334 frag_stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
335 frag_stage.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
336 frag_stage.module = frag_module;
337 frag_stage.pName = "main";
338 std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages = {vert_stage, frag_stage};
339
340 VkVertexInputBindingDescription binding{};
341 binding.binding = 0;
342 binding.stride = sizeof(PointSpriteVertex);
343 binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
344
345 std::array<VkVertexInputAttributeDescription, 3> attributes{};
346 attributes[0].binding = 0;
347 attributes[0].location = 0;
348 attributes[0].format = VK_FORMAT_R32G32B32_SFLOAT;
349 attributes[0].offset = offsetof(PointSpriteVertex, position);
350 attributes[1].binding = 0;
351 attributes[1].location = 1;
352 attributes[1].format = VK_FORMAT_R32_SFLOAT;
353 attributes[1].offset = offsetof(PointSpriteVertex, size);
354 attributes[2].binding = 0;
355 attributes[2].location = 2;
356 attributes[2].format = VK_FORMAT_R32G32B32A32_SFLOAT;
357 attributes[2].offset = offsetof(PointSpriteVertex, color);
358
359 VkPipelineVertexInputStateCreateInfo vertex_input{};
360 vertex_input.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
361 vertex_input.vertexBindingDescriptionCount = 1;
362 vertex_input.pVertexBindingDescriptions = &binding;
363 vertex_input.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributes.size());
364 vertex_input.pVertexAttributeDescriptions = attributes.data();
365
366 VkPipelineInputAssemblyStateCreateInfo input_assembly{};
367 input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
368 input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
369 input_assembly.primitiveRestartEnable = VK_FALSE;
370
371 std::array<VkDynamicState, 2> dynamic_states = {VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR};
372 VkPipelineDynamicStateCreateInfo dynamic_state{};
373 dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
374 dynamic_state.dynamicStateCount = static_cast<uint32_t>(dynamic_states.size());
375 dynamic_state.pDynamicStates = dynamic_states.data();
376
377 VkPipelineViewportStateCreateInfo viewport_state{};
378 viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
379 viewport_state.viewportCount = 1;
380 viewport_state.scissorCount = 1;
381
382 VkPipelineRasterizationStateCreateInfo rasterizer{};
383 rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
384 rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
385 rasterizer.cullMode = VK_CULL_MODE_NONE;
386 rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
387 rasterizer.lineWidth = 1.0f;
388
389 VkPipelineMultisampleStateCreateInfo multisampling{};
390 multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
391 multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
392
393 VkPipelineDepthStencilStateCreateInfo depth_stencil{};
394 depth_stencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
395 depth_stencil.depthTestEnable = depth_test_enabled ? VK_TRUE : VK_FALSE;
396 depth_stencil.depthWriteEnable = depth_write_enabled ? VK_TRUE : VK_FALSE;
397 depth_stencil.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
398
399 VkPipelineColorBlendAttachmentState blend{};
400 blend.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
401 VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
402 blend.blendEnable = VK_TRUE;
403 blend.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
404 blend.dstColorBlendFactor = additive_blending ? VK_BLEND_FACTOR_ONE : VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
405 blend.colorBlendOp = VK_BLEND_OP_ADD;
406 blend.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
407 blend.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
408 blend.alphaBlendOp = VK_BLEND_OP_ADD;
409
410 VkPipelineColorBlendStateCreateInfo color_blending{};
411 color_blending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
412 color_blending.attachmentCount = 1;
413 color_blending.pAttachments = &blend;
414
415 VkPipelineLayoutCreateInfo layout_info{};
416 layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
417 layout_info.setLayoutCount = 1;
418 layout_info.pSetLayouts = &descriptor_set_layout;
419 if (vkCreatePipelineLayout(context.device, &layout_info, nullptr, &pipeline_layout) != VK_SUCCESS) {
420 throw mxvk::Exception("failed to create point-sprite pipeline layout");
421 }
422
423 VkPipelineRenderingCreateInfo rendering_info{};
424 rendering_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
425 rendering_info.colorAttachmentCount = 1;
426 rendering_info.pColorAttachmentFormats = &color_attachment_format;
427 rendering_info.depthAttachmentFormat = depth_attachment_format;
428 rendering_info.stencilAttachmentFormat = VK_FORMAT_UNDEFINED;
429
430 VkGraphicsPipelineCreateInfo pipeline_info{};
431 pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
432 pipeline_info.pNext = &rendering_info;
433 pipeline_info.stageCount = static_cast<uint32_t>(shader_stages.size());
434 pipeline_info.pStages = shader_stages.data();
435 pipeline_info.pVertexInputState = &vertex_input;
436 pipeline_info.pInputAssemblyState = &input_assembly;
437 pipeline_info.pViewportState = &viewport_state;
438 pipeline_info.pRasterizationState = &rasterizer;
439 pipeline_info.pMultisampleState = &multisampling;
440 pipeline_info.pDepthStencilState = &depth_stencil;
441 pipeline_info.pColorBlendState = &color_blending;
442 pipeline_info.pDynamicState = &dynamic_state;
443 pipeline_info.layout = pipeline_layout;
444 pipeline_info.renderPass = VK_NULL_HANDLE;
445 if (vkCreateGraphicsPipelines(context.device, pipeline_cache, 1, &pipeline_info, nullptr, &pipeline) != VK_SUCCESS) {
446 throw mxvk::Exception("failed to create point-sprite graphics pipeline");
447 }
448 } catch (...) {
449 if (frag_module != VK_NULL_HANDLE) {
450 vkDestroyShaderModule(context.device, frag_module, nullptr);
451 }
452 vkDestroyShaderModule(context.device, vert_module, nullptr);
453 throw;
454 }
455
456 vkDestroyShaderModule(context.device, frag_module, nullptr);
457 vkDestroyShaderModule(context.device, vert_module, nullptr);
458 }
459
460 void VK_PointSpriteBatch::destroy_pipeline() {
461 if (context.device == VK_NULL_HANDLE) {
462 pipeline = VK_NULL_HANDLE;
463 pipeline_layout = VK_NULL_HANDLE;
464 return;
465 }
466 if (pipeline != VK_NULL_HANDLE) {
467 vkDestroyPipeline(context.device, pipeline, nullptr);
468 pipeline = VK_NULL_HANDLE;
469 }
470 if (pipeline_layout != VK_NULL_HANDLE) {
471 vkDestroyPipelineLayout(context.device, pipeline_layout, nullptr);
472 pipeline_layout = VK_NULL_HANDLE;
473 }
474 }
475
476 std::vector<char> VK_PointSpriteBatch::read_shader_file(const std::string &path) const {
477 return mxvk::load_spv(path);
478 }
479
480} // namespace mxvk
~VK_PointSpriteBatch()
Destroy all owned Vulkan resources.
void load(VK_Window *window, const std::string &texture_path, const std::string &vertex_shader_path, const std::string &fragment_shader_path, size_t max_vertices)
Create texture, vertex buffer, descriptors, and point-list pipeline.
void set_depth_write_enabled(bool enabled)
Enable or disable depth writes in the point-sprite pipeline.
void render(VkCommandBuffer cmd, uint32_t image_index)
Record point-sprite draw commands into an active rendering scope.
void update_mvp(uint32_t image_index, const glm::mat4 &mvp)
Update the MVP uniform for one swapchain image.
void resize(VK_Window *window)
Recreate swapchain-dependent resources after a window resize.
void cleanup()
Destroy all owned resources and reset the batch to an unloaded state.
void set_additive_blending(bool enabled)
Select additive or alpha-over color blending.
void upload_vertices(const PointSpriteVertex *vertices, size_t count)
Copy point vertices into the persistent mapped vertex buffer.
void set_depth_test_enabled(bool enabled)
Enable or disable depth testing in the point-sprite pipeline.
Main Vulkan window wrapper for MXVK.
Definition mxvk.hpp:37
VkDevice getDevice() const noexcept
Get the Vulkan logical device handle.
Definition mxvk.hpp:168
VkQueue getGraphicsQueue() const noexcept
Get the graphics queue handle.
Definition mxvk.hpp:174
VkCommandPool getCommandPool() const noexcept
Get the command pool used for graphics/upload work.
Definition mxvk.hpp:177
size_t getSwapchainImageCount() const noexcept
Get the number of swapchain images currently allocated.
Definition mxvk.hpp:192
VkFormat getDepthFormat() const noexcept
Get the depth format used for dynamic rendering attachments.
Definition mxvk.hpp:189
VkPipelineCache getPipelineCache() const noexcept
Get the persistent Vulkan pipeline cache used by framework pipelines.
Definition mxvk.hpp:180
VkPhysicalDevice getPhysicalDevice() const noexcept
Get the Vulkan physical device handle.
Definition mxvk.hpp:171
VkFormat getSwapchainFormat() const noexcept
Get the swapchain color format.
Definition mxvk.hpp:183
Reusable point-sprite renderer for particle and starfield effects.
Utilities for loading and saving PNG images.
Definition mxvk.hpp:30
VkShaderModule create_shader_module(VkDevice device, const std::vector< char > &spv_bytes)
Create a shader module from SPIR-V bytecode.
void create_texture_from_png(const VulkanContext &context, const std::string &path, TextureResource &texture, VkFormat format=VK_FORMAT_R8G8B8A8_UNORM)
Load a PNG and upload it into a sampled 2D texture.
void map_buffer(VkDevice device, BufferResource &buffer)
Persistently map a host-visible buffer allocation.
void create_buffer(const VulkanContext &context, VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, BufferResource &buffer)
Create and bind a Vulkan buffer allocation.
void destroy_buffer(VkDevice device, BufferResource &buffer)
Unmap and destroy a BufferResource.
std::vector< char > load_spv(const std::string &path)
Load a SPIR-V file from disk.
void destroy_texture(VkDevice device, TextureResource &texture)
Destroy every Vulkan handle owned by a TextureResource.
Vertex layout consumed by VK_PointSpriteBatch.
VkDevice device
Logical device used to create and destroy resources.