12f18b292ff155af7df35930474857b507dbf18feTony Barbour/*
22f18b292ff155af7df35930474857b507dbf18feTony Barbour * Copyright (C) 2016 Google, Inc.
32f18b292ff155af7df35930474857b507dbf18feTony Barbour *
443b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * Licensed under the Apache License, Version 2.0 (the "License");
543b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * you may not use this file except in compliance with the License.
643b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * You may obtain a copy of the License at
72f18b292ff155af7df35930474857b507dbf18feTony Barbour *
843b53e83705f02245da6ae61e31273866a35b833Jon Ashburn *     http://www.apache.org/licenses/LICENSE-2.0
92f18b292ff155af7df35930474857b507dbf18feTony Barbour *
1043b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * Unless required by applicable law or agreed to in writing, software
1143b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * distributed under the License is distributed on an "AS IS" BASIS,
1243b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1343b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * See the License for the specific language governing permissions and
1443b53e83705f02245da6ae61e31273866a35b833Jon Ashburn * limitations under the License.
152f18b292ff155af7df35930474857b507dbf18feTony Barbour */
162f18b292ff155af7df35930474857b507dbf18feTony Barbour
172f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <array>
182f18b292ff155af7df35930474857b507dbf18feTony Barbour
192f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <glm/gtc/type_ptr.hpp>
202f18b292ff155af7df35930474857b507dbf18feTony Barbour#include <glm/gtc/matrix_transform.hpp>
212f18b292ff155af7df35930474857b507dbf18feTony Barbour
222f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "Helpers.h"
232f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "Smoke.h"
242f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "Meshes.h"
252f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "Shell.h"
262f18b292ff155af7df35930474857b507dbf18feTony Barbour
272f18b292ff155af7df35930474857b507dbf18feTony Barbournamespace {
282f18b292ff155af7df35930474857b507dbf18feTony Barbour
292f18b292ff155af7df35930474857b507dbf18feTony Barbour// TODO do not rely on compiler to use std140 layout
302f18b292ff155af7df35930474857b507dbf18feTony Barbour// TODO move lower frequency data to another descriptor set
312f18b292ff155af7df35930474857b507dbf18feTony Barbourstruct ShaderParamBlock {
322f18b292ff155af7df35930474857b507dbf18feTony Barbour    float light_pos[4];
332f18b292ff155af7df35930474857b507dbf18feTony Barbour    float light_color[4];
342f18b292ff155af7df35930474857b507dbf18feTony Barbour    float model[4 * 4];
352f18b292ff155af7df35930474857b507dbf18feTony Barbour    float view_projection[4 * 4];
362f18b292ff155af7df35930474857b507dbf18feTony Barbour};
372f18b292ff155af7df35930474857b507dbf18feTony Barbour
382f18b292ff155af7df35930474857b507dbf18feTony Barbour} // namespace
392f18b292ff155af7df35930474857b507dbf18feTony Barbour
402f18b292ff155af7df35930474857b507dbf18feTony BarbourSmoke::Smoke(const std::vector<std::string> &args)
412f18b292ff155af7df35930474857b507dbf18feTony Barbour    : Game("Smoke", args), multithread_(true), use_push_constants_(false),
422f18b292ff155af7df35930474857b507dbf18feTony Barbour      sim_paused_(false), sim_(5000), camera_(2.5f), frame_data_(),
432f18b292ff155af7df35930474857b507dbf18feTony Barbour      render_pass_clear_value_({{ 0.0f, 0.1f, 0.2f, 1.0f }}),
442f18b292ff155af7df35930474857b507dbf18feTony Barbour      render_pass_begin_info_(),
452f18b292ff155af7df35930474857b507dbf18feTony Barbour      primary_cmd_begin_info_(), primary_cmd_submit_info_()
462f18b292ff155af7df35930474857b507dbf18feTony Barbour{
472f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (auto it = args.begin(); it != args.end(); ++it) {
482f18b292ff155af7df35930474857b507dbf18feTony Barbour        if (*it == "-s")
492f18b292ff155af7df35930474857b507dbf18feTony Barbour            multithread_ = false;
502f18b292ff155af7df35930474857b507dbf18feTony Barbour        else if (*it == "-p")
512f18b292ff155af7df35930474857b507dbf18feTony Barbour            use_push_constants_ = true;
522f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
532f18b292ff155af7df35930474857b507dbf18feTony Barbour
542f18b292ff155af7df35930474857b507dbf18feTony Barbour    init_workers();
552f18b292ff155af7df35930474857b507dbf18feTony Barbour}
562f18b292ff155af7df35930474857b507dbf18feTony Barbour
572f18b292ff155af7df35930474857b507dbf18feTony BarbourSmoke::~Smoke()
582f18b292ff155af7df35930474857b507dbf18feTony Barbour{
592f18b292ff155af7df35930474857b507dbf18feTony Barbour}
602f18b292ff155af7df35930474857b507dbf18feTony Barbour
612f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::init_workers()
622f18b292ff155af7df35930474857b507dbf18feTony Barbour{
632f18b292ff155af7df35930474857b507dbf18feTony Barbour    int worker_count = std::thread::hardware_concurrency();
642f18b292ff155af7df35930474857b507dbf18feTony Barbour
652f18b292ff155af7df35930474857b507dbf18feTony Barbour    // not enough cores
662f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (!multithread_ || worker_count < 2) {
672f18b292ff155af7df35930474857b507dbf18feTony Barbour        multithread_ = false;
682f18b292ff155af7df35930474857b507dbf18feTony Barbour        worker_count = 1;
692f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
702f18b292ff155af7df35930474857b507dbf18feTony Barbour
7120f5fc0adf53b1f48373ce4e40c745b0d67ebe44Dustin Graves    const int object_per_worker =
7220f5fc0adf53b1f48373ce4e40c745b0d67ebe44Dustin Graves        static_cast<int>(sim_.objects().size()) / worker_count;
732f18b292ff155af7df35930474857b507dbf18feTony Barbour    int object_begin = 0, object_end = 0;
742f18b292ff155af7df35930474857b507dbf18feTony Barbour
752f18b292ff155af7df35930474857b507dbf18feTony Barbour    workers_.reserve(worker_count);
762f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (int i = 0; i < worker_count; i++) {
772f18b292ff155af7df35930474857b507dbf18feTony Barbour        object_begin = object_end;
782f18b292ff155af7df35930474857b507dbf18feTony Barbour        if (i < worker_count - 1)
792f18b292ff155af7df35930474857b507dbf18feTony Barbour            object_end += object_per_worker;
802f18b292ff155af7df35930474857b507dbf18feTony Barbour        else
8120f5fc0adf53b1f48373ce4e40c745b0d67ebe44Dustin Graves            object_end = static_cast<int>(sim_.objects().size());
822f18b292ff155af7df35930474857b507dbf18feTony Barbour
832f18b292ff155af7df35930474857b507dbf18feTony Barbour        Worker *worker = new Worker(*this, i, object_begin, object_end);
842f18b292ff155af7df35930474857b507dbf18feTony Barbour        workers_.emplace_back(std::unique_ptr<Worker>(worker));
852f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
862f18b292ff155af7df35930474857b507dbf18feTony Barbour}
872f18b292ff155af7df35930474857b507dbf18feTony Barbour
882f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::attach_shell(Shell &sh)
892f18b292ff155af7df35930474857b507dbf18feTony Barbour{
902f18b292ff155af7df35930474857b507dbf18feTony Barbour    Game::attach_shell(sh);
912f18b292ff155af7df35930474857b507dbf18feTony Barbour
922f18b292ff155af7df35930474857b507dbf18feTony Barbour    const Shell::Context &ctx = sh.context();
932f18b292ff155af7df35930474857b507dbf18feTony Barbour    physical_dev_ = ctx.physical_dev;
942f18b292ff155af7df35930474857b507dbf18feTony Barbour    dev_ = ctx.dev;
952f18b292ff155af7df35930474857b507dbf18feTony Barbour    queue_ = ctx.game_queue;
962f18b292ff155af7df35930474857b507dbf18feTony Barbour    queue_family_ = ctx.game_queue_family;
972f18b292ff155af7df35930474857b507dbf18feTony Barbour    format_ = ctx.format.format;
982f18b292ff155af7df35930474857b507dbf18feTony Barbour
992f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::GetPhysicalDeviceProperties(physical_dev_, &physical_dev_props_);
1002f18b292ff155af7df35930474857b507dbf18feTony Barbour
1012f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (use_push_constants_ &&
1022f18b292ff155af7df35930474857b507dbf18feTony Barbour        sizeof(ShaderParamBlock) > physical_dev_props_.limits.maxPushConstantsSize) {
1032f18b292ff155af7df35930474857b507dbf18feTony Barbour        shell_->log(Shell::LOG_WARN, "cannot enable push constants");
1042f18b292ff155af7df35930474857b507dbf18feTony Barbour        use_push_constants_ = false;
1052f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
1062f18b292ff155af7df35930474857b507dbf18feTony Barbour
1072f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkPhysicalDeviceMemoryProperties mem_props;
1082f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::GetPhysicalDeviceMemoryProperties(physical_dev_, &mem_props);
1092f18b292ff155af7df35930474857b507dbf18feTony Barbour    mem_flags_.reserve(mem_props.memoryTypeCount);
1102f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (uint32_t i = 0; i < mem_props.memoryTypeCount; i++)
1112f18b292ff155af7df35930474857b507dbf18feTony Barbour        mem_flags_.push_back(mem_props.memoryTypes[i].propertyFlags);
1122f18b292ff155af7df35930474857b507dbf18feTony Barbour
1132f18b292ff155af7df35930474857b507dbf18feTony Barbour    meshes_ = new Meshes(dev_, mem_flags_);
1142f18b292ff155af7df35930474857b507dbf18feTony Barbour
1152f18b292ff155af7df35930474857b507dbf18feTony Barbour    create_render_pass();
1162f18b292ff155af7df35930474857b507dbf18feTony Barbour    create_shader_modules();
1172f18b292ff155af7df35930474857b507dbf18feTony Barbour    create_descriptor_set_layout();
1182f18b292ff155af7df35930474857b507dbf18feTony Barbour    create_pipeline_layout();
1192f18b292ff155af7df35930474857b507dbf18feTony Barbour    create_pipeline();
1202f18b292ff155af7df35930474857b507dbf18feTony Barbour
1212f18b292ff155af7df35930474857b507dbf18feTony Barbour    create_frame_data(2);
1222f18b292ff155af7df35930474857b507dbf18feTony Barbour
1232f18b292ff155af7df35930474857b507dbf18feTony Barbour    render_pass_begin_info_.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
1242f18b292ff155af7df35930474857b507dbf18feTony Barbour    render_pass_begin_info_.renderPass = render_pass_;
1252f18b292ff155af7df35930474857b507dbf18feTony Barbour    render_pass_begin_info_.clearValueCount = 1;
1262f18b292ff155af7df35930474857b507dbf18feTony Barbour    render_pass_begin_info_.pClearValues = &render_pass_clear_value_;
1272f18b292ff155af7df35930474857b507dbf18feTony Barbour
1282f18b292ff155af7df35930474857b507dbf18feTony Barbour    primary_cmd_begin_info_.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
1292f18b292ff155af7df35930474857b507dbf18feTony Barbour    primary_cmd_begin_info_.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
1302f18b292ff155af7df35930474857b507dbf18feTony Barbour
1312f18b292ff155af7df35930474857b507dbf18feTony Barbour    // we will render to the swapchain images
1322f18b292ff155af7df35930474857b507dbf18feTony Barbour    primary_cmd_submit_wait_stages_ = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1332f18b292ff155af7df35930474857b507dbf18feTony Barbour
1342f18b292ff155af7df35930474857b507dbf18feTony Barbour    primary_cmd_submit_info_.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
1352f18b292ff155af7df35930474857b507dbf18feTony Barbour    primary_cmd_submit_info_.waitSemaphoreCount = 1;
1362f18b292ff155af7df35930474857b507dbf18feTony Barbour    primary_cmd_submit_info_.pWaitDstStageMask = &primary_cmd_submit_wait_stages_;
1372f18b292ff155af7df35930474857b507dbf18feTony Barbour    primary_cmd_submit_info_.commandBufferCount = 1;
1382f18b292ff155af7df35930474857b507dbf18feTony Barbour    primary_cmd_submit_info_.signalSemaphoreCount = 1;
1392f18b292ff155af7df35930474857b507dbf18feTony Barbour
1402f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (multithread_) {
1412f18b292ff155af7df35930474857b507dbf18feTony Barbour        for (auto &worker : workers_)
1422f18b292ff155af7df35930474857b507dbf18feTony Barbour            worker->start();
1432f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
1442f18b292ff155af7df35930474857b507dbf18feTony Barbour}
1452f18b292ff155af7df35930474857b507dbf18feTony Barbour
1462f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::detach_shell()
1472f18b292ff155af7df35930474857b507dbf18feTony Barbour{
1482f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (multithread_) {
1492f18b292ff155af7df35930474857b507dbf18feTony Barbour        for (auto &worker : workers_)
1502f18b292ff155af7df35930474857b507dbf18feTony Barbour            worker->stop();
1512f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
1522f18b292ff155af7df35930474857b507dbf18feTony Barbour
1532f18b292ff155af7df35930474857b507dbf18feTony Barbour    destroy_frame_data();
1542f18b292ff155af7df35930474857b507dbf18feTony Barbour
1552f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::DestroyPipeline(dev_, pipeline_, nullptr);
1562f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::DestroyPipelineLayout(dev_, pipeline_layout_, nullptr);
1572f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (!use_push_constants_)
1582f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::DestroyDescriptorSetLayout(dev_, desc_set_layout_, nullptr);
1592f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::DestroyShaderModule(dev_, fs_, nullptr);
1602f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::DestroyShaderModule(dev_, vs_, nullptr);
1612f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::DestroyRenderPass(dev_, render_pass_, nullptr);
1622f18b292ff155af7df35930474857b507dbf18feTony Barbour
1632f18b292ff155af7df35930474857b507dbf18feTony Barbour    delete meshes_;
1642f18b292ff155af7df35930474857b507dbf18feTony Barbour
1652f18b292ff155af7df35930474857b507dbf18feTony Barbour    Game::detach_shell();
1662f18b292ff155af7df35930474857b507dbf18feTony Barbour}
1672f18b292ff155af7df35930474857b507dbf18feTony Barbour
1682f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::create_render_pass()
1692f18b292ff155af7df35930474857b507dbf18feTony Barbour{
1702f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkAttachmentDescription attachment = {};
1712f18b292ff155af7df35930474857b507dbf18feTony Barbour    attachment.format = format_;
1722f18b292ff155af7df35930474857b507dbf18feTony Barbour    attachment.samples = VK_SAMPLE_COUNT_1_BIT;
1732f18b292ff155af7df35930474857b507dbf18feTony Barbour    attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
1742f18b292ff155af7df35930474857b507dbf18feTony Barbour    attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
1752f18b292ff155af7df35930474857b507dbf18feTony Barbour    attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1762f18b292ff155af7df35930474857b507dbf18feTony Barbour    attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
1772f18b292ff155af7df35930474857b507dbf18feTony Barbour
1782f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkAttachmentReference attachment_ref = {};
1792f18b292ff155af7df35930474857b507dbf18feTony Barbour    attachment_ref.attachment = 0;
1802f18b292ff155af7df35930474857b507dbf18feTony Barbour    attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
1812f18b292ff155af7df35930474857b507dbf18feTony Barbour
1822f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkSubpassDescription subpass = {};
1832f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
1842f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass.colorAttachmentCount = 1;
1852f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass.pColorAttachments = &attachment_ref;
1862f18b292ff155af7df35930474857b507dbf18feTony Barbour
1872f18b292ff155af7df35930474857b507dbf18feTony Barbour    std::array<VkSubpassDependency, 2> subpass_deps;
1882f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass_deps[0].srcSubpass = VK_SUBPASS_EXTERNAL;
1892f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass_deps[0].dstSubpass = 0;
1902f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass_deps[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
1912f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass_deps[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
1922f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass_deps[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
1932f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass_deps[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
1942f18b292ff155af7df35930474857b507dbf18feTony Barbour                                    VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
1952f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass_deps[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
1962f18b292ff155af7df35930474857b507dbf18feTony Barbour
1972f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass_deps[1].srcSubpass = 0;
1982f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass_deps[1].dstSubpass = VK_SUBPASS_EXTERNAL;
1992f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass_deps[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
2002f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass_deps[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
2012f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass_deps[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
2022f18b292ff155af7df35930474857b507dbf18feTony Barbour                                    VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
2032f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass_deps[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
2042f18b292ff155af7df35930474857b507dbf18feTony Barbour    subpass_deps[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
2052f18b292ff155af7df35930474857b507dbf18feTony Barbour
2062f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkRenderPassCreateInfo render_pass_info = {};
2072f18b292ff155af7df35930474857b507dbf18feTony Barbour    render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
2082f18b292ff155af7df35930474857b507dbf18feTony Barbour    render_pass_info.attachmentCount = 1;
2092f18b292ff155af7df35930474857b507dbf18feTony Barbour    render_pass_info.pAttachments = &attachment;
2102f18b292ff155af7df35930474857b507dbf18feTony Barbour    render_pass_info.subpassCount = 1;
2112f18b292ff155af7df35930474857b507dbf18feTony Barbour    render_pass_info.pSubpasses = &subpass;
2122f18b292ff155af7df35930474857b507dbf18feTony Barbour    render_pass_info.dependencyCount = (uint32_t)subpass_deps.size();
2132f18b292ff155af7df35930474857b507dbf18feTony Barbour    render_pass_info.pDependencies = subpass_deps.data();
2142f18b292ff155af7df35930474857b507dbf18feTony Barbour
2152f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::assert_success(vk::CreateRenderPass(dev_, &render_pass_info, nullptr, &render_pass_));
2162f18b292ff155af7df35930474857b507dbf18feTony Barbour}
2172f18b292ff155af7df35930474857b507dbf18feTony Barbour
2182f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::create_shader_modules()
2192f18b292ff155af7df35930474857b507dbf18feTony Barbour{
2202f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkShaderModuleCreateInfo sh_info = {};
2212f18b292ff155af7df35930474857b507dbf18feTony Barbour    sh_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
2222f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (use_push_constants_) {
2232f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "Smoke.push_constant.vert.h"
2242f18b292ff155af7df35930474857b507dbf18feTony Barbour        sh_info.codeSize = sizeof(Smoke_push_constant_vert);
2252f18b292ff155af7df35930474857b507dbf18feTony Barbour        sh_info.pCode = Smoke_push_constant_vert;
2262f18b292ff155af7df35930474857b507dbf18feTony Barbour    } else {
2272f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "Smoke.vert.h"
2282f18b292ff155af7df35930474857b507dbf18feTony Barbour        sh_info.codeSize = sizeof(Smoke_vert);
2292f18b292ff155af7df35930474857b507dbf18feTony Barbour        sh_info.pCode = Smoke_vert;
2302f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
2312f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::assert_success(vk::CreateShaderModule(dev_, &sh_info, nullptr, &vs_));
2322f18b292ff155af7df35930474857b507dbf18feTony Barbour
2332f18b292ff155af7df35930474857b507dbf18feTony Barbour#include "Smoke.frag.h"
2342f18b292ff155af7df35930474857b507dbf18feTony Barbour    sh_info.codeSize = sizeof(Smoke_frag);
2352f18b292ff155af7df35930474857b507dbf18feTony Barbour    sh_info.pCode = Smoke_frag;
2362f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::assert_success(vk::CreateShaderModule(dev_, &sh_info, nullptr, &fs_));
2372f18b292ff155af7df35930474857b507dbf18feTony Barbour}
2382f18b292ff155af7df35930474857b507dbf18feTony Barbour
2392f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::create_descriptor_set_layout()
2402f18b292ff155af7df35930474857b507dbf18feTony Barbour{
2412f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (use_push_constants_)
2422f18b292ff155af7df35930474857b507dbf18feTony Barbour        return;
2432f18b292ff155af7df35930474857b507dbf18feTony Barbour
2442f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkDescriptorSetLayoutBinding layout_binding = {};
2452f18b292ff155af7df35930474857b507dbf18feTony Barbour    layout_binding.binding = 0;
2462f18b292ff155af7df35930474857b507dbf18feTony Barbour    layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
2472f18b292ff155af7df35930474857b507dbf18feTony Barbour    layout_binding.descriptorCount = 1;
2482f18b292ff155af7df35930474857b507dbf18feTony Barbour    layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
2492f18b292ff155af7df35930474857b507dbf18feTony Barbour
2502f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkDescriptorSetLayoutCreateInfo layout_info = {};
2512f18b292ff155af7df35930474857b507dbf18feTony Barbour    layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
2522f18b292ff155af7df35930474857b507dbf18feTony Barbour    layout_info.bindingCount = 1;
2532f18b292ff155af7df35930474857b507dbf18feTony Barbour    layout_info.pBindings = &layout_binding;
2542f18b292ff155af7df35930474857b507dbf18feTony Barbour
2552f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::assert_success(vk::CreateDescriptorSetLayout(dev_, &layout_info,
2562f18b292ff155af7df35930474857b507dbf18feTony Barbour                nullptr, &desc_set_layout_));
2572f18b292ff155af7df35930474857b507dbf18feTony Barbour}
2582f18b292ff155af7df35930474857b507dbf18feTony Barbour
2592f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::create_pipeline_layout()
2602f18b292ff155af7df35930474857b507dbf18feTony Barbour{
2612f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkPushConstantRange push_const_range = {};
2622f18b292ff155af7df35930474857b507dbf18feTony Barbour
2632f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkPipelineLayoutCreateInfo pipeline_layout_info = {};
2642f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
2652f18b292ff155af7df35930474857b507dbf18feTony Barbour
2662f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (use_push_constants_) {
2672f18b292ff155af7df35930474857b507dbf18feTony Barbour        push_const_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
2682f18b292ff155af7df35930474857b507dbf18feTony Barbour        push_const_range.offset = 0;
2692f18b292ff155af7df35930474857b507dbf18feTony Barbour        push_const_range.size = sizeof(ShaderParamBlock);
2702f18b292ff155af7df35930474857b507dbf18feTony Barbour
2712f18b292ff155af7df35930474857b507dbf18feTony Barbour        pipeline_layout_info.pushConstantRangeCount = 1;
2722f18b292ff155af7df35930474857b507dbf18feTony Barbour        pipeline_layout_info.pPushConstantRanges = &push_const_range;
2732f18b292ff155af7df35930474857b507dbf18feTony Barbour    } else {
2742f18b292ff155af7df35930474857b507dbf18feTony Barbour        pipeline_layout_info.setLayoutCount = 1;
2752f18b292ff155af7df35930474857b507dbf18feTony Barbour        pipeline_layout_info.pSetLayouts = &desc_set_layout_;
2762f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
2772f18b292ff155af7df35930474857b507dbf18feTony Barbour
2782f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::assert_success(vk::CreatePipelineLayout(dev_, &pipeline_layout_info,
2792f18b292ff155af7df35930474857b507dbf18feTony Barbour                nullptr, &pipeline_layout_));
2802f18b292ff155af7df35930474857b507dbf18feTony Barbour}
2812f18b292ff155af7df35930474857b507dbf18feTony Barbour
2822f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::create_pipeline()
2832f18b292ff155af7df35930474857b507dbf18feTony Barbour{
2842f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkPipelineShaderStageCreateInfo stage_info[2] = {};
2852f18b292ff155af7df35930474857b507dbf18feTony Barbour    stage_info[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
2862f18b292ff155af7df35930474857b507dbf18feTony Barbour    stage_info[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
2872f18b292ff155af7df35930474857b507dbf18feTony Barbour    stage_info[0].module = vs_;
2882f18b292ff155af7df35930474857b507dbf18feTony Barbour    stage_info[0].pName = "main";
2892f18b292ff155af7df35930474857b507dbf18feTony Barbour    stage_info[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
2902f18b292ff155af7df35930474857b507dbf18feTony Barbour    stage_info[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
2912f18b292ff155af7df35930474857b507dbf18feTony Barbour    stage_info[1].module = fs_;
2922f18b292ff155af7df35930474857b507dbf18feTony Barbour    stage_info[1].pName = "main";
2932f18b292ff155af7df35930474857b507dbf18feTony Barbour
2942f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkPipelineViewportStateCreateInfo viewport_info = {};
2952f18b292ff155af7df35930474857b507dbf18feTony Barbour    viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
2962f18b292ff155af7df35930474857b507dbf18feTony Barbour    // both dynamic
2972f18b292ff155af7df35930474857b507dbf18feTony Barbour    viewport_info.viewportCount = 1;
2982f18b292ff155af7df35930474857b507dbf18feTony Barbour    viewport_info.scissorCount = 1;
2992f18b292ff155af7df35930474857b507dbf18feTony Barbour
3002f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkPipelineRasterizationStateCreateInfo rast_info = {};
3012f18b292ff155af7df35930474857b507dbf18feTony Barbour    rast_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
3022f18b292ff155af7df35930474857b507dbf18feTony Barbour    rast_info.depthClampEnable = false;
3032f18b292ff155af7df35930474857b507dbf18feTony Barbour    rast_info.rasterizerDiscardEnable = false;
3042f18b292ff155af7df35930474857b507dbf18feTony Barbour    rast_info.polygonMode = VK_POLYGON_MODE_FILL;
3052f18b292ff155af7df35930474857b507dbf18feTony Barbour    rast_info.cullMode = VK_CULL_MODE_NONE;
3062f18b292ff155af7df35930474857b507dbf18feTony Barbour    rast_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
3072f18b292ff155af7df35930474857b507dbf18feTony Barbour    rast_info.depthBiasEnable = false;
3082f18b292ff155af7df35930474857b507dbf18feTony Barbour    rast_info.lineWidth = 1.0f;
3092f18b292ff155af7df35930474857b507dbf18feTony Barbour
3102f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkPipelineMultisampleStateCreateInfo multisample_info = {};
3112f18b292ff155af7df35930474857b507dbf18feTony Barbour    multisample_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
3122f18b292ff155af7df35930474857b507dbf18feTony Barbour    multisample_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
3132f18b292ff155af7df35930474857b507dbf18feTony Barbour    multisample_info.sampleShadingEnable = false;
3142f18b292ff155af7df35930474857b507dbf18feTony Barbour    multisample_info.pSampleMask = nullptr;
3152f18b292ff155af7df35930474857b507dbf18feTony Barbour    multisample_info.alphaToCoverageEnable = false;
3162f18b292ff155af7df35930474857b507dbf18feTony Barbour    multisample_info.alphaToOneEnable = false;
3172f18b292ff155af7df35930474857b507dbf18feTony Barbour
3182f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkPipelineColorBlendAttachmentState blend_attachment = {};
3192f18b292ff155af7df35930474857b507dbf18feTony Barbour    blend_attachment.blendEnable = true;
3202f18b292ff155af7df35930474857b507dbf18feTony Barbour    blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
3212f18b292ff155af7df35930474857b507dbf18feTony Barbour    blend_attachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
3222f18b292ff155af7df35930474857b507dbf18feTony Barbour    blend_attachment.colorBlendOp = VK_BLEND_OP_ADD;
3232f18b292ff155af7df35930474857b507dbf18feTony Barbour    blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
3242f18b292ff155af7df35930474857b507dbf18feTony Barbour    blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
3252f18b292ff155af7df35930474857b507dbf18feTony Barbour    blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD;
3262f18b292ff155af7df35930474857b507dbf18feTony Barbour    blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
3272f18b292ff155af7df35930474857b507dbf18feTony Barbour                                      VK_COLOR_COMPONENT_G_BIT |
3282f18b292ff155af7df35930474857b507dbf18feTony Barbour                                      VK_COLOR_COMPONENT_B_BIT |
3292f18b292ff155af7df35930474857b507dbf18feTony Barbour                                      VK_COLOR_COMPONENT_A_BIT;
3302f18b292ff155af7df35930474857b507dbf18feTony Barbour
3312f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkPipelineColorBlendStateCreateInfo blend_info = {};
3322f18b292ff155af7df35930474857b507dbf18feTony Barbour    blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
3332f18b292ff155af7df35930474857b507dbf18feTony Barbour    blend_info.logicOpEnable = false;
3342f18b292ff155af7df35930474857b507dbf18feTony Barbour    blend_info.attachmentCount = 1;
3352f18b292ff155af7df35930474857b507dbf18feTony Barbour    blend_info.pAttachments = &blend_attachment;
3362f18b292ff155af7df35930474857b507dbf18feTony Barbour
3372f18b292ff155af7df35930474857b507dbf18feTony Barbour    std::array<VkDynamicState, 2> dynamic_states = {
3382f18b292ff155af7df35930474857b507dbf18feTony Barbour        VK_DYNAMIC_STATE_VIEWPORT,
3392f18b292ff155af7df35930474857b507dbf18feTony Barbour        VK_DYNAMIC_STATE_SCISSOR
3402f18b292ff155af7df35930474857b507dbf18feTony Barbour    };
3412f18b292ff155af7df35930474857b507dbf18feTony Barbour    struct VkPipelineDynamicStateCreateInfo dynamic_info = {};
3422f18b292ff155af7df35930474857b507dbf18feTony Barbour    dynamic_info.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
3432f18b292ff155af7df35930474857b507dbf18feTony Barbour    dynamic_info.dynamicStateCount = (uint32_t)dynamic_states.size();
3442f18b292ff155af7df35930474857b507dbf18feTony Barbour    dynamic_info.pDynamicStates = dynamic_states.data();
3452f18b292ff155af7df35930474857b507dbf18feTony Barbour
3462f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkGraphicsPipelineCreateInfo pipeline_info = {};
3472f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
3482f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_info.stageCount = 2;
3492f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_info.pStages = stage_info;
3502f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_info.pVertexInputState = &meshes_->vertex_input_state();
3512f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_info.pInputAssemblyState = &meshes_->input_assembly_state();
3522f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_info.pTessellationState = nullptr;
3532f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_info.pViewportState = &viewport_info;
3542f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_info.pRasterizationState = &rast_info;
3552f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_info.pMultisampleState = &multisample_info;
3562f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_info.pDepthStencilState = nullptr;
3572f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_info.pColorBlendState = &blend_info;
3582f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_info.pDynamicState = &dynamic_info;
3592f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_info.layout = pipeline_layout_;
3602f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_info.renderPass = render_pass_;
3612f18b292ff155af7df35930474857b507dbf18feTony Barbour    pipeline_info.subpass = 0;
3622f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::assert_success(vk::CreateGraphicsPipelines(dev_, VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &pipeline_));
3632f18b292ff155af7df35930474857b507dbf18feTony Barbour}
3642f18b292ff155af7df35930474857b507dbf18feTony Barbour
3652f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::create_frame_data(int count)
3662f18b292ff155af7df35930474857b507dbf18feTony Barbour{
3672f18b292ff155af7df35930474857b507dbf18feTony Barbour    frame_data_.resize(count);
3682f18b292ff155af7df35930474857b507dbf18feTony Barbour
3692f18b292ff155af7df35930474857b507dbf18feTony Barbour    create_fences();
3702f18b292ff155af7df35930474857b507dbf18feTony Barbour    create_command_buffers();
3712f18b292ff155af7df35930474857b507dbf18feTony Barbour
3722f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (!use_push_constants_) {
3732f18b292ff155af7df35930474857b507dbf18feTony Barbour        create_buffers();
3742f18b292ff155af7df35930474857b507dbf18feTony Barbour        create_buffer_memory();
3752f18b292ff155af7df35930474857b507dbf18feTony Barbour        create_descriptor_sets();
3762f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
3772f18b292ff155af7df35930474857b507dbf18feTony Barbour
3782f18b292ff155af7df35930474857b507dbf18feTony Barbour    frame_data_index_ = 0;
3792f18b292ff155af7df35930474857b507dbf18feTony Barbour}
3802f18b292ff155af7df35930474857b507dbf18feTony Barbour
3812f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::destroy_frame_data()
3822f18b292ff155af7df35930474857b507dbf18feTony Barbour{
3832f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (!use_push_constants_) {
3842f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::DestroyDescriptorPool(dev_, desc_pool_, nullptr);
3852f18b292ff155af7df35930474857b507dbf18feTony Barbour
3862f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::UnmapMemory(dev_, frame_data_mem_);
3872f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::FreeMemory(dev_, frame_data_mem_, nullptr);
3882f18b292ff155af7df35930474857b507dbf18feTony Barbour
3892f18b292ff155af7df35930474857b507dbf18feTony Barbour        for (auto &data : frame_data_)
3902f18b292ff155af7df35930474857b507dbf18feTony Barbour            vk::DestroyBuffer(dev_, data.buf, nullptr);
3912f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
3922f18b292ff155af7df35930474857b507dbf18feTony Barbour
3935122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz    for (auto cmd_pool : worker_cmd_pools_)
3945122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz        vk::DestroyCommandPool(dev_, cmd_pool, nullptr);
3955122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz    worker_cmd_pools_.clear();
3965122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz    vk::DestroyCommandPool(dev_, primary_cmd_pool_, nullptr);
3975122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz
3982f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (auto &data : frame_data_)
3992f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::DestroyFence(dev_, data.fence, nullptr);
4002f18b292ff155af7df35930474857b507dbf18feTony Barbour
4012f18b292ff155af7df35930474857b507dbf18feTony Barbour    frame_data_.clear();
4022f18b292ff155af7df35930474857b507dbf18feTony Barbour}
4032f18b292ff155af7df35930474857b507dbf18feTony Barbour
4042f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::create_fences()
4052f18b292ff155af7df35930474857b507dbf18feTony Barbour{
4062f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkFenceCreateInfo fence_info = {};
4072f18b292ff155af7df35930474857b507dbf18feTony Barbour    fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
4082f18b292ff155af7df35930474857b507dbf18feTony Barbour    fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
4092f18b292ff155af7df35930474857b507dbf18feTony Barbour
4102f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (auto &data : frame_data_)
4112f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::assert_success(vk::CreateFence(dev_, &fence_info, nullptr, &data.fence));
4122f18b292ff155af7df35930474857b507dbf18feTony Barbour}
4132f18b292ff155af7df35930474857b507dbf18feTony Barbour
4142f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::create_command_buffers()
4152f18b292ff155af7df35930474857b507dbf18feTony Barbour{
4162f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkCommandPoolCreateInfo cmd_pool_info = {};
4172f18b292ff155af7df35930474857b507dbf18feTony Barbour    cmd_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
4182f18b292ff155af7df35930474857b507dbf18feTony Barbour    cmd_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
4192f18b292ff155af7df35930474857b507dbf18feTony Barbour    cmd_pool_info.queueFamilyIndex = queue_family_;
4202f18b292ff155af7df35930474857b507dbf18feTony Barbour
4212f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkCommandBufferAllocateInfo cmd_info = {};
4222f18b292ff155af7df35930474857b507dbf18feTony Barbour    cmd_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
4232f18b292ff155af7df35930474857b507dbf18feTony Barbour    cmd_info.commandBufferCount = static_cast<uint32_t>(frame_data_.size());
4242f18b292ff155af7df35930474857b507dbf18feTony Barbour
4252f18b292ff155af7df35930474857b507dbf18feTony Barbour    // create command pools and buffers
4262f18b292ff155af7df35930474857b507dbf18feTony Barbour    std::vector<VkCommandPool> cmd_pools(workers_.size() + 1, VK_NULL_HANDLE);
4272f18b292ff155af7df35930474857b507dbf18feTony Barbour    std::vector<std::vector<VkCommandBuffer>> cmds_vec(workers_.size() + 1,
4282f18b292ff155af7df35930474857b507dbf18feTony Barbour            std::vector<VkCommandBuffer>(frame_data_.size(), VK_NULL_HANDLE));
4292f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (size_t i = 0; i < cmd_pools.size(); i++) {
4302f18b292ff155af7df35930474857b507dbf18feTony Barbour        auto &cmd_pool = cmd_pools[i];
4312f18b292ff155af7df35930474857b507dbf18feTony Barbour        auto &cmds = cmds_vec[i];
4322f18b292ff155af7df35930474857b507dbf18feTony Barbour
4332f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::assert_success(vk::CreateCommandPool(dev_, &cmd_pool_info,
4342f18b292ff155af7df35930474857b507dbf18feTony Barbour                    nullptr, &cmd_pool));
4352f18b292ff155af7df35930474857b507dbf18feTony Barbour
4362f18b292ff155af7df35930474857b507dbf18feTony Barbour        cmd_info.commandPool = cmd_pool;
4372f18b292ff155af7df35930474857b507dbf18feTony Barbour        cmd_info.level = (cmd_pool == cmd_pools.back()) ?
4382f18b292ff155af7df35930474857b507dbf18feTony Barbour            VK_COMMAND_BUFFER_LEVEL_PRIMARY : VK_COMMAND_BUFFER_LEVEL_SECONDARY;
4392f18b292ff155af7df35930474857b507dbf18feTony Barbour
4402f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::assert_success(vk::AllocateCommandBuffers(dev_, &cmd_info, cmds.data()));
4412f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
4422f18b292ff155af7df35930474857b507dbf18feTony Barbour
4432f18b292ff155af7df35930474857b507dbf18feTony Barbour    // update frame_data_
4442f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (size_t i = 0; i < frame_data_.size(); i++) {
4452f18b292ff155af7df35930474857b507dbf18feTony Barbour        for (const auto &cmds : cmds_vec) {
4462f18b292ff155af7df35930474857b507dbf18feTony Barbour            if (cmds == cmds_vec.back()) {
4472f18b292ff155af7df35930474857b507dbf18feTony Barbour                frame_data_[i].primary_cmd = cmds[i];
4482f18b292ff155af7df35930474857b507dbf18feTony Barbour            } else {
4492f18b292ff155af7df35930474857b507dbf18feTony Barbour                frame_data_[i].worker_cmds.push_back(cmds[i]);
4502f18b292ff155af7df35930474857b507dbf18feTony Barbour            }
4512f18b292ff155af7df35930474857b507dbf18feTony Barbour        }
4522f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
4532f18b292ff155af7df35930474857b507dbf18feTony Barbour
4542f18b292ff155af7df35930474857b507dbf18feTony Barbour    primary_cmd_pool_ = cmd_pools.back();
4552f18b292ff155af7df35930474857b507dbf18feTony Barbour    cmd_pools.pop_back();
4562f18b292ff155af7df35930474857b507dbf18feTony Barbour    worker_cmd_pools_ = cmd_pools;
4572f18b292ff155af7df35930474857b507dbf18feTony Barbour}
4582f18b292ff155af7df35930474857b507dbf18feTony Barbour
4592f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::create_buffers()
4602f18b292ff155af7df35930474857b507dbf18feTony Barbour{
4612f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkDeviceSize object_data_size = sizeof(ShaderParamBlock);
4622f18b292ff155af7df35930474857b507dbf18feTony Barbour    // align object data to device limit
4632f18b292ff155af7df35930474857b507dbf18feTony Barbour    const VkDeviceSize &alignment =
4642f18b292ff155af7df35930474857b507dbf18feTony Barbour        physical_dev_props_.limits.minStorageBufferOffsetAlignment;
4652f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (object_data_size % alignment)
4662f18b292ff155af7df35930474857b507dbf18feTony Barbour        object_data_size += alignment - (object_data_size % alignment);
4672f18b292ff155af7df35930474857b507dbf18feTony Barbour
4682f18b292ff155af7df35930474857b507dbf18feTony Barbour    // update simulation
46920f5fc0adf53b1f48373ce4e40c745b0d67ebe44Dustin Graves    sim_.set_frame_data_size(static_cast<uint32_t>(object_data_size));
4702f18b292ff155af7df35930474857b507dbf18feTony Barbour
4712f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkBufferCreateInfo buf_info = {};
4722f18b292ff155af7df35930474857b507dbf18feTony Barbour    buf_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
4732f18b292ff155af7df35930474857b507dbf18feTony Barbour    buf_info.size = object_data_size * sim_.objects().size();
4742f18b292ff155af7df35930474857b507dbf18feTony Barbour    buf_info.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
4752f18b292ff155af7df35930474857b507dbf18feTony Barbour    buf_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
4762f18b292ff155af7df35930474857b507dbf18feTony Barbour
4772f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (auto &data : frame_data_)
4782f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::assert_success(vk::CreateBuffer(dev_, &buf_info, nullptr, &data.buf));
4792f18b292ff155af7df35930474857b507dbf18feTony Barbour}
4802f18b292ff155af7df35930474857b507dbf18feTony Barbour
4812f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::create_buffer_memory()
4822f18b292ff155af7df35930474857b507dbf18feTony Barbour{
4832f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkMemoryRequirements mem_reqs;
4842f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::GetBufferMemoryRequirements(dev_, frame_data_[0].buf, &mem_reqs);
4852f18b292ff155af7df35930474857b507dbf18feTony Barbour
4862f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkDeviceSize aligned_size = mem_reqs.size;
4872f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (aligned_size % mem_reqs.alignment)
4882f18b292ff155af7df35930474857b507dbf18feTony Barbour        aligned_size += mem_reqs.alignment - (aligned_size % mem_reqs.alignment);
4892f18b292ff155af7df35930474857b507dbf18feTony Barbour
4902f18b292ff155af7df35930474857b507dbf18feTony Barbour    // allocate memory
4912f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkMemoryAllocateInfo mem_info = {};
4922f18b292ff155af7df35930474857b507dbf18feTony Barbour    mem_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
4932f18b292ff155af7df35930474857b507dbf18feTony Barbour    mem_info.allocationSize = aligned_size * (frame_data_.size() - 1) +
4942f18b292ff155af7df35930474857b507dbf18feTony Barbour        mem_reqs.size;
4952f18b292ff155af7df35930474857b507dbf18feTony Barbour
4962f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (uint32_t idx = 0; idx < mem_flags_.size(); idx++) {
4972f18b292ff155af7df35930474857b507dbf18feTony Barbour        if ((mem_reqs.memoryTypeBits & (1 << idx)) &&
4982f18b292ff155af7df35930474857b507dbf18feTony Barbour            (mem_flags_[idx] & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) &&
4992f18b292ff155af7df35930474857b507dbf18feTony Barbour            (mem_flags_[idx] & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {
5002f18b292ff155af7df35930474857b507dbf18feTony Barbour            // TODO is this guaranteed to exist?
5012f18b292ff155af7df35930474857b507dbf18feTony Barbour            mem_info.memoryTypeIndex = idx;
5022f18b292ff155af7df35930474857b507dbf18feTony Barbour            break;
5032f18b292ff155af7df35930474857b507dbf18feTony Barbour        }
5042f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
5052f18b292ff155af7df35930474857b507dbf18feTony Barbour
5062f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::AllocateMemory(dev_, &mem_info, nullptr, &frame_data_mem_);
5072f18b292ff155af7df35930474857b507dbf18feTony Barbour
5082f18b292ff155af7df35930474857b507dbf18feTony Barbour    void *ptr;
5092f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::MapMemory(dev_, frame_data_mem_, 0, VK_WHOLE_SIZE, 0, &ptr);
5102f18b292ff155af7df35930474857b507dbf18feTony Barbour
5112f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkDeviceSize offset = 0;
5122f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (auto &data : frame_data_) {
5132f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::BindBufferMemory(dev_, data.buf, frame_data_mem_, offset);
5142f18b292ff155af7df35930474857b507dbf18feTony Barbour        data.base = reinterpret_cast<uint8_t *>(ptr) + offset;
5152f18b292ff155af7df35930474857b507dbf18feTony Barbour        offset += aligned_size;
5162f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
5172f18b292ff155af7df35930474857b507dbf18feTony Barbour}
5182f18b292ff155af7df35930474857b507dbf18feTony Barbour
5192f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::create_descriptor_sets()
5202f18b292ff155af7df35930474857b507dbf18feTony Barbour{
5212f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkDescriptorPoolSize desc_pool_size = {};
5222f18b292ff155af7df35930474857b507dbf18feTony Barbour    desc_pool_size.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
52320f5fc0adf53b1f48373ce4e40c745b0d67ebe44Dustin Graves    desc_pool_size.descriptorCount = static_cast<uint32_t>(frame_data_.size());
5242f18b292ff155af7df35930474857b507dbf18feTony Barbour
5252f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkDescriptorPoolCreateInfo desc_pool_info = {};
5262f18b292ff155af7df35930474857b507dbf18feTony Barbour    desc_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
52720f5fc0adf53b1f48373ce4e40c745b0d67ebe44Dustin Graves    desc_pool_info.maxSets = static_cast<uint32_t>(frame_data_.size());
5282f18b292ff155af7df35930474857b507dbf18feTony Barbour    desc_pool_info.poolSizeCount = 1;
5292f18b292ff155af7df35930474857b507dbf18feTony Barbour    desc_pool_info.pPoolSizes = &desc_pool_size;
5302f18b292ff155af7df35930474857b507dbf18feTony Barbour
5312f18b292ff155af7df35930474857b507dbf18feTony Barbour    // create descriptor pool
5322f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::assert_success(vk::CreateDescriptorPool(dev_, &desc_pool_info,
5332f18b292ff155af7df35930474857b507dbf18feTony Barbour                nullptr, &desc_pool_));
5342f18b292ff155af7df35930474857b507dbf18feTony Barbour
5352f18b292ff155af7df35930474857b507dbf18feTony Barbour    std::vector<VkDescriptorSetLayout> set_layouts(frame_data_.size(), desc_set_layout_);
5362f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkDescriptorSetAllocateInfo set_info = {};
5372f18b292ff155af7df35930474857b507dbf18feTony Barbour    set_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
5382f18b292ff155af7df35930474857b507dbf18feTony Barbour    set_info.descriptorPool = desc_pool_;
5392f18b292ff155af7df35930474857b507dbf18feTony Barbour    set_info.descriptorSetCount = static_cast<uint32_t>(set_layouts.size());
5402f18b292ff155af7df35930474857b507dbf18feTony Barbour    set_info.pSetLayouts = set_layouts.data();
5412f18b292ff155af7df35930474857b507dbf18feTony Barbour
5422f18b292ff155af7df35930474857b507dbf18feTony Barbour    // create descriptor sets
5432f18b292ff155af7df35930474857b507dbf18feTony Barbour    std::vector<VkDescriptorSet> desc_sets(frame_data_.size(), VK_NULL_HANDLE);
5442f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::assert_success(vk::AllocateDescriptorSets(dev_, &set_info, desc_sets.data()));
5452f18b292ff155af7df35930474857b507dbf18feTony Barbour
5462f18b292ff155af7df35930474857b507dbf18feTony Barbour    std::vector<VkDescriptorBufferInfo> desc_bufs(frame_data_.size());
5472f18b292ff155af7df35930474857b507dbf18feTony Barbour    std::vector<VkWriteDescriptorSet> desc_writes(frame_data_.size());
5482f18b292ff155af7df35930474857b507dbf18feTony Barbour
5492f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (size_t i = 0; i < frame_data_.size(); i++) {
5502f18b292ff155af7df35930474857b507dbf18feTony Barbour        auto &data = frame_data_[i];
5512f18b292ff155af7df35930474857b507dbf18feTony Barbour
5522f18b292ff155af7df35930474857b507dbf18feTony Barbour        data.desc_set = desc_sets[i];
5532f18b292ff155af7df35930474857b507dbf18feTony Barbour
5542f18b292ff155af7df35930474857b507dbf18feTony Barbour        VkDescriptorBufferInfo desc_buf = {};
5552f18b292ff155af7df35930474857b507dbf18feTony Barbour        desc_buf.buffer = data.buf;
5562f18b292ff155af7df35930474857b507dbf18feTony Barbour        desc_buf.offset = 0;
5572f18b292ff155af7df35930474857b507dbf18feTony Barbour        desc_buf.range = VK_WHOLE_SIZE;
5582f18b292ff155af7df35930474857b507dbf18feTony Barbour        desc_bufs[i] = desc_buf;
5592f18b292ff155af7df35930474857b507dbf18feTony Barbour
5602f18b292ff155af7df35930474857b507dbf18feTony Barbour        VkWriteDescriptorSet desc_write = {};
5612f18b292ff155af7df35930474857b507dbf18feTony Barbour        desc_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
5622f18b292ff155af7df35930474857b507dbf18feTony Barbour        desc_write.dstSet = data.desc_set;
5632f18b292ff155af7df35930474857b507dbf18feTony Barbour        desc_write.dstBinding = 0;
5642f18b292ff155af7df35930474857b507dbf18feTony Barbour        desc_write.dstArrayElement = 0;
5652f18b292ff155af7df35930474857b507dbf18feTony Barbour        desc_write.descriptorCount = 1;
5662f18b292ff155af7df35930474857b507dbf18feTony Barbour        desc_write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
5672f18b292ff155af7df35930474857b507dbf18feTony Barbour        desc_write.pBufferInfo = &desc_bufs[i];
5682f18b292ff155af7df35930474857b507dbf18feTony Barbour        desc_writes[i] = desc_write;
5692f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
5702f18b292ff155af7df35930474857b507dbf18feTony Barbour
5712f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::UpdateDescriptorSets(dev_,
5722f18b292ff155af7df35930474857b507dbf18feTony Barbour            static_cast<uint32_t>(desc_writes.size()),
5732f18b292ff155af7df35930474857b507dbf18feTony Barbour            desc_writes.data(), 0, nullptr);
5742f18b292ff155af7df35930474857b507dbf18feTony Barbour}
5752f18b292ff155af7df35930474857b507dbf18feTony Barbour
5762f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::attach_swapchain()
5772f18b292ff155af7df35930474857b507dbf18feTony Barbour{
5782f18b292ff155af7df35930474857b507dbf18feTony Barbour    const Shell::Context &ctx = shell_->context();
5792f18b292ff155af7df35930474857b507dbf18feTony Barbour
5802f18b292ff155af7df35930474857b507dbf18feTony Barbour    prepare_viewport(ctx.extent);
5812f18b292ff155af7df35930474857b507dbf18feTony Barbour    prepare_framebuffers(ctx.swapchain);
5822f18b292ff155af7df35930474857b507dbf18feTony Barbour
5832f18b292ff155af7df35930474857b507dbf18feTony Barbour    update_camera();
5842f18b292ff155af7df35930474857b507dbf18feTony Barbour}
5852f18b292ff155af7df35930474857b507dbf18feTony Barbour
5862f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::detach_swapchain()
5872f18b292ff155af7df35930474857b507dbf18feTony Barbour{
5882f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (auto fb : framebuffers_)
5892f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::DestroyFramebuffer(dev_, fb, nullptr);
5902f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (auto view : image_views_)
5912f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::DestroyImageView(dev_, view, nullptr);
5922f18b292ff155af7df35930474857b507dbf18feTony Barbour
5932f18b292ff155af7df35930474857b507dbf18feTony Barbour    framebuffers_.clear();
5942f18b292ff155af7df35930474857b507dbf18feTony Barbour    image_views_.clear();
5952f18b292ff155af7df35930474857b507dbf18feTony Barbour    images_.clear();
5962f18b292ff155af7df35930474857b507dbf18feTony Barbour}
5972f18b292ff155af7df35930474857b507dbf18feTony Barbour
5982f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::prepare_viewport(const VkExtent2D &extent)
5992f18b292ff155af7df35930474857b507dbf18feTony Barbour{
6002f18b292ff155af7df35930474857b507dbf18feTony Barbour    extent_ = extent;
6012f18b292ff155af7df35930474857b507dbf18feTony Barbour
6022f18b292ff155af7df35930474857b507dbf18feTony Barbour    viewport_.x = 0.0f;
6032f18b292ff155af7df35930474857b507dbf18feTony Barbour    viewport_.y = 0.0f;
6042f18b292ff155af7df35930474857b507dbf18feTony Barbour    viewport_.width = static_cast<float>(extent.width);
6052f18b292ff155af7df35930474857b507dbf18feTony Barbour    viewport_.height = static_cast<float>(extent.height);
6062f18b292ff155af7df35930474857b507dbf18feTony Barbour    viewport_.minDepth = 0.0f;
6072f18b292ff155af7df35930474857b507dbf18feTony Barbour    viewport_.maxDepth = 1.0f;
6082f18b292ff155af7df35930474857b507dbf18feTony Barbour
6092f18b292ff155af7df35930474857b507dbf18feTony Barbour    scissor_.offset = { 0, 0 };
6102f18b292ff155af7df35930474857b507dbf18feTony Barbour    scissor_.extent = extent_;
6112f18b292ff155af7df35930474857b507dbf18feTony Barbour}
6122f18b292ff155af7df35930474857b507dbf18feTony Barbour
6132f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::prepare_framebuffers(VkSwapchainKHR swapchain)
6142f18b292ff155af7df35930474857b507dbf18feTony Barbour{
6152f18b292ff155af7df35930474857b507dbf18feTony Barbour    // get swapchain images
6162f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::get(dev_, swapchain, images_);
6172f18b292ff155af7df35930474857b507dbf18feTony Barbour
6182f18b292ff155af7df35930474857b507dbf18feTony Barbour    assert(framebuffers_.empty());
6192f18b292ff155af7df35930474857b507dbf18feTony Barbour    image_views_.reserve(images_.size());
6202f18b292ff155af7df35930474857b507dbf18feTony Barbour    framebuffers_.reserve(images_.size());
6212f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (auto img : images_) {
6222f18b292ff155af7df35930474857b507dbf18feTony Barbour        VkImageViewCreateInfo view_info = {};
6232f18b292ff155af7df35930474857b507dbf18feTony Barbour        view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
6242f18b292ff155af7df35930474857b507dbf18feTony Barbour        view_info.image = img;
6252f18b292ff155af7df35930474857b507dbf18feTony Barbour        view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
6262f18b292ff155af7df35930474857b507dbf18feTony Barbour        view_info.format = format_;
6272f18b292ff155af7df35930474857b507dbf18feTony Barbour        view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
6282f18b292ff155af7df35930474857b507dbf18feTony Barbour        view_info.subresourceRange.levelCount = 1;
6292f18b292ff155af7df35930474857b507dbf18feTony Barbour        view_info.subresourceRange.layerCount = 1;
6302f18b292ff155af7df35930474857b507dbf18feTony Barbour
6312f18b292ff155af7df35930474857b507dbf18feTony Barbour        VkImageView view;
6322f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::assert_success(vk::CreateImageView(dev_, &view_info, nullptr, &view));
6332f18b292ff155af7df35930474857b507dbf18feTony Barbour        image_views_.push_back(view);
6342f18b292ff155af7df35930474857b507dbf18feTony Barbour
6352f18b292ff155af7df35930474857b507dbf18feTony Barbour        VkFramebufferCreateInfo fb_info = {};
6362f18b292ff155af7df35930474857b507dbf18feTony Barbour        fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
6372f18b292ff155af7df35930474857b507dbf18feTony Barbour        fb_info.renderPass = render_pass_;
6382f18b292ff155af7df35930474857b507dbf18feTony Barbour        fb_info.attachmentCount = 1;
6392f18b292ff155af7df35930474857b507dbf18feTony Barbour        fb_info.pAttachments = &view;
6402f18b292ff155af7df35930474857b507dbf18feTony Barbour        fb_info.width = extent_.width;
6412f18b292ff155af7df35930474857b507dbf18feTony Barbour        fb_info.height = extent_.height;
6422f18b292ff155af7df35930474857b507dbf18feTony Barbour        fb_info.layers = 1;
6432f18b292ff155af7df35930474857b507dbf18feTony Barbour
6442f18b292ff155af7df35930474857b507dbf18feTony Barbour        VkFramebuffer fb;
6452f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::assert_success(vk::CreateFramebuffer(dev_, &fb_info, nullptr, &fb));
6462f18b292ff155af7df35930474857b507dbf18feTony Barbour        framebuffers_.push_back(fb);
6472f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
6482f18b292ff155af7df35930474857b507dbf18feTony Barbour}
6492f18b292ff155af7df35930474857b507dbf18feTony Barbour
6502f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::update_camera()
6512f18b292ff155af7df35930474857b507dbf18feTony Barbour{
6522f18b292ff155af7df35930474857b507dbf18feTony Barbour    const glm::vec3 center(0.0f);
6532f18b292ff155af7df35930474857b507dbf18feTony Barbour    const glm::vec3 up(0.f, 0.0f, 1.0f);
6542f18b292ff155af7df35930474857b507dbf18feTony Barbour    const glm::mat4 view = glm::lookAt(camera_.eye_pos, center, up);
6552f18b292ff155af7df35930474857b507dbf18feTony Barbour
6562f18b292ff155af7df35930474857b507dbf18feTony Barbour    float aspect = static_cast<float>(extent_.width) / static_cast<float>(extent_.height);
6572f18b292ff155af7df35930474857b507dbf18feTony Barbour    const glm::mat4 projection = glm::perspective(0.4f, aspect, 0.1f, 100.0f);
6582f18b292ff155af7df35930474857b507dbf18feTony Barbour
6592f18b292ff155af7df35930474857b507dbf18feTony Barbour    // Vulkan clip space has inverted Y and half Z.
6602f18b292ff155af7df35930474857b507dbf18feTony Barbour    const glm::mat4 clip(1.0f,  0.0f, 0.0f, 0.0f,
6612f18b292ff155af7df35930474857b507dbf18feTony Barbour                         0.0f, -1.0f, 0.0f, 0.0f,
6622f18b292ff155af7df35930474857b507dbf18feTony Barbour                         0.0f,  0.0f, 0.5f, 0.0f,
6632f18b292ff155af7df35930474857b507dbf18feTony Barbour                         0.0f,  0.0f, 0.5f, 1.0f);
6642f18b292ff155af7df35930474857b507dbf18feTony Barbour
6652f18b292ff155af7df35930474857b507dbf18feTony Barbour    camera_.view_projection = clip * projection * view;
6662f18b292ff155af7df35930474857b507dbf18feTony Barbour}
6672f18b292ff155af7df35930474857b507dbf18feTony Barbour
6682f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::draw_object(const Simulation::Object &obj, FrameData &data, VkCommandBuffer cmd) const
6692f18b292ff155af7df35930474857b507dbf18feTony Barbour{
6702f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (use_push_constants_) {
6712f18b292ff155af7df35930474857b507dbf18feTony Barbour        ShaderParamBlock params;
6722f18b292ff155af7df35930474857b507dbf18feTony Barbour        memcpy(params.light_pos, glm::value_ptr(obj.light_pos), sizeof(obj.light_pos));
6732f18b292ff155af7df35930474857b507dbf18feTony Barbour        memcpy(params.light_color, glm::value_ptr(obj.light_color), sizeof(obj.light_color));
6742f18b292ff155af7df35930474857b507dbf18feTony Barbour        memcpy(params.model, glm::value_ptr(obj.model), sizeof(obj.model));
6752f18b292ff155af7df35930474857b507dbf18feTony Barbour        memcpy(params.view_projection, glm::value_ptr(camera_.view_projection), sizeof(camera_.view_projection));
6762f18b292ff155af7df35930474857b507dbf18feTony Barbour
6772f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::CmdPushConstants(cmd, pipeline_layout_, VK_SHADER_STAGE_VERTEX_BIT,
6782f18b292ff155af7df35930474857b507dbf18feTony Barbour                0, sizeof(params), &params);
6792f18b292ff155af7df35930474857b507dbf18feTony Barbour    } else {
6802f18b292ff155af7df35930474857b507dbf18feTony Barbour        ShaderParamBlock *params =
6812f18b292ff155af7df35930474857b507dbf18feTony Barbour            reinterpret_cast<ShaderParamBlock *>(data.base + obj.frame_data_offset);
6822f18b292ff155af7df35930474857b507dbf18feTony Barbour        memcpy(params->light_pos, glm::value_ptr(obj.light_pos), sizeof(obj.light_pos));
6832f18b292ff155af7df35930474857b507dbf18feTony Barbour        memcpy(params->light_color, glm::value_ptr(obj.light_color), sizeof(obj.light_color));
6842f18b292ff155af7df35930474857b507dbf18feTony Barbour        memcpy(params->model, glm::value_ptr(obj.model), sizeof(obj.model));
6852f18b292ff155af7df35930474857b507dbf18feTony Barbour        memcpy(params->view_projection, glm::value_ptr(camera_.view_projection), sizeof(camera_.view_projection));
6862f18b292ff155af7df35930474857b507dbf18feTony Barbour
6872f18b292ff155af7df35930474857b507dbf18feTony Barbour        vk::CmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS,
6882f18b292ff155af7df35930474857b507dbf18feTony Barbour                pipeline_layout_, 0, 1, &data.desc_set, 1, &obj.frame_data_offset);
6892f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
6902f18b292ff155af7df35930474857b507dbf18feTony Barbour
6912f18b292ff155af7df35930474857b507dbf18feTony Barbour    meshes_->cmd_draw(cmd, obj.mesh);
6922f18b292ff155af7df35930474857b507dbf18feTony Barbour}
6932f18b292ff155af7df35930474857b507dbf18feTony Barbour
6942f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::update_simulation(const Worker &worker)
6952f18b292ff155af7df35930474857b507dbf18feTony Barbour{
6962f18b292ff155af7df35930474857b507dbf18feTony Barbour    sim_.update(worker.tick_interval_, worker.object_begin_, worker.object_end_);
6972f18b292ff155af7df35930474857b507dbf18feTony Barbour}
6982f18b292ff155af7df35930474857b507dbf18feTony Barbour
6992f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::draw_objects(Worker &worker)
7002f18b292ff155af7df35930474857b507dbf18feTony Barbour{
7012f18b292ff155af7df35930474857b507dbf18feTony Barbour    auto &data = frame_data_[frame_data_index_];
7022f18b292ff155af7df35930474857b507dbf18feTony Barbour    auto cmd = data.worker_cmds[worker.index_];
7032f18b292ff155af7df35930474857b507dbf18feTony Barbour
7042f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkCommandBufferInheritanceInfo inherit_info = {};
7052f18b292ff155af7df35930474857b507dbf18feTony Barbour    inherit_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
7062f18b292ff155af7df35930474857b507dbf18feTony Barbour    inherit_info.renderPass = render_pass_;
7072f18b292ff155af7df35930474857b507dbf18feTony Barbour    inherit_info.framebuffer = worker.fb_;
7082f18b292ff155af7df35930474857b507dbf18feTony Barbour
7092f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkCommandBufferBeginInfo begin_info = {};
7102f18b292ff155af7df35930474857b507dbf18feTony Barbour    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
7112f18b292ff155af7df35930474857b507dbf18feTony Barbour    begin_info.flags = VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
7122f18b292ff155af7df35930474857b507dbf18feTony Barbour    begin_info.pInheritanceInfo = &inherit_info;
7132f18b292ff155af7df35930474857b507dbf18feTony Barbour
7142f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::BeginCommandBuffer(cmd, &begin_info);
7152f18b292ff155af7df35930474857b507dbf18feTony Barbour
7162f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::CmdSetViewport(cmd, 0, 1, &viewport_);
7172f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::CmdSetScissor(cmd, 0, 1, &scissor_);
7182f18b292ff155af7df35930474857b507dbf18feTony Barbour
7192f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::CmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_);
7202f18b292ff155af7df35930474857b507dbf18feTony Barbour
7212f18b292ff155af7df35930474857b507dbf18feTony Barbour    meshes_->cmd_bind_buffers(cmd);
7222f18b292ff155af7df35930474857b507dbf18feTony Barbour
7232f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (int i = worker.object_begin_; i < worker.object_end_; i++) {
7242f18b292ff155af7df35930474857b507dbf18feTony Barbour        auto &obj = sim_.objects()[i];
7252f18b292ff155af7df35930474857b507dbf18feTony Barbour
7262f18b292ff155af7df35930474857b507dbf18feTony Barbour        draw_object(obj, data, cmd);
7272f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
7282f18b292ff155af7df35930474857b507dbf18feTony Barbour
7292f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::EndCommandBuffer(cmd);
7302f18b292ff155af7df35930474857b507dbf18feTony Barbour}
7312f18b292ff155af7df35930474857b507dbf18feTony Barbour
7322f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::on_key(Key key)
7332f18b292ff155af7df35930474857b507dbf18feTony Barbour{
7342f18b292ff155af7df35930474857b507dbf18feTony Barbour    switch (key) {
7352f18b292ff155af7df35930474857b507dbf18feTony Barbour    case KEY_SHUTDOWN:
7362f18b292ff155af7df35930474857b507dbf18feTony Barbour    case KEY_ESC:
7372f18b292ff155af7df35930474857b507dbf18feTony Barbour        shell_->quit();
7382f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
7392f18b292ff155af7df35930474857b507dbf18feTony Barbour    case KEY_UP:
7402f18b292ff155af7df35930474857b507dbf18feTony Barbour        camera_.eye_pos -= glm::vec3(0.05f);
7412f18b292ff155af7df35930474857b507dbf18feTony Barbour        update_camera();
7422f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
7432f18b292ff155af7df35930474857b507dbf18feTony Barbour    case KEY_DOWN:
7442f18b292ff155af7df35930474857b507dbf18feTony Barbour        camera_.eye_pos += glm::vec3(0.05f);
7452f18b292ff155af7df35930474857b507dbf18feTony Barbour        update_camera();
7462f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
7472f18b292ff155af7df35930474857b507dbf18feTony Barbour    case KEY_SPACE:
7482f18b292ff155af7df35930474857b507dbf18feTony Barbour        sim_paused_ = !sim_paused_;
7492f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
7502f18b292ff155af7df35930474857b507dbf18feTony Barbour    default:
7512f18b292ff155af7df35930474857b507dbf18feTony Barbour        break;
7522f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
7532f18b292ff155af7df35930474857b507dbf18feTony Barbour}
7542f18b292ff155af7df35930474857b507dbf18feTony Barbour
7552f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::on_tick()
7562f18b292ff155af7df35930474857b507dbf18feTony Barbour{
7572f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (sim_paused_)
7582f18b292ff155af7df35930474857b507dbf18feTony Barbour        return;
7592f18b292ff155af7df35930474857b507dbf18feTony Barbour
7602f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (auto &worker : workers_)
7612f18b292ff155af7df35930474857b507dbf18feTony Barbour        worker->update_simulation();
7622f18b292ff155af7df35930474857b507dbf18feTony Barbour}
7632f18b292ff155af7df35930474857b507dbf18feTony Barbour
7642f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::on_frame(float frame_pred)
7652f18b292ff155af7df35930474857b507dbf18feTony Barbour{
7662f18b292ff155af7df35930474857b507dbf18feTony Barbour    auto &data = frame_data_[frame_data_index_];
7672f18b292ff155af7df35930474857b507dbf18feTony Barbour
7682f18b292ff155af7df35930474857b507dbf18feTony Barbour    // wait for the last submission since we reuse frame data
7692f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::assert_success(vk::WaitForFences(dev_, 1, &data.fence, true, UINT64_MAX));
7702f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::assert_success(vk::ResetFences(dev_, 1, &data.fence));
7712f18b292ff155af7df35930474857b507dbf18feTony Barbour
7722f18b292ff155af7df35930474857b507dbf18feTony Barbour    const Shell::BackBuffer &back = shell_->context().acquired_back_buffer;
7732f18b292ff155af7df35930474857b507dbf18feTony Barbour
7742f18b292ff155af7df35930474857b507dbf18feTony Barbour    // ignore frame_pred
7752f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (auto &worker : workers_)
7762f18b292ff155af7df35930474857b507dbf18feTony Barbour        worker->draw_objects(framebuffers_[back.image_index]);
7772f18b292ff155af7df35930474857b507dbf18feTony Barbour
7782f18b292ff155af7df35930474857b507dbf18feTony Barbour    VkResult res = vk::BeginCommandBuffer(data.primary_cmd, &primary_cmd_begin_info_);
7792f18b292ff155af7df35930474857b507dbf18feTony Barbour
7805122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz    if (!use_push_constants_) {
7815122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz        VkBufferMemoryBarrier buf_barrier = {};
7825122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz        buf_barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
7835122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz        buf_barrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
7845122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz        buf_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
7855122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz        buf_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
7865122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz        buf_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
7875122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz        buf_barrier.buffer = data.buf;
7885122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz        buf_barrier.offset = 0;
7895122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz        buf_barrier.size = VK_WHOLE_SIZE;
7905122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz        vk::CmdPipelineBarrier(data.primary_cmd,
7915122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz                               VK_PIPELINE_STAGE_HOST_BIT,
7925122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz                               VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
7935122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz                               0, 0, nullptr, 1, &buf_barrier, 0, nullptr);
7945122cb1ddc48c8a98d4f5d4dc94f21aa92a3929cKarl Schultz    }
7952f18b292ff155af7df35930474857b507dbf18feTony Barbour
7962f18b292ff155af7df35930474857b507dbf18feTony Barbour    render_pass_begin_info_.framebuffer = framebuffers_[back.image_index];
7972f18b292ff155af7df35930474857b507dbf18feTony Barbour    render_pass_begin_info_.renderArea.extent = extent_;
7982f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::CmdBeginRenderPass(data.primary_cmd, &render_pass_begin_info_,
7992f18b292ff155af7df35930474857b507dbf18feTony Barbour            VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS);
8002f18b292ff155af7df35930474857b507dbf18feTony Barbour
8012f18b292ff155af7df35930474857b507dbf18feTony Barbour    // record render pass commands
8022f18b292ff155af7df35930474857b507dbf18feTony Barbour    for (auto &worker : workers_)
8032f18b292ff155af7df35930474857b507dbf18feTony Barbour        worker->wait_idle();
8042f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::CmdExecuteCommands(data.primary_cmd,
8052f18b292ff155af7df35930474857b507dbf18feTony Barbour            static_cast<uint32_t>(data.worker_cmds.size()),
8062f18b292ff155af7df35930474857b507dbf18feTony Barbour            data.worker_cmds.data());
8072f18b292ff155af7df35930474857b507dbf18feTony Barbour
8082f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::CmdEndRenderPass(data.primary_cmd);
8092f18b292ff155af7df35930474857b507dbf18feTony Barbour    vk::EndCommandBuffer(data.primary_cmd);
8102f18b292ff155af7df35930474857b507dbf18feTony Barbour
8112f18b292ff155af7df35930474857b507dbf18feTony Barbour    // wait for the image to be owned and signal for render completion
8122f18b292ff155af7df35930474857b507dbf18feTony Barbour    primary_cmd_submit_info_.pWaitSemaphores = &back.acquire_semaphore;
8132f18b292ff155af7df35930474857b507dbf18feTony Barbour    primary_cmd_submit_info_.pCommandBuffers = &data.primary_cmd;
8142f18b292ff155af7df35930474857b507dbf18feTony Barbour    primary_cmd_submit_info_.pSignalSemaphores = &back.render_semaphore;
8152f18b292ff155af7df35930474857b507dbf18feTony Barbour
8162f18b292ff155af7df35930474857b507dbf18feTony Barbour    res = vk::QueueSubmit(queue_, 1, &primary_cmd_submit_info_, data.fence);
8172f18b292ff155af7df35930474857b507dbf18feTony Barbour
8182f18b292ff155af7df35930474857b507dbf18feTony Barbour    frame_data_index_ = (frame_data_index_ + 1) % frame_data_.size();
8192f18b292ff155af7df35930474857b507dbf18feTony Barbour
8202f18b292ff155af7df35930474857b507dbf18feTony Barbour    (void) res;
8212f18b292ff155af7df35930474857b507dbf18feTony Barbour}
8222f18b292ff155af7df35930474857b507dbf18feTony Barbour
8232f18b292ff155af7df35930474857b507dbf18feTony BarbourSmoke::Worker::Worker(Smoke &smoke, int index, int object_begin, int object_end)
8242f18b292ff155af7df35930474857b507dbf18feTony Barbour    : smoke_(smoke), index_(index),
8252f18b292ff155af7df35930474857b507dbf18feTony Barbour      object_begin_(object_begin), object_end_(object_end),
8262f18b292ff155af7df35930474857b507dbf18feTony Barbour      tick_interval_(1.0f / smoke.settings_.ticks_per_second), state_(INIT)
8272f18b292ff155af7df35930474857b507dbf18feTony Barbour{
8282f18b292ff155af7df35930474857b507dbf18feTony Barbour}
8292f18b292ff155af7df35930474857b507dbf18feTony Barbour
8302f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::Worker::start()
8312f18b292ff155af7df35930474857b507dbf18feTony Barbour{
8322f18b292ff155af7df35930474857b507dbf18feTony Barbour    state_ = IDLE;
8332f18b292ff155af7df35930474857b507dbf18feTony Barbour    thread_ = std::thread(Smoke::Worker::thread_loop, this);
8342f18b292ff155af7df35930474857b507dbf18feTony Barbour}
8352f18b292ff155af7df35930474857b507dbf18feTony Barbour
8362f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::Worker::stop()
8372f18b292ff155af7df35930474857b507dbf18feTony Barbour{
8382f18b292ff155af7df35930474857b507dbf18feTony Barbour    {
8392f18b292ff155af7df35930474857b507dbf18feTony Barbour        std::lock_guard<std::mutex> lock(mutex_);
8402f18b292ff155af7df35930474857b507dbf18feTony Barbour        state_ = INIT;
8412f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
8422f18b292ff155af7df35930474857b507dbf18feTony Barbour    state_cv_.notify_one();
8432f18b292ff155af7df35930474857b507dbf18feTony Barbour
8442f18b292ff155af7df35930474857b507dbf18feTony Barbour    thread_.join();
8452f18b292ff155af7df35930474857b507dbf18feTony Barbour}
8462f18b292ff155af7df35930474857b507dbf18feTony Barbour
8472f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::Worker::update_simulation()
8482f18b292ff155af7df35930474857b507dbf18feTony Barbour{
8492f18b292ff155af7df35930474857b507dbf18feTony Barbour    {
8502f18b292ff155af7df35930474857b507dbf18feTony Barbour        std::lock_guard<std::mutex> lock(mutex_);
8512f18b292ff155af7df35930474857b507dbf18feTony Barbour        bool started = (state_ != INIT);
8522f18b292ff155af7df35930474857b507dbf18feTony Barbour
8532f18b292ff155af7df35930474857b507dbf18feTony Barbour        state_ = STEP;
8542f18b292ff155af7df35930474857b507dbf18feTony Barbour
8552f18b292ff155af7df35930474857b507dbf18feTony Barbour        // step directly
8562f18b292ff155af7df35930474857b507dbf18feTony Barbour        if (!started) {
8572f18b292ff155af7df35930474857b507dbf18feTony Barbour            smoke_.update_simulation(*this);
8582f18b292ff155af7df35930474857b507dbf18feTony Barbour            state_ = INIT;
8592f18b292ff155af7df35930474857b507dbf18feTony Barbour        }
8602f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
8612f18b292ff155af7df35930474857b507dbf18feTony Barbour    state_cv_.notify_one();
8622f18b292ff155af7df35930474857b507dbf18feTony Barbour}
8632f18b292ff155af7df35930474857b507dbf18feTony Barbour
8642f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::Worker::draw_objects(VkFramebuffer fb)
8652f18b292ff155af7df35930474857b507dbf18feTony Barbour{
8662f18b292ff155af7df35930474857b507dbf18feTony Barbour    // wait for step_objects first
8672f18b292ff155af7df35930474857b507dbf18feTony Barbour    wait_idle();
8682f18b292ff155af7df35930474857b507dbf18feTony Barbour
8692f18b292ff155af7df35930474857b507dbf18feTony Barbour    {
8702f18b292ff155af7df35930474857b507dbf18feTony Barbour        std::lock_guard<std::mutex> lock(mutex_);
8712f18b292ff155af7df35930474857b507dbf18feTony Barbour        bool started = (state_ != INIT);
8722f18b292ff155af7df35930474857b507dbf18feTony Barbour
8732f18b292ff155af7df35930474857b507dbf18feTony Barbour        fb_ = fb;
8742f18b292ff155af7df35930474857b507dbf18feTony Barbour        state_ = DRAW;
8752f18b292ff155af7df35930474857b507dbf18feTony Barbour
8762f18b292ff155af7df35930474857b507dbf18feTony Barbour        // render directly
8772f18b292ff155af7df35930474857b507dbf18feTony Barbour        if (!started) {
8782f18b292ff155af7df35930474857b507dbf18feTony Barbour            smoke_.draw_objects(*this);
8792f18b292ff155af7df35930474857b507dbf18feTony Barbour            state_ = INIT;
8802f18b292ff155af7df35930474857b507dbf18feTony Barbour        }
8812f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
8822f18b292ff155af7df35930474857b507dbf18feTony Barbour    state_cv_.notify_one();
8832f18b292ff155af7df35930474857b507dbf18feTony Barbour}
8842f18b292ff155af7df35930474857b507dbf18feTony Barbour
8852f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::Worker::wait_idle()
8862f18b292ff155af7df35930474857b507dbf18feTony Barbour{
8872f18b292ff155af7df35930474857b507dbf18feTony Barbour    std::unique_lock<std::mutex> lock(mutex_);
8882f18b292ff155af7df35930474857b507dbf18feTony Barbour    bool started = (state_ != INIT);
8892f18b292ff155af7df35930474857b507dbf18feTony Barbour
8902f18b292ff155af7df35930474857b507dbf18feTony Barbour    if (started)
8912f18b292ff155af7df35930474857b507dbf18feTony Barbour        state_cv_.wait(lock, [this] { return (state_ == IDLE); });
8922f18b292ff155af7df35930474857b507dbf18feTony Barbour}
8932f18b292ff155af7df35930474857b507dbf18feTony Barbour
8942f18b292ff155af7df35930474857b507dbf18feTony Barbourvoid Smoke::Worker::update_loop()
8952f18b292ff155af7df35930474857b507dbf18feTony Barbour{
8962f18b292ff155af7df35930474857b507dbf18feTony Barbour    while (true) {
8972f18b292ff155af7df35930474857b507dbf18feTony Barbour        std::unique_lock<std::mutex> lock(mutex_);
8982f18b292ff155af7df35930474857b507dbf18feTony Barbour
8992f18b292ff155af7df35930474857b507dbf18feTony Barbour        state_cv_.wait(lock, [this] { return (state_ != IDLE); });
9002f18b292ff155af7df35930474857b507dbf18feTony Barbour        if (state_ == INIT)
9012f18b292ff155af7df35930474857b507dbf18feTony Barbour            break;
9022f18b292ff155af7df35930474857b507dbf18feTony Barbour
9032f18b292ff155af7df35930474857b507dbf18feTony Barbour        assert(state_ == STEP || state_ == DRAW);
9042f18b292ff155af7df35930474857b507dbf18feTony Barbour        if (state_ == STEP)
9052f18b292ff155af7df35930474857b507dbf18feTony Barbour            smoke_.update_simulation(*this);
9062f18b292ff155af7df35930474857b507dbf18feTony Barbour        else
9072f18b292ff155af7df35930474857b507dbf18feTony Barbour            smoke_.draw_objects(*this);
9082f18b292ff155af7df35930474857b507dbf18feTony Barbour
9092f18b292ff155af7df35930474857b507dbf18feTony Barbour        state_ = IDLE;
9102f18b292ff155af7df35930474857b507dbf18feTony Barbour        lock.unlock();
9112f18b292ff155af7df35930474857b507dbf18feTony Barbour        state_cv_.notify_one();
9122f18b292ff155af7df35930474857b507dbf18feTony Barbour    }
9132f18b292ff155af7df35930474857b507dbf18feTony Barbour}
914