Dodo 0.1
Template for CPP projects
Loading...
Searching...
No Matches
HelloTriangleApplication Class Reference

Public Member Functions

void run ()
 

Private Member Functions

void initVulkan ()
 
void initWindow ()
 
void mainLoop ()
 
void cleanup ()
 
void createInstance ()
 
void setupDebugMessenger ()
 
void pickPhysicalDevice ()
 
uint32_t findQueueFamilies (vk::raii::PhysicalDevice physicalDevice)
 
void createLogicalDevice ()
 
void createSurface ()
 

Static Private Member Functions

static VKAPI_ATTR vk::Bool32 VKAPI_CALL debugCallback (vk::DebugUtilsMessageSeverityFlagBitsEXT severity, vk::DebugUtilsMessageTypeFlagsEXT type, const vk::DebugUtilsMessengerCallbackDataEXT *pCallbackData, void *)
 

Private Attributes

GLFWwindow_window = nullptr
 
vk::raii::Context _context
 
vk::raii::Instance _instance = nullptr
 
vk::raii::PhysicalDevice _physicalDevice = nullptr
 
vk::raii::DebugUtilsMessengerEXT _debugMessenger = nullptr
 
vk::raii::Device _device = nullptr
 
vk::raii::Queue _graphicsQueue = nullptr
 
vk::raii::SurfaceKHR surface = nullptr
 
vk::raii::Queue _presentQueue = nullptr
 
std::vector< const char * > deviceExtensions
 

Member Function Documentation

◆ cleanup()

void HelloTriangleApplication::cleanup ( )
inlineprivate
90 {
93 }
GLFWwindow * _window
Definition main.cpp:47
GLFWAPI void glfwTerminate(void)
Terminates the GLFW library.
GLFWAPI void glfwDestroyWindow(GLFWwindow *window)
Destroys the specified window and its context.

References _window, glfwDestroyWindow(), and glfwTerminate().

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ createInstance()

void HelloTriangleApplication::createInstance ( )
inlineprivate
95 {
96 // Some elements are optional, replace by builder pattern
97 constexpr vk::ApplicationInfo APP_INFO{
98 .pApplicationName = "Hello Triangle",
99 .applicationVersion = VK_MAKE_VERSION( 1, 0, 0 ),
100 .pEngineName = "No Engine",
101 .engineVersion = VK_MAKE_VERSION( 1, 0, 0 ),
102 .apiVersion = vk::ApiVersion13
103 };
104
105
106 // Get the required layers
107 std::vector<char const*> requiredLayers;
109 requiredLayers.assign(validationLayers.begin(), validationLayers.end());
110 }
111
112 // Check if the required layers are supported by the Vulkan implementation.
113 auto layerProperties = _context.enumerateInstanceLayerProperties();
114 if (std::ranges::any_of(requiredLayers, [&layerProperties](auto const& requiredLayer) {
115 return std::ranges::none_of(layerProperties,
116 [requiredLayer](auto const& layerProperty)
117 { return strcmp(layerProperty.layerName, requiredLayer) == 0; });
118 }))
119 {
120 throw std::runtime_error("One or more required layers are not supported!");
121 }
122
123 for (auto layer: requiredLayers) {
124 std::cout << layer << std::endl;
125 }
126
127 // Get the required instance extensions from GLFW.
128 uint32_t glfwExtensionCount = 0;
129 auto glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
130
131 auto extensions = _context.enumerateInstanceExtensionProperties();
132 std::cout << "available extensions:\n";
133
134 for (const auto& extension : extensions) {
135 std::cout << '\t' << extension.extensionName << '\n';
136 }
137
138 // Check if the required GLFW extensions are supported by the Vulkan implementation.
139 auto extensionProperties = _context.enumerateInstanceExtensionProperties();
140 for (uint32_t i = 0; i < glfwExtensionCount; ++i)
141 {
142 if (std::ranges::none_of(extensionProperties,
143 [glfwExtension = glfwExtensions[i]](auto const& extensionProperty)
144 { return strcmp(extensionProperty.extensionName, glfwExtension) == 0; }))
145 {
146 throw std::runtime_error("Required GLFW extension not supported: " + std::string(glfwExtensions[i]));
147 }
148 }
149
150 vk::InstanceCreateInfo createInfo{
151 .pApplicationInfo = &APP_INFO,
152 .enabledLayerCount = static_cast<uint32_t>(requiredLayers.size()),
153 .ppEnabledLayerNames = requiredLayers.data(),
154 .enabledExtensionCount = glfwExtensionCount,
155 .ppEnabledExtensionNames = glfwExtensions,
156 };
157
158 _instance = vk::raii::Instance(_context, createInfo);
159 }
vk::raii::Context _context
Definition main.cpp:48
vk::raii::Instance _instance
Definition main.cpp:49
GLFWAPI const char ** glfwGetRequiredInstanceExtensions(uint32_t *count)
Returns the Vulkan instance extensions required by GLFW.
const std::vector< char const * > validationLayers
Definition main.cpp:28
constexpr bool enableValidationLayers
Definition main.cpp:35

References _context, _instance, enableValidationLayers, glfwGetRequiredInstanceExtensions(), and validationLayers.

Referenced by initVulkan().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ createLogicalDevice()

void HelloTriangleApplication::createLogicalDevice ( )
inlineprivate
230 {
231 std::vector<vk::QueueFamilyProperties> queueFamilyProperties = _physicalDevice.getQueueFamilyProperties();
232 uint32_t graphicsIndex = findQueueFamilies(_physicalDevice);
233
234 // determine a queueFamilyIndex that supports present
235 // first check if the graphicsIndex is good enough
236 auto presentIndex = _physicalDevice.getSurfaceSupportKHR(graphicsIndex, *surface )
237 ? graphicsIndex : static_cast<uint32_t>(queueFamilyProperties.size());
238
239 if ( presentIndex == queueFamilyProperties.size() )
240 {
241 // the graphicsIndex doesn't support present -> look for another family index that supports both
242 // graphics and present
243 for ( size_t i = 0; i < queueFamilyProperties.size(); i++ )
244 {
245 if ( ( queueFamilyProperties[i].queueFlags & vk::QueueFlagBits::eGraphics ) &&
246 _physicalDevice.getSurfaceSupportKHR( static_cast<uint32_t>( i ), *surface ) )
247 {
248 graphicsIndex = static_cast<uint32_t>( i );
249 presentIndex = graphicsIndex;
250 break;
251 }
252 }
253 if ( presentIndex == queueFamilyProperties.size() )
254 {
255 // there's nothing like a single family index that supports both graphics and present -> look for another
256 // family index that supports present
257 for ( size_t i = 0; i < queueFamilyProperties.size(); i++ )
258 {
259 if ( _physicalDevice.getSurfaceSupportKHR( static_cast<uint32_t>( i ), *surface ) )
260 {
261 presentIndex = static_cast<uint32_t>( i );
262 break;
263 }
264 }
265 }
266 }
267 if ( ( graphicsIndex == queueFamilyProperties.size() ) || ( presentIndex == queueFamilyProperties.size() ) )
268 {
269 throw std::runtime_error( "Could not find a queue for graphics or present -> terminating" );
270 }
271
272
273
274 float queuePriority = 1.0f; // Vulkan lets you assign priorities to queues to influence the scheduling of command buffer execution using floating point numbers between 0.0 and 1.0
275 //The currently available drivers will only allow you to create a small number of queues for each queue family, and you don’t really need more than one
276 vk::DeviceQueueCreateInfo deviceQueueCreateInfo { .queueFamilyIndex = graphicsIndex, .queueCount = 1, .pQueuePriorities = &queuePriority };
277 vk::PhysicalDeviceFeatures deviceFeatures;
278
279
280
281 // Here maybe use a builder to add features to pnext
282 // Create a chain of feature structures
283 vk::StructureChain<vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan13Features, vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT> featureChain = {
284 {}, // vk::PhysicalDeviceFeatures2 (empty for now)
285 {.dynamicRendering = true }, // Enable dynamic rendering from Vulkan 1.3
286 {.extendedDynamicState = true }, // Enable extended dynamic state from the extension
287 };
288
289 vk::DeviceCreateInfo deviceCreateInfo{
290 .pNext = &featureChain.get<vk::PhysicalDeviceFeatures2>(),
291 .queueCreateInfoCount = 1,
292 .pQueueCreateInfos = &deviceQueueCreateInfo,
293 .enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size()),
294 .ppEnabledExtensionNames = deviceExtensions.data()
295 };
296
297 _device = vk::raii::Device(_physicalDevice, deviceCreateInfo);
298 _graphicsQueue = vk::raii::Queue( _device, graphicsIndex, 0 );
299 _presentQueue = vk::raii::Queue( _device, presentIndex, 0 );
300 }
vk::raii::SurfaceKHR surface
Definition main.cpp:54
vk::raii::Device _device
Definition main.cpp:52
vk::raii::Queue _presentQueue
Definition main.cpp:55
std::vector< const char * > deviceExtensions
Definition main.cpp:174
uint32_t findQueueFamilies(vk::raii::PhysicalDevice physicalDevice)
Definition main.cpp:217
vk::raii::Queue _graphicsQueue
Definition main.cpp:53
vk::raii::PhysicalDevice _physicalDevice
Definition main.cpp:50

References _device, _graphicsQueue, _physicalDevice, _presentQueue, deviceExtensions, findQueueFamilies(), and surface.

Here is the call graph for this function:

◆ createSurface()

void HelloTriangleApplication::createSurface ( )
inlineprivate
303 {
304 VkSurfaceKHR _surface;
305 if (glfwCreateWindowSurface(*_instance, _window, nullptr, &_surface) != 0) {
306 throw std::runtime_error("failed to create window surface!");
307 }
308 surface = vk::raii::SurfaceKHR(_instance, _surface);
309 }

References _instance, _window, and surface.

◆ debugCallback()

static VKAPI_ATTR vk::Bool32 VKAPI_CALL HelloTriangleApplication::debugCallback ( vk::DebugUtilsMessageSeverityFlagBitsEXT severity,
vk::DebugUtilsMessageTypeFlagsEXT type,
const vk::DebugUtilsMessengerCallbackDataEXT * pCallbackData,
void *  )
inlinestaticprivate
182 {
183 if (severity >= vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning)
184 std::cerr << "validation layer: type " << to_string(type) << " msg: " << pCallbackData->pMessage << std::endl;
185 return vk::False;
186 }

Referenced by setupDebugMessenger().

Here is the caller graph for this function:

◆ findQueueFamilies()

uint32_t HelloTriangleApplication::findQueueFamilies ( vk::raii::PhysicalDevice physicalDevice)
inlineprivate
217 {
218 // find the index of the first queue family that supports graphics
219 std::vector<vk::QueueFamilyProperties> queueFamilyProperties = physicalDevice.getQueueFamilyProperties();
220
221 // get the first index into queueFamilyProperties which supports graphics
222 auto graphicsQueueFamilyProperty =
223 std::find_if( queueFamilyProperties.begin(),
224 queueFamilyProperties.end(),
225 []( vk::QueueFamilyProperties const & qfp ) { return qfp.queueFlags & vk::QueueFlagBits::eGraphics; } );
226
227 return static_cast<uint32_t>(std::distance(queueFamilyProperties.begin(), graphicsQueueFamilyProperty));
228 }

Referenced by createLogicalDevice().

Here is the caller graph for this function:

◆ initVulkan()

void HelloTriangleApplication::initVulkan ( )
inlineprivate
65 {
67 // setupDebugMessenger();
69 }
void createInstance()
Definition main.cpp:95
void pickPhysicalDevice()
Definition main.cpp:188

References createInstance(), and pickPhysicalDevice().

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ initWindow()

void HelloTriangleApplication::initWindow ( )
inlineprivate
71 {
72 glfwInit(); // Init glfw
73 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); // No API beceause OpenGL by default
74 glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); // Disable resizing because more work
75
76 constexpr int HEIGHT = 800;
77 constexpr int WIDTH = 600;
78 const std::string TITLE = "Vulkan";
79 // Pass parameters by a WindowInfo struct to avoid errors like inverting width and height
80 _window = glfwCreateWindow(WIDTH, HEIGHT, TITLE.c_str(), nullptr, nullptr);
81
82 }
#define GLFW_NO_API
Definition glfw3.h:1140
GLFWAPI int glfwInit(void)
Initializes the GLFW library.
#define GLFW_FALSE
Zero.
Definition glfw3.h:321
#define GLFW_CLIENT_API
Context client API hint and attribute.
Definition glfw3.h:1031
GLFWAPI void glfwWindowHint(int hint, int value)
Sets the specified window hint to the desired value.
GLFWAPI GLFWwindow * glfwCreateWindow(int width, int height, const char *title, GLFWmonitor *monitor, GLFWwindow *share)
Creates a window and its associated context.
#define GLFW_RESIZABLE
Window resize-ability window hint and attribute.
Definition glfw3.h:870

References _window, GLFW_CLIENT_API, GLFW_FALSE, GLFW_NO_API, GLFW_RESIZABLE, glfwCreateWindow(), glfwInit(), and glfwWindowHint().

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mainLoop()

void HelloTriangleApplication::mainLoop ( )
inlineprivate
84 {
87 }
88 }
GLFWAPI void glfwPollEvents(void)
Processes all pending events.
GLFWAPI int glfwWindowShouldClose(GLFWwindow *window)
Checks the close flag of the specified window.

References _window, glfwPollEvents(), and glfwWindowShouldClose().

Referenced by run().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pickPhysicalDevice()

void HelloTriangleApplication::pickPhysicalDevice ( )
inlineprivate
188 {
189 std::vector<vk::raii::PhysicalDevice> devices = _instance.enumeratePhysicalDevices();
190 const auto devIter = std::ranges::find_if(devices,
191 [&](auto const & device) {
192 auto queueFamilies = device.getQueueFamilyProperties();
193 bool isSuitable = device.getProperties().apiVersion >= VK_API_VERSION_1_3;
194 const auto qfpIter = std::ranges::find_if(queueFamilies,
195 []( vk::QueueFamilyProperties const & qfp )
196 {
197 return (qfp.queueFlags & vk::QueueFlagBits::eGraphics) != static_cast<vk::QueueFlags>(0);
198 } );
199 isSuitable = isSuitable && ( qfpIter != queueFamilies.end() );
200 auto extensions = device.enumerateDeviceExtensionProperties( );
201 bool found = true;
202 for (auto const & extension : deviceExtensions) {
203 auto extensionIter = std::ranges::find_if(extensions, [extension](auto const & ext) {return strcmp(ext.extensionName, extension) == 0;});
204 found = found && extensionIter != extensions.end();
205 }
206 isSuitable = isSuitable && found;
207 if (isSuitable) {
208 _physicalDevice = device;
209 }
210 return isSuitable;
211 });
212 if (devIter == devices.end()) {
213 throw std::runtime_error("failed to find a suitable GPU!");
214 }
215 }

References _instance, _physicalDevice, and deviceExtensions.

Referenced by initVulkan().

Here is the caller graph for this function:

◆ run()

void HelloTriangleApplication::run ( )
inline
58 {
59 initVulkan();
60 initWindow();
61 mainLoop();
62 cleanup();
63 }
void initWindow()
Definition main.cpp:71
void mainLoop()
Definition main.cpp:84
void cleanup()
Definition main.cpp:90
void initVulkan()
Definition main.cpp:65

References cleanup(), initVulkan(), initWindow(), and mainLoop().

Here is the call graph for this function:

◆ setupDebugMessenger()

void HelloTriangleApplication::setupDebugMessenger ( )
inlineprivate
162 {
163 vk::DebugUtilsMessageSeverityFlagsEXT severityFlags(vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
164 vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
165 vk::DebugUtilsMessageSeverityFlagBitsEXT::eError);
166 vk::DebugUtilsMessageTypeFlagsEXT messageTypeFlags(
167 vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral | vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance | vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation);
168 vk::DebugUtilsMessengerCreateInfoEXT debugUtilsMessengerCreateInfoEXT{.messageSeverity = severityFlags,
169 .messageType = messageTypeFlags,
170 .pfnUserCallback = &debugCallback};
171 _debugMessenger = _instance.createDebugUtilsMessengerEXT(debugUtilsMessengerCreateInfoEXT);
172 }
static VKAPI_ATTR vk::Bool32 VKAPI_CALL debugCallback(vk::DebugUtilsMessageSeverityFlagBitsEXT severity, vk::DebugUtilsMessageTypeFlagsEXT type, const vk::DebugUtilsMessengerCallbackDataEXT *pCallbackData, void *)
Definition main.cpp:178
vk::raii::DebugUtilsMessengerEXT _debugMessenger
Definition main.cpp:51

References _debugMessenger, _instance, and debugCallback().

Here is the call graph for this function:

Member Data Documentation

◆ _context

vk::raii::Context HelloTriangleApplication::_context
private

Referenced by createInstance().

◆ _debugMessenger

vk::raii::DebugUtilsMessengerEXT HelloTriangleApplication::_debugMessenger = nullptr
private

Referenced by setupDebugMessenger().

◆ _device

vk::raii::Device HelloTriangleApplication::_device = nullptr
private

Referenced by createLogicalDevice().

◆ _graphicsQueue

vk::raii::Queue HelloTriangleApplication::_graphicsQueue = nullptr
private

Referenced by createLogicalDevice().

◆ _instance

vk::raii::Instance HelloTriangleApplication::_instance = nullptr
private

◆ _physicalDevice

vk::raii::PhysicalDevice HelloTriangleApplication::_physicalDevice = nullptr
private

◆ _presentQueue

vk::raii::Queue HelloTriangleApplication::_presentQueue = nullptr
private

Referenced by createLogicalDevice().

◆ _window

GLFWwindow* HelloTriangleApplication::_window = nullptr
private

◆ deviceExtensions

std::vector<const char*> HelloTriangleApplication::deviceExtensions
private
Initial value:
= {
vk::KHRSwapchainExtensionName
}
174 {
175 vk::KHRSwapchainExtensionName
176 };

Referenced by createLogicalDevice(), and pickPhysicalDevice().

◆ surface

vk::raii::SurfaceKHR HelloTriangleApplication::surface = nullptr
private

The documentation for this class was generated from the following file: