/
VulkanContext.h
322 lines (252 loc) · 10.4 KB
/
VulkanContext.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
#ifndef UTIL_INIT
#define UTIL_INIT
#ifdef __ANDROID__
#undef NDEBUG // asserts
#endif
#include <cassert>
#include <string>
#include <vector>
#include <utility>
#include "base/logging.h"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define VK_USE_PLATFORM_WIN32_KHR
#define NOMINMAX /* Don't let Windows define min() or max() */
#define APP_NAME_STR_LEN 80
#include <Windows.h>
#elif defined(__ANDROID__) // _WIN32
#include <android/native_window_jni.h>
#define VK_USE_PLATFORM_ANDROID_KHR
#else
#define VK_USE_PLATFORM_XCB_KHR
#include <unistd.h>
#endif // _WIN32
#include "Common/Vulkan/VulkanLoader.h"
// Amount of time, in nanoseconds, to wait for a command buffer to complete
#define FENCE_TIMEOUT 10000000000
#if defined(NDEBUG) && defined(__GNUC__)
#define U_ASSERT_ONLY __attribute__((unused))
#else
#define U_ASSERT_ONLY
#endif
enum {
VULKAN_FLAG_VALIDATE = 1,
VULKAN_FLAG_PRESENT_MAILBOX = 2,
VULKAN_FLAG_PRESENT_IMMEDIATE = 4,
VULKAN_FLAG_PRESENT_FIFO_RELAXED = 8,
};
enum {
VULKAN_VENDOR_NVIDIA = 0x000010de,
VULKAN_VENDOR_INTEL = 0x00008086, // Haha!
VULKAN_VENDOR_AMD = 0x00001002,
VULKAN_VENDOR_ARM = 0x000013B5, // Mali
VULKAN_VENDOR_QUALCOMM = 0x00005143,
VULKAN_VENDOR_IMGTEC = 0x00001010, // PowerVR
};
std::string VulkanVendorString(uint32_t vendorId);
struct VulkanPhysicalDeviceInfo {
VkFormat preferredDepthStencilFormat;
};
// This is a bit repetitive...
class VulkanDeleteList {
struct Callback {
explicit Callback(void(*f)(void *userdata), void *u)
: func(f), userdata(u) {
}
void(*func)(void *userdata);
void *userdata;
};
public:
// NOTE: These all take reference handles so they can zero the input value.
void QueueDeleteCommandPool(VkCommandPool &pool) { cmdPools_.push_back(pool); pool = VK_NULL_HANDLE; }
void QueueDeleteDescriptorPool(VkDescriptorPool &pool) { descPools_.push_back(pool); pool = VK_NULL_HANDLE; }
void QueueDeleteShaderModule(VkShaderModule &module) { modules_.push_back(module); module = VK_NULL_HANDLE; }
void QueueDeleteBuffer(VkBuffer &buffer) { buffers_.push_back(buffer); buffer = VK_NULL_HANDLE; }
void QueueDeleteBufferView(VkBufferView &bufferView) { bufferViews_.push_back(bufferView); bufferView = VK_NULL_HANDLE; }
void QueueDeleteImage(VkImage &image) { images_.push_back(image); image = VK_NULL_HANDLE; }
void QueueDeleteImageView(VkImageView &imageView) { imageViews_.push_back(imageView); imageView = VK_NULL_HANDLE; }
void QueueDeleteDeviceMemory(VkDeviceMemory &deviceMemory) { deviceMemory_.push_back(deviceMemory); deviceMemory = VK_NULL_HANDLE; }
void QueueDeleteSampler(VkSampler &sampler) { samplers_.push_back(sampler); sampler = VK_NULL_HANDLE; }
void QueueDeletePipeline(VkPipeline &pipeline) { pipelines_.push_back(pipeline); pipeline = VK_NULL_HANDLE; }
void QueueDeletePipelineCache(VkPipelineCache &pipelineCache) { pipelineCaches_.push_back(pipelineCache); pipelineCache = VK_NULL_HANDLE; }
void QueueDeleteRenderPass(VkRenderPass &renderPass) { renderPasses_.push_back(renderPass); renderPass = VK_NULL_HANDLE; }
void QueueDeleteFramebuffer(VkFramebuffer &framebuffer) { framebuffers_.push_back(framebuffer); framebuffer = VK_NULL_HANDLE; }
void QueueDeletePipelineLayout(VkPipelineLayout &pipelineLayout) { pipelineLayouts_.push_back(pipelineLayout); pipelineLayout = VK_NULL_HANDLE; }
void QueueDeleteDescriptorSetLayout(VkDescriptorSetLayout &descSetLayout) { descSetLayouts_.push_back(descSetLayout); descSetLayout = VK_NULL_HANDLE; }
void QueueCallback(void(*func)(void *userdata), void *userdata) { callbacks_.push_back(Callback(func, userdata)); }
void Take(VulkanDeleteList &del);
void PerformDeletes(VkDevice device);
private:
std::vector<VkCommandPool> cmdPools_;
std::vector<VkDescriptorPool> descPools_;
std::vector<VkShaderModule> modules_;
std::vector<VkBuffer> buffers_;
std::vector<VkBufferView> bufferViews_;
std::vector<VkImage> images_;
std::vector<VkImageView> imageViews_;
std::vector<VkDeviceMemory> deviceMemory_;
std::vector<VkSampler> samplers_;
std::vector<VkPipeline> pipelines_;
std::vector<VkPipelineCache> pipelineCaches_;
std::vector<VkRenderPass> renderPasses_;
std::vector<VkFramebuffer> framebuffers_;
std::vector<VkPipelineLayout> pipelineLayouts_;
std::vector<VkDescriptorSetLayout> descSetLayouts_;
std::vector<Callback> callbacks_;
};
// VulkanContext manages the device and swapchain, and deferred deletion of objects.
class VulkanContext {
public:
VulkanContext();
~VulkanContext();
VkResult CreateInstance(const char *app_name, int app_ver, uint32_t flags);
void DestroyInstance();
int GetBestPhysicalDevice();
void ChooseDevice(int physical_device);
bool EnableDeviceExtension(const char *extension);
VkResult CreateDevice();
const std::string &InitError() { return init_error_; }
VkDevice GetDevice() { return device_; }
VkInstance GetInstance() { return instance_; }
VulkanDeleteList &Delete() { return globalDeleteList_; }
VkPipelineCache CreatePipelineCache();
#ifdef _WIN32
void InitSurfaceWin32(HINSTANCE conn, HWND wnd);
void ReinitSurfaceWin32();
#elif __ANDROID__
void InitSurfaceAndroid(ANativeWindow *native_window, int width, int height);
void ReinitSurfaceAndroid(int width, int height);
#endif
bool InitQueue();
bool InitObjects();
bool InitSwapchain();
// Also destroys the surface.
void DestroyObjects();
void DestroyDevice();
void WaitUntilQueueIdle();
// Utility functions for shorter code
VkFence CreateFence(bool presignalled);
bool CreateShaderModule(const std::vector<uint32_t> &spirv, VkShaderModule *shaderModule);
int GetBackbufferWidth() { return width_; }
int GetBackbufferHeight() { return height_; }
void BeginFrame();
void EndFrame();
bool MemoryTypeFromProperties(uint32_t typeBits, VkFlags requirements_mask, uint32_t *typeIndex);
VkResult InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFunc, int bits, void *userdata = nullptr);
void DestroyDebugMsgCallback();
VkPhysicalDevice GetPhysicalDevice(int n = 0) const {
return physical_devices_[n];
}
VkQueue GetGraphicsQueue() const {
return gfx_queue_;
}
int GetGraphicsQueueFamilyIndex() const {
return graphics_queue_family_index_;
}
const VkPhysicalDeviceProperties &GetPhysicalDeviceProperties() {
return gpu_props;
}
VkResult GetInstanceLayerExtensionList(const char *layerName, std::vector<VkExtensionProperties> &extensions);
VkResult GetInstanceLayerProperties();
VkResult GetDeviceLayerExtensionList(const char *layerName, std::vector<VkExtensionProperties> &extensions);
VkResult GetDeviceLayerProperties();
const std::vector<VkExtensionProperties> &GetDeviceExtensionsAvailable() const {
return device_extension_properties_;
}
const std::vector<const char *> &GetDeviceExtensionsEnabled() const {
return device_extensions_enabled_;
}
const VkPhysicalDeviceFeatures &GetFeaturesAvailable() const { return featuresAvailable_; }
const VkPhysicalDeviceFeatures &GetFeaturesEnabled() const { return featuresEnabled_; }
const VulkanPhysicalDeviceInfo &GetDeviceInfo() const { return deviceInfo_; }
bool IsDeviceExtensionAvailable(const char *name) const {
for (auto &iter : device_extension_properties_) {
if (!strcmp(name, iter.extensionName))
return true;
}
return false;
}
int GetInflightFrames() const {
return inflightFrames_;
}
int GetCurFrame() const {
return curFrame_;
}
VkSwapchainKHR GetSwapchain() const {
return swapchain_;
}
VkFormat GetSwapchainFormat() const {
return swapchainFormat_;
}
// 1 for no frame overlap and thus minimal latency but worst performance.
// 2 is an OK compromise, while 3 performs best but risks slightly higher latency.
enum {
MAX_INFLIGHT_FRAMES = 3,
};
private:
// A layer can expose extensions, keep track of those extensions here.
struct LayerProperties {
VkLayerProperties properties;
std::vector<VkExtensionProperties> extensions;
};
bool CheckLayers(const std::vector<LayerProperties> &layer_props, const std::vector<const char *> &layer_names) const;
#ifdef _WIN32
HINSTANCE connection = nullptr; // hInstance - Windows Instance
HWND window = nullptr; // hWnd - window handle
#elif __ANDROID__ // _WIN32
ANativeWindow *native_window = nullptr;
#endif // _WIN32
VkInstance instance_ = VK_NULL_HANDLE;
VkDevice device_ = VK_NULL_HANDLE;
VkQueue gfx_queue_ = VK_NULL_HANDLE;
VkSurfaceKHR surface_ = VK_NULL_HANDLE;
std::string init_error_;
std::vector<const char *> instance_layer_names_;
std::vector<LayerProperties> instance_layer_properties_;
std::vector<const char *> instance_extensions_enabled_;
std::vector<VkExtensionProperties> instance_extension_properties_;
std::vector<const char *> device_layer_names_;
std::vector<LayerProperties> device_layer_properties_;
std::vector<const char *> device_extensions_enabled_;
std::vector<VkExtensionProperties> device_extension_properties_;
std::vector<VkPhysicalDevice> physical_devices_;
int physical_device_ = -1;
uint32_t graphics_queue_family_index_ = -1;
VkPhysicalDeviceProperties gpu_props{};
std::vector<VkQueueFamilyProperties> queue_props;
VkPhysicalDeviceMemoryProperties memory_properties{};
// Custom collection of things that are good to know
VulkanPhysicalDeviceInfo deviceInfo_{};
// Swap chain
int width_ = 0;
int height_ = 0;
int flags_ = 0;
int inflightFrames_ = MAX_INFLIGHT_FRAMES;
struct FrameData {
FrameData() {}
VulkanDeleteList deleteList;
};
FrameData frame_[MAX_INFLIGHT_FRAMES];
int curFrame_ = 0;
// At the end of the frame, this is copied into the frame's delete list, so it can be processed
// the next time the frame comes around again.
VulkanDeleteList globalDeleteList_;
std::vector<VkDebugReportCallbackEXT> msg_callbacks;
VkSwapchainKHR swapchain_ = VK_NULL_HANDLE;
VkFormat swapchainFormat_;
uint32_t queue_count = 0;
VkPhysicalDeviceFeatures featuresAvailable_{};
VkPhysicalDeviceFeatures featuresEnabled_{};
std::vector<VkCommandBuffer> cmdQueue_;
};
// Detailed control.
void TransitionImageLayout2(VkCommandBuffer cmd, VkImage image, VkImageAspectFlags aspectMask,
VkImageLayout oldImageLayout, VkImageLayout newImageLayout,
VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask,
VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, int mipLevels = VK_REMAINING_MIP_LEVELS);
// GLSL compiler
void init_glslang();
void finalize_glslang();
bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector<uint32_t> &spirv, std::string *errorMessage = nullptr);
const char *VulkanResultToString(VkResult res);
#endif // UTIL_INIT