• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
Win32Timer()29     Win32Timer() {
30         LARGE_INTEGER freq;
31         QueryPerformanceFrequency(&freq);
32         freq_ = static_cast<double>(freq.QuadPart);
33 
34         reset();
35     }
36 
reset()37     void reset() { QueryPerformanceCounter(&start_); }
38 
get() const39     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 
ShellWin32(Game & game)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 
~ShellWin32()59 ShellWin32::~ShellWin32() {
60     cleanup_vk();
61     FreeLibrary(hmodule_);
62 }
63 
create_window()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 
load_vk()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 
can_present(VkPhysicalDevice phy,uint32_t queue_family)114 bool ShellWin32::can_present(VkPhysicalDevice phy, uint32_t queue_family) {
115     return vk::GetPhysicalDeviceWin32PresentationSupportKHR(phy, queue_family) == VK_TRUE;
116 }
117 
create_surface(VkInstance instance)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 
handle_message(UINT msg,WPARAM wparam,LPARAM lparam)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 
quit()174 void ShellWin32::quit() { PostQuitMessage(0); }
175 
run()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