1/*
2 * Copyright (C) 2016 Google, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23#ifndef SMOKE_H
24#define SMOKE_H
25
26#include <condition_variable>
27#include <memory>
28#include <mutex>
29#include <string>
30#include <thread>
31#include <vector>
32
33#include <vulkan/vulkan.h>
34#include <glm/glm.hpp>
35
36#include "Simulation.h"
37#include "Game.h"
38
39class Meshes;
40
41class Smoke : public Game {
42public:
43    Smoke(const std::vector<std::string> &args);
44    ~Smoke();
45
46    void attach_shell(Shell &sh);
47    void detach_shell();
48
49    void attach_swapchain();
50    void detach_swapchain();
51
52    void on_key(Key key);
53    void on_tick();
54
55    void on_frame(float frame_pred);
56
57private:
58    class Worker {
59    public:
60        Worker(Smoke &smoke, int index, int object_begin, int object_end);
61
62        void start();
63        void stop();
64        void update_simulation();
65        void draw_objects(VkFramebuffer fb);
66        void wait_idle();
67
68        Smoke &smoke_;
69
70        const int index_;
71        const int object_begin_;
72        const int object_end_;
73
74        const float tick_interval_;
75
76        VkFramebuffer fb_;
77
78    private:
79        enum State {
80            INIT,
81            IDLE,
82            STEP,
83            DRAW,
84        };
85
86        void update_loop();
87
88        static void thread_loop(Worker *worker) { worker->update_loop(); }
89
90        std::thread thread_;
91        std::mutex mutex_;
92        std::condition_variable state_cv_;
93        State state_;
94    };
95
96    struct Camera {
97        glm::vec3 eye_pos;
98        glm::mat4 view_projection;
99
100        Camera(float eye) : eye_pos(eye) {}
101    };
102
103    struct FrameData {
104        // signaled when this struct is ready for reuse
105        VkFence fence;
106
107        VkCommandBuffer primary_cmd;
108        std::vector<VkCommandBuffer> worker_cmds;
109
110        VkBuffer buf;
111        uint8_t *base;
112        VkDescriptorSet desc_set;
113    };
114
115    // called by the constructor
116    void init_workers();
117
118    bool multithread_;
119    bool use_push_constants_;
120
121    // called mostly by on_key
122    void update_camera();
123
124    bool sim_paused_;
125    Simulation sim_;
126    Camera camera_;
127
128    std::vector<std::unique_ptr<Worker>> workers_;
129
130    // called by attach_shell
131    void create_render_pass();
132    void create_shader_modules();
133    void create_descriptor_set_layout();
134    void create_pipeline_layout();
135    void create_pipeline();
136
137    void create_frame_data(int count);
138    void destroy_frame_data();
139    void create_fences();
140    void create_command_buffers();
141    void create_buffers();
142    void create_buffer_memory();
143    void create_descriptor_sets();
144
145    VkPhysicalDevice physical_dev_;
146    VkDevice dev_;
147    VkQueue queue_;
148    uint32_t queue_family_;
149    VkFormat format_;
150
151    VkPhysicalDeviceProperties physical_dev_props_;
152    std::vector<VkMemoryPropertyFlags> mem_flags_;
153
154    const Meshes *meshes_;
155
156    VkRenderPass render_pass_;
157    VkShaderModule vs_;
158    VkShaderModule fs_;
159    VkDescriptorSetLayout desc_set_layout_;
160    VkPipelineLayout pipeline_layout_;
161    VkPipeline pipeline_;
162
163    VkCommandPool primary_cmd_pool_;
164    std::vector<VkCommandPool> worker_cmd_pools_;
165    VkDescriptorPool desc_pool_;
166    VkDeviceMemory frame_data_mem_;
167    std::vector<FrameData> frame_data_;
168    int frame_data_index_;
169
170    VkClearValue render_pass_clear_value_;
171    VkRenderPassBeginInfo render_pass_begin_info_;
172
173    VkCommandBufferBeginInfo primary_cmd_begin_info_;
174    VkPipelineStageFlags primary_cmd_submit_wait_stages_;
175    VkSubmitInfo primary_cmd_submit_info_;
176
177    // called by attach_swapchain
178    void prepare_viewport(const VkExtent2D &extent);
179    void prepare_framebuffers(VkSwapchainKHR swapchain);
180
181    VkExtent2D extent_;
182    VkViewport viewport_;
183    VkRect2D scissor_;
184
185    std::vector<VkImage> images_;
186    std::vector<VkImageView> image_views_;
187    std::vector<VkFramebuffer> framebuffers_;
188
189    // called by workers
190    void update_simulation(const Worker &worker);
191    void draw_object(const Simulation::Object &obj, FrameData &data, VkCommandBuffer cmd) const;
192    void draw_objects(Worker &worker);
193};
194
195#endif // HOLOGRAM_H
196