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