Aeon Engine c550894
AeonGames Open Source Game Engine
Loading...
Searching...
No Matches
VulkanRenderer.cpp
1/*
2Copyright (C) 2016-2021,2025,2026 Rodrigo Jose Hernandez Cordoba
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17/* Reference and Credits:
18 Vulkan SDK Demo code.
19 https://www.youtube.com/playlist?list=PLUXvZMiAqNbK8jd7s52BIDtCbZnKNGp0P
20 https://vulkan.lunarg.com/app/docs/v1.0.8.0/layers
21 https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_debug_utils.html
22*/
23
24#include <cassert>
25#include <cstring>
26#include <iostream>
27#include <sstream>
28#include <array>
29#include <algorithm>
30#include <limits>
31#include "VulkanRenderer.hpp"
32#include "VulkanWindow.hpp"
33#include "VulkanBuffer.hpp"
34#include "VulkanUtilities.hpp"
36#include "aeongames/Mesh.hpp"
37#include "aeongames/Pipeline.hpp"
38#include "aeongames/Material.hpp"
39#include "aeongames/Texture.hpp"
40#include "aeongames/Utilities.hpp"
41#include "aeongames/MemoryPool.hpp"
42#include "SPIR-V/CompilerLinker.hpp"
43
44namespace AeonGames
45{
47 {
48 try
49 {
50 SetupLayersAndExtensions();
51 if ( mValidate )
52 {
53 SetupDebug();
54 }
55 InitializeInstance();
56 if ( mValidate )
57 {
58 /* LoadFunctions currently only loads
59 Debug Functions. */
60 LoadFunctions();
61 InitializeDebug();
62 }
63 InitializeDevice();
64 InitializeCommandPools();
65 AttachWindow ( aWindow );
66 }
67 catch ( ... )
68 {
69 this->~VulkanRenderer();
70 throw;
71 }
72 }
73
74 VulkanRenderer::~VulkanRenderer()
75 {
76 vkQueueWaitIdle ( mVkQueue );
77 mWindowStore.clear();
78 mTextureStore.clear();
79 mMaterialStore.clear();
80 mPipelineStore.clear();
81 mMeshStore.clear();
82 for ( auto& i : mVkDescriptorSetLayouts )
83 {
84 vkDestroyDescriptorSetLayout ( mVkDevice, std::get<1> ( i ), nullptr );
85 }
86 mVkDescriptorSetLayouts.clear();
87 FinalizeCommandPools();
88 FinalizeDevice();
89 FinalizeDebug();
90 FinalizeInstance();
91 }
92
93 const VkDevice & VulkanRenderer::GetDevice() const
94 {
95 return mVkDevice;
96 }
97
98 const VkQueue & VulkanRenderer::GetQueue() const
99 {
100 return mVkQueue;
101 }
102
103 const VkInstance & VulkanRenderer::GetInstance() const
104 {
105 return mVkInstance;
106 }
107
108 const VkPhysicalDevice & VulkanRenderer::GetPhysicalDevice() const
109 {
110 return mVkPhysicalDevice;
111 }
112
113 const VkPhysicalDeviceProperties & VulkanRenderer::GetPhysicalDeviceProperties() const
114 {
115 return mVkPhysicalDeviceProperties;
116 }
117
118 const VkPhysicalDeviceMemoryProperties & VulkanRenderer::GetPhysicalDeviceMemoryProperties() const
119 {
120 return mVkPhysicalDeviceMemoryProperties;
121 }
122
123 VkRenderPass VulkanRenderer::GetRenderPass() const
124 {
125 auto it = mWindowStore.begin();
126 if ( it != mWindowStore.end() )
127 {
128 return it->second.GetRenderPass();
129 }
130 std::cout << LogLevel::Error << __FUNCTION__ << " No RenderPass found!" << std::endl;
131 return VK_NULL_HANDLE;
132 }
133
135 {
136 return mQueueFamilyIndex;
137 }
138
139 uint32_t VulkanRenderer::FindMemoryTypeIndex ( uint32_t typeFilter, VkMemoryPropertyFlags properties ) const
140 {
141 for ( uint32_t i = 0; i < mVkPhysicalDeviceMemoryProperties.memoryTypeCount; ++i )
142 {
143 if ( ( typeFilter & ( 1 << i ) ) && ( mVkPhysicalDeviceMemoryProperties.memoryTypes[i].propertyFlags & properties ) == properties )
144 {
145 return i;
146 }
147 }
148 return std::numeric_limits<uint32_t>::max();
149 }
150
151#if defined (VK_USE_PLATFORM_XLIB_KHR)
152 Display* VulkanRenderer::GetDisplay() const
153 {
154 return mDisplay;
155 }
156#endif
157
158 uint32_t VulkanRenderer::GetMemoryTypeIndex ( VkMemoryPropertyFlags aVkMemoryPropertyFlags ) const
159 {
160 for ( uint32_t i = 0; i < mVkPhysicalDeviceMemoryProperties.memoryTypeCount; ++i )
161 {
162 if ( ( mVkPhysicalDeviceMemoryProperties.memoryTypes[i].propertyFlags &
163 ( aVkMemoryPropertyFlags ) ) == ( aVkMemoryPropertyFlags ) )
164 {
165 return i;
166 }
167 }
168 return std::numeric_limits<uint32_t>::max();
169 }
170
171 void VulkanRenderer::LoadFunctions()
172 {
173 assert ( mVkInstance && "mVkInstance is a nullptr." );
174 if ( !mFunctionsLoaded && mVkInstance )
175 {
176
177 if ( ( vkCreateDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT> ( vkGetInstanceProcAddr ( mVkInstance, "vkCreateDebugUtilsMessengerEXT" ) ) ) == nullptr )
178 {
179 std::cout << LogLevel::Error << "vkGetInstanceProcAddr failed to load vkCreateDebugUtilsMessengerEXT" << std::endl;
180 throw std::runtime_error ( "vkGetInstanceProcAddr failed to load vkCreateDebugUtilsMessengerEXT" );
181 }
182 if ( ( vkDestroyDebugUtilsMessengerEXT = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT> ( vkGetInstanceProcAddr ( mVkInstance, "vkDestroyDebugUtilsMessengerEXT" ) ) ) == nullptr )
183 {
184 std::cout << LogLevel::Error << "vkGetInstanceProcAddr failed to load vkDestroyDebugUtilsMessengerEXT" << std::endl;
185 throw std::runtime_error ( "vkGetInstanceProcAddr failed to load vkDestroyDebugUtilsMessengerEXT" );
186 }
187 mFunctionsLoaded = true;
188 }
189 }
190
191
192 void VulkanRenderer::SetupDebug()
193 {
194 mInstanceExtensionNames.emplace_back ( VK_EXT_DEBUG_UTILS_EXTENSION_NAME );
195 mInstanceExtensionNames.emplace_back ( VK_EXT_DEBUG_REPORT_EXTENSION_NAME );
196 mInstanceLayerNames.emplace_back ( "VK_LAYER_KHRONOS_validation" );
197 }
198
199 void VulkanRenderer::InitializeDebug()
200 {
201 VkDebugUtilsMessengerCreateInfoEXT debug_utils_messenger_create_info_ext
202 {
203 VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
204 nullptr,
205 0,
206 VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT |
207 VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT |
208 VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
209 VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
210 VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
211 VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
212 VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
214 nullptr
215 };
216
217 if ( VkResult result = vkCreateDebugUtilsMessengerEXT ( mVkInstance, &debug_utils_messenger_create_info_ext, nullptr, &mVkDebugUtilsMessengerEXT ) )
218 {
219 std::ostringstream stream;
220 stream << "Could not create Debug Utils Messenger. error code: ( " << GetVulkanResultString ( result ) << " )";
221 std::string error_string = stream.str();
222 std::cout << LogLevel::Error << error_string << std::endl;
223 throw std::runtime_error ( error_string.c_str() );
224 }
225 }
226
227 void VulkanRenderer::SetupLayersAndExtensions()
228 {
229 mInstanceExtensionNames.push_back ( VK_KHR_SURFACE_EXTENSION_NAME );
230#ifdef VK_USE_PLATFORM_WIN32_KHR
231 mInstanceExtensionNames.push_back ( VK_KHR_WIN32_SURFACE_EXTENSION_NAME );
232 mDeviceExtensionNames.push_back ( VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME );
233#elif defined (VK_USE_PLATFORM_METAL_EXT)
234 mInstanceExtensionNames.push_back ( VK_EXT_METAL_SURFACE_EXTENSION_NAME );
235 mInstanceExtensionNames.push_back ( VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME );
236 mInstanceExtensionNames.push_back ( VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME );
237 mDeviceExtensionNames.push_back ( "VK_KHR_portability_subset" );
238#elif defined (VK_USE_PLATFORM_XLIB_KHR)
239 mInstanceExtensionNames.push_back ( VK_KHR_XLIB_SURFACE_EXTENSION_NAME );
240#endif
241 mDeviceExtensionNames.push_back ( VK_KHR_SWAPCHAIN_EXTENSION_NAME );
242 }
243
244 void VulkanRenderer::InitializeInstance()
245 {
246 VkInstanceCreateInfo instance_create_info {};
247 VkApplicationInfo application_info {};
248
249 application_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
250 application_info.apiVersion = VK_API_VERSION_1_3;
251 application_info.applicationVersion = VK_MAKE_VERSION ( 0, 1, 0 );
252 application_info.pApplicationName = "AeonEngine Vulkan Renderer";
253
254 // Validate that all requested layers are available
255 {
256 uint32_t available_layer_count;
257 vkEnumerateInstanceLayerProperties ( &available_layer_count, nullptr );
258 std::vector<VkLayerProperties> available_layers ( available_layer_count );
259 vkEnumerateInstanceLayerProperties ( &available_layer_count, available_layers.data() );
260 std::cout << LogLevel::Info << "VulkanRenderer Available Layers" << std::endl;
261 for ( auto& i : available_layers )
262 {
263 std::cout << LogLevel::Info << " - " << i.layerName << ": " << i.description << std::endl;
264 {
265 uint32_t instance_extension_layer_count;
266 vkEnumerateInstanceExtensionProperties ( i.layerName, &instance_extension_layer_count, nullptr );
267 std::vector<VkExtensionProperties> instance_extension_layer_list ( instance_extension_layer_count );
268 vkEnumerateInstanceExtensionProperties ( i.layerName, &instance_extension_layer_count, instance_extension_layer_list.data() );
269 for ( auto& j : instance_extension_layer_list )
270 {
271 std::cout << LogLevel::Info << " - " << j.extensionName << std::endl;
272 }
273 }
274 }
275
276 for ( auto it = mInstanceLayerNames.begin(); it != mInstanceLayerNames.end(); )
277 {
278 bool layer_found = false;
279 for ( const auto& available_layer : available_layers )
280 {
281 if ( strcmp ( *it, available_layer.layerName ) == 0 )
282 {
283 layer_found = true;
284 break;
285 }
286 }
287 if ( !layer_found )
288 {
289 std::cout << LogLevel::Warning << "Requested layer '" << *it
290 << "' is not available." << std::endl;
291 it = mInstanceLayerNames.erase ( it ); // erase returns an iterator to the next element
292 }
293 else
294 {
295 ++it; // only increment if no erase occurred
296 }
297 }
298 }
299
300 // Validate that all requested extensions are available
301 {
302 // Get global instance extensions
303 uint32_t available_extension_count;
304 vkEnumerateInstanceExtensionProperties ( nullptr, &available_extension_count, nullptr );
305 std::vector<VkExtensionProperties> available_extensions ( available_extension_count );
306 vkEnumerateInstanceExtensionProperties ( nullptr, &available_extension_count, available_extensions.data() );
307
308 // Also get extensions provided by layers
309 std::vector<VkExtensionProperties> layer_extensions;
310 for ( const char * layer_name : mInstanceLayerNames )
311 {
312 uint32_t layer_extension_count;
313 vkEnumerateInstanceExtensionProperties ( layer_name, &layer_extension_count, nullptr );
314 std::vector<VkExtensionProperties> layer_ext_props ( layer_extension_count );
315 vkEnumerateInstanceExtensionProperties ( layer_name, &layer_extension_count, layer_ext_props.data() );
316 layer_extensions.insert ( layer_extensions.end(), layer_ext_props.begin(), layer_ext_props.end() );
317 }
318
319 std::cout << LogLevel::Info << "VulkanRenderer Available Instance Extensions" << std::endl;
320 for ( const auto& extension : available_extensions )
321 {
322 std::cout << LogLevel::Info << " - " << extension.extensionName << " (version " << extension.specVersion << ")" << std::endl;
323 }
324
325 for ( auto it = mInstanceExtensionNames.begin(); it != mInstanceExtensionNames.end(); )
326 {
327 bool extension_found = false;
328
329 // Check global extensions
330 for ( const auto& available_extension : available_extensions )
331 {
332 if ( strcmp ( *it, available_extension.extensionName ) == 0 )
333 {
334 extension_found = true;
335 break;
336 }
337 }
338
339 // If not found in global extensions, check layer extensions
340 if ( !extension_found )
341 {
342 for ( const auto& layer_extension : layer_extensions )
343 {
344 if ( strcmp ( *it, layer_extension.extensionName ) == 0 )
345 {
346 extension_found = true;
347 break;
348 }
349 }
350 }
351
352 if ( !extension_found )
353 {
354 std::cout << LogLevel::Warning << "Requested extension '" << *it
355 << "' is not available." << std::endl;
356 it = mInstanceExtensionNames.erase ( it ); // erase returns an iterator to the next element
357 }
358 else
359 {
360 ++it; // only increment if no erase occurred
361 }
362 }
363 }
364
365 instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
366 instance_create_info.pApplicationInfo = &application_info;
367 instance_create_info.enabledLayerCount = static_cast<uint32_t> ( mInstanceLayerNames.size() );
368 instance_create_info.ppEnabledLayerNames = mInstanceLayerNames.data();
369 instance_create_info.enabledExtensionCount = static_cast<uint32_t> ( mInstanceExtensionNames.size() );
370 instance_create_info.ppEnabledExtensionNames = mInstanceExtensionNames.data();
371#ifdef VK_USE_PLATFORM_METAL_EXT
372 instance_create_info.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
373#endif
374 if ( VkResult result = vkCreateInstance ( &instance_create_info, nullptr, &mVkInstance ) )
375 {
376 std::ostringstream stream;
377 stream << "Could not create VulkanRenderer instance. error code: ( " << GetVulkanResultString ( result ) << " )";
378 std::string error_string = stream.str();
379 std::cout << LogLevel::Error << error_string << std::endl;
380 throw std::runtime_error ( error_string.c_str() );
381 }
382 }
383
384 void VulkanRenderer::InitializeDevice()
385 {
386 if ( !mVkInstance )
387 {
388 std::cout << LogLevel::Error << "mVkInstance is a nullptr." << std::endl;
389 throw std::runtime_error ( "mVkInstance is a nullptr." );
390 }
391 {
392 uint32_t physical_device_count;
393 vkEnumeratePhysicalDevices ( mVkInstance, &physical_device_count, nullptr );
394
395 if ( physical_device_count == 0 )
396 {
397 std::cout << LogLevel::Error << "No VulkanRenderer physical device found" << std::endl;
398 throw std::runtime_error ( "No VulkanRenderer physical device found" );
399 }
400
401 std::vector<VkPhysicalDevice> physical_device_list ( physical_device_count );
402 vkEnumeratePhysicalDevices ( mVkInstance, &physical_device_count, physical_device_list.data() );
403
404 mVkPhysicalDevice = physical_device_list[0];
405 vkGetPhysicalDeviceProperties ( mVkPhysicalDevice, &mVkPhysicalDeviceProperties );
406 std::cout << LogLevel::Debug << "minUniformBufferOffsetAlignment: " << mVkPhysicalDeviceProperties.limits.minUniformBufferOffsetAlignment << std::endl;
407 std::cout << LogLevel::Debug << "maxUniformBufferRange: " << mVkPhysicalDeviceProperties.limits.maxUniformBufferRange << std::endl;
408 vkGetPhysicalDeviceMemoryProperties ( mVkPhysicalDevice, &mVkPhysicalDeviceMemoryProperties );
409 }
410 {
411 uint32_t family_properties_count;
412 vkGetPhysicalDeviceQueueFamilyProperties ( mVkPhysicalDevice, &family_properties_count, nullptr );
413 if ( family_properties_count == 0 )
414 {
415 std::cout << LogLevel::Error << "VulkanRenderer physical device has no queue family properties." << std::endl;
416 throw std::runtime_error ( "VulkanRenderer physical device has no queue family properties." );
417 }
418 std::vector<VkQueueFamilyProperties> family_properties_list ( family_properties_count );
419 vkGetPhysicalDeviceQueueFamilyProperties ( mVkPhysicalDevice, &family_properties_count, family_properties_list.data() );
420 bool graphics_queue_family_found = false;
421 for ( auto family_property = family_properties_list.begin();
422 family_property != family_properties_list.end();
423 ++family_property )
424 {
425 if ( family_property->queueFlags & VK_QUEUE_GRAPHICS_BIT )
426 {
427 graphics_queue_family_found = true;
428 mQueueFamilyIndex =
429 static_cast<uint32_t> ( family_property - family_properties_list.begin() );
430 break;
431 }
432 }
433 if ( !graphics_queue_family_found )
434 {
435 std::cout << LogLevel::Error << "No graphics queue family found." << std::endl;
436 throw std::runtime_error ( "No graphics queue family found." );
437 }
438 }
439
440 {
441 uint32_t extension_property_count;
442 vkEnumerateDeviceExtensionProperties ( mVkPhysicalDevice, nullptr, &extension_property_count, nullptr );
443 std::vector<VkExtensionProperties> extension_properties ( extension_property_count );
444 vkEnumerateDeviceExtensionProperties ( mVkPhysicalDevice, nullptr, &extension_property_count, extension_properties.data() );
445 std::cout << LogLevel::Info << "Vulkan Renderer Available Device Extensions" << std::endl;
446 for ( auto& i : extension_properties )
447 {
448 std::cout << LogLevel::Info << " - " << i.extensionName << " (version " << i.specVersion << ")" << std::endl;
449
450 if ( !strcmp ( i.extensionName, VK_EXT_DEBUG_MARKER_EXTENSION_NAME ) )
451 {
452 mDeviceExtensionNames.emplace_back ( VK_EXT_DEBUG_MARKER_EXTENSION_NAME );
453 }
454 }
455 }
456
458 float queue_priorities[] {1.0f};
459 VkDeviceQueueCreateInfo device_queue_create_info{};
460 device_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
461 device_queue_create_info.pNext = nullptr;
462 device_queue_create_info.queueCount = 1;
463 device_queue_create_info.queueFamilyIndex = mQueueFamilyIndex;
464 device_queue_create_info.pQueuePriorities = queue_priorities;
465
466#ifdef VK_USE_PLATFORM_METAL_EXT
467 // For some reason this causes a crash on AMD drivers on the RogAlly, so keep it MacOS only while I figure it out.
468 VkPhysicalDevicePrimitiveTopologyListRestartFeaturesEXT physical_device_primitive_topology_list_restart_features {};
469 physical_device_primitive_topology_list_restart_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT;
470 physical_device_primitive_topology_list_restart_features.pNext = nullptr;
471 physical_device_primitive_topology_list_restart_features.primitiveTopologyListRestart = VK_TRUE;
472 physical_device_primitive_topology_list_restart_features.primitiveTopologyPatchListRestart = VK_TRUE;
473#endif
474 VkDeviceCreateInfo device_create_info {};
475 device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
476#ifdef VK_USE_PLATFORM_METAL_EXT
477 // For some reason this causes a crash on AMD drivers on the RogAlly, so keep it MacOS only while I figure it out.
478 device_create_info.pNext = &physical_device_primitive_topology_list_restart_features;
479#else
480 device_create_info.pNext = nullptr;
481#endif
482 device_create_info.queueCreateInfoCount = 1;
483 device_create_info.pQueueCreateInfos = &device_queue_create_info;
484 device_create_info.enabledLayerCount = static_cast<uint32_t> ( mDeviceLayerNames.size() );
485 device_create_info.ppEnabledLayerNames = mDeviceLayerNames.data();
486 device_create_info.enabledExtensionCount = static_cast<uint32_t> ( mDeviceExtensionNames.size() );
487 device_create_info.ppEnabledExtensionNames = mDeviceExtensionNames.data();
488 device_create_info.pEnabledFeatures = nullptr;
489
491 if ( VkResult result = vkCreateDevice ( mVkPhysicalDevice, &device_create_info, nullptr, &mVkDevice ) )
492 {
493 std::ostringstream stream;
494 stream << "Could not create VulkanRenderer device. error code: ( " << GetVulkanResultString ( result ) << " )";
495 std::cout << LogLevel::Error << stream.str() << std::endl;
496 throw std::runtime_error ( stream.str().c_str() );
497 }
498 vkGetDeviceQueue ( mVkDevice, mQueueFamilyIndex, 0, &mVkQueue );
499 }
500
501 void VulkanRenderer::InitializeCommandPools()
502 {
503 VkCommandPoolCreateInfo command_pool_create_info{};
504 command_pool_create_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
505 command_pool_create_info.queueFamilyIndex = mQueueFamilyIndex;
506 command_pool_create_info.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
507 vkCreateCommandPool ( mVkDevice, &command_pool_create_info, nullptr, &mVkSingleTimeCommandPool );
508 }
509
510 void VulkanRenderer::FinalizeCommandPools()
511 {
512 if ( mVkSingleTimeCommandPool != VK_NULL_HANDLE )
513 {
514 vkDestroyCommandPool ( mVkDevice, mVkSingleTimeCommandPool, nullptr );
515 mVkSingleTimeCommandPool = VK_NULL_HANDLE;
516 }
517 }
518
519 void VulkanRenderer::FinalizeDebug()
520 {
521 if ( mVkInstance && ( mVkDebugUtilsMessengerEXT != VK_NULL_HANDLE ) )
522 {
523 vkDestroyDebugUtilsMessengerEXT ( mVkInstance, mVkDebugUtilsMessengerEXT, nullptr );
524 mVkDebugUtilsMessengerEXT = VK_NULL_HANDLE;
525 }
526 }
527
528 void VulkanRenderer::FinalizeInstance()
529 {
530 if ( mVkInstance != VK_NULL_HANDLE )
531 {
532 vkDestroyInstance ( mVkInstance, nullptr );
533 mVkInstance = VK_NULL_HANDLE;
534 }
535 }
536
537 void VulkanRenderer::FinalizeDevice()
538 {
539 if ( mVkDevice != VK_NULL_HANDLE )
540 {
541 if ( VkResult result = vkDeviceWaitIdle ( mVkDevice ) )
542 {
543 std::cout << LogLevel::Error << "vkDeviceWaitIdle returned " << GetVulkanResultString ( result ) << std::endl;
544 }
545 vkDestroyDevice ( mVkDevice, nullptr );
546 mVkDevice = VK_NULL_HANDLE;
547 }
548 }
549
551 {
552 VkCommandBufferAllocateInfo command_buffer_allocate_info{};
553 VkCommandBuffer command_buffer{};
554 VkCommandBufferBeginInfo beginInfo{};
555 command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
556 command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
557 command_buffer_allocate_info.commandPool = mVkSingleTimeCommandPool;
558 command_buffer_allocate_info.commandBufferCount = 1;
559 vkAllocateCommandBuffers ( mVkDevice, &command_buffer_allocate_info, &command_buffer );
560 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
561 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
562 vkBeginCommandBuffer ( command_buffer, &beginInfo );
563 return command_buffer;
564 }
565
566 void VulkanRenderer::EndSingleTimeCommands ( VkCommandBuffer aVkCommandBuffer ) const
567 {
568 vkEndCommandBuffer ( aVkCommandBuffer );
569 VkSubmitInfo submit_info = {};
570 submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
571 submit_info.commandBufferCount = 1;
572 submit_info.pCommandBuffers = &aVkCommandBuffer;
573 vkQueueSubmit ( mVkQueue, 1, &submit_info, VK_NULL_HANDLE );
574 vkQueueWaitIdle ( mVkQueue );
575 vkFreeCommandBuffers ( mVkDevice, mVkSingleTimeCommandPool, 1, &aVkCommandBuffer );
576 }
577
578 void VulkanRenderer::LoadMesh ( const Mesh& aMesh )
579 {
580 if ( aMesh.GetVertexCount() == 0 )
581 {
582 return;
583 }
584 auto it = mMeshStore.find ( aMesh.GetConsecutiveId() );
585 if ( it != mMeshStore.end() )
586 {
587 std::cout << LogLevel::Warning << " Mesh " << aMesh.GetConsecutiveId() << " Already Loaded at: " << __FUNCTION__ << std::endl;
588 return;
589 }
590 mMeshStore.emplace ( aMesh.GetConsecutiveId(), VulkanMesh{*this, aMesh} );
591 }
592
593 void VulkanRenderer::UnloadMesh ( const Mesh& aMesh )
594 {
595 auto it = mMeshStore.find ( aMesh.GetConsecutiveId() );
596 if ( it != mMeshStore.end() )
597 {
598 mMeshStore.erase ( it );
599 }
600 }
601
603 {
604 auto it = mMeshStore.find ( aMesh.GetConsecutiveId() );
605 if ( it == mMeshStore.end() )
606 {
607 LoadMesh ( aMesh );
608 it = mMeshStore.find ( aMesh.GetConsecutiveId() );
609 }
610 if ( it != mMeshStore.end() )
611 {
612 return &it->second;
613 }
614 return nullptr;
615 }
616
617 /*-----------------Pipeline-----------------------*/
618
620 {
621 auto it = mPipelineStore.find ( aPipeline.GetConsecutiveId() );
622 if ( it == mPipelineStore.end() )
623 {
624 LoadPipeline ( aPipeline );
625 it = mPipelineStore.find ( aPipeline.GetConsecutiveId() );
626 }
627 if ( it != mPipelineStore.end() )
628 {
629 return &it->second;
630 }
631 return nullptr;
632 }
633
635 {
636 auto it = mMaterialStore.find ( aMaterial.GetConsecutiveId() );
637 if ( it == mMaterialStore.end() )
638 {
639 LoadMaterial ( aMaterial );
640 it = mMaterialStore.find ( aMaterial.GetConsecutiveId() );
641 }
642
643 if ( it != mMaterialStore.end() )
644 {
645 return &it->second;
646 }
647 return nullptr;
648 }
649
650 void VulkanRenderer::LoadPipeline ( const Pipeline& aPipeline )
651 {
652 auto it = mPipelineStore.find ( aPipeline.GetConsecutiveId() );
653 if ( it != mPipelineStore.end() )
654 {
655 std::cout << LogLevel::Warning << " Pipeline " << aPipeline.GetConsecutiveId() << " Already Loaded at: " << __FUNCTION__ << std::endl;
656 return;
657 }
658 mPipelineStore.emplace ( aPipeline.GetConsecutiveId(), VulkanPipeline{*this, aPipeline} );
659 }
660
661 void VulkanRenderer::UnloadPipeline ( const Pipeline& aPipeline )
662 {
663 auto it = mPipelineStore.find ( aPipeline.GetConsecutiveId() );
664 if ( it == mPipelineStore.end() )
665 {
666 return;
667 }
668 if ( mBoundPipeline == &it->second )
669 {
670 mBoundPipeline = nullptr;
671 }
672 mPipelineStore.erase ( it );
673 }
674
675 /*---------------------Material---------------------*/
676 void VulkanRenderer::LoadMaterial ( const Material& aMaterial )
677 {
678 auto it = mMaterialStore.find ( aMaterial.GetConsecutiveId() );
679 if ( it != mMaterialStore.end() )
680 {
681 std::cout << LogLevel::Warning << " Material " << aMaterial.GetConsecutiveId() << " already loaded." << std::endl;
682 return;
683 }
684 // Preload linked textures
685 for ( auto& i : aMaterial.GetSamplers() )
686 {
687 const Texture* texture = std::get<1> ( i ).Get<Texture>();
688 if ( mTextureStore.find ( texture->GetConsecutiveId() ) == mTextureStore.end() )
689 {
690 LoadTexture ( *texture );
691 }
692 }
693 mMaterialStore.emplace ( aMaterial.GetConsecutiveId(), VulkanMaterial{*this, aMaterial} );
694 }
695
696 void VulkanRenderer::UnloadMaterial ( const Material& aMaterial )
697 {
698 auto it = mMaterialStore.find ( aMaterial.GetConsecutiveId() );
699 if ( it == mMaterialStore.end() )
700 {
701 return;
702 }
703 // Unload linked textures
704 for ( auto& i : aMaterial.GetSamplers() )
705 {
706 const Texture* texture = std::get<1> ( i ).Get<Texture>();
707 if ( mTextureStore.find ( texture->GetConsecutiveId() ) != mTextureStore.end() )
708 {
709 UnloadTexture ( *texture );
710 }
711 }
712 mMaterialStore.erase ( it );
713 }
714
715 void VulkanRenderer::LoadTexture ( const Texture& aTexture )
716 {
717 auto it = mTextureStore.find ( aTexture.GetConsecutiveId() );
718 if ( it != mTextureStore.end() )
719 {
720 std::cout << LogLevel::Warning << " Texture " << aTexture.GetConsecutiveId() << " already loaded at: " << __FUNCTION__ << std::endl;
721 return;
722 }
723 mTextureStore.emplace ( aTexture.GetConsecutiveId(), VulkanTexture{*this, aTexture} );
724 }
725
726 void VulkanRenderer::UnloadTexture ( const Texture& aTexture )
727 {
728 auto it = mTextureStore.find ( aTexture.GetConsecutiveId() );
729 if ( it == mTextureStore.end() )
730 {
731 return;
732 }
733 mTextureStore.erase ( it );
734 }
735
736 const VkDescriptorImageInfo* VulkanRenderer::GetTextureDescriptorImageInfo ( const Texture& aTexture ) const
737 {
738 auto it = mTextureStore.find ( aTexture.GetConsecutiveId() );
739 if ( it == mTextureStore.end() )
740 {
741 std::ostringstream stream;
742 stream << "Texture Not Found at: ( " << __FUNCTION__ << " )";
743 std::string error_string = stream.str();
744 std::cout << LogLevel::Error << error_string << std::endl;
745 throw std::runtime_error ( error_string.c_str() );
746 }
747 return &it->second.GetDescriptorImageInfo();
748 }
749
750 const VkDescriptorSetLayout& VulkanRenderer::GetDescriptorSetLayout ( const VkDescriptorSetLayoutCreateInfo& aDescriptorSetLayoutCreateInfo ) const
751 {
752 uint32_t key
753 {
754 crc32i ( reinterpret_cast<const char*> ( &aDescriptorSetLayoutCreateInfo.bindingCount ), sizeof ( uint32_t ),
755 crc32i ( reinterpret_cast<const char*> ( &aDescriptorSetLayoutCreateInfo.flags ), sizeof ( VkDescriptorSetLayoutCreateFlags ),
756 crc32i ( reinterpret_cast<const char*> ( &aDescriptorSetLayoutCreateInfo.sType ), sizeof ( VkStructureType ) ) ) )
757 };
758
759 for ( uint32_t i = 0; i < aDescriptorSetLayoutCreateInfo.bindingCount; ++i )
760 {
761 key =
762 crc32i ( reinterpret_cast<const char*> ( &aDescriptorSetLayoutCreateInfo.pBindings[i].stageFlags ), sizeof ( VkShaderStageFlags ),
763 crc32i ( reinterpret_cast<const char*> ( &aDescriptorSetLayoutCreateInfo.pBindings[i].descriptorCount ), sizeof ( uint32_t ),
764 crc32i ( reinterpret_cast<const char*> ( &aDescriptorSetLayoutCreateInfo.pBindings[i].descriptorType ), sizeof ( VkDescriptorType ),
765 crc32i ( reinterpret_cast<const char*> ( &aDescriptorSetLayoutCreateInfo.pBindings[i].binding ), sizeof ( uint32_t ), key ) ) ) );
766 }
767
768 auto lb = std::lower_bound ( mVkDescriptorSetLayouts.begin(), mVkDescriptorSetLayouts.end(), key,
769 [] ( const std::tuple<size_t, VkDescriptorSetLayout>& a, size_t b )
770 {
771 return std::get<0> ( a ) < b;
772 } );
773
774 if ( lb != mVkDescriptorSetLayouts.end() && std::get<0> ( *lb ) == key )
775 {
776 return std::get<1> ( *lb );
777 }
778 VkDescriptorSetLayout descriptor_set_layout;
779 if ( VkResult result = vkCreateDescriptorSetLayout ( mVkDevice, &aDescriptorSetLayoutCreateInfo, nullptr, &descriptor_set_layout ) )
780 {
781 std::ostringstream stream;
782 stream << "DescriptorSet Layout creation failed: ( " << GetVulkanResultString ( result ) << " )";
783 std::cout << LogLevel::Error << stream.str() << std::endl;
784 throw std::runtime_error ( stream.str().c_str() );
785 }
786 lb = mVkDescriptorSetLayouts.insert ( lb, { {key}, {descriptor_set_layout} } );
787 return std::get<1> ( *lb );
788 }
789#if 0
790 const VkDescriptorSetLayout& VulkanRenderer::GetSamplerDescriptorSetLayout ( size_t aSamplerCount ) const
791 {
792 auto lb = std::lower_bound ( mVkDescriptorSetLayouts.begin(), mVkDescriptorSetLayouts.end(), aSamplerCount,
793 [] ( const std::tuple<size_t, VkDescriptorSetLayout>&a, size_t b )
794 {
795 return std::get<0> ( a ) < b;
796 } );
797 if ( lb != mVkDescriptorSetLayouts.end() && std::get<0> ( *lb ) == aSamplerCount )
798 {
799 return std::get<1> ( *lb );
800 }
801 if ( aSamplerCount )
802 {
803 std::vector<VkDescriptorSetLayoutBinding> descriptor_set_layout_bindings;
804 descriptor_set_layout_bindings.resize ( aSamplerCount );
805 for ( uint32_t i = 0; i < aSamplerCount; ++i )
806 {
807 descriptor_set_layout_bindings[i].binding = i;
808 descriptor_set_layout_bindings[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
809 // Descriptor Count is the count of elements in an array.
810 descriptor_set_layout_bindings[i].descriptorCount = 1;
811 descriptor_set_layout_bindings[i].stageFlags = VK_SHADER_STAGE_ALL;
812 descriptor_set_layout_bindings[i].pImmutableSamplers = nullptr;
813 }
814
815 VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info {};
816 descriptor_set_layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
817 descriptor_set_layout_create_info.pNext = nullptr;
818 descriptor_set_layout_create_info.flags = 0;
819 descriptor_set_layout_create_info.bindingCount = static_cast<uint32_t> ( descriptor_set_layout_bindings.size() );
820 descriptor_set_layout_create_info.pBindings = descriptor_set_layout_bindings.data();
821 lb = mVkDescriptorSetLayouts.insert ( lb, {{aSamplerCount}, {VK_NULL_HANDLE}} );
822 if ( VkResult result = vkCreateDescriptorSetLayout ( mVkDevice, &descriptor_set_layout_create_info, nullptr,
823 &std::get<1> ( *lb ) ) )
824 {
825 std::ostringstream stream;
826 stream << "DescriptorSet Layout creation failed: ( " << GetVulkanResultString ( result ) << " )";
827 throw std::runtime_error ( stream.str().c_str() );
828 }
829 return std::get<1> ( *lb );
830 }
831 std::cout << LogLevel::Error << "Sampler Count must be > 0" << std::endl;
832 throw std::runtime_error ( "Sampler Count must be > 0" );
833 }
834#endif
835 void VulkanRenderer::InitializeDescriptorSetLayout ( VkDescriptorSetLayout& aVkDescriptorSetLayout, VkDescriptorType aVkDescriptorType )
836 {
837 VkDescriptorSetLayoutBinding descriptor_set_layout_binding;
838 descriptor_set_layout_binding.binding = 0;
839 descriptor_set_layout_binding.descriptorType = aVkDescriptorType;
840 /* We will bind just 1 UBO, descriptor count is the number of array elements, and we just use a single struct. */
841 descriptor_set_layout_binding.descriptorCount = 1;
842 descriptor_set_layout_binding.stageFlags = VK_SHADER_STAGE_ALL;
843 descriptor_set_layout_binding.pImmutableSamplers = nullptr;
844
845 VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_info{};
846 descriptor_set_layout_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
847 descriptor_set_layout_create_info.pNext = nullptr;
848 descriptor_set_layout_create_info.flags = 0;
849 descriptor_set_layout_create_info.bindingCount = 1;
850 descriptor_set_layout_create_info.pBindings = &descriptor_set_layout_binding;
851 if ( VkResult result = vkCreateDescriptorSetLayout ( mVkDevice, &descriptor_set_layout_create_info, nullptr, &aVkDescriptorSetLayout ) )
852 {
853 std::ostringstream stream;
854 stream << "DescriptorSet Layout creation failed: ( " << GetVulkanResultString ( result ) << " )";
855 std::cout << LogLevel::Error << stream.str() << std::endl;
856 throw std::runtime_error ( stream.str().c_str() );
857 }
858 }
859
860 void VulkanRenderer::FinalizeDescriptorSetLayout ( VkDescriptorSetLayout& aVkDescriptorSetLayout )
861 {
862 if ( aVkDescriptorSetLayout != VK_NULL_HANDLE )
863 {
864 vkDestroyDescriptorSetLayout ( mVkDevice, aVkDescriptorSetLayout, nullptr );
865 aVkDescriptorSetLayout = VK_NULL_HANDLE;
866 }
867 }
868
869 void VulkanRenderer::AttachWindow ( void* aWindowId )
870 {
871 auto it = mWindowStore.find ( aWindowId );
872 if ( it != mWindowStore.end() )
873 {
874 std::cout << LogLevel::Warning << " Window " << aWindowId << " Already Loaded at: " << __FUNCTION__ << std::endl;
875 return;
876 }
877 mWindowStore.emplace ( aWindowId, VulkanWindow{*this, aWindowId} );
878 }
879 void VulkanRenderer::DetachWindow ( void* aWindowId )
880 {
881 auto it = mWindowStore.find ( aWindowId );
882 if ( it == mWindowStore.end() )
883 {
884 return;
885 }
886 mWindowStore.erase ( it );
887 }
888
889 void VulkanRenderer::SetProjectionMatrix ( void* aWindowId, const Matrix4x4& aMatrix )
890 {
891 auto it = mWindowStore.find ( aWindowId );
892 if ( it == mWindowStore.end() )
893 {
894 return;
895 }
896 it->second.SetProjectionMatrix ( aMatrix );
897 }
898
899 void VulkanRenderer::SetViewMatrix ( void* aWindowId, const Matrix4x4& aMatrix )
900 {
901 auto it = mWindowStore.find ( aWindowId );
902 if ( it == mWindowStore.end() )
903 {
904 return;
905 }
906 it->second.SetViewMatrix ( aMatrix );
907 }
908
909 void VulkanRenderer::ResizeViewport ( void* aWindowId, int32_t aX, int32_t aY, uint32_t aWidth, uint32_t aHeight )
910 {
911 auto it = mWindowStore.find ( aWindowId );
912 if ( it == mWindowStore.end() )
913 {
914 return;
915 }
916 it->second.ResizeViewport ( aX, aY, aWidth, aHeight );
917 }
918
919 void VulkanRenderer::BeginRender ( void* aWindowId )
920 {
921 auto it = mWindowStore.find ( aWindowId );
922 if ( it == mWindowStore.end() )
923 {
924 return;
925 }
926 it->second.BeginRender();
927 }
928 void VulkanRenderer::EndRender ( void* aWindowId )
929 {
930 auto it = mWindowStore.find ( aWindowId );
931 if ( it == mWindowStore.end() )
932 {
933 return;
934 }
935 it->second.EndRender();
936 }
937 void VulkanRenderer::Render ( void* aWindowId,
938 const Matrix4x4& aModelMatrix,
939 const Mesh& aMesh,
940 const Pipeline& aPipeline,
941 const Material* aMaterial,
942 const BufferAccessor* aSkeleton,
943 Topology aTopology,
944 uint32_t aVertexStart,
945 uint32_t aVertexCount,
946 uint32_t aInstanceCount,
947 uint32_t aFirstInstance ) const
948 {
949 auto it = mWindowStore.find ( aWindowId );
950 if ( it == mWindowStore.end() )
951 {
952 return;
953 }
954 it->second.Render ( aModelMatrix, aMesh, aPipeline, aMaterial, aSkeleton, aTopology, aVertexStart, aVertexCount, aInstanceCount, aFirstInstance );
955 }
956
957 const Frustum& VulkanRenderer::GetFrustum ( void* aWindowId ) const
958 {
959 auto it = mWindowStore.find ( aWindowId );
960 if ( it == mWindowStore.end() )
961 {
962 std::cout << LogLevel::Error << "Unknown Window Id." << std::endl;
963 throw std::runtime_error ( "Unknown Window Id." );
964 }
965 return it->second.GetFrustum();
966 }
967
969 {
970 auto it = mWindowStore.find ( aWindowId );
971 if ( it == mWindowStore.end() )
972 {
973 std::cout << LogLevel::Error << "Unknown Window Id." << std::endl;
974 throw std::runtime_error ( "Unknown Window Id." );
975 }
976 return it->second.AllocateSingleFrameUniformMemory ( aSize );
977 }
978
979 void VulkanRenderer::SetClearColor ( void* aWindowId, float R, float G, float B, float A )
980 {
981 auto it = mWindowStore.find ( aWindowId );
982 if ( it == mWindowStore.end() )
983 {
984 return;
985 }
987 //it->second.SetClearColor ( R, G, B, A );
988 }
989}
Defines log severity levels and stream output for the AeonGames engine.
Provides access to a region within a memory pool buffer.
View frustum defined by six clipping planes, extracted from a projection (or view-projection) matrix.
Definition Frustum.hpp:35
Represents a surface material with uniform properties and texture samplers.
Definition Material.hpp:38
DLL const std::vector< std::tuple< uint32_t, ResourceId > > & GetSamplers() const
Get all sampler bindings.
Definition Material.cpp:245
4 by 4 matrix in colum mayor order.
Definition Matrix4x4.hpp:35
Represents a polygon mesh with vertex attributes and index data.
Definition Mesh.hpp:31
DLL uint32_t GetVertexCount() const
Get the total number of vertices.
Definition Mesh.cpp:53
Rendering pipeline resource.
Definition Pipeline.hpp:122
DLL size_t GetConsecutiveId() const
Get the Consecutive Id for the resource object.
Definition Resource.cpp:42
Represents a 2D texture image resource.
Definition Texture.hpp:33
Vulkan material binding handler for descriptor sets and uniforms.
Vulkan mesh wrapper managing vertex and index buffer resources.
Vulkan graphics pipeline with descriptor set and push constant reflection.
uint32_t GetQueueFamilyIndex() const
Get the queue family index used for graphics operations.
void UnloadMesh(const Mesh &aMesh) final
Unloads mesh data from GPU memory.
const VkDescriptorSetLayout & GetDescriptorSetLayout(const VkDescriptorSetLayoutCreateInfo &aDescriptorSetLayoutCreateInfo) const
Get or create a descriptor set layout matching the given create info.
void UnloadPipeline(const Pipeline &aPipeline) final
Unloads a rendering pipeline from the renderer.
const VkPhysicalDevice & GetPhysicalDevice() const
Get the physical device handle.
void LoadMesh(const Mesh &aMesh) final
Loads mesh data into GPU memory.
const VkInstance & GetInstance() const
Get the Vulkan instance handle.
void BeginRender(void *aWindowId) final
Begins a render pass for the given window surface.
const VulkanMesh * GetVulkanMesh(const Mesh &aMesh)
Get the cached VulkanMesh for a Mesh resource.
BufferAccessor AllocateSingleFrameUniformMemory(void *aWindowId, size_t aSize) final
Allocates uniform buffer memory that is valid for a single frame.
const VulkanMaterial * GetVulkanMaterial(const Material &aMaterial)
Get the cached VulkanMaterial for a Material resource.
const VkPhysicalDeviceMemoryProperties & GetPhysicalDeviceMemoryProperties() const
Get the physical device memory properties.
VkCommandBuffer BeginSingleTimeCommands() const
Begin recording a single-use command buffer.
VulkanRenderer(void *aWindow)
Construct from a native window handle.
void LoadPipeline(const Pipeline &aPipeline) final
Loads a rendering pipeline (shaders and state) into the renderer.
void SetClearColor(void *aWindowId, float R, float G, float B, float A) final
Sets the color to be used to clear the window background.
void AttachWindow(void *aWindowId) final
Attach a Window as a rendering surface.
const VkQueue & GetQueue() const
Get the graphics queue handle.
void ResizeViewport(void *aWindowId, int32_t aX, int32_t aY, uint32_t aWidth, uint32_t aHeight) final
Resizes the specific window surface's viewport.
void LoadTexture(const Texture &aTexture) final
Loads a texture into GPU memory.
void LoadMaterial(const Material &aMaterial) final
Loads material data into the renderer.
const VulkanPipeline * GetVulkanPipeline(const Pipeline &aPipeline)
Get the cached VulkanPipeline for a Pipeline resource.
uint32_t FindMemoryTypeIndex(uint32_t typeFilter, VkMemoryPropertyFlags properties) const
Find a memory type index matching both a type filter and property flags.
void SetViewMatrix(void *aWindowId, const Matrix4x4 &aMatrix) final
Sets the view matrix for a specific window surface.
void EndSingleTimeCommands(VkCommandBuffer commandBuffer) const
Submit and free a single-use command buffer.
void Render(void *aWindowId, const Matrix4x4 &aModelMatrix, const Mesh &aMesh, const Pipeline &aPipeline, const Material *aMaterial=nullptr, const BufferAccessor *aSkeleton=nullptr, Topology aTopology=Topology::TRIANGLE_LIST, uint32_t aVertexStart=0, uint32_t aVertexCount=0xffffffff, uint32_t aInstanceCount=1, uint32_t aFirstInstance=0) const final
Issues a draw call for a mesh with the given pipeline and optional material.
const VkPhysicalDeviceProperties & GetPhysicalDeviceProperties() const
Get the physical device properties.
const VkDescriptorImageInfo * GetTextureDescriptorImageInfo(const Texture &aTexture) const
Get the descriptor image info for a loaded texture.
void DetachWindow(void *aWindowId) final
Detach a Window as a rendering surface.
VkRenderPass GetRenderPass() const
Get the common Vulkan render pass.
void EndRender(void *aWindowId) final
Ends the current render pass for the given window surface.
const Frustum & GetFrustum(void *aWindowId) const final
Returns the view frustum for the given window surface.
void SetProjectionMatrix(void *aWindowId, const Matrix4x4 &aMatrix) final
Sets the projection matrix for a specific window surface.
uint32_t GetMemoryTypeIndex(VkMemoryPropertyFlags aVkMemoryPropertyFlags) const
Get a memory type index matching the requested property flags.
void UnloadTexture(const Texture &aTexture) final
Unloads a texture from GPU memory.
const VkDevice & GetDevice() const
Get the logical device handle.
void UnloadMaterial(const Material &aMaterial) final
Unloads material data from the renderer.
Vulkan texture resource wrapper with image and descriptor management.
Vulkan per-window swapchain, render pass, and rendering state.
<- This is here just for the literals
Definition AABB.hpp:31
VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT aMessageSeverity, VkDebugUtilsMessageTypeFlagsEXT aMessageTypes, const VkDebugUtilsMessengerCallbackDataEXT *aCallbackData, void *aUserData)
Vulkan debug messenger callback.
uint32_t crc32i(const char *message, size_t size, uint32_t previous_crc)
Compute the CRC32 of a given message, continuing from a previous CRC value.
Definition CRC.cpp:27
const char * GetVulkanResultString(VkResult aResult)
Convert a VkResult code to a human-readable string.
Topology
Primitive topology types for rendering.
Definition Pipeline.hpp:38
@ Warning
Potential issues that may need attention.
Definition LogLevel.hpp:32
@ Info
General informational messages.
Definition LogLevel.hpp:30
@ Error
Error conditions.
Definition LogLevel.hpp:33
@ Debug
Detailed diagnostic information.
Definition LogLevel.hpp:29