diff options
Diffstat (limited to 'video/out/vulkan/context.c')
-rw-r--r-- | video/out/vulkan/context.c | 172 |
1 files changed, 125 insertions, 47 deletions
diff --git a/video/out/vulkan/context.c b/video/out/vulkan/context.c index f9b20fd165..196f6f468d 100644 --- a/video/out/vulkan/context.c +++ b/video/out/vulkan/context.c @@ -15,73 +15,98 @@ * License along with mpv. If not, see <http://www.gnu.org/licenses/>. */ +#include "config.h" + +#if HAVE_LAVU_UUID +#include <libavutil/uuid.h> +#else +#include "misc/uuid.h" +#endif + #include "options/m_config.h" #include "video/out/placebo/ra_pl.h" +#include "video/out/placebo/utils.h" #include "context.h" -#include "utils.h" struct vulkan_opts { char *device; // force a specific GPU int swap_mode; int queue_count; - int async_transfer; - int async_compute; + bool async_transfer; + bool async_compute; }; -static int vk_validate_dev(struct mp_log *log, const struct m_option *opt, - struct bstr name, const char **value) +static inline OPT_STRING_VALIDATE_FUNC(vk_validate_dev) { - struct bstr param = bstr0(*value); int ret = M_OPT_INVALID; - VkResult res; + void *ta_ctx = talloc_new(NULL); + pl_log pllog = mppl_log_create(ta_ctx, log); + if (!pllog) + goto done; // Create a dummy instance to validate/list the devices - VkInstanceCreateInfo info = { - .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - }; - - VkInstance inst; - VkPhysicalDevice *devices = NULL; - uint32_t num = 0; - - res = vkCreateInstance(&info, NULL, &inst); - if (res != VK_SUCCESS) + mppl_log_set_probing(pllog, true); + pl_vk_inst inst = pl_vk_inst_create(pllog, pl_vk_inst_params()); + mppl_log_set_probing(pllog, false); + if (!inst) goto done; - res = vkEnumeratePhysicalDevices(inst, &num, NULL); + uint32_t num = 0; + VkResult res = vkEnumeratePhysicalDevices(inst->instance, &num, NULL); if (res != VK_SUCCESS) goto done; - devices = talloc_array(NULL, VkPhysicalDevice, num); - vkEnumeratePhysicalDevices(inst, &num, devices); + VkPhysicalDevice *devices = talloc_array(ta_ctx, VkPhysicalDevice, num); + res = vkEnumeratePhysicalDevices(inst->instance, &num, devices); if (res != VK_SUCCESS) goto done; + struct bstr param = bstr0(*value); bool help = bstr_equals0(param, "help"); if (help) { mp_info(log, "Available vulkan devices:\n"); ret = M_OPT_EXIT; } + AVUUID param_uuid; + bool is_uuid = av_uuid_parse(*value, param_uuid) == 0; + for (int i = 0; i < num; i++) { - VkPhysicalDeviceProperties prop; - vkGetPhysicalDeviceProperties(devices[i], &prop); + VkPhysicalDeviceIDPropertiesKHR id_prop = { 0 }; + id_prop.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR; + + VkPhysicalDeviceProperties2KHR prop2 = { 0 }; + prop2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR; + prop2.pNext = &id_prop; + + vkGetPhysicalDeviceProperties2(devices[i], &prop2); + + const VkPhysicalDeviceProperties *prop = &prop2.properties; if (help) { - mp_info(log, " '%s' (GPU %d, ID %x:%x)\n", prop.deviceName, i, - (unsigned)prop.vendorID, (unsigned)prop.deviceID); - } else if (bstr_equals0(param, prop.deviceName)) { + char device_uuid[37]; + av_uuid_unparse(id_prop.deviceUUID, device_uuid); + mp_info(log, " '%s' (GPU %d, PCI ID %x:%x, UUID %s)\n", + prop->deviceName, i, (unsigned)prop->vendorID, + (unsigned)prop->deviceID, device_uuid); + } else if (bstr_equals0(param, prop->deviceName)) { + ret = 0; + goto done; + } else if (is_uuid && av_uuid_equal(param_uuid, id_prop.deviceUUID)) { ret = 0; goto done; } } if (!help) - mp_err(log, "No device with name '%.*s'!\n", BSTR_P(param)); + mp_err(log, "No device with %s '%.*s'!\n", is_uuid ? "UUID" : "name", + BSTR_P(param)); done: - talloc_free(devices); + pl_vk_inst_destroy(&inst); + pl_log_destroy(&pllog); + talloc_free(ta_ctx); return ret; } @@ -96,8 +121,8 @@ const struct m_sub_options vulkan_conf = { {"mailbox", VK_PRESENT_MODE_MAILBOX_KHR}, {"immediate", VK_PRESENT_MODE_IMMEDIATE_KHR})}, {"vulkan-queue-count", OPT_INT(queue_count), M_RANGE(1, 8)}, - {"vulkan-async-transfer", OPT_FLAG(async_transfer)}, - {"vulkan-async-compute", OPT_FLAG(async_compute)}, + {"vulkan-async-transfer", OPT_BOOL(async_transfer)}, + {"vulkan-async-compute", OPT_BOOL(async_compute)}, {"vulkan-disable-events", OPT_REMOVED("Unused")}, {0} }, @@ -121,7 +146,7 @@ static const struct ra_swapchain_fns vulkan_swapchain; struct mpvk_ctx *ra_vk_ctx_get(struct ra_ctx *ctx) { - if (ctx->swapchain->fns != &vulkan_swapchain) + if (!ctx->swapchain || ctx->swapchain->fns != &vulkan_swapchain) return NULL; struct priv *p = ctx->swapchain->priv; @@ -148,6 +173,75 @@ void ra_vk_ctx_uninit(struct ra_ctx *ctx) TA_FREEP(&ctx->swapchain); } +pl_vulkan mppl_create_vulkan(struct vulkan_opts *opts, + pl_vk_inst vkinst, + pl_log pllog, + VkSurfaceKHR surface) +{ + VkPhysicalDeviceFeatures2 features = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, + }; + +#if HAVE_VULKAN_INTEROP + /* + * Request the additional extensions and features required to make full use + * of the ffmpeg Vulkan hwcontext and video decoding capability. + */ + const char *opt_extensions[] = { + VK_EXT_DESCRIPTOR_BUFFER_EXTENSION_NAME, + VK_EXT_SHADER_ATOMIC_FLOAT_EXTENSION_NAME, + VK_KHR_VIDEO_DECODE_QUEUE_EXTENSION_NAME, + VK_KHR_VIDEO_DECODE_H264_EXTENSION_NAME, + VK_KHR_VIDEO_DECODE_H265_EXTENSION_NAME, + VK_KHR_VIDEO_QUEUE_EXTENSION_NAME, + "VK_KHR_video_decode_av1", /* VK_KHR_VIDEO_DECODE_AV1_EXTENSION_NAME */ + }; + + VkPhysicalDeviceDescriptorBufferFeaturesEXT descriptor_buffer_feature = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT, + .pNext = NULL, + .descriptorBuffer = true, + .descriptorBufferPushDescriptors = true, + }; + + VkPhysicalDeviceShaderAtomicFloatFeaturesEXT atomic_float_feature = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_FLOAT_FEATURES_EXT, + .pNext = &descriptor_buffer_feature, + .shaderBufferFloat32Atomics = true, + .shaderBufferFloat32AtomicAdd = true, + }; + + features.pNext = &atomic_float_feature; +#endif + + AVUUID param_uuid = { 0 }; + bool is_uuid = opts->device && + av_uuid_parse(opts->device, param_uuid) == 0; + + assert(pllog); + assert(vkinst); + struct pl_vulkan_params device_params = { + .instance = vkinst->instance, + .get_proc_addr = vkinst->get_proc_addr, + .surface = surface, + .async_transfer = opts->async_transfer, + .async_compute = opts->async_compute, + .queue_count = opts->queue_count, +#if HAVE_VULKAN_INTEROP + .extra_queues = VK_QUEUE_VIDEO_DECODE_BIT_KHR, + .opt_extensions = opt_extensions, + .num_opt_extensions = MP_ARRAY_SIZE(opt_extensions), +#endif + .features = &features, + .device_name = is_uuid ? NULL : opts->device, + }; + if (is_uuid) + av_uuid_copy(device_params.device_uuid, param_uuid); + + return pl_vulkan_create(pllog, &device_params); + +} + bool ra_vk_ctx_init(struct ra_ctx *ctx, struct mpvk_ctx *vk, struct ra_vk_ctx_params params, VkPresentModeKHR preferred_mode) @@ -161,17 +255,7 @@ bool ra_vk_ctx_init(struct ra_ctx *ctx, struct mpvk_ctx *vk, p->params = params; p->opts = mp_get_config_group(p, ctx->global, &vulkan_conf); - assert(vk->pllog); - assert(vk->vkinst); - vk->vulkan = pl_vulkan_create(vk->pllog, &(struct pl_vulkan_params) { - .instance = vk->vkinst->instance, - .get_proc_addr = vk->vkinst->get_proc_addr, - .surface = vk->surface, - .async_transfer = p->opts->async_transfer, - .async_compute = p->opts->async_compute, - .queue_count = p->opts->queue_count, - .device_name = p->opts->device, - }); + vk->vulkan = mppl_create_vulkan(p->opts, vk->vkinst, vk->pllog, vk->surface); if (!vk->vulkan) goto error; @@ -229,11 +313,6 @@ char *ra_vk_ctx_get_device_name(struct ra_ctx *ctx) return device_name; } -static int color_depth(struct ra_swapchain *sw) -{ - return 0; // TODO: implement this somehow? -} - static bool start_frame(struct ra_swapchain *sw, struct ra_fbo *out_fbo) { struct priv *p = sw->priv; @@ -283,7 +362,6 @@ static void get_vsync(struct ra_swapchain *sw, } static const struct ra_swapchain_fns vulkan_swapchain = { - .color_depth = color_depth, .start_frame = start_frame, .submit_frame = submit_frame, .swap_buffers = swap_buffers, |