From 3e56c80cad69b0777fd684aa0e7808af8b4199b7 Mon Sep 17 00:00:00 2001 From: Simon Oehrl <simon.oehrl@rwth-aachen.de> Date: Thu, 5 Jan 2023 14:43:25 +0100 Subject: [PATCH] Implement screen-tearing test --- CMakeLists.txt | 2 +- liblava/app/app.cpp | 6 ++ src/main.cpp | 198 +++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 202 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6a2c065..fc9375a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -666,7 +666,7 @@ option(LIBLAVA_TEMPLATE "Enable Template" TRUE) if(LIBLAVA_TEMPLATE) message("========================================================================") - set(LIBLAVA_TEMPLATE_NAME "template" CACHE STRING "Name of template using liblava") + set(LIBLAVA_TEMPLATE_NAME "screen-tearer" CACHE STRING "Name of template using liblava") message("> ${LIBLAVA_TEMPLATE_NAME}") diff --git a/liblava/app/app.cpp b/liblava/app/app.cpp index be9b7ab..ad656a3 100644 --- a/liblava/app/app.cpp +++ b/liblava/app/app.cpp @@ -150,6 +150,12 @@ bool app::setup() { update(); render(); + + bool fullscreen = false; + cmd_line({ "-fs", "--fullscreen" }) >> fullscreen; + spdlog::info("Fullscreen: {}", fullscreen); + window.set_fullscreen(fullscreen); + add_run_end([&]() { camera.destroy(); diff --git a/src/main.cpp b/src/main.cpp index c065c6f..060ab6e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,20 +1,212 @@ /** - * @file main.cpp - * @brief Template + * @file liblava-demo/shapes.cpp + * @brief Shapes demo * @authors Lava Block OÜ and contributors * @copyright Copyright (c) 2018-present, MIT License */ #include <imgui.h> +#include <GLFW/glfw3.h> #include <liblava/lava.hpp> using namespace lava; +std::string get_video_mode_string(const GLFWvidmode& mode) { + return fmt::format("{}x{}@{}Hz Bit Depth(R/G/B): {}/{}/{}", mode.width, mode.height, mode.refreshRate, mode.redBits, mode.greenBits, mode.blueBits); +} + //----------------------------------------------------------------------------- int main(int argc, char* argv[]) { - app app("template", { argc, argv }); + app app("lava shapes", { argc, argv }); + if (!app.setup()) return error::not_ready; + + int monitor_count; + GLFWmonitor** monitors = glfwGetMonitors(&monitor_count); + + spdlog::info("------"); + for (int i = 0; i < monitor_count; ++i) { + const auto monitor = monitors[i]; + spdlog::info("Monitor {}", glfwGetMonitorName(monitor)); + const GLFWvidmode* mode = glfwGetVideoMode(monitor); + spdlog::info("Active mode: {}", get_video_mode_string(*mode)); + int video_mode_count; + const GLFWvidmode* modes = glfwGetVideoModes(monitor, &video_mode_count); + spdlog::info("Supported video modes:"); + for (int j = 0; j < video_mode_count; ++j) { + spdlog::info("- {}", get_video_mode_string(modes[j])); + } + spdlog::info("------"); + } + +// app.window.set_fullscreen(true); + + // Initialize camera + app.camera.position = v3(0.f, -2.f, 8.f); + app.camera.rotation = v3(0.f, 0.f, 0.f); // Degrees + + // All shapes will share the same world-space matrix in this example + mat4 world_matrix = glm::identity<mat4>(); + // world_matrix = glm::translate(world_matrix, v3(0, 1, 0)); + world_matrix = glm::scale(world_matrix, v3(1, 50, 1)); + + v3 rotation_vector = v3{ 0, 0, 0 }; + + buffer world_matrix_buffer; + if (!world_matrix_buffer.create_mapped(app.device, &world_matrix, sizeof(world_matrix), + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)) + return error::create_failed; + + // All shapes will share the same rotation value + buffer rotation_buffer; + if (!rotation_buffer.create_mapped(app.device, &rotation_vector, sizeof(rotation_vector), + VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT)) + return error::create_failed; + + mesh::ptr quad; + quad = create_mesh(app.device, mesh_type::quad); + for (auto& vertex : quad->get_vertices()) { + vertex.color = v4(1.0, 1.0, 1.0, 1.0); + } + + if (!quad) + return error::create_failed; + quad->reload(); + + // A descriptor is needed for representing the world-space matrix + descriptor::ptr descriptor; + descriptor::pool::ptr descriptor_pool; + VkDescriptorSet descriptor_set = VK_NULL_HANDLE; + + graphics_pipeline::ptr pipeline; + pipeline_layout::ptr layout; + + app.on_create = [&]() { + pipeline = make_graphics_pipeline(app.device); + pipeline->add_color_blend_attachment(); + pipeline->set_depth_test_and_write(); + pipeline->set_depth_compare_op(VK_COMPARE_OP_LESS_OR_EQUAL); + + // All shapes use the same simple shaders + if (!pipeline->add_shader(file_data("shapes/vertex.spirv"), VK_SHADER_STAGE_VERTEX_BIT)) + return false; + if (!pipeline->add_shader(file_data("shapes/fragment.spirv"), VK_SHADER_STAGE_FRAGMENT_BIT)) + return false; + + pipeline->set_vertex_input_binding({ 0, sizeof(vertex), VK_VERTEX_INPUT_RATE_VERTEX }); + // Only send position and color to shaders for this demo + // TODO: Update this comment + pipeline->set_vertex_input_attributes({ + { 0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(vertex, position) }, + { 1, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(vertex, color) }, + { 2, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(vertex, normal) }, + }); + + // Descriptor sets must be made to transfer the shapes' world matrix and the camera's + // view matrix to the physical device + descriptor = make_descriptor(); + descriptor->add_binding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + VK_SHADER_STAGE_VERTEX_BIT); // View matrix + descriptor->add_binding(1, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + VK_SHADER_STAGE_VERTEX_BIT); // World matrix + descriptor->add_binding(2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + VK_SHADER_STAGE_VERTEX_BIT); // Rotation vector + if (!descriptor->create(app.device)) + return false; + + descriptor_pool = make_descriptor_pool(); + if (!descriptor_pool->create(app.device, { { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3 } })) + return false; + + layout = make_pipeline_layout(); + layout->add(descriptor); + if (!layout->create(app.device)) + return false; + + pipeline->set_layout(layout); + + descriptor_set = descriptor->allocate(descriptor_pool->get()); + VkWriteDescriptorSet const write_desc_ubo_camera{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descriptor_set, + .dstBinding = 0, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pBufferInfo = app.camera.get_descriptor_info(), + }; + VkWriteDescriptorSet const write_desc_ubo_world{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descriptor_set, + .dstBinding = 1, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pBufferInfo = world_matrix_buffer.get_descriptor_info(), + }; + VkWriteDescriptorSet const write_desc_ubo_rotation{ + .sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descriptor_set, + .dstBinding = 2, + .descriptorCount = 1, + .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pBufferInfo = rotation_buffer.get_descriptor_info(), + }; + app.device->vkUpdateDescriptorSets({ write_desc_ubo_camera, write_desc_ubo_world, + write_desc_ubo_rotation }); + + render_pass::ptr render_pass = app.shading.get_pass(); + + if (!pipeline->create(render_pass->get())) + return false; + + // Push this render pass to the pipeline + render_pass->add_front(pipeline); + + pipeline->on_process = [&](VkCommandBuffer cmd_buf) { + layout->bind(cmd_buf, descriptor_set); + quad->bind_draw(cmd_buf); + return true; + }; + + return true; + }; + + app.on_destroy = [&]() { + descriptor->free(descriptor_set, descriptor_pool->get()); + + descriptor_pool->destroy(); + descriptor->destroy(); + + pipeline->destroy(); + layout->destroy(); + }; + + app.imgui.on_draw = [&]() { + ImGui::Begin(app.get_name()); + + app.draw_about(); + + ImGui::End(); + }; + + app.on_update = [&](delta dt) { + // rotation_vector += v3{ 0, 10.f, 0 } * dt; + // memcpy(as_ptr(rotation_buffer.get_mapped_data()), &rotation_vector, sizeof(rotation_vector)); + app.camera.position.x += 50 * dt; + while (app.camera.position.x > 5) { + app.camera.position.x -= 10; + } + + if (app.camera.activated()) + app.camera.update_view(to_dt(app.run_time.delta), app.input.get_mouse_position()); + + return true; + }; + + app.add_run_end([&]() { + quad->destroy(); + }); + return app.run(); } -- GitLab