summaryrefslogtreecommitdiffstats
path: root/video/out/vulkan/context.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/vulkan/context.c')
-rw-r--r--video/out/vulkan/context.c191
1 files changed, 137 insertions, 54 deletions
diff --git a/video/out/vulkan/context.c b/video/out/vulkan/context.c
index 3518d3efd2..82c878afec 100644
--- a/video/out/vulkan/context.c
+++ b/video/out/vulkan/context.c
@@ -15,8 +15,17 @@
* 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"
@@ -25,63 +34,80 @@ struct vulkan_opts {
char *device; // force a specific GPU
int swap_mode;
int queue_count;
- int async_transfer;
- int async_compute;
- int disable_events;
+ bool async_transfer;
+ bool async_compute;
};
-static int vk_validate_dev(struct mp_log *log, const struct m_option *opt,
- struct bstr name, struct bstr param)
+static inline OPT_STRING_VALIDATE_FUNC(vk_validate_dev)
{
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,9 +122,9 @@ 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-disable-events", OPT_FLAG(disable_events)},
+ {"vulkan-async-transfer", OPT_BOOL(async_transfer)},
+ {"vulkan-async-compute", OPT_BOOL(async_compute)},
+ {"vulkan-disable-events", OPT_REMOVED("Unused")},
{0}
},
.size = sizeof(struct vulkan_opts),
@@ -114,7 +140,6 @@ struct priv {
struct mpvk_ctx *vk;
struct vulkan_opts *opts;
struct ra_vk_ctx_params params;
- const struct pl_swapchain *swapchain;
struct ra_tex proxy_tex;
};
@@ -122,7 +147,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;
@@ -139,7 +164,7 @@ void ra_vk_ctx_uninit(struct ra_ctx *ctx)
if (ctx->ra) {
pl_gpu_finish(vk->gpu);
- pl_swapchain_destroy(&p->swapchain);
+ pl_swapchain_destroy(&vk->swapchain);
ctx->ra->fns->destroy(ctx->ra);
ctx->ra = NULL;
}
@@ -162,19 +187,67 @@ 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->ctx);
+ 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 = p->opts->device &&
+ av_uuid_parse(p->opts->device, param_uuid) == 0;
+
+ assert(vk->pllog);
assert(vk->vkinst);
- vk->vulkan = pl_vulkan_create(vk->ctx, &(struct pl_vulkan_params) {
+ struct pl_vulkan_params device_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,
-#if PL_API_VER >= 24
- .disable_events = p->opts->disable_events,
+#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 : p->opts->device,
+ };
+ if (is_uuid)
+ av_uuid_copy(device_params.device_uuid, param_uuid);
+
+ vk->vulkan = pl_vulkan_create(vk->pllog, &device_params);
if (!vk->vulkan)
goto error;
@@ -188,18 +261,16 @@ bool ra_vk_ctx_init(struct ra_ctx *ctx, struct mpvk_ctx *vk,
.surface = vk->surface,
.present_mode = preferred_mode,
.swapchain_depth = ctx->vo->opts->swapchain_depth,
-#if PL_API_VER >= 29
// mpv already handles resize events, so gracefully allow suboptimal
// swapchains to exist in order to make resizing even smoother
.allow_suboptimal = true,
-#endif
};
if (p->opts->swap_mode >= 0) // user override
pl_params.present_mode = p->opts->swap_mode;
- p->swapchain = pl_vulkan_create_swapchain(vk->vulkan, &pl_params);
- if (!p->swapchain)
+ vk->swapchain = pl_vulkan_create_swapchain(vk->vulkan, &pl_params);
+ if (!vk->swapchain)
goto error;
return true;
@@ -213,28 +284,41 @@ bool ra_vk_ctx_resize(struct ra_ctx *ctx, int width, int height)
{
struct priv *p = ctx->swapchain->priv;
- bool ok = pl_swapchain_resize(p->swapchain, &width, &height);
+ bool ok = pl_swapchain_resize(p->vk->swapchain, &width, &height);
ctx->vo->dwidth = width;
ctx->vo->dheight = height;
return ok;
}
-static int color_depth(struct ra_swapchain *sw)
+char *ra_vk_ctx_get_device_name(struct ra_ctx *ctx)
{
- return 0; // TODO: implement this somehow?
+ /*
+ * This implementation is a bit odd because it has to work even if the
+ * ctx hasn't been initialised yet. A context implementation may need access
+ * to the device name before it can fully initialise the ctx.
+ */
+ struct vulkan_opts *opts = mp_get_config_group(NULL, ctx->global,
+ &vulkan_conf);
+ char *device_name = talloc_strdup(NULL, opts->device);
+ talloc_free(opts);
+ return device_name;
}
static bool start_frame(struct ra_swapchain *sw, struct ra_fbo *out_fbo)
{
struct priv *p = sw->priv;
struct pl_swapchain_frame frame;
- bool start = true;
- if (p->params.start_frame)
- start = p->params.start_frame(sw->ctx);
- if (!start)
- return false;
- if (!pl_swapchain_start_frame(p->swapchain, &frame))
+
+ bool visible = true;
+ if (p->params.check_visible)
+ visible = p->params.check_visible(sw->ctx);
+
+ // If out_fbo is NULL, this was called from vo_gpu_next. Bail out.
+ if (out_fbo == NULL || !visible)
+ return visible;
+
+ if (!pl_swapchain_start_frame(p->vk->swapchain, &frame))
return false;
if (!mppl_wrap_tex(sw->ctx->ra, frame.fbo, &p->proxy_tex))
return false;
@@ -250,13 +334,13 @@ static bool start_frame(struct ra_swapchain *sw, struct ra_fbo *out_fbo)
static bool submit_frame(struct ra_swapchain *sw, const struct vo_frame *frame)
{
struct priv *p = sw->priv;
- return pl_swapchain_submit_frame(p->swapchain);
+ return pl_swapchain_submit_frame(p->vk->swapchain);
}
static void swap_buffers(struct ra_swapchain *sw)
{
struct priv *p = sw->priv;
- pl_swapchain_swap_buffers(p->swapchain);
+ pl_swapchain_swap_buffers(p->vk->swapchain);
if (p->params.swap_buffers)
p->params.swap_buffers(sw->ctx);
}
@@ -270,7 +354,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,