diff options
Diffstat (limited to 'src/engine.cpp')
| -rw-r--r-- | src/engine.cpp | 158 |
1 files changed, 147 insertions, 11 deletions
diff --git a/src/engine.cpp b/src/engine.cpp index 84e62a5..142a8e1 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -161,7 +161,7 @@ static void scene_main(Renderer<FrameBuffer>& renderer, const Matrix4& final_tra while (cont) { renderer.clear(); auto pre_final_mat = final_transform_mat - * scene.camera.to_mat4(static_cast<float>(renderer.height()) / static_cast<float>(renderer.width()), .5f, 12.f); + * scene.camera.to_mat4(static_cast<float>(renderer.width()) / static_cast<float>(renderer.height()), .5f, 12.f); for (const auto& obj : scene.objs) { auto obj_mat = obj.transform.to_mat4(); auto final_mat = pre_final_mat * obj_mat; @@ -297,8 +297,8 @@ static int main_term() { } #endif -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 +#define SCREEN_WIDTH 800 +#define SCREEN_HEIGHT 600 static const std::vector<const char*> validation_layers = { "VK_LAYER_KHRONOS_validation", @@ -1143,6 +1143,31 @@ static int main_graphical() { recreate_swapchain(); + // create descriptor set layout + auto descriptor_set_layout = [&]() { + VkDescriptorSetLayoutBinding descriptor_set_layout_binding { + .binding = 0, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1, + .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, + .pImmutableSamplers = {}, + }; + VkDescriptorSetLayoutCreateInfo descriptor_set_layout_ci { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = {}, + .bindingCount = 1, + .pBindings = &descriptor_set_layout_binding, + }; + VkDescriptorSetLayout descriptor_set_layout; + if (VkResult res = vkCreateDescriptorSetLayout(device, &descriptor_set_layout_ci, nullptr, &descriptor_set_layout); res != VK_SUCCESS) { + std::cerr << "failed to create descriptor set layout, error code: " << string_VkResult(res) << std::endl; + std::exit(EXIT_FAILURE); + } + return descriptor_set_layout; + }(); + + // create pipeline auto [pl_layout, graphics_pl] = [&]() { // reading shader file auto shader_module = [&]() { @@ -1248,7 +1273,7 @@ static int main_graphical() { .rasterizerDiscardEnable = VK_FALSE, .polygonMode = VK_POLYGON_MODE_FILL, .cullMode = VK_CULL_MODE_BACK_BIT, - .frontFace = VK_FRONT_FACE_CLOCKWISE, + .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, .depthBiasEnable = VK_FALSE, .depthBiasConstantFactor = {}, .depthBiasClamp = {}, @@ -1299,8 +1324,8 @@ static int main_graphical() { .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, .pNext = nullptr, .flags = {}, - .setLayoutCount = 0, - .pSetLayouts = {}, + .setLayoutCount = 1, + .pSetLayouts = &descriptor_set_layout, .pushConstantRangeCount = 0, .pPushConstantRanges = {}, }; @@ -1446,6 +1471,91 @@ static int main_graphical() { return std::tuple { index_buf, index_buf_device_mem }; }(); + // create uniform buffers + auto [uniform_bufs, uniform_buf_device_mems, uniform_buf_mems] = [&]() { + constexpr VkDeviceSize uniform_buf_size = sizeof(engine::vk::UniformBufferObject); + std::array<VkBuffer, max_frames_in_flight> uniform_bufs; + std::array<VkDeviceMemory, max_frames_in_flight> uniform_buf_device_mems; + std::array<void*, max_frames_in_flight> uniform_buf_mems; + for (size_t i = 0; i < max_frames_in_flight; i++) { + std::tie(uniform_bufs[i], uniform_buf_device_mems[i]) = create_buf(physical_device, device, uniform_buf_size, + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + if (VkResult res = vkMapMemory(device, uniform_buf_device_mems[i], 0, uniform_buf_size, 0, &uniform_buf_mems[i]); res != VK_SUCCESS) { + std::cerr << "failed to map uniform buffer #" << i << " memory, error code: " << string_VkResult(res) << std::endl; + std::exit(EXIT_FAILURE); + } + } + return std::tuple { uniform_bufs, uniform_buf_device_mems, uniform_buf_mems }; + }(); + + // create descriptor pool + auto descriptor_pool = [&]() { + VkDescriptorPoolSize descriptor_pool_size { + .type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = max_frames_in_flight, + }; + VkDescriptorPoolCreateInfo descriptor_pool_ci { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO, + .pNext = nullptr, + // TODO: right now we do not touch descriptor sets after they've been created, so + // setting VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT is useless + .flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT, + .maxSets = max_frames_in_flight, + .poolSizeCount = 1, + .pPoolSizes = &descriptor_pool_size, + }; + VkDescriptorPool descriptor_pool; + if (VkResult res = vkCreateDescriptorPool(device, &descriptor_pool_ci, nullptr, &descriptor_pool); res != VK_SUCCESS) { + std::cerr << "failed to create descriptor pool, error code: " << string_VkResult(res) << std::endl; + std::exit(EXIT_FAILURE); + } + return descriptor_pool; + }(); + + // create descriptor sets + auto descriptor_sets = [&]() { + std::array<VkDescriptorSetLayout, max_frames_in_flight> layouts; + layouts.fill(descriptor_set_layout); + VkDescriptorSetAllocateInfo descriptor_set_ai { + .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO, + .pNext = nullptr, + .descriptorPool = descriptor_pool, + .descriptorSetCount = static_cast<uint32_t>(layouts.size()), + .pSetLayouts = layouts.data(), + }; + std::array<VkDescriptorSet, max_frames_in_flight> descriptor_sets; + if (VkResult res = vkAllocateDescriptorSets(device, &descriptor_set_ai, descriptor_sets.data()); res != VK_SUCCESS) { + std::cerr << "failed to allocate descriptor sets, error code: " << string_VkResult(res) << std::endl; + std::exit(EXIT_FAILURE); + } + std::array<VkDescriptorBufferInfo, max_frames_in_flight> descriptor_buffer_infos; + std::array<VkWriteDescriptorSet, max_frames_in_flight> write_descriptor_sets; + for (size_t i = 0; i < max_frames_in_flight; i++) { + descriptor_buffer_infos[i] = VkDescriptorBufferInfo { + .buffer = uniform_bufs[i], + .offset = 0, + .range = sizeof(engine::vk::UniformBufferObject), + }; + write_descriptor_sets[i] = VkWriteDescriptorSet { + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .pNext = nullptr, + .dstSet = descriptor_sets[i], + .dstBinding = 0, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pImageInfo = {}, + .pBufferInfo = &descriptor_buffer_infos[i], + .pTexelBufferView = {}, + }; + } + // TODO: maybe we should call this function for each descriptor sets, which I would find + // weird by the fact that it takes an array as an argument, but IDK + vkUpdateDescriptorSets(device, static_cast<uint32_t>(write_descriptor_sets.size()), write_descriptor_sets.data(), 0, nullptr); + return descriptor_sets; + }(); + // create command buffers auto cmd_bufs = [&]() { VkCommandBufferAllocateInfo cmd_buf_ai { @@ -1548,7 +1658,8 @@ static int main_graphical() { } std::cout << " ]" << std::endl; - auto last_time = std::chrono::system_clock::now(); + auto start_time = std::chrono::high_resolution_clock::now(); + auto last_time = start_time; uint32_t frame_idx = 0; @@ -1556,12 +1667,13 @@ static int main_graphical() { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); - auto cur_time = std::chrono::system_clock::now(); - auto ellapsed_time = cur_time - last_time; + auto cur_time = std::chrono::high_resolution_clock::now(); + float ellapsed_time = std::chrono::duration<float, std::chrono::seconds::period>(cur_time - last_time).count(); last_time = cur_time; + float time = std::chrono::duration<float, std::chrono::seconds::period>(cur_time - start_time).count(); if (show_fps) - std::cout << "\rfps: " << (1'000'000'000. / static_cast<double>(ellapsed_time.count())); + std::cout << "\rfps: " << (1.f / ellapsed_time); if (VkResult res = vkWaitForFences(device, 1, &fences_in_flight[frame_idx], VK_TRUE, std::numeric_limits<uint64_t>::max()); res != VK_SUCCESS) { std::cerr << "failed to wait for draw fence, error code: " << string_VkResult(res) << std::endl; @@ -1585,6 +1697,21 @@ static int main_graphical() { } } + // update uniform buffer + { + // TODO: should use push constants + // TODO: we shouldn't have to transpose, we could change the Matrix4 implementation to + // make all operation on transpose, which wouldn't change anything for the software + // renderer + engine::vk::UniformBufferObject ubo { + .model = Matrix4::rot_z(time * PI / 2.f).transpose(), + .view = Matrix4::look_at(Vector3(2.f, 2.f, 2.f), Vector3(0.f, 0.f, 0.f), Vector3(0.f, 0.f, 1.f)).transpose(), + .proj = Matrix4::perspective(PI / 4.f, static_cast<float>(swapchain_extent.width) / static_cast<float>(swapchain_extent.height), .1f, 10.f).transpose(), + }; + memcpy(uniform_buf_mems[frame_idx], &ubo, sizeof(engine::vk::UniformBufferObject)); + } + + // implicit command buffer reset // record command buffer { VkCommandBufferBeginInfo cmd_buf_bi { @@ -1665,6 +1792,7 @@ static int main_graphical() { vkCmdBindVertexBuffers(cmd_bufs[frame_idx], 0, 1, &vertex_buf, &vertex_buf_offset); vkCmdBindIndexBuffer(cmd_bufs[frame_idx], index_buf, 0, VK_INDEX_TYPE_UINT16); + vkCmdBindDescriptorSets(cmd_bufs[frame_idx], VK_PIPELINE_BIND_POINT_GRAPHICS, pl_layout, 0, 1, &descriptor_sets[frame_idx], 0, nullptr); vkCmdDrawIndexed(cmd_bufs[frame_idx], static_cast<uint32_t>(indices.size()), 1, 0, 0, 0); vkCmdEndRendering(cmd_bufs[frame_idx]); @@ -1742,14 +1870,22 @@ static int main_graphical() { vkDestroySemaphore(device, *it_sem, nullptr); for (auto it_sem = sems_present_complete.rbegin(); it_sem != sems_present_complete.rend(); ++it_sem) vkDestroySemaphore(device, *it_sem, nullptr); + vkDestroyDescriptorPool(device, descriptor_pool, nullptr); + for (size_t i = max_frames_in_flight; i > 0; i--) { + vkUnmapMemory(device, uniform_buf_device_mems[i - 1]); + vkFreeMemory(device, uniform_buf_device_mems[i - 1], nullptr); + vkDestroyBuffer(device, uniform_bufs[i - 1], nullptr); + } vkFreeMemory(device, index_buf_device_mem, nullptr); vkDestroyBuffer(device, index_buf, nullptr); vkFreeMemory(device, vertex_buf_device_mem, nullptr); vkDestroyBuffer(device, vertex_buf, nullptr); // no need to free cmd_buf because destroying the command pool will vkDestroyCommandPool(device, cmd_pool, nullptr); - vkDestroyPipeline(device, graphics_pl, nullptr); + // no need to free descriptor_sets because destroying the descriptor pool will + vkDestroyDescriptorSetLayout(device, descriptor_set_layout, nullptr); vkDestroyPipelineLayout(device, pl_layout, nullptr); + vkDestroyPipeline(device, graphics_pl, nullptr); destroy_swapchain(); vkDestroySurfaceKHR(instance, surface, nullptr); vkDestroyDevice(device, nullptr); |
