demos: Add Hologram snapshot as Smoke test/demo
diff --git a/demos/smoke/Shell.h b/demos/smoke/Shell.h
new file mode 100644
index 0000000..2aa0b6f
--- /dev/null
+++ b/demos/smoke/Shell.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef SHELL_H
+#define SHELL_H
+
+#include <queue>
+#include <vector>
+#include <stdexcept>
+#include <vulkan/vulkan.h>
+
+#include "Game.h"
+
+class Game;
+
+class Shell {
+public:
+    Shell(const Shell &sh) = delete;
+    Shell &operator=(const Shell &sh) = delete;
+    virtual ~Shell() {}
+
+    struct BackBuffer {
+        uint32_t image_index;
+
+        VkSemaphore acquire_semaphore;
+        VkSemaphore render_semaphore;
+
+        // signaled when this struct is ready for reuse
+        VkFence present_fence;
+    };
+
+    struct Context {
+        VkInstance instance;
+        VkDebugReportCallbackEXT debug_report;
+
+        VkPhysicalDevice physical_dev;
+        uint32_t game_queue_family;
+        uint32_t present_queue_family;
+
+        VkDevice dev;
+        VkQueue game_queue;
+        VkQueue present_queue;
+
+        std::queue<BackBuffer> back_buffers;
+
+        VkSurfaceKHR surface;
+        VkSurfaceFormatKHR format;
+
+        VkSwapchainKHR swapchain;
+        VkExtent2D extent;
+
+        BackBuffer acquired_back_buffer;
+    };
+    const Context &context() const { return ctx_; }
+
+    enum LogPriority {
+        LOG_DEBUG,
+        LOG_INFO,
+        LOG_WARN,
+        LOG_ERR,
+    };
+    virtual void log(LogPriority priority, const char *msg);
+
+    virtual void run() = 0;
+    virtual void quit() = 0;
+
+protected:
+    Shell(Game &game);
+
+    void init_vk();
+    void cleanup_vk();
+
+    void create_context();
+    void destroy_context();
+
+    void resize_swapchain(uint32_t width_hint, uint32_t height_hint);
+
+    void add_game_time(float time);
+
+    void acquire_back_buffer();
+    void present_back_buffer();
+
+    Game &game_;
+    const Game::Settings &settings_;
+
+    std::vector<const char *> instance_layers_;
+    std::vector<const char *> instance_extensions_;
+
+    std::vector<const char *> device_layers_;
+    std::vector<const char *> device_extensions_;
+
+private:
+    bool debug_report_callback(VkDebugReportFlagsEXT flags,
+                               VkDebugReportObjectTypeEXT obj_type,
+                               uint64_t object,
+                               size_t location,
+                               int32_t msg_code,
+                               const char *layer_prefix,
+                               const char *msg);
+    static VKAPI_ATTR VkBool32 VKAPI_CALL debug_report_callback(
+                               VkDebugReportFlagsEXT flags,
+                               VkDebugReportObjectTypeEXT obj_type,
+                               uint64_t object,
+                               size_t location,
+                               int32_t msg_code,
+                               const char *layer_prefix,
+                               const char *msg,
+                               void *user_data)
+    {
+        Shell *shell = reinterpret_cast<Shell *>(user_data);
+        return shell->debug_report_callback(flags, obj_type, object, location, msg_code, layer_prefix, msg);
+    }
+
+    void assert_all_instance_layers() const;
+    void assert_all_instance_extensions() const;
+
+    bool has_all_device_layers(VkPhysicalDevice phy) const;
+    bool has_all_device_extensions(VkPhysicalDevice phy) const;
+
+    // called by init_vk
+    virtual PFN_vkGetInstanceProcAddr load_vk() = 0;
+    virtual bool can_present(VkPhysicalDevice phy, uint32_t queue_family) = 0;
+    void init_instance();
+    void init_debug_report();
+    void init_physical_dev();
+
+    // called by create_context
+    void create_dev();
+    void create_back_buffers();
+    void destroy_back_buffers();
+    virtual VkSurfaceKHR create_surface(VkInstance instance) = 0;
+    void create_swapchain();
+    void destroy_swapchain();
+
+    void fake_present();
+
+    Context ctx_;
+
+    const float game_tick_;
+    float game_time_;
+};
+
+#endif // SHELL_H