/* GStreamer * * Copyright (C) 2023 Igalia, S.L. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include static GstVulkanInstance *instance; static GstVulkanDevice *device; static GstVulkanQueue *queue = NULL; static void setup (void) { instance = gst_vulkan_instance_new (); fail_unless (gst_vulkan_instance_open (instance, NULL)); } static void teardown (void) { gst_clear_object (&queue); gst_clear_object (&device); gst_object_unref (instance); } static gboolean _choose_queue (GstVulkanDevice * device, GstVulkanQueue * _queue, gpointer data) { guint flags = device->physical_device->queue_family_props[_queue->family].queueFlags; guint expected_flags = GPOINTER_TO_UINT (data); if ((flags & expected_flags) != 0) { gst_object_replace ((GstObject **) & queue, GST_OBJECT_CAST (_queue)); return FALSE; } return TRUE; } static void setup_queue (guint expected_flags) { int i; gst_clear_object (&queue); for (i = 0; i < instance->n_physical_devices; i++) { device = gst_vulkan_device_new_with_index (instance, i); fail_unless (gst_vulkan_device_open (device, NULL)); gst_vulkan_device_foreach_queue (device, _choose_queue, GUINT_TO_POINTER (expected_flags)); if (queue && GST_IS_VULKAN_QUEUE (queue)) break; gst_object_unref (device); } fail_unless (GST_IS_VULKAN_QUEUE (queue)); } static GstBufferPool * create_buffer_pool (const char *format, VkImageUsageFlags usage, GstCaps * dec_caps) { GstCaps *caps; GstBufferPool *pool; GstStructure *config; caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, format, "width", G_TYPE_INT, 1024, "height", G_TYPE_INT, 780, NULL); gst_caps_set_features_simple (caps, gst_caps_features_new (GST_CAPS_FEATURE_MEMORY_VULKAN_IMAGE, NULL)); pool = gst_vulkan_image_buffer_pool_new (device); config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, caps, 1024, 1, 0); gst_caps_unref (caps); gst_vulkan_image_buffer_pool_config_set_allocation_params (config, usage, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); if (dec_caps) gst_vulkan_image_buffer_pool_config_set_decode_caps (config, dec_caps); fail_unless (gst_buffer_pool_set_config (pool, config)); gst_buffer_pool_set_active (pool, TRUE); return pool; } GST_START_TEST (test_image) { GstBufferPool *pool; GstFlowReturn ret; GstBuffer *buffer = NULL; setup_queue (VK_QUEUE_COMPUTE_BIT); pool = create_buffer_pool ("NV12", 0, NULL); ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL); fail_unless (ret == GST_FLOW_OK); gst_buffer_unref (buffer); gst_buffer_pool_set_active (pool, FALSE); gst_object_unref (pool); } GST_END_TEST; #if GST_VULKAN_HAVE_VIDEO_EXTENSIONS GST_START_TEST (test_vulkan_profiles) { GstCaps *caps; /* *INDENT-OFF* */ GstVulkanVideoProfile profile2 = { { 0, }, }, profile = { .profile = { .sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR, .pNext = &profile.codec, .videoCodecOperation = VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR, .chromaSubsampling = VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR, .chromaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR, .lumaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR, }, .codec.h265dec = { .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H265_PROFILE_INFO_KHR, .stdProfileIdc = STD_VIDEO_H265_PROFILE_IDC_MAIN_10, } }; /* *INDENT-ON* */ caps = gst_vulkan_video_profile_to_caps (&profile); fail_unless (caps); fail_unless (gst_vulkan_video_profile_from_caps (&profile2, caps, GST_VULKAN_VIDEO_OPERATION_DECODE)); gst_caps_unref (caps); fail_unless (profile2.profile.sType == VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR); fail_unless (profile2.profile.videoCodecOperation == profile.profile.videoCodecOperation); fail_unless (profile2.codec.h265dec.stdProfileIdc == profile.codec.h265dec.stdProfileIdc); } GST_END_TEST; GST_START_TEST (test_decoding_image) { GstBufferPool *pool; GstCaps *dec_caps; GstBuffer *buffer = NULL; GstFlowReturn ret; /* *INDENT-OFF* */ GstVulkanVideoProfile profile = { .profile = { .sType = VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR, .pNext = &profile.codec, .videoCodecOperation = VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR, .chromaSubsampling = VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR, .chromaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR, .lumaBitDepth = VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR, }, .codec.h264dec = { .sType = VK_STRUCTURE_TYPE_VIDEO_DECODE_H264_PROFILE_INFO_KHR, .stdProfileIdc = STD_VIDEO_H264_PROFILE_IDC_MAIN, .pictureLayout = VK_VIDEO_DECODE_H264_PICTURE_LAYOUT_PROGRESSIVE_KHR, } }; /* *INDENT-ON* */ /* force to use a queue with decoding support */ setup_queue (VK_QUEUE_VIDEO_DECODE_BIT_KHR); if ((device->physical_device->queue_family_ops[queue->family].video & VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR) == 0) return; dec_caps = gst_vulkan_video_profile_to_caps (&profile); fail_unless (dec_caps); pool = create_buffer_pool ("NV12", VK_IMAGE_USAGE_VIDEO_DECODE_DST_BIT_KHR, dec_caps); gst_caps_unref (dec_caps); ret = gst_buffer_pool_acquire_buffer (pool, &buffer, NULL); fail_unless (ret == GST_FLOW_OK); gst_buffer_unref (buffer); gst_buffer_pool_set_active (pool, FALSE); gst_object_unref (pool); } GST_END_TEST; #endif static Suite * vkimagebufferpool_suite (void) { Suite *s = suite_create ("vkimagebufferpool"); TCase *tc_basic = tcase_create ("general"); gboolean have_instance; suite_add_tcase (s, tc_basic); tcase_add_checked_fixture (tc_basic, setup, teardown); /* FIXME: CI doesn't have a software vulkan renderer (and none exists currently) */ instance = gst_vulkan_instance_new (); have_instance = gst_vulkan_instance_open (instance, NULL); gst_object_unref (instance); if (have_instance) { tcase_add_test (tc_basic, test_image); #if GST_VULKAN_HAVE_VIDEO_EXTENSIONS tcase_add_test (tc_basic, test_decoding_image); tcase_add_test (tc_basic, test_vulkan_profiles); #endif } return s; } GST_CHECK_MAIN (vkimagebufferpool);