PeriDyno 1.0.0
Loading...
Searching...
No Matches
VulkanTools.cpp
Go to the documentation of this file.
1/*
2* Assorted commonly used Vulkan helper functions
3*
4* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
5*
6* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
7*/
8
9#include "VulkanTools.h"
10
11namespace vks
12{
13 namespace tools
14 {
15 bool errorModeSilent = false;
16
17 std::string errorString(VkResult errorCode)
18 {
19 switch (errorCode)
20 {
21#define STR(r) case VK_ ##r: return #r
22 STR(NOT_READY);
23 STR(TIMEOUT);
24 STR(EVENT_SET);
25 STR(EVENT_RESET);
26 STR(INCOMPLETE);
27 STR(ERROR_OUT_OF_HOST_MEMORY);
28 STR(ERROR_OUT_OF_DEVICE_MEMORY);
29 STR(ERROR_INITIALIZATION_FAILED);
30 STR(ERROR_DEVICE_LOST);
31 STR(ERROR_MEMORY_MAP_FAILED);
32 STR(ERROR_LAYER_NOT_PRESENT);
33 STR(ERROR_EXTENSION_NOT_PRESENT);
34 STR(ERROR_FEATURE_NOT_PRESENT);
35 STR(ERROR_INCOMPATIBLE_DRIVER);
36 STR(ERROR_TOO_MANY_OBJECTS);
37 STR(ERROR_FORMAT_NOT_SUPPORTED);
38 STR(ERROR_SURFACE_LOST_KHR);
39 STR(ERROR_NATIVE_WINDOW_IN_USE_KHR);
40 STR(SUBOPTIMAL_KHR);
41 STR(ERROR_OUT_OF_DATE_KHR);
42 STR(ERROR_INCOMPATIBLE_DISPLAY_KHR);
43 STR(ERROR_VALIDATION_FAILED_EXT);
44 STR(ERROR_INVALID_SHADER_NV);
45#undef STR
46 default:
47 return "UNKNOWN_ERROR";
48 }
49 }
50
51 std::string physicalDeviceTypeString(VkPhysicalDeviceType type)
52 {
53 switch (type)
54 {
55#define STR(r) case VK_PHYSICAL_DEVICE_TYPE_ ##r: return #r
56 STR(OTHER);
57 STR(INTEGRATED_GPU);
58 STR(DISCRETE_GPU);
59 STR(VIRTUAL_GPU);
60 STR(CPU);
61#undef STR
62 default: return "UNKNOWN_DEVICE_TYPE";
63 }
64 }
65
66 VkBool32 getSupportedDepthFormat(VkPhysicalDevice physicalDevice, VkFormat *depthFormat)
67 {
68 // Since all depth formats may be optional, we need to find a suitable depth format to use
69 // Start with the highest precision packed format
70 std::vector<VkFormat> depthFormats = {
71 VK_FORMAT_D32_SFLOAT_S8_UINT,
72 VK_FORMAT_D32_SFLOAT,
73 VK_FORMAT_D24_UNORM_S8_UINT,
74 VK_FORMAT_D16_UNORM_S8_UINT,
75 VK_FORMAT_D16_UNORM
76 };
77
78 for (auto& format : depthFormats)
79 {
80 VkFormatProperties formatProps;
81 vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProps);
82 // Format must support depth stencil attachment for optimal tiling
83 if (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
84 {
85 *depthFormat = format;
86 return true;
87 }
88 }
89
90 return false;
91 }
92
93 // Returns if a given format support LINEAR filtering
94 VkBool32 formatIsFilterable(VkPhysicalDevice physicalDevice, VkFormat format, VkImageTiling tiling)
95 {
96 VkFormatProperties formatProps;
97 vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProps);
98
99 if (tiling == VK_IMAGE_TILING_OPTIMAL)
100 return formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
101
102 if (tiling == VK_IMAGE_TILING_LINEAR)
103 return formatProps.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT;
104
105 return false;
106 }
107
108 // Create an image memory barrier for changing the layout of
109 // an image and put it into an active command buffer
110 // See chapter 11.4 "Image Layout" for details
111
113 VkCommandBuffer cmdbuffer,
114 VkImage image,
115 VkImageLayout oldImageLayout,
116 VkImageLayout newImageLayout,
117 VkImageSubresourceRange subresourceRange,
118 VkPipelineStageFlags srcStageMask,
119 VkPipelineStageFlags dstStageMask)
120 {
121 // Create an image barrier object
122 VkImageMemoryBarrier imageMemoryBarrier = vks::initializers::imageMemoryBarrier();
123 imageMemoryBarrier.oldLayout = oldImageLayout;
124 imageMemoryBarrier.newLayout = newImageLayout;
125 imageMemoryBarrier.image = image;
126 imageMemoryBarrier.subresourceRange = subresourceRange;
127
128 // Source layouts (old)
129 // Source access mask controls actions that have to be finished on the old layout
130 // before it will be transitioned to the new layout
131 switch (oldImageLayout)
132 {
133 case VK_IMAGE_LAYOUT_UNDEFINED:
134 // Image layout is undefined (or does not matter)
135 // Only valid as initial layout
136 // No flags required, listed only for completeness
137 imageMemoryBarrier.srcAccessMask = 0;
138 break;
139
140 case VK_IMAGE_LAYOUT_PREINITIALIZED:
141 // Image is preinitialized
142 // Only valid as initial layout for linear images, preserves memory contents
143 // Make sure host writes have been finished
144 imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
145 break;
146
147 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
148 // Image is a color attachment
149 // Make sure any writes to the color buffer have been finished
150 imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
151 break;
152
153 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
154 // Image is a depth/stencil attachment
155 // Make sure any writes to the depth/stencil buffer have been finished
156 imageMemoryBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
157 break;
158
159 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
160 // Image is a transfer source
161 // Make sure any reads from the image have been finished
162 imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
163 break;
164
165 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
166 // Image is a transfer destination
167 // Make sure any writes to the image have been finished
168 imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
169 break;
170
171 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
172 // Image is read by a shader
173 // Make sure any shader reads from the image have been finished
174 imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
175 break;
176 default:
177 // Other source layouts aren't handled (yet)
178 break;
179 }
180
181 // Target layouts (new)
182 // Destination access mask controls the dependency for the new image layout
183 switch (newImageLayout)
184 {
185 case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
186 // Image will be used as a transfer destination
187 // Make sure any writes to the image have been finished
188 imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
189 break;
190
191 case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
192 // Image will be used as a transfer source
193 // Make sure any reads from the image have been finished
194 imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
195 break;
196
197 case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
198 // Image will be used as a color attachment
199 // Make sure any writes to the color buffer have been finished
200 imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
201 break;
202
203 case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
204 // Image layout will be used as a depth/stencil attachment
205 // Make sure any writes to depth/stencil buffer have been finished
206 imageMemoryBarrier.dstAccessMask = imageMemoryBarrier.dstAccessMask | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
207 break;
208
209 case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
210 // Image will be read in a shader (sampler, input attachment)
211 // Make sure any writes to the image have been finished
212 if (imageMemoryBarrier.srcAccessMask == 0)
213 {
214 imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
215 }
216 imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
217 break;
218 default:
219 // Other source layouts aren't handled (yet)
220 break;
221 }
222
223 // Put barrier inside setup command buffer
224 vkCmdPipelineBarrier(
225 cmdbuffer,
226 srcStageMask,
227 dstStageMask,
228 0,
229 0, nullptr,
230 0, nullptr,
231 1, &imageMemoryBarrier);
232 }
233
234 // Fixed sub resource on first mip level and layer
236 VkCommandBuffer cmdbuffer,
237 VkImage image,
238 VkImageAspectFlags aspectMask,
239 VkImageLayout oldImageLayout,
240 VkImageLayout newImageLayout,
241 VkPipelineStageFlags srcStageMask,
242 VkPipelineStageFlags dstStageMask)
243 {
244 VkImageSubresourceRange subresourceRange = {};
245 subresourceRange.aspectMask = aspectMask;
246 subresourceRange.baseMipLevel = 0;
247 subresourceRange.levelCount = 1;
248 subresourceRange.layerCount = 1;
249 setImageLayout(cmdbuffer, image, oldImageLayout, newImageLayout, subresourceRange, srcStageMask, dstStageMask);
250 }
251
253 VkCommandBuffer cmdbuffer,
254 VkImage image,
255 VkAccessFlags srcAccessMask,
256 VkAccessFlags dstAccessMask,
257 VkImageLayout oldImageLayout,
258 VkImageLayout newImageLayout,
259 VkPipelineStageFlags srcStageMask,
260 VkPipelineStageFlags dstStageMask,
261 VkImageSubresourceRange subresourceRange)
262 {
263 VkImageMemoryBarrier imageMemoryBarrier = vks::initializers::imageMemoryBarrier();
264 imageMemoryBarrier.srcAccessMask = srcAccessMask;
265 imageMemoryBarrier.dstAccessMask = dstAccessMask;
266 imageMemoryBarrier.oldLayout = oldImageLayout;
267 imageMemoryBarrier.newLayout = newImageLayout;
268 imageMemoryBarrier.image = image;
269 imageMemoryBarrier.subresourceRange = subresourceRange;
270
271 vkCmdPipelineBarrier(
272 cmdbuffer,
273 srcStageMask,
274 dstStageMask,
275 0,
276 0, nullptr,
277 0, nullptr,
278 1, &imageMemoryBarrier);
279 }
280
281 void exitFatal(const std::string& message, int32_t exitCode)
282 {
283#if defined(_WIN32)
284 if (!errorModeSilent) {
285 MessageBox(NULL, message.c_str(), NULL, MB_OK | MB_ICONERROR);
286 }
287#elif defined(__ANDROID__)
288 LOGE("Fatal error: %s", message.c_str());
289 vks::android::showAlert(message.c_str());
290#endif
291 std::cerr << message << "\n";
292#if !defined(__ANDROID__)
293 exit(exitCode);
294#endif
295 }
296
297 void exitFatal(const std::string& message, VkResult resultCode)
298 {
299 exitFatal(message, (int32_t)resultCode);
300 }
301
302
303 VkShaderModule loadShaderModule(const std::string fileName, VkDevice device)
304 {
305#if defined(VK_USE_PLATFORM_ANDROID_KHR)
306 return vks::tools::loadShader(androidApp->activity->assetManager, fileName.c_str(), device);
307#else
308 return vks::tools::loadShader(fileName.c_str(), device);
309#endif
310 }
311
312#if defined(__ANDROID__)
313 // Android shaders are stored as assets in the apk
314 // So they need to be loaded via the asset manager
315 VkShaderModule loadShader(AAssetManager* assetManager, const char *fileName, VkDevice device)
316 {
317 // Load shader from compressed asset
318 AAsset* asset = AAssetManager_open(assetManager, fileName, AASSET_MODE_STREAMING);
319 assert(asset);
320 size_t size = AAsset_getLength(asset);
321 assert(size > 0);
322
323 char *shaderCode = new char[size];
324 AAsset_read(asset, shaderCode, size);
325 AAsset_close(asset);
326
327 VkShaderModule shaderModule;
328 VkShaderModuleCreateInfo moduleCreateInfo;
329 moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
330 moduleCreateInfo.pNext = NULL;
331 moduleCreateInfo.codeSize = size;
332 moduleCreateInfo.pCode = (uint32_t*)shaderCode;
333 moduleCreateInfo.flags = 0;
334
335 VK_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderModule));
336
337 delete[] shaderCode;
338
339 return shaderModule;
340 }
341#else
342 VkShaderModule loadShader(const char *fileName, VkDevice device)
343 {
344 std::ifstream is(fileName, std::ios::binary | std::ios::in | std::ios::ate);
345
346 if (is.is_open())
347 {
348 size_t size = is.tellg();
349 is.seekg(0, std::ios::beg);
350 char* shaderCode = new char[size];
351 is.read(shaderCode, size);
352 is.close();
353
354 assert(size > 0);
355
356 VkShaderModule shaderModule;
357 VkShaderModuleCreateInfo moduleCreateInfo{};
358 moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
359 moduleCreateInfo.codeSize = size;
360 moduleCreateInfo.pCode = (uint32_t*)shaderCode;
361
362 VK_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderModule));
363
364 delete[] shaderCode;
365
366 return shaderModule;
367 }
368 else
369 {
370 std::cerr << "Error: Could not open shader file \"" << fileName << "\"" << "\n";
371 return VK_NULL_HANDLE;
372 }
373 }
374#endif
375
376 bool fileExists(const std::string &filename)
377 {
378 std::ifstream f(filename.c_str());
379 return !f.fail();
380 }
381
382 uint32_t alignedSize(uint32_t value, uint32_t alignment)
383 {
384 return (value + alignment - 1) & ~(alignment - 1);
385 }
386
387 }
388}
assert(queueCount >=1)
#define STR(r)
#define VK_CHECK_RESULT(f)
Definition VulkanTools.h:55
VkImageMemoryBarrier imageMemoryBarrier()
Initialize an image memory barrier with no image transfer ownership.
bool fileExists(const std::string &filename)
Checks if a file exists.
void insertImageMemoryBarrier(VkCommandBuffer cmdbuffer, VkImage image, VkAccessFlags srcAccessMask, VkAccessFlags dstAccessMask, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask, VkImageSubresourceRange subresourceRange)
Insert an image memory barrier into the command buffer.
void setImageLayout(VkCommandBuffer cmdbuffer, VkImage image, VkImageLayout oldImageLayout, VkImageLayout newImageLayout, VkImageSubresourceRange subresourceRange, VkPipelineStageFlags srcStageMask, VkPipelineStageFlags dstStageMask)
uint32_t alignedSize(uint32_t value, uint32_t alignment)
std::string errorString(VkResult errorCode)
Returns an error code as a string.
std::string physicalDeviceTypeString(VkPhysicalDeviceType type)
Returns the device type as a string.
VkBool32 getSupportedDepthFormat(VkPhysicalDevice physicalDevice, VkFormat *depthFormat)
VkBool32 formatIsFilterable(VkPhysicalDevice physicalDevice, VkFormat format, VkImageTiling tiling)
VkShaderModule loadShader(const char *fileName, VkDevice device)
bool errorModeSilent
Disable message boxes on fatal errors.
VkShaderModule loadShaderModule(const std::string fileName, VkDevice device)
void exitFatal(const std::string &message, int32_t exitCode)