Blender V4.3
vk_device.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <sstream>
10
11#include "vk_backend.hh"
12#include "vk_context.hh"
13#include "vk_device.hh"
14#include "vk_memory.hh"
15#include "vk_state_manager.hh"
16#include "vk_storage_buffer.hh"
17#include "vk_texture.hh"
18#include "vk_vertex_buffer.hh"
19
20#include "GPU_capabilities.hh"
21
23
24#include "GHOST_C-api.h"
25
27
28namespace blender::gpu {
29
31{
32 samplers_.free();
33 samplers_.init();
34}
35
37{
38 if (!is_initialized()) {
39 return;
40 }
41
43 samplers_.free();
44
45 {
46 while (!thread_data_.is_empty()) {
47 VKThreadData *thread_data = thread_data_.pop_last();
48 thread_data->deinit(*this);
49 delete thread_data;
50 }
51 thread_data_.clear();
52 }
55 descriptor_set_layouts_.deinit();
56 vmaDestroyAllocator(mem_allocator_);
57 mem_allocator_ = VK_NULL_HANDLE;
58
59 debugging_tools_.deinit(vk_instance_);
60
61 vk_instance_ = VK_NULL_HANDLE;
62 vk_physical_device_ = VK_NULL_HANDLE;
63 vk_device_ = VK_NULL_HANDLE;
64 vk_queue_family_ = 0;
65 vk_queue_ = VK_NULL_HANDLE;
66 vk_physical_device_properties_ = {};
67 glsl_patch_.clear();
68}
69
71{
72 return vk_device_ != VK_NULL_HANDLE;
73}
74
75void VKDevice::init(void *ghost_context)
76{
78 void *queue_mutex = nullptr;
79 GHOST_GetVulkanHandles((GHOST_ContextHandle)ghost_context,
80 &vk_instance_,
81 &vk_physical_device_,
82 &vk_device_,
83 &vk_queue_family_,
84 &vk_queue_,
85 &queue_mutex);
86 queue_mutex_ = static_cast<std::mutex *>(queue_mutex);
87
88 init_physical_device_properties();
89 init_physical_device_memory_properties();
90 init_physical_device_features();
91 init_physical_device_extensions();
92 VKBackend::platform_init(*this);
94 init_functions();
95 init_debug_callbacks();
96 init_memory_allocator();
99
100 samplers_.init();
101 init_dummy_buffer();
102
103 debug::object_label(vk_handle(), "LogicalDevice");
104 debug::object_label(queue_get(), "GenericQueue");
106}
107
108void VKDevice::init_functions()
109{
110#define LOAD_FUNCTION(name) (PFN_##name) vkGetInstanceProcAddr(vk_instance_, STRINGIFY(name))
111 /* VK_KHR_dynamic_rendering */
112 functions.vkCmdBeginRendering = LOAD_FUNCTION(vkCmdBeginRenderingKHR);
113 functions.vkCmdEndRendering = LOAD_FUNCTION(vkCmdEndRenderingKHR);
114
115 /* VK_EXT_debug_utils */
116 functions.vkCmdBeginDebugUtilsLabel = LOAD_FUNCTION(vkCmdBeginDebugUtilsLabelEXT);
117 functions.vkCmdEndDebugUtilsLabel = LOAD_FUNCTION(vkCmdEndDebugUtilsLabelEXT);
118 functions.vkSetDebugUtilsObjectName = LOAD_FUNCTION(vkSetDebugUtilsObjectNameEXT);
119 functions.vkCreateDebugUtilsMessenger = LOAD_FUNCTION(vkCreateDebugUtilsMessengerEXT);
120 functions.vkDestroyDebugUtilsMessenger = LOAD_FUNCTION(vkDestroyDebugUtilsMessengerEXT);
121#undef LOAD_FUNCTION
122}
123
124void VKDevice::init_debug_callbacks()
125{
126 debugging_tools_.init(vk_instance_);
127}
128
129void VKDevice::init_physical_device_properties()
130{
131 BLI_assert(vk_physical_device_ != VK_NULL_HANDLE);
132
133 VkPhysicalDeviceProperties2 vk_physical_device_properties = {};
134 vk_physical_device_properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
135 vk_physical_device_driver_properties_.sType =
136 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
137 vk_physical_device_properties.pNext = &vk_physical_device_driver_properties_;
138
139 vkGetPhysicalDeviceProperties2(vk_physical_device_, &vk_physical_device_properties);
140 vk_physical_device_properties_ = vk_physical_device_properties.properties;
141}
142
143void VKDevice::init_physical_device_memory_properties()
144{
145 BLI_assert(vk_physical_device_ != VK_NULL_HANDLE);
146 vkGetPhysicalDeviceMemoryProperties(vk_physical_device_, &vk_physical_device_memory_properties_);
147}
148
149void VKDevice::init_physical_device_features()
150{
151 BLI_assert(vk_physical_device_ != VK_NULL_HANDLE);
152
153 VkPhysicalDeviceFeatures2 features = {};
154 features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
155 vk_physical_device_vulkan_11_features_.sType =
156 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES;
157 vk_physical_device_vulkan_12_features_.sType =
158 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
159
160 features.pNext = &vk_physical_device_vulkan_11_features_;
161 vk_physical_device_vulkan_11_features_.pNext = &vk_physical_device_vulkan_12_features_;
162
163 vkGetPhysicalDeviceFeatures2(vk_physical_device_, &features);
164 vk_physical_device_features_ = features.features;
165}
166
167void VKDevice::init_physical_device_extensions()
168{
169 uint32_t count = 0;
170 vkEnumerateDeviceExtensionProperties(vk_physical_device_, nullptr, &count, nullptr);
171 device_extensions_ = Array<VkExtensionProperties>(count);
172 vkEnumerateDeviceExtensionProperties(
173 vk_physical_device_, nullptr, &count, device_extensions_.data());
174}
175
176bool VKDevice::supports_extension(const char *extension_name) const
177{
178 for (const VkExtensionProperties &vk_extension_properties : device_extensions_) {
179 if (STREQ(vk_extension_properties.extensionName, extension_name)) {
180 return true;
181 }
182 }
183 return false;
184}
185
186void VKDevice::init_memory_allocator()
187{
189 VmaAllocatorCreateInfo info = {};
190 info.vulkanApiVersion = VK_API_VERSION_1_2;
191 info.physicalDevice = vk_physical_device_;
192 info.device = vk_device_;
193 info.instance = vk_instance_;
194 info.pAllocationCallbacks = vk_allocation_callbacks;
195 vmaCreateAllocator(&info, &mem_allocator_);
196}
197
198void VKDevice::init_dummy_buffer()
199{
202 VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
204 /* Default dummy buffer. Set the 4th element to 1 to fix missing orcos. */
205 float data[16] = {
206 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
207 dummy_buffer.update_immediately(static_cast<void *>(data));
208}
209
211{
212 std::stringstream ss;
213
214 ss << "#version 450\n";
216 ss << "#extension GL_ARB_shader_draw_parameters : enable\n";
217 ss << "#define GPU_ARB_shader_draw_parameters\n";
218 ss << "#define gpu_BaseInstance (gl_BaseInstanceARB)\n";
219 }
220
221 ss << "#define gl_VertexID gl_VertexIndex\n";
222 ss << "#define gpu_InstanceIndex (gl_InstanceIndex)\n";
223 ss << "#define gl_InstanceID (gpu_InstanceIndex - gpu_BaseInstance)\n";
224
225 ss << "#extension GL_ARB_shader_viewport_layer_array: enable\n";
227 ss << "#extension GL_ARB_shader_stencil_export: enable\n";
228 ss << "#define GPU_ARB_shader_stencil_export 1\n";
229 }
230 if (!workarounds_.shader_output_layer) {
231 ss << "#define gpu_Layer gl_Layer\n";
232 }
233 if (!workarounds_.shader_output_viewport_index) {
234 ss << "#define gpu_ViewportIndex gl_ViewportIndex\n";
235 }
236 if (!workarounds_.fragment_shader_barycentric) {
237 ss << "#extension GL_EXT_fragment_shader_barycentric : require\n";
238 ss << "#define gpu_BaryCoord gl_BaryCoordEXT\n";
239 ss << "#define gpu_BaryCoordNoPersp gl_BaryCoordNoPerspEXT\n";
240 }
241
242 ss << "#define DFDX_SIGN 1.0\n";
243 ss << "#define DFDY_SIGN 1.0\n";
244
245 /* GLSL Backend Lib. */
247 glsl_patch_ = ss.str();
248}
249
250const char *VKDevice::glsl_patch_get() const
251{
252 BLI_assert(!glsl_patch_.empty());
253 return glsl_patch_.c_str();
254}
255
256/* -------------------------------------------------------------------- */
260constexpr int32_t PCI_ID_NVIDIA = 0x10de;
261constexpr int32_t PCI_ID_INTEL = 0x8086;
262constexpr int32_t PCI_ID_AMD = 0x1002;
263constexpr int32_t PCI_ID_ATI = 0x1022;
264constexpr int32_t PCI_ID_APPLE = 0x106b;
265
267{
268 switch (vk_physical_device_driver_properties_.driverID) {
269 case VK_DRIVER_ID_AMD_PROPRIETARY:
270 case VK_DRIVER_ID_AMD_OPEN_SOURCE:
271 case VK_DRIVER_ID_MESA_RADV:
272 return GPU_DEVICE_ATI;
273
274 case VK_DRIVER_ID_NVIDIA_PROPRIETARY:
275 case VK_DRIVER_ID_MESA_NVK:
276 return GPU_DEVICE_NVIDIA;
277
278 case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS:
279 case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA:
280 return GPU_DEVICE_INTEL;
281
282 case VK_DRIVER_ID_QUALCOMM_PROPRIETARY:
283 return GPU_DEVICE_QUALCOMM;
284
285 case VK_DRIVER_ID_MOLTENVK:
286 return GPU_DEVICE_APPLE;
287
288 case VK_DRIVER_ID_MESA_LLVMPIPE:
289 return GPU_DEVICE_SOFTWARE;
290
291 default:
292 return GPU_DEVICE_UNKNOWN;
293 }
294
295 return GPU_DEVICE_UNKNOWN;
296}
297
299{
300 switch (vk_physical_device_driver_properties_.driverID) {
301 case VK_DRIVER_ID_AMD_PROPRIETARY:
302 case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS:
303 case VK_DRIVER_ID_NVIDIA_PROPRIETARY:
304 case VK_DRIVER_ID_QUALCOMM_PROPRIETARY:
305 return GPU_DRIVER_OFFICIAL;
306
307 case VK_DRIVER_ID_MOLTENVK:
308 case VK_DRIVER_ID_AMD_OPEN_SOURCE:
309 case VK_DRIVER_ID_MESA_RADV:
310 case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA:
311 case VK_DRIVER_ID_MESA_NVK:
313
314 case VK_DRIVER_ID_MESA_LLVMPIPE:
315 return GPU_DRIVER_SOFTWARE;
316
317 default:
318 return GPU_DRIVER_ANY;
319 }
320
321 return GPU_DRIVER_ANY;
322}
323
324std::string VKDevice::vendor_name() const
325{
326 /* Below 0x10000 are the PCI vendor IDs (https://pcisig.com/membership/member-companies) */
327 if (vk_physical_device_properties_.vendorID < 0x10000) {
328 switch (vk_physical_device_properties_.vendorID) {
329 case PCI_ID_AMD:
330 case PCI_ID_ATI:
331 return "Advanced Micro Devices";
332 case PCI_ID_NVIDIA:
333 return "NVIDIA Corporation";
334 case PCI_ID_INTEL:
335 return "Intel Corporation";
336 case PCI_ID_APPLE:
337 return "Apple";
338 default:
339 return std::to_string(vk_physical_device_properties_.vendorID);
340 }
341 }
342 else {
343 /* above 0x10000 should be vkVendorIDs
344 * NOTE: When debug_messaging landed we can use something similar to
345 * vk::to_string(vk::VendorId(properties.vendorID));
346 */
347 return std::to_string(vk_physical_device_properties_.vendorID);
348 }
349}
350
351std::string VKDevice::driver_version() const
352{
353 return StringRefNull(vk_physical_device_driver_properties_.driverName) + " " +
354 StringRefNull(vk_physical_device_driver_properties_.driverInfo);
355}
356
359/* -------------------------------------------------------------------- */
363VKThreadData::VKThreadData(VKDevice &device, pthread_t thread_id) : thread_id(thread_id)
364{
365 for (VKResourcePool &resource_pool : resource_pools) {
366 resource_pool.init(device);
367 }
368}
369
371{
372 for (VKResourcePool &resource_pool : resource_pools) {
373 resource_pool.deinit(device);
374 }
375}
376
379/* -------------------------------------------------------------------- */
384{
385 std::scoped_lock mutex(resources.mutex);
386 pthread_t current_thread_id = pthread_self();
387
388 for (VKThreadData *thread_data : thread_data_) {
389 if (pthread_equal(thread_data->thread_id, current_thread_id)) {
390 return *thread_data;
391 }
392 }
393
394 VKThreadData *thread_data = new VKThreadData(*this, current_thread_id);
395 thread_data_.append(thread_data);
396 return *thread_data;
397}
398
400{
401 std::scoped_lock mutex(resources.mutex);
402 pthread_t current_thread_id = pthread_self();
403 if (BLI_thread_is_main()) {
404 for (VKThreadData *thread_data : thread_data_) {
405 if (pthread_equal(thread_data->thread_id, current_thread_id)) {
406 return thread_data->resource_pool_get().discard_pool;
407 }
408 }
409 }
410
411 return orphaned_data;
412}
413
415{
416 contexts_.append(std::reference_wrapper(context));
417}
418
420{
421 contexts_.remove(contexts_.first_index_of(std::reference_wrapper(context)));
422}
424{
425 return contexts_;
426};
427
428void VKDevice::memory_statistics_get(int *r_total_mem_kb, int *r_free_mem_kb) const
429{
430 VmaBudget budgets[VK_MAX_MEMORY_HEAPS];
431 vmaGetHeapBudgets(mem_allocator_get(), budgets);
432 VkDeviceSize total_mem = 0;
433 VkDeviceSize used_mem = 0;
434
435 for (int memory_heap_index : IndexRange(vk_physical_device_memory_properties_.memoryHeapCount)) {
436 const VkMemoryHeap &memory_heap =
437 vk_physical_device_memory_properties_.memoryHeaps[memory_heap_index];
438 const VmaBudget &budget = budgets[memory_heap_index];
439
440 /* Skip host memory-heaps. */
441 if (!bool(memory_heap.flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT)) {
442 continue;
443 }
444
445 total_mem += memory_heap.size;
446 used_mem += budget.usage;
447 }
448
449 *r_total_mem_kb = int(total_mem / 1024);
450 *r_free_mem_kb = int((total_mem - used_mem) / 1024);
451}
452
455/* -------------------------------------------------------------------- */
459void VKDevice::debug_print(std::ostream &os, const VKDiscardPool &discard_pool)
460{
461 if (discard_pool.images_.is_empty() && discard_pool.buffers_.is_empty() &&
462 discard_pool.image_views_.is_empty() && discard_pool.shader_modules_.is_empty() &&
463 discard_pool.pipeline_layouts_.is_empty())
464 {
465 return;
466 }
467 os << " Discardable resources: ";
468 if (!discard_pool.images_.is_empty()) {
469 os << "VkImage=" << discard_pool.images_.size() << " ";
470 }
471 if (!discard_pool.image_views_.is_empty()) {
472 os << "VkImageView=" << discard_pool.image_views_.size() << " ";
473 }
474 if (!discard_pool.buffers_.is_empty()) {
475 os << "VkBuffer=" << discard_pool.buffers_.size() << " ";
476 }
477 if (!discard_pool.shader_modules_.is_empty()) {
478 os << "VkShaderModule=" << discard_pool.shader_modules_.size() << " ";
479 }
480 if (!discard_pool.pipeline_layouts_.is_empty()) {
481 os << "VkPipelineLayout=" << discard_pool.pipeline_layouts_.size();
482 }
483 os << "\n";
484}
485
487{
489 "VKDevice::debug_print can only be called from the main thread.");
490
491 std::ostream &os = std::cout;
492
493 os << "Pipelines\n";
494 os << " Graphics: " << pipelines.graphic_pipelines_.size() << "\n";
495 os << " Compute: " << pipelines.compute_pipelines_.size() << "\n";
496 os << "Descriptor sets\n";
497 os << " VkDescriptorSetLayouts: " << descriptor_set_layouts_.size() << "\n";
498 for (const VKThreadData *thread_data : thread_data_) {
499 /* NOTE: Assumption that this is always called form the main thread. This could be solved by
500 * keeping track of the main thread inside the thread data.*/
501 const bool is_main = pthread_equal(thread_data->thread_id, pthread_self());
502 os << "ThreadData" << (is_main ? " (main-thread)" : "") << ")\n";
503 os << " Rendering_depth: " << thread_data->rendering_depth << "\n";
504 for (int resource_pool_index : IndexRange(thread_data->resource_pools.size())) {
505 const VKResourcePool &resource_pool = thread_data->resource_pools[resource_pool_index];
506 const bool is_active = thread_data->resource_pool_index == resource_pool_index;
507 os << " Resource Pool (index=" << resource_pool_index << (is_active ? " active" : "")
508 << ")\n";
509 debug_print(os, resource_pool.discard_pool);
510 }
511 }
512 os << "Orphaned data\n";
514 os << "\n";
515}
516
519} // namespace blender::gpu
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
int BLI_thread_is_main(void)
Definition threads.cc:179
#define STREQ(a, b)
ThreadMutex mutex
GHOST C-API function and type declarations.
bool GPU_stencil_export_support()
bool GPU_shader_draw_parameters_support()
eGPUDriverType
@ GPU_DRIVER_ANY
@ GPU_DRIVER_OFFICIAL
@ GPU_DRIVER_OPENSOURCE
@ GPU_DRIVER_SOFTWARE
eGPUDeviceType
@ GPU_DEVICE_UNKNOWN
@ GPU_DEVICE_ATI
@ GPU_DEVICE_QUALCOMM
@ GPU_DEVICE_SOFTWARE
@ GPU_DEVICE_NVIDIA
@ GPU_DEVICE_APPLE
@ GPU_DEVICE_INTEL
@ GPU_USAGE_DEVICE_ONLY
const T * data() const
Definition BLI_array.hh:301
int64_t size() const
bool is_empty() const
static void capabilities_init(VKDevice &device)
void update_immediately(const void *data) const
Definition vk_buffer.cc:109
bool create(size_t size, GPUUsageType usage, VkBufferUsageFlags buffer_usage, bool is_host_visible=true)
Definition vk_buffer.cc:53
VkBuffer vk_handle() const
Definition vk_buffer.hh:69
VKPipelinePool pipelines
Definition vk_device.hh:174
void init(void *ghost_context)
Definition vk_device.cc:75
render_graph::VKResourceStateTracker resources
Definition vk_device.hh:172
VmaAllocator mem_allocator_get() const
Definition vk_device.hh:243
VkQueue queue_get() const
Definition vk_device.hh:229
VkDevice vk_handle() const
Definition vk_device.hh:224
bool supports_extension(const char *extension_name) const
Definition vk_device.cc:176
std::string vendor_name() const
Definition vk_device.cc:324
std::string driver_version() const
Definition vk_device.cc:351
VKDiscardPool orphaned_data
Definition vk_device.hh:173
VKThreadData & current_thread_data()
Definition vk_device.cc:383
eGPUDriverType driver_type() const
Definition vk_device.cc:298
VKDiscardPool & discard_pool_for_current_thread()
Definition vk_device.cc:399
const char * glsl_patch_get() const
Definition vk_device.cc:250
void context_register(VKContext &context)
Definition vk_device.cc:414
bool is_initialized() const
Definition vk_device.cc:70
void context_unregister(VKContext &context)
Definition vk_device.cc:419
void memory_statistics_get(int *r_total_mem_kb, int *r_free_mem_kb) const
Definition vk_device.cc:428
struct blender::gpu::VKDevice::@670 functions
Span< std::reference_wrapper< VKContext > > contexts_get() const
Definition vk_device.cc:423
eGPUDeviceType device_type() const
Definition vk_device.cc:266
std::array< VKResourcePool, resource_pools_count > resource_pools
Definition vk_device.hh:87
VKThreadData(VKDevice &device, pthread_t thread_id)
Definition vk_device.cc:363
void deinit(VKDevice &device)
Definition vk_device.cc:370
void init(VkInstance vk_instance)
Definition vk_debug.cc:100
void deinit(VkInstance vk_instance)
Definition vk_debug.cc:106
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
char datatoc_glsl_shader_defines_glsl[]
Definition gl_shader.cc:44
int count
void object_label(GLenum type, GLuint object, const char *name)
Definition gl_debug.cc:344
constexpr int32_t PCI_ID_NVIDIA
Definition vk_device.cc:260
constexpr int32_t PCI_ID_INTEL
Definition vk_device.cc:261
constexpr int32_t PCI_ID_ATI
Definition vk_device.cc:263
constexpr int32_t PCI_ID_AMD
Definition vk_device.cc:262
constexpr int32_t PCI_ID_APPLE
Definition vk_device.cc:264
MatBase< float, 4, 4 > float4x4
unsigned int uint32_t
Definition stdint.h:80
signed int int32_t
Definition stdint.h:77
char datatoc_glsl_shader_defines_glsl[]
Definition vk_device.cc:26
#define LOAD_FUNCTION(name)
#define VK_ALLOCATION_CALLBACKS
Definition vk_memory.hh:58