vulkan_loader.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*
  2. * This file is part of FFmpeg.
  3. *
  4. * FFmpeg is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * FFmpeg is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with FFmpeg; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #ifndef AVUTIL_VULKAN_LOADER_H
  19. #define AVUTIL_VULKAN_LOADER_H
  20. #include <stdio.h>
  21. #include "avassert.h"
  22. #include "vulkan_functions.h"
  23. /* Macro to turn a function name into a loader struct */
  24. #define PFN_LOAD_INFO(req_inst, req_dev, ext_flag, name) \
  25. { \
  26. req_inst, \
  27. req_dev, \
  28. offsetof(FFVulkanFunctions, name), \
  29. ext_flag, \
  30. },
  31. static inline uint64_t ff_vk_extensions_to_mask(const char * const *extensions,
  32. int nb_extensions)
  33. {
  34. static const struct ExtensionMap {
  35. const char *name;
  36. FFVulkanExtensions flag;
  37. } extension_map[] = {
  38. { VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_DMABUF_MEMORY },
  39. { VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME, FF_VK_EXT_DRM_MODIFIER_FLAGS },
  40. { VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_FD_MEMORY },
  41. { VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_FD_SEM },
  42. { VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_HOST_MEMORY },
  43. { VK_EXT_DEBUG_UTILS_EXTENSION_NAME, FF_VK_EXT_DEBUG_UTILS },
  44. { VK_EXT_PHYSICAL_DEVICE_DRM_EXTENSION_NAME, FF_VK_EXT_DEVICE_DRM },
  45. { VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME, FF_VK_EXT_ATOMIC_FLOAT },
  46. { VK_KHR_COOPERATIVE_MATRIX_EXTENSION_NAME, FF_VK_EXT_COOP_MATRIX },
  47. { VK_NV_OPTICAL_FLOW_EXTENSION_NAME, FF_VK_EXT_OPTICAL_FLOW },
  48. { VK_EXT_SHADER_OBJECT_EXTENSION_NAME, FF_VK_EXT_SHADER_OBJECT },
  49. { VK_KHR_VIDEO_MAINTENANCE_1_EXTENSION_NAME, FF_VK_EXT_VIDEO_MAINTENANCE_1 },
  50. #ifdef _WIN32
  51. { VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_WIN32_MEMORY },
  52. { VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, FF_VK_EXT_EXTERNAL_WIN32_SEM },
  53. #endif
  54. { VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME, FF_VK_EXT_DESCRIPTOR_BUFFER, },
  55. { VK_KHR_VIDEO_QUEUE_EXTENSION_NAME, FF_VK_EXT_VIDEO_QUEUE },
  56. { VK_KHR_VIDEO_ENCODE_QUEUE_EXTENSION_NAME, FF_VK_EXT_VIDEO_ENCODE_QUEUE },
  57. { VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_QUEUE },
  58. { VK_KHR_VIDEO_ENCODE_H264_EXTENSION_NAME, FF_VK_EXT_VIDEO_ENCODE_H264 },
  59. { VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_H264 },
  60. { VK_KHR_VIDEO_ENCODE_H265_EXTENSION_NAME, FF_VK_EXT_VIDEO_ENCODE_H265 },
  61. { VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_H265 },
  62. { VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME, FF_VK_EXT_VIDEO_DECODE_AV1 },
  63. { VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, FF_VK_EXT_PUSH_DESCRIPTOR },
  64. };
  65. FFVulkanExtensions mask = 0x0;
  66. for (int i = 0; i < nb_extensions; i++) {
  67. for (int j = 0; j < FF_ARRAY_ELEMS(extension_map); j++) {
  68. if (!strcmp(extensions[i], extension_map[j].name)) {
  69. mask |= extension_map[j].flag;
  70. continue;
  71. }
  72. }
  73. }
  74. return mask;
  75. }
  76. /**
  77. * Function loader.
  78. * Vulkan function from scratch loading happens in 3 stages - the first one
  79. * is before any initialization has happened, and you have neither an instance
  80. * structure nor a device structure. At this stage, you can only get the bare
  81. * minimals to initialize an instance.
  82. * The second stage is when you have an instance. At this stage, you can
  83. * initialize a VkDevice, and have an idea of what extensions each device
  84. * supports.
  85. * Finally, in the third stage, you can proceed and load all core functions,
  86. * plus you can be sure that any extensions you've enabled during device
  87. * initialization will be available.
  88. */
  89. static inline int ff_vk_load_functions(AVHWDeviceContext *ctx,
  90. FFVulkanFunctions *vk,
  91. uint64_t extensions_mask,
  92. int has_inst, int has_dev)
  93. {
  94. AVVulkanDeviceContext *hwctx = ctx->hwctx;
  95. static const struct FunctionLoadInfo {
  96. char req_inst;
  97. char req_dev;
  98. uint16_t struct_offset;
  99. FFVulkanExtensions ext_flag;
  100. } vk_load_info[] = {
  101. FN_LIST(PFN_LOAD_INFO)
  102. #ifdef _WIN32
  103. FN_LIST_WIN32(PFN_LOAD_INFO)
  104. #endif
  105. };
  106. // Concatenate the names to avoid relocations. The resulting string
  107. // will end with \0\0
  108. #define FUNC_NAME(req_inst, req_dev, ext_flag, name) "vk"#name"\0"
  109. const char *name =
  110. FN_LIST(FUNC_NAME)
  111. #ifdef _WIN32
  112. FN_LIST_WIN32(FUNC_NAME)
  113. #endif
  114. ;
  115. #undef FUNC_NAME
  116. for (int i = 0; i < FF_ARRAY_ELEMS(vk_load_info); name += strlen(name) + 1, i++) {
  117. const struct FunctionLoadInfo *load = &vk_load_info[i];
  118. static const char extensions[][4] = { "", "EXT", "KHR" };
  119. PFN_vkVoidFunction fn;
  120. if (load->req_dev && !has_dev)
  121. continue;
  122. if (load->req_inst && !has_inst)
  123. continue;
  124. for (int j = 0; j < FF_ARRAY_ELEMS(extensions); j++) {
  125. char ext_name[128];
  126. av_unused int n;
  127. n = snprintf(ext_name, sizeof(ext_name), "%s%s", name, extensions[j]);
  128. av_assert1(n < sizeof(ext_name));
  129. if (load->req_dev)
  130. fn = vk->GetDeviceProcAddr(hwctx->act_dev, ext_name);
  131. else if (load->req_inst)
  132. fn = hwctx->get_proc_addr(hwctx->inst, ext_name);
  133. else
  134. fn = hwctx->get_proc_addr(NULL, ext_name);
  135. if (fn)
  136. break;
  137. }
  138. if (!fn && ((extensions_mask &~ FF_VK_EXT_NO_FLAG) & load->ext_flag)) {
  139. av_log(ctx, AV_LOG_ERROR, "Loader error, function \"%s\" indicated "
  140. "as supported, but got NULL function pointer!\n", name);
  141. return AVERROR_EXTERNAL;
  142. }
  143. *(PFN_vkVoidFunction *)((uint8_t *)vk + load->struct_offset) = fn;
  144. }
  145. av_assert1(*name == '\0');
  146. return 0;
  147. }
  148. #endif /* AVUTIL_VULKAN_LOADER_H */