1 | // |
2 | // Copyright 2016 The ANGLE Project Authors. All rights reserved. |
3 | // Use of this source code is governed by a BSD-style license that can be |
4 | // found in the LICENSE file. |
5 | // |
6 | // RendererVk.cpp: |
7 | // Implements the class methods for RendererVk. |
8 | // |
9 | |
10 | #include "libANGLE/renderer/vulkan/RendererVk.h" |
11 | |
12 | // Placing this first seems to solve an intellisense bug. |
13 | #include "libANGLE/renderer/vulkan/vk_utils.h" |
14 | |
15 | #include <EGL/eglext.h> |
16 | |
17 | #include "common/debug.h" |
18 | #include "common/platform.h" |
19 | #include "common/system_utils.h" |
20 | #include "common/vulkan/libvulkan_loader.h" |
21 | #include "common/vulkan/vk_google_filtering_precision.h" |
22 | #include "common/vulkan/vulkan_icd.h" |
23 | #include "gpu_info_util/SystemInfo.h" |
24 | #include "libANGLE/Context.h" |
25 | #include "libANGLE/Display.h" |
26 | #include "libANGLE/renderer/driver_utils.h" |
27 | #include "libANGLE/renderer/vulkan/CompilerVk.h" |
28 | #include "libANGLE/renderer/vulkan/ContextVk.h" |
29 | #include "libANGLE/renderer/vulkan/DisplayVk.h" |
30 | #include "libANGLE/renderer/vulkan/FramebufferVk.h" |
31 | #include "libANGLE/renderer/vulkan/ProgramVk.h" |
32 | #include "libANGLE/renderer/vulkan/ResourceVk.h" |
33 | #include "libANGLE/renderer/vulkan/SyncVk.h" |
34 | #include "libANGLE/renderer/vulkan/VertexArrayVk.h" |
35 | #include "libANGLE/renderer/vulkan/vk_caps_utils.h" |
36 | #include "libANGLE/renderer/vulkan/vk_format_utils.h" |
37 | #include "libANGLE/trace.h" |
38 | #include "platform/PlatformMethods.h" |
39 | |
40 | // Consts |
41 | namespace |
42 | { |
43 | constexpr VkFormatFeatureFlags kInvalidFormatFeatureFlags = static_cast<VkFormatFeatureFlags>(-1); |
44 | |
45 | #if defined(ANGLE_EXPOSE_NON_CONFORMANT_EXTENSIONS_AND_VERSIONS) |
46 | constexpr bool kExposeNonConformantExtensionsAndVersions = true; |
47 | #else |
48 | constexpr bool kExposeNonConformantExtensionsAndVersions = false; |
49 | #endif |
50 | |
51 | #if defined(ANGLE_ENABLE_CRC_FOR_PIPELINE_CACHE) |
52 | constexpr bool kEnableCRCForPipelineCache = true; |
53 | #else |
54 | constexpr bool kEnableCRCForPipelineCache = false; |
55 | #endif |
56 | } // anonymous namespace |
57 | |
58 | namespace rx |
59 | { |
60 | |
61 | namespace |
62 | { |
63 | constexpr uint32_t kMinDefaultUniformBufferSize = 16 * 1024u; |
64 | // This size is picked based on experience. Majority of devices support 64K |
65 | // maxUniformBufferSize. Since this is per context buffer, a bigger buffer size reduces the |
66 | // number of descriptor set allocations, so we picked the maxUniformBufferSize that most |
67 | // devices supports. It may needs further tuning based on specific device needs and balance |
68 | // between performance and memory usage. |
69 | constexpr uint32_t kPreferredDefaultUniformBufferSize = 64 * 1024u; |
70 | |
71 | // Maximum size to use VMA image suballocation. Any allocation greater than or equal to this |
72 | // value will use a dedicated VkDeviceMemory. |
73 | constexpr size_t kImageSizeThresholdForDedicatedMemoryAllocation = 4 * 1024 * 1024; |
74 | |
75 | // Pipeline cache header version. It should be incremented any time there is an update to the cache |
76 | // header or data structure. |
77 | constexpr uint16_t kPipelineCacheVersion = 1; |
78 | |
79 | // Update the pipeline cache every this many swaps. |
80 | constexpr uint32_t kPipelineCacheVkUpdatePeriod = 60; |
81 | // Per the Vulkan specification, ANGLE must indicate the highest version of Vulkan functionality |
82 | // that it uses. The Vulkan validation layers will issue messages for any core functionality that |
83 | // requires a higher version. |
84 | // |
85 | // ANGLE specifically limits its core version to Vulkan 1.1 and relies on availability of |
86 | // extensions. While implementations are not required to expose an extension that is promoted to |
87 | // later versions, they always do so in practice. Avoiding later core versions helps keep the |
88 | // initialization logic simpler. |
89 | constexpr uint32_t kPreferredVulkanAPIVersion = VK_API_VERSION_1_1; |
90 | |
91 | bool IsVulkan11(uint32_t apiVersion) |
92 | { |
93 | return apiVersion >= VK_API_VERSION_1_1; |
94 | } |
95 | |
96 | bool IsVenus(uint32_t driverId, const char *deviceName) |
97 | { |
98 | // Where driver id is available, check against Venus driver id: |
99 | if (driverId != 0) |
100 | { |
101 | return driverId == VK_DRIVER_ID_MESA_VENUS; |
102 | } |
103 | |
104 | // Otherwise, look for Venus in the device name. |
105 | return strstr(s1: deviceName, s2: "Venus" ) != nullptr; |
106 | } |
107 | |
108 | bool IsQualcommOpenSource(uint32_t vendorId, uint32_t driverId, const char *deviceName) |
109 | { |
110 | if (!IsQualcomm(vendorId)) |
111 | { |
112 | return false; |
113 | } |
114 | |
115 | // Where driver id is available, distinguish by driver id: |
116 | if (driverId != 0) |
117 | { |
118 | return driverId != VK_DRIVER_ID_QUALCOMM_PROPRIETARY; |
119 | } |
120 | |
121 | // Otherwise, look for Venus or Turnip in the device name. |
122 | return strstr(s1: deviceName, s2: "Venus" ) != nullptr || strstr(s1: deviceName, s2: "Turnip" ) != nullptr; |
123 | } |
124 | |
125 | bool IsPixel() |
126 | { |
127 | if (!IsAndroid()) |
128 | { |
129 | return false; |
130 | } |
131 | |
132 | angle::SystemInfo info; |
133 | if (!angle::GetSystemInfo(info: &info)) |
134 | { |
135 | return false; |
136 | } |
137 | |
138 | return strstr(s1: info.machineModelName.c_str(), s2: "Pixel" ) != nullptr; |
139 | } |
140 | |
141 | angle::vk::ICD ChooseICDFromAttribs(const egl::AttributeMap &attribs) |
142 | { |
143 | #if !defined(ANGLE_PLATFORM_ANDROID) |
144 | // Mock ICD does not currently run on Android |
145 | EGLAttrib deviceType = attribs.get(EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, |
146 | EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE); |
147 | |
148 | switch (deviceType) |
149 | { |
150 | case EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE: |
151 | break; |
152 | case EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE: |
153 | return angle::vk::ICD::Mock; |
154 | case EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE: |
155 | return angle::vk::ICD::SwiftShader; |
156 | default: |
157 | UNREACHABLE(); |
158 | break; |
159 | } |
160 | #endif // !defined(ANGLE_PLATFORM_ANDROID) |
161 | |
162 | return angle::vk::ICD::Default; |
163 | } |
164 | |
165 | bool StrLess(const char *a, const char *b) |
166 | { |
167 | return strcmp(s1: a, s2: b) < 0; |
168 | } |
169 | |
170 | bool ExtensionFound(const char *needle, const vk::ExtensionNameList &haystack) |
171 | { |
172 | // NOTE: The list must be sorted. |
173 | return std::binary_search(first: haystack.begin(), last: haystack.end(), value: needle, comp: StrLess); |
174 | } |
175 | |
176 | VkResult VerifyExtensionsPresent(const vk::ExtensionNameList &haystack, |
177 | const vk::ExtensionNameList &needles) |
178 | { |
179 | // NOTE: The lists must be sorted. |
180 | if (std::includes(first1: haystack.begin(), last1: haystack.end(), first2: needles.begin(), last2: needles.end(), comp: StrLess)) |
181 | { |
182 | return VK_SUCCESS; |
183 | } |
184 | for (const char *needle : needles) |
185 | { |
186 | if (!ExtensionFound(needle, haystack)) |
187 | { |
188 | ERR() << "Extension not supported: " << needle; |
189 | } |
190 | } |
191 | return VK_ERROR_EXTENSION_NOT_PRESENT; |
192 | } |
193 | |
194 | // Array of Validation error/warning messages that will be ignored, should include bugID |
195 | constexpr const char *kSkippedMessages[] = { |
196 | // http://anglebug.com/2866 |
197 | "UNASSIGNED-CoreValidation-Shader-OutputNotConsumed" , |
198 | // http://anglebug.com/4928 |
199 | "VUID-vkMapMemory-memory-00683" , |
200 | // http://anglebug.com/5027 |
201 | "UNASSIGNED-CoreValidation-Shader-PushConstantOutOfRange" , |
202 | // http://anglebug.com/5304 |
203 | "VUID-vkCmdDraw-magFilter-04553" , |
204 | "VUID-vkCmdDrawIndexed-magFilter-04553" , |
205 | // http://anglebug.com/5309 |
206 | "VUID-VkImageViewCreateInfo-usage-02652" , |
207 | // http://issuetracker.google.com/175584609 |
208 | "VUID-vkCmdDraw-None-04584" , |
209 | "VUID-vkCmdDrawIndexed-None-04584" , |
210 | "VUID-vkCmdDrawIndirect-None-04584" , |
211 | "VUID-vkCmdDrawIndirectCount-None-04584" , |
212 | "VUID-vkCmdDrawIndexedIndirect-None-04584" , |
213 | "VUID-vkCmdDrawIndexedIndirectCount-None-04584" , |
214 | // http://anglebug.com/5912 |
215 | "VUID-VkImageViewCreateInfo-pNext-01585" , |
216 | // http://anglebug.com/6514 |
217 | "vkEnumeratePhysicalDevices: One or more layers modified physical devices" , |
218 | // When using Vulkan secondary command buffers, the command buffer is begun with the current |
219 | // framebuffer specified in pInheritanceInfo::framebuffer. If the framebuffer is multisampled |
220 | // and is resolved, an optimization would change the framebuffer to add the resolve target and |
221 | // use a subpass resolve operation instead. The following error complains that the framebuffer |
222 | // used to start the render pass and the one specified in pInheritanceInfo::framebuffer must be |
223 | // equal, which is not true in that case. In practice, this is benign, as the part of the |
224 | // framebuffer that's accessed by the command buffer is identically laid out. |
225 | // http://anglebug.com/6811 |
226 | "VUID-vkCmdExecuteCommands-pCommandBuffers-00099" , |
227 | // http://anglebug.com/7325 |
228 | "VUID-vkCmdBindVertexBuffers2-pStrides-06209" , |
229 | // http://anglebug.com/7729 |
230 | "VUID-vkDestroySemaphore-semaphore-01137" , |
231 | // http://anglebug.com/7843 |
232 | "VUID-VkGraphicsPipelineCreateInfo-Vertex-07722" , |
233 | // http://anglebug.com/7861 |
234 | "VUID-vkCmdDraw-None-06887" , |
235 | "VUID-vkCmdDraw-None-06886" , |
236 | "VUID-vkCmdDrawIndexed-None-06887" , |
237 | // http://anglebug.com/7865 |
238 | "VUID-VkDescriptorImageInfo-imageView-06711" , |
239 | "VUID-VkDescriptorImageInfo-descriptorType-06713" , |
240 | // http://crbug.com/1412096 |
241 | "VUID-VkImageCreateInfo-pNext-00990" , |
242 | // http://crbug.com/1420265 |
243 | "VUID-vkCmdEndDebugUtilsLabelEXT-commandBuffer-01912" , |
244 | // http://anglebug.com/8076 |
245 | "VUID-VkGraphicsPipelineCreateInfo-None-06573" , |
246 | // http://anglebug.com/8119 |
247 | "VUID-VkGraphicsPipelineCreateInfo-Input-07904" , |
248 | "VUID-VkGraphicsPipelineCreateInfo-Input-07905" , |
249 | "VUID-vkCmdDrawIndexed-None-07835" , |
250 | "VUID-VkGraphicsPipelineCreateInfo-Input-08733" , |
251 | // http://anglebug.com/8151 |
252 | "VUID-vkCmdDraw-None-07844" , |
253 | "VUID-vkCmdDraw-None-07845" , |
254 | "VUID-vkCmdDraw-None-07848" , |
255 | // https://anglebug.com/8128#c3 |
256 | "VUID-VkBufferViewCreateInfo-buffer-00934" , |
257 | // https://anglebug.com/8203 |
258 | "VUID-VkVertexInputBindingDivisorDescriptionEXT-divisor-01870" , |
259 | // https://anglebug.com/8237 |
260 | "VUID-VkGraphicsPipelineCreateInfo-topology-08890" , |
261 | // https://anglebug.com/8242 |
262 | "VUID-vkCmdDraw-None-08608" , |
263 | "VUID-vkCmdDrawIndexed-None-08608" , |
264 | "VUID-vkCmdDraw-None-08753" , |
265 | "VUID-vkCmdDrawIndexed-None-08753" , |
266 | "VUID-vkCmdDraw-None-09003" , |
267 | "VUID-vkCmdDrawIndexed-None-09003" , |
268 | }; |
269 | |
270 | // Validation messages that should be ignored only when VK_EXT_primitive_topology_list_restart is |
271 | // not present. |
272 | constexpr const char *kNoListRestartSkippedMessages[] = { |
273 | // http://anglebug.com/3832 |
274 | "VUID-VkPipelineInputAssemblyStateCreateInfo-topology-00428" , |
275 | }; |
276 | |
277 | // Some syncval errors are resolved in the presence of the NONE load or store render pass ops. For |
278 | // those, ANGLE makes no further attempt to resolve them and expects vendor support for the |
279 | // extensions instead. The list of skipped messages is split based on this support. |
280 | constexpr vk::SkippedSyncvalMessage kSkippedSyncvalMessages[] = { |
281 | // http://anglebug.com/6416 |
282 | // http://anglebug.com/6421 |
283 | { |
284 | .messageId: "SYNC-HAZARD-WRITE-AFTER-WRITE" , |
285 | .messageContents1: "Access info (usage: SYNC_IMAGE_LAYOUT_TRANSITION, prior_usage: " |
286 | "SYNC_IMAGE_LAYOUT_TRANSITION, " |
287 | "write_barriers: 0, command: vkCmdEndRenderPass" , |
288 | }, |
289 | // These errors are caused by a feedback loop tests that don't produce correct Vulkan to begin |
290 | // with. |
291 | // http://anglebug.com/6417 |
292 | // http://anglebug.com/7070 |
293 | // |
294 | // Occassionally, this is due to VVL's lack of support for some extensions. For example, |
295 | // syncval doesn't properly account for VK_EXT_fragment_shader_interlock, which gives |
296 | // synchronization guarantees without the need for an image barrier. |
297 | // https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/4387 |
298 | { |
299 | .messageId: "SYNC-HAZARD-READ-AFTER-WRITE" , |
300 | .messageContents1: "imageLayout: VK_IMAGE_LAYOUT_GENERAL" , |
301 | .messageContents2: "usage: SYNC_FRAGMENT_SHADER_SHADER_" , |
302 | }, |
303 | // http://anglebug.com/6551 |
304 | { |
305 | .messageId: "SYNC-HAZARD-WRITE-AFTER-WRITE" , |
306 | .messageContents1: "Access info (usage: SYNC_IMAGE_LAYOUT_TRANSITION, prior_usage: " |
307 | "SYNC_COLOR_ATTACHMENT_OUTPUT_COLOR_ATTACHMENT_WRITE, write_barriers: " |
308 | "SYNC_EARLY_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_READ|SYNC_EARLY_FRAGMENT_TESTS_DEPTH_" |
309 | "STENCIL_ATTACHMENT_WRITE|SYNC_LATE_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_READ|SYNC_LATE_" |
310 | "FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE|SYNC_COLOR_ATTACHMENT_OUTPUT_COLOR_" |
311 | "ATTACHMENT_" |
312 | "READ|SYNC_COLOR_ATTACHMENT_OUTPUT_COLOR_ATTACHMENT_WRITE, command: vkCmdEndRenderPass" , |
313 | }, |
314 | { |
315 | .messageId: "SYNC-HAZARD-WRITE-AFTER-WRITE" , |
316 | .messageContents1: "Access info (usage: SYNC_IMAGE_LAYOUT_TRANSITION, prior_usage: " |
317 | "SYNC_COLOR_ATTACHMENT_OUTPUT_COLOR_ATTACHMENT_WRITE, write_barriers: " |
318 | "SYNC_COLOR_ATTACHMENT_OUTPUT_COLOR_ATTACHMENT_READ|SYNC_COLOR_ATTACHMENT_OUTPUT_COLOR_" |
319 | "ATTACHMENT_WRITE, command: vkCmdEndRenderPass" , |
320 | }, |
321 | // From: TraceTest.manhattan_31 with SwiftShader and |
322 | // VulkanPerformanceCounterTest.NewTextureDoesNotBreakRenderPass for both depth and stencil |
323 | // aspect. http://anglebug.com/6701 |
324 | { |
325 | .messageId: "SYNC-HAZARD-WRITE-AFTER-WRITE" , |
326 | .messageContents1: "Hazard WRITE_AFTER_WRITE in subpass 0 for attachment 1 aspect " , |
327 | .messageContents2: "during load with loadOp VK_ATTACHMENT_LOAD_OP_DONT_CARE. Access info (usage: " |
328 | "SYNC_EARLY_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE, prior_usage: " |
329 | "SYNC_IMAGE_LAYOUT_TRANSITION" , |
330 | }, |
331 | // From various tests. The validation layer does not calculate the exact vertexCounts that's |
332 | // being accessed. http://anglebug.com/6725 |
333 | { |
334 | .messageId: "SYNC-HAZARD-READ-AFTER-WRITE" , |
335 | .messageContents1: "vkCmdDrawIndexed: Hazard READ_AFTER_WRITE for vertex" , |
336 | .messageContents2: "usage: SYNC_VERTEX_ATTRIBUTE_INPUT_VERTEX_ATTRIBUTE_READ" , |
337 | }, |
338 | { |
339 | .messageId: "SYNC-HAZARD-READ-AFTER-WRITE" , |
340 | .messageContents1: "vkCmdDrawIndexedIndirect: Hazard READ_AFTER_WRITE for vertex" , |
341 | .messageContents2: "usage: SYNC_VERTEX_ATTRIBUTE_INPUT_VERTEX_ATTRIBUTE_READ" , |
342 | }, |
343 | { |
344 | .messageId: "SYNC-HAZARD-READ-AFTER-WRITE" , |
345 | .messageContents1: "vkCmdDrawIndirect: Hazard READ_AFTER_WRITE for vertex" , |
346 | .messageContents2: "usage: SYNC_VERTEX_ATTRIBUTE_INPUT_VERTEX_ATTRIBUTE_READ" , |
347 | }, |
348 | { |
349 | .messageId: "SYNC-HAZARD-READ-AFTER-WRITE" , |
350 | .messageContents1: "vkCmdDrawIndexedIndirect: Hazard READ_AFTER_WRITE for index" , |
351 | .messageContents2: "usage: SYNC_INDEX_INPUT_INDEX_READ" , |
352 | }, |
353 | { |
354 | .messageId: "SYNC-HAZARD-WRITE-AFTER-READ" , |
355 | .messageContents1: "vkCmdDraw: Hazard WRITE_AFTER_READ for" , |
356 | .messageContents2: "Access info (usage: SYNC_VERTEX_SHADER_SHADER_STORAGE_WRITE, prior_usage: " |
357 | "SYNC_VERTEX_ATTRIBUTE_INPUT_VERTEX_ATTRIBUTE_READ" , |
358 | }, |
359 | { |
360 | .messageId: "SYNC-HAZARD-WRITE-AFTER-READ" , |
361 | .messageContents1: "vkCmdCopyImageToBuffer: Hazard WRITE_AFTER_READ for dstBuffer VkBuffer" , |
362 | .messageContents2: "Access info (usage: SYNC_COPY_TRANSFER_WRITE, prior_usage: " |
363 | "SYNC_VERTEX_ATTRIBUTE_INPUT_VERTEX_ATTRIBUTE_READ" , |
364 | }, |
365 | { |
366 | .messageId: "SYNC-HAZARD-WRITE-AFTER-READ" , |
367 | .messageContents1: "vkCmdCopyBuffer: Hazard WRITE_AFTER_READ for dstBuffer VkBuffer" , |
368 | .messageContents2: "Access info (usage: SYNC_COPY_TRANSFER_WRITE, prior_usage: " |
369 | "SYNC_VERTEX_ATTRIBUTE_INPUT_VERTEX_ATTRIBUTE_READ" , |
370 | }, |
371 | { |
372 | .messageId: "SYNC-HAZARD-WRITE-AFTER-READ" , |
373 | .messageContents1: "vkCmdDispatch: Hazard WRITE_AFTER_READ for VkBuffer" , |
374 | .messageContents2: "Access info (usage: SYNC_COMPUTE_SHADER_SHADER_STORAGE_WRITE, prior_usage: " |
375 | "SYNC_VERTEX_ATTRIBUTE_INPUT_VERTEX_ATTRIBUTE_READ" , |
376 | }, |
377 | // From: MultisampledRenderToTextureES3Test.TransformFeedbackTest. http://anglebug.com/6725 |
378 | { |
379 | .messageId: "SYNC-HAZARD-WRITE-AFTER-WRITE" , |
380 | .messageContents1: "vkCmdBeginRenderPass: Hazard WRITE_AFTER_WRITE in subpass" , |
381 | .messageContents2: "write_barriers: " |
382 | "SYNC_TRANSFORM_FEEDBACK_EXT_TRANSFORM_FEEDBACK_COUNTER_READ_EXT|SYNC_TRANSFORM_FEEDBACK_" |
383 | "EXT_" |
384 | "TRANSFORM_FEEDBACK_COUNTER_WRITE_EXT" , |
385 | }, |
386 | // http://anglebug.com/8054 (VkNonDispatchableHandle on x86 bots) |
387 | { |
388 | .messageId: "SYNC-HAZARD-READ-AFTER-WRITE" , |
389 | .messageContents1: "vkCmdDraw: Hazard READ_AFTER_WRITE for VkBuffer" , |
390 | .messageContents2: "usage: SYNC_VERTEX_SHADER_SHADER_STORAGE_READ" , |
391 | }, |
392 | { |
393 | .messageId: "SYNC-HAZARD-READ-AFTER-WRITE" , |
394 | .messageContents1: "vkCmdDraw: Hazard READ_AFTER_WRITE for VkNonDispatchableHandle" , |
395 | .messageContents2: "usage: SYNC_VERTEX_SHADER_SHADER_STORAGE_READ" , |
396 | }, |
397 | // From: TraceTest.manhattan_31 with SwiftShader. These failures appears related to |
398 | // dynamic uniform buffers. The failures are gone if I force mUniformBufferDescriptorType to |
399 | // VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER. My guess is that syncval is not doing a fine grain enough |
400 | // range tracking with dynamic uniform buffers. http://anglebug.com/6725 |
401 | { |
402 | .messageId: "SYNC-HAZARD-WRITE-AFTER-READ" , |
403 | .messageContents1: "usage: SYNC_VERTEX_SHADER_UNIFORM_READ" , |
404 | }, |
405 | { |
406 | .messageId: "SYNC-HAZARD-READ-AFTER-WRITE" , |
407 | .messageContents1: "usage: SYNC_VERTEX_SHADER_UNIFORM_READ" , |
408 | }, |
409 | { |
410 | .messageId: "SYNC-HAZARD-WRITE-AFTER-READ" , |
411 | .messageContents1: "type: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC" , |
412 | }, |
413 | { |
414 | .messageId: "SYNC-HAZARD-READ-AFTER-WRITE" , |
415 | .messageContents1: "type: VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC" , |
416 | }, |
417 | // Coherent framebuffer fetch is enabled on some platforms that are known a priori to have the |
418 | // needed behavior, even though this is not specified in the Vulkan spec. These generate |
419 | // syncval errors that are benign on those platforms. |
420 | // http://anglebug.com/6870 |
421 | // From: TraceTest.dead_by_daylight |
422 | // From: TraceTest.genshin_impact |
423 | {.messageId: "SYNC-HAZARD-READ-AFTER-WRITE" , |
424 | .messageContents1: "vkCmdBeginRenderPass: Hazard READ_AFTER_WRITE in subpass 0 for attachment " , |
425 | .messageContents2: "aspect color during load with loadOp VK_ATTACHMENT_LOAD_OP_LOAD. Access info (usage: " |
426 | "SYNC_COLOR_ATTACHMENT_OUTPUT_COLOR_ATTACHMENT_READ, prior_usage: " |
427 | "SYNC_IMAGE_LAYOUT_TRANSITION, write_barriers: 0, command: vkCmdEndRenderPass" , |
428 | .isDueToNonConformantCoherentFramebufferFetch: true}, |
429 | {.messageId: "SYNC-HAZARD-WRITE-AFTER-WRITE" , |
430 | .messageContents1: "vkCmdBeginRenderPass: Hazard WRITE_AFTER_WRITE in subpass 0 for attachment " , |
431 | .messageContents2: "image layout transition (old_layout: VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, new_layout: " |
432 | "VK_IMAGE_LAYOUT_GENERAL). Access info (usage: SYNC_IMAGE_LAYOUT_TRANSITION, prior_usage: " |
433 | "SYNC_COLOR_ATTACHMENT_OUTPUT_COLOR_ATTACHMENT_WRITE, write_barriers:" , |
434 | .isDueToNonConformantCoherentFramebufferFetch: true}, |
435 | // From: TraceTest.special_forces_group_2 http://anglebug.com/5592 |
436 | { |
437 | .messageId: "SYNC-HAZARD-WRITE-AFTER-READ" , |
438 | .messageContents1: "Access info (usage: SYNC_IMAGE_LAYOUT_TRANSITION, prior_usage: " |
439 | "SYNC_FRAGMENT_SHADER_SHADER_" , |
440 | }, |
441 | // http://anglebug.com/7031 |
442 | {.messageId: "SYNC-HAZARD-READ-AFTER-WRITE" , |
443 | .messageContents1: "type: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, imageLayout: " |
444 | "VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, binding #0, index 0. Access info (usage: " |
445 | "SYNC_COMPUTE_SHADER_SHADER_" , |
446 | .messageContents2: "" , .isDueToNonConformantCoherentFramebufferFetch: false}, |
447 | // http://anglebug.com/7456 |
448 | { |
449 | .messageId: "SYNC-HAZARD-READ-AFTER-WRITE" , |
450 | .messageContents1: "type: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, " |
451 | "imageLayout: VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL" , |
452 | .messageContents2: "Access info (usage: SYNC_FRAGMENT_SHADER_SHADER_" , |
453 | }, |
454 | // From: TraceTest.life_is_strange http://anglebug.com/7711 |
455 | {.messageId: "SYNC-HAZARD-WRITE-AFTER-READ" , |
456 | .messageContents1: "vkCmdEndRenderPass: Hazard WRITE_AFTER_READ in subpass 0 for attachment 1 " |
457 | "depth aspect during store with storeOp VK_ATTACHMENT_STORE_OP_DONT_CARE. " |
458 | "Access info (usage: SYNC_LATE_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE, " |
459 | "prior_usage: SYNC_FRAGMENT_SHADER_SHADER_" }, |
460 | // From: TraceTest.life_is_strange http://anglebug.com/7711 |
461 | {.messageId: "SYNC-HAZARD-READ-AFTER-WRITE" , |
462 | .messageContents1: "type: VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, " |
463 | "imageLayout: VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL" , |
464 | .messageContents2: "usage: SYNC_FRAGMENT_SHADER_SHADER_" }, |
465 | // From: TraceTest.diablo_immortal http://anglebug.com/7837 |
466 | {.messageId: "SYNC-HAZARD-WRITE-AFTER-WRITE" , .messageContents1: "vkCmdDrawIndexed: Hazard WRITE_AFTER_WRITE for VkImageView " , |
467 | .messageContents2: "Subpass #0, and pColorAttachments #0. Access info (usage: " |
468 | "SYNC_COLOR_ATTACHMENT_OUTPUT_COLOR_ATTACHMENT_WRITE, prior_usage: " |
469 | "SYNC_IMAGE_LAYOUT_TRANSITION, write_barriers: 0, command: vkCmdEndRenderPass" }, |
470 | // From: TraceTest.diablo_immortal http://anglebug.com/7837 |
471 | {.messageId: "SYNC-HAZARD-WRITE-AFTER-READ" , |
472 | .messageContents1: "load with loadOp VK_ATTACHMENT_LOAD_OP_DONT_CARE. Access info (usage: " |
473 | "SYNC_EARLY_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE, prior_usage: " |
474 | "SYNC_FRAGMENT_SHADER_SHADER_" }, |
475 | // From: TraceTest.catalyst_black http://anglebug.com/7924 |
476 | {.messageId: "SYNC-HAZARD-WRITE-AFTER-READ" , |
477 | .messageContents1: "store with storeOp VK_ATTACHMENT_STORE_OP_STORE. Access info (usage: " |
478 | "SYNC_LATE_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE, prior_usage: " |
479 | "SYNC_FRAGMENT_SHADER_SHADER_" }, |
480 | }; |
481 | |
482 | // Messages that shouldn't be generated if storeOp=NONE is supported, otherwise they are expected. |
483 | constexpr vk::SkippedSyncvalMessage kSkippedSyncvalMessagesWithoutStoreOpNone[] = { |
484 | // These errors are generated when simultaneously using a read-only depth/stencil attachment as |
485 | // sampler. This is valid Vulkan. |
486 | // |
487 | // When storeOp=NONE is not present, ANGLE uses storeOp=STORE, but considers the image read-only |
488 | // and produces a hazard. ANGLE relies on storeOp=NONE and so this is not expected to be worked |
489 | // around. |
490 | // |
491 | // With storeOp=NONE, there is another bug where a depth/stencil attachment may use storeOp=NONE |
492 | // for depth while storeOp=DONT_CARE for stencil, and the latter causes a synchronization error |
493 | // (similarly to the previous case as DONT_CARE is also a write operation). |
494 | // http://anglebug.com/5962 |
495 | { |
496 | .messageId: "SYNC-HAZARD-WRITE-AFTER-READ" , |
497 | .messageContents1: "depth aspect during store with storeOp VK_ATTACHMENT_STORE_OP_STORE. Access info (usage: " |
498 | "SYNC_LATE_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE" , |
499 | .messageContents2: "usage: SYNC_FRAGMENT_SHADER_SHADER_" , |
500 | }, |
501 | { |
502 | .messageId: "SYNC-HAZARD-WRITE-AFTER-READ" , |
503 | .messageContents1: "stencil aspect during store with stencilStoreOp VK_ATTACHMENT_STORE_OP_STORE. Access info " |
504 | "(usage: SYNC_LATE_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE" , |
505 | .messageContents2: "usage: SYNC_FRAGMENT_SHADER_SHADER_" , |
506 | }, |
507 | { |
508 | .messageId: "SYNC-HAZARD-READ-AFTER-WRITE" , |
509 | .messageContents1: "imageLayout: VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL" , |
510 | .messageContents2: "usage: SYNC_FRAGMENT_SHADER_SHADER_" , |
511 | }, |
512 | // From: TraceTest.antutu_refinery http://anglebug.com/6663 |
513 | { |
514 | .messageId: "SYNC-HAZARD-READ-AFTER-WRITE" , |
515 | .messageContents1: "imageLayout: VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL" , |
516 | .messageContents2: "usage: SYNC_COMPUTE_SHADER_SHADER_SAMPLED_READ" , |
517 | }, |
518 | }; |
519 | |
520 | // Messages that shouldn't be generated if both loadOp=NONE and storeOp=NONE are supported, |
521 | // otherwise they are expected. |
522 | constexpr vk::SkippedSyncvalMessage kSkippedSyncvalMessagesWithoutLoadStoreOpNone[] = { |
523 | // This error is generated for multiple reasons: |
524 | // |
525 | // - http://anglebug.com/6411 |
526 | // - http://anglebug.com/5371: This is resolved with storeOp=NONE |
527 | { |
528 | .messageId: "SYNC-HAZARD-WRITE-AFTER-WRITE" , |
529 | .messageContents1: "Access info (usage: SYNC_IMAGE_LAYOUT_TRANSITION, prior_usage: " |
530 | "SYNC_LATE_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE, write_barriers: 0, command: " |
531 | "vkCmdEndRenderPass" , |
532 | }, |
533 | // http://anglebug.com/6411 |
534 | // http://anglebug.com/6584 |
535 | { |
536 | .messageId: "SYNC-HAZARD-WRITE-AFTER-WRITE" , |
537 | .messageContents1: "aspect depth during load with loadOp VK_ATTACHMENT_LOAD_OP_DONT_CARE. Access info (usage: " |
538 | "SYNC_EARLY_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE, prior_usage: " |
539 | "SYNC_IMAGE_LAYOUT_TRANSITION" , |
540 | }, |
541 | { |
542 | .messageId: "SYNC-HAZARD-WRITE-AFTER-WRITE" , |
543 | .messageContents1: "aspect stencil during load with loadOp VK_ATTACHMENT_LOAD_OP_DONT_CARE. Access info " |
544 | "(usage: " |
545 | "SYNC_EARLY_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE" , |
546 | }, |
547 | // http://anglebug.com/5962 |
548 | { |
549 | .messageId: "SYNC-HAZARD-WRITE-AFTER-WRITE" , |
550 | .messageContents1: "aspect stencil during load with loadOp VK_ATTACHMENT_LOAD_OP_DONT_CARE. Access info " |
551 | "(usage: " |
552 | "SYNC_EARLY_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE, prior_usage: " |
553 | "SYNC_IMAGE_LAYOUT_TRANSITION" , |
554 | }, |
555 | { |
556 | .messageId: "SYNC-HAZARD-WRITE-AFTER-WRITE" , |
557 | .messageContents1: "aspect stencil during load with loadOp VK_ATTACHMENT_LOAD_OP_DONT_CARE. Access info " |
558 | "(usage: " |
559 | "SYNC_EARLY_FRAGMENT_TESTS_DEPTH_STENCIL_ATTACHMENT_WRITE, prior_usage: " |
560 | "SYNC_IMAGE_LAYOUT_TRANSITION" , |
561 | }, |
562 | }; |
563 | |
564 | enum class DebugMessageReport |
565 | { |
566 | Ignore, |
567 | Print, |
568 | }; |
569 | |
570 | bool IsMessageInSkipList(const char *message, |
571 | const char *const skippedList[], |
572 | size_t skippedListSize) |
573 | { |
574 | for (size_t index = 0; index < skippedListSize; ++index) |
575 | { |
576 | if (strstr(s1: message, s2: skippedList[index]) != nullptr) |
577 | { |
578 | return true; |
579 | } |
580 | } |
581 | |
582 | return false; |
583 | } |
584 | |
585 | // Suppress validation errors that are known. Returns DebugMessageReport::Ignore in that case. |
586 | DebugMessageReport ShouldReportDebugMessage(RendererVk *renderer, |
587 | const char *messageId, |
588 | const char *message) |
589 | { |
590 | if (message == nullptr || messageId == nullptr) |
591 | { |
592 | return DebugMessageReport::Print; |
593 | } |
594 | |
595 | // Check with non-syncval messages: |
596 | const std::vector<const char *> &skippedMessages = renderer->getSkippedValidationMessages(); |
597 | if (IsMessageInSkipList(message, skippedList: skippedMessages.data(), skippedListSize: skippedMessages.size())) |
598 | { |
599 | return DebugMessageReport::Ignore; |
600 | } |
601 | |
602 | // Then check with syncval messages: |
603 | const bool isFramebufferFetchUsed = renderer->isFramebufferFetchUsed(); |
604 | |
605 | for (const vk::SkippedSyncvalMessage &msg : renderer->getSkippedSyncvalMessages()) |
606 | { |
607 | if (strstr(s1: messageId, s2: msg.messageId) == nullptr || |
608 | strstr(s1: message, s2: msg.messageContents1) == nullptr || |
609 | strstr(s1: message, s2: msg.messageContents2) == nullptr) |
610 | { |
611 | continue; |
612 | } |
613 | |
614 | // If the error is due to exposing coherent framebuffer fetch (without |
615 | // VK_EXT_rasterization_order_attachment_access), but framebuffer fetch has not been used by |
616 | // the application, report it. |
617 | // |
618 | // Note that currently syncval doesn't support the |
619 | // VK_EXT_rasterization_order_attachment_access extension, so the syncval messages would |
620 | // continue to be produced despite the extension. |
621 | constexpr bool kSyncValSupportsRasterizationOrderExtension = false; |
622 | const bool hasRasterizationOrderExtension = |
623 | renderer->getFeatures().supportsRasterizationOrderAttachmentAccess.enabled && |
624 | kSyncValSupportsRasterizationOrderExtension; |
625 | if (msg.isDueToNonConformantCoherentFramebufferFetch && |
626 | (!isFramebufferFetchUsed || hasRasterizationOrderExtension)) |
627 | { |
628 | return DebugMessageReport::Print; |
629 | } |
630 | |
631 | // Otherwise ignore the message |
632 | return DebugMessageReport::Ignore; |
633 | } |
634 | |
635 | return DebugMessageReport::Print; |
636 | } |
637 | |
638 | const char *GetVkObjectTypeName(VkObjectType type) |
639 | { |
640 | switch (type) |
641 | { |
642 | case VK_OBJECT_TYPE_UNKNOWN: |
643 | return "Unknown" ; |
644 | case VK_OBJECT_TYPE_INSTANCE: |
645 | return "Instance" ; |
646 | case VK_OBJECT_TYPE_PHYSICAL_DEVICE: |
647 | return "Physical Device" ; |
648 | case VK_OBJECT_TYPE_DEVICE: |
649 | return "Device" ; |
650 | case VK_OBJECT_TYPE_QUEUE: |
651 | return "Queue" ; |
652 | case VK_OBJECT_TYPE_SEMAPHORE: |
653 | return "Semaphore" ; |
654 | case VK_OBJECT_TYPE_COMMAND_BUFFER: |
655 | return "Command Buffer" ; |
656 | case VK_OBJECT_TYPE_FENCE: |
657 | return "Fence" ; |
658 | case VK_OBJECT_TYPE_DEVICE_MEMORY: |
659 | return "Device Memory" ; |
660 | case VK_OBJECT_TYPE_BUFFER: |
661 | return "Buffer" ; |
662 | case VK_OBJECT_TYPE_IMAGE: |
663 | return "Image" ; |
664 | case VK_OBJECT_TYPE_EVENT: |
665 | return "Event" ; |
666 | case VK_OBJECT_TYPE_QUERY_POOL: |
667 | return "Query Pool" ; |
668 | case VK_OBJECT_TYPE_BUFFER_VIEW: |
669 | return "Buffer View" ; |
670 | case VK_OBJECT_TYPE_IMAGE_VIEW: |
671 | return "Image View" ; |
672 | case VK_OBJECT_TYPE_SHADER_MODULE: |
673 | return "Shader Module" ; |
674 | case VK_OBJECT_TYPE_PIPELINE_CACHE: |
675 | return "Pipeline Cache" ; |
676 | case VK_OBJECT_TYPE_PIPELINE_LAYOUT: |
677 | return "Pipeline Layout" ; |
678 | case VK_OBJECT_TYPE_RENDER_PASS: |
679 | return "Render Pass" ; |
680 | case VK_OBJECT_TYPE_PIPELINE: |
681 | return "Pipeline" ; |
682 | case VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT: |
683 | return "Descriptor Set Layout" ; |
684 | case VK_OBJECT_TYPE_SAMPLER: |
685 | return "Sampler" ; |
686 | case VK_OBJECT_TYPE_DESCRIPTOR_POOL: |
687 | return "Descriptor Pool" ; |
688 | case VK_OBJECT_TYPE_DESCRIPTOR_SET: |
689 | return "Descriptor Set" ; |
690 | case VK_OBJECT_TYPE_FRAMEBUFFER: |
691 | return "Framebuffer" ; |
692 | case VK_OBJECT_TYPE_COMMAND_POOL: |
693 | return "Command Pool" ; |
694 | case VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION: |
695 | return "Sampler YCbCr Conversion" ; |
696 | case VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE: |
697 | return "Descriptor Update Template" ; |
698 | case VK_OBJECT_TYPE_SURFACE_KHR: |
699 | return "Surface" ; |
700 | case VK_OBJECT_TYPE_SWAPCHAIN_KHR: |
701 | return "Swapchain" ; |
702 | case VK_OBJECT_TYPE_DISPLAY_KHR: |
703 | return "Display" ; |
704 | case VK_OBJECT_TYPE_DISPLAY_MODE_KHR: |
705 | return "Display Mode" ; |
706 | case VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV: |
707 | return "Indirect Commands Layout" ; |
708 | case VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT: |
709 | return "Debug Utils Messenger" ; |
710 | case VK_OBJECT_TYPE_VALIDATION_CACHE_EXT: |
711 | return "Validation Cache" ; |
712 | case VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV: |
713 | return "Acceleration Structure" ; |
714 | default: |
715 | return "<Unrecognized>" ; |
716 | } |
717 | } |
718 | |
719 | VKAPI_ATTR VkBool32 VKAPI_CALL |
720 | DebugUtilsMessenger(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, |
721 | VkDebugUtilsMessageTypeFlagsEXT messageTypes, |
722 | const VkDebugUtilsMessengerCallbackDataEXT *callbackData, |
723 | void *userData) |
724 | { |
725 | RendererVk *rendererVk = static_cast<RendererVk *>(userData); |
726 | |
727 | // See if it's an issue we are aware of and don't want to be spammed about. |
728 | if (ShouldReportDebugMessage(renderer: rendererVk, messageId: callbackData->pMessageIdName, |
729 | message: callbackData->pMessage) == DebugMessageReport::Ignore) |
730 | { |
731 | return VK_FALSE; |
732 | } |
733 | |
734 | std::ostringstream log; |
735 | if (callbackData->pMessageIdName) |
736 | { |
737 | log << "[ " << callbackData->pMessageIdName << " ] " ; |
738 | } |
739 | log << callbackData->pMessage << std::endl; |
740 | |
741 | // Aesthetic value based on length of the function name, line number, etc. |
742 | constexpr size_t kStartIndent = 28; |
743 | |
744 | // Output the debug marker hierarchy under which this error has occured. |
745 | size_t indent = kStartIndent; |
746 | if (callbackData->queueLabelCount > 0) |
747 | { |
748 | log << std::string(indent++, ' ') << "<Queue Label Hierarchy:>" << std::endl; |
749 | for (uint32_t i = 0; i < callbackData->queueLabelCount; ++i) |
750 | { |
751 | log << std::string(indent++, ' ') << callbackData->pQueueLabels[i].pLabelName |
752 | << std::endl; |
753 | } |
754 | } |
755 | if (callbackData->cmdBufLabelCount > 0) |
756 | { |
757 | log << std::string(indent++, ' ') << "<Command Buffer Label Hierarchy:>" << std::endl; |
758 | for (uint32_t i = 0; i < callbackData->cmdBufLabelCount; ++i) |
759 | { |
760 | log << std::string(indent++, ' ') << callbackData->pCmdBufLabels[i].pLabelName |
761 | << std::endl; |
762 | } |
763 | } |
764 | // Output the objects involved in this error message. |
765 | if (callbackData->objectCount > 0) |
766 | { |
767 | for (uint32_t i = 0; i < callbackData->objectCount; ++i) |
768 | { |
769 | const char *objectName = callbackData->pObjects[i].pObjectName; |
770 | const char *objectType = GetVkObjectTypeName(type: callbackData->pObjects[i].objectType); |
771 | uint64_t objectHandle = callbackData->pObjects[i].objectHandle; |
772 | log << std::string(indent, ' ') << "Object: " ; |
773 | if (objectHandle == 0) |
774 | { |
775 | log << "VK_NULL_HANDLE" ; |
776 | } |
777 | else |
778 | { |
779 | log << "0x" << std::hex << objectHandle << std::dec; |
780 | } |
781 | log << " (type = " << objectType << "(" << callbackData->pObjects[i].objectType << "))" ; |
782 | if (objectName) |
783 | { |
784 | log << " [" << objectName << "]" ; |
785 | } |
786 | log << std::endl; |
787 | } |
788 | } |
789 | |
790 | bool isError = (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0; |
791 | std::string msg = log.str(); |
792 | |
793 | rendererVk->onNewValidationMessage(message: msg); |
794 | |
795 | if (isError) |
796 | { |
797 | ERR() << msg; |
798 | } |
799 | else |
800 | { |
801 | WARN() << msg; |
802 | } |
803 | |
804 | return VK_FALSE; |
805 | } |
806 | |
807 | VKAPI_ATTR void VKAPI_CALL |
808 | MemoryReportCallback(const VkDeviceMemoryReportCallbackDataEXT *callbackData, void *userData) |
809 | { |
810 | RendererVk *rendererVk = static_cast<RendererVk *>(userData); |
811 | rendererVk->processMemoryReportCallback(callbackData: *callbackData); |
812 | } |
813 | |
814 | bool ShouldUseValidationLayers(const egl::AttributeMap &attribs) |
815 | { |
816 | #if defined(ANGLE_ENABLE_VULKAN_VALIDATION_LAYERS_BY_DEFAULT) |
817 | return ShouldUseDebugLayers(attribs); |
818 | #else |
819 | EGLAttrib debugSetting = |
820 | attribs.get(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE, EGL_DONT_CARE); |
821 | return debugSetting == EGL_TRUE; |
822 | #endif // defined(ANGLE_ENABLE_VULKAN_VALIDATION_LAYERS_BY_DEFAULT) |
823 | } |
824 | |
825 | gl::Version LimitVersionTo(const gl::Version ¤t, const gl::Version &lower) |
826 | { |
827 | return std::min(a: current, b: lower); |
828 | } |
829 | |
830 | [[maybe_unused]] bool FencePropertiesCompatibleWithAndroid( |
831 | const VkExternalFenceProperties &externalFenceProperties) |
832 | { |
833 | // handleType here is the external fence type - |
834 | // we want type compatible with creating and export/dup() Android FD |
835 | |
836 | // Imported handleType that can be exported - need for vkGetFenceFdKHR() |
837 | if ((externalFenceProperties.exportFromImportedHandleTypes & |
838 | VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR) == 0) |
839 | { |
840 | return false; |
841 | } |
842 | |
843 | // HandleTypes which can be specified at creating a fence |
844 | if ((externalFenceProperties.compatibleHandleTypes & |
845 | VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR) == 0) |
846 | { |
847 | return false; |
848 | } |
849 | |
850 | constexpr VkExternalFenceFeatureFlags kFeatureFlags = |
851 | (VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR | |
852 | VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR); |
853 | if ((externalFenceProperties.externalFenceFeatures & kFeatureFlags) != kFeatureFlags) |
854 | { |
855 | return false; |
856 | } |
857 | |
858 | return true; |
859 | } |
860 | |
861 | [[maybe_unused]] bool SemaphorePropertiesCompatibleWithAndroid( |
862 | const VkExternalSemaphoreProperties &externalSemaphoreProperties) |
863 | { |
864 | // handleType here is the external semaphore type - |
865 | // we want type compatible with importing an Android FD |
866 | |
867 | constexpr VkExternalSemaphoreFeatureFlags kFeatureFlags = |
868 | (VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR); |
869 | if ((externalSemaphoreProperties.externalSemaphoreFeatures & kFeatureFlags) != kFeatureFlags) |
870 | { |
871 | return false; |
872 | } |
873 | |
874 | return true; |
875 | } |
876 | |
877 | // CRC16-CCITT is used for header before the pipeline cache key data. |
878 | uint16_t ComputeCRC16(const uint8_t *data, const size_t size) |
879 | { |
880 | constexpr uint16_t kPolynomialCRC16 = 0x8408; |
881 | uint16_t rem = 0; |
882 | |
883 | for (size_t i = 0; i < size; i++) |
884 | { |
885 | rem ^= data[i]; |
886 | for (int j = 0; j < 8; j++) |
887 | { |
888 | rem = (rem & 1) ? kPolynomialCRC16 ^ (rem >> 1) : rem >> 1; |
889 | } |
890 | } |
891 | return rem; |
892 | } |
893 | |
894 | // Header data type used for the pipeline cache. |
895 | ANGLE_ENABLE_STRUCT_PADDING_WARNINGS |
896 | |
897 | class |
898 | { |
899 | public: |
900 | void (uint16_t compressedDataCRC, |
901 | uint32_t cacheDataSize, |
902 | uint16_t numChunks, |
903 | uint16_t chunkIndex) |
904 | { |
905 | mVersion = kPipelineCacheVersion; |
906 | mCompressedDataCRC = compressedDataCRC; |
907 | mCacheDataSize = cacheDataSize; |
908 | mNumChunks = numChunks; |
909 | mChunkIndex = chunkIndex; |
910 | } |
911 | |
912 | void (uint16_t *versionOut, |
913 | uint16_t *compressedDataCRCOut, |
914 | uint32_t *cacheDataSizeOut, |
915 | size_t *numChunksOut, |
916 | size_t *chunkIndexOut) const |
917 | { |
918 | *versionOut = mVersion; |
919 | *compressedDataCRCOut = mCompressedDataCRC; |
920 | *cacheDataSizeOut = mCacheDataSize; |
921 | *numChunksOut = static_cast<size_t>(mNumChunks); |
922 | *chunkIndexOut = static_cast<size_t>(mChunkIndex); |
923 | } |
924 | |
925 | private: |
926 | // For pipeline cache, the values stored in key data has the following order: |
927 | // {headerVersion, compressedDataCRC, originalCacheSize, numChunks, chunkIndex; |
928 | // chunkCompressedData}. The header values are used to validate the data. For example, if the |
929 | // original and compressed sizes are 70000 bytes (68k) and 68841 bytes (67k), the compressed |
930 | // data will be divided into two chunks: {ver,crc0,70000,2,0;34421 bytes} and |
931 | // {ver,crc1,70000,2,1;34420 bytes}. |
932 | // The version is used to keep track of the cache format. Please note that kPipelineCacheVersion |
933 | // must be incremented by 1 in case of any updates to the cache header or data structure. While |
934 | // it is possible to modify the fields in the header, it is recommended to keep the version on |
935 | // top and the same size unless absolutely necessary. |
936 | |
937 | uint16_t ; |
938 | uint16_t ; |
939 | uint32_t ; |
940 | uint16_t ; |
941 | uint16_t ; |
942 | }; |
943 | |
944 | ANGLE_DISABLE_STRUCT_PADDING_WARNINGS |
945 | |
946 | // Pack header data for the pipeline cache key data. |
947 | void (uint16_t compressedDataCRC, |
948 | uint32_t cacheDataSize, |
949 | uint16_t numChunks, |
950 | uint16_t chunkIndex, |
951 | CacheDataHeader *dataOut) |
952 | { |
953 | dataOut->setData(compressedDataCRC, cacheDataSize, numChunks, chunkIndex); |
954 | } |
955 | |
956 | // Unpack header data from the pipeline cache key data. |
957 | void (CacheDataHeader *data, |
958 | uint16_t *versionOut, |
959 | uint16_t *compressedDataCRCOut, |
960 | uint32_t *cacheDataSizeOut, |
961 | size_t *numChunksOut, |
962 | size_t *chunkIndexOut) |
963 | { |
964 | data->getData(versionOut, compressedDataCRCOut, cacheDataSizeOut, numChunksOut, chunkIndexOut); |
965 | } |
966 | |
967 | void ComputePipelineCacheVkChunkKey(VkPhysicalDeviceProperties physicalDeviceProperties, |
968 | const uint8_t chunkIndex, |
969 | egl::BlobCache::Key *hashOut) |
970 | { |
971 | std::ostringstream hashStream("ANGLE Pipeline Cache: " , std::ios_base::ate); |
972 | // Add the pipeline cache UUID to make sure the blob cache always gives a compatible pipeline |
973 | // cache. It's not particularly necessary to write it as a hex number as done here, so long as |
974 | // there is no '\0' in the result. |
975 | for (const uint32_t c : physicalDeviceProperties.pipelineCacheUUID) |
976 | { |
977 | hashStream << std::hex << c; |
978 | } |
979 | // Add the vendor and device id too for good measure. |
980 | hashStream << std::hex << physicalDeviceProperties.vendorID; |
981 | hashStream << std::hex << physicalDeviceProperties.deviceID; |
982 | |
983 | // Add chunkIndex to generate unique key for chunks. |
984 | hashStream << std::hex << static_cast<uint32_t>(chunkIndex); |
985 | |
986 | const std::string &hashString = hashStream.str(); |
987 | angle::base::SHA1HashBytes(data: reinterpret_cast<const unsigned char *>(hashString.c_str()), |
988 | len: hashString.length(), hash: hashOut->data()); |
989 | } |
990 | |
991 | void CompressAndStorePipelineCacheVk(VkPhysicalDeviceProperties physicalDeviceProperties, |
992 | DisplayVk *displayVk, |
993 | ContextVk *contextVk, |
994 | const std::vector<uint8_t> &cacheData, |
995 | const size_t maxTotalSize) |
996 | { |
997 | // Though the pipeline cache will be compressed and divided into several chunks to store in blob |
998 | // cache, the largest total size of blob cache is only 2M in android now, so there is no use to |
999 | // handle big pipeline cache when android will reject it finally. |
1000 | if (cacheData.size() >= maxTotalSize) |
1001 | { |
1002 | // TODO: handle the big pipeline cache. http://anglebug.com/4722 |
1003 | ANGLE_PERF_WARNING(contextVk->getDebug(), GL_DEBUG_SEVERITY_LOW, |
1004 | "Skip syncing pipeline cache data when it's larger than maxTotalSize." ); |
1005 | return; |
1006 | } |
1007 | |
1008 | // To make it possible to store more pipeline cache data, compress the whole pipelineCache. |
1009 | angle::MemoryBuffer compressedData; |
1010 | |
1011 | if (!egl::CompressBlobCacheData(cacheSize: cacheData.size(), cacheData: cacheData.data(), compressedData: &compressedData)) |
1012 | { |
1013 | ANGLE_PERF_WARNING(contextVk->getDebug(), GL_DEBUG_SEVERITY_LOW, |
1014 | "Skip syncing pipeline cache data as it failed compression." ); |
1015 | return; |
1016 | } |
1017 | |
1018 | // If the size of compressedData is larger than (kMaxBlobCacheSize - sizeof(numChunks)), |
1019 | // the pipelineCache still can't be stored in blob cache. Divide the large compressed |
1020 | // pipelineCache into several parts to store seperately. There is no function to |
1021 | // query the limit size in android. |
1022 | constexpr size_t kMaxBlobCacheSize = 64 * 1024; |
1023 | size_t compressedOffset = 0; |
1024 | |
1025 | const size_t numChunks = UnsignedCeilDivide(value: static_cast<unsigned int>(compressedData.size()), |
1026 | divisor: kMaxBlobCacheSize - sizeof(CacheDataHeader)); |
1027 | ASSERT(numChunks <= UINT16_MAX); |
1028 | size_t chunkSize = UnsignedCeilDivide(value: static_cast<unsigned int>(compressedData.size()), |
1029 | divisor: static_cast<unsigned int>(numChunks)); |
1030 | uint16_t compressedDataCRC = 0; |
1031 | if (kEnableCRCForPipelineCache) |
1032 | { |
1033 | compressedDataCRC = ComputeCRC16(data: compressedData.data(), size: compressedData.size()); |
1034 | } |
1035 | |
1036 | for (size_t chunkIndex = 0; chunkIndex < numChunks; ++chunkIndex) |
1037 | { |
1038 | if (chunkIndex == numChunks - 1) |
1039 | { |
1040 | chunkSize = compressedData.size() - compressedOffset; |
1041 | } |
1042 | |
1043 | angle::MemoryBuffer keyData; |
1044 | if (!keyData.resize(size: sizeof(CacheDataHeader) + chunkSize)) |
1045 | { |
1046 | ANGLE_PERF_WARNING(contextVk->getDebug(), GL_DEBUG_SEVERITY_LOW, |
1047 | "Skip syncing pipeline cache data due to out of memory." ); |
1048 | return; |
1049 | } |
1050 | |
1051 | // Add the header data, followed by the compressed data. |
1052 | ASSERT(cacheData.size() <= UINT32_MAX); |
1053 | CacheDataHeader = {}; |
1054 | PackHeaderDataForPipelineCache(compressedDataCRC, cacheDataSize: static_cast<uint32_t>(cacheData.size()), |
1055 | numChunks: static_cast<uint16_t>(numChunks), |
1056 | chunkIndex: static_cast<uint16_t>(chunkIndex), dataOut: &headerData); |
1057 | memcpy(dest: keyData.data(), src: &headerData, n: sizeof(CacheDataHeader)); |
1058 | memcpy(dest: keyData.data() + sizeof(CacheDataHeader), src: compressedData.data() + compressedOffset, |
1059 | n: chunkSize); |
1060 | compressedOffset += chunkSize; |
1061 | |
1062 | // Create unique hash key. |
1063 | egl::BlobCache::Key chunkCacheHash; |
1064 | ComputePipelineCacheVkChunkKey(physicalDeviceProperties, chunkIndex, hashOut: &chunkCacheHash); |
1065 | |
1066 | displayVk->getBlobCache()->putApplication(key: chunkCacheHash, value: keyData); |
1067 | } |
1068 | } |
1069 | |
1070 | class CompressAndStorePipelineCacheTask : public angle::Closure |
1071 | { |
1072 | public: |
1073 | CompressAndStorePipelineCacheTask(DisplayVk *displayVk, |
1074 | ContextVk *contextVk, |
1075 | std::vector<uint8_t> &&cacheData, |
1076 | size_t kMaxTotalSize) |
1077 | : mDisplayVk(displayVk), |
1078 | mContextVk(contextVk), |
1079 | mCacheData(std::move(cacheData)), |
1080 | mMaxTotalSize(kMaxTotalSize) |
1081 | {} |
1082 | |
1083 | void operator()() override |
1084 | { |
1085 | ANGLE_TRACE_EVENT0("gpu.angle" , "CompressAndStorePipelineCacheVk" ); |
1086 | CompressAndStorePipelineCacheVk(physicalDeviceProperties: mContextVk->getRenderer()->getPhysicalDeviceProperties(), |
1087 | displayVk: mDisplayVk, contextVk: mContextVk, cacheData: mCacheData, maxTotalSize: mMaxTotalSize); |
1088 | } |
1089 | |
1090 | private: |
1091 | DisplayVk *mDisplayVk; |
1092 | ContextVk *mContextVk; |
1093 | std::vector<uint8_t> mCacheData; |
1094 | size_t mMaxTotalSize; |
1095 | }; |
1096 | |
1097 | class WaitableCompressEventImpl : public WaitableCompressEvent |
1098 | { |
1099 | public: |
1100 | WaitableCompressEventImpl(std::shared_ptr<angle::WaitableEvent> waitableEvent, |
1101 | std::shared_ptr<CompressAndStorePipelineCacheTask> compressTask) |
1102 | : WaitableCompressEvent(waitableEvent), mCompressTask(compressTask) |
1103 | {} |
1104 | |
1105 | private: |
1106 | std::shared_ptr<CompressAndStorePipelineCacheTask> mCompressTask; |
1107 | }; |
1108 | |
1109 | angle::Result GetAndDecompressPipelineCacheVk(VkPhysicalDeviceProperties physicalDeviceProperties, |
1110 | DisplayVk *displayVk, |
1111 | angle::MemoryBuffer *uncompressedData, |
1112 | bool *success) |
1113 | { |
1114 | // Make sure that the bool output is initialized to false. |
1115 | *success = false; |
1116 | |
1117 | // Compute the hash key of chunkIndex 0 and find the first cache data in blob cache. |
1118 | egl::BlobCache::Key chunkCacheHash; |
1119 | ComputePipelineCacheVkChunkKey(physicalDeviceProperties, chunkIndex: 0, hashOut: &chunkCacheHash); |
1120 | egl::BlobCache::Value keyData; |
1121 | size_t keySize = 0; |
1122 | |
1123 | if (!displayVk->getBlobCache()->get(scratchBuffer: displayVk->getScratchBuffer(), key: chunkCacheHash, valueOut: &keyData, |
1124 | bufferSizeOut: &keySize) || |
1125 | keyData.size() < sizeof(CacheDataHeader)) |
1126 | { |
1127 | // Nothing in the cache. |
1128 | return angle::Result::Continue; |
1129 | } |
1130 | |
1131 | // Get the number of chunks and other values from the header for data validation. |
1132 | uint16_t cacheVersion; |
1133 | uint16_t compressedDataCRC; |
1134 | uint32_t uncompressedCacheDataSize; |
1135 | size_t numChunks; |
1136 | size_t chunkIndex0; |
1137 | |
1138 | CacheDataHeader = {}; |
1139 | memcpy(dest: &headerData, src: keyData.data(), n: sizeof(CacheDataHeader)); |
1140 | UnpackHeaderDataForPipelineCache(data: &headerData, versionOut: &cacheVersion, compressedDataCRCOut: &compressedDataCRC, |
1141 | cacheDataSizeOut: &uncompressedCacheDataSize, numChunksOut: &numChunks, chunkIndexOut: &chunkIndex0); |
1142 | if (cacheVersion == kPipelineCacheVersion) |
1143 | { |
1144 | // The data must not contain corruption. |
1145 | if (chunkIndex0 != 0 || numChunks == 0 || uncompressedCacheDataSize == 0) |
1146 | { |
1147 | FATAL() << "Unexpected values while unpacking chunk index 0: " |
1148 | << "cacheVersion = " << cacheVersion << ", chunkIndex = " << chunkIndex0 |
1149 | << ", numChunks = " << numChunks |
1150 | << ", uncompressedCacheDataSize = " << uncompressedCacheDataSize; |
1151 | } |
1152 | } |
1153 | else |
1154 | { |
1155 | // Either the header structure has been updated, or the header value has been changed. |
1156 | if (cacheVersion > kPipelineCacheVersion + (1 << 8)) |
1157 | { |
1158 | // TODO(abdolrashidi): Data corruption in the version should result in a fatal error. |
1159 | // For now, a warning is shown instead, but it should change when the version field is |
1160 | // no longer new. |
1161 | WARN() << "Existing cache version is significantly greater than the new version" |
1162 | ", possibly due to data corruption: " |
1163 | << "newVersion = " << kPipelineCacheVersion |
1164 | << ", existingVersion = " << cacheVersion; |
1165 | } |
1166 | else |
1167 | { |
1168 | WARN() << "Change in cache header version detected: " |
1169 | << "newVersion = " << kPipelineCacheVersion |
1170 | << ", existingVersion = " << cacheVersion; |
1171 | } |
1172 | return angle::Result::Continue; |
1173 | } |
1174 | |
1175 | size_t chunkSize = keySize - sizeof(CacheDataHeader); |
1176 | size_t compressedSize = 0; |
1177 | |
1178 | // Allocate enough memory. |
1179 | angle::MemoryBuffer compressedData; |
1180 | ANGLE_VK_CHECK(displayVk, compressedData.resize(chunkSize * numChunks), |
1181 | VK_ERROR_INITIALIZATION_FAILED); |
1182 | |
1183 | // To combine the parts of the pipelineCache data. |
1184 | for (size_t chunkIndex = 0; chunkIndex < numChunks; ++chunkIndex) |
1185 | { |
1186 | // Get the unique key by chunkIndex. |
1187 | ComputePipelineCacheVkChunkKey(physicalDeviceProperties, chunkIndex, hashOut: &chunkCacheHash); |
1188 | |
1189 | if (!displayVk->getBlobCache()->get(scratchBuffer: displayVk->getScratchBuffer(), key: chunkCacheHash, valueOut: &keyData, |
1190 | bufferSizeOut: &keySize) || |
1191 | keyData.size() < sizeof(CacheDataHeader)) |
1192 | { |
1193 | // Can't find every part of the cache data. |
1194 | WARN() << "Failed to get pipeline cache chunk " << chunkIndex << " of " << numChunks; |
1195 | return angle::Result::Continue; |
1196 | } |
1197 | |
1198 | // Validate the header values and ensure there is enough space to store. |
1199 | uint16_t checkCacheVersion; |
1200 | uint16_t checkCompressedDataCRC; |
1201 | uint32_t checkUncompressedCacheDataSize; |
1202 | size_t checkNumChunks; |
1203 | size_t checkChunkIndex; |
1204 | |
1205 | memcpy(dest: &headerData, src: keyData.data(), n: sizeof(CacheDataHeader)); |
1206 | UnpackHeaderDataForPipelineCache(data: &headerData, versionOut: &checkCacheVersion, compressedDataCRCOut: &checkCompressedDataCRC, |
1207 | cacheDataSizeOut: &checkUncompressedCacheDataSize, numChunksOut: &checkNumChunks, |
1208 | chunkIndexOut: &checkChunkIndex); |
1209 | |
1210 | chunkSize = keySize - sizeof(CacheDataHeader); |
1211 | bool = |
1212 | (checkCacheVersion != cacheVersion) || (checkNumChunks != numChunks) || |
1213 | (checkUncompressedCacheDataSize != uncompressedCacheDataSize) || |
1214 | (checkCompressedDataCRC != compressedDataCRC) || (checkChunkIndex != chunkIndex) || |
1215 | (compressedData.size() < compressedSize + chunkSize); |
1216 | if (isHeaderDataCorrupted) |
1217 | { |
1218 | WARN() << "Pipeline cache chunk header corrupted: " |
1219 | << "checkCacheVersion = " << checkCacheVersion |
1220 | << ", cacheVersion = " << cacheVersion << ", checkNumChunks = " << checkNumChunks |
1221 | << ", numChunks = " << numChunks |
1222 | << ", checkUncompressedCacheDataSize = " << checkUncompressedCacheDataSize |
1223 | << ", uncompressedCacheDataSize = " << uncompressedCacheDataSize |
1224 | << ", checkCompressedDataCRC = " << checkCompressedDataCRC |
1225 | << ", compressedDataCRC = " << compressedDataCRC |
1226 | << ", checkChunkIndex = " << checkChunkIndex << ", chunkIndex = " << chunkIndex |
1227 | << ", compressedData.size() = " << compressedData.size() |
1228 | << ", (compressedSize + chunkSize) = " << (compressedSize + chunkSize); |
1229 | return angle::Result::Continue; |
1230 | } |
1231 | |
1232 | memcpy(dest: compressedData.data() + compressedSize, src: keyData.data() + sizeof(CacheDataHeader), |
1233 | n: chunkSize); |
1234 | compressedSize += chunkSize; |
1235 | } |
1236 | |
1237 | // CRC for compressed data and size for decompressed data should match the values in the header. |
1238 | if (kEnableCRCForPipelineCache) |
1239 | { |
1240 | uint16_t computedCompressedDataCRC = ComputeCRC16(data: compressedData.data(), size: compressedSize); |
1241 | if (computedCompressedDataCRC != compressedDataCRC) |
1242 | { |
1243 | if (compressedDataCRC == 0) |
1244 | { |
1245 | // This could be due to the cache being populated before kEnableCRCForPipelineCache |
1246 | // was enabled. |
1247 | WARN() << "Expected CRC = " << compressedDataCRC |
1248 | << ", Actual CRC = " << computedCompressedDataCRC; |
1249 | return angle::Result::Continue; |
1250 | } |
1251 | |
1252 | // If the expected CRC is non-zero and does not match the actual CRC from the data, |
1253 | // there has been an unexpected data corruption. |
1254 | ERR() << "Expected CRC = " << compressedDataCRC |
1255 | << ", Actual CRC = " << computedCompressedDataCRC; |
1256 | |
1257 | ERR() << "Data extracted from the cache headers: " << std::hex |
1258 | << ", compressedDataCRC = 0x" << compressedDataCRC << "numChunks = 0x" |
1259 | << numChunks << ", uncompressedCacheDataSize = 0x" << uncompressedCacheDataSize; |
1260 | |
1261 | FATAL() << "CRC check failed; possible pipeline cache data corruption." ; |
1262 | return angle::Result::Stop; |
1263 | } |
1264 | } |
1265 | |
1266 | ANGLE_VK_CHECK( |
1267 | displayVk, |
1268 | egl::DecompressBlobCacheData(compressedData.data(), compressedSize, uncompressedData), |
1269 | VK_ERROR_INITIALIZATION_FAILED); |
1270 | |
1271 | if (uncompressedData->size() != uncompressedCacheDataSize) |
1272 | { |
1273 | WARN() << "Expected uncompressed size = " << uncompressedCacheDataSize |
1274 | << ", Actual uncompressed size = " << uncompressedData->size(); |
1275 | return angle::Result::Continue; |
1276 | } |
1277 | |
1278 | *success = true; |
1279 | return angle::Result::Continue; |
1280 | } |
1281 | |
1282 | // Environment variable (and associated Android property) to enable Vulkan debug-utils markers |
1283 | constexpr char kEnableDebugMarkersVarName[] = "ANGLE_ENABLE_DEBUG_MARKERS" ; |
1284 | constexpr char kEnableDebugMarkersPropertyName[] = "debug.angle.markers" ; |
1285 | |
1286 | ANGLE_INLINE gl::ShadingRate GetShadingRateFromVkExtent(const VkExtent2D &extent) |
1287 | { |
1288 | if (extent.width == 1 && extent.height == 2) |
1289 | { |
1290 | return gl::ShadingRate::_1x2; |
1291 | } |
1292 | else if (extent.width == 2 && extent.height == 1) |
1293 | { |
1294 | return gl::ShadingRate::_2x1; |
1295 | } |
1296 | else if (extent.width == 2 && extent.height == 2) |
1297 | { |
1298 | return gl::ShadingRate::_2x2; |
1299 | } |
1300 | else if (extent.width == 4 && extent.height == 2) |
1301 | { |
1302 | return gl::ShadingRate::_4x2; |
1303 | } |
1304 | else if (extent.width == 4 && extent.height == 4) |
1305 | { |
1306 | return gl::ShadingRate::_4x4; |
1307 | } |
1308 | |
1309 | return gl::ShadingRate::_1x1; |
1310 | } |
1311 | } // namespace |
1312 | |
1313 | // OneOffCommandPool implementation. |
1314 | OneOffCommandPool::OneOffCommandPool() : mProtectionType(vk::ProtectionType::InvalidEnum) {} |
1315 | |
1316 | void OneOffCommandPool::init(vk::ProtectionType protectionType) |
1317 | { |
1318 | ASSERT(!mCommandPool.valid()); |
1319 | mProtectionType = protectionType; |
1320 | } |
1321 | |
1322 | void OneOffCommandPool::destroy(VkDevice device) |
1323 | { |
1324 | std::unique_lock<std::mutex> lock(mMutex); |
1325 | for (PendingOneOffCommands &pending : mPendingCommands) |
1326 | { |
1327 | pending.commandBuffer.releaseHandle(); |
1328 | } |
1329 | mCommandPool.destroy(device); |
1330 | mProtectionType = vk::ProtectionType::InvalidEnum; |
1331 | } |
1332 | |
1333 | angle::Result OneOffCommandPool::getCommandBuffer(vk::Context *context, |
1334 | vk::PrimaryCommandBuffer *commandBufferOut) |
1335 | { |
1336 | std::unique_lock<std::mutex> lock(mMutex); |
1337 | |
1338 | if (!mPendingCommands.empty() && |
1339 | context->getRenderer()->hasResourceUseFinished(use: mPendingCommands.front().use)) |
1340 | { |
1341 | *commandBufferOut = std::move(mPendingCommands.front().commandBuffer); |
1342 | mPendingCommands.pop_front(); |
1343 | ANGLE_VK_TRY(context, commandBufferOut->reset()); |
1344 | } |
1345 | else |
1346 | { |
1347 | if (!mCommandPool.valid()) |
1348 | { |
1349 | VkCommandPoolCreateInfo createInfo = {}; |
1350 | createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; |
1351 | createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | |
1352 | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; |
1353 | ASSERT(mProtectionType == vk::ProtectionType::Unprotected || |
1354 | mProtectionType == vk::ProtectionType::Protected); |
1355 | if (mProtectionType == vk::ProtectionType::Protected) |
1356 | { |
1357 | createInfo.flags |= VK_COMMAND_POOL_CREATE_PROTECTED_BIT; |
1358 | } |
1359 | ANGLE_VK_TRY(context, mCommandPool.init(context->getDevice(), createInfo)); |
1360 | } |
1361 | |
1362 | VkCommandBufferAllocateInfo allocInfo = {}; |
1363 | allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; |
1364 | allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; |
1365 | allocInfo.commandBufferCount = 1; |
1366 | allocInfo.commandPool = mCommandPool.getHandle(); |
1367 | |
1368 | ANGLE_VK_TRY(context, commandBufferOut->init(context->getDevice(), allocInfo)); |
1369 | } |
1370 | |
1371 | VkCommandBufferBeginInfo beginInfo = {}; |
1372 | beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; |
1373 | beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; |
1374 | beginInfo.pInheritanceInfo = nullptr; |
1375 | ANGLE_VK_TRY(context, commandBufferOut->begin(beginInfo)); |
1376 | |
1377 | return angle::Result::Continue; |
1378 | } |
1379 | |
1380 | void OneOffCommandPool::releaseCommandBuffer(const QueueSerial &submitQueueSerial, |
1381 | vk::PrimaryCommandBuffer &&primary) |
1382 | { |
1383 | std::unique_lock<std::mutex> lock(mMutex); |
1384 | mPendingCommands.push_back(v: {.use: vk::ResourceUse(submitQueueSerial), .commandBuffer: std::move(primary)}); |
1385 | } |
1386 | |
1387 | // RendererVk implementation. |
1388 | RendererVk::RendererVk() |
1389 | : mDisplay(nullptr), |
1390 | mLibVulkanLibrary(nullptr), |
1391 | mCapsInitialized(false), |
1392 | mInstanceVersion(0), |
1393 | mDeviceVersion(0), |
1394 | mInstance(VK_NULL_HANDLE), |
1395 | mEnableValidationLayers(false), |
1396 | mEnableDebugUtils(false), |
1397 | mAngleDebuggerMode(false), |
1398 | mEnabledICD(angle::vk::ICD::Default), |
1399 | mDebugUtilsMessenger(VK_NULL_HANDLE), |
1400 | mPhysicalDevice(VK_NULL_HANDLE), |
1401 | mMaxVertexAttribDivisor(1), |
1402 | mCurrentQueueFamilyIndex(std::numeric_limits<uint32_t>::max()), |
1403 | mMaxVertexAttribStride(0), |
1404 | mDefaultUniformBufferSize(kPreferredDefaultUniformBufferSize), |
1405 | mDevice(VK_NULL_HANDLE), |
1406 | mDeviceLost(false), |
1407 | mSuballocationGarbageSizeInBytes(0), |
1408 | mSuballocationGarbageDestroyed(0), |
1409 | mSuballocationGarbageSizeInBytesCachedAtomic(0), |
1410 | mCoherentStagingBufferMemoryTypeIndex(kInvalidMemoryTypeIndex), |
1411 | mNonCoherentStagingBufferMemoryTypeIndex(kInvalidMemoryTypeIndex), |
1412 | mStagingBufferAlignment(1), |
1413 | mHostVisibleVertexConversionBufferMemoryTypeIndex(kInvalidMemoryTypeIndex), |
1414 | mDeviceLocalVertexConversionBufferMemoryTypeIndex(kInvalidMemoryTypeIndex), |
1415 | mVertexConversionBufferAlignment(1), |
1416 | mPipelineCacheVkUpdateTimeout(kPipelineCacheVkUpdatePeriod), |
1417 | mPipelineCacheSizeAtLastSync(0), |
1418 | mPipelineCacheInitialized(false), |
1419 | mValidationMessageCount(0), |
1420 | mCommandProcessor(this, &mCommandQueue), |
1421 | mSupportedVulkanPipelineStageMask(0), |
1422 | mSupportedVulkanShaderStageMask(0), |
1423 | mMemoryAllocationTracker(MemoryAllocationTracker(this)) |
1424 | { |
1425 | VkFormatProperties invalid = {.linearTilingFeatures: 0, .optimalTilingFeatures: 0, .bufferFeatures: kInvalidFormatFeatureFlags}; |
1426 | mFormatProperties.fill(u: invalid); |
1427 | |
1428 | // We currently don't have any big-endian devices in the list of supported platforms. There are |
1429 | // a number of places in the Vulkan backend that make this assumption. This assertion is made |
1430 | // early to fail immediately on big-endian platforms. |
1431 | ASSERT(IsLittleEndian()); |
1432 | } |
1433 | |
1434 | RendererVk::~RendererVk() {} |
1435 | |
1436 | bool RendererVk::hasSharedGarbage() |
1437 | { |
1438 | std::unique_lock<std::mutex> lock(mGarbageMutex); |
1439 | return !mSharedGarbage.empty() || !mPendingSubmissionGarbage.empty() || |
1440 | !mSuballocationGarbage.empty() || !mPendingSubmissionSuballocationGarbage.empty(); |
1441 | } |
1442 | |
1443 | void RendererVk::onDestroy(vk::Context *context) |
1444 | { |
1445 | if (isDeviceLost()) |
1446 | { |
1447 | handleDeviceLost(); |
1448 | } |
1449 | |
1450 | mCommandProcessor.destroy(context); |
1451 | mCommandQueue.destroy(context); |
1452 | |
1453 | // mCommandQueue.destroy should already set "last completed" serials to infinite. |
1454 | cleanupGarbage(); |
1455 | ASSERT(!hasSharedGarbage()); |
1456 | ASSERT(mOrphanedBufferBlocks.empty()); |
1457 | |
1458 | for (OneOffCommandPool &oneOffCommandPool : mOneOffCommandPoolMap) |
1459 | { |
1460 | oneOffCommandPool.destroy(device: mDevice); |
1461 | } |
1462 | |
1463 | mPipelineCache.destroy(device: mDevice); |
1464 | mSamplerCache.destroy(rendererVk: this); |
1465 | mYuvConversionCache.destroy(rendererVk: this); |
1466 | mVkFormatDescriptorCountMap.clear(); |
1467 | |
1468 | mOutsideRenderPassCommandBufferRecycler.onDestroy(); |
1469 | mRenderPassCommandBufferRecycler.onDestroy(); |
1470 | |
1471 | mImageMemorySuballocator.destroy(renderer: this); |
1472 | mAllocator.destroy(); |
1473 | |
1474 | // When the renderer is being destroyed, it is possible to check if all the allocated memory |
1475 | // throughout the execution has been freed. |
1476 | mMemoryAllocationTracker.onDestroy(); |
1477 | |
1478 | if (mDevice) |
1479 | { |
1480 | vkDestroyDevice(mDevice, nullptr); |
1481 | mDevice = VK_NULL_HANDLE; |
1482 | } |
1483 | |
1484 | if (mDebugUtilsMessenger) |
1485 | { |
1486 | vkDestroyDebugUtilsMessengerEXT(mInstance, mDebugUtilsMessenger, nullptr); |
1487 | } |
1488 | |
1489 | logCacheStats(); |
1490 | |
1491 | if (mInstance) |
1492 | { |
1493 | vkDestroyInstance(mInstance, nullptr); |
1494 | mInstance = VK_NULL_HANDLE; |
1495 | } |
1496 | |
1497 | if (mCompressEvent) |
1498 | { |
1499 | mCompressEvent->wait(); |
1500 | mCompressEvent.reset(); |
1501 | } |
1502 | |
1503 | mMemoryProperties.destroy(); |
1504 | mPhysicalDevice = VK_NULL_HANDLE; |
1505 | |
1506 | mEnabledInstanceExtensions.clear(); |
1507 | mEnabledDeviceExtensions.clear(); |
1508 | |
1509 | ASSERT(!hasSharedGarbage()); |
1510 | |
1511 | if (mLibVulkanLibrary) |
1512 | { |
1513 | angle::CloseSystemLibrary(libraryHandle: mLibVulkanLibrary); |
1514 | mLibVulkanLibrary = nullptr; |
1515 | } |
1516 | } |
1517 | |
1518 | void RendererVk::notifyDeviceLost() |
1519 | { |
1520 | mDeviceLost = true; |
1521 | mDisplay->notifyDeviceLost(); |
1522 | } |
1523 | |
1524 | bool RendererVk::isDeviceLost() const |
1525 | { |
1526 | return mDeviceLost; |
1527 | } |
1528 | |
1529 | bool RendererVk::isVulkan11Instance() const |
1530 | { |
1531 | return IsVulkan11(apiVersion: mInstanceVersion); |
1532 | } |
1533 | |
1534 | bool RendererVk::isVulkan11Device() const |
1535 | { |
1536 | return IsVulkan11(apiVersion: mDeviceVersion); |
1537 | } |
1538 | |
1539 | angle::Result RendererVk::enableInstanceExtensions( |
1540 | DisplayVk *displayVk, |
1541 | const VulkanLayerVector &enabledInstanceLayerNames, |
1542 | const char *wsiExtension, |
1543 | bool canLoadDebugUtils) |
1544 | { |
1545 | // Enumerate instance extensions that are provided by the vulkan implementation and implicit |
1546 | // layers. |
1547 | uint32_t instanceExtensionCount = 0; |
1548 | { |
1549 | ANGLE_SCOPED_DISABLE_LSAN(); |
1550 | ANGLE_SCOPED_DISABLE_MSAN(); |
1551 | ANGLE_VK_TRY(displayVk, vkEnumerateInstanceExtensionProperties( |
1552 | nullptr, &instanceExtensionCount, nullptr)); |
1553 | } |
1554 | |
1555 | std::vector<VkExtensionProperties> instanceExtensionProps(instanceExtensionCount); |
1556 | if (instanceExtensionCount > 0) |
1557 | { |
1558 | ANGLE_SCOPED_DISABLE_LSAN(); |
1559 | ANGLE_SCOPED_DISABLE_MSAN(); |
1560 | ANGLE_VK_TRY(displayVk, |
1561 | vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtensionCount, |
1562 | instanceExtensionProps.data())); |
1563 | // In case fewer items were returned than requested, resize instanceExtensionProps to the |
1564 | // number of extensions returned (i.e. instanceExtensionCount). |
1565 | instanceExtensionProps.resize(sz: instanceExtensionCount); |
1566 | } |
1567 | |
1568 | // Enumerate instance extensions that are provided by explicit layers. |
1569 | for (const char *layerName : enabledInstanceLayerNames) |
1570 | { |
1571 | uint32_t previousExtensionCount = static_cast<uint32_t>(instanceExtensionProps.size()); |
1572 | uint32_t instanceLayerExtensionCount = 0; |
1573 | { |
1574 | ANGLE_SCOPED_DISABLE_LSAN(); |
1575 | ANGLE_SCOPED_DISABLE_MSAN(); |
1576 | ANGLE_VK_TRY(displayVk, vkEnumerateInstanceExtensionProperties( |
1577 | layerName, &instanceLayerExtensionCount, nullptr)); |
1578 | } |
1579 | instanceExtensionProps.resize(sz: previousExtensionCount + instanceLayerExtensionCount); |
1580 | { |
1581 | ANGLE_SCOPED_DISABLE_LSAN(); |
1582 | ANGLE_SCOPED_DISABLE_MSAN(); |
1583 | ANGLE_VK_TRY(displayVk, vkEnumerateInstanceExtensionProperties( |
1584 | layerName, &instanceLayerExtensionCount, |
1585 | instanceExtensionProps.data() + previousExtensionCount)); |
1586 | } |
1587 | // In case fewer items were returned than requested, resize instanceExtensionProps to the |
1588 | // number of extensions returned (i.e. instanceLayerExtensionCount). |
1589 | instanceExtensionProps.resize(sz: previousExtensionCount + instanceLayerExtensionCount); |
1590 | } |
1591 | |
1592 | // Get the list of instance extensions that are available. |
1593 | vk::ExtensionNameList instanceExtensionNames; |
1594 | if (!instanceExtensionProps.empty()) |
1595 | { |
1596 | for (const VkExtensionProperties &i : instanceExtensionProps) |
1597 | { |
1598 | instanceExtensionNames.push_back(value: i.extensionName); |
1599 | } |
1600 | std::sort(first: instanceExtensionNames.begin(), last: instanceExtensionNames.end(), comp: StrLess); |
1601 | } |
1602 | |
1603 | // Set ANGLE features that depend on instance extensions |
1604 | ANGLE_FEATURE_CONDITION( |
1605 | &mFeatures, supportsSurfaceCapabilities2Extension, |
1606 | ExtensionFound(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, instanceExtensionNames)); |
1607 | |
1608 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsSurfaceProtectedCapabilitiesExtension, |
1609 | ExtensionFound(VK_KHR_SURFACE_PROTECTED_CAPABILITIES_EXTENSION_NAME, |
1610 | instanceExtensionNames)); |
1611 | |
1612 | // TODO: Validation layer has a bug when vkGetPhysicalDeviceSurfaceFormats2KHR is called |
1613 | // on Mock ICD with surface handle set as VK_NULL_HANDLE. http://anglebug.com/7631 |
1614 | ANGLE_FEATURE_CONDITION( |
1615 | &mFeatures, supportsSurfacelessQueryExtension, |
1616 | ExtensionFound(VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME, instanceExtensionNames) && |
1617 | !isMockICDEnabled()); |
1618 | |
1619 | // VK_KHR_external_fence_capabilities and VK_KHR_extenral_semaphore_capabilities are promoted to |
1620 | // core in Vulkan 1.1 |
1621 | ANGLE_FEATURE_CONDITION( |
1622 | &mFeatures, supportsExternalFenceCapabilities, |
1623 | isVulkan11Instance() || ExtensionFound(VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME, |
1624 | instanceExtensionNames)); |
1625 | |
1626 | ANGLE_FEATURE_CONDITION( |
1627 | &mFeatures, supportsExternalSemaphoreCapabilities, |
1628 | isVulkan11Instance() || |
1629 | ExtensionFound(VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME, |
1630 | instanceExtensionNames)); |
1631 | |
1632 | // On macOS, there is no native Vulkan driver, so we need to enable the |
1633 | // portability enumeration extension to allow use of MoltenVK. |
1634 | ANGLE_FEATURE_CONDITION( |
1635 | &mFeatures, supportsPortabilityEnumeration, |
1636 | ExtensionFound(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, instanceExtensionNames)); |
1637 | |
1638 | ANGLE_FEATURE_CONDITION(&mFeatures, enablePortabilityEnumeration, |
1639 | mFeatures.supportsPortabilityEnumeration.enabled && IsApple()); |
1640 | |
1641 | // Enable extensions that could be used |
1642 | if (displayVk->isUsingSwapchain()) |
1643 | { |
1644 | mEnabledInstanceExtensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); |
1645 | if (ExtensionFound(VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME, haystack: instanceExtensionNames)) |
1646 | { |
1647 | mEnabledInstanceExtensions.push_back(VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME); |
1648 | } |
1649 | } |
1650 | |
1651 | if (wsiExtension) |
1652 | { |
1653 | mEnabledInstanceExtensions.push_back(value: wsiExtension); |
1654 | } |
1655 | |
1656 | mEnableDebugUtils = canLoadDebugUtils && mEnableValidationLayers && |
1657 | ExtensionFound(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, haystack: instanceExtensionNames); |
1658 | |
1659 | if (mEnableDebugUtils) |
1660 | { |
1661 | mEnabledInstanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); |
1662 | } |
1663 | |
1664 | if (mFeatures.supportsSurfaceCapabilities2Extension.enabled) |
1665 | { |
1666 | mEnabledInstanceExtensions.push_back(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME); |
1667 | } |
1668 | |
1669 | if (mFeatures.supportsSurfaceProtectedCapabilitiesExtension.enabled) |
1670 | { |
1671 | mEnabledInstanceExtensions.push_back(VK_KHR_SURFACE_PROTECTED_CAPABILITIES_EXTENSION_NAME); |
1672 | } |
1673 | |
1674 | if (mFeatures.supportsSurfacelessQueryExtension.enabled) |
1675 | { |
1676 | mEnabledInstanceExtensions.push_back(VK_GOOGLE_SURFACELESS_QUERY_EXTENSION_NAME); |
1677 | } |
1678 | |
1679 | if (ExtensionFound(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME, haystack: instanceExtensionNames)) |
1680 | { |
1681 | mEnabledInstanceExtensions.push_back(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME); |
1682 | } |
1683 | |
1684 | if (!isVulkan11Instance()) |
1685 | { |
1686 | if (ExtensionFound(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, |
1687 | haystack: instanceExtensionNames)) |
1688 | { |
1689 | mEnabledInstanceExtensions.push_back( |
1690 | VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); |
1691 | } |
1692 | |
1693 | if (mFeatures.supportsExternalFenceCapabilities.enabled) |
1694 | { |
1695 | mEnabledInstanceExtensions.push_back(VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME); |
1696 | } |
1697 | |
1698 | if (mFeatures.supportsExternalSemaphoreCapabilities.enabled) |
1699 | { |
1700 | mEnabledInstanceExtensions.push_back( |
1701 | VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME); |
1702 | } |
1703 | } |
1704 | |
1705 | if (mFeatures.enablePortabilityEnumeration.enabled) |
1706 | { |
1707 | mEnabledInstanceExtensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); |
1708 | } |
1709 | |
1710 | // Verify the required extensions are in the extension names set. Fail if not. |
1711 | std::sort(first: mEnabledInstanceExtensions.begin(), last: mEnabledInstanceExtensions.end(), comp: StrLess); |
1712 | ANGLE_VK_TRY(displayVk, |
1713 | VerifyExtensionsPresent(instanceExtensionNames, mEnabledInstanceExtensions)); |
1714 | |
1715 | return angle::Result::Continue; |
1716 | } |
1717 | |
1718 | angle::Result RendererVk::initialize(DisplayVk *displayVk, |
1719 | egl::Display *display, |
1720 | const char *wsiExtension, |
1721 | const char *wsiLayer) |
1722 | { |
1723 | bool canLoadDebugUtils = true; |
1724 | #if defined(ANGLE_SHARED_LIBVULKAN) |
1725 | { |
1726 | ANGLE_SCOPED_DISABLE_MSAN(); |
1727 | mLibVulkanLibrary = angle::vk::OpenLibVulkan(); |
1728 | ANGLE_VK_CHECK(displayVk, mLibVulkanLibrary, VK_ERROR_INITIALIZATION_FAILED); |
1729 | |
1730 | PFN_vkGetInstanceProcAddr vulkanLoaderGetInstanceProcAddr = |
1731 | reinterpret_cast<PFN_vkGetInstanceProcAddr>( |
1732 | angle::GetLibrarySymbol(libraryHandle: mLibVulkanLibrary, symbolName: "vkGetInstanceProcAddr" )); |
1733 | |
1734 | // Set all vk* function ptrs |
1735 | volkInitializeCustom(handler: vulkanLoaderGetInstanceProcAddr); |
1736 | |
1737 | uint32_t ver = volkGetInstanceVersion(); |
1738 | if (!IsAndroid() && ver < VK_MAKE_VERSION(1, 1, 91)) |
1739 | { |
1740 | // http://crbug.com/1205999 - non-Android Vulkan Loader versions before 1.1.91 have a |
1741 | // bug which prevents loading VK_EXT_debug_utils function pointers. |
1742 | canLoadDebugUtils = false; |
1743 | } |
1744 | } |
1745 | #endif // defined(ANGLE_SHARED_LIBVULKAN) |
1746 | |
1747 | mDisplay = display; |
1748 | const egl::AttributeMap &attribs = mDisplay->getAttributeMap(); |
1749 | angle::vk::ScopedVkLoaderEnvironment scopedEnvironment(ShouldUseValidationLayers(attribs), |
1750 | ChooseICDFromAttribs(attribs)); |
1751 | mEnableValidationLayers = scopedEnvironment.canEnableValidationLayers(); |
1752 | mEnabledICD = scopedEnvironment.getEnabledICD(); |
1753 | |
1754 | // Gather global layer properties. |
1755 | uint32_t instanceLayerCount = 0; |
1756 | { |
1757 | ANGLE_SCOPED_DISABLE_LSAN(); |
1758 | ANGLE_SCOPED_DISABLE_MSAN(); |
1759 | ANGLE_VK_TRY(displayVk, vkEnumerateInstanceLayerProperties(&instanceLayerCount, nullptr)); |
1760 | } |
1761 | |
1762 | std::vector<VkLayerProperties> instanceLayerProps(instanceLayerCount); |
1763 | if (instanceLayerCount > 0) |
1764 | { |
1765 | ANGLE_SCOPED_DISABLE_LSAN(); |
1766 | ANGLE_SCOPED_DISABLE_MSAN(); |
1767 | ANGLE_VK_TRY(displayVk, vkEnumerateInstanceLayerProperties(&instanceLayerCount, |
1768 | instanceLayerProps.data())); |
1769 | } |
1770 | |
1771 | VulkanLayerVector enabledInstanceLayerNames; |
1772 | if (mEnableValidationLayers) |
1773 | { |
1774 | bool layersRequested = |
1775 | (attribs.get(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE, EGL_DONT_CARE) == EGL_TRUE); |
1776 | mEnableValidationLayers = GetAvailableValidationLayers(layerProps: instanceLayerProps, mustHaveLayers: layersRequested, |
1777 | enabledLayerNames: &enabledInstanceLayerNames); |
1778 | } |
1779 | |
1780 | if (wsiLayer) |
1781 | { |
1782 | enabledInstanceLayerNames.push_back(value: wsiLayer); |
1783 | } |
1784 | |
1785 | auto enumerateInstanceVersion = reinterpret_cast<PFN_vkEnumerateInstanceVersion>( |
1786 | vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion" )); |
1787 | |
1788 | uint32_t highestApiVersion = mInstanceVersion = VK_API_VERSION_1_0; |
1789 | if (enumerateInstanceVersion) |
1790 | { |
1791 | { |
1792 | ANGLE_SCOPED_DISABLE_LSAN(); |
1793 | ANGLE_SCOPED_DISABLE_MSAN(); |
1794 | ANGLE_VK_TRY(displayVk, enumerateInstanceVersion(&mInstanceVersion)); |
1795 | } |
1796 | |
1797 | if (isVulkan11Instance()) |
1798 | { |
1799 | // This is the highest version of core Vulkan functionality that ANGLE uses. Per the |
1800 | // Vulkan spec, the application is allowed to specify a higher version than supported by |
1801 | // the instance. ANGLE still respects the *device's* version. |
1802 | highestApiVersion = kPreferredVulkanAPIVersion; |
1803 | } |
1804 | } |
1805 | |
1806 | ANGLE_TRY(enableInstanceExtensions(displayVk, enabledInstanceLayerNames, wsiExtension, |
1807 | canLoadDebugUtils)); |
1808 | |
1809 | const std::string appName = angle::GetExecutableName(); |
1810 | |
1811 | mApplicationInfo = {}; |
1812 | mApplicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; |
1813 | mApplicationInfo.pApplicationName = appName.c_str(); |
1814 | mApplicationInfo.applicationVersion = 1; |
1815 | mApplicationInfo.pEngineName = "ANGLE" ; |
1816 | mApplicationInfo.engineVersion = 1; |
1817 | mApplicationInfo.apiVersion = highestApiVersion; |
1818 | |
1819 | VkInstanceCreateInfo instanceInfo = {}; |
1820 | instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; |
1821 | instanceInfo.flags = 0; |
1822 | instanceInfo.pApplicationInfo = &mApplicationInfo; |
1823 | |
1824 | // Enable requested layers and extensions. |
1825 | instanceInfo.enabledExtensionCount = static_cast<uint32_t>(mEnabledInstanceExtensions.size()); |
1826 | instanceInfo.ppEnabledExtensionNames = |
1827 | mEnabledInstanceExtensions.empty() ? nullptr : mEnabledInstanceExtensions.data(); |
1828 | |
1829 | instanceInfo.enabledLayerCount = static_cast<uint32_t>(enabledInstanceLayerNames.size()); |
1830 | instanceInfo.ppEnabledLayerNames = enabledInstanceLayerNames.data(); |
1831 | |
1832 | // On macOS, there is no native Vulkan driver, so we need to enable the |
1833 | // portability enumeration extension to allow use of MoltenVK. |
1834 | if (mFeatures.enablePortabilityEnumeration.enabled) |
1835 | { |
1836 | instanceInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; |
1837 | } |
1838 | |
1839 | // http://anglebug.com/7050 - Shader validation caching is broken on Android |
1840 | VkValidationFeaturesEXT validationFeatures = {}; |
1841 | VkValidationFeatureDisableEXT disabledFeatures[] = { |
1842 | VK_VALIDATION_FEATURE_DISABLE_SHADER_VALIDATION_CACHE_EXT}; |
1843 | if (mEnableValidationLayers && IsAndroid()) |
1844 | { |
1845 | validationFeatures.sType = VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT; |
1846 | validationFeatures.disabledValidationFeatureCount = 1; |
1847 | validationFeatures.pDisabledValidationFeatures = disabledFeatures; |
1848 | |
1849 | vk::AddToPNextChain(chainStart: &instanceInfo, ptr: &validationFeatures); |
1850 | } |
1851 | |
1852 | { |
1853 | ANGLE_SCOPED_DISABLE_MSAN(); |
1854 | ANGLE_VK_TRY(displayVk, vkCreateInstance(&instanceInfo, nullptr, &mInstance)); |
1855 | #if defined(ANGLE_SHARED_LIBVULKAN) |
1856 | // Load volk if we are linking dynamically |
1857 | volkLoadInstance(instance: mInstance); |
1858 | #endif // defined(ANGLE_SHARED_LIBVULKAN) |
1859 | |
1860 | initInstanceExtensionEntryPoints(); |
1861 | } |
1862 | |
1863 | if (mEnableDebugUtils) |
1864 | { |
1865 | // Use the newer EXT_debug_utils if it exists. |
1866 | #if !defined(ANGLE_SHARED_LIBVULKAN) |
1867 | InitDebugUtilsEXTFunctions(mInstance); |
1868 | #endif // !defined(ANGLE_SHARED_LIBVULKAN) |
1869 | |
1870 | // Create the messenger callback. |
1871 | VkDebugUtilsMessengerCreateInfoEXT messengerInfo = {}; |
1872 | |
1873 | constexpr VkDebugUtilsMessageSeverityFlagsEXT kSeveritiesToLog = |
1874 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | |
1875 | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; |
1876 | |
1877 | constexpr VkDebugUtilsMessageTypeFlagsEXT kMessagesToLog = |
1878 | VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | |
1879 | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | |
1880 | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; |
1881 | |
1882 | messengerInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; |
1883 | messengerInfo.messageSeverity = kSeveritiesToLog; |
1884 | messengerInfo.messageType = kMessagesToLog; |
1885 | messengerInfo.pfnUserCallback = &DebugUtilsMessenger; |
1886 | messengerInfo.pUserData = this; |
1887 | |
1888 | ANGLE_VK_TRY(displayVk, vkCreateDebugUtilsMessengerEXT(mInstance, &messengerInfo, nullptr, |
1889 | &mDebugUtilsMessenger)); |
1890 | } |
1891 | |
1892 | if (isVulkan11Instance() || |
1893 | std::find(first: mEnabledInstanceExtensions.begin(), last: mEnabledInstanceExtensions.end(), |
1894 | VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) != |
1895 | mEnabledInstanceExtensions.end()) |
1896 | { |
1897 | #if !defined(ANGLE_SHARED_LIBVULKAN) |
1898 | if (!isVulkan11Instance()) |
1899 | { |
1900 | InitGetPhysicalDeviceProperties2KHRFunctions(mInstance); |
1901 | } |
1902 | #endif // !defined(ANGLE_SHARED_LIBVULKAN) |
1903 | |
1904 | ASSERT(vkGetPhysicalDeviceProperties2KHR); |
1905 | } |
1906 | |
1907 | uint32_t physicalDeviceCount = 0; |
1908 | ANGLE_VK_TRY(displayVk, vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, nullptr)); |
1909 | ANGLE_VK_CHECK(displayVk, physicalDeviceCount > 0, VK_ERROR_INITIALIZATION_FAILED); |
1910 | |
1911 | // TODO(jmadill): Handle multiple physical devices. For now, use the first device. |
1912 | std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount); |
1913 | ANGLE_VK_TRY(displayVk, vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, |
1914 | physicalDevices.data())); |
1915 | uint32_t preferredVendorId = |
1916 | static_cast<uint32_t>(attribs.get(EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE, defaultValue: 0)); |
1917 | uint32_t preferredDeviceId = |
1918 | static_cast<uint32_t>(attribs.get(EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE, defaultValue: 0)); |
1919 | ChoosePhysicalDevice(pGetPhysicalDeviceProperties: vkGetPhysicalDeviceProperties, physicalDevices, preferredICD: mEnabledICD, |
1920 | preferredVendorID: preferredVendorId, preferredDeviceID: preferredDeviceId, physicalDeviceOut: &mPhysicalDevice, |
1921 | physicalDevicePropertiesOut: &mPhysicalDeviceProperties); |
1922 | |
1923 | // The device version that is assumed by ANGLE is the minimum of the actual device version and |
1924 | // the highest it's allowed to use. |
1925 | mDeviceVersion = std::min(a: mPhysicalDeviceProperties.apiVersion, b: highestApiVersion); |
1926 | |
1927 | mGarbageCollectionFlushThreshold = |
1928 | static_cast<uint32_t>(mPhysicalDeviceProperties.limits.maxMemoryAllocationCount * |
1929 | kPercentMaxMemoryAllocationCount); |
1930 | vkGetPhysicalDeviceFeatures(mPhysicalDevice, &mPhysicalDeviceFeatures); |
1931 | |
1932 | // Ensure we can find a graphics queue family. |
1933 | uint32_t queueFamilyCount = 0; |
1934 | vkGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueFamilyCount, nullptr); |
1935 | |
1936 | ANGLE_VK_CHECK(displayVk, queueFamilyCount > 0, VK_ERROR_INITIALIZATION_FAILED); |
1937 | |
1938 | mQueueFamilyProperties.resize(sz: queueFamilyCount); |
1939 | vkGetPhysicalDeviceQueueFamilyProperties(mPhysicalDevice, &queueFamilyCount, |
1940 | mQueueFamilyProperties.data()); |
1941 | |
1942 | uint32_t queueFamilyMatchCount = 0; |
1943 | // Try first for a protected graphics queue family |
1944 | uint32_t firstGraphicsQueueFamily = vk::QueueFamily::FindIndex( |
1945 | queueFamilyProperties: mQueueFamilyProperties, |
1946 | flags: (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_PROTECTED_BIT), matchNumber: 0, |
1947 | matchCount: &queueFamilyMatchCount); |
1948 | // else just a graphics queue family |
1949 | if (queueFamilyMatchCount == 0) |
1950 | { |
1951 | firstGraphicsQueueFamily = vk::QueueFamily::FindIndex( |
1952 | queueFamilyProperties: mQueueFamilyProperties, flags: (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT), matchNumber: 0, |
1953 | matchCount: &queueFamilyMatchCount); |
1954 | } |
1955 | ANGLE_VK_CHECK(displayVk, queueFamilyMatchCount > 0, VK_ERROR_INITIALIZATION_FAILED); |
1956 | |
1957 | // Store the physical device memory properties so we can find the right memory pools. |
1958 | mMemoryProperties.init(physicalDevice: mPhysicalDevice); |
1959 | ANGLE_VK_CHECK(displayVk, mMemoryProperties.getMemoryTypeCount() > 0, |
1960 | VK_ERROR_INITIALIZATION_FAILED); |
1961 | |
1962 | // The counters for the memory allocation tracker should be initialized. |
1963 | // Each memory allocation could be made in one of the available memory heaps. We initialize the |
1964 | // per-heap memory allocation trackers for MemoryAllocationType objects here, after |
1965 | // mMemoryProperties has been set up. |
1966 | mMemoryAllocationTracker.initMemoryTrackers(); |
1967 | |
1968 | // If only one queue family, go ahead and initialize the device. If there is more than one |
1969 | // queue, we'll have to wait until we see a WindowSurface to know which supports present. |
1970 | if (queueFamilyMatchCount == 1) |
1971 | { |
1972 | ANGLE_TRY(initializeDevice(displayVk, firstGraphicsQueueFamily)); |
1973 | } |
1974 | |
1975 | ANGLE_TRY(initializeMemoryAllocator(displayVk)); |
1976 | |
1977 | // Initialize the format table. |
1978 | mFormatTable.initialize(renderer: this, outTextureCapsMap: &mNativeTextureCaps); |
1979 | |
1980 | setGlobalDebugAnnotator(); |
1981 | |
1982 | // Null terminate the extension list returned for EGL_VULKAN_INSTANCE_EXTENSIONS_ANGLE. |
1983 | mEnabledInstanceExtensions.push_back(value: nullptr); |
1984 | |
1985 | for (vk::ProtectionType protectionType : angle::AllEnums<vk::ProtectionType>()) |
1986 | { |
1987 | mOneOffCommandPoolMap[protectionType].init(protectionType); |
1988 | } |
1989 | |
1990 | return angle::Result::Continue; |
1991 | } |
1992 | |
1993 | angle::Result RendererVk::initializeMemoryAllocator(DisplayVk *displayVk) |
1994 | { |
1995 | // This number matches Chromium and was picked by looking at memory usage of |
1996 | // Android apps. The allocator will start making blocks at 1/8 the max size |
1997 | // and builds up block size as needed before capping at the max set here. |
1998 | mPreferredLargeHeapBlockSize = 4 * 1024 * 1024; |
1999 | |
2000 | // Create VMA allocator |
2001 | ANGLE_VK_TRY(displayVk, |
2002 | mAllocator.init(mPhysicalDevice, mDevice, mInstance, mApplicationInfo.apiVersion, |
2003 | mPreferredLargeHeapBlockSize)); |
2004 | |
2005 | // Figure out the alignment for default buffer allocations |
2006 | VkBufferCreateInfo createInfo = {}; |
2007 | createInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; |
2008 | createInfo.flags = 0; |
2009 | createInfo.size = 4096; |
2010 | createInfo.usage = GetDefaultBufferUsageFlags(renderer: this); |
2011 | createInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; |
2012 | createInfo.queueFamilyIndexCount = 0; |
2013 | createInfo.pQueueFamilyIndices = nullptr; |
2014 | |
2015 | vk::DeviceScoped<vk::Buffer> tempBuffer(mDevice); |
2016 | tempBuffer.get().init(device: mDevice, createInfo); |
2017 | |
2018 | VkMemoryRequirements defaultBufferMemoryRequirements; |
2019 | tempBuffer.get().getMemoryRequirements(device: mDevice, memoryRequirementsOut: &defaultBufferMemoryRequirements); |
2020 | ASSERT(gl::isPow2(defaultBufferMemoryRequirements.alignment)); |
2021 | |
2022 | const VkPhysicalDeviceLimits &limitsVk = getPhysicalDeviceProperties().limits; |
2023 | ASSERT(gl::isPow2(limitsVk.minUniformBufferOffsetAlignment)); |
2024 | ASSERT(gl::isPow2(limitsVk.minStorageBufferOffsetAlignment)); |
2025 | ASSERT(gl::isPow2(limitsVk.minTexelBufferOffsetAlignment)); |
2026 | ASSERT(gl::isPow2(limitsVk.minMemoryMapAlignment)); |
2027 | |
2028 | mDefaultBufferAlignment = |
2029 | std::max(t: {static_cast<size_t>(limitsVk.minUniformBufferOffsetAlignment), |
2030 | static_cast<size_t>(limitsVk.minStorageBufferOffsetAlignment), |
2031 | static_cast<size_t>(limitsVk.minTexelBufferOffsetAlignment), |
2032 | static_cast<size_t>(limitsVk.minMemoryMapAlignment), |
2033 | static_cast<size_t>(defaultBufferMemoryRequirements.alignment)}); |
2034 | |
2035 | // Initialize staging buffer memory type index and alignment. |
2036 | // These buffers will only be used as transfer sources or transfer targets. |
2037 | createInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; |
2038 | VkMemoryPropertyFlags requiredFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; |
2039 | bool persistentlyMapped = mFeatures.persistentlyMappedBuffers.enabled; |
2040 | |
2041 | // Uncached coherent staging buffer |
2042 | VkMemoryPropertyFlags preferredFlags = VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; |
2043 | ANGLE_VK_TRY(displayVk, mAllocator.findMemoryTypeIndexForBufferInfo( |
2044 | createInfo, requiredFlags, preferredFlags, persistentlyMapped, |
2045 | &mCoherentStagingBufferMemoryTypeIndex)); |
2046 | ASSERT(mCoherentStagingBufferMemoryTypeIndex != kInvalidMemoryTypeIndex); |
2047 | |
2048 | // Cached (b/219974369) Non-coherent staging buffer |
2049 | preferredFlags = VK_MEMORY_PROPERTY_HOST_CACHED_BIT; |
2050 | ANGLE_VK_TRY(displayVk, mAllocator.findMemoryTypeIndexForBufferInfo( |
2051 | createInfo, requiredFlags, preferredFlags, persistentlyMapped, |
2052 | &mNonCoherentStagingBufferMemoryTypeIndex)); |
2053 | ASSERT(mNonCoherentStagingBufferMemoryTypeIndex != kInvalidMemoryTypeIndex); |
2054 | |
2055 | // Alignment |
2056 | mStagingBufferAlignment = |
2057 | static_cast<size_t>(mPhysicalDeviceProperties.limits.minMemoryMapAlignment); |
2058 | ASSERT(gl::isPow2(mPhysicalDeviceProperties.limits.nonCoherentAtomSize)); |
2059 | ASSERT(gl::isPow2(mPhysicalDeviceProperties.limits.optimalBufferCopyOffsetAlignment)); |
2060 | // Usually minTexelBufferOffsetAlignment is much smaller than nonCoherentAtomSize |
2061 | ASSERT(gl::isPow2(mPhysicalDeviceProperties.limits.minTexelBufferOffsetAlignment)); |
2062 | mStagingBufferAlignment = std::max( |
2063 | t: {mStagingBufferAlignment, |
2064 | static_cast<size_t>(mPhysicalDeviceProperties.limits.optimalBufferCopyOffsetAlignment), |
2065 | static_cast<size_t>(mPhysicalDeviceProperties.limits.nonCoherentAtomSize), |
2066 | static_cast<size_t>(mPhysicalDeviceProperties.limits.minTexelBufferOffsetAlignment)}); |
2067 | ASSERT(gl::isPow2(mStagingBufferAlignment)); |
2068 | |
2069 | // Device local vertex conversion buffer |
2070 | createInfo.usage = vk::kVertexBufferUsageFlags; |
2071 | requiredFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; |
2072 | preferredFlags = 0; |
2073 | ANGLE_VK_TRY(displayVk, mAllocator.findMemoryTypeIndexForBufferInfo( |
2074 | createInfo, requiredFlags, preferredFlags, persistentlyMapped, |
2075 | &mDeviceLocalVertexConversionBufferMemoryTypeIndex)); |
2076 | ASSERT(mDeviceLocalVertexConversionBufferMemoryTypeIndex != kInvalidMemoryTypeIndex); |
2077 | |
2078 | // Host visible and non-coherent vertex conversion buffer, which is the same as non-coherent |
2079 | // staging buffer |
2080 | mHostVisibleVertexConversionBufferMemoryTypeIndex = mNonCoherentStagingBufferMemoryTypeIndex; |
2081 | |
2082 | // We may use compute shader to do conversion, so we must meet |
2083 | // minStorageBufferOffsetAlignment requirement as well. Also take into account non-coherent |
2084 | // alignment requirements. |
2085 | mVertexConversionBufferAlignment = std::max( |
2086 | t: {vk::kVertexBufferAlignment, |
2087 | static_cast<size_t>(mPhysicalDeviceProperties.limits.minStorageBufferOffsetAlignment), |
2088 | static_cast<size_t>(mPhysicalDeviceProperties.limits.nonCoherentAtomSize), |
2089 | static_cast<size_t>(defaultBufferMemoryRequirements.alignment)}); |
2090 | ASSERT(gl::isPow2(mVertexConversionBufferAlignment)); |
2091 | |
2092 | return angle::Result::Continue; |
2093 | } |
2094 | |
2095 | // The following features and properties are not promoted to any core Vulkan versions (up to Vulkan |
2096 | // 1.3): |
2097 | // |
2098 | // - VK_EXT_line_rasterization: bresenhamLines (feature) |
2099 | // - VK_EXT_provoking_vertex: provokingVertexLast (feature) |
2100 | // - VK_EXT_vertex_attribute_divisor: vertexAttributeInstanceRateDivisor (feature), |
2101 | // maxVertexAttribDivisor (property) |
2102 | // - VK_EXT_transform_feedback: transformFeedback (feature), |
2103 | // geometryStreams (feature) |
2104 | // - VK_EXT_index_type_uint8: indexTypeUint8 (feature) |
2105 | // - VK_EXT_device_memory_report: deviceMemoryReport (feature) |
2106 | // - VK_EXT_multisampled_render_to_single_sampled or |
2107 | // VK_GOOGLEX_multisampled_render_to_single_sampled: multisampledRenderToSingleSampled (feature) |
2108 | // - VK_EXT_image_2d_view_of_3d: image2DViewOf3D (feature) |
2109 | // sampler2DViewOf3D (feature) |
2110 | // - VK_EXT_custom_border_color: customBorderColors (feature) |
2111 | // customBorderColorWithoutFormat (feature) |
2112 | // - VK_EXT_depth_clamp_zero_one: depthClampZeroOne (feature) |
2113 | // - VK_EXT_depth_clip_enable: depthClipEnable (feature) |
2114 | // - VK_EXT_depth_clip_control: depthClipControl (feature) |
2115 | // - VK_EXT_primitives_generated_query: primitivesGeneratedQuery (feature), |
2116 | // primitivesGeneratedQueryWithRasterizerDiscard |
2117 | // (property) |
2118 | // - VK_EXT_primitive_topology_list_restart: primitiveTopologyListRestart (feature) |
2119 | // - VK_EXT_graphics_pipeline_library: graphicsPipelineLibrary (feature), |
2120 | // graphicsPipelineLibraryFastLinking (property) |
2121 | // - VK_KHR_fragment_shading_rate: pipelineFragmentShadingRate (feature) |
2122 | // - VK_EXT_fragment_shader_interlock: fragmentShaderPixelInterlock (feature) |
2123 | // - VK_EXT_pipeline_robustness: pipelineRobustness (feature) |
2124 | // - VK_EXT_pipeline_protected_access: pipelineProtectedAccess (feature) |
2125 | // - VK_EXT_rasterization_order_attachment_access or |
2126 | // VK_ARM_rasterization_order_attachment_access: rasterizationOrderColorAttachmentAccess |
2127 | // (feature) |
2128 | // - VK_EXT_swapchain_maintenance1: swapchainMaintenance1 (feature) |
2129 | // - VK_EXT_legacy_dithering: supportsLegacyDithering (feature) |
2130 | // - VK_EXT_physical_device_drm: hasPrimary (property), |
2131 | // hasRender (property) |
2132 | // |
2133 | void RendererVk::appendDeviceExtensionFeaturesNotPromoted( |
2134 | const vk::ExtensionNameList &deviceExtensionNames, |
2135 | VkPhysicalDeviceFeatures2KHR *deviceFeatures, |
2136 | VkPhysicalDeviceProperties2 *deviceProperties) |
2137 | { |
2138 | if (ExtensionFound(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2139 | { |
2140 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mLineRasterizationFeatures); |
2141 | } |
2142 | |
2143 | if (ExtensionFound(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2144 | { |
2145 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mProvokingVertexFeatures); |
2146 | } |
2147 | |
2148 | if (ExtensionFound(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2149 | { |
2150 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mVertexAttributeDivisorFeatures); |
2151 | vk::AddToPNextChain(chainStart: deviceProperties, ptr: &mVertexAttributeDivisorProperties); |
2152 | } |
2153 | |
2154 | if (ExtensionFound(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2155 | { |
2156 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mTransformFeedbackFeatures); |
2157 | } |
2158 | |
2159 | if (ExtensionFound(VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2160 | { |
2161 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mIndexTypeUint8Features); |
2162 | } |
2163 | |
2164 | if (ExtensionFound(VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2165 | { |
2166 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mMemoryReportFeatures); |
2167 | } |
2168 | |
2169 | if (ExtensionFound(VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXTENSION_NAME, |
2170 | haystack: deviceExtensionNames)) |
2171 | { |
2172 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mMultisampledRenderToSingleSampledFeatures); |
2173 | } |
2174 | else if (ExtensionFound(VK_GOOGLEX_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXTENSION_NAME, |
2175 | haystack: deviceExtensionNames)) |
2176 | { |
2177 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mMultisampledRenderToSingleSampledFeaturesGOOGLEX); |
2178 | } |
2179 | |
2180 | if (ExtensionFound(VK_EXT_IMAGE_2D_VIEW_OF_3D_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2181 | { |
2182 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mImage2dViewOf3dFeatures); |
2183 | } |
2184 | |
2185 | if (ExtensionFound(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2186 | { |
2187 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mCustomBorderColorFeatures); |
2188 | } |
2189 | |
2190 | if (ExtensionFound(VK_EXT_DEPTH_CLAMP_ZERO_ONE_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2191 | { |
2192 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mDepthClampZeroOneFeatures); |
2193 | } |
2194 | |
2195 | if (ExtensionFound(VK_EXT_DEPTH_CLIP_ENABLE_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2196 | { |
2197 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mDepthClipEnableFeatures); |
2198 | } |
2199 | |
2200 | if (ExtensionFound(VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2201 | { |
2202 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mDepthClipControlFeatures); |
2203 | } |
2204 | |
2205 | if (ExtensionFound(VK_EXT_PRIMITIVES_GENERATED_QUERY_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2206 | { |
2207 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mPrimitivesGeneratedQueryFeatures); |
2208 | } |
2209 | |
2210 | if (ExtensionFound(VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2211 | { |
2212 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mPrimitiveTopologyListRestartFeatures); |
2213 | } |
2214 | |
2215 | if (ExtensionFound(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2216 | { |
2217 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mGraphicsPipelineLibraryFeatures); |
2218 | vk::AddToPNextChain(chainStart: deviceProperties, ptr: &mGraphicsPipelineLibraryProperties); |
2219 | } |
2220 | |
2221 | if (ExtensionFound(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2222 | { |
2223 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mFragmentShadingRateFeatures); |
2224 | } |
2225 | |
2226 | if (ExtensionFound(VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2227 | { |
2228 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mFragmentShaderInterlockFeatures); |
2229 | } |
2230 | |
2231 | if (ExtensionFound(VK_EXT_PIPELINE_ROBUSTNESS_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2232 | { |
2233 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mPipelineRobustnessFeatures); |
2234 | } |
2235 | |
2236 | if (ExtensionFound(VK_EXT_PIPELINE_PROTECTED_ACCESS_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2237 | { |
2238 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mPipelineProtectedAccessFeatures); |
2239 | } |
2240 | |
2241 | // The EXT and ARM versions are interchangeable. The structs and enums alias each other. |
2242 | if (ExtensionFound(VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME, |
2243 | haystack: deviceExtensionNames)) |
2244 | { |
2245 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mRasterizationOrderAttachmentAccessFeatures); |
2246 | } |
2247 | else if (ExtensionFound(VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME, |
2248 | haystack: deviceExtensionNames)) |
2249 | { |
2250 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mRasterizationOrderAttachmentAccessFeatures); |
2251 | } |
2252 | |
2253 | if (ExtensionFound(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2254 | { |
2255 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mSwapchainMaintenance1Features); |
2256 | } |
2257 | |
2258 | if (ExtensionFound(VK_EXT_LEGACY_DITHERING_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2259 | { |
2260 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mDitheringFeatures); |
2261 | } |
2262 | |
2263 | if (ExtensionFound(VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2264 | { |
2265 | vk::AddToPNextChain(chainStart: deviceProperties, ptr: &mDrmProperties); |
2266 | } |
2267 | } |
2268 | |
2269 | // The following features and properties used by ANGLE have been promoted to Vulkan 1.1: |
2270 | // |
2271 | // - (unpublished VK_KHR_subgroup): supportedStages (property), |
2272 | // supportedOperations (property) |
2273 | // - (unpublished VK_KHR_protected_memory): protectedMemory (feature) |
2274 | // - VK_KHR_sampler_ycbcr_conversion: samplerYcbcrConversion (feature) |
2275 | // - VK_KHR_multiview: multiview (feature), |
2276 | // maxMultiviewViewCount (property) |
2277 | // |
2278 | // |
2279 | // Note that subgroup and protected memory features and properties came from unpublished extensions |
2280 | // and are core in Vulkan 1.1. |
2281 | // |
2282 | void RendererVk::appendDeviceExtensionFeaturesPromotedTo11( |
2283 | const vk::ExtensionNameList &deviceExtensionNames, |
2284 | VkPhysicalDeviceFeatures2KHR *deviceFeatures, |
2285 | VkPhysicalDeviceProperties2 *deviceProperties) |
2286 | { |
2287 | if (isVulkan11Device()) |
2288 | { |
2289 | vk::AddToPNextChain(chainStart: deviceProperties, ptr: &mSubgroupProperties); |
2290 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mProtectedMemoryFeatures); |
2291 | } |
2292 | |
2293 | if (ExtensionFound(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2294 | { |
2295 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mSamplerYcbcrConversionFeatures); |
2296 | } |
2297 | |
2298 | if (ExtensionFound(VK_KHR_MULTIVIEW_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2299 | { |
2300 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mMultiviewFeatures); |
2301 | vk::AddToPNextChain(chainStart: deviceProperties, ptr: &mMultiviewProperties); |
2302 | } |
2303 | } |
2304 | |
2305 | // The following features and properties used by ANGLE have been promoted to Vulkan 1.2: |
2306 | // |
2307 | // - VK_KHR_shader_float16_int8: shaderFloat16 (feature) |
2308 | // - VK_KHR_depth_stencil_resolve: supportedDepthResolveModes (property), |
2309 | // independentResolveNone (property) |
2310 | // - VK_KHR_driver_properties: driverName (property), |
2311 | // driverID (property) |
2312 | // - VK_KHR_shader_subgroup_extended_types: shaderSubgroupExtendedTypes (feature) |
2313 | // - VK_EXT_host_query_reset: hostQueryReset (feature) |
2314 | // - VK_KHR_imageless_framebuffer: imagelessFramebuffer (feature) |
2315 | // - VK_KHR_timeline_semaphore: timelineSemaphore (feature) |
2316 | // |
2317 | // Note that supportedDepthResolveModes is used just to check if the property struct is populated. |
2318 | // ANGLE always uses VK_RESOLVE_MODE_SAMPLE_ZERO_BIT for both depth and stencil, and support for |
2319 | // this bit is mandatory as long as the extension (or Vulkan 1.2) exists. |
2320 | // |
2321 | void RendererVk::appendDeviceExtensionFeaturesPromotedTo12( |
2322 | const vk::ExtensionNameList &deviceExtensionNames, |
2323 | VkPhysicalDeviceFeatures2KHR *deviceFeatures, |
2324 | VkPhysicalDeviceProperties2 *deviceProperties) |
2325 | { |
2326 | if (ExtensionFound(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2327 | { |
2328 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mShaderFloat16Int8Features); |
2329 | } |
2330 | |
2331 | if (ExtensionFound(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2332 | { |
2333 | vk::AddToPNextChain(chainStart: deviceProperties, ptr: &mDepthStencilResolveProperties); |
2334 | } |
2335 | |
2336 | if (ExtensionFound(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2337 | { |
2338 | vk::AddToPNextChain(chainStart: deviceProperties, ptr: &mDriverProperties); |
2339 | } |
2340 | |
2341 | if (ExtensionFound(VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2342 | { |
2343 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mSubgroupExtendedTypesFeatures); |
2344 | } |
2345 | |
2346 | if (ExtensionFound(VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2347 | { |
2348 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mHostQueryResetFeatures); |
2349 | } |
2350 | |
2351 | if (ExtensionFound(VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2352 | { |
2353 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mImagelessFramebufferFeatures); |
2354 | } |
2355 | |
2356 | if (ExtensionFound(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2357 | { |
2358 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mTimelineSemaphoreFeatures); |
2359 | } |
2360 | } |
2361 | |
2362 | // The following features and properties used by ANGLE have been promoted to Vulkan 1.3: |
2363 | // |
2364 | // - VK_EXT_pipeline_creation_cache_control: pipelineCreationCacheControl (feature) |
2365 | // - VK_EXT_extended_dynamic_state: extendedDynamicState (feature) |
2366 | // - VK_EXT_extended_dynamic_state2: extendedDynamicState2 (feature), |
2367 | // extendedDynamicState2LogicOp (feature) |
2368 | // |
2369 | // Note that VK_EXT_extended_dynamic_state2 is partially promoted to Vulkan 1.3. If ANGLE creates a |
2370 | // Vulkan 1.3 device, it would still need to enable this extension separately for |
2371 | // extendedDynamicState2LogicOp. |
2372 | // |
2373 | void RendererVk::appendDeviceExtensionFeaturesPromotedTo13( |
2374 | const vk::ExtensionNameList &deviceExtensionNames, |
2375 | VkPhysicalDeviceFeatures2KHR *deviceFeatures, |
2376 | VkPhysicalDeviceProperties2 *deviceProperties) |
2377 | { |
2378 | if (ExtensionFound(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2379 | { |
2380 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mPipelineCreationCacheControlFeatures); |
2381 | } |
2382 | |
2383 | if (ExtensionFound(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2384 | { |
2385 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mExtendedDynamicStateFeatures); |
2386 | } |
2387 | |
2388 | if (ExtensionFound(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2389 | { |
2390 | vk::AddToPNextChain(chainStart: deviceFeatures, ptr: &mExtendedDynamicState2Features); |
2391 | } |
2392 | } |
2393 | |
2394 | void RendererVk::queryDeviceExtensionFeatures(const vk::ExtensionNameList &deviceExtensionNames) |
2395 | { |
2396 | // Default initialize all extension features to false. |
2397 | mPhysicalDevice11Properties = {}; |
2398 | mPhysicalDevice11Properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_PROPERTIES; |
2399 | |
2400 | mPhysicalDevice11Features = {}; |
2401 | mPhysicalDevice11Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES; |
2402 | |
2403 | mLineRasterizationFeatures = {}; |
2404 | mLineRasterizationFeatures.sType = |
2405 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LINE_RASTERIZATION_FEATURES_EXT; |
2406 | |
2407 | mProvokingVertexFeatures = {}; |
2408 | mProvokingVertexFeatures.sType = |
2409 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT; |
2410 | |
2411 | mVertexAttributeDivisorFeatures = {}; |
2412 | mVertexAttributeDivisorFeatures.sType = |
2413 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT; |
2414 | |
2415 | mVertexAttributeDivisorProperties = {}; |
2416 | mVertexAttributeDivisorProperties.sType = |
2417 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT; |
2418 | |
2419 | mTransformFeedbackFeatures = {}; |
2420 | mTransformFeedbackFeatures.sType = |
2421 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT; |
2422 | |
2423 | mIndexTypeUint8Features = {}; |
2424 | mIndexTypeUint8Features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INDEX_TYPE_UINT8_FEATURES_EXT; |
2425 | |
2426 | mSubgroupProperties = {}; |
2427 | mSubgroupProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; |
2428 | |
2429 | mSubgroupExtendedTypesFeatures = {}; |
2430 | mSubgroupExtendedTypesFeatures.sType = |
2431 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_SUBGROUP_EXTENDED_TYPES_FEATURES; |
2432 | |
2433 | mMemoryReportFeatures = {}; |
2434 | mMemoryReportFeatures.sType = |
2435 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT; |
2436 | |
2437 | mShaderFloat16Int8Features = {}; |
2438 | mShaderFloat16Int8Features.sType = |
2439 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_FLOAT16_INT8_FEATURES; |
2440 | |
2441 | mDepthStencilResolveProperties = {}; |
2442 | mDepthStencilResolveProperties.sType = |
2443 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_STENCIL_RESOLVE_PROPERTIES; |
2444 | |
2445 | mCustomBorderColorFeatures = {}; |
2446 | mCustomBorderColorFeatures.sType = |
2447 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CUSTOM_BORDER_COLOR_FEATURES_EXT; |
2448 | |
2449 | mMultisampledRenderToSingleSampledFeatures = {}; |
2450 | mMultisampledRenderToSingleSampledFeatures.sType = |
2451 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_EXT; |
2452 | |
2453 | mMultisampledRenderToSingleSampledFeaturesGOOGLEX = {}; |
2454 | mMultisampledRenderToSingleSampledFeaturesGOOGLEX.sType = |
2455 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_FEATURES_GOOGLEX; |
2456 | |
2457 | mImage2dViewOf3dFeatures = {}; |
2458 | mImage2dViewOf3dFeatures.sType = |
2459 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT; |
2460 | |
2461 | mMultiviewFeatures = {}; |
2462 | mMultiviewFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; |
2463 | |
2464 | mMultiviewProperties = {}; |
2465 | mMultiviewProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES; |
2466 | |
2467 | mDriverProperties = {}; |
2468 | mDriverProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; |
2469 | |
2470 | mSamplerYcbcrConversionFeatures = {}; |
2471 | mSamplerYcbcrConversionFeatures.sType = |
2472 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES; |
2473 | |
2474 | mProtectedMemoryFeatures = {}; |
2475 | mProtectedMemoryFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES; |
2476 | |
2477 | mHostQueryResetFeatures = {}; |
2478 | mHostQueryResetFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT; |
2479 | |
2480 | mDepthClampZeroOneFeatures = {}; |
2481 | mDepthClampZeroOneFeatures.sType = |
2482 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLAMP_ZERO_ONE_FEATURES_EXT; |
2483 | |
2484 | mDepthClipEnableFeatures = {}; |
2485 | mDepthClipEnableFeatures.sType = |
2486 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_ENABLE_FEATURES_EXT; |
2487 | |
2488 | mDepthClipControlFeatures = {}; |
2489 | mDepthClipControlFeatures.sType = |
2490 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT; |
2491 | |
2492 | mPrimitivesGeneratedQueryFeatures = {}; |
2493 | mPrimitivesGeneratedQueryFeatures.sType = |
2494 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVES_GENERATED_QUERY_FEATURES_EXT; |
2495 | |
2496 | mPrimitiveTopologyListRestartFeatures = {}; |
2497 | mPrimitiveTopologyListRestartFeatures.sType = |
2498 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIMITIVE_TOPOLOGY_LIST_RESTART_FEATURES_EXT; |
2499 | |
2500 | mPipelineCreationCacheControlFeatures = {}; |
2501 | mPipelineCreationCacheControlFeatures.sType = |
2502 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES_EXT; |
2503 | |
2504 | mExtendedDynamicStateFeatures = {}; |
2505 | mExtendedDynamicStateFeatures.sType = |
2506 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT; |
2507 | |
2508 | mExtendedDynamicState2Features = {}; |
2509 | mExtendedDynamicState2Features.sType = |
2510 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT; |
2511 | |
2512 | mGraphicsPipelineLibraryFeatures = {}; |
2513 | mGraphicsPipelineLibraryFeatures.sType = |
2514 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT; |
2515 | |
2516 | mGraphicsPipelineLibraryProperties = {}; |
2517 | mGraphicsPipelineLibraryProperties.sType = |
2518 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_PROPERTIES_EXT; |
2519 | |
2520 | mFragmentShadingRateFeatures = {}; |
2521 | mFragmentShadingRateFeatures.sType = |
2522 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_FEATURES_KHR; |
2523 | |
2524 | mFragmentShaderInterlockFeatures = {}; |
2525 | mFragmentShaderInterlockFeatures.sType = |
2526 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADER_INTERLOCK_FEATURES_EXT; |
2527 | |
2528 | mImagelessFramebufferFeatures = {}; |
2529 | mImagelessFramebufferFeatures.sType = |
2530 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES_KHR; |
2531 | |
2532 | mPipelineRobustnessFeatures = {}; |
2533 | mPipelineRobustnessFeatures.sType = |
2534 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT; |
2535 | |
2536 | mPipelineProtectedAccessFeatures = {}; |
2537 | mPipelineProtectedAccessFeatures.sType = |
2538 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_PROTECTED_ACCESS_FEATURES_EXT; |
2539 | |
2540 | mRasterizationOrderAttachmentAccessFeatures = {}; |
2541 | mRasterizationOrderAttachmentAccessFeatures.sType = |
2542 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_FEATURES_EXT; |
2543 | |
2544 | mSwapchainMaintenance1Features = {}; |
2545 | mSwapchainMaintenance1Features.sType = |
2546 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SWAPCHAIN_MAINTENANCE_1_FEATURES_EXT; |
2547 | |
2548 | mDitheringFeatures = {}; |
2549 | mDitheringFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LEGACY_DITHERING_FEATURES_EXT; |
2550 | |
2551 | mDrmProperties = {}; |
2552 | mDrmProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT; |
2553 | |
2554 | mTimelineSemaphoreFeatures = {}; |
2555 | mTimelineSemaphoreFeatures.sType = |
2556 | VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES_KHR; |
2557 | |
2558 | if (!vkGetPhysicalDeviceProperties2KHR || !vkGetPhysicalDeviceFeatures2KHR) |
2559 | { |
2560 | return; |
2561 | } |
2562 | |
2563 | // Query features and properties. |
2564 | VkPhysicalDeviceFeatures2KHR deviceFeatures = {}; |
2565 | deviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; |
2566 | |
2567 | VkPhysicalDeviceProperties2 deviceProperties = {}; |
2568 | deviceProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; |
2569 | |
2570 | appendDeviceExtensionFeaturesNotPromoted(deviceExtensionNames, deviceFeatures: &deviceFeatures, |
2571 | deviceProperties: &deviceProperties); |
2572 | appendDeviceExtensionFeaturesPromotedTo11(deviceExtensionNames, deviceFeatures: &deviceFeatures, |
2573 | deviceProperties: &deviceProperties); |
2574 | appendDeviceExtensionFeaturesPromotedTo12(deviceExtensionNames, deviceFeatures: &deviceFeatures, |
2575 | deviceProperties: &deviceProperties); |
2576 | appendDeviceExtensionFeaturesPromotedTo13(deviceExtensionNames, deviceFeatures: &deviceFeatures, |
2577 | deviceProperties: &deviceProperties); |
2578 | |
2579 | vkGetPhysicalDeviceFeatures2KHR(mPhysicalDevice, &deviceFeatures); |
2580 | vkGetPhysicalDeviceProperties2KHR(mPhysicalDevice, &deviceProperties); |
2581 | |
2582 | // Clean up pNext chains |
2583 | mPhysicalDevice11Properties.pNext = nullptr; |
2584 | mPhysicalDevice11Features.pNext = nullptr; |
2585 | mLineRasterizationFeatures.pNext = nullptr; |
2586 | mMemoryReportFeatures.pNext = nullptr; |
2587 | mProvokingVertexFeatures.pNext = nullptr; |
2588 | mVertexAttributeDivisorFeatures.pNext = nullptr; |
2589 | mVertexAttributeDivisorProperties.pNext = nullptr; |
2590 | mTransformFeedbackFeatures.pNext = nullptr; |
2591 | mIndexTypeUint8Features.pNext = nullptr; |
2592 | mSubgroupProperties.pNext = nullptr; |
2593 | mSubgroupExtendedTypesFeatures.pNext = nullptr; |
2594 | mCustomBorderColorFeatures.pNext = nullptr; |
2595 | mShaderFloat16Int8Features.pNext = nullptr; |
2596 | mDepthStencilResolveProperties.pNext = nullptr; |
2597 | mMultisampledRenderToSingleSampledFeatures.pNext = nullptr; |
2598 | mMultisampledRenderToSingleSampledFeaturesGOOGLEX.pNext = nullptr; |
2599 | mImage2dViewOf3dFeatures.pNext = nullptr; |
2600 | mMultiviewFeatures.pNext = nullptr; |
2601 | mMultiviewProperties.pNext = nullptr; |
2602 | mDriverProperties.pNext = nullptr; |
2603 | mSamplerYcbcrConversionFeatures.pNext = nullptr; |
2604 | mProtectedMemoryFeatures.pNext = nullptr; |
2605 | mHostQueryResetFeatures.pNext = nullptr; |
2606 | mDepthClampZeroOneFeatures.pNext = nullptr; |
2607 | mDepthClipEnableFeatures.pNext = nullptr; |
2608 | mDepthClipControlFeatures.pNext = nullptr; |
2609 | mPrimitivesGeneratedQueryFeatures.pNext = nullptr; |
2610 | mPrimitiveTopologyListRestartFeatures.pNext = nullptr; |
2611 | mPipelineCreationCacheControlFeatures.pNext = nullptr; |
2612 | mExtendedDynamicStateFeatures.pNext = nullptr; |
2613 | mExtendedDynamicState2Features.pNext = nullptr; |
2614 | mGraphicsPipelineLibraryFeatures.pNext = nullptr; |
2615 | mGraphicsPipelineLibraryProperties.pNext = nullptr; |
2616 | mFragmentShadingRateFeatures.pNext = nullptr; |
2617 | mFragmentShaderInterlockFeatures.pNext = nullptr; |
2618 | mImagelessFramebufferFeatures.pNext = nullptr; |
2619 | mPipelineRobustnessFeatures.pNext = nullptr; |
2620 | mPipelineProtectedAccessFeatures.pNext = nullptr; |
2621 | mRasterizationOrderAttachmentAccessFeatures.pNext = nullptr; |
2622 | mSwapchainMaintenance1Features.pNext = nullptr; |
2623 | mDitheringFeatures.pNext = nullptr; |
2624 | mDrmProperties.pNext = nullptr; |
2625 | mTimelineSemaphoreFeatures.pNext = nullptr; |
2626 | } |
2627 | |
2628 | // See comment above appendDeviceExtensionFeaturesNotPromoted. Additional extensions are enabled |
2629 | // here which don't have feature structs: |
2630 | // |
2631 | // - VK_KHR_shared_presentable_image |
2632 | // - VK_EXT_memory_budget |
2633 | // - VK_KHR_incremental_present |
2634 | // - VK_EXT_queue_family_foreign |
2635 | // - VK_ANDROID_external_memory_android_hardware_buffer |
2636 | // - VK_GGP_frame_token |
2637 | // - VK_KHR_external_memory_fd |
2638 | // - VK_KHR_external_memory_fuchsia |
2639 | // - VK_KHR_external_semaphore_fd |
2640 | // - VK_KHR_external_fence_fd |
2641 | // - VK_FUCHSIA_external_semaphore |
2642 | // - VK_EXT_shader_stencil_export |
2643 | // - VK_EXT_load_store_op_none |
2644 | // - VK_QCOM_render_pass_store_ops |
2645 | // - VK_GOOGLE_display_timing |
2646 | // - VK_EXT_external_memory_dma_buf |
2647 | // - VK_EXT_image_drm_format_modifier |
2648 | // - VK_EXT_blend_operation_advanced |
2649 | // - VK_EXT_full_screen_exclusive |
2650 | // |
2651 | void RendererVk::enableDeviceExtensionsNotPromoted( |
2652 | const vk::ExtensionNameList &deviceExtensionNames) |
2653 | { |
2654 | if (mFeatures.supportsSharedPresentableImageExtension.enabled) |
2655 | { |
2656 | mEnabledDeviceExtensions.push_back(VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME); |
2657 | } |
2658 | |
2659 | if (mFeatures.supportsDepthClampZeroOne.enabled) |
2660 | { |
2661 | mEnabledDeviceExtensions.push_back(VK_EXT_DEPTH_CLAMP_ZERO_ONE_EXTENSION_NAME); |
2662 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mDepthClampZeroOneFeatures); |
2663 | } |
2664 | |
2665 | if (mFeatures.supportsMemoryBudget.enabled) |
2666 | { |
2667 | mEnabledDeviceExtensions.push_back(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME); |
2668 | } |
2669 | |
2670 | if (mFeatures.supportsIncrementalPresent.enabled) |
2671 | { |
2672 | mEnabledDeviceExtensions.push_back(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME); |
2673 | } |
2674 | |
2675 | #if defined(ANGLE_PLATFORM_ANDROID) |
2676 | if (mFeatures.supportsAndroidHardwareBuffer.enabled) |
2677 | { |
2678 | mEnabledDeviceExtensions.push_back(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME); |
2679 | mEnabledDeviceExtensions.push_back( |
2680 | VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME); |
2681 | } |
2682 | #else |
2683 | ASSERT(!mFeatures.supportsAndroidHardwareBuffer.enabled); |
2684 | #endif |
2685 | |
2686 | #if defined(ANGLE_PLATFORM_GGP) |
2687 | if (mFeatures.supportsGGPFrameToken.enabled) |
2688 | { |
2689 | mEnabledDeviceExtensions.push_back(VK_GGP_FRAME_TOKEN_EXTENSION_NAME); |
2690 | } |
2691 | #else |
2692 | ASSERT(!mFeatures.supportsGGPFrameToken.enabled); |
2693 | #endif |
2694 | |
2695 | if (mFeatures.supportsExternalMemoryFd.enabled) |
2696 | { |
2697 | mEnabledDeviceExtensions.push_back(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME); |
2698 | } |
2699 | |
2700 | if (mFeatures.supportsExternalMemoryFuchsia.enabled) |
2701 | { |
2702 | mEnabledDeviceExtensions.push_back(VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME); |
2703 | } |
2704 | |
2705 | if (mFeatures.supportsExternalSemaphoreFd.enabled) |
2706 | { |
2707 | mEnabledDeviceExtensions.push_back(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME); |
2708 | } |
2709 | |
2710 | if (mFeatures.supportsExternalFenceFd.enabled) |
2711 | { |
2712 | mEnabledDeviceExtensions.push_back(VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME); |
2713 | } |
2714 | |
2715 | if (mFeatures.supportsExternalSemaphoreFuchsia.enabled) |
2716 | { |
2717 | mEnabledDeviceExtensions.push_back(VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME); |
2718 | } |
2719 | |
2720 | if (mFeatures.supportsShaderStencilExport.enabled) |
2721 | { |
2722 | mEnabledDeviceExtensions.push_back(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME); |
2723 | } |
2724 | |
2725 | if (mFeatures.supportsRenderPassLoadStoreOpNone.enabled) |
2726 | { |
2727 | mEnabledDeviceExtensions.push_back(VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME); |
2728 | } |
2729 | else if (mFeatures.supportsRenderPassStoreOpNone.enabled) |
2730 | { |
2731 | mEnabledDeviceExtensions.push_back(VK_QCOM_RENDER_PASS_STORE_OPS_EXTENSION_NAME); |
2732 | } |
2733 | |
2734 | if (mFeatures.supportsTimestampSurfaceAttribute.enabled) |
2735 | { |
2736 | mEnabledDeviceExtensions.push_back(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME); |
2737 | } |
2738 | |
2739 | if (mFeatures.bresenhamLineRasterization.enabled) |
2740 | { |
2741 | mEnabledDeviceExtensions.push_back(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME); |
2742 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mLineRasterizationFeatures); |
2743 | } |
2744 | |
2745 | if (mFeatures.provokingVertex.enabled) |
2746 | { |
2747 | mEnabledDeviceExtensions.push_back(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME); |
2748 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mProvokingVertexFeatures); |
2749 | } |
2750 | |
2751 | if (mVertexAttributeDivisorFeatures.vertexAttributeInstanceRateDivisor) |
2752 | { |
2753 | mEnabledDeviceExtensions.push_back(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME); |
2754 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mVertexAttributeDivisorFeatures); |
2755 | |
2756 | // We only store 8 bit divisor in GraphicsPipelineDesc so capping value & we emulate if |
2757 | // exceeded |
2758 | mMaxVertexAttribDivisor = |
2759 | std::min(a: mVertexAttributeDivisorProperties.maxVertexAttribDivisor, |
2760 | b: static_cast<uint32_t>(std::numeric_limits<uint8_t>::max())); |
2761 | } |
2762 | |
2763 | if (mFeatures.supportsTransformFeedbackExtension.enabled) |
2764 | { |
2765 | mEnabledDeviceExtensions.push_back(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME); |
2766 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mTransformFeedbackFeatures); |
2767 | } |
2768 | |
2769 | if (mFeatures.supportsCustomBorderColor.enabled) |
2770 | { |
2771 | mEnabledDeviceExtensions.push_back(VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME); |
2772 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mCustomBorderColorFeatures); |
2773 | } |
2774 | |
2775 | if (mFeatures.supportsIndexTypeUint8.enabled) |
2776 | { |
2777 | mEnabledDeviceExtensions.push_back(VK_EXT_INDEX_TYPE_UINT8_EXTENSION_NAME); |
2778 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mIndexTypeUint8Features); |
2779 | } |
2780 | |
2781 | if (mFeatures.supportsMultisampledRenderToSingleSampled.enabled) |
2782 | { |
2783 | mEnabledDeviceExtensions.push_back( |
2784 | VK_EXT_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXTENSION_NAME); |
2785 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mMultisampledRenderToSingleSampledFeatures); |
2786 | } |
2787 | |
2788 | if (mFeatures.supportsMultisampledRenderToSingleSampledGOOGLEX.enabled) |
2789 | { |
2790 | ASSERT(!mFeatures.supportsMultisampledRenderToSingleSampled.enabled); |
2791 | mEnabledDeviceExtensions.push_back( |
2792 | VK_GOOGLEX_MULTISAMPLED_RENDER_TO_SINGLE_SAMPLED_EXTENSION_NAME); |
2793 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mMultisampledRenderToSingleSampledFeaturesGOOGLEX); |
2794 | } |
2795 | |
2796 | if (mFeatures.logMemoryReportCallbacks.enabled || mFeatures.logMemoryReportStats.enabled) |
2797 | { |
2798 | ASSERT(mMemoryReportFeatures.deviceMemoryReport); |
2799 | mEnabledDeviceExtensions.push_back(VK_EXT_DEVICE_MEMORY_REPORT_EXTENSION_NAME); |
2800 | } |
2801 | |
2802 | if (mFeatures.supportsExternalMemoryDmaBufAndModifiers.enabled) |
2803 | { |
2804 | mEnabledDeviceExtensions.push_back(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME); |
2805 | mEnabledDeviceExtensions.push_back(VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME); |
2806 | } |
2807 | |
2808 | if (mFeatures.supportsDepthClipControl.enabled) |
2809 | { |
2810 | mEnabledDeviceExtensions.push_back(VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME); |
2811 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mDepthClipControlFeatures); |
2812 | } |
2813 | |
2814 | if (mFeatures.supportsPrimitivesGeneratedQuery.enabled) |
2815 | { |
2816 | mEnabledDeviceExtensions.push_back(VK_EXT_PRIMITIVES_GENERATED_QUERY_EXTENSION_NAME); |
2817 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mPrimitivesGeneratedQueryFeatures); |
2818 | } |
2819 | |
2820 | if (mFeatures.supportsPrimitiveTopologyListRestart.enabled) |
2821 | { |
2822 | mEnabledDeviceExtensions.push_back(VK_EXT_PRIMITIVE_TOPOLOGY_LIST_RESTART_EXTENSION_NAME); |
2823 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mPrimitiveTopologyListRestartFeatures); |
2824 | } |
2825 | |
2826 | if (mFeatures.supportsBlendOperationAdvanced.enabled) |
2827 | { |
2828 | mEnabledDeviceExtensions.push_back(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME); |
2829 | } |
2830 | |
2831 | if (mFeatures.supportsGraphicsPipelineLibrary.enabled) |
2832 | { |
2833 | // VK_EXT_graphics_pipeline_library requires VK_KHR_pipeline_library |
2834 | ASSERT(ExtensionFound(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME, deviceExtensionNames)); |
2835 | mEnabledDeviceExtensions.push_back(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); |
2836 | |
2837 | mEnabledDeviceExtensions.push_back(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME); |
2838 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mGraphicsPipelineLibraryFeatures); |
2839 | } |
2840 | |
2841 | if (mFeatures.supportsFragmentShadingRate.enabled) |
2842 | { |
2843 | mEnabledDeviceExtensions.push_back(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME); |
2844 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mFragmentShadingRateFeatures); |
2845 | } |
2846 | |
2847 | if (mFeatures.supportsFragmentShaderPixelInterlock.enabled) |
2848 | { |
2849 | mEnabledDeviceExtensions.push_back(VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME); |
2850 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mFragmentShaderInterlockFeatures); |
2851 | } |
2852 | |
2853 | if (mFeatures.supportsPipelineRobustness.enabled) |
2854 | { |
2855 | mEnabledDeviceExtensions.push_back(VK_EXT_PIPELINE_ROBUSTNESS_EXTENSION_NAME); |
2856 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mPipelineRobustnessFeatures); |
2857 | } |
2858 | |
2859 | if (mFeatures.supportsPipelineProtectedAccess.enabled) |
2860 | { |
2861 | mEnabledDeviceExtensions.push_back(VK_EXT_PIPELINE_PROTECTED_ACCESS_EXTENSION_NAME); |
2862 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mPipelineProtectedAccessFeatures); |
2863 | } |
2864 | |
2865 | if (mFeatures.supportsRasterizationOrderAttachmentAccess.enabled) |
2866 | { |
2867 | if (ExtensionFound(VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME, |
2868 | haystack: deviceExtensionNames)) |
2869 | { |
2870 | mEnabledDeviceExtensions.push_back( |
2871 | VK_EXT_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME); |
2872 | } |
2873 | else |
2874 | { |
2875 | ASSERT(ExtensionFound(VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME, |
2876 | deviceExtensionNames)); |
2877 | mEnabledDeviceExtensions.push_back( |
2878 | VK_ARM_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_EXTENSION_NAME); |
2879 | } |
2880 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mRasterizationOrderAttachmentAccessFeatures); |
2881 | } |
2882 | |
2883 | if (mFeatures.supportsImage2dViewOf3d.enabled) |
2884 | { |
2885 | mEnabledDeviceExtensions.push_back(VK_EXT_IMAGE_2D_VIEW_OF_3D_EXTENSION_NAME); |
2886 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mImage2dViewOf3dFeatures); |
2887 | } |
2888 | |
2889 | if (mFeatures.supportsSwapchainMaintenance1.enabled) |
2890 | { |
2891 | mEnabledDeviceExtensions.push_back(VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME); |
2892 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mSwapchainMaintenance1Features); |
2893 | } |
2894 | |
2895 | if (mFeatures.supportsLegacyDithering.enabled) |
2896 | { |
2897 | mEnabledDeviceExtensions.push_back(VK_EXT_LEGACY_DITHERING_EXTENSION_NAME); |
2898 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mDitheringFeatures); |
2899 | } |
2900 | |
2901 | #if defined(ANGLE_PLATFORM_WINDOWS) |
2902 | // We only need the VK_EXT_full_screen_exclusive extension if we are opting |
2903 | // out of it via VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT (i.e. working |
2904 | // around driver bugs). |
2905 | if (getFeatures().supportsFullScreenExclusive.enabled && |
2906 | getFeatures().forceDisableFullScreenExclusive.enabled) |
2907 | { |
2908 | mEnabledDeviceExtensions.push_back(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME); |
2909 | } |
2910 | #endif |
2911 | } |
2912 | |
2913 | // See comment above appendDeviceExtensionFeaturesPromotedTo11. Additional extensions are enabled |
2914 | // here which don't have feature structs: |
2915 | // |
2916 | // - VK_KHR_get_memory_requirements2 |
2917 | // - VK_KHR_bind_memory2 |
2918 | // - VK_KHR_maintenance1 |
2919 | // - VK_KHR_external_memory |
2920 | // - VK_KHR_external_semaphore |
2921 | // - VK_KHR_external_fence |
2922 | // |
2923 | void RendererVk::enableDeviceExtensionsPromotedTo11( |
2924 | const vk::ExtensionNameList &deviceExtensionNames) |
2925 | { |
2926 | // OVR_multiview disallows multiview with geometry and tessellation, so don't request these |
2927 | // features. |
2928 | mMultiviewFeatures.multiviewGeometryShader = VK_FALSE; |
2929 | mMultiviewFeatures.multiviewTessellationShader = VK_FALSE; |
2930 | mPhysicalDevice11Features.multiviewGeometryShader = VK_FALSE; |
2931 | mPhysicalDevice11Features.multiviewTessellationShader = VK_FALSE; |
2932 | |
2933 | // Disable protected memory if not needed as it can introduce overhead |
2934 | if (!mFeatures.supportsProtectedMemory.enabled) |
2935 | { |
2936 | mPhysicalDevice11Features.protectedMemory = VK_FALSE; |
2937 | } |
2938 | |
2939 | if (isVulkan11Device()) |
2940 | { |
2941 | if (mFeatures.supportsMultiview.enabled) |
2942 | { |
2943 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mMultiviewFeatures); |
2944 | } |
2945 | |
2946 | if (mFeatures.supportsYUVSamplerConversion.enabled) |
2947 | { |
2948 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mSamplerYcbcrConversionFeatures); |
2949 | } |
2950 | |
2951 | if (mFeatures.supportsProtectedMemory.enabled) |
2952 | { |
2953 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mProtectedMemoryFeatures); |
2954 | } |
2955 | |
2956 | return; |
2957 | } |
2958 | |
2959 | if (mFeatures.supportsGetMemoryRequirements2.enabled) |
2960 | { |
2961 | mEnabledDeviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); |
2962 | } |
2963 | |
2964 | if (ExtensionFound(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME, haystack: deviceExtensionNames)) |
2965 | { |
2966 | mEnabledDeviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); |
2967 | } |
2968 | |
2969 | if (mFeatures.supportsBindMemory2.enabled) |
2970 | { |
2971 | mEnabledDeviceExtensions.push_back(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME); |
2972 | } |
2973 | |
2974 | if (mFeatures.supportsNegativeViewport.enabled) |
2975 | { |
2976 | mEnabledDeviceExtensions.push_back(VK_KHR_MAINTENANCE1_EXTENSION_NAME); |
2977 | } |
2978 | |
2979 | if (mFeatures.supportsAndroidHardwareBuffer.enabled || |
2980 | mFeatures.supportsExternalMemoryFd.enabled || |
2981 | mFeatures.supportsExternalMemoryFuchsia.enabled) |
2982 | { |
2983 | mEnabledDeviceExtensions.push_back(VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME); |
2984 | } |
2985 | |
2986 | if (mFeatures.supportsExternalSemaphoreFd.enabled || |
2987 | mFeatures.supportsExternalSemaphoreFuchsia.enabled) |
2988 | { |
2989 | mEnabledDeviceExtensions.push_back(VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME); |
2990 | } |
2991 | |
2992 | if (mFeatures.supportsExternalFenceFd.enabled) |
2993 | { |
2994 | mEnabledDeviceExtensions.push_back(VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME); |
2995 | } |
2996 | |
2997 | if (mFeatures.supportsMultiview.enabled) |
2998 | { |
2999 | mEnabledDeviceExtensions.push_back(VK_KHR_MULTIVIEW_EXTENSION_NAME); |
3000 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mMultiviewFeatures); |
3001 | } |
3002 | |
3003 | if (mFeatures.supportsYUVSamplerConversion.enabled) |
3004 | { |
3005 | mEnabledDeviceExtensions.push_back(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME); |
3006 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mSamplerYcbcrConversionFeatures); |
3007 | } |
3008 | |
3009 | if (mFeatures.supportsProtectedMemory.enabled) |
3010 | { |
3011 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mProtectedMemoryFeatures); |
3012 | } |
3013 | } |
3014 | |
3015 | // See comment above appendDeviceExtensionFeaturesPromotedTo12. Additional extensions are enabled |
3016 | // here which don't have feature structs: |
3017 | // |
3018 | // - VK_KHR_create_renderpass2 |
3019 | // - VK_KHR_image_format_list |
3020 | // - VK_KHR_sampler_mirror_clamp_to_edge |
3021 | // |
3022 | void RendererVk::enableDeviceExtensionsPromotedTo12( |
3023 | const vk::ExtensionNameList &deviceExtensionNames) |
3024 | { |
3025 | if (mFeatures.supportsRenderpass2.enabled) |
3026 | { |
3027 | mEnabledDeviceExtensions.push_back(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME); |
3028 | } |
3029 | |
3030 | if (mFeatures.supportsImageFormatList.enabled) |
3031 | { |
3032 | mEnabledDeviceExtensions.push_back(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME); |
3033 | } |
3034 | |
3035 | if (mFeatures.supportsSamplerMirrorClampToEdge.enabled) |
3036 | { |
3037 | mEnabledDeviceExtensions.push_back(VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME); |
3038 | } |
3039 | |
3040 | if (mFeatures.supportsDepthStencilResolve.enabled) |
3041 | { |
3042 | mEnabledDeviceExtensions.push_back(VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME); |
3043 | } |
3044 | |
3045 | if (mFeatures.allowGenerateMipmapWithCompute.enabled) |
3046 | { |
3047 | mEnabledDeviceExtensions.push_back(VK_KHR_SHADER_SUBGROUP_EXTENDED_TYPES_EXTENSION_NAME); |
3048 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mSubgroupExtendedTypesFeatures); |
3049 | } |
3050 | |
3051 | if (mFeatures.supportsShaderFloat16.enabled) |
3052 | { |
3053 | mEnabledDeviceExtensions.push_back(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME); |
3054 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mShaderFloat16Int8Features); |
3055 | } |
3056 | |
3057 | if (mFeatures.supportsHostQueryReset.enabled) |
3058 | { |
3059 | mEnabledDeviceExtensions.push_back(VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME); |
3060 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mHostQueryResetFeatures); |
3061 | } |
3062 | |
3063 | if (mFeatures.supportsImagelessFramebuffer.enabled) |
3064 | { |
3065 | mEnabledDeviceExtensions.push_back(VK_KHR_IMAGELESS_FRAMEBUFFER_EXTENSION_NAME); |
3066 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mImagelessFramebufferFeatures); |
3067 | } |
3068 | |
3069 | if (mFeatures.supportsTimelineSemaphore.enabled) |
3070 | { |
3071 | mEnabledDeviceExtensions.push_back(VK_KHR_TIMELINE_SEMAPHORE_EXTENSION_NAME); |
3072 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mTimelineSemaphoreFeatures); |
3073 | } |
3074 | } |
3075 | |
3076 | // See comment above appendDeviceExtensionFeaturesPromotedTo13. |
3077 | void RendererVk::enableDeviceExtensionsPromotedTo13( |
3078 | const vk::ExtensionNameList &deviceExtensionNames) |
3079 | { |
3080 | if (mFeatures.supportsPipelineCreationCacheControl.enabled) |
3081 | { |
3082 | mEnabledDeviceExtensions.push_back(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME); |
3083 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mPipelineCreationCacheControlFeatures); |
3084 | } |
3085 | |
3086 | if (mFeatures.supportsPipelineCreationFeedback.enabled) |
3087 | { |
3088 | mEnabledDeviceExtensions.push_back(VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME); |
3089 | } |
3090 | |
3091 | if (mFeatures.supportsExtendedDynamicState.enabled) |
3092 | { |
3093 | mEnabledDeviceExtensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME); |
3094 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mExtendedDynamicStateFeatures); |
3095 | } |
3096 | |
3097 | if (mFeatures.supportsExtendedDynamicState2.enabled) |
3098 | { |
3099 | mEnabledDeviceExtensions.push_back(VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME); |
3100 | vk::AddToPNextChain(chainStart: &mEnabledFeatures, ptr: &mExtendedDynamicState2Features); |
3101 | } |
3102 | } |
3103 | |
3104 | angle::Result RendererVk::enableDeviceExtensions(DisplayVk *displayVk, |
3105 | const VulkanLayerVector &enabledDeviceLayerNames) |
3106 | { |
3107 | // Enumerate device extensions that are provided by the vulkan |
3108 | // implementation and implicit layers. |
3109 | uint32_t deviceExtensionCount = 0; |
3110 | ANGLE_VK_TRY(displayVk, vkEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, |
3111 | &deviceExtensionCount, nullptr)); |
3112 | |
3113 | // Work-around a race condition in the Android platform during Android start-up, that can cause |
3114 | // the second call to vkEnumerateDeviceExtensionProperties to have an additional extension. In |
3115 | // that case, the second call will return VK_INCOMPLETE. To work-around that, add 1 to |
3116 | // deviceExtensionCount and ask for one more extension property than the first call said there |
3117 | // were. See: http://anglebug.com/6715 and internal-to-Google bug: b/206733351. |
3118 | deviceExtensionCount++; |
3119 | std::vector<VkExtensionProperties> deviceExtensionProps(deviceExtensionCount); |
3120 | ANGLE_VK_TRY(displayVk, |
3121 | vkEnumerateDeviceExtensionProperties( |
3122 | mPhysicalDevice, nullptr, &deviceExtensionCount, deviceExtensionProps.data())); |
3123 | // In case fewer items were returned than requested, resize deviceExtensionProps to the number |
3124 | // of extensions returned (i.e. deviceExtensionCount). See: b/208937840 |
3125 | deviceExtensionProps.resize(sz: deviceExtensionCount); |
3126 | |
3127 | // Enumerate device extensions that are provided by explicit layers. |
3128 | for (const char *layerName : enabledDeviceLayerNames) |
3129 | { |
3130 | uint32_t previousExtensionCount = static_cast<uint32_t>(deviceExtensionProps.size()); |
3131 | uint32_t deviceLayerExtensionCount = 0; |
3132 | ANGLE_VK_TRY(displayVk, |
3133 | vkEnumerateDeviceExtensionProperties(mPhysicalDevice, layerName, |
3134 | &deviceLayerExtensionCount, nullptr)); |
3135 | deviceExtensionProps.resize(sz: previousExtensionCount + deviceLayerExtensionCount); |
3136 | ANGLE_VK_TRY(displayVk, vkEnumerateDeviceExtensionProperties( |
3137 | mPhysicalDevice, layerName, &deviceLayerExtensionCount, |
3138 | deviceExtensionProps.data() + previousExtensionCount)); |
3139 | // In case fewer items were returned than requested, resize deviceExtensionProps to the |
3140 | // number of extensions returned (i.e. deviceLayerExtensionCount). |
3141 | deviceExtensionProps.resize(sz: previousExtensionCount + deviceLayerExtensionCount); |
3142 | } |
3143 | |
3144 | // Get the list of device extensions that are available. |
3145 | vk::ExtensionNameList deviceExtensionNames; |
3146 | if (!deviceExtensionProps.empty()) |
3147 | { |
3148 | ASSERT(deviceExtensionNames.size() <= deviceExtensionProps.size()); |
3149 | for (const VkExtensionProperties &prop : deviceExtensionProps) |
3150 | { |
3151 | deviceExtensionNames.push_back(value: prop.extensionName); |
3152 | } |
3153 | std::sort(first: deviceExtensionNames.begin(), last: deviceExtensionNames.end(), comp: StrLess); |
3154 | } |
3155 | |
3156 | if (displayVk->isUsingSwapchain()) |
3157 | { |
3158 | mEnabledDeviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); |
3159 | } |
3160 | |
3161 | // Query extensions and their features. |
3162 | queryDeviceExtensionFeatures(deviceExtensionNames); |
3163 | |
3164 | // Initialize features and workarounds. |
3165 | initFeatures(display: displayVk, extensions: deviceExtensionNames); |
3166 | |
3167 | // App based feature overrides. |
3168 | appBasedFeatureOverrides(display: displayVk, extensions: deviceExtensionNames); |
3169 | |
3170 | // Enable extensions that could be used |
3171 | enableDeviceExtensionsNotPromoted(deviceExtensionNames); |
3172 | enableDeviceExtensionsPromotedTo11(deviceExtensionNames); |
3173 | enableDeviceExtensionsPromotedTo12(deviceExtensionNames); |
3174 | enableDeviceExtensionsPromotedTo13(deviceExtensionNames); |
3175 | |
3176 | std::sort(first: mEnabledDeviceExtensions.begin(), last: mEnabledDeviceExtensions.end(), comp: StrLess); |
3177 | ANGLE_VK_TRY(displayVk, |
3178 | VerifyExtensionsPresent(deviceExtensionNames, mEnabledDeviceExtensions)); |
3179 | |
3180 | return angle::Result::Continue; |
3181 | } |
3182 | |
3183 | void RendererVk::initInstanceExtensionEntryPoints() |
3184 | { |
3185 | #if !defined(ANGLE_SHARED_LIBVULKAN) |
3186 | // Instance entry points |
3187 | if (mFeatures.supportsExternalSemaphoreFd.enabled || |
3188 | mFeatures.supportsExternalSemaphoreFuchsia.enabled) |
3189 | { |
3190 | InitExternalSemaphoreFdFunctions(mInstance); |
3191 | } |
3192 | |
3193 | if (mFeatures.supportsExternalFenceFd.enabled) |
3194 | { |
3195 | InitExternalFenceFdFunctions(mInstance); |
3196 | } |
3197 | |
3198 | # if defined(ANGLE_PLATFORM_ANDROID) |
3199 | if (mFeatures.supportsAndroidHardwareBuffer.enabled) |
3200 | { |
3201 | InitExternalMemoryHardwareBufferANDROIDFunctions(mInstance); |
3202 | } |
3203 | # endif |
3204 | |
3205 | if (!isVulkan11Instance()) |
3206 | { |
3207 | if (mFeatures.supportsExternalFenceCapabilities.enabled) |
3208 | { |
3209 | InitExternalFenceCapabilitiesFunctions(mInstance); |
3210 | } |
3211 | if (mFeatures.supportsExternalSemaphoreCapabilities.enabled) |
3212 | { |
3213 | InitExternalSemaphoreCapabilitiesFunctions(mInstance); |
3214 | } |
3215 | } |
3216 | #endif |
3217 | |
3218 | // For promoted extensions, initialize their entry points from the core version. |
3219 | initializeInstanceExtensionEntryPointsFromCore(); |
3220 | } |
3221 | |
3222 | void RendererVk::initDeviceExtensionEntryPoints() |
3223 | { |
3224 | #if !defined(ANGLE_SHARED_LIBVULKAN) |
3225 | // Device entry points |
3226 | if (mFeatures.supportsTransformFeedbackExtension.enabled) |
3227 | { |
3228 | InitTransformFeedbackEXTFunctions(mDevice); |
3229 | } |
3230 | if (useLogicOpDynamicState()) |
3231 | { |
3232 | // VK_EXT_extended_dynamic_state2 is only partially core in Vulkan 1.3. If the logicOp |
3233 | // dynamic state (only from the extension) is used, need to load the entry points from the |
3234 | // extension |
3235 | InitExtendedDynamicState2EXTFunctions(mDevice); |
3236 | } |
3237 | if (mFeatures.supportsFragmentShadingRate.enabled) |
3238 | { |
3239 | InitFragmentShadingRateKHRDeviceFunction(mDevice); |
3240 | } |
3241 | if (mFeatures.supportsTimestampSurfaceAttribute.enabled) |
3242 | { |
3243 | InitGetPastPresentationTimingGoogleFunction(mDevice); |
3244 | } |
3245 | if (!isVulkan11Device()) |
3246 | { |
3247 | if (mFeatures.supportsGetMemoryRequirements2.enabled) |
3248 | { |
3249 | InitGetMemoryRequirements2KHRFunctions(mDevice); |
3250 | } |
3251 | if (mFeatures.supportsBindMemory2.enabled) |
3252 | { |
3253 | InitBindMemory2KHRFunctions(mDevice); |
3254 | } |
3255 | if (mFeatures.supportsYUVSamplerConversion.enabled) |
3256 | { |
3257 | InitSamplerYcbcrKHRFunctions(mDevice); |
3258 | } |
3259 | } |
3260 | // Extensions promoted to Vulkan 1.2 |
3261 | { |
3262 | if (mFeatures.supportsHostQueryReset.enabled) |
3263 | { |
3264 | InitHostQueryResetFunctions(mDevice); |
3265 | } |
3266 | if (mFeatures.supportsRenderpass2.enabled) |
3267 | { |
3268 | InitRenderPass2KHRFunctions(mDevice); |
3269 | } |
3270 | } |
3271 | // Extensions promoted to Vulkan 1.3 |
3272 | { |
3273 | if (mFeatures.supportsExtendedDynamicState.enabled) |
3274 | { |
3275 | InitExtendedDynamicStateEXTFunctions(mDevice); |
3276 | } |
3277 | if (mFeatures.supportsExtendedDynamicState2.enabled) |
3278 | { |
3279 | InitExtendedDynamicState2EXTFunctions(mDevice); |
3280 | } |
3281 | } |
3282 | #endif // !defined(ANGLE_SHARED_LIBVULKAN) |
3283 | |
3284 | // For promoted extensions, initialize their entry points from the core version. |
3285 | initializeDeviceExtensionEntryPointsFromCore(); |
3286 | } |
3287 | |
3288 | angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueFamilyIndex) |
3289 | { |
3290 | uint32_t deviceLayerCount = 0; |
3291 | ANGLE_VK_TRY(displayVk, |
3292 | vkEnumerateDeviceLayerProperties(mPhysicalDevice, &deviceLayerCount, nullptr)); |
3293 | |
3294 | std::vector<VkLayerProperties> deviceLayerProps(deviceLayerCount); |
3295 | ANGLE_VK_TRY(displayVk, vkEnumerateDeviceLayerProperties(mPhysicalDevice, &deviceLayerCount, |
3296 | deviceLayerProps.data())); |
3297 | |
3298 | VulkanLayerVector enabledDeviceLayerNames; |
3299 | if (mEnableValidationLayers) |
3300 | { |
3301 | mEnableValidationLayers = |
3302 | GetAvailableValidationLayers(layerProps: deviceLayerProps, mustHaveLayers: false, enabledLayerNames: &enabledDeviceLayerNames); |
3303 | } |
3304 | |
3305 | const char *wsiLayer = displayVk->getWSILayer(); |
3306 | if (wsiLayer) |
3307 | { |
3308 | enabledDeviceLayerNames.push_back(value: wsiLayer); |
3309 | } |
3310 | |
3311 | mEnabledFeatures = {}; |
3312 | mEnabledFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; |
3313 | |
3314 | ANGLE_TRY(enableDeviceExtensions(displayVk, enabledDeviceLayerNames)); |
3315 | |
3316 | // Used to support cubemap array: |
3317 | mEnabledFeatures.features.imageCubeArray = mFeatures.supportsImageCubeArray.enabled; |
3318 | // Used to support framebuffers with multiple attachments: |
3319 | mEnabledFeatures.features.independentBlend = mPhysicalDeviceFeatures.independentBlend; |
3320 | // Used to support multi_draw_indirect |
3321 | mEnabledFeatures.features.multiDrawIndirect = mPhysicalDeviceFeatures.multiDrawIndirect; |
3322 | mEnabledFeatures.features.drawIndirectFirstInstance = |
3323 | mPhysicalDeviceFeatures.drawIndirectFirstInstance; |
3324 | // Used to support robust buffer access, if VK_EXT_pipeline_robustness is not supported. |
3325 | if (!mFeatures.supportsPipelineRobustness.enabled) |
3326 | { |
3327 | mEnabledFeatures.features.robustBufferAccess = mPhysicalDeviceFeatures.robustBufferAccess; |
3328 | } |
3329 | // Used to support Anisotropic filtering: |
3330 | mEnabledFeatures.features.samplerAnisotropy = mPhysicalDeviceFeatures.samplerAnisotropy; |
3331 | // Used to support wide lines: |
3332 | mEnabledFeatures.features.wideLines = mPhysicalDeviceFeatures.wideLines; |
3333 | // Used to emulate transform feedback: |
3334 | mEnabledFeatures.features.vertexPipelineStoresAndAtomics = |
3335 | mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics; |
3336 | // Used to implement storage buffers and images in the fragment shader: |
3337 | mEnabledFeatures.features.fragmentStoresAndAtomics = |
3338 | mPhysicalDeviceFeatures.fragmentStoresAndAtomics; |
3339 | // Used to emulate the primitives generated query: |
3340 | mEnabledFeatures.features.pipelineStatisticsQuery = |
3341 | !mFeatures.supportsPrimitivesGeneratedQuery.enabled && |
3342 | mFeatures.supportsPipelineStatisticsQuery.enabled; |
3343 | // Used to support geometry shaders: |
3344 | mEnabledFeatures.features.geometryShader = mPhysicalDeviceFeatures.geometryShader; |
3345 | // Used to support EXT_gpu_shader5: |
3346 | mEnabledFeatures.features.shaderImageGatherExtended = |
3347 | mPhysicalDeviceFeatures.shaderImageGatherExtended; |
3348 | // Used to support EXT_gpu_shader5: |
3349 | mEnabledFeatures.features.shaderUniformBufferArrayDynamicIndexing = |
3350 | mPhysicalDeviceFeatures.shaderUniformBufferArrayDynamicIndexing; |
3351 | mEnabledFeatures.features.shaderSampledImageArrayDynamicIndexing = |
3352 | mPhysicalDeviceFeatures.shaderSampledImageArrayDynamicIndexing; |
3353 | // Used to support APPLE_clip_distance |
3354 | mEnabledFeatures.features.shaderClipDistance = mPhysicalDeviceFeatures.shaderClipDistance; |
3355 | // Used to support OES_sample_shading |
3356 | mEnabledFeatures.features.sampleRateShading = mPhysicalDeviceFeatures.sampleRateShading; |
3357 | // Used to support EXT_depth_clamp and depth clears through draw calls |
3358 | mEnabledFeatures.features.depthClamp = mPhysicalDeviceFeatures.depthClamp; |
3359 | // Used to support EXT_polygon_offset_clamp |
3360 | mEnabledFeatures.features.depthBiasClamp = mPhysicalDeviceFeatures.depthBiasClamp; |
3361 | // Used to support NV_polygon_mode / ANGLE_polygon_mode |
3362 | mEnabledFeatures.features.fillModeNonSolid = mPhysicalDeviceFeatures.fillModeNonSolid; |
3363 | // Used to support EXT_clip_cull_distance |
3364 | mEnabledFeatures.features.shaderCullDistance = mPhysicalDeviceFeatures.shaderCullDistance; |
3365 | // Used to support tessellation Shader: |
3366 | mEnabledFeatures.features.tessellationShader = mPhysicalDeviceFeatures.tessellationShader; |
3367 | // Used to support EXT_blend_func_extended |
3368 | mEnabledFeatures.features.dualSrcBlend = mPhysicalDeviceFeatures.dualSrcBlend; |
3369 | // Used to support ANGLE_logic_op and GLES1 |
3370 | mEnabledFeatures.features.logicOp = mPhysicalDeviceFeatures.logicOp; |
3371 | // Used to support EXT_multisample_compatibility |
3372 | mEnabledFeatures.features.alphaToOne = mPhysicalDeviceFeatures.alphaToOne; |
3373 | |
3374 | if (!vk::OutsideRenderPassCommandBuffer::ExecutesInline() || |
3375 | !vk::RenderPassCommandBuffer::ExecutesInline()) |
3376 | { |
3377 | mEnabledFeatures.features.inheritedQueries = mPhysicalDeviceFeatures.inheritedQueries; |
3378 | } |
3379 | |
3380 | // Setup device initialization struct |
3381 | VkDeviceCreateInfo createInfo = {}; |
3382 | |
3383 | if (mFeatures.logMemoryReportCallbacks.enabled || mFeatures.logMemoryReportStats.enabled) |
3384 | { |
3385 | ASSERT(mMemoryReportFeatures.deviceMemoryReport); |
3386 | |
3387 | mMemoryReportCallback = {}; |
3388 | mMemoryReportCallback.sType = VK_STRUCTURE_TYPE_DEVICE_DEVICE_MEMORY_REPORT_CREATE_INFO_EXT; |
3389 | mMemoryReportCallback.pfnUserCallback = &MemoryReportCallback; |
3390 | mMemoryReportCallback.pUserData = this; |
3391 | vk::AddToPNextChain(chainStart: &createInfo, ptr: &mMemoryReportCallback); |
3392 | } |
3393 | |
3394 | mCurrentQueueFamilyIndex = queueFamilyIndex; |
3395 | |
3396 | vk::QueueFamily queueFamily; |
3397 | queueFamily.initialize(queueFamilyProperties: mQueueFamilyProperties[queueFamilyIndex], index: queueFamilyIndex); |
3398 | ANGLE_VK_CHECK(displayVk, queueFamily.getDeviceQueueCount() > 0, |
3399 | VK_ERROR_INITIALIZATION_FAILED); |
3400 | |
3401 | // We enable protected context only if both supportsProtectedMemory and device also supports |
3402 | // protected. There are cases we have to disable supportsProtectedMemory feature due to driver |
3403 | // bugs. |
3404 | bool enableProtectedContent = |
3405 | queueFamily.supportsProtected() && mFeatures.supportsProtectedMemory.enabled; |
3406 | |
3407 | uint32_t queueCount = std::min(a: queueFamily.getDeviceQueueCount(), |
3408 | b: static_cast<uint32_t>(egl::ContextPriority::EnumCount)); |
3409 | |
3410 | uint32_t queueCreateInfoCount = 1; |
3411 | VkDeviceQueueCreateInfo queueCreateInfo[1] = {}; |
3412 | queueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; |
3413 | queueCreateInfo[0].flags = enableProtectedContent ? VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT : 0; |
3414 | queueCreateInfo[0].queueFamilyIndex = queueFamilyIndex; |
3415 | queueCreateInfo[0].queueCount = queueCount; |
3416 | queueCreateInfo[0].pQueuePriorities = vk::QueueFamily::kQueuePriorities; |
3417 | |
3418 | // Create Device |
3419 | createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; |
3420 | createInfo.flags = 0; |
3421 | createInfo.queueCreateInfoCount = queueCreateInfoCount; |
3422 | createInfo.pQueueCreateInfos = queueCreateInfo; |
3423 | createInfo.enabledLayerCount = static_cast<uint32_t>(enabledDeviceLayerNames.size()); |
3424 | createInfo.ppEnabledLayerNames = enabledDeviceLayerNames.data(); |
3425 | createInfo.enabledExtensionCount = static_cast<uint32_t>(mEnabledDeviceExtensions.size()); |
3426 | createInfo.ppEnabledExtensionNames = |
3427 | mEnabledDeviceExtensions.empty() ? nullptr : mEnabledDeviceExtensions.data(); |
3428 | mEnabledDeviceExtensions.push_back(value: nullptr); |
3429 | |
3430 | // Enable core features without assuming VkPhysicalDeviceFeatures2KHR is accepted in the |
3431 | // pNext chain of VkDeviceCreateInfo. |
3432 | createInfo.pEnabledFeatures = &mEnabledFeatures.features; |
3433 | |
3434 | // Append the feature structs chain to the end of createInfo structs chain. |
3435 | if (mEnabledFeatures.pNext) |
3436 | { |
3437 | vk::AppendToPNextChain(chainStart: &createInfo, ptr: mEnabledFeatures.pNext); |
3438 | } |
3439 | |
3440 | // Create the list of expected VVL messages to suppress. Done before creating the device, as it |
3441 | // may also generate messages. |
3442 | initializeValidationMessageSuppressions(); |
3443 | |
3444 | ANGLE_VK_TRY(displayVk, vkCreateDevice(mPhysicalDevice, &createInfo, nullptr, &mDevice)); |
3445 | #if defined(ANGLE_SHARED_LIBVULKAN) |
3446 | // Load volk if we are loading dynamically |
3447 | volkLoadDevice(device: mDevice); |
3448 | #endif // defined(ANGLE_SHARED_LIBVULKAN) |
3449 | |
3450 | initDeviceExtensionEntryPoints(); |
3451 | |
3452 | vk::DeviceQueueMap graphicsQueueMap = |
3453 | queueFamily.initializeQueueMap(device: mDevice, makeProtected: enableProtectedContent, queueIndex: 0, queueCount); |
3454 | |
3455 | ANGLE_TRY(mCommandQueue.init(displayVk, graphicsQueueMap)); |
3456 | ANGLE_TRY(mCommandProcessor.init()); |
3457 | |
3458 | if (mFeatures.forceMaxUniformBufferSize16KB.enabled) |
3459 | { |
3460 | mDefaultUniformBufferSize = kMinDefaultUniformBufferSize; |
3461 | } |
3462 | // Cap it with the driver limit |
3463 | mDefaultUniformBufferSize = std::min( |
3464 | a: mDefaultUniformBufferSize, b: getPhysicalDeviceProperties().limits.maxUniformBufferRange); |
3465 | |
3466 | // Initialize the vulkan pipeline cache. |
3467 | { |
3468 | std::unique_lock<std::mutex> lock(mPipelineCacheMutex); |
3469 | bool loadedFromBlobCache = false; |
3470 | ANGLE_TRY(initPipelineCache(displayVk, &mPipelineCache, &loadedFromBlobCache)); |
3471 | if (loadedFromBlobCache) |
3472 | { |
3473 | ANGLE_TRY(getPipelineCacheSize(displayVk, &mPipelineCacheSizeAtLastSync)); |
3474 | } |
3475 | } |
3476 | |
3477 | // Track the set of supported pipeline stages. This is used when issuing image layout |
3478 | // transitions that cover many stages (such as AllGraphicsReadOnly) to mask out unsupported |
3479 | // stages, which avoids enumerating every possible combination of stages in the layouts. |
3480 | VkPipelineStageFlags unsupportedStages = 0; |
3481 | mSupportedVulkanShaderStageMask = |
3482 | VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT | VK_SHADER_STAGE_COMPUTE_BIT; |
3483 | if (!mPhysicalDeviceFeatures.tessellationShader) |
3484 | { |
3485 | unsupportedStages |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT | |
3486 | VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT; |
3487 | } |
3488 | else |
3489 | { |
3490 | mSupportedVulkanShaderStageMask |= |
3491 | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; |
3492 | } |
3493 | if (!mPhysicalDeviceFeatures.geometryShader) |
3494 | { |
3495 | unsupportedStages |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT; |
3496 | } |
3497 | else |
3498 | { |
3499 | mSupportedVulkanShaderStageMask |= VK_SHADER_STAGE_GEOMETRY_BIT; |
3500 | } |
3501 | mSupportedVulkanPipelineStageMask = ~unsupportedStages; |
3502 | |
3503 | // Log the memory heap stats when the device has been initialized (when debugging). |
3504 | mMemoryAllocationTracker.onDeviceInit(); |
3505 | |
3506 | return angle::Result::Continue; |
3507 | } |
3508 | |
3509 | void RendererVk::initializeValidationMessageSuppressions() |
3510 | { |
3511 | // Build the list of validation errors that are currently expected and should be skipped. |
3512 | mSkippedValidationMessages.insert(position: mSkippedValidationMessages.end(), first: kSkippedMessages, |
3513 | last: kSkippedMessages + ArraySize(kSkippedMessages)); |
3514 | if (!getFeatures().supportsPrimitiveTopologyListRestart.enabled) |
3515 | { |
3516 | mSkippedValidationMessages.insert( |
3517 | position: mSkippedValidationMessages.end(), first: kNoListRestartSkippedMessages, |
3518 | last: kNoListRestartSkippedMessages + ArraySize(kNoListRestartSkippedMessages)); |
3519 | } |
3520 | |
3521 | // Build the list of syncval errors that are currently expected and should be skipped. |
3522 | mSkippedSyncvalMessages.insert(position: mSkippedSyncvalMessages.end(), first: kSkippedSyncvalMessages, |
3523 | last: kSkippedSyncvalMessages + ArraySize(kSkippedSyncvalMessages)); |
3524 | if (!getFeatures().supportsRenderPassStoreOpNone.enabled && |
3525 | !getFeatures().supportsRenderPassLoadStoreOpNone.enabled) |
3526 | { |
3527 | mSkippedSyncvalMessages.insert(position: mSkippedSyncvalMessages.end(), |
3528 | first: kSkippedSyncvalMessagesWithoutStoreOpNone, |
3529 | last: kSkippedSyncvalMessagesWithoutStoreOpNone + |
3530 | ArraySize(kSkippedSyncvalMessagesWithoutStoreOpNone)); |
3531 | } |
3532 | if (!getFeatures().supportsRenderPassLoadStoreOpNone.enabled) |
3533 | { |
3534 | mSkippedSyncvalMessages.insert( |
3535 | position: mSkippedSyncvalMessages.end(), first: kSkippedSyncvalMessagesWithoutLoadStoreOpNone, |
3536 | last: kSkippedSyncvalMessagesWithoutLoadStoreOpNone + |
3537 | ArraySize(kSkippedSyncvalMessagesWithoutLoadStoreOpNone)); |
3538 | } |
3539 | } |
3540 | |
3541 | angle::Result RendererVk::selectPresentQueueForSurface(DisplayVk *displayVk, |
3542 | VkSurfaceKHR surface, |
3543 | uint32_t *presentQueueOut) |
3544 | { |
3545 | // We've already initialized a device, and can't re-create it unless it's never been used. |
3546 | // TODO(jmadill): Handle the re-creation case if necessary. |
3547 | if (mDevice != VK_NULL_HANDLE) |
3548 | { |
3549 | ASSERT(mCurrentQueueFamilyIndex != std::numeric_limits<uint32_t>::max()); |
3550 | |
3551 | // Check if the current device supports present on this surface. |
3552 | VkBool32 supportsPresent = VK_FALSE; |
3553 | ANGLE_VK_TRY(displayVk, |
3554 | vkGetPhysicalDeviceSurfaceSupportKHR(mPhysicalDevice, mCurrentQueueFamilyIndex, |
3555 | surface, &supportsPresent)); |
3556 | |
3557 | if (supportsPresent == VK_TRUE) |
3558 | { |
3559 | *presentQueueOut = mCurrentQueueFamilyIndex; |
3560 | return angle::Result::Continue; |
3561 | } |
3562 | } |
3563 | |
3564 | // Find a graphics and present queue. |
3565 | Optional<uint32_t> newPresentQueue; |
3566 | uint32_t queueCount = static_cast<uint32_t>(mQueueFamilyProperties.size()); |
3567 | constexpr VkQueueFlags kGraphicsAndCompute = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT; |
3568 | for (uint32_t queueIndex = 0; queueIndex < queueCount; ++queueIndex) |
3569 | { |
3570 | const auto &queueInfo = mQueueFamilyProperties[queueIndex]; |
3571 | if ((queueInfo.queueFlags & kGraphicsAndCompute) == kGraphicsAndCompute) |
3572 | { |
3573 | VkBool32 supportsPresent = VK_FALSE; |
3574 | ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfaceSupportKHR( |
3575 | mPhysicalDevice, queueIndex, surface, &supportsPresent)); |
3576 | |
3577 | if (supportsPresent == VK_TRUE) |
3578 | { |
3579 | newPresentQueue = queueIndex; |
3580 | break; |
3581 | } |
3582 | } |
3583 | } |
3584 | |
3585 | ANGLE_VK_CHECK(displayVk, newPresentQueue.valid(), VK_ERROR_INITIALIZATION_FAILED); |
3586 | ANGLE_TRY(initializeDevice(displayVk, newPresentQueue.value())); |
3587 | |
3588 | *presentQueueOut = newPresentQueue.value(); |
3589 | return angle::Result::Continue; |
3590 | } |
3591 | |
3592 | std::string RendererVk::getVendorString() const |
3593 | { |
3594 | return GetVendorString(vendorId: mPhysicalDeviceProperties.vendorID); |
3595 | } |
3596 | |
3597 | std::string RendererVk::getRendererDescription() const |
3598 | { |
3599 | std::stringstream strstr; |
3600 | |
3601 | uint32_t apiVersion = mPhysicalDeviceProperties.apiVersion; |
3602 | |
3603 | strstr << "Vulkan " ; |
3604 | strstr << VK_VERSION_MAJOR(apiVersion) << "." ; |
3605 | strstr << VK_VERSION_MINOR(apiVersion) << "." ; |
3606 | strstr << VK_VERSION_PATCH(apiVersion); |
3607 | |
3608 | strstr << " (" ; |
3609 | |
3610 | // In the case of NVIDIA, deviceName does not necessarily contain "NVIDIA". Add "NVIDIA" so that |
3611 | // Vulkan end2end tests can be selectively disabled on NVIDIA. TODO(jmadill): should not be |
3612 | // needed after http://anglebug.com/1874 is fixed and end2end_tests use more sophisticated |
3613 | // driver detection. |
3614 | if (mPhysicalDeviceProperties.vendorID == VENDOR_ID_NVIDIA) |
3615 | { |
3616 | strstr << GetVendorString(vendorId: mPhysicalDeviceProperties.vendorID) << " " ; |
3617 | } |
3618 | |
3619 | strstr << mPhysicalDeviceProperties.deviceName; |
3620 | strstr << " (" << gl::FmtHex(value: mPhysicalDeviceProperties.deviceID) << ")" ; |
3621 | |
3622 | strstr << ")" ; |
3623 | |
3624 | return strstr.str(); |
3625 | } |
3626 | |
3627 | std::string RendererVk::getVersionString(bool includeFullVersion) const |
3628 | { |
3629 | std::stringstream strstr; |
3630 | |
3631 | uint32_t driverVersion = mPhysicalDeviceProperties.driverVersion; |
3632 | std::string driverName = std::string(mDriverProperties.driverName); |
3633 | |
3634 | if (!driverName.empty()) |
3635 | { |
3636 | strstr << driverName; |
3637 | } |
3638 | else |
3639 | { |
3640 | strstr << GetVendorString(vendorId: mPhysicalDeviceProperties.vendorID); |
3641 | } |
3642 | |
3643 | if (includeFullVersion) |
3644 | { |
3645 | strstr << "-" ; |
3646 | |
3647 | if (mPhysicalDeviceProperties.vendorID == VENDOR_ID_NVIDIA) |
3648 | { |
3649 | strstr << ANGLE_VK_VERSION_MAJOR_NVIDIA(driverVersion) << "." ; |
3650 | strstr << ANGLE_VK_VERSION_MINOR_NVIDIA(driverVersion) << "." ; |
3651 | strstr << ANGLE_VK_VERSION_SUB_MINOR_NVIDIA(driverVersion) << "." ; |
3652 | strstr << ANGLE_VK_VERSION_PATCH_NVIDIA(driverVersion); |
3653 | } |
3654 | else if (mPhysicalDeviceProperties.vendorID == VENDOR_ID_INTEL && IsWindows()) |
3655 | { |
3656 | strstr << ANGLE_VK_VERSION_MAJOR_WIN_INTEL(driverVersion) << "." ; |
3657 | strstr << ANGLE_VK_VERSION_MAJOR_WIN_INTEL(driverVersion) << "." ; |
3658 | } |
3659 | // All other drivers use the Vulkan standard |
3660 | else |
3661 | { |
3662 | strstr << VK_VERSION_MAJOR(driverVersion) << "." ; |
3663 | strstr << VK_VERSION_MINOR(driverVersion) << "." ; |
3664 | strstr << VK_VERSION_PATCH(driverVersion); |
3665 | } |
3666 | } |
3667 | |
3668 | return strstr.str(); |
3669 | } |
3670 | |
3671 | gl::Version RendererVk::getMaxSupportedESVersion() const |
3672 | { |
3673 | // Current highest supported version |
3674 | gl::Version maxVersion = gl::Version(3, 2); |
3675 | |
3676 | // Early out without downgrading ES version if mock ICD enabled. |
3677 | // Mock ICD doesn't expose sufficient capabilities yet. |
3678 | // https://github.com/KhronosGroup/Vulkan-Tools/issues/84 |
3679 | if (isMockICDEnabled()) |
3680 | { |
3681 | return maxVersion; |
3682 | } |
3683 | |
3684 | // Limit to ES3.1 if there are any blockers for 3.2. |
3685 | if (!vk::CanSupportGPUShader5EXT(features: mPhysicalDeviceFeatures) && |
3686 | !mFeatures.exposeNonConformantExtensionsAndVersions.enabled) |
3687 | { |
3688 | maxVersion = LimitVersionTo(current: maxVersion, lower: {3, 1}); |
3689 | } |
3690 | |
3691 | // TODO: more extension checks for 3.2. http://anglebug.com/5366 |
3692 | if (!mFeatures.exposeNonConformantExtensionsAndVersions.enabled) |
3693 | { |
3694 | maxVersion = LimitVersionTo(current: maxVersion, lower: {3, 1}); |
3695 | } |
3696 | |
3697 | // Limit to ES3.0 if there are any blockers for 3.1. |
3698 | |
3699 | // ES3.1 requires at least one atomic counter buffer and four storage buffers in compute. |
3700 | // Atomic counter buffers are emulated with storage buffers. For simplicity, we always support |
3701 | // either none or IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFERS atomic counter buffers. So if |
3702 | // Vulkan doesn't support at least that many storage buffers in compute, we don't support 3.1. |
3703 | const uint32_t kMinimumStorageBuffersForES31 = |
3704 | gl::limits::kMinimumComputeStorageBuffers + |
3705 | gl::IMPLEMENTATION_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS; |
3706 | if (mPhysicalDeviceProperties.limits.maxPerStageDescriptorStorageBuffers < |
3707 | kMinimumStorageBuffersForES31) |
3708 | { |
3709 | maxVersion = LimitVersionTo(current: maxVersion, lower: {3, 0}); |
3710 | } |
3711 | |
3712 | // ES3.1 requires at least a maximum offset of at least 2047. |
3713 | // If the Vulkan implementation can't support that, we cannot support 3.1. |
3714 | if (mPhysicalDeviceProperties.limits.maxVertexInputAttributeOffset < 2047) |
3715 | { |
3716 | maxVersion = LimitVersionTo(current: maxVersion, lower: {3, 0}); |
3717 | } |
3718 | |
3719 | // Limit to ES2.0 if there are any blockers for 3.0. |
3720 | // TODO: http://anglebug.com/3972 Limit to GLES 2.0 if flat shading can't be emulated |
3721 | |
3722 | // Multisample textures (ES3.1) and multisample renderbuffers (ES3.0) require the Vulkan driver |
3723 | // to support the standard sample locations (in order to pass dEQP tests that check these |
3724 | // locations). If the Vulkan implementation can't support that, we cannot support 3.0/3.1. |
3725 | if (mPhysicalDeviceProperties.limits.standardSampleLocations != VK_TRUE) |
3726 | { |
3727 | maxVersion = LimitVersionTo(current: maxVersion, lower: {2, 0}); |
3728 | } |
3729 | |
3730 | // If independentBlend is not supported, we can't have a mix of has-alpha and emulated-alpha |
3731 | // render targets in a framebuffer. We also cannot perform masked clears of multiple render |
3732 | // targets. |
3733 | if (!mPhysicalDeviceFeatures.independentBlend) |
3734 | { |
3735 | maxVersion = LimitVersionTo(current: maxVersion, lower: {2, 0}); |
3736 | } |
3737 | |
3738 | // If the Vulkan transform feedback extension is not present, we use an emulation path that |
3739 | // requires the vertexPipelineStoresAndAtomics feature. Without the extension or this feature, |
3740 | // we can't currently support transform feedback. |
3741 | if (!mFeatures.supportsTransformFeedbackExtension.enabled && |
3742 | !mFeatures.emulateTransformFeedback.enabled) |
3743 | { |
3744 | maxVersion = LimitVersionTo(current: maxVersion, lower: {2, 0}); |
3745 | } |
3746 | |
3747 | // Limit to GLES 2.0 if maxPerStageDescriptorUniformBuffers is too low. |
3748 | // Table 6.31 MAX_VERTEX_UNIFORM_BLOCKS minimum value = 12 |
3749 | // Table 6.32 MAX_FRAGMENT_UNIFORM_BLOCKS minimum value = 12 |
3750 | // NOTE: We reserve some uniform buffers for emulation, so use the NativeCaps which takes this |
3751 | // into account, rather than the physical device maxPerStageDescriptorUniformBuffers limits. |
3752 | for (gl::ShaderType shaderType : gl::AllShaderTypes()) |
3753 | { |
3754 | if (static_cast<GLuint>(getNativeCaps().maxShaderUniformBlocks[shaderType]) < |
3755 | gl::limits::kMinimumShaderUniformBlocks) |
3756 | { |
3757 | maxVersion = LimitVersionTo(current: maxVersion, lower: {2, 0}); |
3758 | } |
3759 | } |
3760 | |
3761 | // Limit to GLES 2.0 if maxVertexOutputComponents is too low. |
3762 | // Table 6.31 MAX VERTEX OUTPUT COMPONENTS minimum value = 64 |
3763 | // NOTE: We reserve some vertex output components for emulation, so use the NativeCaps which |
3764 | // takes this into account, rather than the physical device maxVertexOutputComponents limits. |
3765 | if (static_cast<GLuint>(getNativeCaps().maxVertexOutputComponents) < |
3766 | gl::limits::kMinimumVertexOutputComponents) |
3767 | { |
3768 | maxVersion = LimitVersionTo(current: maxVersion, lower: {2, 0}); |
3769 | } |
3770 | |
3771 | return maxVersion; |
3772 | } |
3773 | |
3774 | gl::Version RendererVk::getMaxConformantESVersion() const |
3775 | { |
3776 | const gl::Version maxSupportedESVersion = getMaxSupportedESVersion(); |
3777 | const bool hasGeometryAndTessSupport = |
3778 | getNativeExtensions().geometryShaderAny() && getNativeExtensions().tessellationShaderEXT; |
3779 | |
3780 | if (!hasGeometryAndTessSupport || !mFeatures.exposeNonConformantExtensionsAndVersions.enabled) |
3781 | { |
3782 | return LimitVersionTo(current: maxSupportedESVersion, lower: {3, 1}); |
3783 | } |
3784 | |
3785 | return maxSupportedESVersion; |
3786 | } |
3787 | |
3788 | uint32_t RendererVk::getDeviceVersion() |
3789 | { |
3790 | return mDeviceVersion == 0 ? mInstanceVersion : mDeviceVersion; |
3791 | } |
3792 | |
3793 | bool RendererVk::canSupportFragmentShadingRate(const vk::ExtensionNameList &deviceExtensionNames) |
3794 | { |
3795 | // Device needs to support VK_KHR_fragment_shading_rate and specifically |
3796 | // pipeline fragment shading rate. |
3797 | if (mFragmentShadingRateFeatures.pipelineFragmentShadingRate != VK_TRUE) |
3798 | { |
3799 | return false; |
3800 | } |
3801 | |
3802 | // Init required functions |
3803 | #if !defined(ANGLE_SHARED_LIBVULKAN) |
3804 | InitFragmentShadingRateKHRInstanceFunction(mInstance); |
3805 | #endif // !defined(ANGLE_SHARED_LIBVULKAN) |
3806 | ASSERT(vkGetPhysicalDeviceFragmentShadingRatesKHR); |
3807 | |
3808 | // Query number of supported shading rates first |
3809 | uint32_t shadingRatesCount = 0; |
3810 | VkResult result = |
3811 | vkGetPhysicalDeviceFragmentShadingRatesKHR(mPhysicalDevice, &shadingRatesCount, nullptr); |
3812 | ASSERT(result == VK_SUCCESS); |
3813 | ASSERT(shadingRatesCount > 0); |
3814 | |
3815 | std::vector<VkPhysicalDeviceFragmentShadingRateKHR> shadingRates( |
3816 | shadingRatesCount, |
3817 | {.sType: VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_SHADING_RATE_KHR, .pNext: nullptr, .sampleCounts: 0, .fragmentSize: {.width: 0, .height: 0}}); |
3818 | |
3819 | // Query supported shading rates |
3820 | result = vkGetPhysicalDeviceFragmentShadingRatesKHR(mPhysicalDevice, &shadingRatesCount, |
3821 | shadingRates.data()); |
3822 | ASSERT(result == VK_SUCCESS); |
3823 | |
3824 | // Cache supported fragment shading rates |
3825 | mSupportedFragmentShadingRates.reset(); |
3826 | for (const VkPhysicalDeviceFragmentShadingRateKHR &shadingRate : shadingRates) |
3827 | { |
3828 | if (shadingRate.sampleCounts == 0) |
3829 | { |
3830 | continue; |
3831 | } |
3832 | mSupportedFragmentShadingRates.set(pos: GetShadingRateFromVkExtent(extent: shadingRate.fragmentSize)); |
3833 | } |
3834 | |
3835 | // To implement GL_QCOM_shading_rate extension the Vulkan ICD needs to support at least the |
3836 | // following shading rates - |
3837 | // {1, 1} |
3838 | // {1, 2} |
3839 | // {2, 1} |
3840 | // {2, 2} |
3841 | return mSupportedFragmentShadingRates.test(pos: gl::ShadingRate::_1x1) && |
3842 | mSupportedFragmentShadingRates.test(pos: gl::ShadingRate::_1x2) && |
3843 | mSupportedFragmentShadingRates.test(pos: gl::ShadingRate::_2x1) && |
3844 | mSupportedFragmentShadingRates.test(pos: gl::ShadingRate::_2x2); |
3845 | } |
3846 | |
3847 | bool RendererVk::canPreferDeviceLocalMemoryHostVisible(VkPhysicalDeviceType deviceType) |
3848 | { |
3849 | if (deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) |
3850 | { |
3851 | const vk::MemoryProperties &memoryProperties = getMemoryProperties(); |
3852 | static constexpr VkMemoryPropertyFlags kHostVisiableDeviceLocalFlags = |
3853 | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; |
3854 | VkDeviceSize minHostVisiableDeviceLocalHeapSize = std::numeric_limits<VkDeviceSize>::max(); |
3855 | VkDeviceSize maxDeviceLocalHeapSize = 0; |
3856 | for (uint32_t i = 0; i < memoryProperties.getMemoryTypeCount(); ++i) |
3857 | { |
3858 | if ((memoryProperties.getMemoryType(i).propertyFlags & |
3859 | VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) |
3860 | { |
3861 | maxDeviceLocalHeapSize = |
3862 | std::max(a: maxDeviceLocalHeapSize, b: memoryProperties.getHeapSizeForMemoryType(memoryType: i)); |
3863 | } |
3864 | if ((memoryProperties.getMemoryType(i).propertyFlags & kHostVisiableDeviceLocalFlags) == |
3865 | kHostVisiableDeviceLocalFlags) |
3866 | { |
3867 | minHostVisiableDeviceLocalHeapSize = |
3868 | std::min(a: minHostVisiableDeviceLocalHeapSize, |
3869 | b: memoryProperties.getHeapSizeForMemoryType(memoryType: i)); |
3870 | } |
3871 | } |
3872 | return minHostVisiableDeviceLocalHeapSize != std::numeric_limits<VkDeviceSize>::max() && |
3873 | minHostVisiableDeviceLocalHeapSize >= |
3874 | static_cast<VkDeviceSize>(maxDeviceLocalHeapSize * 0.8); |
3875 | } |
3876 | return deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU; |
3877 | } |
3878 | |
3879 | void RendererVk::initFeatures(DisplayVk *displayVk, |
3880 | const vk::ExtensionNameList &deviceExtensionNames) |
3881 | { |
3882 | if (displayVk->getState().featuresAllDisabled) |
3883 | { |
3884 | ApplyFeatureOverrides(features: &mFeatures, state: displayVk->getState()); |
3885 | return; |
3886 | } |
3887 | |
3888 | constexpr uint32_t kPixel2DriverWithRelaxedPrecision = 0x801EA000; |
3889 | constexpr uint32_t kPixel4DriverWithWorkingSpecConstSupport = 0x80201000; |
3890 | |
3891 | const bool isAMD = IsAMD(vendorId: mPhysicalDeviceProperties.vendorID); |
3892 | const bool isApple = IsAppleGPU(vendorId: mPhysicalDeviceProperties.vendorID); |
3893 | const bool isARM = IsARM(vendorId: mPhysicalDeviceProperties.vendorID); |
3894 | const bool isIntel = IsIntel(vendorId: mPhysicalDeviceProperties.vendorID); |
3895 | const bool isNvidia = IsNvidia(vendorId: mPhysicalDeviceProperties.vendorID); |
3896 | const bool isPowerVR = IsPowerVR(vendorId: mPhysicalDeviceProperties.vendorID); |
3897 | const bool isQualcomm = IsQualcomm(vendorId: mPhysicalDeviceProperties.vendorID); |
3898 | const bool isBroadcom = IsBroadcom(vendorId: mPhysicalDeviceProperties.vendorID); |
3899 | const bool isSamsung = IsSamsung(vendorId: mPhysicalDeviceProperties.vendorID); |
3900 | const bool isSwiftShader = |
3901 | IsSwiftshader(vendorId: mPhysicalDeviceProperties.vendorID, deviceId: mPhysicalDeviceProperties.deviceID); |
3902 | |
3903 | // MESA Virtio-GPU Venus driver: https://docs.mesa3d.org/drivers/venus.html |
3904 | const bool isVenus = IsVenus(driverId: mDriverProperties.driverID, deviceName: mPhysicalDeviceProperties.deviceName); |
3905 | |
3906 | const bool isGalaxyS23 = |
3907 | IsGalaxyS23(vendorId: mPhysicalDeviceProperties.vendorID, deviceId: mPhysicalDeviceProperties.deviceID); |
3908 | |
3909 | // Distinguish between the open source and proprietary Qualcomm drivers |
3910 | const bool isQualcommOpenSource = |
3911 | IsQualcommOpenSource(vendorId: mPhysicalDeviceProperties.vendorID, driverId: mDriverProperties.driverID, |
3912 | deviceName: mPhysicalDeviceProperties.deviceName); |
3913 | const bool isQualcommProprietary = isQualcomm && !isQualcommOpenSource; |
3914 | |
3915 | // Lacking other explicit ways to tell if mali GPU is job manager based or command stream front |
3916 | // end based, we use maxDrawIndirectCount as equivalent since all JM based has |
3917 | // maxDrawIndirectCount==1 and all CSF based has maxDrawIndirectCount>1. |
3918 | bool isMaliJobManagerBasedGPU = |
3919 | isARM && getPhysicalDeviceProperties().limits.maxDrawIndirectCount <= 1; |
3920 | // Parse the ARM driver version to be readable/comparable |
3921 | const ARMDriverVersion armDriverVersion = |
3922 | ParseARMDriverVersion(driverVersion: mPhysicalDeviceProperties.driverVersion); |
3923 | |
3924 | // Identify Google Pixel brand Android devices |
3925 | const bool isPixel = IsPixel(); |
3926 | |
3927 | angle::VersionInfo nvidiaVersion; |
3928 | if (isNvidia) |
3929 | { |
3930 | nvidiaVersion = angle::ParseNvidiaDriverVersion(version: mPhysicalDeviceProperties.driverVersion); |
3931 | } |
3932 | |
3933 | angle::VersionInfo mesaVersion; |
3934 | if (isIntel && IsLinux()) |
3935 | { |
3936 | mesaVersion = angle::ParseMesaDriverVersion(version: mPhysicalDeviceProperties.driverVersion); |
3937 | } |
3938 | |
3939 | // Classify devices based on general architecture: |
3940 | // |
3941 | // - IMR (Immediate-Mode Rendering) devices generally progress through draw calls once and use |
3942 | // the main GPU memory (accessed through caches) to store intermediate rendering results. |
3943 | // - TBR (Tile-Based Rendering) devices issue a pre-rendering geometry pass, then run through |
3944 | // draw calls once per tile and store intermediate rendering results on the tile cache. |
3945 | // |
3946 | // Due to these key architectural differences, some operations improve performance on one while |
3947 | // deteriorating performance on the other. ANGLE will accordingly make some decisions based on |
3948 | // the device architecture for optimal performance on both. |
3949 | const bool isImmediateModeRenderer = isNvidia || isAMD || isIntel || isSamsung || isSwiftShader; |
3950 | const bool isTileBasedRenderer = isARM || isPowerVR || isQualcomm || isBroadcom || isApple; |
3951 | |
3952 | // Make sure all known architectures are accounted for. |
3953 | if (!isImmediateModeRenderer && !isTileBasedRenderer && !isMockICDEnabled()) |
3954 | { |
3955 | WARN() << "Unknown GPU architecture" ; |
3956 | } |
3957 | |
3958 | bool supportsNegativeViewport = |
3959 | isVulkan11Device() || |
3960 | ExtensionFound(VK_KHR_MAINTENANCE1_EXTENSION_NAME, haystack: deviceExtensionNames); |
3961 | |
3962 | ANGLE_FEATURE_CONDITION(&mFeatures, appendAliasedMemoryDecorations, true); |
3963 | |
3964 | ANGLE_FEATURE_CONDITION( |
3965 | &mFeatures, supportsSharedPresentableImageExtension, |
3966 | ExtensionFound(VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME, deviceExtensionNames)); |
3967 | |
3968 | ANGLE_FEATURE_CONDITION( |
3969 | &mFeatures, supportsGetMemoryRequirements2, |
3970 | isVulkan11Device() || |
3971 | ExtensionFound(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME, deviceExtensionNames)); |
3972 | |
3973 | ANGLE_FEATURE_CONDITION( |
3974 | &mFeatures, supportsBindMemory2, |
3975 | isVulkan11Device() || |
3976 | ExtensionFound(VK_KHR_BIND_MEMORY_2_EXTENSION_NAME, deviceExtensionNames)); |
3977 | |
3978 | ANGLE_FEATURE_CONDITION(&mFeatures, bresenhamLineRasterization, |
3979 | mLineRasterizationFeatures.bresenhamLines == VK_TRUE); |
3980 | |
3981 | ANGLE_FEATURE_CONDITION(&mFeatures, provokingVertex, |
3982 | mProvokingVertexFeatures.provokingVertexLast == VK_TRUE); |
3983 | |
3984 | // http://b/208458772. ARM driver supports this protected memory extension but we are seeing |
3985 | // excessive load/store unit activity when this extension is enabled, even if not been used. |
3986 | // Disable this extension on older ARM platforms that don't support |
3987 | // VK_EXT_pipeline_protected_access. |
3988 | // http://anglebug.com/7714 |
3989 | ANGLE_FEATURE_CONDITION( |
3990 | &mFeatures, supportsProtectedMemory, |
3991 | mProtectedMemoryFeatures.protectedMemory == VK_TRUE && |
3992 | (!isARM || mPipelineProtectedAccessFeatures.pipelineProtectedAccess == VK_TRUE)); |
3993 | |
3994 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsHostQueryReset, |
3995 | mHostQueryResetFeatures.hostQueryReset == VK_TRUE); |
3996 | |
3997 | // VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL and |
3998 | // VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL are introduced by |
3999 | // VK_KHR_maintenance2 and promoted to Vulkan 1.1. For simplicity, this feature is only enabled |
4000 | // on Vulkan 1.1. |
4001 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsMixedReadWriteDepthStencilLayouts, |
4002 | isVulkan11Device()); |
4003 | |
4004 | // VK_EXT_pipeline_creation_feedback is promoted to core in Vulkan 1.3. |
4005 | ANGLE_FEATURE_CONDITION( |
4006 | &mFeatures, supportsPipelineCreationFeedback, |
4007 | ExtensionFound(VK_EXT_PIPELINE_CREATION_FEEDBACK_EXTENSION_NAME, deviceExtensionNames)); |
4008 | |
4009 | // Incomplete implementation on SwiftShader: http://issuetracker.google.com/234439593 |
4010 | ANGLE_FEATURE_CONDITION( |
4011 | &mFeatures, supportsPipelineCreationCacheControl, |
4012 | mPipelineCreationCacheControlFeatures.pipelineCreationCacheControl && !isSwiftShader); |
4013 | |
4014 | // Note: Protected Swapchains is not determined until we have a VkSurface to query. |
4015 | // So here vendors should indicate support so that protected_content extension |
4016 | // is enabled. |
4017 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsSurfaceProtectedSwapchains, IsAndroid()); |
4018 | |
4019 | // Work around incorrect NVIDIA point size range clamping. |
4020 | // http://anglebug.com/2970#c10 |
4021 | // Clamp if driver version is: |
4022 | // < 430 on Windows |
4023 | // < 421 otherwise |
4024 | ANGLE_FEATURE_CONDITION(&mFeatures, clampPointSize, |
4025 | isNvidia && nvidiaVersion.major < uint32_t(IsWindows() ? 430 : 421)); |
4026 | |
4027 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsDepthClipEnable, |
4028 | mDepthClipEnableFeatures.depthClipEnable == VK_TRUE); |
4029 | |
4030 | // Vulkan implementations are not required to clamp gl_FragDepth to [0, 1] by default. |
4031 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsDepthClampZeroOne, |
4032 | mDepthClampZeroOneFeatures.depthClampZeroOne == VK_TRUE); |
4033 | |
4034 | ANGLE_FEATURE_CONDITION(&mFeatures, clampFragDepth, |
4035 | isNvidia && !mFeatures.supportsDepthClampZeroOne.enabled); |
4036 | |
4037 | ANGLE_FEATURE_CONDITION( |
4038 | &mFeatures, supportsRenderpass2, |
4039 | ExtensionFound(VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME, deviceExtensionNames)); |
4040 | |
4041 | ANGLE_FEATURE_CONDITION( |
4042 | &mFeatures, supportsIncrementalPresent, |
4043 | ExtensionFound(VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME, deviceExtensionNames)); |
4044 | |
4045 | #if defined(ANGLE_PLATFORM_ANDROID) |
4046 | ANGLE_FEATURE_CONDITION( |
4047 | &mFeatures, supportsAndroidHardwareBuffer, |
4048 | IsAndroid() && |
4049 | ExtensionFound(VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME, |
4050 | deviceExtensionNames) && |
4051 | ExtensionFound(VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME, deviceExtensionNames)); |
4052 | #endif |
4053 | |
4054 | #if defined(ANGLE_PLATFORM_GGP) |
4055 | ANGLE_FEATURE_CONDITION( |
4056 | &mFeatures, supportsGGPFrameToken, |
4057 | ExtensionFound(VK_GGP_FRAME_TOKEN_EXTENSION_NAME, deviceExtensionNames)); |
4058 | #endif |
4059 | |
4060 | ANGLE_FEATURE_CONDITION( |
4061 | &mFeatures, supportsExternalMemoryFd, |
4062 | ExtensionFound(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, deviceExtensionNames)); |
4063 | |
4064 | #if defined(ANGLE_PLATFORM_WINDOWS) |
4065 | ANGLE_FEATURE_CONDITION( |
4066 | &mFeatures, supportsFullScreenExclusive, |
4067 | ExtensionFound(VK_EXT_FULL_SCREEN_EXCLUSIVE_EXTENSION_NAME, deviceExtensionNames)); |
4068 | |
4069 | // On Windows+AMD, drivers before version 0x800106 (2.0.262) would |
4070 | // implicitly enable VK_EXT_full_screen_exclusive and start returning |
4071 | // extension-specific error codes in swapchain functions. Since the |
4072 | // extension was not enabled by ANGLE, it was impossible to handle these |
4073 | // error codes correctly. On these earlier drivers, we want to explicitly |
4074 | // enable the extension and opt out of it to avoid seeing those error codes |
4075 | // entirely. |
4076 | ANGLE_FEATURE_CONDITION(&mFeatures, forceDisableFullScreenExclusive, |
4077 | isAMD && mPhysicalDeviceProperties.driverVersion < 0x800106); |
4078 | #endif |
4079 | |
4080 | ANGLE_FEATURE_CONDITION( |
4081 | &mFeatures, supportsExternalMemoryFuchsia, |
4082 | ExtensionFound(VK_FUCHSIA_EXTERNAL_MEMORY_EXTENSION_NAME, deviceExtensionNames)); |
4083 | |
4084 | ANGLE_FEATURE_CONDITION( |
4085 | &mFeatures, supportsFilteringPrecision, |
4086 | ExtensionFound(VK_GOOGLE_SAMPLER_FILTERING_PRECISION_EXTENSION_NAME, deviceExtensionNames)); |
4087 | |
4088 | ANGLE_FEATURE_CONDITION( |
4089 | &mFeatures, supportsExternalSemaphoreFd, |
4090 | ExtensionFound(VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, deviceExtensionNames)); |
4091 | |
4092 | ANGLE_FEATURE_CONDITION( |
4093 | &mFeatures, supportsExternalSemaphoreFuchsia, |
4094 | ExtensionFound(VK_FUCHSIA_EXTERNAL_SEMAPHORE_EXTENSION_NAME, deviceExtensionNames)); |
4095 | |
4096 | ANGLE_FEATURE_CONDITION( |
4097 | &mFeatures, supportsExternalFenceFd, |
4098 | ExtensionFound(VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME, deviceExtensionNames)); |
4099 | |
4100 | #if defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_LINUX) |
4101 | if (mFeatures.supportsExternalFenceCapabilities.enabled && |
4102 | mFeatures.supportsExternalSemaphoreCapabilities.enabled) |
4103 | { |
4104 | VkExternalFenceProperties externalFenceProperties = {}; |
4105 | externalFenceProperties.sType = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES; |
4106 | |
4107 | VkPhysicalDeviceExternalFenceInfo externalFenceInfo = {}; |
4108 | externalFenceInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO; |
4109 | externalFenceInfo.handleType = VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR; |
4110 | |
4111 | vkGetPhysicalDeviceExternalFencePropertiesKHR(mPhysicalDevice, &externalFenceInfo, |
4112 | &externalFenceProperties); |
4113 | |
4114 | VkExternalSemaphoreProperties externalSemaphoreProperties = {}; |
4115 | externalSemaphoreProperties.sType = VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES; |
4116 | |
4117 | VkPhysicalDeviceExternalSemaphoreInfo externalSemaphoreInfo = {}; |
4118 | externalSemaphoreInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO; |
4119 | externalSemaphoreInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR; |
4120 | |
4121 | vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(mPhysicalDevice, &externalSemaphoreInfo, |
4122 | &externalSemaphoreProperties); |
4123 | |
4124 | ANGLE_FEATURE_CONDITION( |
4125 | &mFeatures, supportsAndroidNativeFenceSync, |
4126 | (mFeatures.supportsExternalFenceFd.enabled && |
4127 | FencePropertiesCompatibleWithAndroid(externalFenceProperties) && |
4128 | mFeatures.supportsExternalSemaphoreFd.enabled && |
4129 | SemaphorePropertiesCompatibleWithAndroid(externalSemaphoreProperties))); |
4130 | } |
4131 | else |
4132 | { |
4133 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsAndroidNativeFenceSync, |
4134 | (mFeatures.supportsExternalFenceFd.enabled && |
4135 | mFeatures.supportsExternalSemaphoreFd.enabled)); |
4136 | } |
4137 | #endif // defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_LINUX) |
4138 | |
4139 | ANGLE_FEATURE_CONDITION( |
4140 | &mFeatures, supportsShaderStencilExport, |
4141 | ExtensionFound(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, deviceExtensionNames)); |
4142 | |
4143 | ANGLE_FEATURE_CONDITION( |
4144 | &mFeatures, supportsRenderPassLoadStoreOpNone, |
4145 | ExtensionFound(VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME, deviceExtensionNames)); |
4146 | |
4147 | ANGLE_FEATURE_CONDITION(&mFeatures, disallowMixedDepthStencilLoadOpNoneAndLoad, |
4148 | isARM && armDriverVersion < ARMDriverVersion(38, 1, 0)); |
4149 | |
4150 | ANGLE_FEATURE_CONDITION( |
4151 | &mFeatures, supportsRenderPassStoreOpNone, |
4152 | !mFeatures.supportsRenderPassLoadStoreOpNone.enabled && |
4153 | ExtensionFound(VK_QCOM_RENDER_PASS_STORE_OPS_EXTENSION_NAME, deviceExtensionNames)); |
4154 | |
4155 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsDepthClipControl, |
4156 | mDepthClipControlFeatures.depthClipControl == VK_TRUE); |
4157 | |
4158 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsPrimitivesGeneratedQuery, |
4159 | mPrimitivesGeneratedQueryFeatures.primitivesGeneratedQuery == VK_TRUE); |
4160 | |
4161 | ANGLE_FEATURE_CONDITION( |
4162 | &mFeatures, supportsPrimitiveTopologyListRestart, |
4163 | mPrimitiveTopologyListRestartFeatures.primitiveTopologyListRestart == VK_TRUE); |
4164 | |
4165 | ANGLE_FEATURE_CONDITION( |
4166 | &mFeatures, supportsBlendOperationAdvanced, |
4167 | ExtensionFound(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, deviceExtensionNames)); |
4168 | |
4169 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsTransformFeedbackExtension, |
4170 | mTransformFeedbackFeatures.transformFeedback == VK_TRUE); |
4171 | |
4172 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsGeometryStreamsCapability, |
4173 | mTransformFeedbackFeatures.geometryStreams == VK_TRUE); |
4174 | |
4175 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsIndexTypeUint8, |
4176 | mIndexTypeUint8Features.indexTypeUint8 == VK_TRUE); |
4177 | |
4178 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsDepthStencilResolve, |
4179 | mFeatures.supportsRenderpass2.enabled && |
4180 | mDepthStencilResolveProperties.supportedDepthResolveModes != 0); |
4181 | |
4182 | ANGLE_FEATURE_CONDITION( |
4183 | &mFeatures, supportsMultisampledRenderToSingleSampled, |
4184 | mFeatures.supportsRenderpass2.enabled && mFeatures.supportsDepthStencilResolve.enabled && |
4185 | mMultisampledRenderToSingleSampledFeatures.multisampledRenderToSingleSampled == |
4186 | VK_TRUE); |
4187 | |
4188 | ANGLE_FEATURE_CONDITION( |
4189 | &mFeatures, supportsMultisampledRenderToSingleSampledGOOGLEX, |
4190 | !mFeatures.supportsMultisampledRenderToSingleSampled.enabled && |
4191 | mFeatures.supportsRenderpass2.enabled && |
4192 | mFeatures.supportsDepthStencilResolve.enabled && |
4193 | mMultisampledRenderToSingleSampledFeaturesGOOGLEX.multisampledRenderToSingleSampled == |
4194 | VK_TRUE); |
4195 | |
4196 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsImage2dViewOf3d, |
4197 | mImage2dViewOf3dFeatures.image2DViewOf3D == VK_TRUE); |
4198 | |
4199 | // Note: sampler2DViewOf3D is only useful for supporting EGL_KHR_gl_texture_3D_image. If the |
4200 | // VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT added to 3D images measurable hurts sampling |
4201 | // performance, it might be better to remove support for EGL_KHR_gl_texture_3D_image in favor of |
4202 | // faster 3D images. |
4203 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsSampler2dViewOf3d, |
4204 | mFeatures.supportsImage2dViewOf3d.enabled && |
4205 | mImage2dViewOf3dFeatures.sampler2DViewOf3D == VK_TRUE); |
4206 | |
4207 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsMultiview, mMultiviewFeatures.multiview == VK_TRUE); |
4208 | |
4209 | ANGLE_FEATURE_CONDITION(&mFeatures, emulateTransformFeedback, |
4210 | (!mFeatures.supportsTransformFeedbackExtension.enabled && |
4211 | mPhysicalDeviceFeatures.vertexPipelineStoresAndAtomics == VK_TRUE)); |
4212 | |
4213 | // TODO: http://anglebug.com/5927 - drop dependency on customBorderColorWithoutFormat. |
4214 | ANGLE_FEATURE_CONDITION( |
4215 | &mFeatures, supportsCustomBorderColor, |
4216 | mCustomBorderColorFeatures.customBorderColors == VK_TRUE && |
4217 | mCustomBorderColorFeatures.customBorderColorWithoutFormat == VK_TRUE); |
4218 | |
4219 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsMultiDrawIndirect, |
4220 | mPhysicalDeviceFeatures.multiDrawIndirect == VK_TRUE); |
4221 | |
4222 | ANGLE_FEATURE_CONDITION(&mFeatures, perFrameWindowSizeQuery, |
4223 | IsAndroid() || isIntel || (IsWindows() && isAMD) || IsFuchsia() || |
4224 | isSamsung || displayVk->isWayland()); |
4225 | |
4226 | ANGLE_FEATURE_CONDITION(&mFeatures, padBuffersToMaxVertexAttribStride, isAMD || isSamsung); |
4227 | mMaxVertexAttribStride = std::min(a: static_cast<uint32_t>(gl::limits::kMaxVertexAttribStride), |
4228 | b: mPhysicalDeviceProperties.limits.maxVertexInputBindingStride); |
4229 | |
4230 | ANGLE_FEATURE_CONDITION(&mFeatures, forceD16TexFilter, IsAndroid() && isQualcommProprietary); |
4231 | |
4232 | ANGLE_FEATURE_CONDITION(&mFeatures, disableFlippingBlitWithCommand, |
4233 | IsAndroid() && isQualcommProprietary); |
4234 | |
4235 | // Allocation sanitization disabled by default because of a heaveyweight implementation |
4236 | // that can cause OOM and timeouts. |
4237 | ANGLE_FEATURE_CONDITION(&mFeatures, allocateNonZeroMemory, false); |
4238 | |
4239 | // ARM does buffer copy on geometry pipeline, which may create a GPU pipeline bubble that |
4240 | // prevents vertex shader to overlap with fragment shader on job manager based architecture. For |
4241 | // now we always choose CPU to do copy on ARM job manager based GPU. |
4242 | ANGLE_FEATURE_CONDITION(&mFeatures, preferCPUForBufferSubData, isMaliJobManagerBasedGPU); |
4243 | |
4244 | // On android, we usually are GPU limited, we try to use CPU to do data copy when other |
4245 | // conditions are the same. Set to zero will use GPU to do copy. This is subject to further |
4246 | // tuning for each platform https://issuetracker.google.com/201826021 |
4247 | mMaxCopyBytesUsingCPUWhenPreservingBufferData = |
4248 | IsAndroid() ? std::numeric_limits<uint32_t>::max() : 0; |
4249 | |
4250 | ANGLE_FEATURE_CONDITION(&mFeatures, persistentlyMappedBuffers, true); |
4251 | |
4252 | ANGLE_FEATURE_CONDITION(&mFeatures, logMemoryReportCallbacks, false); |
4253 | ANGLE_FEATURE_CONDITION(&mFeatures, logMemoryReportStats, false); |
4254 | |
4255 | ANGLE_FEATURE_CONDITION( |
4256 | &mFeatures, supportsExternalMemoryDmaBufAndModifiers, |
4257 | ExtensionFound(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME, deviceExtensionNames) && |
4258 | ExtensionFound(VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, deviceExtensionNames)); |
4259 | |
4260 | // Android pre-rotation support can be disabled. |
4261 | ANGLE_FEATURE_CONDITION(&mFeatures, enablePreRotateSurfaces, |
4262 | IsAndroid() && supportsNegativeViewport); |
4263 | |
4264 | // http://anglebug.com/3078 |
4265 | ANGLE_FEATURE_CONDITION( |
4266 | &mFeatures, enablePrecisionQualifiers, |
4267 | !(IsPixel2(mPhysicalDeviceProperties.vendorID, mPhysicalDeviceProperties.deviceID) && |
4268 | (mPhysicalDeviceProperties.driverVersion < kPixel2DriverWithRelaxedPrecision)) && |
4269 | !IsPixel4(mPhysicalDeviceProperties.vendorID, mPhysicalDeviceProperties.deviceID)); |
4270 | |
4271 | // http://anglebug.com/7488 |
4272 | ANGLE_FEATURE_CONDITION(&mFeatures, varyingsRequireMatchingPrecisionInSpirv, isPowerVR); |
4273 | |
4274 | // IMR devices are less sensitive to the src/dst stage masks in barriers, and behave more |
4275 | // efficiently when all barriers are aggregated, rather than individually and precisely |
4276 | // specified. |
4277 | ANGLE_FEATURE_CONDITION(&mFeatures, preferAggregateBarrierCalls, isImmediateModeRenderer); |
4278 | |
4279 | // For IMR devices, it's more efficient to ignore invalidate of framebuffer attachments with |
4280 | // emulated formats that have extra channels. For TBR devices, the invalidate will be followed |
4281 | // by a clear to retain valid values in said extra channels. |
4282 | ANGLE_FEATURE_CONDITION(&mFeatures, preferSkippingInvalidateForEmulatedFormats, |
4283 | isImmediateModeRenderer); |
4284 | |
4285 | // Currently disabled by default: http://anglebug.com/4324 |
4286 | ANGLE_FEATURE_CONDITION(&mFeatures, asyncCommandQueue, false); |
4287 | |
4288 | ANGLE_FEATURE_CONDITION(&mFeatures, asyncCommandBufferReset, true); |
4289 | |
4290 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsYUVSamplerConversion, |
4291 | mSamplerYcbcrConversionFeatures.samplerYcbcrConversion != VK_FALSE); |
4292 | |
4293 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsShaderFloat16, |
4294 | mShaderFloat16Int8Features.shaderFloat16 == VK_TRUE); |
4295 | |
4296 | // Prefer driver uniforms over specialization constants in the following: |
4297 | // |
4298 | // - Older Qualcomm drivers where specialization constants severly degrade the performance of |
4299 | // pipeline creation. http://issuetracker.google.com/173636783 |
4300 | // - ARM hardware |
4301 | // - Imagination hardware |
4302 | // - SwiftShader |
4303 | // |
4304 | ANGLE_FEATURE_CONDITION( |
4305 | &mFeatures, preferDriverUniformOverSpecConst, |
4306 | (isQualcommProprietary && |
4307 | mPhysicalDeviceProperties.driverVersion < kPixel4DriverWithWorkingSpecConstSupport) || |
4308 | isARM || isPowerVR || isSwiftShader); |
4309 | |
4310 | // The compute shader used to generate mipmaps needs - |
4311 | // 1. subgroup quad operations in compute shader stage. |
4312 | // 2. subgroup operations that can use extended types. |
4313 | // 3. 256-wide workgroup. |
4314 | // |
4315 | // Furthermore, VK_IMAGE_USAGE_STORAGE_BIT is detrimental to performance on many platforms, on |
4316 | // which this path is not enabled. Platforms that are known to have better performance with |
4317 | // this path are: |
4318 | // |
4319 | // - AMD |
4320 | // - Nvidia |
4321 | // - Samsung |
4322 | // |
4323 | // Additionally, this path is disabled on buggy drivers: |
4324 | // |
4325 | // - AMD/Windows: Unfortunately the trybots use ancient AMD cards and drivers. |
4326 | const bool supportsSubgroupQuadOpsInComputeShader = |
4327 | (mSubgroupProperties.supportedStages & VK_SHADER_STAGE_COMPUTE_BIT) && |
4328 | (mSubgroupProperties.supportedOperations & VK_SUBGROUP_FEATURE_QUAD_BIT); |
4329 | |
4330 | const uint32_t maxComputeWorkGroupInvocations = |
4331 | mPhysicalDeviceProperties.limits.maxComputeWorkGroupInvocations; |
4332 | |
4333 | ANGLE_FEATURE_CONDITION(&mFeatures, allowGenerateMipmapWithCompute, |
4334 | supportsSubgroupQuadOpsInComputeShader && |
4335 | mSubgroupExtendedTypesFeatures.shaderSubgroupExtendedTypes && |
4336 | maxComputeWorkGroupInvocations >= 256 && |
4337 | ((isAMD && !IsWindows()) || isNvidia || isSamsung)); |
4338 | |
4339 | bool isAdreno540 = mPhysicalDeviceProperties.deviceID == angle::kDeviceID_Adreno540; |
4340 | ANGLE_FEATURE_CONDITION(&mFeatures, forceMaxUniformBufferSize16KB, |
4341 | isQualcommProprietary && isAdreno540); |
4342 | |
4343 | ANGLE_FEATURE_CONDITION( |
4344 | &mFeatures, supportsImageFormatList, |
4345 | ExtensionFound(VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, deviceExtensionNames)); |
4346 | |
4347 | ANGLE_FEATURE_CONDITION( |
4348 | &mFeatures, supportsSamplerMirrorClampToEdge, |
4349 | ExtensionFound(VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME, deviceExtensionNames)); |
4350 | |
4351 | // Emulation of GL_EXT_multisampled_render_to_texture is only really useful on tiling hardware, |
4352 | // but is exposed on any configuration deployed on Android, such as Samsung's AMD-based GPU. |
4353 | // |
4354 | // During testing, it was also discovered that emulation triggers bugs on some platforms: |
4355 | // |
4356 | // - Swiftshader: |
4357 | // * Failure on mac: http://anglebug.com/4937 |
4358 | // * OOM: http://crbug.com/1263046 |
4359 | // - Intel on windows: http://anglebug.com/5032 |
4360 | // - AMD on windows: http://crbug.com/1132366 |
4361 | // |
4362 | const bool supportsIndependentDepthStencilResolve = |
4363 | mFeatures.supportsDepthStencilResolve.enabled && |
4364 | mDepthStencilResolveProperties.independentResolveNone == VK_TRUE; |
4365 | ANGLE_FEATURE_CONDITION( |
4366 | &mFeatures, enableMultisampledRenderToTexture, |
4367 | mFeatures.supportsMultisampledRenderToSingleSampled.enabled || |
4368 | mFeatures.supportsMultisampledRenderToSingleSampledGOOGLEX.enabled || |
4369 | (supportsIndependentDepthStencilResolve && (isTileBasedRenderer || isSamsung))); |
4370 | |
4371 | // Currently we enable cube map arrays based on the imageCubeArray Vk feature. |
4372 | // TODO: Check device caps for full cube map array support. http://anglebug.com/5143 |
4373 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsImageCubeArray, |
4374 | mPhysicalDeviceFeatures.imageCubeArray == VK_TRUE); |
4375 | |
4376 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsPipelineStatisticsQuery, |
4377 | mPhysicalDeviceFeatures.pipelineStatisticsQuery == VK_TRUE); |
4378 | |
4379 | // Defer glFLush call causes manhattan 3.0 perf regression. Let Qualcomm driver opt out from |
4380 | // this optimization. |
4381 | ANGLE_FEATURE_CONDITION(&mFeatures, deferFlushUntilEndRenderPass, !isQualcommProprietary); |
4382 | |
4383 | // Android mistakenly destroys the old swapchain when creating a new one. |
4384 | ANGLE_FEATURE_CONDITION(&mFeatures, waitIdleBeforeSwapchainRecreation, IsAndroid() && isARM); |
4385 | |
4386 | // vkCmdClearAttachments races with draw calls on Qualcomm hardware as observed on Pixel2 and |
4387 | // Pixel4. https://issuetracker.google.com/issues/166809097 |
4388 | ANGLE_FEATURE_CONDITION(&mFeatures, preferDrawClearOverVkCmdClearAttachments, |
4389 | isQualcommProprietary); |
4390 | |
4391 | // r32f image emulation is done unconditionally so VK_FORMAT_FEATURE_STORAGE_*_ATOMIC_BIT is not |
4392 | // required. |
4393 | ANGLE_FEATURE_CONDITION(&mFeatures, emulateR32fImageAtomicExchange, true); |
4394 | |
4395 | // Negative viewports are exposed in the Maintenance1 extension and in core Vulkan 1.1+. |
4396 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsNegativeViewport, supportsNegativeViewport); |
4397 | |
4398 | // Whether non-conformant configurations and extensions should be exposed. Always disable for |
4399 | // MESA Virtio-GPU Venus driver for production purpose. |
4400 | ANGLE_FEATURE_CONDITION(&mFeatures, exposeNonConformantExtensionsAndVersions, |
4401 | kExposeNonConformantExtensionsAndVersions && !isVenus); |
4402 | |
4403 | ANGLE_FEATURE_CONDITION( |
4404 | &mFeatures, supportsMemoryBudget, |
4405 | ExtensionFound(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME, deviceExtensionNames)); |
4406 | |
4407 | // Disabled by default. Only enable it for experimental purpose, as this will cause various |
4408 | // tests to fail. |
4409 | ANGLE_FEATURE_CONDITION(&mFeatures, forceFragmentShaderPrecisionHighpToMediump, false); |
4410 | |
4411 | // Testing shows that on ARM GPU, doing implicit flush at framebuffer boundary improves |
4412 | // performance. Most app traces shows frame time reduced and manhattan 3.1 offscreen score |
4413 | // improves 7%. Disable for MESA Virtio-GPU Venus driver in virtualized environment where |
4414 | // batching is preferred. |
4415 | ANGLE_FEATURE_CONDITION(&mFeatures, preferSubmitAtFBOBoundary, |
4416 | (isARM || isSwiftShader) && !isVenus); |
4417 | |
4418 | // In order to support immutable samplers tied to external formats, we need to overallocate |
4419 | // descriptor counts for such immutable samplers |
4420 | ANGLE_FEATURE_CONDITION(&mFeatures, useMultipleDescriptorsForExternalFormats, true); |
4421 | |
4422 | // http://anglebug.com/6651 |
4423 | // When creating a surface with the format GL_RGB8, override the format to be GL_RGBA8, since |
4424 | // Android prevents creating swapchain images with VK_FORMAT_R8G8B8_UNORM. |
4425 | // Do this for all platforms, since few (none?) IHVs support 24-bit formats with their HW |
4426 | // natively anyway. |
4427 | ANGLE_FEATURE_CONDITION(&mFeatures, overrideSurfaceFormatRGB8ToRGBA8, true); |
4428 | |
4429 | // We set |
4430 | // |
4431 | // - VK_PIPELINE_COLOR_BLEND_STATE_CREATE_RASTERIZATION_ORDER_ATTACHMENT_ACCESS_BIT_EXT |
4432 | // - VK_SUBPASS_DESCRIPTION_RASTERIZATION_ORDER_ATTACHMENT_COLOR_ACCESS_BIT_EXT |
4433 | // |
4434 | // when this feature is supported and there is framebuffer fetch. But the |
4435 | // check for framebuffer fetch is not accurate enough and those bits can |
4436 | // have great impact on Qualcomm (it only affects the open source driver |
4437 | // because the proprietary driver does not expose the extension). Let's |
4438 | // disable it on Qualcomm. |
4439 | // |
4440 | // https://issuetracker.google.com/issues/255837430 |
4441 | ANGLE_FEATURE_CONDITION( |
4442 | &mFeatures, supportsRasterizationOrderAttachmentAccess, |
4443 | !isQualcomm && |
4444 | mRasterizationOrderAttachmentAccessFeatures.rasterizationOrderColorAttachmentAccess == |
4445 | VK_TRUE); |
4446 | |
4447 | // The VK_EXT_surface_maintenance1 and VK_EXT_swapchain_maintenance1 extensions are used for a |
4448 | // variety of improvements: |
4449 | // |
4450 | // - Recycling present semaphores |
4451 | // - Avoiding swapchain recreation when present modes change |
4452 | // - Amortizing the cost of memory allocation for swapchain creation over multiple frames |
4453 | // |
4454 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsSwapchainMaintenance1, |
4455 | mSwapchainMaintenance1Features.swapchainMaintenance1 == VK_TRUE); |
4456 | |
4457 | // The VK_EXT_legacy_dithering extension enables dithering support without emulation |
4458 | // Disable the usage of VK_EXT_legacy_dithering on ARM until the driver bug |
4459 | // http://issuetracker.google.com/293136916, http://issuetracker.google.com/292282210 are fixed. |
4460 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsLegacyDithering, |
4461 | mDitheringFeatures.legacyDithering == VK_TRUE && !isARM); |
4462 | |
4463 | // Applications on Android have come to rely on hardware dithering, and visually regress without |
4464 | // it. On desktop GPUs, OpenGL's dithering is a no-op. The following setting mimics that |
4465 | // behavior. Dithering is also currently not enabled on SwiftShader, but can be as needed |
4466 | // (which would require Chromium and Capture/Replay test expectations updates). |
4467 | ANGLE_FEATURE_CONDITION(&mFeatures, emulateDithering, |
4468 | IsAndroid() && !mFeatures.supportsLegacyDithering.enabled); |
4469 | |
4470 | // http://anglebug.com/6872 |
4471 | // On ARM hardware, framebuffer-fetch-like behavior on Vulkan is already coherent, so we can |
4472 | // expose the coherent version of the GL extension despite unofficial Vulkan support. |
4473 | ANGLE_FEATURE_CONDITION( |
4474 | &mFeatures, supportsShaderFramebufferFetch, |
4475 | (IsAndroid() && isARM) || mFeatures.supportsRasterizationOrderAttachmentAccess.enabled); |
4476 | |
4477 | // Important games are not checking supported extensions properly, and are confusing the |
4478 | // GL_EXT_shader_framebuffer_fetch_non_coherent as the GL_EXT_shader_framebuffer_fetch |
4479 | // extension. Therefore, don't enable the extension on Arm and Qualcomm by default. |
4480 | // https://issuetracker.google.com/issues/186643966 |
4481 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsShaderFramebufferFetchNonCoherent, |
4482 | (IsAndroid() && !(isARM || isQualcomm)) || isSwiftShader); |
4483 | |
4484 | // On tile-based renderers, breaking the render pass is costly. Changing into and out of |
4485 | // framebuffer fetch causes the render pass to break so that the layout of the color attachments |
4486 | // can be adjusted. On such hardware, the switch to framebuffer fetch mode is made permanent so |
4487 | // such render pass breaks don't happen. |
4488 | ANGLE_FEATURE_CONDITION(&mFeatures, permanentlySwitchToFramebufferFetchMode, |
4489 | isTileBasedRenderer); |
4490 | |
4491 | // Support EGL_KHR_lock_surface3 extension. |
4492 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsLockSurfaceExtension, IsAndroid()); |
4493 | |
4494 | // http://anglebug.com/6878 |
4495 | // Android needs swapbuffers to update image and present to display. |
4496 | ANGLE_FEATURE_CONDITION(&mFeatures, swapbuffersOnFlushOrFinishWithSingleBuffer, IsAndroid()); |
4497 | |
4498 | // Workaround a Qualcomm imprecision with dithering |
4499 | ANGLE_FEATURE_CONDITION(&mFeatures, roundOutputAfterDithering, isQualcomm); |
4500 | |
4501 | // GL_KHR_blend_equation_advanced is emulated when the equivalent Vulkan extension is not |
4502 | // usable. Additionally, the following platforms don't support INPUT_ATTACHMENT usage for the |
4503 | // swapchain, so they are excluded: |
4504 | // |
4505 | // - Intel |
4506 | // |
4507 | // The above platforms are not excluded if behind MESA Virtio-GPU Venus driver since WSI is |
4508 | // implemented with external memory there. |
4509 | // |
4510 | // Without VK_GOOGLE_surfaceless_query, there is no way to automatically deduce this support. |
4511 | ANGLE_FEATURE_CONDITION( |
4512 | &mFeatures, emulateAdvancedBlendEquations, |
4513 | !mFeatures.supportsBlendOperationAdvanced.enabled && (isVenus || !isIntel)); |
4514 | |
4515 | // http://anglebug.com/6933 |
4516 | // Android expects VkPresentRegionsKHR rectangles with a bottom-left origin, while spec |
4517 | // states they should have a top-left origin. |
4518 | ANGLE_FEATURE_CONDITION(&mFeatures, bottomLeftOriginPresentRegionRectangles, IsAndroid()); |
4519 | |
4520 | // Use VMA for image suballocation. |
4521 | ANGLE_FEATURE_CONDITION(&mFeatures, useVmaForImageSuballocation, true); |
4522 | |
4523 | // Retain debug info in SPIR-V blob. |
4524 | ANGLE_FEATURE_CONDITION(&mFeatures, retainSPIRVDebugInfo, getEnableValidationLayers()); |
4525 | |
4526 | // For discrete GPUs, most of device local memory is host invisible. We should not force the |
4527 | // host visible flag for them and result in allocation failure. |
4528 | ANGLE_FEATURE_CONDITION( |
4529 | &mFeatures, preferDeviceLocalMemoryHostVisible, |
4530 | canPreferDeviceLocalMemoryHostVisible(mPhysicalDeviceProperties.deviceType)); |
4531 | |
4532 | bool dynamicStateWorks = true; |
4533 | if (isARM) |
4534 | { |
4535 | // Multiple dynamic state issues on ARM have been fixed. |
4536 | // http://issuetracker.google.com/285124778 |
4537 | // http://issuetracker.google.com/285196249 |
4538 | // http://issuetracker.google.com/286224923 |
4539 | // http://issuetracker.google.com/287318431 |
4540 | |
4541 | // Use it on drivers/devices known to work. |
4542 | if (isPixel) |
4543 | { |
4544 | // Pixel devices are working after r44 |
4545 | dynamicStateWorks = armDriverVersion >= ARMDriverVersion(44, 0, 0); |
4546 | } |
4547 | else |
4548 | { |
4549 | // Others should work after r44p1 |
4550 | dynamicStateWorks = armDriverVersion >= ARMDriverVersion(44, 1, 0); |
4551 | } |
4552 | } |
4553 | |
4554 | ANGLE_FEATURE_CONDITION( |
4555 | &mFeatures, supportsExtendedDynamicState, |
4556 | mExtendedDynamicStateFeatures.extendedDynamicState == VK_TRUE && dynamicStateWorks); |
4557 | |
4558 | ANGLE_FEATURE_CONDITION(&mFeatures, useVertexInputBindingStrideDynamicState, |
4559 | mFeatures.supportsExtendedDynamicState.enabled && dynamicStateWorks); |
4560 | ANGLE_FEATURE_CONDITION(&mFeatures, useCullModeDynamicState, |
4561 | mFeatures.supportsExtendedDynamicState.enabled && dynamicStateWorks); |
4562 | ANGLE_FEATURE_CONDITION(&mFeatures, useDepthCompareOpDynamicState, |
4563 | mFeatures.supportsExtendedDynamicState.enabled); |
4564 | ANGLE_FEATURE_CONDITION(&mFeatures, useDepthTestEnableDynamicState, |
4565 | mFeatures.supportsExtendedDynamicState.enabled); |
4566 | ANGLE_FEATURE_CONDITION(&mFeatures, useDepthWriteEnableDynamicState, |
4567 | mFeatures.supportsExtendedDynamicState.enabled && dynamicStateWorks); |
4568 | ANGLE_FEATURE_CONDITION(&mFeatures, useFrontFaceDynamicState, |
4569 | mFeatures.supportsExtendedDynamicState.enabled); |
4570 | ANGLE_FEATURE_CONDITION(&mFeatures, useStencilOpDynamicState, |
4571 | mFeatures.supportsExtendedDynamicState.enabled); |
4572 | ANGLE_FEATURE_CONDITION(&mFeatures, useStencilTestEnableDynamicState, |
4573 | mFeatures.supportsExtendedDynamicState.enabled); |
4574 | |
4575 | ANGLE_FEATURE_CONDITION( |
4576 | &mFeatures, supportsExtendedDynamicState2, |
4577 | mExtendedDynamicState2Features.extendedDynamicState2 == VK_TRUE && dynamicStateWorks); |
4578 | |
4579 | ANGLE_FEATURE_CONDITION(&mFeatures, usePrimitiveRestartEnableDynamicState, |
4580 | mFeatures.supportsExtendedDynamicState2.enabled && dynamicStateWorks); |
4581 | ANGLE_FEATURE_CONDITION(&mFeatures, useRasterizerDiscardEnableDynamicState, |
4582 | mFeatures.supportsExtendedDynamicState2.enabled); |
4583 | ANGLE_FEATURE_CONDITION(&mFeatures, useDepthBiasEnableDynamicState, |
4584 | mFeatures.supportsExtendedDynamicState2.enabled); |
4585 | |
4586 | // Disabled on Intel/Mesa due to driver bug (crbug.com/1379201). This bug is fixed since Mesa |
4587 | // 22.2.0. |
4588 | const bool isMesaLessThan22_2 = |
4589 | mesaVersion.major < 22 || (mesaVersion.major == 22 && mesaVersion.minor < 2); |
4590 | |
4591 | ANGLE_FEATURE_CONDITION( |
4592 | &mFeatures, supportsLogicOpDynamicState, |
4593 | mFeatures.supportsExtendedDynamicState2.enabled && |
4594 | mExtendedDynamicState2Features.extendedDynamicState2LogicOp == VK_TRUE && |
4595 | !(IsLinux() && isIntel && isMesaLessThan22_2) && !(IsAndroid() && isGalaxyS23)); |
4596 | |
4597 | // Support GL_QCOM_shading_rate extension |
4598 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsFragmentShadingRate, |
4599 | canSupportFragmentShadingRate(deviceExtensionNames)); |
4600 | |
4601 | // We can use the interlock to support GL_ANGLE_shader_pixel_local_storage_coherent. |
4602 | ANGLE_FEATURE_CONDITION( |
4603 | &mFeatures, supportsFragmentShaderPixelInterlock, |
4604 | mFragmentShaderInterlockFeatures.fragmentShaderPixelInterlock == VK_TRUE); |
4605 | |
4606 | // Samsung Vulkan driver crashes in vkCmdClearAttachments() when imageless Framebuffer |
4607 | // is used to begin Secondary Command Buffer before the corresponding vkCmdBeginRenderPass(). |
4608 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsImagelessFramebuffer, |
4609 | mImagelessFramebufferFeatures.imagelessFramebuffer == VK_TRUE && |
4610 | (vk::RenderPassCommandBuffer::ExecutesInline() || !isSamsung)); |
4611 | |
4612 | // The VK_PIPELINE_ROBUSTNESS_BUFFER_BEHAVIOR_ROBUST_BUFFER_ACCESS_EXT behavior is used by |
4613 | // ANGLE, which requires the robustBufferAccess feature to be available. |
4614 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsPipelineRobustness, |
4615 | mPipelineRobustnessFeatures.pipelineRobustness == VK_TRUE && |
4616 | mPhysicalDeviceFeatures.robustBufferAccess); |
4617 | |
4618 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsPipelineProtectedAccess, |
4619 | mPipelineProtectedAccessFeatures.pipelineProtectedAccess == VK_TRUE && |
4620 | mProtectedMemoryFeatures.protectedMemory == VK_TRUE); |
4621 | |
4622 | // VK_EXT_graphics_pipeline_library is available on NVIDIA drivers earlier |
4623 | // than version 531, but there are transient visual glitches with rendering |
4624 | // on those earlier versions. |
4625 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsGraphicsPipelineLibrary, |
4626 | mGraphicsPipelineLibraryFeatures.graphicsPipelineLibrary == VK_TRUE && |
4627 | (!isNvidia || nvidiaVersion.major >= 531)); |
4628 | |
4629 | // The following drivers are known to key the pipeline cache blobs with vertex input and |
4630 | // fragment output state, causing draw-time pipeline creation to miss the cache regardless of |
4631 | // warmup: |
4632 | // |
4633 | // - ARM drivers |
4634 | // - Imagination drivers |
4635 | // |
4636 | // The following drivers are instead known to _not_ include said state, and hit the cache at |
4637 | // draw time. |
4638 | // |
4639 | // - SwiftShader |
4640 | // - Open source Qualcomm drivers |
4641 | // |
4642 | // The situation is unknown for other drivers. |
4643 | // |
4644 | // Additionally, numerous tests that previously never created a Vulkan pipeline fail or crash on |
4645 | // proprietary Qualcomm drivers when they do during cache warm up. On Intel/Linux, one trace |
4646 | // shows flakiness with this. |
4647 | const bool libraryBlobsAreReusedByMonolithicPipelines = !isARM && !isPowerVR; |
4648 | ANGLE_FEATURE_CONDITION(&mFeatures, warmUpPipelineCacheAtLink, |
4649 | libraryBlobsAreReusedByMonolithicPipelines && !isQualcommProprietary && |
4650 | !(IsLinux() && isIntel) && !(IsChromeOS() && isSwiftShader)); |
4651 | |
4652 | // On SwiftShader, no data is retrieved from the pipeline cache, so there is no reason to |
4653 | // serialize it or put it in the blob cache. |
4654 | // For Windows Nvidia Vulkan driver older than 520, Vulkan pipeline cache will only generate one |
4655 | // single huge cache for one process shared by all graphics piplines in the same process, which |
4656 | // can be huge. |
4657 | const bool nvVersionLessThan520 = isNvidia && (nvidiaVersion.major < 520u); |
4658 | ANGLE_FEATURE_CONDITION(&mFeatures, hasEffectivePipelineCacheSerialization, |
4659 | !isSwiftShader && !nvVersionLessThan520); |
4660 | |
4661 | // When the driver sets graphicsPipelineLibraryFastLinking, it means that monolithic pipelines |
4662 | // are just a bundle of the libraries, and that there is no benefit in creating monolithic |
4663 | // pipelines. |
4664 | // |
4665 | // Note: for testing purposes, this is enabled on SwiftShader despite the fact that it doesn't |
4666 | // need it. This should be undone once there is at least one bot that supports |
4667 | // VK_EXT_graphics_pipeline_library without graphicsPipelineLibraryFastLinking |
4668 | ANGLE_FEATURE_CONDITION( |
4669 | &mFeatures, preferMonolithicPipelinesOverLibraries, |
4670 | !mGraphicsPipelineLibraryProperties.graphicsPipelineLibraryFastLinking || isSwiftShader); |
4671 | |
4672 | // Whether the pipeline caches should merge into the global pipeline cache. This should only be |
4673 | // enabled on platforms if: |
4674 | // |
4675 | // - VK_EXT_graphics_pipeline_library is not supported. In that case, only the program's cache |
4676 | // used during warm up is merged into the global cache for later monolithic pipeline creation. |
4677 | // - VK_EXT_graphics_pipeline_library is supported, monolithic pipelines are preferred, and the |
4678 | // driver is able to reuse blobs from partial pipelines when creating monolithic pipelines. |
4679 | ANGLE_FEATURE_CONDITION(&mFeatures, mergeProgramPipelineCachesToGlobalCache, |
4680 | !mFeatures.supportsGraphicsPipelineLibrary.enabled || |
4681 | (mFeatures.preferMonolithicPipelinesOverLibraries.enabled && |
4682 | libraryBlobsAreReusedByMonolithicPipelines)); |
4683 | |
4684 | ANGLE_FEATURE_CONDITION(&mFeatures, enableAsyncPipelineCacheCompression, true); |
4685 | |
4686 | // Sync monolithic pipelines to the blob cache occasionally on platforms that would benefit from |
4687 | // it: |
4688 | // |
4689 | // - VK_EXT_graphics_pipeline_library is not supported, and the program cache is not warmed up: |
4690 | // If the pipeline cache is being warmed up at link time, the blobs corresponding to each |
4691 | // program is individually retrieved and stored in the blob cache already. |
4692 | // - VK_EXT_graphics_pipeline_library is supported, but monolithic pipelines are still prefered, |
4693 | // and the cost of syncing the large cache is acceptable. |
4694 | // |
4695 | // Otherwise monolithic pipelines are recreated on every run. |
4696 | const bool hasNoPipelineWarmUp = !mFeatures.supportsGraphicsPipelineLibrary.enabled && |
4697 | !mFeatures.warmUpPipelineCacheAtLink.enabled; |
4698 | const bool canSyncLargeMonolithicCache = |
4699 | mFeatures.supportsGraphicsPipelineLibrary.enabled && |
4700 | mFeatures.preferMonolithicPipelinesOverLibraries.enabled && |
4701 | (!IsAndroid() || mFeatures.enableAsyncPipelineCacheCompression.enabled); |
4702 | ANGLE_FEATURE_CONDITION(&mFeatures, syncMonolithicPipelinesToBlobCache, |
4703 | mFeatures.hasEffectivePipelineCacheSerialization.enabled && |
4704 | (hasNoPipelineWarmUp || canSyncLargeMonolithicCache)); |
4705 | |
4706 | // On ARM, dynamic state for stencil write mask doesn't work correctly in the presence of |
4707 | // discard or alpha to coverage, if the static state provided when creating the pipeline has a |
4708 | // value of 0. |
4709 | ANGLE_FEATURE_CONDITION(&mFeatures, useNonZeroStencilWriteMaskStaticState, |
4710 | isARM && armDriverVersion < ARMDriverVersion(43, 0, 0)); |
4711 | |
4712 | // On ARM, per-sample shading is not enabled despite the presence of a Sample decoration. As a |
4713 | // workaround, per-sample shading is inferred by ANGLE and explicitly enabled by the API. |
4714 | ANGLE_FEATURE_CONDITION(&mFeatures, explicitlyEnablePerSampleShading, isARM); |
4715 | |
4716 | ANGLE_FEATURE_CONDITION(&mFeatures, explicitlyCastMediumpFloatTo16Bit, isARM && !isVenus); |
4717 | |
4718 | // Force to create swapchain with continuous refresh on shared present. Disabled by default. |
4719 | // Only enable it on integrations without EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID passthrough. |
4720 | ANGLE_FEATURE_CONDITION(&mFeatures, forceContinuousRefreshOnSharedPresent, false); |
4721 | |
4722 | // Enable setting frame timestamp surface attribute on Android platform. |
4723 | // Frame timestamp is enabled by calling into "vkGetPastPresentationTimingGOOGLE" |
4724 | // which, on Android platforms, makes the necessary ANativeWindow API calls. |
4725 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsTimestampSurfaceAttribute, |
4726 | IsAndroid() && ExtensionFound(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME, |
4727 | deviceExtensionNames)); |
4728 | |
4729 | // 1) host vk driver does not natively support ETC format. |
4730 | // 2) host vk driver supports BC format. |
4731 | // 3) host vk driver supports subgroup instructions: clustered, shuffle. |
4732 | // * This limitation can be removed if necessary. |
4733 | // 4) host vk driver has maxTexelBufferSize >= 64M. |
4734 | // * Usually on desktop device the limit is more than 128M. we may switch to dynamic |
4735 | // decide cpu or gpu upload texture based on texture size. |
4736 | constexpr VkSubgroupFeatureFlags kRequiredSubgroupOp = |
4737 | VK_SUBGROUP_FEATURE_SHUFFLE_BIT | VK_SUBGROUP_FEATURE_CLUSTERED_BIT; |
4738 | static constexpr bool kSupportTranscodeEtcToBc = false; |
4739 | static constexpr uint32_t kMaxTexelBufferSize = 64 * 1024 * 1024; |
4740 | const VkPhysicalDeviceLimits &limitsVk = mPhysicalDeviceProperties.limits; |
4741 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsComputeTranscodeEtcToBc, |
4742 | !mPhysicalDeviceFeatures.textureCompressionETC2 && |
4743 | kSupportTranscodeEtcToBc && |
4744 | (mSubgroupProperties.supportedOperations & kRequiredSubgroupOp) == |
4745 | kRequiredSubgroupOp && |
4746 | (limitsVk.maxTexelBufferElements >= kMaxTexelBufferSize)); |
4747 | |
4748 | // http://anglebug.com/7308 |
4749 | // Flushing mutable textures causes flakes in perf tests using Windows/Intel GPU. Failures are |
4750 | // due to lost context/device. |
4751 | // http://b/278600575 |
4752 | // Flushing mutable texture is disabled for discrete GPUs to mitigate possible VRAM OOM. |
4753 | ANGLE_FEATURE_CONDITION( |
4754 | &mFeatures, mutableMipmapTextureUpload, |
4755 | canPreferDeviceLocalMemoryHostVisible(mPhysicalDeviceProperties.deviceType)); |
4756 | |
4757 | // Allow passthrough of EGL colorspace attributes on Android platform and for vendors that |
4758 | // are known to support wide color gamut. |
4759 | ANGLE_FEATURE_CONDITION(&mFeatures, eglColorspaceAttributePassthrough, |
4760 | IsAndroid() && isSamsung); |
4761 | |
4762 | // GBM does not have a VkSurface hence it does not support presentation through a Vulkan queue. |
4763 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsPresentation, !displayVk->isGBM()); |
4764 | |
4765 | // For tiled renderer, the renderpass query result may not available until the entire renderpass |
4766 | // is completed. This may cause a bubble in the application thread waiting result to be |
4767 | // available. When this feature flag is enabled, we will issue an immediate flush when we detect |
4768 | // there is switch from query enabled draw to query disabled draw. Since most apps uses bunch of |
4769 | // query back to back, this should only introduce one extra flush per frame. |
4770 | // https://issuetracker.google.com/250706693 |
4771 | ANGLE_FEATURE_CONDITION(&mFeatures, preferSubmitOnAnySamplesPassedQueryEnd, |
4772 | isTileBasedRenderer); |
4773 | |
4774 | // ARM driver appears having a bug that if we did not wait for submission to complete, but call |
4775 | // vkGetQueryPoolResults(VK_QUERY_RESULT_WAIT_BIT), it may result VK_NOT_READY. |
4776 | // https://issuetracker.google.com/253522366 |
4777 | // |
4778 | // Workaround for nvidia earlier version driver which appears having a bug that On older nvidia |
4779 | // driver, vkGetQueryPoolResult() with VK_QUERY_RESULT_WAIT_BIT may result in incorrect result. |
4780 | // In that case we force into CPU wait for submission to complete. http://anglebug.com/6692 |
4781 | ANGLE_FEATURE_CONDITION(&mFeatures, forceWaitForSubmissionToCompleteForQueryResult, |
4782 | isARM || (isNvidia && nvidiaVersion.major < 470u)); |
4783 | |
4784 | // Some ARM drivers may not free memory in "vkFreeCommandBuffers()" without |
4785 | // VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT flag. |
4786 | ANGLE_FEATURE_CONDITION(&mFeatures, useResetCommandBufferBitForSecondaryPools, isARM); |
4787 | |
4788 | // Required to pass android.media.cts.DecodeAccuracyTest with MESA Virtio-GPU Venus driver in |
4789 | // virtualized environment. https://issuetracker.google.com/246378938 |
4790 | ANGLE_FEATURE_CONDITION(&mFeatures, preferLinearFilterForYUV, isVenus); |
4791 | |
4792 | // Intel mesa drivers need depthBiasConstantFactor to be doubled to align with GL. |
4793 | ANGLE_FEATURE_CONDITION(&mFeatures, doubleDepthBiasConstantFactor, isIntel && !IsWindows()); |
4794 | |
4795 | // Required to pass android.media.codec.cts.EncodeDecodeTest with MESA Virtio-GPU Venus driver |
4796 | // in virtualized environment. https://issuetracker.google.com/246218584 |
4797 | ANGLE_FEATURE_CONDITION(&mFeatures, mapUnspecifiedColorSpaceToPassThrough, isVenus); |
4798 | |
4799 | ANGLE_FEATURE_CONDITION(&mFeatures, enablePipelineCacheDataCompression, true); |
4800 | |
4801 | ANGLE_FEATURE_CONDITION(&mFeatures, supportsTimelineSemaphore, |
4802 | mTimelineSemaphoreFeatures.timelineSemaphore == VK_TRUE); |
4803 | |
4804 | ApplyFeatureOverrides(features: &mFeatures, state: displayVk->getState()); |
4805 | |
4806 | // Disable memory report feature overrides if extension is not supported. |
4807 | if ((mFeatures.logMemoryReportCallbacks.enabled || mFeatures.logMemoryReportStats.enabled) && |
4808 | !mMemoryReportFeatures.deviceMemoryReport) |
4809 | { |
4810 | WARN() << "Disabling the following feature(s) because driver does not support " |
4811 | "VK_EXT_device_memory_report extension:" ; |
4812 | if (getFeatures().logMemoryReportStats.enabled) |
4813 | { |
4814 | WARN() << "\tlogMemoryReportStats" ; |
4815 | ANGLE_FEATURE_CONDITION(&mFeatures, logMemoryReportStats, false); |
4816 | } |
4817 | if (getFeatures().logMemoryReportCallbacks.enabled) |
4818 | { |
4819 | WARN() << "\tlogMemoryReportCallbacks" ; |
4820 | ANGLE_FEATURE_CONDITION(&mFeatures, logMemoryReportCallbacks, false); |
4821 | } |
4822 | } |
4823 | } |
4824 | |
4825 | void RendererVk::appBasedFeatureOverrides(DisplayVk *display, |
4826 | const vk::ExtensionNameList &extensions) |
4827 | { |
4828 | // NOOP for now. |
4829 | } |
4830 | |
4831 | angle::Result RendererVk::initPipelineCache(DisplayVk *display, |
4832 | vk::PipelineCache *pipelineCache, |
4833 | bool *success) |
4834 | { |
4835 | angle::MemoryBuffer initialData; |
4836 | ANGLE_TRY( |
4837 | GetAndDecompressPipelineCacheVk(mPhysicalDeviceProperties, display, &initialData, success)); |
4838 | |
4839 | VkPipelineCacheCreateInfo pipelineCacheCreateInfo = {}; |
4840 | |
4841 | pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; |
4842 | pipelineCacheCreateInfo.flags = 0; |
4843 | pipelineCacheCreateInfo.initialDataSize = *success ? initialData.size() : 0; |
4844 | pipelineCacheCreateInfo.pInitialData = *success ? initialData.data() : nullptr; |
4845 | |
4846 | if (display->getRenderer()->getFeatures().supportsPipelineCreationCacheControl.enabled) |
4847 | { |
4848 | pipelineCacheCreateInfo.flags |= VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT_EXT; |
4849 | } |
4850 | |
4851 | ANGLE_VK_TRY(display, pipelineCache->init(mDevice, pipelineCacheCreateInfo)); |
4852 | |
4853 | return angle::Result::Continue; |
4854 | } |
4855 | |
4856 | angle::Result RendererVk::getPipelineCache(vk::PipelineCacheAccess *pipelineCacheOut) |
4857 | { |
4858 | DisplayVk *displayVk = vk::GetImpl(glObject: mDisplay); |
4859 | |
4860 | // Note that ANGLE externally synchronizes the pipeline cache, and uses |
4861 | // VK_EXT_pipeline_creation_cache_control (where available) to disable internal synchronization. |
4862 | std::unique_lock<std::mutex> lock(mPipelineCacheMutex); |
4863 | |
4864 | if (!mPipelineCacheInitialized) |
4865 | { |
4866 | // We should now recreate the pipeline cache with the blob cache pipeline data. |
4867 | vk::PipelineCache pCache; |
4868 | bool loadedFromBlobCache = false; |
4869 | ANGLE_TRY(initPipelineCache(displayVk, &pCache, &loadedFromBlobCache)); |
4870 | if (loadedFromBlobCache) |
4871 | { |
4872 | // Merge the newly created pipeline cache into the existing one. |
4873 | mPipelineCache.merge(device: mDevice, srcCacheCount: 1, srcCaches: pCache.ptr()); |
4874 | |
4875 | ANGLE_TRY(getPipelineCacheSize(displayVk, &mPipelineCacheSizeAtLastSync)); |
4876 | } |
4877 | |
4878 | mPipelineCacheInitialized = true; |
4879 | pCache.destroy(device: mDevice); |
4880 | } |
4881 | |
4882 | pipelineCacheOut->init(pipelineCache: &mPipelineCache, mutex: &mPipelineCacheMutex); |
4883 | return angle::Result::Continue; |
4884 | } |
4885 | |
4886 | angle::Result RendererVk::mergeIntoPipelineCache(const vk::PipelineCache &pipelineCache) |
4887 | { |
4888 | vk::PipelineCacheAccess globalCache; |
4889 | ANGLE_TRY(getPipelineCache(&globalCache)); |
4890 | |
4891 | globalCache.merge(renderer: this, pipelineCache); |
4892 | |
4893 | return angle::Result::Continue; |
4894 | } |
4895 | |
4896 | const gl::Caps &RendererVk::getNativeCaps() const |
4897 | { |
4898 | ensureCapsInitialized(); |
4899 | return mNativeCaps; |
4900 | } |
4901 | |
4902 | const gl::TextureCapsMap &RendererVk::getNativeTextureCaps() const |
4903 | { |
4904 | ensureCapsInitialized(); |
4905 | return mNativeTextureCaps; |
4906 | } |
4907 | |
4908 | const gl::Extensions &RendererVk::getNativeExtensions() const |
4909 | { |
4910 | ensureCapsInitialized(); |
4911 | return mNativeExtensions; |
4912 | } |
4913 | |
4914 | const gl::Limitations &RendererVk::getNativeLimitations() const |
4915 | { |
4916 | ensureCapsInitialized(); |
4917 | return mNativeLimitations; |
4918 | } |
4919 | |
4920 | const ShPixelLocalStorageOptions &RendererVk::getNativePixelLocalStorageOptions() const |
4921 | { |
4922 | return mNativePLSOptions; |
4923 | } |
4924 | |
4925 | void RendererVk::initializeFrontendFeatures(angle::FrontendFeatures *features) const |
4926 | { |
4927 | const bool isSwiftShader = |
4928 | IsSwiftshader(vendorId: mPhysicalDeviceProperties.vendorID, deviceId: mPhysicalDeviceProperties.deviceID); |
4929 | |
4930 | // Hopefully-temporary work-around for a crash on SwiftShader. An Android process is turning |
4931 | // off GL error checking, and then asking ANGLE to write past the end of a buffer. |
4932 | // https://issuetracker.google.com/issues/220069903 |
4933 | ANGLE_FEATURE_CONDITION(features, forceGlErrorChecking, (IsAndroid() && isSwiftShader)); |
4934 | |
4935 | ANGLE_FEATURE_CONDITION(features, cacheCompiledShader, true); |
4936 | } |
4937 | |
4938 | angle::Result RendererVk::getPipelineCacheSize(DisplayVk *displayVk, size_t *pipelineCacheSizeOut) |
4939 | { |
4940 | VkResult result = mPipelineCache.getCacheData(device: mDevice, cacheSize: pipelineCacheSizeOut, cacheData: nullptr); |
4941 | ANGLE_VK_TRY(displayVk, result); |
4942 | |
4943 | return angle::Result::Continue; |
4944 | } |
4945 | |
4946 | angle::Result RendererVk::syncPipelineCacheVk(DisplayVk *displayVk, const gl::Context *context) |
4947 | { |
4948 | ASSERT(mPipelineCache.valid()); |
4949 | |
4950 | if (!mFeatures.syncMonolithicPipelinesToBlobCache.enabled) |
4951 | { |
4952 | return angle::Result::Continue; |
4953 | } |
4954 | |
4955 | if (--mPipelineCacheVkUpdateTimeout > 0) |
4956 | { |
4957 | return angle::Result::Continue; |
4958 | } |
4959 | |
4960 | mPipelineCacheVkUpdateTimeout = kPipelineCacheVkUpdatePeriod; |
4961 | |
4962 | size_t pipelineCacheSize = 0; |
4963 | ANGLE_TRY(getPipelineCacheSize(displayVk, &pipelineCacheSize)); |
4964 | if (pipelineCacheSize <= mPipelineCacheSizeAtLastSync) |
4965 | { |
4966 | return angle::Result::Continue; |
4967 | } |
4968 | mPipelineCacheSizeAtLastSync = pipelineCacheSize; |
4969 | |
4970 | // Make sure we will receive enough data to hold the pipeline cache header |
4971 | // Table 7. Layout for pipeline cache header version VK_PIPELINE_CACHE_HEADER_VERSION_ONE |
4972 | const size_t = 16 + VK_UUID_SIZE; |
4973 | if (pipelineCacheSize < kPipelineCacheHeaderSize) |
4974 | { |
4975 | // No pipeline cache data to read, so return |
4976 | return angle::Result::Continue; |
4977 | } |
4978 | |
4979 | ContextVk *contextVk = vk::GetImpl(glObject: context); |
4980 | |
4981 | // Use worker thread pool to complete compression. |
4982 | // If the last task hasn't been finished, skip the syncing. |
4983 | if (mCompressEvent && !mCompressEvent->isReady()) |
4984 | { |
4985 | ANGLE_PERF_WARNING(contextVk->getDebug(), GL_DEBUG_SEVERITY_LOW, |
4986 | "Skip syncing pipeline cache data when the last task is not ready." ); |
4987 | return angle::Result::Continue; |
4988 | } |
4989 | |
4990 | std::vector<uint8_t> pipelineCacheData(pipelineCacheSize); |
4991 | |
4992 | size_t oldPipelineCacheSize = pipelineCacheSize; |
4993 | VkResult result = |
4994 | mPipelineCache.getCacheData(device: mDevice, cacheSize: &pipelineCacheSize, cacheData: pipelineCacheData.data()); |
4995 | // We don't need all of the cache data, so just make sure we at least got the header |
4996 | // Vulkan Spec 9.6. Pipeline Cache |
4997 | // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/chap9.html#pipelines-cache |
4998 | // If pDataSize is less than what is necessary to store this header, nothing will be written to |
4999 | // pData and zero will be written to pDataSize. |
5000 | // Any data written to pData is valid and can be provided as the pInitialData member of the |
5001 | // VkPipelineCacheCreateInfo structure passed to vkCreatePipelineCache. |
5002 | if (ANGLE_UNLIKELY(pipelineCacheSize < kPipelineCacheHeaderSize)) |
5003 | { |
5004 | WARN() << "Not enough pipeline cache data read." ; |
5005 | return angle::Result::Continue; |
5006 | } |
5007 | else if (ANGLE_UNLIKELY(result == VK_INCOMPLETE)) |
5008 | { |
5009 | WARN() << "Received VK_INCOMPLETE: Old: " << oldPipelineCacheSize |
5010 | << ", New: " << pipelineCacheSize; |
5011 | } |
5012 | else |
5013 | { |
5014 | ANGLE_VK_TRY(displayVk, result); |
5015 | } |
5016 | |
5017 | // If vkGetPipelineCacheData ends up writing fewer bytes than requested, zero out the rest of |
5018 | // the buffer to avoid leaking garbage memory. |
5019 | ASSERT(pipelineCacheSize <= pipelineCacheData.size()); |
5020 | if (pipelineCacheSize < pipelineCacheData.size()) |
5021 | { |
5022 | memset(s: pipelineCacheData.data() + pipelineCacheSize, c: 0, |
5023 | n: pipelineCacheData.size() - pipelineCacheSize); |
5024 | } |
5025 | |
5026 | if (mFeatures.enableAsyncPipelineCacheCompression.enabled) |
5027 | { |
5028 | // zlib compression ratio normally ranges from 2:1 to 5:1. Set kMaxTotalSize to 64M to |
5029 | // ensure the size can fit into the 32MB blob cache limit on supported platforms. |
5030 | constexpr size_t kMaxTotalSize = 64 * 1024 * 1024; |
5031 | |
5032 | // Create task to compress. |
5033 | auto compressAndStorePipelineCacheTask = |
5034 | std::make_shared<CompressAndStorePipelineCacheTask>( |
5035 | args&: displayVk, args&: contextVk, args: std::move(pipelineCacheData), args: kMaxTotalSize); |
5036 | mCompressEvent = std::make_shared<WaitableCompressEventImpl>( |
5037 | args: context->getWorkerThreadPool()->postWorkerTask(task: compressAndStorePipelineCacheTask), |
5038 | args&: compressAndStorePipelineCacheTask); |
5039 | } |
5040 | else |
5041 | { |
5042 | // If enableAsyncPipelineCacheCompression is disabled, to avoid the risk, set kMaxTotalSize |
5043 | // to 64k. |
5044 | constexpr size_t kMaxTotalSize = 64 * 1024; |
5045 | CompressAndStorePipelineCacheVk(physicalDeviceProperties: mPhysicalDeviceProperties, displayVk, contextVk, |
5046 | cacheData: pipelineCacheData, maxTotalSize: kMaxTotalSize); |
5047 | } |
5048 | |
5049 | return angle::Result::Continue; |
5050 | } |
5051 | |
5052 | // These functions look at the mandatory format for support, and fallback to querying the device (if |
5053 | // necessary) to test the availability of the bits. |
5054 | bool RendererVk::hasLinearImageFormatFeatureBits(angle::FormatID formatID, |
5055 | const VkFormatFeatureFlags featureBits) const |
5056 | { |
5057 | return hasFormatFeatureBits<&VkFormatProperties::linearTilingFeatures>(formatID, featureBits); |
5058 | } |
5059 | |
5060 | VkFormatFeatureFlags RendererVk::getLinearImageFormatFeatureBits( |
5061 | angle::FormatID formatID, |
5062 | const VkFormatFeatureFlags featureBits) const |
5063 | { |
5064 | return getFormatFeatureBits<&VkFormatProperties::linearTilingFeatures>(formatID, featureBits); |
5065 | } |
5066 | |
5067 | VkFormatFeatureFlags RendererVk::getImageFormatFeatureBits( |
5068 | angle::FormatID formatID, |
5069 | const VkFormatFeatureFlags featureBits) const |
5070 | { |
5071 | return getFormatFeatureBits<&VkFormatProperties::optimalTilingFeatures>(formatID, featureBits); |
5072 | } |
5073 | |
5074 | bool RendererVk::hasImageFormatFeatureBits(angle::FormatID formatID, |
5075 | const VkFormatFeatureFlags featureBits) const |
5076 | { |
5077 | return hasFormatFeatureBits<&VkFormatProperties::optimalTilingFeatures>(formatID, featureBits); |
5078 | } |
5079 | |
5080 | bool RendererVk::hasBufferFormatFeatureBits(angle::FormatID formatID, |
5081 | const VkFormatFeatureFlags featureBits) const |
5082 | { |
5083 | return hasFormatFeatureBits<&VkFormatProperties::bufferFeatures>(formatID, featureBits); |
5084 | } |
5085 | |
5086 | void RendererVk::outputVmaStatString() |
5087 | { |
5088 | // Output the VMA stats string |
5089 | // This JSON string can be passed to VmaDumpVis.py to generate a visualization of the |
5090 | // allocations the VMA has performed. |
5091 | char *statsString; |
5092 | mAllocator.buildStatsString(statsString: &statsString, detailedMap: true); |
5093 | INFO() << std::endl << statsString << std::endl; |
5094 | mAllocator.freeStatsString(statsString); |
5095 | } |
5096 | |
5097 | angle::Result RendererVk::queueSubmitOneOff(vk::Context *context, |
5098 | vk::PrimaryCommandBuffer &&primary, |
5099 | vk::ProtectionType protectionType, |
5100 | egl::ContextPriority priority, |
5101 | VkSemaphore waitSemaphore, |
5102 | VkPipelineStageFlags waitSemaphoreStageMasks, |
5103 | vk::SubmitPolicy submitPolicy, |
5104 | QueueSerial *queueSerialOut) |
5105 | { |
5106 | ANGLE_TRACE_EVENT0("gpu.angle" , "RendererVk::queueSubmitOneOff" ); |
5107 | // Allocate a one off SerialIndex and generate a QueueSerial and then use it and release the |
5108 | // index. |
5109 | vk::ScopedQueueSerialIndex index; |
5110 | ANGLE_TRY(allocateScopedQueueSerialIndex(&index)); |
5111 | QueueSerial submitQueueSerial(index.get(), generateQueueSerial(index: index.get())); |
5112 | |
5113 | if (isAsyncCommandQueueEnabled()) |
5114 | { |
5115 | ANGLE_TRY(mCommandProcessor.enqueueSubmitOneOffCommands( |
5116 | context, protectionType, priority, primary.getHandle(), waitSemaphore, |
5117 | waitSemaphoreStageMasks, submitPolicy, submitQueueSerial)); |
5118 | } |
5119 | else |
5120 | { |
5121 | ANGLE_TRY(mCommandQueue.queueSubmitOneOff( |
5122 | context, protectionType, priority, primary.getHandle(), waitSemaphore, |
5123 | waitSemaphoreStageMasks, submitPolicy, submitQueueSerial)); |
5124 | } |
5125 | |
5126 | *queueSerialOut = submitQueueSerial; |
5127 | if (primary.valid()) |
5128 | { |
5129 | mOneOffCommandPoolMap[protectionType].releaseCommandBuffer(submitQueueSerial, |
5130 | primary: std::move(primary)); |
5131 | } |
5132 | |
5133 | ANGLE_TRY(mCommandQueue.postSubmitCheck(context)); |
5134 | |
5135 | return angle::Result::Continue; |
5136 | } |
5137 | |
5138 | angle::Result RendererVk::queueSubmitWaitSemaphore(vk::Context *context, |
5139 | egl::ContextPriority priority, |
5140 | const vk::Semaphore &waitSemaphore, |
5141 | VkPipelineStageFlags waitSemaphoreStageMasks, |
5142 | QueueSerial submitQueueSerial) |
5143 | { |
5144 | if (isAsyncCommandQueueEnabled()) |
5145 | { |
5146 | ANGLE_TRY(mCommandProcessor.enqueueSubmitOneOffCommands( |
5147 | context, vk::ProtectionType::Unprotected, priority, VK_NULL_HANDLE, |
5148 | waitSemaphore.getHandle(), waitSemaphoreStageMasks, vk::SubmitPolicy::AllowDeferred, |
5149 | submitQueueSerial)); |
5150 | } |
5151 | else |
5152 | { |
5153 | ANGLE_TRY(mCommandQueue.queueSubmitOneOff( |
5154 | context, vk::ProtectionType::Unprotected, priority, VK_NULL_HANDLE, |
5155 | waitSemaphore.getHandle(), waitSemaphoreStageMasks, vk::SubmitPolicy::AllowDeferred, |
5156 | submitQueueSerial)); |
5157 | } |
5158 | |
5159 | return angle::Result::Continue; |
5160 | } |
5161 | |
5162 | template <VkFormatFeatureFlags VkFormatProperties::*features> |
5163 | VkFormatFeatureFlags RendererVk::getFormatFeatureBits(angle::FormatID formatID, |
5164 | const VkFormatFeatureFlags featureBits) const |
5165 | { |
5166 | ASSERT(formatID != angle::FormatID::NONE); |
5167 | VkFormatProperties &deviceProperties = mFormatProperties[formatID]; |
5168 | |
5169 | if (deviceProperties.bufferFeatures == kInvalidFormatFeatureFlags) |
5170 | { |
5171 | // If we don't have the actual device features, see if the requested features are mandatory. |
5172 | // If so, there's no need to query the device. |
5173 | const VkFormatProperties &mandatoryProperties = vk::GetMandatoryFormatSupport(formatID); |
5174 | if (IsMaskFlagSet(mask: mandatoryProperties.*features, flag: featureBits)) |
5175 | { |
5176 | return featureBits; |
5177 | } |
5178 | |
5179 | VkFormat vkFormat = vk::GetVkFormatFromFormatID(actualFormatID: formatID); |
5180 | ASSERT(vkFormat != VK_FORMAT_UNDEFINED); |
5181 | |
5182 | // Otherwise query the format features and cache it. |
5183 | vkGetPhysicalDeviceFormatProperties(mPhysicalDevice, vkFormat, &deviceProperties); |
5184 | // Workaround for some Android devices that don't indicate filtering |
5185 | // support on D16_UNORM and they should. |
5186 | if (mFeatures.forceD16TexFilter.enabled && vkFormat == VK_FORMAT_D16_UNORM) |
5187 | { |
5188 | deviceProperties.*features |= VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT; |
5189 | } |
5190 | } |
5191 | |
5192 | return deviceProperties.*features & featureBits; |
5193 | } |
5194 | |
5195 | template <VkFormatFeatureFlags VkFormatProperties::*features> |
5196 | bool RendererVk::hasFormatFeatureBits(angle::FormatID formatID, |
5197 | const VkFormatFeatureFlags featureBits) const |
5198 | { |
5199 | return IsMaskFlagSet(getFormatFeatureBits<features>(formatID, featureBits), featureBits); |
5200 | } |
5201 | |
5202 | bool RendererVk::haveSameFormatFeatureBits(angle::FormatID formatID1, |
5203 | angle::FormatID formatID2) const |
5204 | { |
5205 | if (formatID1 == angle::FormatID::NONE || formatID2 == angle::FormatID::NONE) |
5206 | { |
5207 | return false; |
5208 | } |
5209 | |
5210 | constexpr VkFormatFeatureFlags kImageUsageFeatureBits = |
5211 | VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT | |
5212 | VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT; |
5213 | |
5214 | VkFormatFeatureFlags fmt1LinearFeatureBits = |
5215 | getLinearImageFormatFeatureBits(formatID: formatID1, featureBits: kImageUsageFeatureBits); |
5216 | VkFormatFeatureFlags fmt1OptimalFeatureBits = |
5217 | getImageFormatFeatureBits(formatID: formatID1, featureBits: kImageUsageFeatureBits); |
5218 | |
5219 | return hasLinearImageFormatFeatureBits(formatID: formatID2, featureBits: fmt1LinearFeatureBits) && |
5220 | hasImageFormatFeatureBits(formatID: formatID2, featureBits: fmt1OptimalFeatureBits); |
5221 | } |
5222 | |
5223 | void RendererVk::addBufferBlockToOrphanList(vk::BufferBlock *block) |
5224 | { |
5225 | std::unique_lock<std::mutex> lock(mGarbageMutex); |
5226 | mOrphanedBufferBlocks.emplace_back(args&: block); |
5227 | } |
5228 | |
5229 | void RendererVk::pruneOrphanedBufferBlocks() |
5230 | { |
5231 | for (auto iter = mOrphanedBufferBlocks.begin(); iter != mOrphanedBufferBlocks.end();) |
5232 | { |
5233 | if (!(*iter)->isEmpty()) |
5234 | { |
5235 | ++iter; |
5236 | continue; |
5237 | } |
5238 | (*iter)->destroy(renderer: this); |
5239 | iter = mOrphanedBufferBlocks.erase(position: iter); |
5240 | } |
5241 | } |
5242 | |
5243 | void RendererVk::cleanupGarbage() |
5244 | { |
5245 | std::unique_lock<std::mutex> lock(mGarbageMutex); |
5246 | |
5247 | // Clean up general garbages |
5248 | while (!mSharedGarbage.empty()) |
5249 | { |
5250 | vk::SharedGarbage &garbage = mSharedGarbage.front(); |
5251 | if (!garbage.destroyIfComplete(renderer: this)) |
5252 | { |
5253 | break; |
5254 | } |
5255 | mSharedGarbage.pop(); |
5256 | } |
5257 | |
5258 | // Clean up suballocation garbages |
5259 | VkDeviceSize suballocationBytesDestroyed = 0; |
5260 | while (!mSuballocationGarbage.empty()) |
5261 | { |
5262 | vk::SharedBufferSuballocationGarbage &garbage = mSuballocationGarbage.front(); |
5263 | VkDeviceSize garbageSize = garbage.getSize(); |
5264 | if (!garbage.destroyIfComplete(renderer: this)) |
5265 | { |
5266 | break; |
5267 | } |
5268 | // Actually destroyed. |
5269 | mSuballocationGarbage.pop(); |
5270 | suballocationBytesDestroyed += garbageSize; |
5271 | } |
5272 | mSuballocationGarbageDestroyed += suballocationBytesDestroyed; |
5273 | mSuballocationGarbageSizeInBytes -= suballocationBytesDestroyed; |
5274 | |
5275 | // Note: do this after clean up mSuballocationGarbage so that we will have more chances to find |
5276 | // orphaned blocks being empty. |
5277 | if (!mOrphanedBufferBlocks.empty()) |
5278 | { |
5279 | pruneOrphanedBufferBlocks(); |
5280 | } |
5281 | |
5282 | // Cache the value with atomic variable for access without mGarbageMutex lock. |
5283 | mSuballocationGarbageSizeInBytesCachedAtomic.store(d: mSuballocationGarbageSizeInBytes, |
5284 | m: std::memory_order_release); |
5285 | } |
5286 | |
5287 | void RendererVk::cleanupPendingSubmissionGarbage() |
5288 | { |
5289 | std::unique_lock<std::mutex> lock(mGarbageMutex); |
5290 | |
5291 | // Check if pending garbage is still pending. If not, move them to the garbage list. |
5292 | vk::SharedGarbageList pendingGarbage; |
5293 | while (!mPendingSubmissionGarbage.empty()) |
5294 | { |
5295 | vk::SharedGarbage &garbage = mPendingSubmissionGarbage.front(); |
5296 | if (garbage.hasResourceUseSubmitted(renderer: this)) |
5297 | { |
5298 | mSharedGarbage.push(v: std::move(garbage)); |
5299 | } |
5300 | else |
5301 | { |
5302 | pendingGarbage.push(v: std::move(garbage)); |
5303 | } |
5304 | mPendingSubmissionGarbage.pop(); |
5305 | } |
5306 | if (!pendingGarbage.empty()) |
5307 | { |
5308 | mPendingSubmissionGarbage = std::move(pendingGarbage); |
5309 | } |
5310 | |
5311 | vk::SharedBufferSuballocationGarbageList pendingSuballocationGarbage; |
5312 | while (!mPendingSubmissionSuballocationGarbage.empty()) |
5313 | { |
5314 | vk::SharedBufferSuballocationGarbage &suballocationGarbage = |
5315 | mPendingSubmissionSuballocationGarbage.front(); |
5316 | if (suballocationGarbage.hasResourceUseSubmitted(renderer: this)) |
5317 | { |
5318 | mSuballocationGarbageSizeInBytes += suballocationGarbage.getSize(); |
5319 | mSuballocationGarbage.push(v: std::move(suballocationGarbage)); |
5320 | } |
5321 | else |
5322 | { |
5323 | pendingSuballocationGarbage.push(v: std::move(suballocationGarbage)); |
5324 | } |
5325 | mPendingSubmissionSuballocationGarbage.pop(); |
5326 | } |
5327 | if (!pendingSuballocationGarbage.empty()) |
5328 | { |
5329 | mPendingSubmissionSuballocationGarbage = std::move(pendingSuballocationGarbage); |
5330 | } |
5331 | } |
5332 | |
5333 | void RendererVk::onNewValidationMessage(const std::string &message) |
5334 | { |
5335 | mLastValidationMessage = message; |
5336 | ++mValidationMessageCount; |
5337 | } |
5338 | |
5339 | void RendererVk::onFramebufferFetchUsed() |
5340 | { |
5341 | mIsFramebufferFetchUsed = true; |
5342 | } |
5343 | |
5344 | std::string RendererVk::getAndClearLastValidationMessage(uint32_t *countSinceLastClear) |
5345 | { |
5346 | *countSinceLastClear = mValidationMessageCount; |
5347 | mValidationMessageCount = 0; |
5348 | |
5349 | return std::move(mLastValidationMessage); |
5350 | } |
5351 | |
5352 | uint64_t RendererVk::getMaxFenceWaitTimeNs() const |
5353 | { |
5354 | constexpr uint64_t kMaxFenceWaitTimeNs = std::numeric_limits<uint64_t>::max(); |
5355 | |
5356 | return kMaxFenceWaitTimeNs; |
5357 | } |
5358 | |
5359 | void RendererVk::setGlobalDebugAnnotator() |
5360 | { |
5361 | // Install one of two DebugAnnotator classes: |
5362 | // |
5363 | // 1) The global class enables basic ANGLE debug functionality (e.g. Vulkan validation errors |
5364 | // will cause dEQP tests to fail). |
5365 | // |
5366 | // 2) The DebugAnnotatorVk class processes OpenGL ES commands that the application uses. It is |
5367 | // installed for the following purposes: |
5368 | // |
5369 | // 1) To enable calling the vkCmd*DebugUtilsLabelEXT functions in order to communicate to |
5370 | // debuggers (e.g. AGI) the OpenGL ES commands that the application uses. In addition to |
5371 | // simply installing DebugAnnotatorVk, also enable calling vkCmd*DebugUtilsLabelEXT. |
5372 | // |
5373 | // 2) To enable logging to Android logcat the OpenGL ES commands that the application uses. |
5374 | bool installDebugAnnotatorVk = false; |
5375 | |
5376 | // Enable calling the vkCmd*DebugUtilsLabelEXT functions if the vkCmd*DebugUtilsLabelEXT |
5377 | // functions exist, and if the kEnableDebugMarkersVarName environment variable is set. |
5378 | if (vkCmdBeginDebugUtilsLabelEXT) |
5379 | { |
5380 | // Use the GetAndSet variant to improve future lookup times |
5381 | std::string enabled = angle::GetAndSetEnvironmentVarOrUnCachedAndroidProperty( |
5382 | variableName: kEnableDebugMarkersVarName, propertyName: kEnableDebugMarkersPropertyName); |
5383 | if (!enabled.empty() && enabled.compare(s: "0" ) != 0) |
5384 | { |
5385 | mAngleDebuggerMode = true; |
5386 | installDebugAnnotatorVk = true; |
5387 | } |
5388 | } |
5389 | #if defined(ANGLE_ENABLE_TRACE_ANDROID_LOGCAT) |
5390 | // Only install DebugAnnotatorVk to log all API commands to Android's logcat. |
5391 | installDebugAnnotatorVk = true; |
5392 | #endif |
5393 | |
5394 | { |
5395 | std::unique_lock<std::mutex> lock(gl::GetDebugMutex()); |
5396 | if (installDebugAnnotatorVk) |
5397 | { |
5398 | gl::InitializeDebugAnnotations(debugAnnotator: &mAnnotator); |
5399 | } |
5400 | else |
5401 | { |
5402 | mDisplay->setGlobalDebugAnnotator(); |
5403 | } |
5404 | } |
5405 | } |
5406 | |
5407 | void RendererVk::reloadVolkIfNeeded() const |
5408 | { |
5409 | #if defined(ANGLE_SHARED_LIBVULKAN) |
5410 | if ((mInstance != VK_NULL_HANDLE) && (volkGetLoadedInstance() != mInstance)) |
5411 | { |
5412 | volkLoadInstance(instance: mInstance); |
5413 | } |
5414 | |
5415 | if ((mDevice != VK_NULL_HANDLE) && (volkGetLoadedDevice() != mDevice)) |
5416 | { |
5417 | volkLoadDevice(device: mDevice); |
5418 | } |
5419 | |
5420 | initializeInstanceExtensionEntryPointsFromCore(); |
5421 | initializeDeviceExtensionEntryPointsFromCore(); |
5422 | #endif // defined(ANGLE_SHARED_LIBVULKAN) |
5423 | } |
5424 | |
5425 | void RendererVk::initializeInstanceExtensionEntryPointsFromCore() const |
5426 | { |
5427 | if (isVulkan11Instance()) |
5428 | { |
5429 | InitGetPhysicalDeviceProperties2KHRFunctionsFromCore(); |
5430 | if (mFeatures.supportsExternalFenceCapabilities.enabled) |
5431 | { |
5432 | InitExternalFenceCapabilitiesFunctionsFromCore(); |
5433 | } |
5434 | if (mFeatures.supportsExternalSemaphoreCapabilities.enabled) |
5435 | { |
5436 | InitExternalSemaphoreCapabilitiesFunctionsFromCore(); |
5437 | } |
5438 | } |
5439 | } |
5440 | |
5441 | void RendererVk::initializeDeviceExtensionEntryPointsFromCore() const |
5442 | { |
5443 | if (isVulkan11Device()) |
5444 | { |
5445 | if (mFeatures.supportsGetMemoryRequirements2.enabled) |
5446 | { |
5447 | InitGetMemoryRequirements2KHRFunctionsFromCore(); |
5448 | } |
5449 | if (mFeatures.supportsBindMemory2.enabled) |
5450 | { |
5451 | InitBindMemory2KHRFunctionsFromCore(); |
5452 | } |
5453 | if (mFeatures.supportsYUVSamplerConversion.enabled) |
5454 | { |
5455 | InitSamplerYcbcrKHRFunctionsFromCore(); |
5456 | } |
5457 | } |
5458 | } |
5459 | |
5460 | angle::Result RendererVk::submitCommands(vk::Context *context, |
5461 | vk::ProtectionType protectionType, |
5462 | egl::ContextPriority contextPriority, |
5463 | const vk::Semaphore *signalSemaphore, |
5464 | const vk::SharedExternalFence *externalFence, |
5465 | const QueueSerial &submitQueueSerial) |
5466 | { |
5467 | ASSERT(signalSemaphore == nullptr || signalSemaphore->valid()); |
5468 | const VkSemaphore signalVkSemaphore = |
5469 | signalSemaphore ? signalSemaphore->getHandle() : VK_NULL_HANDLE; |
5470 | |
5471 | vk::SharedExternalFence externalFenceCopy; |
5472 | if (externalFence != nullptr) |
5473 | { |
5474 | externalFenceCopy = *externalFence; |
5475 | } |
5476 | |
5477 | if (isAsyncCommandQueueEnabled()) |
5478 | { |
5479 | ANGLE_TRY(mCommandProcessor.enqueueSubmitCommands( |
5480 | context, protectionType, contextPriority, signalVkSemaphore, |
5481 | std::move(externalFenceCopy), submitQueueSerial)); |
5482 | } |
5483 | else |
5484 | { |
5485 | ANGLE_TRY(mCommandQueue.submitCommands(context, protectionType, contextPriority, |
5486 | signalVkSemaphore, std::move(externalFenceCopy), |
5487 | submitQueueSerial)); |
5488 | } |
5489 | |
5490 | ANGLE_TRY(mCommandQueue.postSubmitCheck(context)); |
5491 | |
5492 | return angle::Result::Continue; |
5493 | } |
5494 | |
5495 | angle::Result RendererVk::submitPriorityDependency(vk::Context *context, |
5496 | vk::ProtectionTypes protectionTypes, |
5497 | egl::ContextPriority srcContextPriority, |
5498 | egl::ContextPriority dstContextPriority, |
5499 | SerialIndex index) |
5500 | { |
5501 | vk::RendererScoped<vk::ReleasableResource<vk::Semaphore>> semaphore(this); |
5502 | ANGLE_VK_TRY(context, semaphore.get().get().init(mDevice)); |
5503 | |
5504 | // First, submit already flushed commands / wait semaphores into the source Priority VkQueue. |
5505 | // Commands that are in the Secondary Command Buffers will be flushed into the new VkQueue. |
5506 | |
5507 | // Submit commands and attach Signal Semaphore. |
5508 | ASSERT(protectionTypes.any()); |
5509 | while (protectionTypes.any()) |
5510 | { |
5511 | vk::ProtectionType protectionType = protectionTypes.first(); |
5512 | protectionTypes.reset(pos: protectionType); |
5513 | |
5514 | QueueSerial queueSerial(index, generateQueueSerial(index)); |
5515 | // Submit semaphore only if this is the last submission (all into the same VkQueue). |
5516 | const vk::Semaphore *signalSemaphore = nullptr; |
5517 | if (protectionTypes.none()) |
5518 | { |
5519 | // Update QueueSerial to collect semaphore using the latest possible queueSerial. |
5520 | semaphore.get().setQueueSerial(queueSerial); |
5521 | signalSemaphore = &semaphore.get().get(); |
5522 | } |
5523 | ANGLE_TRY(submitCommands(context, protectionType, srcContextPriority, signalSemaphore, |
5524 | nullptr, queueSerial)); |
5525 | } |
5526 | |
5527 | // Submit only Wait Semaphore into the destination Priority (VkQueue). |
5528 | QueueSerial queueSerial(index, generateQueueSerial(index)); |
5529 | semaphore.get().setQueueSerial(queueSerial); |
5530 | ANGLE_TRY(queueSubmitWaitSemaphore(context, dstContextPriority, semaphore.get().get(), |
5531 | VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, queueSerial)); |
5532 | |
5533 | return angle::Result::Continue; |
5534 | } |
5535 | |
5536 | void RendererVk::handleDeviceLost() |
5537 | { |
5538 | if (isAsyncCommandQueueEnabled()) |
5539 | { |
5540 | mCommandProcessor.handleDeviceLost(renderer: this); |
5541 | } |
5542 | else |
5543 | { |
5544 | mCommandQueue.handleDeviceLost(renderer: this); |
5545 | } |
5546 | } |
5547 | |
5548 | angle::Result RendererVk::finishResourceUse(vk::Context *context, const vk::ResourceUse &use) |
5549 | { |
5550 | if (isAsyncCommandQueueEnabled()) |
5551 | { |
5552 | ANGLE_TRY(mCommandProcessor.waitForResourceUseToBeSubmitted(context, use)); |
5553 | } |
5554 | return mCommandQueue.finishResourceUse(context, use, timeout: getMaxFenceWaitTimeNs()); |
5555 | } |
5556 | |
5557 | angle::Result RendererVk::finishQueueSerial(vk::Context *context, const QueueSerial &queueSerial) |
5558 | { |
5559 | ASSERT(queueSerial.valid()); |
5560 | if (isAsyncCommandQueueEnabled()) |
5561 | { |
5562 | ANGLE_TRY(mCommandProcessor.waitForQueueSerialToBeSubmitted(context, queueSerial)); |
5563 | } |
5564 | return mCommandQueue.finishQueueSerial(context, queueSerial, timeout: getMaxFenceWaitTimeNs()); |
5565 | } |
5566 | |
5567 | angle::Result RendererVk::waitForResourceUseToFinishWithUserTimeout(vk::Context *context, |
5568 | const vk::ResourceUse &use, |
5569 | uint64_t timeout, |
5570 | VkResult *result) |
5571 | { |
5572 | ANGLE_TRACE_EVENT0("gpu.angle" , "RendererVk::waitForResourceUseToFinishWithUserTimeout" ); |
5573 | if (isAsyncCommandQueueEnabled()) |
5574 | { |
5575 | ANGLE_TRY(mCommandProcessor.waitForResourceUseToBeSubmitted(context, use)); |
5576 | } |
5577 | return mCommandQueue.waitForResourceUseToFinishWithUserTimeout(context, use, timeout, result); |
5578 | } |
5579 | |
5580 | angle::Result RendererVk::flushWaitSemaphores( |
5581 | vk::ProtectionType protectionType, |
5582 | egl::ContextPriority priority, |
5583 | std::vector<VkSemaphore> &&waitSemaphores, |
5584 | std::vector<VkPipelineStageFlags> &&waitSemaphoreStageMasks) |
5585 | { |
5586 | ANGLE_TRACE_EVENT0("gpu.angle" , "RendererVk::flushWaitSemaphores" ); |
5587 | if (isAsyncCommandQueueEnabled()) |
5588 | { |
5589 | ANGLE_TRY(mCommandProcessor.enqueueFlushWaitSemaphores(protectionType, priority, |
5590 | std::move(waitSemaphores), |
5591 | std::move(waitSemaphoreStageMasks))); |
5592 | } |
5593 | else |
5594 | { |
5595 | mCommandQueue.flushWaitSemaphores(protectionType, priority, waitSemaphores: std::move(waitSemaphores), |
5596 | waitSemaphoreStageMasks: std::move(waitSemaphoreStageMasks)); |
5597 | } |
5598 | |
5599 | return angle::Result::Continue; |
5600 | } |
5601 | |
5602 | angle::Result RendererVk::flushRenderPassCommands( |
5603 | vk::Context *context, |
5604 | vk::ProtectionType protectionType, |
5605 | egl::ContextPriority priority, |
5606 | const vk::RenderPass &renderPass, |
5607 | vk::RenderPassCommandBufferHelper **renderPassCommands) |
5608 | { |
5609 | ANGLE_TRACE_EVENT0("gpu.angle" , "RendererVk::flushRenderPassCommands" ); |
5610 | if (isAsyncCommandQueueEnabled()) |
5611 | { |
5612 | ANGLE_TRY(mCommandProcessor.enqueueFlushRenderPassCommands( |
5613 | context, protectionType, priority, renderPass, renderPassCommands)); |
5614 | } |
5615 | else |
5616 | { |
5617 | ANGLE_TRY(mCommandQueue.flushRenderPassCommands(context, protectionType, priority, |
5618 | renderPass, renderPassCommands)); |
5619 | } |
5620 | |
5621 | return angle::Result::Continue; |
5622 | } |
5623 | |
5624 | angle::Result RendererVk::flushOutsideRPCommands( |
5625 | vk::Context *context, |
5626 | vk::ProtectionType protectionType, |
5627 | egl::ContextPriority priority, |
5628 | vk::OutsideRenderPassCommandBufferHelper **outsideRPCommands) |
5629 | { |
5630 | ANGLE_TRACE_EVENT0("gpu.angle" , "RendererVk::flushOutsideRPCommands" ); |
5631 | if (isAsyncCommandQueueEnabled()) |
5632 | { |
5633 | ANGLE_TRY(mCommandProcessor.enqueueFlushOutsideRPCommands(context, protectionType, priority, |
5634 | outsideRPCommands)); |
5635 | } |
5636 | else |
5637 | { |
5638 | ANGLE_TRY(mCommandQueue.flushOutsideRPCommands(context, protectionType, priority, |
5639 | outsideRPCommands)); |
5640 | } |
5641 | |
5642 | return angle::Result::Continue; |
5643 | } |
5644 | |
5645 | void RendererVk::queuePresent(vk::Context *context, |
5646 | egl::ContextPriority priority, |
5647 | const VkPresentInfoKHR &presentInfo, |
5648 | vk::SwapchainStatus *swapchainStatus) |
5649 | { |
5650 | if (isAsyncCommandQueueEnabled()) |
5651 | { |
5652 | mCommandProcessor.enqueuePresent(contextPriority: priority, presentInfo, swapchainStatus); |
5653 | // lastPresentResult should always VK_SUCCESS when isPending is true |
5654 | ASSERT(!swapchainStatus->isPending || swapchainStatus->lastPresentResult == VK_SUCCESS); |
5655 | } |
5656 | else |
5657 | { |
5658 | mCommandQueue.queuePresent(contextPriority: priority, presentInfo, swapchainStatus); |
5659 | ASSERT(!swapchainStatus->isPending); |
5660 | } |
5661 | |
5662 | if (getFeatures().logMemoryReportStats.enabled) |
5663 | { |
5664 | mMemoryReport.logMemoryReportStats(); |
5665 | } |
5666 | } |
5667 | |
5668 | template <typename CommandBufferHelperT, typename RecyclerT> |
5669 | angle::Result RendererVk::getCommandBufferImpl( |
5670 | vk::Context *context, |
5671 | vk::SecondaryCommandPool *commandPool, |
5672 | vk::SecondaryCommandMemoryAllocator *commandsAllocator, |
5673 | RecyclerT *recycler, |
5674 | CommandBufferHelperT **commandBufferHelperOut) |
5675 | { |
5676 | return recycler->getCommandBufferHelper(context, commandPool, commandsAllocator, |
5677 | commandBufferHelperOut); |
5678 | } |
5679 | |
5680 | angle::Result RendererVk::getOutsideRenderPassCommandBufferHelper( |
5681 | vk::Context *context, |
5682 | vk::SecondaryCommandPool *commandPool, |
5683 | vk::SecondaryCommandMemoryAllocator *commandsAllocator, |
5684 | vk::OutsideRenderPassCommandBufferHelper **commandBufferHelperOut) |
5685 | { |
5686 | ANGLE_TRACE_EVENT0("gpu.angle" , "RendererVk::getOutsideRenderPassCommandBufferHelper" ); |
5687 | return getCommandBufferImpl(context, commandPool, commandsAllocator, |
5688 | recycler: &mOutsideRenderPassCommandBufferRecycler, commandBufferHelperOut); |
5689 | } |
5690 | |
5691 | angle::Result RendererVk::getRenderPassCommandBufferHelper( |
5692 | vk::Context *context, |
5693 | vk::SecondaryCommandPool *commandPool, |
5694 | vk::SecondaryCommandMemoryAllocator *commandsAllocator, |
5695 | vk::RenderPassCommandBufferHelper **commandBufferHelperOut) |
5696 | { |
5697 | ANGLE_TRACE_EVENT0("gpu.angle" , "RendererVk::getRenderPassCommandBufferHelper" ); |
5698 | return getCommandBufferImpl(context, commandPool, commandsAllocator, |
5699 | recycler: &mRenderPassCommandBufferRecycler, commandBufferHelperOut); |
5700 | } |
5701 | |
5702 | void RendererVk::recycleOutsideRenderPassCommandBufferHelper( |
5703 | vk::OutsideRenderPassCommandBufferHelper **commandBuffer) |
5704 | { |
5705 | ANGLE_TRACE_EVENT0("gpu.angle" , "RendererVk::recycleOutsideRenderPassCommandBufferHelper" ); |
5706 | mOutsideRenderPassCommandBufferRecycler.recycleCommandBufferHelper(commandBuffer); |
5707 | } |
5708 | |
5709 | void RendererVk::recycleRenderPassCommandBufferHelper( |
5710 | vk::RenderPassCommandBufferHelper **commandBuffer) |
5711 | { |
5712 | ANGLE_TRACE_EVENT0("gpu.angle" , "RendererVk::recycleRenderPassCommandBufferHelper" ); |
5713 | mRenderPassCommandBufferRecycler.recycleCommandBufferHelper(commandBuffer); |
5714 | } |
5715 | |
5716 | void RendererVk::logCacheStats() const |
5717 | { |
5718 | if (!vk::kOutputCumulativePerfCounters) |
5719 | { |
5720 | return; |
5721 | } |
5722 | |
5723 | std::unique_lock<std::mutex> localLock(mCacheStatsMutex); |
5724 | |
5725 | int cacheType = 0; |
5726 | INFO() << "Vulkan object cache hit ratios: " ; |
5727 | for (const CacheStats &stats : mVulkanCacheStats) |
5728 | { |
5729 | INFO() << " CacheType " << cacheType++ << ": " << stats.getHitRatio(); |
5730 | } |
5731 | } |
5732 | |
5733 | angle::Result RendererVk::getFormatDescriptorCountForVkFormat(ContextVk *contextVk, |
5734 | VkFormat format, |
5735 | uint32_t *descriptorCountOut) |
5736 | { |
5737 | if (mVkFormatDescriptorCountMap.count(key: format) == 0) |
5738 | { |
5739 | // Query device for descriptor count with basic values for most of |
5740 | // VkPhysicalDeviceImageFormatInfo2 members. |
5741 | VkPhysicalDeviceImageFormatInfo2 imageFormatInfo = {}; |
5742 | imageFormatInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2; |
5743 | imageFormatInfo.format = format; |
5744 | imageFormatInfo.type = VK_IMAGE_TYPE_2D; |
5745 | imageFormatInfo.tiling = VK_IMAGE_TILING_OPTIMAL; |
5746 | imageFormatInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; |
5747 | imageFormatInfo.flags = 0; |
5748 | |
5749 | VkImageFormatProperties imageFormatProperties = {}; |
5750 | VkSamplerYcbcrConversionImageFormatProperties ycbcrImageFormatProperties = {}; |
5751 | ycbcrImageFormatProperties.sType = |
5752 | VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES; |
5753 | |
5754 | VkImageFormatProperties2 imageFormatProperties2 = {}; |
5755 | imageFormatProperties2.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; |
5756 | imageFormatProperties2.pNext = &ycbcrImageFormatProperties; |
5757 | imageFormatProperties2.imageFormatProperties = imageFormatProperties; |
5758 | |
5759 | ANGLE_VK_TRY(contextVk, vkGetPhysicalDeviceImageFormatProperties2( |
5760 | mPhysicalDevice, &imageFormatInfo, &imageFormatProperties2)); |
5761 | |
5762 | mVkFormatDescriptorCountMap[format] = |
5763 | ycbcrImageFormatProperties.combinedImageSamplerDescriptorCount; |
5764 | } |
5765 | |
5766 | ASSERT(descriptorCountOut); |
5767 | *descriptorCountOut = mVkFormatDescriptorCountMap[format]; |
5768 | return angle::Result::Continue; |
5769 | } |
5770 | |
5771 | angle::Result RendererVk::getFormatDescriptorCountForExternalFormat(ContextVk *contextVk, |
5772 | uint64_t format, |
5773 | uint32_t *descriptorCountOut) |
5774 | { |
5775 | ASSERT(descriptorCountOut); |
5776 | |
5777 | // TODO: need to query for external formats as well once spec is fixed. http://anglebug.com/6141 |
5778 | ANGLE_VK_CHECK(contextVk, getFeatures().useMultipleDescriptorsForExternalFormats.enabled, |
5779 | VK_ERROR_INCOMPATIBLE_DRIVER); |
5780 | |
5781 | // Vulkan spec has a gap in that there is no mechanism available to query the immutable |
5782 | // sampler descriptor count of an external format. For now, return a default value. |
5783 | constexpr uint32_t kExternalFormatDefaultDescriptorCount = 4; |
5784 | *descriptorCountOut = kExternalFormatDefaultDescriptorCount; |
5785 | return angle::Result::Continue; |
5786 | } |
5787 | |
5788 | void RendererVk::onAllocateHandle(vk::HandleType handleType) |
5789 | { |
5790 | std::unique_lock<std::mutex> localLock(mActiveHandleCountsMutex); |
5791 | mActiveHandleCounts.onAllocate(handleType); |
5792 | } |
5793 | |
5794 | void RendererVk::onDeallocateHandle(vk::HandleType handleType) |
5795 | { |
5796 | std::unique_lock<std::mutex> localLock(mActiveHandleCountsMutex); |
5797 | mActiveHandleCounts.onDeallocate(handleType); |
5798 | } |
5799 | |
5800 | VkDeviceSize RendererVk::getPreferedBufferBlockSize(uint32_t memoryTypeIndex) const |
5801 | { |
5802 | // Try not to exceed 1/64 of heap size to begin with. |
5803 | const VkDeviceSize heapSize = getMemoryProperties().getHeapSizeForMemoryType(memoryType: memoryTypeIndex); |
5804 | return std::min(a: heapSize / 64, b: mPreferredLargeHeapBlockSize); |
5805 | } |
5806 | |
5807 | angle::Result RendererVk::allocateScopedQueueSerialIndex(vk::ScopedQueueSerialIndex *indexOut) |
5808 | { |
5809 | SerialIndex index; |
5810 | ANGLE_TRY(allocateQueueSerialIndex(&index)); |
5811 | indexOut->init(index, indexAllocator: &mQueueSerialIndexAllocator); |
5812 | return angle::Result::Continue; |
5813 | } |
5814 | |
5815 | angle::Result RendererVk::allocateQueueSerialIndex(SerialIndex *serialIndexOut) |
5816 | { |
5817 | *serialIndexOut = mQueueSerialIndexAllocator.allocate(); |
5818 | if (*serialIndexOut == kInvalidQueueSerialIndex) |
5819 | { |
5820 | return angle::Result::Stop; |
5821 | } |
5822 | return angle::Result::Continue; |
5823 | } |
5824 | |
5825 | void RendererVk::releaseQueueSerialIndex(SerialIndex index) |
5826 | { |
5827 | mQueueSerialIndexAllocator.release(index); |
5828 | } |
5829 | |
5830 | angle::Result RendererVk::finishOneCommandBatchAndCleanup(vk::Context *context, |
5831 | bool *anyBatchCleaned) |
5832 | { |
5833 | return mCommandQueue.finishOneCommandBatchAndCleanup(context, timeout: getMaxFenceWaitTimeNs(), |
5834 | anyFinished: anyBatchCleaned); |
5835 | } |
5836 | |
5837 | // static |
5838 | const char *RendererVk::GetVulkanObjectTypeName(VkObjectType type) |
5839 | { |
5840 | return GetVkObjectTypeName(type); |
5841 | } |
5842 | |
5843 | namespace vk |
5844 | { |
5845 | ImageMemorySuballocator::ImageMemorySuballocator() {} |
5846 | ImageMemorySuballocator::~ImageMemorySuballocator() {} |
5847 | |
5848 | void ImageMemorySuballocator::destroy(RendererVk *renderer) {} |
5849 | |
5850 | VkResult ImageMemorySuballocator::allocateAndBindMemory(Context *context, |
5851 | Image *image, |
5852 | const VkImageCreateInfo *imageCreateInfo, |
5853 | VkMemoryPropertyFlags requiredFlags, |
5854 | VkMemoryPropertyFlags preferredFlags, |
5855 | MemoryAllocationType memoryAllocationType, |
5856 | Allocation *allocationOut, |
5857 | VkMemoryPropertyFlags *memoryFlagsOut, |
5858 | uint32_t *memoryTypeIndexOut, |
5859 | VkDeviceSize *sizeOut) |
5860 | { |
5861 | ASSERT(image && image->valid()); |
5862 | ASSERT(allocationOut && !allocationOut->valid()); |
5863 | RendererVk *renderer = context->getRenderer(); |
5864 | const Allocator &allocator = renderer->getAllocator(); |
5865 | |
5866 | VkMemoryRequirements memoryRequirements; |
5867 | image->getMemoryRequirements(device: renderer->getDevice(), requirementsOut: &memoryRequirements); |
5868 | bool allocateDedicatedMemory = |
5869 | memoryRequirements.size >= kImageSizeThresholdForDedicatedMemoryAllocation; |
5870 | |
5871 | // Allocate and bind memory for the image. Try allocating on the device first. If unsuccessful, |
5872 | // it is possible to retry allocation after cleaning the garbage. |
5873 | VkResult result; |
5874 | bool anyBatchCleaned = false; |
5875 | uint32_t batchesWaitedAndCleaned = 0; |
5876 | |
5877 | do |
5878 | { |
5879 | result = vma::AllocateAndBindMemoryForImage( |
5880 | allocator: allocator.getHandle(), pImage: &image->mHandle, requiredFlags, preferredFlags, |
5881 | allocateDedicatedMemory, pAllocationOut: &allocationOut->mHandle, pMemoryTypeIndexOut: memoryTypeIndexOut, sizeOut); |
5882 | |
5883 | if (result != VK_SUCCESS) |
5884 | { |
5885 | // If there is an error in command batch finish, a device OOM error will be returned. |
5886 | if (renderer->finishOneCommandBatchAndCleanup(context, anyBatchCleaned: &anyBatchCleaned) == |
5887 | angle::Result::Stop) |
5888 | { |
5889 | return VK_ERROR_OUT_OF_DEVICE_MEMORY; |
5890 | } |
5891 | |
5892 | if (anyBatchCleaned) |
5893 | { |
5894 | batchesWaitedAndCleaned++; |
5895 | } |
5896 | } |
5897 | } while (result != VK_SUCCESS && anyBatchCleaned); |
5898 | |
5899 | if (batchesWaitedAndCleaned > 0) |
5900 | { |
5901 | INFO() << "Initial allocation failed. Waited for " << batchesWaitedAndCleaned |
5902 | << " commands to finish and free garbage | Allocation result: " |
5903 | << ((result == VK_SUCCESS) ? "SUCCESS" : "FAIL" ); |
5904 | } |
5905 | |
5906 | // If there is still no space for the new allocation, the allocation may still be made outside |
5907 | // the device, although it will result in performance penalty. |
5908 | if (result != VK_SUCCESS) |
5909 | { |
5910 | requiredFlags &= (~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
5911 | result = vma::AllocateAndBindMemoryForImage( |
5912 | allocator: allocator.getHandle(), pImage: &image->mHandle, requiredFlags, preferredFlags, |
5913 | allocateDedicatedMemory, pAllocationOut: &allocationOut->mHandle, pMemoryTypeIndexOut: memoryTypeIndexOut, sizeOut); |
5914 | |
5915 | INFO() |
5916 | << "Allocation failed. Removed the DEVICE_LOCAL bit requirement | Allocation result: " |
5917 | << ((result == VK_SUCCESS) ? "SUCCESS" : "FAIL" ); |
5918 | } |
5919 | |
5920 | // At the end, if all available options fail, we should return the appropriate out-of-memory |
5921 | // error. |
5922 | if (result != VK_SUCCESS) |
5923 | { |
5924 | // Record the failed memory allocation. |
5925 | uint32_t pendingMemoryTypeIndex; |
5926 | if (vma::FindMemoryTypeIndexForImageInfo( |
5927 | allocator: allocator.getHandle(), pImageCreateInfo: imageCreateInfo, requiredFlags, preferredFlags, |
5928 | allocateDedicatedMemory, pMemoryTypeIndexOut: &pendingMemoryTypeIndex) == VK_SUCCESS) |
5929 | { |
5930 | renderer->getMemoryAllocationTracker()->setPendingMemoryAlloc( |
5931 | allocType: memoryAllocationType, size: memoryRequirements.size, memoryTypeIndex: pendingMemoryTypeIndex); |
5932 | } |
5933 | |
5934 | return result; |
5935 | } |
5936 | |
5937 | // We need to get the property flags of the allocated memory. |
5938 | *memoryFlagsOut = |
5939 | renderer->getMemoryProperties().getMemoryType(i: *memoryTypeIndexOut).propertyFlags; |
5940 | if ((~(*memoryFlagsOut) & preferredFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0) |
5941 | { |
5942 | // For images allocated here, although allocation is preferred on the device, it is not |
5943 | // required. |
5944 | ASSERT((requiredFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0); |
5945 | renderer->getMemoryAllocationTracker()->compareExpectedFlagsWithAllocatedFlags( |
5946 | requiredFlags, preferredFlags, allocatedFlags: *memoryFlagsOut, |
5947 | handle: reinterpret_cast<void *>(allocationOut->getHandle())); |
5948 | context->getPerfCounters().deviceMemoryImageAllocationFallbacks++; |
5949 | } |
5950 | |
5951 | renderer->onMemoryAlloc(allocType: memoryAllocationType, size: *sizeOut, memoryTypeIndex: *memoryTypeIndexOut, |
5952 | handle: allocationOut->getHandle()); |
5953 | return VK_SUCCESS; |
5954 | } |
5955 | |
5956 | VkResult ImageMemorySuballocator::mapMemoryAndInitWithNonZeroValue(RendererVk *renderer, |
5957 | Allocation *allocation, |
5958 | VkDeviceSize size, |
5959 | int value, |
5960 | VkMemoryPropertyFlags flags) |
5961 | { |
5962 | ASSERT(allocation && allocation->valid()); |
5963 | const Allocator &allocator = renderer->getAllocator(); |
5964 | |
5965 | void *mappedMemoryData; |
5966 | VkResult result = vma::MapMemory(allocator: allocator.getHandle(), allocation: allocation->mHandle, ppData: &mappedMemoryData); |
5967 | if (result != VK_SUCCESS) |
5968 | { |
5969 | return result; |
5970 | } |
5971 | |
5972 | memset(s: mappedMemoryData, c: value, n: static_cast<size_t>(size)); |
5973 | vma::UnmapMemory(allocator: allocator.getHandle(), allocation: allocation->mHandle); |
5974 | |
5975 | // If the memory type is not host coherent, we perform an explicit flush. |
5976 | if ((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0) |
5977 | { |
5978 | vma::FlushAllocation(allocator: allocator.getHandle(), allocation: allocation->mHandle, offset: 0, VK_WHOLE_SIZE); |
5979 | } |
5980 | |
5981 | return VK_SUCCESS; |
5982 | } |
5983 | |
5984 | } // namespace vk |
5985 | } // namespace rx |
5986 | |