mirror of
https://github.com/charles-lunarg/vk-bootstrap.git
synced 2024-11-26 00:34:35 +00:00
Revised error handling to be sensible and consistent.
While more error values need to be fleshed out (one for every possible vulkan error) it has all of the major issues handled.
This commit is contained in:
parent
5375504bb3
commit
3e7e283e3f
@ -8,8 +8,7 @@
|
|||||||
|
|
||||||
const int MAX_FRAMES_IN_FLIGHT = 2;
|
const int MAX_FRAMES_IN_FLIGHT = 2;
|
||||||
|
|
||||||
struct Init
|
struct Init {
|
||||||
{
|
|
||||||
GLFWwindow* window;
|
GLFWwindow* window;
|
||||||
vkb::Instance instance;
|
vkb::Instance instance;
|
||||||
VkSurfaceKHR surface;
|
VkSurfaceKHR surface;
|
||||||
@ -17,8 +16,7 @@ struct Init
|
|||||||
vkb::Swapchain swapchain;
|
vkb::Swapchain swapchain;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RenderData
|
struct RenderData {
|
||||||
{
|
|
||||||
VkQueue graphics_queue;
|
VkQueue graphics_queue;
|
||||||
VkQueue present_queue;
|
VkQueue present_queue;
|
||||||
|
|
||||||
@ -40,15 +38,13 @@ struct RenderData
|
|||||||
size_t current_frame = 0;
|
size_t current_frame = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
int device_initialization (Init& init)
|
int device_initialization (Init& init) {
|
||||||
{
|
|
||||||
init.window = create_window_glfw (false);
|
init.window = create_window_glfw (false);
|
||||||
|
|
||||||
vkb::InstanceBuilder instance_builder;
|
vkb::InstanceBuilder instance_builder;
|
||||||
auto instance_ret = instance_builder.set_default_debug_messenger ().setup_validation_layers ().build ();
|
auto instance_ret = instance_builder.set_default_debug_messenger ().setup_validation_layers ().build ();
|
||||||
if (!instance_ret)
|
if (!instance_ret) {
|
||||||
{
|
std::cout << static_cast<uint32_t> (instance_ret.error ().type) << "\n";
|
||||||
std::cout << instance_ret.error ().msg << "\n";
|
|
||||||
}
|
}
|
||||||
init.instance = instance_ret.value ();
|
init.instance = instance_ret.value ();
|
||||||
|
|
||||||
@ -56,40 +52,35 @@ int device_initialization (Init& init)
|
|||||||
|
|
||||||
vkb::PhysicalDeviceSelector phys_device_selector (init.instance);
|
vkb::PhysicalDeviceSelector phys_device_selector (init.instance);
|
||||||
auto phys_device_ret = phys_device_selector.set_surface (init.surface).select ();
|
auto phys_device_ret = phys_device_selector.set_surface (init.surface).select ();
|
||||||
if (!phys_device_ret)
|
if (!phys_device_ret) {
|
||||||
{
|
std::cout << static_cast<uint32_t> (phys_device_ret.error ().type) << "\n";
|
||||||
std::cout << phys_device_ret.error ().msg << "\n";
|
|
||||||
}
|
}
|
||||||
vkb::PhysicalDevice physical_device = phys_device_ret.value ();
|
vkb::PhysicalDevice physical_device = phys_device_ret.value ();
|
||||||
|
|
||||||
vkb::DeviceBuilder device_builder{ physical_device };
|
vkb::DeviceBuilder device_builder{ physical_device };
|
||||||
auto device_ret = device_builder.build ();
|
auto device_ret = device_builder.build ();
|
||||||
if (!device_ret)
|
if (!device_ret) {
|
||||||
{
|
std::cout << static_cast<uint32_t> (device_ret.error ().type) << "\n";
|
||||||
std::cout << device_ret.error ().msg << "\n";
|
|
||||||
}
|
}
|
||||||
init.device = device_ret.value ();
|
init.device = device_ret.value ();
|
||||||
|
|
||||||
vkb::SwapchainBuilder swapchain_builder{ init.device };
|
vkb::SwapchainBuilder swapchain_builder{ init.device };
|
||||||
auto swap_ret =
|
auto swap_ret =
|
||||||
swapchain_builder.use_default_format_selection ().use_default_present_mode_selection ().build ();
|
swapchain_builder.use_default_format_selection ().use_default_present_mode_selection ().build ();
|
||||||
if (!swap_ret)
|
if (!swap_ret) {
|
||||||
{
|
std::cout << static_cast<uint32_t> (swap_ret.error ().type) << "\n";
|
||||||
std::cout << swap_ret.error ().msg << "\n";
|
|
||||||
}
|
}
|
||||||
init.swapchain = swap_ret.value ();
|
init.swapchain = swap_ret.value ();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_queues (Init& init, RenderData& data)
|
int get_queues (Init& init, RenderData& data) {
|
||||||
{
|
data.graphics_queue = vkb::get_graphics_queue (init.device).value ();
|
||||||
data.graphics_queue = vkb::get_queue_graphics (init.device).value ();
|
data.present_queue = vkb::get_present_queue (init.device).value ();
|
||||||
data.present_queue = vkb::get_queue_graphics (init.device).value ();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_render_pass (Init& init, RenderData& data)
|
int create_render_pass (Init& init, RenderData& data) {
|
||||||
{
|
|
||||||
VkAttachmentDescription color_attachment = {};
|
VkAttachmentDescription color_attachment = {};
|
||||||
color_attachment.format = init.swapchain.image_format;
|
color_attachment.format = init.swapchain.image_format;
|
||||||
color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||||
@ -126,19 +117,16 @@ int create_render_pass (Init& init, RenderData& data)
|
|||||||
render_pass_info.dependencyCount = 1;
|
render_pass_info.dependencyCount = 1;
|
||||||
render_pass_info.pDependencies = &dependency;
|
render_pass_info.pDependencies = &dependency;
|
||||||
|
|
||||||
if (vkCreateRenderPass (init.device.device, &render_pass_info, nullptr, &data.render_pass) != VK_SUCCESS)
|
if (vkCreateRenderPass (init.device.device, &render_pass_info, nullptr, &data.render_pass) != VK_SUCCESS) {
|
||||||
{
|
|
||||||
return -1; // failed to create render pass!
|
return -1; // failed to create render pass!
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<char> readFile (const std::string& filename)
|
std::vector<char> readFile (const std::string& filename) {
|
||||||
{
|
|
||||||
std::ifstream file (filename, std::ios::ate | std::ios::binary);
|
std::ifstream file (filename, std::ios::ate | std::ios::binary);
|
||||||
|
|
||||||
if (!file.is_open ())
|
if (!file.is_open ()) {
|
||||||
{
|
|
||||||
throw std::runtime_error ("failed to open file!");
|
throw std::runtime_error ("failed to open file!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,31 +141,27 @@ std::vector<char> readFile (const std::string& filename)
|
|||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkShaderModule createShaderModule (Init& init, const std::vector<char>& code)
|
VkShaderModule createShaderModule (Init& init, const std::vector<char>& code) {
|
||||||
{
|
|
||||||
VkShaderModuleCreateInfo create_info = {};
|
VkShaderModuleCreateInfo create_info = {};
|
||||||
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||||
create_info.codeSize = code.size ();
|
create_info.codeSize = code.size ();
|
||||||
create_info.pCode = reinterpret_cast<const uint32_t*> (code.data ());
|
create_info.pCode = reinterpret_cast<const uint32_t*> (code.data ());
|
||||||
|
|
||||||
VkShaderModule shaderModule;
|
VkShaderModule shaderModule;
|
||||||
if (vkCreateShaderModule (init.device.device, &create_info, nullptr, &shaderModule) != VK_SUCCESS)
|
if (vkCreateShaderModule (init.device.device, &create_info, nullptr, &shaderModule) != VK_SUCCESS) {
|
||||||
{
|
|
||||||
return VK_NULL_HANDLE; // failed to create shader module
|
return VK_NULL_HANDLE; // failed to create shader module
|
||||||
}
|
}
|
||||||
|
|
||||||
return shaderModule;
|
return shaderModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_graphics_pipeline (Init& init, RenderData& data)
|
int create_graphics_pipeline (Init& init, RenderData& data) {
|
||||||
{
|
|
||||||
auto vert_code = readFile ("vert.spv");
|
auto vert_code = readFile ("vert.spv");
|
||||||
auto frag_code = readFile ("frag.spv");
|
auto frag_code = readFile ("frag.spv");
|
||||||
|
|
||||||
VkShaderModule vert_module = createShaderModule (init, vert_code);
|
VkShaderModule vert_module = createShaderModule (init, vert_code);
|
||||||
VkShaderModule frag_module = createShaderModule (init, frag_code);
|
VkShaderModule frag_module = createShaderModule (init, frag_code);
|
||||||
if (vert_module == VK_NULL_HANDLE || frag_module == VK_NULL_HANDLE)
|
if (vert_module == VK_NULL_HANDLE || frag_module == VK_NULL_HANDLE) {
|
||||||
{
|
|
||||||
return -1; // failed to create shader modules
|
return -1; // failed to create shader modules
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,8 +244,8 @@ int create_graphics_pipeline (Init& init, RenderData& data)
|
|||||||
pipeline_layout_info.setLayoutCount = 0;
|
pipeline_layout_info.setLayoutCount = 0;
|
||||||
pipeline_layout_info.pushConstantRangeCount = 0;
|
pipeline_layout_info.pushConstantRangeCount = 0;
|
||||||
|
|
||||||
if (vkCreatePipelineLayout (init.device.device, &pipeline_layout_info, nullptr, &data.pipeline_layout) != VK_SUCCESS)
|
if (vkCreatePipelineLayout (
|
||||||
{
|
init.device.device, &pipeline_layout_info, nullptr, &data.pipeline_layout) != VK_SUCCESS) {
|
||||||
return -1; // failed to create pipeline layout
|
return -1; // failed to create pipeline layout
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -281,8 +265,7 @@ int create_graphics_pipeline (Init& init, RenderData& data)
|
|||||||
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
||||||
|
|
||||||
if (vkCreateGraphicsPipelines (
|
if (vkCreateGraphicsPipelines (
|
||||||
init.device.device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &data.graphics_pipeline) != VK_SUCCESS)
|
init.device.device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &data.graphics_pipeline) != VK_SUCCESS) {
|
||||||
{
|
|
||||||
return -1; // failed to create graphics pipeline
|
return -1; // failed to create graphics pipeline
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,8 +274,7 @@ int create_graphics_pipeline (Init& init, RenderData& data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_framebuffers (Init& init, RenderData& data)
|
int create_framebuffers (Init& init, RenderData& data) {
|
||||||
{
|
|
||||||
data.swapchain_images = vkb::get_swapchain_images (init.swapchain).value ();
|
data.swapchain_images = vkb::get_swapchain_images (init.swapchain).value ();
|
||||||
// init.swapchain.image_count = data.swapchain_images.size ();
|
// init.swapchain.image_count = data.swapchain_images.size ();
|
||||||
data.swapchain_image_views =
|
data.swapchain_image_views =
|
||||||
@ -300,8 +282,7 @@ int create_framebuffers (Init& init, RenderData& data)
|
|||||||
|
|
||||||
data.framebuffers.resize (data.swapchain_image_views.size ());
|
data.framebuffers.resize (data.swapchain_image_views.size ());
|
||||||
|
|
||||||
for (size_t i = 0; i < data.swapchain_image_views.size (); i++)
|
for (size_t i = 0; i < data.swapchain_image_views.size (); i++) {
|
||||||
{
|
|
||||||
VkImageView attachments[] = { data.swapchain_image_views[i] };
|
VkImageView attachments[] = { data.swapchain_image_views[i] };
|
||||||
|
|
||||||
VkFramebufferCreateInfo framebuffer_info = {};
|
VkFramebufferCreateInfo framebuffer_info = {};
|
||||||
@ -313,29 +294,25 @@ int create_framebuffers (Init& init, RenderData& data)
|
|||||||
framebuffer_info.height = init.swapchain.extent.height;
|
framebuffer_info.height = init.swapchain.extent.height;
|
||||||
framebuffer_info.layers = 1;
|
framebuffer_info.layers = 1;
|
||||||
|
|
||||||
if (vkCreateFramebuffer (init.device.device, &framebuffer_info, nullptr, &data.framebuffers[i]) != VK_SUCCESS)
|
if (vkCreateFramebuffer (init.device.device, &framebuffer_info, nullptr, &data.framebuffers[i]) != VK_SUCCESS) {
|
||||||
{
|
|
||||||
return -1; // failed to create framebuffer
|
return -1; // failed to create framebuffer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_command_pool (Init& init, RenderData& data)
|
int create_command_pool (Init& init, RenderData& data) {
|
||||||
{
|
|
||||||
VkCommandPoolCreateInfo pool_info = {};
|
VkCommandPoolCreateInfo pool_info = {};
|
||||||
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
pool_info.queueFamilyIndex = vkb::get_queue_index_graphics (init.device);
|
pool_info.queueFamilyIndex = vkb::get_graphics_queue_index (init.device).value ();
|
||||||
|
|
||||||
if (vkCreateCommandPool (init.device.device, &pool_info, nullptr, &data.command_pool) != VK_SUCCESS)
|
if (vkCreateCommandPool (init.device.device, &pool_info, nullptr, &data.command_pool) != VK_SUCCESS) {
|
||||||
{
|
|
||||||
return -1; // failed to create command pool
|
return -1; // failed to create command pool
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_command_buffers (Init& init, RenderData& data)
|
int create_command_buffers (Init& init, RenderData& data) {
|
||||||
{
|
|
||||||
data.command_buffers.resize (data.framebuffers.size ());
|
data.command_buffers.resize (data.framebuffers.size ());
|
||||||
|
|
||||||
VkCommandBufferAllocateInfo allocInfo = {};
|
VkCommandBufferAllocateInfo allocInfo = {};
|
||||||
@ -344,18 +321,15 @@ int create_command_buffers (Init& init, RenderData& data)
|
|||||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
allocInfo.commandBufferCount = (uint32_t)data.command_buffers.size ();
|
allocInfo.commandBufferCount = (uint32_t)data.command_buffers.size ();
|
||||||
|
|
||||||
if (vkAllocateCommandBuffers (init.device.device, &allocInfo, data.command_buffers.data ()) != VK_SUCCESS)
|
if (vkAllocateCommandBuffers (init.device.device, &allocInfo, data.command_buffers.data ()) != VK_SUCCESS) {
|
||||||
{
|
|
||||||
return -1; // failed to allocate command buffers;
|
return -1; // failed to allocate command buffers;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < data.command_buffers.size (); i++)
|
for (size_t i = 0; i < data.command_buffers.size (); i++) {
|
||||||
{
|
|
||||||
VkCommandBufferBeginInfo begin_info = {};
|
VkCommandBufferBeginInfo begin_info = {};
|
||||||
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
|
||||||
if (vkBeginCommandBuffer (data.command_buffers[i], &begin_info) != VK_SUCCESS)
|
if (vkBeginCommandBuffer (data.command_buffers[i], &begin_info) != VK_SUCCESS) {
|
||||||
{
|
|
||||||
return -1; // failed to begin recording command buffer
|
return -1; // failed to begin recording command buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,16 +352,14 @@ int create_command_buffers (Init& init, RenderData& data)
|
|||||||
|
|
||||||
vkCmdEndRenderPass (data.command_buffers[i]);
|
vkCmdEndRenderPass (data.command_buffers[i]);
|
||||||
|
|
||||||
if (vkEndCommandBuffer (data.command_buffers[i]) != VK_SUCCESS)
|
if (vkEndCommandBuffer (data.command_buffers[i]) != VK_SUCCESS) {
|
||||||
{
|
|
||||||
return -1; // failed to record command buffer!
|
return -1; // failed to record command buffer!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int create_sync_objects (Init& init, RenderData& data)
|
int create_sync_objects (Init& init, RenderData& data) {
|
||||||
{
|
|
||||||
data.available_semaphores.resize (MAX_FRAMES_IN_FLIGHT);
|
data.available_semaphores.resize (MAX_FRAMES_IN_FLIGHT);
|
||||||
data.finished_semaphore.resize (MAX_FRAMES_IN_FLIGHT);
|
data.finished_semaphore.resize (MAX_FRAMES_IN_FLIGHT);
|
||||||
data.in_flight_fences.resize (MAX_FRAMES_IN_FLIGHT);
|
data.in_flight_fences.resize (MAX_FRAMES_IN_FLIGHT);
|
||||||
@ -400,20 +372,17 @@ int create_sync_objects (Init& init, RenderData& data)
|
|||||||
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
|
|
||||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||||
{
|
|
||||||
if (vkCreateSemaphore (init.device.device, &semaphore_info, nullptr, &data.available_semaphores[i]) != VK_SUCCESS ||
|
if (vkCreateSemaphore (init.device.device, &semaphore_info, nullptr, &data.available_semaphores[i]) != VK_SUCCESS ||
|
||||||
vkCreateSemaphore (init.device.device, &semaphore_info, nullptr, &data.finished_semaphore[i]) != VK_SUCCESS ||
|
vkCreateSemaphore (init.device.device, &semaphore_info, nullptr, &data.finished_semaphore[i]) != VK_SUCCESS ||
|
||||||
vkCreateFence (init.device.device, &fence_info, nullptr, &data.in_flight_fences[i]) != VK_SUCCESS)
|
vkCreateFence (init.device.device, &fence_info, nullptr, &data.in_flight_fences[i]) != VK_SUCCESS) {
|
||||||
{
|
|
||||||
return -1; // failed to create synchronization objects for a frame
|
return -1; // failed to create synchronization objects for a frame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int draw_frame (Init& init, RenderData& data)
|
int draw_frame (Init& init, RenderData& data) {
|
||||||
{
|
|
||||||
vkWaitForFences (init.device.device, 1, &data.in_flight_fences[data.current_frame], VK_TRUE, UINT64_MAX);
|
vkWaitForFences (init.device.device, 1, &data.in_flight_fences[data.current_frame], VK_TRUE, UINT64_MAX);
|
||||||
|
|
||||||
uint32_t image_index = 0;
|
uint32_t image_index = 0;
|
||||||
@ -424,8 +393,7 @@ int draw_frame (Init& init, RenderData& data)
|
|||||||
VK_NULL_HANDLE,
|
VK_NULL_HANDLE,
|
||||||
&image_index);
|
&image_index);
|
||||||
|
|
||||||
if (data.image_in_flight[image_index] != VK_NULL_HANDLE)
|
if (data.image_in_flight[image_index] != VK_NULL_HANDLE) {
|
||||||
{
|
|
||||||
vkWaitForFences (init.device.device, 1, &data.image_in_flight[image_index], VK_TRUE, UINT64_MAX);
|
vkWaitForFences (init.device.device, 1, &data.image_in_flight[image_index], VK_TRUE, UINT64_MAX);
|
||||||
}
|
}
|
||||||
data.image_in_flight[image_index] = data.in_flight_fences[data.current_frame];
|
data.image_in_flight[image_index] = data.in_flight_fences[data.current_frame];
|
||||||
@ -448,8 +416,7 @@ int draw_frame (Init& init, RenderData& data)
|
|||||||
|
|
||||||
vkResetFences (init.device.device, 1, &data.in_flight_fences[data.current_frame]);
|
vkResetFences (init.device.device, 1, &data.in_flight_fences[data.current_frame]);
|
||||||
|
|
||||||
if (vkQueueSubmit (data.graphics_queue, 1, &submitInfo, data.in_flight_fences[data.current_frame]) != VK_SUCCESS)
|
if (vkQueueSubmit (data.graphics_queue, 1, &submitInfo, data.in_flight_fences[data.current_frame]) != VK_SUCCESS) {
|
||||||
{
|
|
||||||
return -1; //"failed to submit draw command buffer
|
return -1; //"failed to submit draw command buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,10 +438,8 @@ int draw_frame (Init& init, RenderData& data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup (Init& init, RenderData& data)
|
void cleanup (Init& init, RenderData& data) {
|
||||||
{
|
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
|
||||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
|
||||||
{
|
|
||||||
vkDestroySemaphore (init.device.device, data.finished_semaphore[i], nullptr);
|
vkDestroySemaphore (init.device.device, data.finished_semaphore[i], nullptr);
|
||||||
vkDestroySemaphore (init.device.device, data.available_semaphores[i], nullptr);
|
vkDestroySemaphore (init.device.device, data.available_semaphores[i], nullptr);
|
||||||
vkDestroyFence (init.device.device, data.in_flight_fences[i], nullptr);
|
vkDestroyFence (init.device.device, data.in_flight_fences[i], nullptr);
|
||||||
@ -482,8 +447,7 @@ void cleanup (Init& init, RenderData& data)
|
|||||||
|
|
||||||
vkDestroyCommandPool (init.device.device, data.command_pool, nullptr);
|
vkDestroyCommandPool (init.device.device, data.command_pool, nullptr);
|
||||||
|
|
||||||
for (auto framebuffer : data.framebuffers)
|
for (auto framebuffer : data.framebuffers) {
|
||||||
{
|
|
||||||
vkDestroyFramebuffer (init.device.device, framebuffer, nullptr);
|
vkDestroyFramebuffer (init.device.device, framebuffer, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,8 +455,7 @@ void cleanup (Init& init, RenderData& data)
|
|||||||
vkDestroyPipelineLayout (init.device.device, data.pipeline_layout, nullptr);
|
vkDestroyPipelineLayout (init.device.device, data.pipeline_layout, nullptr);
|
||||||
vkDestroyRenderPass (init.device.device, data.render_pass, nullptr);
|
vkDestroyRenderPass (init.device.device, data.render_pass, nullptr);
|
||||||
|
|
||||||
for (auto imageView : data.swapchain_image_views)
|
for (auto imageView : data.swapchain_image_views) {
|
||||||
{
|
|
||||||
vkDestroyImageView (init.device.device, imageView, nullptr);
|
vkDestroyImageView (init.device.device, imageView, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,8 +466,7 @@ void cleanup (Init& init, RenderData& data)
|
|||||||
destroy_window_glfw (init.window);
|
destroy_window_glfw (init.window);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main ()
|
int main () {
|
||||||
{
|
|
||||||
Init init;
|
Init init;
|
||||||
RenderData render_data;
|
RenderData render_data;
|
||||||
|
|
||||||
@ -518,18 +480,15 @@ int main ()
|
|||||||
res = create_command_buffers (init, render_data);
|
res = create_command_buffers (init, render_data);
|
||||||
res = create_sync_objects (init, render_data);
|
res = create_sync_objects (init, render_data);
|
||||||
|
|
||||||
if (res != 0)
|
if (res != 0) {
|
||||||
{
|
|
||||||
std::cout << "failed to initialize vulkan\n";
|
std::cout << "failed to initialize vulkan\n";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!glfwWindowShouldClose (init.window))
|
while (!glfwWindowShouldClose (init.window)) {
|
||||||
{
|
|
||||||
glfwPollEvents ();
|
glfwPollEvents ();
|
||||||
int res = draw_frame (init, render_data);
|
int res = draw_frame (init, render_data);
|
||||||
if (res != 0)
|
if (res != 0) {
|
||||||
{
|
|
||||||
std::cout << "failed to draw frame \n";
|
std::cout << "failed to draw frame \n";
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,13 @@ auto get_vector (F&& f, Ts&&... ts) -> Expected<std::vector<T>, VkResult> {
|
|||||||
do {
|
do {
|
||||||
err = f (ts..., &count, nullptr);
|
err = f (ts..., &count, nullptr);
|
||||||
if (err) {
|
if (err) {
|
||||||
return Error{ err, "" };
|
return err;
|
||||||
};
|
};
|
||||||
results.resize (count);
|
results.resize (count);
|
||||||
err = f (ts..., &count, results.data ());
|
err = f (ts..., &count, results.data ());
|
||||||
} while (err == VK_INCOMPLETE);
|
} while (err == VK_INCOMPLETE);
|
||||||
if (err) {
|
if (err != VK_SUCCESS) {
|
||||||
return Error{ err, "" };
|
return err;
|
||||||
};
|
};
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
@ -146,7 +146,7 @@ void destroy_instance (Instance instance) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::Expected<Instance, VkResult> InstanceBuilder::build () {
|
detail::Expected<Instance, detail::Error<InstanceError>> InstanceBuilder::build () {
|
||||||
|
|
||||||
VkApplicationInfo app_info = {};
|
VkApplicationInfo app_info = {};
|
||||||
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||||
@ -189,7 +189,7 @@ detail::Expected<Instance, VkResult> InstanceBuilder::build () {
|
|||||||
}
|
}
|
||||||
bool all_layers_supported = detail::check_layers_supported (layers);
|
bool all_layers_supported = detail::check_layers_supported (layers);
|
||||||
if (!all_layers_supported) {
|
if (!all_layers_supported) {
|
||||||
return detail::Error{ VK_ERROR_LAYER_NOT_PRESENT, "Not all layers supported!" };
|
return detail::Error<InstanceError>{ InstanceError::requested_layers_not_present };
|
||||||
}
|
}
|
||||||
|
|
||||||
VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {};
|
VkDebugUtilsMessengerCreateInfoEXT messengerCreateInfo = {};
|
||||||
@ -234,7 +234,8 @@ detail::Expected<Instance, VkResult> InstanceBuilder::build () {
|
|||||||
|
|
||||||
Instance instance;
|
Instance instance;
|
||||||
VkResult res = vkCreateInstance (&instance_create_info, nullptr, &instance.instance);
|
VkResult res = vkCreateInstance (&instance_create_info, nullptr, &instance.instance);
|
||||||
if (res != VK_SUCCESS) return detail::Error{ res, "Failed to create instance" };
|
if (res != VK_SUCCESS)
|
||||||
|
return detail::Error<InstanceError>{ InstanceError::failed_create_instance, res };
|
||||||
|
|
||||||
if (info.use_debug_messenger) {
|
if (info.use_debug_messenger) {
|
||||||
res = create_debug_utils_messenger (instance.instance,
|
res = create_debug_utils_messenger (instance.instance,
|
||||||
@ -243,7 +244,7 @@ detail::Expected<Instance, VkResult> InstanceBuilder::build () {
|
|||||||
info.debug_message_type,
|
info.debug_message_type,
|
||||||
&instance.debug_messenger);
|
&instance.debug_messenger);
|
||||||
if (res != VK_SUCCESS) {
|
if (res != VK_SUCCESS) {
|
||||||
return detail::Error{ res, "Failed to create setup debug callback" };
|
return detail::Error<InstanceError>{ InstanceError::failed_create_debug_messenger, res };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,30 +337,33 @@ struct SurfaceSupportDetails {
|
|||||||
std::vector<VkPresentModeKHR> present_modes;
|
std::vector<VkPresentModeKHR> present_modes;
|
||||||
};
|
};
|
||||||
|
|
||||||
Expected<SurfaceSupportDetails, VkResult> query_surface_support_details (
|
enum class SurfaceSupportError {
|
||||||
|
surface_handle_null,
|
||||||
|
failed_get_surface_capabilities,
|
||||||
|
failed_enumerate_surface_formats,
|
||||||
|
failed_enumerate_present_modes
|
||||||
|
};
|
||||||
|
|
||||||
|
Expected<SurfaceSupportDetails, detail::Error<SurfaceSupportError>> query_surface_support_details (
|
||||||
VkPhysicalDevice phys_device, VkSurfaceKHR surface) {
|
VkPhysicalDevice phys_device, VkSurfaceKHR surface) {
|
||||||
if (surface == VK_NULL_HANDLE)
|
if (surface == VK_NULL_HANDLE)
|
||||||
return Error{ VK_ERROR_INITIALIZATION_FAILED, "surface handle was null" };
|
return detail::Error<SurfaceSupportError>{ SurfaceSupportError::surface_handle_null };
|
||||||
|
|
||||||
VkSurfaceCapabilitiesKHR capabilities;
|
VkSurfaceCapabilitiesKHR capabilities;
|
||||||
VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR (phys_device, surface, &capabilities);
|
VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR (phys_device, surface, &capabilities);
|
||||||
if (res != VK_SUCCESS) {
|
if (res != VK_SUCCESS) {
|
||||||
// error
|
return detail::Error<SurfaceSupportError>{ SurfaceSupportError::failed_get_surface_capabilities, res };
|
||||||
/* possible errors
|
|
||||||
VK_ERROR_OUT_OF_HOST_MEMORY
|
|
||||||
VK_ERROR_OUT_OF_DEVICE_MEMORY
|
|
||||||
VK_ERROR_SURFACE_LOST_KHR
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
auto formats = detail::get_vector<VkSurfaceFormatKHR> (
|
auto formats = detail::get_vector<VkSurfaceFormatKHR> (
|
||||||
vkGetPhysicalDeviceSurfaceFormatsKHR, phys_device, surface);
|
vkGetPhysicalDeviceSurfaceFormatsKHR, phys_device, surface);
|
||||||
if (!formats.has_value ())
|
if (!formats.has_value ())
|
||||||
return detail::Error{ formats.error ().error_code, "Couldn't get surface formats" };
|
return detail::Error<SurfaceSupportError>{ SurfaceSupportError::failed_enumerate_surface_formats,
|
||||||
|
formats.error () };
|
||||||
auto present_modes = detail::get_vector<VkPresentModeKHR> (
|
auto present_modes = detail::get_vector<VkPresentModeKHR> (
|
||||||
vkGetPhysicalDeviceSurfacePresentModesKHR, phys_device, surface);
|
vkGetPhysicalDeviceSurfacePresentModesKHR, phys_device, surface);
|
||||||
if (!present_modes.has_value ())
|
if (!present_modes.has_value ())
|
||||||
return detail::Error{ formats.error ().error_code, "Couldn't get surface present modes" };
|
return detail::Error<SurfaceSupportError>{ SurfaceSupportError::failed_enumerate_present_modes,
|
||||||
|
formats.error () };
|
||||||
return SurfaceSupportDetails{ capabilities, formats.value (), present_modes.value () };
|
return SurfaceSupportDetails{ capabilities, formats.value (), present_modes.value () };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -580,13 +584,14 @@ PhysicalDeviceSelector::PhysicalDeviceSelector (Instance const& instance) {
|
|||||||
criteria.require_present = !instance.headless;
|
criteria.require_present = !instance.headless;
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::Expected<PhysicalDevice, VkResult> PhysicalDeviceSelector::select () {
|
detail::Expected<PhysicalDevice, detail::Error<PhysicalDeviceError>> PhysicalDeviceSelector::select () {
|
||||||
auto physical_devices = detail::get_vector<VkPhysicalDevice> (vkEnumeratePhysicalDevices, info.instance);
|
auto physical_devices = detail::get_vector<VkPhysicalDevice> (vkEnumeratePhysicalDevices, info.instance);
|
||||||
if (!physical_devices.has_value ()) {
|
if (!physical_devices.has_value ()) {
|
||||||
return detail::Error{ physical_devices.error ().error_code, "Failed to find physical devices" };
|
return detail::Error<PhysicalDeviceError>{ PhysicalDeviceError::failed_enumerate_physical_devices,
|
||||||
|
physical_devices.error () };
|
||||||
}
|
}
|
||||||
if (physical_devices.value ().size () == 0) {
|
if (physical_devices.value ().size () == 0) {
|
||||||
return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "No physical devices found" };
|
return detail::Error<PhysicalDeviceError>{ PhysicalDeviceError::no_physical_devices_found };
|
||||||
}
|
}
|
||||||
|
|
||||||
PhysicalDevice physical_device;
|
PhysicalDevice physical_device;
|
||||||
@ -605,7 +610,7 @@ detail::Expected<PhysicalDevice, VkResult> PhysicalDeviceSelector::select () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (physical_device.phys_device == VK_NULL_HANDLE) {
|
if (physical_device.phys_device == VK_NULL_HANDLE) {
|
||||||
return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "Failed to find a suitable GPU!" };
|
return detail::Error<PhysicalDeviceError>{ PhysicalDeviceError::no_suitable_device };
|
||||||
}
|
}
|
||||||
|
|
||||||
physical_device.surface = info.surface;
|
physical_device.surface = info.surface;
|
||||||
@ -703,7 +708,7 @@ DeviceBuilder::DeviceBuilder (PhysicalDevice phys_device) {
|
|||||||
info.extensions = phys_device.extensions_to_enable;
|
info.extensions = phys_device.extensions_to_enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::Expected<Device, VkResult> DeviceBuilder::build () {
|
detail::Expected<Device, detail::Error<DeviceError>> DeviceBuilder::build () {
|
||||||
|
|
||||||
auto queue_families = detail::get_vector_noerror<VkQueueFamilyProperties> (
|
auto queue_families = detail::get_vector_noerror<VkQueueFamilyProperties> (
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties, info.physical_device.phys_device);
|
vkGetPhysicalDeviceQueueFamilyProperties, info.physical_device.phys_device);
|
||||||
@ -739,7 +744,7 @@ detail::Expected<Device, VkResult> DeviceBuilder::build () {
|
|||||||
VkResult res =
|
VkResult res =
|
||||||
vkCreateDevice (info.physical_device.phys_device, &device_create_info, nullptr, &device.device);
|
vkCreateDevice (info.physical_device.phys_device, &device_create_info, nullptr, &device.device);
|
||||||
if (res != VK_SUCCESS) {
|
if (res != VK_SUCCESS) {
|
||||||
return detail::Error{ res, "Couldn't create device" };
|
return detail::Error<DeviceError>{ DeviceError::failed_create_device, res };
|
||||||
}
|
}
|
||||||
device.physical_device = info.physical_device;
|
device.physical_device = info.physical_device;
|
||||||
device.surface = info.physical_device.surface;
|
device.surface = info.physical_device.surface;
|
||||||
@ -753,38 +758,62 @@ template <typename T> DeviceBuilder& DeviceBuilder::add_pNext (T* structure) {
|
|||||||
|
|
||||||
// ---- Getting Queues ---- //
|
// ---- Getting Queues ---- //
|
||||||
|
|
||||||
|
detail::Expected<uint32_t, detail::Error<QueueError>> get_present_queue_index (Device const& device) {
|
||||||
|
int present = get_present_queue_index (
|
||||||
|
device.physical_device.phys_device, device.surface, device.queue_families);
|
||||||
|
if (present < 0) return detail::Error<QueueError>{ QueueError::present_unavailable };
|
||||||
|
return static_cast<uint32_t> (present);
|
||||||
|
}
|
||||||
|
detail::Expected<uint32_t, detail::Error<QueueError>> get_graphics_queue_index (Device const& device) {
|
||||||
|
int graphics = get_graphics_queue_index (device.queue_families);
|
||||||
|
if (graphics < 0) return detail::Error<QueueError>{ QueueError::invalid_queue_family_index };
|
||||||
|
return static_cast<uint32_t> (graphics);
|
||||||
|
}
|
||||||
|
detail::Expected<uint32_t, detail::Error<QueueError>> get_compute_queue_index (Device const& device) {
|
||||||
|
int compute = get_distinct_compute_queue_index (device.queue_families);
|
||||||
|
if (compute < 0) return detail::Error<QueueError>{ QueueError::compute_unavailable };
|
||||||
|
return static_cast<uint32_t> (compute);
|
||||||
|
}
|
||||||
|
detail::Expected<uint32_t, detail::Error<QueueError>> get_transfer_queue_index (Device const& device) {
|
||||||
|
int transfer = get_distinct_transfer_queue_index (device.queue_families);
|
||||||
|
if (transfer < 0) return detail::Error<QueueError>{ QueueError::transfer_unavailable };
|
||||||
|
return static_cast<uint32_t> (transfer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
VkQueue get_queue (VkDevice device, int32_t family) {
|
VkQueue get_queue (VkDevice device, int32_t family) {
|
||||||
VkQueue out_queue;
|
VkQueue out_queue;
|
||||||
vkGetDeviceQueue (device, family, 0, &out_queue);
|
vkGetDeviceQueue (device, family, 0, &out_queue);
|
||||||
return out_queue;
|
return out_queue;
|
||||||
}
|
}
|
||||||
detail::Expected<VkQueue, VkResult> get_present_queue (Device const& device) {
|
detail::Expected<VkQueue, detail::Error<QueueError>> get_present_queue (Device const& device) {
|
||||||
int present = get_present_queue_index (device.physical_device, device.surface, device.queue_families);
|
int present = get_present_queue_index (
|
||||||
|
device.physical_device.phys_device, device.surface, device.queue_families);
|
||||||
if (present >= 0) {
|
if (present >= 0) {
|
||||||
return get_queue (device.device, present);
|
return get_queue (device.device, present);
|
||||||
}
|
}
|
||||||
return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "presentation queue is not available" };
|
return detail::Error<QueueError>{ QueueError::present_unavailable };
|
||||||
}
|
}
|
||||||
detail::Expected<VkQueue, VkResult> get_graphics_queue (Device const& device) {
|
detail::Expected<VkQueue, detail::Error<QueueError>> get_graphics_queue (Device const& device) {
|
||||||
int graphics = get_graphics_queue_index (device.physical_device, device.surface, device.queue_families);
|
int graphics = get_graphics_queue_index (device.queue_families);
|
||||||
if (graphics >= 0) {
|
if (graphics >= 0) {
|
||||||
return get_queue (device.device, graphics);
|
return get_queue (device.device, graphics);
|
||||||
}
|
}
|
||||||
return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "requested queue family is not available" };
|
return detail::Error<QueueError>{ QueueError::invalid_queue_family_index };
|
||||||
}
|
}
|
||||||
detail::Expected<VkQueue, VkResult> get_compute_queue (Device const& device) {
|
detail::Expected<VkQueue, detail::Error<QueueError>> get_compute_queue (Device const& device) {
|
||||||
int compute = get_distinct_compute_queue_index (device.physical_device, device.surface, device.queue_families);
|
int compute = get_distinct_compute_queue_index (device.queue_families);
|
||||||
if (compute >= 0) {
|
if (compute >= 0) {
|
||||||
return get_queue (device.device, compute);
|
return get_queue (device.device, compute);
|
||||||
}
|
}
|
||||||
return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "requested queue family is not available" };
|
return detail::Error<QueueError>{ QueueError::compute_unavailable };
|
||||||
}
|
}
|
||||||
detail::Expected<VkQueue, VkResult> get_transfer_queue (Device const& device) {
|
detail::Expected<VkQueue, detail::Error<QueueError>> get_transfer_queue (Device const& device) {
|
||||||
int transfer = get_distinct_transfer_queue_index (device.physical_device, device.surface, device.queue_families);
|
int transfer = get_distinct_transfer_queue_index (device.queue_families);
|
||||||
if (transfer >= 0) {
|
if (transfer >= 0) {
|
||||||
return get_queue (device.device, transfer);
|
return get_queue (device.device, transfer);
|
||||||
}
|
}
|
||||||
return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "requested queue family is not available" };
|
return detail::Error<QueueError>{ QueueError::transfer_unavailable };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -840,21 +869,34 @@ SwapchainBuilder::SwapchainBuilder (Device const& device) {
|
|||||||
info.device = device.device;
|
info.device = device.device;
|
||||||
info.physical_device = device.physical_device.phys_device;
|
info.physical_device = device.physical_device.phys_device;
|
||||||
info.surface = device.surface;
|
info.surface = device.surface;
|
||||||
|
int present = get_present_queue_index (
|
||||||
|
device.physical_device.phys_device, device.surface, device.queue_families);
|
||||||
|
int graphics = get_graphics_queue_index (device.queue_families);
|
||||||
|
|
||||||
|
info.graphics_queue_index = graphics;
|
||||||
|
info.present_queue_index = present;
|
||||||
}
|
}
|
||||||
|
|
||||||
SwapchainBuilder::SwapchainBuilder (
|
SwapchainBuilder::SwapchainBuilder (VkPhysicalDevice const physical_device,
|
||||||
VkPhysicalDevice const physical_device, VkDevice const device, VkSurfaceKHR const surface) {
|
VkDevice const device,
|
||||||
|
VkSurfaceKHR const surface,
|
||||||
|
uint32_t graphics_queue_index,
|
||||||
|
uint32_t present_queue_index) {
|
||||||
info.physical_device = physical_device;
|
info.physical_device = physical_device;
|
||||||
info.device = device;
|
info.device = device;
|
||||||
info.surface = surface;
|
info.surface = surface;
|
||||||
|
info.graphics_queue_index = graphics_queue_index;
|
||||||
|
info.present_queue_index = present_queue_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::Expected<Swapchain, VkResult> SwapchainBuilder::build () {
|
detail::Expected<Swapchain, detail::Error<SwapchainError>> SwapchainBuilder::build () {
|
||||||
if (info.desired_formats.size () == 0) use_default_format_selection ();
|
if (info.desired_formats.size () == 0) use_default_format_selection ();
|
||||||
if (info.desired_present_modes.size () == 0) use_default_present_mode_selection ();
|
if (info.desired_present_modes.size () == 0) use_default_present_mode_selection ();
|
||||||
|
|
||||||
auto surface_support = detail::query_surface_support_details (info.physical_device, info.surface);
|
auto surface_support = detail::query_surface_support_details (info.physical_device, info.surface);
|
||||||
if (!surface_support.has_value ()) return surface_support.error ();
|
if (!surface_support.has_value ())
|
||||||
|
return detail::Error<SwapchainError>{ SwapchainError::failed_query_surface_support_details,
|
||||||
|
surface_support.error ().vk_result };
|
||||||
VkSurfaceFormatKHR surface_format =
|
VkSurfaceFormatKHR surface_format =
|
||||||
detail::find_surface_format (surface_support.value ().formats, info.desired_formats);
|
detail::find_surface_format (surface_support.value ().formats, info.desired_formats);
|
||||||
VkPresentModeKHR present_mode =
|
VkPresentModeKHR present_mode =
|
||||||
@ -879,11 +921,9 @@ detail::Expected<Swapchain, VkResult> SwapchainBuilder::build () {
|
|||||||
swapchain_create_info.imageArrayLayers = 1;
|
swapchain_create_info.imageArrayLayers = 1;
|
||||||
swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||||
|
|
||||||
QueueFamilies indices = find_queue_families (info.physical_device, info.surface);
|
uint32_t queue_family_indices[] = { info.graphics_queue_index, info.present_queue_index };
|
||||||
uint32_t queue_family_indices[] = { static_cast<uint32_t> (indices.graphics),
|
|
||||||
static_cast<uint32_t> (indices.present) };
|
|
||||||
|
|
||||||
if (indices.graphics != indices.present) {
|
if (info.graphics_queue_index != info.present_queue_index) {
|
||||||
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||||
swapchain_create_info.queueFamilyIndexCount = 2;
|
swapchain_create_info.queueFamilyIndexCount = 2;
|
||||||
swapchain_create_info.pQueueFamilyIndices = queue_family_indices;
|
swapchain_create_info.pQueueFamilyIndices = queue_family_indices;
|
||||||
@ -899,7 +939,7 @@ detail::Expected<Swapchain, VkResult> SwapchainBuilder::build () {
|
|||||||
Swapchain swapchain{};
|
Swapchain swapchain{};
|
||||||
VkResult res = vkCreateSwapchainKHR (info.device, &swapchain_create_info, nullptr, &swapchain.swapchain);
|
VkResult res = vkCreateSwapchainKHR (info.device, &swapchain_create_info, nullptr, &swapchain.swapchain);
|
||||||
if (res != VK_SUCCESS) {
|
if (res != VK_SUCCESS) {
|
||||||
return detail::Error{ res, "Failed to create swapchain" };
|
return detail::Error<SwapchainError>{ SwapchainError::failed_create_swapchain, res };
|
||||||
}
|
}
|
||||||
swapchain.device = info.device;
|
swapchain.device = info.device;
|
||||||
swapchain.image_format = surface_format.format;
|
swapchain.image_format = surface_format.format;
|
||||||
@ -908,22 +948,24 @@ detail::Expected<Swapchain, VkResult> SwapchainBuilder::build () {
|
|||||||
auto images = get_swapchain_images (swapchain);
|
auto images = get_swapchain_images (swapchain);
|
||||||
swapchain.image_count = images.value ().size ();
|
swapchain.image_count = images.value ().size ();
|
||||||
return swapchain;
|
return swapchain;
|
||||||
}
|
} // namespace vkb
|
||||||
detail::Expected<Swapchain, VkResult> SwapchainBuilder::recreate (Swapchain const& swapchain) {
|
detail::Expected<Swapchain, detail::Error<SwapchainError>> SwapchainBuilder::recreate (Swapchain const& swapchain) {
|
||||||
info.old_swapchain = swapchain.swapchain;
|
info.old_swapchain = swapchain.swapchain;
|
||||||
return build ();
|
return build ();
|
||||||
}
|
}
|
||||||
detail::Expected<std::vector<VkImage>, VkResult> get_swapchain_images (Swapchain const& swapchain) {
|
detail::Expected<std::vector<VkImage>, detail::Error<SwapchainError>> get_swapchain_images (
|
||||||
|
Swapchain const& swapchain) {
|
||||||
auto swapchain_images =
|
auto swapchain_images =
|
||||||
detail::get_vector<VkImage> (vkGetSwapchainImagesKHR, swapchain.device, swapchain.swapchain);
|
detail::get_vector<VkImage> (vkGetSwapchainImagesKHR, swapchain.device, swapchain.swapchain);
|
||||||
if (!swapchain_images) {
|
if (!swapchain_images) {
|
||||||
return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "Failed to get swapchain Images" };
|
return detail::Error<SwapchainError>{ SwapchainError::failed_get_swapchain_images,
|
||||||
|
swapchain_images.error () };
|
||||||
}
|
}
|
||||||
return swapchain_images.value ();
|
return swapchain_images.value ();
|
||||||
}
|
}
|
||||||
|
|
||||||
detail::Expected<std::vector<VkImageView>, VkResult> get_swapchain_image_views (
|
detail::Expected<std::vector<VkImageView>, detail::Error<SwapchainError>>
|
||||||
Swapchain const& swapchain, std::vector<VkImage> const& images) {
|
get_swapchain_image_views (Swapchain const& swapchain, std::vector<VkImage> const& images) {
|
||||||
std::vector<VkImageView> views{ swapchain.image_count };
|
std::vector<VkImageView> views{ swapchain.image_count };
|
||||||
|
|
||||||
for (size_t i = 0; i < swapchain.image_count; i++) {
|
for (size_t i = 0; i < swapchain.image_count; i++) {
|
||||||
@ -944,7 +986,7 @@ detail::Expected<std::vector<VkImageView>, VkResult> get_swapchain_image_views (
|
|||||||
|
|
||||||
VkResult res = vkCreateImageView (swapchain.device, &createInfo, nullptr, &views[i]);
|
VkResult res = vkCreateImageView (swapchain.device, &createInfo, nullptr, &views[i]);
|
||||||
if (res != VK_SUCCESS)
|
if (res != VK_SUCCESS)
|
||||||
return detail::Error{ VK_ERROR_INITIALIZATION_FAILED, "Failed to create image views" };
|
return detail::Error<SwapchainError>{ SwapchainError::failed_create_swapchain_image_views, res };
|
||||||
}
|
}
|
||||||
return views;
|
return views;
|
||||||
}
|
}
|
||||||
|
@ -11,33 +11,32 @@
|
|||||||
namespace vkb {
|
namespace vkb {
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
template <typename ErrorType> struct Error {
|
||||||
|
explicit Error (ErrorType type, VkResult result = VK_SUCCESS)
|
||||||
|
: type (type), vk_result (result) {}
|
||||||
|
|
||||||
enum class BootstrapErrorType : uint32_t {
|
ErrorType type;
|
||||||
|
VkResult vk_result; // optional error value if a vulkan call failed
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Error {
|
|
||||||
VkResult error_code;
|
|
||||||
const char* msg;
|
|
||||||
};
|
|
||||||
template <typename E, typename U> class Expected {
|
template <typename E, typename U> class Expected {
|
||||||
public:
|
public:
|
||||||
Expected (const E& expect) : m_expect{ expect }, m_init{ true } {}
|
Expected (const E& expect) : m_expect{ expect }, m_init{ true } {}
|
||||||
Expected (E&& expect) : m_expect{ std::move (expect) }, m_init{ true } {}
|
Expected (E&& expect) : m_expect{ std::move (expect) }, m_init{ true } {}
|
||||||
Expected (const Error& error) : m_error{ error }, m_init{ false } {}
|
Expected (const U& error) : m_error{ error }, m_init{ false } {}
|
||||||
Expected (Error&& error) : m_error{ std::move (error) }, m_init{ false } {}
|
Expected (U&& error) : m_error{ std::move (error) }, m_init{ false } {}
|
||||||
~Expected () { destroy (); }
|
~Expected () { destroy (); }
|
||||||
Expected (Expected const& expected) : m_init (expected.m_init) {
|
Expected (Expected const& expected) : m_init (expected.m_init) {
|
||||||
if (m_init)
|
if (m_init)
|
||||||
new (&m_expect) E{ expected.m_expect };
|
new (&m_expect) E{ expected.m_expect };
|
||||||
else
|
else
|
||||||
new (&m_error) Error{ expected.m_error };
|
new (&m_error) U{ expected.m_error };
|
||||||
}
|
}
|
||||||
Expected (Expected&& expected) : m_init (expected.m_init) {
|
Expected (Expected&& expected) : m_init (expected.m_init) {
|
||||||
if (m_init)
|
if (m_init)
|
||||||
new (&m_expect) E{ std::move (expected.m_expect) };
|
new (&m_expect) E{ std::move (expected.m_expect) };
|
||||||
else
|
else
|
||||||
new (&m_error) Error{ std::move (expected.m_error) };
|
new (&m_error) U{ std::move (expected.m_error) };
|
||||||
expected.destroy ();
|
expected.destroy ();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,16 +52,16 @@ template <typename E, typename U> class Expected {
|
|||||||
new (&m_expect) E{ std::move (expect) };
|
new (&m_expect) E{ std::move (expect) };
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Expected& operator= (const Error& error) {
|
Expected& operator= (const U& error) {
|
||||||
destroy ();
|
destroy ();
|
||||||
m_init = false;
|
m_init = false;
|
||||||
new (&m_error) Error{ error };
|
new (&m_error) U{ error };
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
Expected& operator= (Error&& error) {
|
Expected& operator= (U&& error) {
|
||||||
destroy ();
|
destroy ();
|
||||||
m_init = false;
|
m_init = false;
|
||||||
new (&m_error) Error{ std::move (error) };
|
new (&m_error) U{ std::move (error) };
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
// clang-format off
|
// clang-format off
|
||||||
@ -75,10 +74,10 @@ template <typename E, typename U> class Expected {
|
|||||||
E& value () & { assert (m_init); return m_expect; }
|
E& value () & { assert (m_init); return m_expect; }
|
||||||
const E&& value () const&& { assert (m_init); return std::move (m_expect); }
|
const E&& value () const&& { assert (m_init); return std::move (m_expect); }
|
||||||
E&& value () && { assert (m_init); return std::move (m_expect); }
|
E&& value () && { assert (m_init); return std::move (m_expect); }
|
||||||
const Error& error () const& { assert (!m_init); return m_error; }
|
const U& error () const& { assert (!m_init); return m_error; }
|
||||||
Error& error () & { assert (!m_init); return m_error; }
|
U& error () & { assert (!m_init); return m_error; }
|
||||||
const Error&& error () const&& { assert (!m_init); return std::move (m_error); }
|
const U&& error () const&& { assert (!m_init); return std::move (m_error); }
|
||||||
Error&& error () && { assert (!m_init); return std::move (m_error); }
|
U&& error () && { assert (!m_init); return std::move (m_error); }
|
||||||
// clang-format on
|
// clang-format on
|
||||||
bool has_value () const { return m_init; }
|
bool has_value () const { return m_init; }
|
||||||
explicit operator bool () const { return m_init; }
|
explicit operator bool () const { return m_init; }
|
||||||
@ -88,19 +87,25 @@ template <typename E, typename U> class Expected {
|
|||||||
if (m_init)
|
if (m_init)
|
||||||
m_expect.~E ();
|
m_expect.~E ();
|
||||||
else
|
else
|
||||||
m_error.~Error ();
|
m_error.~U ();
|
||||||
}
|
}
|
||||||
union {
|
union {
|
||||||
E m_expect;
|
E m_expect;
|
||||||
Error m_error;
|
U m_error;
|
||||||
};
|
};
|
||||||
bool m_init;
|
bool m_init;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TODO implement operator == and operator != as friend or global */
|
/* TODO implement operator == and operator != as friend or global */
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
|
enum class InstanceError {
|
||||||
|
failed_create_instance,
|
||||||
|
failed_create_debug_messenger,
|
||||||
|
requested_layers_not_present,
|
||||||
|
requested_extensions_not_present
|
||||||
|
};
|
||||||
|
|
||||||
class InstanceBuilder;
|
class InstanceBuilder;
|
||||||
class PhysicalDeviceSelector;
|
class PhysicalDeviceSelector;
|
||||||
|
|
||||||
@ -121,7 +126,7 @@ void destroy_instance (Instance instance); // release instance resources
|
|||||||
|
|
||||||
class InstanceBuilder {
|
class InstanceBuilder {
|
||||||
public:
|
public:
|
||||||
detail::Expected<Instance, VkResult> build (); // use builder pattern
|
detail::Expected<Instance, detail::Error<InstanceError>> build (); // use builder pattern
|
||||||
|
|
||||||
InstanceBuilder& set_app_name (std::string app_name);
|
InstanceBuilder& set_app_name (std::string app_name);
|
||||||
InstanceBuilder& set_engine_name (std::string engine_name);
|
InstanceBuilder& set_engine_name (std::string engine_name);
|
||||||
@ -200,6 +205,13 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL default_debug_callback (VkDebugUtilsMessag
|
|||||||
void* pUserData);
|
void* pUserData);
|
||||||
|
|
||||||
// ---- Physical Device ---- //
|
// ---- Physical Device ---- //
|
||||||
|
enum class PhysicalDeviceError {
|
||||||
|
failed_enumerate_physical_devices,
|
||||||
|
no_physical_devices_found,
|
||||||
|
no_suitable_device,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
class PhysicalDeviceSelector;
|
class PhysicalDeviceSelector;
|
||||||
class DeviceBuilder;
|
class DeviceBuilder;
|
||||||
|
|
||||||
@ -218,7 +230,7 @@ struct PhysicalDeviceSelector {
|
|||||||
public:
|
public:
|
||||||
PhysicalDeviceSelector (Instance const& instance);
|
PhysicalDeviceSelector (Instance const& instance);
|
||||||
|
|
||||||
detail::Expected<PhysicalDevice, VkResult> select ();
|
detail::Expected<PhysicalDevice, detail::Error<PhysicalDeviceError>> select ();
|
||||||
|
|
||||||
PhysicalDeviceSelector& set_surface (VkSurfaceKHR instance);
|
PhysicalDeviceSelector& set_surface (VkSurfaceKHR instance);
|
||||||
|
|
||||||
@ -283,6 +295,9 @@ struct PhysicalDeviceSelector {
|
|||||||
enum class QueueType : uint8_t { primary, compute, transfer };
|
enum class QueueType : uint8_t { primary, compute, transfer };
|
||||||
|
|
||||||
// ---- Device ---- //
|
// ---- Device ---- //
|
||||||
|
enum class DeviceError {
|
||||||
|
failed_create_device,
|
||||||
|
};
|
||||||
|
|
||||||
struct Device {
|
struct Device {
|
||||||
VkDevice device = VK_NULL_HANDLE;
|
VkDevice device = VK_NULL_HANDLE;
|
||||||
@ -296,13 +311,13 @@ void destroy_device (Device device);
|
|||||||
class DeviceBuilder {
|
class DeviceBuilder {
|
||||||
public:
|
public:
|
||||||
DeviceBuilder (PhysicalDevice device);
|
DeviceBuilder (PhysicalDevice device);
|
||||||
detail::Expected<Device, VkResult> build ();
|
detail::Expected<Device, detail::Error<DeviceError>> build ();
|
||||||
|
|
||||||
template <typename T> DeviceBuilder& add_pNext (T* structure);
|
template <typename T> DeviceBuilder& add_pNext (T* structure);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct DeviceInfo {
|
struct DeviceInfo {
|
||||||
VkDeviceCreateFlags flags;
|
VkDeviceCreateFlags flags = 0;
|
||||||
std::vector<VkBaseOutStructure*> pNext_chain;
|
std::vector<VkBaseOutStructure*> pNext_chain;
|
||||||
PhysicalDevice physical_device;
|
PhysicalDevice physical_device;
|
||||||
std::vector<std::string> extensions;
|
std::vector<std::string> extensions;
|
||||||
@ -311,14 +326,34 @@ class DeviceBuilder {
|
|||||||
|
|
||||||
// ---- Getting Queues ---- //
|
// ---- Getting Queues ---- //
|
||||||
|
|
||||||
detail::Expected<VkQueue, VkResult> get_present_queue (Device const& device);
|
enum class QueueError {
|
||||||
detail::Expected<VkQueue, VkResult> get_graphics_queue (Device const& device);
|
present_unavailable,
|
||||||
detail::Expected<VkQueue, VkResult> get_compute_queue (Device const& device);
|
compute_unavailable,
|
||||||
detail::Expected<VkQueue, VkResult> get_transfer_queue (Device const& device);
|
transfer_unavailable,
|
||||||
|
queue_index_out_of_range,
|
||||||
|
invalid_queue_family_index
|
||||||
|
};
|
||||||
|
|
||||||
|
detail::Expected<uint32_t, detail::Error<QueueError>> get_present_queue_index (Device const& device);
|
||||||
|
detail::Expected<uint32_t, detail::Error<QueueError>> get_graphics_queue_index (Device const& device);
|
||||||
|
detail::Expected<uint32_t, detail::Error<QueueError>> get_compute_queue_index (Device const& device);
|
||||||
|
detail::Expected<uint32_t, detail::Error<QueueError>> get_transfer_queue_index (Device const& device);
|
||||||
|
|
||||||
|
detail::Expected<VkQueue, detail::Error<QueueError>> get_present_queue (Device const& device);
|
||||||
|
detail::Expected<VkQueue, detail::Error<QueueError>> get_graphics_queue (Device const& device);
|
||||||
|
detail::Expected<VkQueue, detail::Error<QueueError>> get_compute_queue (Device const& device);
|
||||||
|
detail::Expected<VkQueue, detail::Error<QueueError>> get_transfer_queue (Device const& device);
|
||||||
|
|
||||||
|
|
||||||
// ---- Swapchain ---- //
|
// ---- Swapchain ---- //
|
||||||
|
|
||||||
|
enum class SwapchainError {
|
||||||
|
failed_query_surface_support_details,
|
||||||
|
failed_create_swapchain,
|
||||||
|
failed_get_swapchain_images,
|
||||||
|
failed_create_swapchain_image_views,
|
||||||
|
};
|
||||||
|
|
||||||
struct Swapchain {
|
struct Swapchain {
|
||||||
VkDevice device = VK_NULL_HANDLE;
|
VkDevice device = VK_NULL_HANDLE;
|
||||||
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
|
VkSwapchainKHR swapchain = VK_NULL_HANDLE;
|
||||||
@ -329,17 +364,22 @@ struct Swapchain {
|
|||||||
|
|
||||||
void destroy_swapchain (Swapchain const& swapchain);
|
void destroy_swapchain (Swapchain const& swapchain);
|
||||||
|
|
||||||
detail::Expected<std::vector<VkImage>, VkResult> get_swapchain_images (Swapchain const& swapchain);
|
detail::Expected<std::vector<VkImage>, detail::Error<SwapchainError>> get_swapchain_images (
|
||||||
detail::Expected<std::vector<VkImageView>, VkResult> get_swapchain_image_views (
|
Swapchain const& swapchain);
|
||||||
Swapchain const& swapchain, std::vector<VkImage> const& images);
|
detail::Expected<std::vector<VkImageView>, detail::Error<SwapchainError>>
|
||||||
|
get_swapchain_image_views (Swapchain const& swapchain, std::vector<VkImage> const& images);
|
||||||
|
|
||||||
class SwapchainBuilder {
|
class SwapchainBuilder {
|
||||||
public:
|
public:
|
||||||
SwapchainBuilder (Device const& device);
|
SwapchainBuilder (Device const& device);
|
||||||
SwapchainBuilder (VkPhysicalDevice const physical_device, VkDevice const device, VkSurfaceKHR const surface);
|
SwapchainBuilder (VkPhysicalDevice const physical_device,
|
||||||
|
VkDevice const device,
|
||||||
|
VkSurfaceKHR const surface,
|
||||||
|
uint32_t graphics_queue_index,
|
||||||
|
uint32_t present_queue_index);
|
||||||
|
|
||||||
detail::Expected<Swapchain, VkResult> build ();
|
detail::Expected<Swapchain, detail::Error<SwapchainError>> build ();
|
||||||
detail::Expected<Swapchain, VkResult> recreate (Swapchain const& swapchain);
|
detail::Expected<Swapchain, detail::Error<SwapchainError>> recreate (Swapchain const& swapchain);
|
||||||
|
|
||||||
// SwapchainBuilder& set_desired_image_count (uint32_t count);
|
// SwapchainBuilder& set_desired_image_count (uint32_t count);
|
||||||
// SwapchainBuilder& set_maximum_image_count (uint32_t count);
|
// SwapchainBuilder& set_maximum_image_count (uint32_t count);
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
int test_happy_path ()
|
int test_happy_path () {
|
||||||
{
|
|
||||||
auto window = create_window_glfw ();
|
auto window = create_window_glfw ();
|
||||||
|
|
||||||
vkb::InstanceBuilder instance_builder;
|
vkb::InstanceBuilder instance_builder;
|
||||||
auto instance_ret = instance_builder.set_default_debug_messenger ().build ();
|
auto instance_ret = instance_builder.set_default_debug_messenger ().build ();
|
||||||
if (!instance_ret)
|
if (!instance_ret) {
|
||||||
{
|
std::cout << static_cast<uint32_t> (instance_ret.error ().type) << "\n";
|
||||||
std::cout << instance_ret.error ().msg << "\n";
|
|
||||||
return -1; // couldn't make instance
|
return -1; // couldn't make instance
|
||||||
}
|
}
|
||||||
vkb::Instance instance = instance_ret.value ();
|
vkb::Instance instance = instance_ret.value ();
|
||||||
@ -37,8 +35,7 @@ int test_happy_path ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int test_instance_basic ()
|
int test_instance_basic () {
|
||||||
{
|
|
||||||
|
|
||||||
vkb::InstanceBuilder builder;
|
vkb::InstanceBuilder builder;
|
||||||
|
|
||||||
@ -56,15 +53,13 @@ int test_instance_basic ()
|
|||||||
})
|
})
|
||||||
.set_api_version (1, 2, 111)
|
.set_api_version (1, 2, 111)
|
||||||
.build ();
|
.build ();
|
||||||
if (!instance_ret.has_value ())
|
if (!instance_ret.has_value ()) {
|
||||||
{
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_instance_headless ()
|
int test_instance_headless () {
|
||||||
{
|
|
||||||
|
|
||||||
vkb::InstanceBuilder builder;
|
vkb::InstanceBuilder builder;
|
||||||
|
|
||||||
@ -76,15 +71,13 @@ int test_instance_headless ()
|
|||||||
.set_api_version (1, 0, 34)
|
.set_api_version (1, 0, 34)
|
||||||
.set_default_debug_messenger ()
|
.set_default_debug_messenger ()
|
||||||
.build ();
|
.build ();
|
||||||
if (!instance_ret.has_value ())
|
if (!instance_ret.has_value ()) {
|
||||||
{
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_physical_device_selection ()
|
int test_physical_device_selection () {
|
||||||
{
|
|
||||||
vkb::InstanceBuilder instance_builder;
|
vkb::InstanceBuilder instance_builder;
|
||||||
auto instance_ret = instance_builder.set_default_debug_messenger ().build ();
|
auto instance_ret = instance_builder.set_default_debug_messenger ().build ();
|
||||||
auto instance = instance_ret.value ();
|
auto instance = instance_ret.value ();
|
||||||
@ -98,8 +91,7 @@ int test_physical_device_selection ()
|
|||||||
.set_minimum_version (1, 0)
|
.set_minimum_version (1, 0)
|
||||||
.set_desired_version (1, 1)
|
.set_desired_version (1, 1)
|
||||||
.select ();
|
.select ();
|
||||||
if (!phys_dev_ret.has_value ())
|
if (!phys_dev_ret.has_value ()) {
|
||||||
{
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
vkb::destroy_instance (instance);
|
vkb::destroy_instance (instance);
|
||||||
@ -107,8 +99,7 @@ int test_physical_device_selection ()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int test_device_creation ()
|
int test_device_creation () {
|
||||||
{
|
|
||||||
vkb::InstanceBuilder instance_builder;
|
vkb::InstanceBuilder instance_builder;
|
||||||
auto instance_ret = instance_builder.set_default_debug_messenger ().build ();
|
auto instance_ret = instance_builder.set_default_debug_messenger ().build ();
|
||||||
auto instance = instance_ret.value ();
|
auto instance = instance_ret.value ();
|
||||||
@ -121,9 +112,8 @@ int test_device_creation ()
|
|||||||
|
|
||||||
vkb::DeviceBuilder device_builder (phys_dev);
|
vkb::DeviceBuilder device_builder (phys_dev);
|
||||||
auto dev_ret = device_builder.build ();
|
auto dev_ret = device_builder.build ();
|
||||||
if (!dev_ret.has_value ())
|
if (!dev_ret.has_value ()) {
|
||||||
{
|
printf ("couldn't create device %i\n", static_cast<uint32_t> (dev_ret.error ().type));
|
||||||
printf ("%s\n", dev_ret.error ().msg);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,8 +123,7 @@ int test_device_creation ()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main ()
|
int main () {
|
||||||
{
|
|
||||||
printf ("happy path\n");
|
printf ("happy path\n");
|
||||||
test_happy_path ();
|
test_happy_path ();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user