diff --git a/spa/plugins/vulkan/vulkan-compute-utils.c b/spa/plugins/vulkan/vulkan-compute-utils.c index 76125c746..c91987da5 100644 --- a/spa/plugins/vulkan/vulkan-compute-utils.c +++ b/spa/plugins/vulkan/vulkan-compute-utils.c @@ -539,8 +539,11 @@ int spa_vulkan_process(struct vulkan_compute_state *s) int spa_vulkan_init(struct vulkan_compute_state *s) { s->base.log = s->log; + uint32_t dsp_format = SPA_VIDEO_FORMAT_DSP_F32; struct vulkan_base_info baseInfo = { .queueFlags = VK_QUEUE_COMPUTE_BIT, + .formatInfo.formatCount = 1, + .formatInfo.formats = &dsp_format, }; return vulkan_base_init(&s->base, &baseInfo); } diff --git a/spa/plugins/vulkan/vulkan-types.h b/spa/plugins/vulkan/vulkan-types.h index 1e59a14ee..143a425ce 100644 --- a/spa/plugins/vulkan/vulkan-types.h +++ b/spa/plugins/vulkan/vulkan-types.h @@ -7,6 +7,18 @@ #define MAX_BUFFERS 16 +struct vulkan_modifier_info { + VkDrmFormatModifierPropertiesEXT props; + VkExtent2D max_extent; +}; + +struct vulkan_format_info { + uint32_t spa_format; + VkFormat vk_format; + uint32_t modifierCount; + struct vulkan_modifier_info *infos; +}; + struct vulkan_buffer { int fd; VkImage image; @@ -28,6 +40,11 @@ struct vulkan_stream { struct vulkan_base_info { uint32_t queueFlags; + + struct { + uint32_t formatCount; + uint32_t *formats; + } formatInfo; }; struct vulkan_base { @@ -41,5 +58,8 @@ struct vulkan_base { uint32_t queueFamilyIndex; VkDevice device; + uint32_t formatInfoCount; + struct vulkan_format_info *formatInfos; + unsigned int initialized:1; }; diff --git a/spa/plugins/vulkan/vulkan-utils.c b/spa/plugins/vulkan/vulkan-utils.c index 5c42b4d42..1c3f678b8 100644 --- a/spa/plugins/vulkan/vulkan-utils.c +++ b/spa/plugins/vulkan/vulkan-utils.c @@ -200,13 +200,15 @@ static int createDevice(struct vulkan_base *s, struct vulkan_base_info *info) }; static const char * const extensions[] = { VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, - VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME + VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, + VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME, + VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME }; const VkDeviceCreateInfo deviceCreateInfo = { .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .queueCreateInfoCount = 1, .pQueueCreateInfos = &queueCreateInfo, - .enabledExtensionCount = 2, + .enabledExtensionCount = SPA_N_ELEMENTS(extensions), .ppEnabledExtensionNames = extensions, }; @@ -217,6 +219,110 @@ static int createDevice(struct vulkan_base *s, struct vulkan_base_info *info) return 0; } +static int queryFormatInfo(struct vulkan_base *s, struct vulkan_base_info *info) +{ + if (s->formatInfos) + return 0; + + s->formatInfos = calloc(info->formatInfo.formatCount, sizeof(struct vulkan_format_info)); + if (!s->formatInfos) + return -ENOMEM; + + for (uint32_t i = 0; i < info->formatInfo.formatCount; i++) { + VkFormat format = vulkan_id_to_vkformat(info->formatInfo.formats[i]); + if (format == VK_FORMAT_UNDEFINED) + continue; + struct vulkan_format_info *f_info = &s->formatInfos[s->formatInfoCount++]; + f_info->spa_format = info->formatInfo.formats[i]; + f_info->vk_format = format; + + VkDrmFormatModifierPropertiesListEXT modPropsList = { + .sType = VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT, + }; + VkFormatProperties2 fmtProps = { + .sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, + .pNext = &modPropsList, + }; + vkGetPhysicalDeviceFormatProperties2(s->physicalDevice, format, &fmtProps); + + if (!modPropsList.drmFormatModifierCount) + continue; + + modPropsList.pDrmFormatModifierProperties = calloc(modPropsList.drmFormatModifierCount, + sizeof(modPropsList.pDrmFormatModifierProperties[0])); + if (!modPropsList.pDrmFormatModifierProperties) + continue; + vkGetPhysicalDeviceFormatProperties2(s->physicalDevice, format, &fmtProps); + + f_info->infos = calloc(modPropsList.drmFormatModifierCount, sizeof(f_info->infos[0])); + if (!f_info->infos) { + free(modPropsList.pDrmFormatModifierProperties); + continue; + } + + for (uint32_t j = 0; j < modPropsList.drmFormatModifierCount; j++) { + VkDrmFormatModifierPropertiesEXT props = modPropsList.pDrmFormatModifierProperties[j]; + + if (!(props.drmFormatModifierTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) + continue; + + VkPhysicalDeviceImageDrmFormatModifierInfoEXT modInfo = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT, + .drmFormatModifier = props.drmFormatModifier, + .sharingMode = VK_SHARING_MODE_EXCLUSIVE, + }; + VkPhysicalDeviceExternalImageFormatInfo extImgFmtInfo = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, + .pNext = &modInfo, + .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, + }; + VkPhysicalDeviceImageFormatInfo2 imgFmtInfo = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, + .pNext = &extImgFmtInfo, + .type = VK_IMAGE_TYPE_2D, + .format = format, + .usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT, + }; + + VkExternalImageFormatProperties extImgFmtProps = { + .sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES, + }; + VkImageFormatProperties2 imgFmtProps = { + .sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, + .pNext = &extImgFmtProps, + }; + + VK_CHECK_RESULT_LOOP(vkGetPhysicalDeviceImageFormatProperties2(s->physicalDevice, &imgFmtInfo, &imgFmtProps)) + + VkExternalMemoryFeatureFlags extMemFeatures = + extImgFmtProps.externalMemoryProperties.externalMemoryFeatures; + if (!(extMemFeatures & VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT)) { + continue; + } + + VkExtent3D max_extent = imgFmtProps.imageFormatProperties.maxExtent; + f_info->infos[f_info->modifierCount++] = (struct vulkan_modifier_info){ + .props = props, + .max_extent = { .width = max_extent.width, .height = max_extent.height }, + }; + + } + free(modPropsList.pDrmFormatModifierProperties); + } + return 0; +} + +static void destroyFormatInfo(struct vulkan_base *s) +{ + for (uint32_t i = 0; i < s->formatInfoCount; i++) { + free(s->formatInfos[i].infos); + } + free(s->formatInfos); + s->formatInfos = NULL; + s->formatInfoCount = 0; +} + int vulkan_commandPool_create(struct vulkan_base *s, VkCommandPool *commandPool) { const VkCommandPoolCreateInfo commandPoolCreateInfo = { @@ -262,6 +368,27 @@ uint32_t vulkan_memoryType_find(struct vulkan_base *s, return -1; } +struct vulkan_format_info *vulkan_formatInfo_find(struct vulkan_base *s, VkFormat format) +{ + for (uint32_t i = 0; i < s->formatInfoCount; i++) { + if (s->formatInfos[i].vk_format == format) + return &s->formatInfos[i]; + } + return NULL; +} + +struct vulkan_modifier_info *vulkan_modifierInfo_find(struct vulkan_base *s, VkFormat format, uint64_t mod) +{ + struct vulkan_format_info *f_info = vulkan_formatInfo_find(s, format); + if (!f_info) + return NULL; + for (uint32_t i = 0; i < f_info->modifierCount; i++) { + if (f_info->infos[i].props.drmFormatModifier == mod) + return &f_info->infos[i]; + } + return NULL; +} + void vulkan_buffer_clear(struct vulkan_base *s, struct vulkan_buffer *buffer) { if (buffer->fd != -1) @@ -311,6 +438,7 @@ int vulkan_base_init(struct vulkan_base *s, struct vulkan_base_info *info) CHECK(createInstance(s)); CHECK(findPhysicalDevice(s)); CHECK(createDevice(s, info)); + CHECK(queryFormatInfo(s, info)); s->initialized = true; } return 0; @@ -319,6 +447,7 @@ int vulkan_base_init(struct vulkan_base *s, struct vulkan_base_info *info) void vulkan_base_deinit(struct vulkan_base *s) { if (s->initialized) { + destroyFormatInfo(s); vkDestroyDevice(s->device, NULL); vkDestroyInstance(s->instance, NULL); s->initialized = false; diff --git a/spa/plugins/vulkan/vulkan-utils.h b/spa/plugins/vulkan/vulkan-utils.h index de9a4a670..b4d28a46c 100644 --- a/spa/plugins/vulkan/vulkan-utils.h +++ b/spa/plugins/vulkan/vulkan-utils.h @@ -18,6 +18,15 @@ return _r; \ } \ } +#define VK_CHECK_RESULT_LOOP(f) \ +{ \ + VkResult _result = (f); \ + int _r = -vkresult_to_errno(_result); \ + if (_result != VK_SUCCESS) { \ + spa_log_error(s->log, "error: %d (%d %s)", _result, _r, spa_strerror(_r)); \ + continue; \ + } \ +} #define CHECK(f) \ { \ int _res = (f); \ @@ -30,6 +39,8 @@ int vulkan_commandBuffer_create(struct vulkan_base *s, VkCommandPool commandPool uint32_t vulkan_memoryType_find(struct vulkan_base *s, uint32_t memoryTypeBits, VkMemoryPropertyFlags properties); +struct vulkan_format_info *vulkan_formatInfo_find(struct vulkan_base *s, VkFormat format); +struct vulkan_modifier_info *vulkan_modifierInfo_find(struct vulkan_base *s, VkFormat format, uint64_t modifier); void vulkan_buffer_clear(struct vulkan_base *s, struct vulkan_buffer *buffer);