Home | History | Annotate | Download | only in smoke
      1 /*
      2  * Copyright (C) 2016 Google, Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <cassert>
     18 #include <iostream>
     19 #include <sstream>
     20 
     21 #include "Helpers.h"
     22 #include "Game.h"
     23 #include "ShellWin32.h"
     24 
     25 namespace {
     26 
     27 class Win32Timer {
     28    public:
     29     Win32Timer() {
     30         LARGE_INTEGER freq;
     31         QueryPerformanceFrequency(&freq);
     32         freq_ = static_cast<double>(freq.QuadPart);
     33 
     34         reset();
     35     }
     36 
     37     void reset() { QueryPerformanceCounter(&start_); }
     38 
     39     double get() const {
     40         LARGE_INTEGER now;
     41         QueryPerformanceCounter(&now);
     42 
     43         return static_cast<double>(now.QuadPart - start_.QuadPart) / freq_;
     44     }
     45 
     46    private:
     47     double freq_;
     48     LARGE_INTEGER start_;
     49 };
     50 
     51 }  // namespace
     52 
     53 ShellWin32::ShellWin32(Game &game) : Shell(game), hwnd_(nullptr) {
     54     if (game.settings().validate) instance_layers_.push_back("VK_LAYER_LUNARG_standard_validation");
     55     instance_extensions_.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
     56     init_vk();
     57 }
     58 
     59 ShellWin32::~ShellWin32() {
     60     cleanup_vk();
     61     FreeLibrary(hmodule_);
     62 }
     63 
     64 void ShellWin32::create_window() {
     65     const std::string class_name(settings_.name + "WindowClass");
     66 
     67     hinstance_ = GetModuleHandle(nullptr);
     68 
     69     WNDCLASSEX win_class = {};
     70     win_class.cbSize = sizeof(WNDCLASSEX);
     71     win_class.style = CS_HREDRAW | CS_VREDRAW;
     72     win_class.lpfnWndProc = window_proc;
     73     win_class.hInstance = hinstance_;
     74     win_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
     75     win_class.lpszClassName = class_name.c_str();
     76     RegisterClassEx(&win_class);
     77 
     78     const DWORD win_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE | WS_OVERLAPPEDWINDOW;
     79 
     80     RECT win_rect = {0, 0, settings_.initial_width, settings_.initial_height};
     81     AdjustWindowRect(&win_rect, win_style, false);
     82 
     83     hwnd_ = CreateWindowEx(WS_EX_APPWINDOW, class_name.c_str(), settings_.name.c_str(), win_style, 0, 0,
     84                            win_rect.right - win_rect.left, win_rect.bottom - win_rect.top, nullptr, nullptr, hinstance_, nullptr);
     85 
     86     SetForegroundWindow(hwnd_);
     87     SetWindowLongPtr(hwnd_, GWLP_USERDATA, (LONG_PTR) this);
     88 }
     89 
     90 PFN_vkGetInstanceProcAddr ShellWin32::load_vk() {
     91     const char filename[] = "vulkan-1.dll";
     92     HMODULE mod;
     93     PFN_vkGetInstanceProcAddr get_proc = NULL;
     94 
     95     mod = LoadLibrary(filename);
     96     if (mod) {
     97         get_proc = reinterpret_cast<PFN_vkGetInstanceProcAddr>(GetProcAddress(mod, "vkGetInstanceProcAddr"));
     98     }
     99 
    100     if (!mod || !get_proc) {
    101         std::stringstream ss;
    102         ss << "failed to load " << filename;
    103 
    104         if (mod) FreeLibrary(mod);
    105 
    106         throw std::runtime_error(ss.str());
    107     }
    108 
    109     hmodule_ = mod;
    110 
    111     return get_proc;
    112 }
    113 
    114 bool ShellWin32::can_present(VkPhysicalDevice phy, uint32_t queue_family) {
    115     return vk::GetPhysicalDeviceWin32PresentationSupportKHR(phy, queue_family) == VK_TRUE;
    116 }
    117 
    118 VkSurfaceKHR ShellWin32::create_surface(VkInstance instance) {
    119     VkWin32SurfaceCreateInfoKHR surface_info = {};
    120     surface_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
    121     surface_info.hinstance = hinstance_;
    122     surface_info.hwnd = hwnd_;
    123 
    124     VkSurfaceKHR surface;
    125     vk::assert_success(vk::CreateWin32SurfaceKHR(instance, &surface_info, nullptr, &surface));
    126 
    127     return surface;
    128 }
    129 
    130 LRESULT ShellWin32::handle_message(UINT msg, WPARAM wparam, LPARAM lparam) {
    131     switch (msg) {
    132         case WM_SIZE: {
    133             UINT w = LOWORD(lparam);
    134             UINT h = HIWORD(lparam);
    135             resize_swapchain(w, h);
    136         } break;
    137         case WM_KEYDOWN: {
    138             Game::Key key;
    139 
    140             switch (wparam) {
    141                 case VK_ESCAPE:
    142                     key = Game::KEY_ESC;
    143                     break;
    144                 case VK_UP:
    145                     key = Game::KEY_UP;
    146                     break;
    147                 case VK_DOWN:
    148                     key = Game::KEY_DOWN;
    149                     break;
    150                 case VK_SPACE:
    151                     key = Game::KEY_SPACE;
    152                     break;
    153                 default:
    154                     key = Game::KEY_UNKNOWN;
    155                     break;
    156             }
    157 
    158             game_.on_key(key);
    159         } break;
    160         case WM_CLOSE:
    161             game_.on_key(Game::KEY_SHUTDOWN);
    162             break;
    163         case WM_DESTROY:
    164             quit();
    165             break;
    166         default:
    167             return DefWindowProc(hwnd_, msg, wparam, lparam);
    168             break;
    169     }
    170 
    171     return 0;
    172 }
    173 
    174 void ShellWin32::quit() { PostQuitMessage(0); }
    175 
    176 void ShellWin32::run() {
    177     create_window();
    178 
    179     create_context();
    180     resize_swapchain(settings_.initial_width, settings_.initial_height);
    181 
    182     Win32Timer timer;
    183     double current_time = timer.get();
    184 
    185     while (true) {
    186         bool quit = false;
    187 
    188         assert(settings_.animate);
    189 
    190         // process all messages
    191         MSG msg;
    192         while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
    193             if (msg.message == WM_QUIT) {
    194                 quit = true;
    195                 break;
    196             }
    197 
    198             TranslateMessage(&msg);
    199             DispatchMessage(&msg);
    200         }
    201 
    202         if (quit) break;
    203 
    204         acquire_back_buffer();
    205 
    206         double t = timer.get();
    207         add_game_time(static_cast<float>(t - current_time));
    208 
    209         present_back_buffer();
    210 
    211         current_time = t;
    212     }
    213 
    214     destroy_context();
    215 
    216     DestroyWindow(hwnd_);
    217 }
    218