From patchwork Sat Apr 30 20:07:40 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aman Karmani X-Patchwork-Id: 35526 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:a885:b0:7f:4be2:bd17 with SMTP id ca5csp1018154pzb; Sat, 30 Apr 2022 13:08:04 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyayayyigEZ3hVx7k2IDVYls1U5aItX9brFw4eByjUsSF5fH8S70tUBWqo6plyiN1Uonw2c X-Received: by 2002:a05:6402:1698:b0:425:f339:80ef with SMTP id a24-20020a056402169800b00425f33980efmr5667376edv.225.1651349284641; Sat, 30 Apr 2022 13:08:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1651349284; cv=none; d=google.com; s=arc-20160816; b=JIgig8a2whzl7tpQenSo3XVB79nUR19zYyZEZT/fg78H166MLI/vExzs2K5beO9E5B TvHmLjM/Kl3nqnZh8O8+/LsRQJtIWNzPc99VQjc+Lvu9NMASDNz6ZYI6qlWMfdzFsHfj 0Pd3gSWn9QEsxJpKpt6Wk1ekOXP8tCf/pOAxDQZEFw6Q6Sm1OZePf38teAH8NrTH8/nb TgaYjt6StQkAN+svwjLnDm+2JhiCZwbvuxNcF/1etJa3i4J/HAR5BLJr0/nMXGuusznq yEml5X5AxCHkzopv9XslxKL8XXhvNKfVJuJZLBKVgQqC1jMAqiIO5GT9pywOb6k6HJTk ehZA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:to:mime-version:fcc:date:references :in-reply-to:message-id:from:dkim-signature:delivered-to; bh=wK6v8ZhyBg/rf0ys7JCXWBDLcQXnOHEyOE5NpHpw4HA=; b=eUirMvdMq6+fu3EXbCTK1QGEXmdWH9wrqe3Q+qMtpsV8gLirR1gwO9LsQdrudcrgWg KjutlchT/RMy3FDAL5xZUSFukWrmuaRqRFSECW4Ih9mdtrM77llR0ki544B15slBH0qN 6DyyTJUwZq5dmCGRdRa5StubGk3UudWb65gZ9KrO8Ah7mudoM6cmV5oRMpbpw6wfqptu nvMjQZCeLslczrqphzPPjLfmHLvCbbu4+VEhxCRPV+HVD3pqtjKih6ctvSdeYeL9I4x5 5L9SxPYYv4bR6Ce5Zq68Wmik3QwRPFvCoJyU5F8YyhXV11Wm3xO4RtQP9rFnquGajuKf h2Ig== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=i2lgJUPp; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id b17-20020a056402351100b00418c2b5bda6si10180149edd.136.2022.04.30.13.08.03; Sat, 30 Apr 2022 13:08:04 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=i2lgJUPp; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 181F668B234; Sat, 30 Apr 2022 23:07:54 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-pj1-f43.google.com (mail-pj1-f43.google.com [209.85.216.43]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id CD0FE68B180 for ; Sat, 30 Apr 2022 23:07:46 +0300 (EEST) Received: by mail-pj1-f43.google.com with SMTP id j8-20020a17090a060800b001cd4fb60dccso9923964pjj.2 for ; Sat, 30 Apr 2022 13:07:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:message-id:in-reply-to:references:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=SwpeUywqltcKe/kcubTGbxvATrTYElzH7aJ0BfFogRo=; b=i2lgJUPp1Pa+dNl7uExoUUKqe8Jn4uU95ZQmRkdQ6GfmuD9UaBp1yqUTfmSmusAFf/ RcOQ3P2usFu2x4aECk3sck3DcSs5+6Xc9JMMZzDeQ/NQE9U6sq+5Z5DU1AAH4J3Ko3c/ l1uQfQX24aYwRul4gqs60gGaFE8kQczAlPl/mj6vK5EP5iTnKInOXlW7qgF3U7R4BVqu P1cK+DbUBtyWntLxUGlCOYc1GbMo+1MPzdfiVLduc96oFFjz0a1OJt//RERfUj4rZEeS 9L8aJkAsHM1dM2oglUtZ1y9u9APkr+LcEhJ9oBpxR4yhOBx6fp9jAipKBEg3ePwgAMZl Z0lw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:message-id:in-reply-to:references:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=SwpeUywqltcKe/kcubTGbxvATrTYElzH7aJ0BfFogRo=; b=zTEw2/s32pBCXZyXHANjFo2vIN/BamtW3tbyEVyc69nO4y/D0g5ljMcXTPdi8KtXD7 AeUnCldYZ9w+5AkAcAZ8nAC2op+fjZX63V5ENj/4CwpfGsjcdLML1tNsZc3MtGcqMFBv n0t7OttFMbNcrsbxa+v8jtZnssA1jy25JDYbdWX5R00lZ+PN/NOXcwLpuBaQ9SHdEeIv 5dFip8Dve7kDNY8bAfm0GrasS5/lfsWMUm2qPUpr5V32gu9E5RoXmqSk58g4a+JT2Mg2 yfQybuj+6/eBB3kp6+h2TdU7HHVeVl+HhbYbOe302b54Epo2jXGQE6hirASc8CvhUJ21 tKVw== X-Gm-Message-State: AOAM531WCBNleEWdGpPKJ7YIatGM9o5lL2udu6UzvEvxd11mqt18K7QX w53egLZ0XfDm3vLxQs2XSD8NRxztGFHZrw== X-Received: by 2002:a17:90a:c797:b0:1d9:2764:a83b with SMTP id gn23-20020a17090ac79700b001d92764a83bmr10254152pjb.5.1651349265053; Sat, 30 Apr 2022 13:07:45 -0700 (PDT) Received: from [127.0.0.1] (master.gitmailbox.com. [34.83.118.50]) by smtp.gmail.com with ESMTPSA id 192-20020a6301c9000000b003c14af50619sm9052034pgb.49.2022.04.30.13.07.44 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sat, 30 Apr 2022 13:07:44 -0700 (PDT) From: softworkz X-Google-Original-From: softworkz Message-Id: <85ff784b6ff80d4f2e0f724d0b93472e50d2c256.1651349262.git.ffmpegagent@gmail.com> In-Reply-To: References: Date: Sat, 30 Apr 2022 20:07:40 +0000 Fcc: Sent MIME-Version: 1.0 To: ffmpeg-devel@ffmpeg.org Subject: [FFmpeg-devel] [PATCH 1/3] avutils/hwcontext: add derive-device function which searches for existing devices in both directions X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: softworkz Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: artfWxTfKz8j From: softworkz The test /libavutil/tests/hwdevice checks that when deriving a device from a source device and then deriving back to the type of the source device, the result is matching the original source device, i.e. the derivation mechanism doesn't create a new device in this case. Previously, this test was usually passed, but only due to two different kind of flaws: 1. The test covers only a single level of derivation (and back) It derives device Y from device X and then Y back to the type of X and checks whether the result matches X. What it doesn't check for, are longer chains of derivation like: CUDA1 > OpenCL2 > CUDA3 and then back to OpenCL4 In that case, the second derivation returns the first device (CUDA3 == CUDA1), but when deriving OpenCL4, hwcontext.c was creating a new OpenCL4 context instead of returning OpenCL2, because there was no link from CUDA1 to OpenCL2 (only backwards from OpenCL2 to CUDA1) If the test would check for two levels of derivation, it would have failed. This patch fixes those (yet untested) cases by introducing forward references (derived_device) in addition to the existing back references (source_device). 2. hwcontext_qsv didn't properly set the source_device In case of QSV, hwcontext_qsv creates a source context internally (vaapi, dxva2 or d3d11va) without calling av_hwdevice_ctx_create_derived and without setting source_device. This way, the hwcontext test ran successful, but what practically happened, was that - for example - deriving vaapi from qsv didn't return the original underlying vaapi device and a new one was created instead: Exactly what the test is intended to detect and prevent. It just couldn't do so, because the original device was hidden (= not set as the source_device of the QSV device). This patch properly makes these setting and fixes all derivation scenarios. (at a later stage, /libavutil/tests/hwdevice should be extended to check longer derivation chains as well) Signed-off-by: softworkz --- libavutil/hwcontext.c | 72 +++++++++++++++++++++++++++++++--- libavutil/hwcontext.h | 20 ++++++++++ libavutil/hwcontext_internal.h | 6 +++ libavutil/hwcontext_qsv.c | 13 ++++-- 4 files changed, 102 insertions(+), 9 deletions(-) diff --git a/libavutil/hwcontext.c b/libavutil/hwcontext.c index ab9ad3703e..1aea7dd5c3 100644 --- a/libavutil/hwcontext.c +++ b/libavutil/hwcontext.c @@ -123,6 +123,7 @@ static const AVClass hwdevice_ctx_class = { static void hwdevice_ctx_free(void *opaque, uint8_t *data) { AVHWDeviceContext *ctx = (AVHWDeviceContext*)data; + int i; /* uninit might still want access the hw context and the user * free() callback might destroy it, so uninit has to be called first */ @@ -133,6 +134,8 @@ static void hwdevice_ctx_free(void *opaque, uint8_t *data) ctx->free(ctx); av_buffer_unref(&ctx->internal->source_device); + for (i = 0; i < AV_HWDEVICE_TYPE_NB; i++) + av_buffer_unref(&ctx->internal->derived_devices[i]); av_freep(&ctx->hwctx); av_freep(&ctx->internal->priv); @@ -644,10 +647,31 @@ fail: return ret; } -int av_hwdevice_ctx_create_derived_opts(AVBufferRef **dst_ref_ptr, - enum AVHWDeviceType type, - AVBufferRef *src_ref, - AVDictionary *options, int flags) +static AVBufferRef* find_derived_hwdevice_ctx(AVBufferRef *src_ref, enum AVHWDeviceType type) +{ + AVBufferRef *tmp_ref; + AVHWDeviceContext *src_ctx; + int i; + + src_ctx = (AVHWDeviceContext*)src_ref->data; + if (src_ctx->type == type) + return src_ref; + + for (i = 0; i < AV_HWDEVICE_TYPE_NB; i++) + if (src_ctx->internal->derived_devices[i]) { + tmp_ref = find_derived_hwdevice_ctx(src_ctx->internal->derived_devices[i], type); + if (tmp_ref) + return tmp_ref; + } + + return NULL; +} + +static int hwdevice_ctx_create_derived(AVBufferRef **dst_ref_ptr, + enum AVHWDeviceType type, + AVBufferRef *src_ref, + AVDictionary *options, int flags, + int get_existing) { AVBufferRef *dst_ref = NULL, *tmp_ref; AVHWDeviceContext *dst_ctx, *tmp_ctx; @@ -667,6 +691,18 @@ int av_hwdevice_ctx_create_derived_opts(AVBufferRef **dst_ref_ptr, tmp_ref = tmp_ctx->internal->source_device; } + if (get_existing) { + tmp_ref = find_derived_hwdevice_ctx(src_ref, type); + if (tmp_ref) { + dst_ref = av_buffer_ref(tmp_ref); + if (!dst_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + goto done; + } + } + dst_ref = av_hwdevice_ctx_alloc(type); if (!dst_ref) { ret = AVERROR(ENOMEM); @@ -688,6 +724,13 @@ int av_hwdevice_ctx_create_derived_opts(AVBufferRef **dst_ref_ptr, ret = AVERROR(ENOMEM); goto fail; } + if (!tmp_ctx->internal->derived_devices[type]) { + tmp_ctx->internal->derived_devices[type] = av_buffer_ref(dst_ref); + if (!tmp_ctx->internal->derived_devices[type]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } ret = av_hwdevice_ctx_init(dst_ref); if (ret < 0) goto fail; @@ -712,12 +755,29 @@ fail: return ret; } +int av_hwdevice_ctx_create_derived_opts(AVBufferRef **dst_ref_ptr, + enum AVHWDeviceType type, + AVBufferRef *src_ref, + AVDictionary *options, int flags) +{ + return hwdevice_ctx_create_derived(dst_ref_ptr, type, src_ref, + options, flags, 0); +} + +int av_hwdevice_ctx_get_or_create_derived(AVBufferRef **dst_ref_ptr, + enum AVHWDeviceType type, + AVBufferRef *src_ref, int flags) +{ + return hwdevice_ctx_create_derived(dst_ref_ptr, type, src_ref, + NULL, flags, 1); +} + int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ref_ptr, enum AVHWDeviceType type, AVBufferRef *src_ref, int flags) { - return av_hwdevice_ctx_create_derived_opts(dst_ref_ptr, type, src_ref, - NULL, flags); + return hwdevice_ctx_create_derived(dst_ref_ptr, type, src_ref, + NULL, flags, 0); } static void ff_hwframe_unmap(void *opaque, uint8_t *data) diff --git a/libavutil/hwcontext.h b/libavutil/hwcontext.h index c18b7e1e8b..3785811f98 100644 --- a/libavutil/hwcontext.h +++ b/libavutil/hwcontext.h @@ -37,6 +37,7 @@ enum AVHWDeviceType { AV_HWDEVICE_TYPE_OPENCL, AV_HWDEVICE_TYPE_MEDIACODEC, AV_HWDEVICE_TYPE_VULKAN, + AV_HWDEVICE_TYPE_NB, ///< number of hw device types }; typedef struct AVHWDeviceInternal AVHWDeviceInternal; @@ -328,6 +329,25 @@ int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ctx, enum AVHWDeviceType type, AVBufferRef *src_ctx, int flags); +/** + * Create a new device of the specified type from an existing device. + * + * This function performs the same action as av_hwdevice_ctx_create_derived, + * however, if a derived device of the specified type already exists, + * it returns the existing instance. + * + * @param dst_ctx On success, a reference to the newly-created + * AVHWDeviceContext. + * @param type The type of the new device to create. + * @param src_ctx A reference to an existing AVHWDeviceContext which will be + * used to create the new device. + * @param flags Currently unused; should be set to zero. + * @return Zero on success, a negative AVERROR code on failure. + */ +int av_hwdevice_ctx_get_or_create_derived(AVBufferRef **dst_ctx, + enum AVHWDeviceType type, + AVBufferRef *src_ctx, int flags); + /** * Create a new device of the specified type from an existing device. * diff --git a/libavutil/hwcontext_internal.h b/libavutil/hwcontext_internal.h index e6266494ac..f6fb67c491 100644 --- a/libavutil/hwcontext_internal.h +++ b/libavutil/hwcontext_internal.h @@ -109,6 +109,12 @@ struct AVHWDeviceInternal { * context it was derived from. */ AVBufferRef *source_device; + + /** + * An array of reference to device contexts which + * were derived from this device. + */ + AVBufferRef *derived_devices[AV_HWDEVICE_TYPE_NB]; }; struct AVHWFramesInternal { diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c index 66c0e38955..f24d06fe97 100644 --- a/libavutil/hwcontext_qsv.c +++ b/libavutil/hwcontext_qsv.c @@ -309,7 +309,7 @@ static void qsv_frames_uninit(AVHWFramesContext *ctx) av_buffer_unref(&s->child_frames_ref); } -static void qsv_pool_release_dummy(void *opaque, uint8_t *data) +static void qsv_release_dummy(void *opaque, uint8_t *data) { } @@ -322,7 +322,7 @@ static AVBufferRef *qsv_pool_alloc(void *opaque, size_t size) if (s->nb_surfaces_used < hwctx->nb_surfaces) { s->nb_surfaces_used++; return av_buffer_create((uint8_t*)(s->surfaces_internal + s->nb_surfaces_used - 1), - sizeof(*hwctx->surfaces), qsv_pool_release_dummy, NULL, 0); + sizeof(*hwctx->surfaces), qsv_release_dummy, NULL, 0); } return NULL; @@ -1649,8 +1649,15 @@ static int qsv_device_create(AVHWDeviceContext *ctx, const char *device, child_device = (AVHWDeviceContext*)priv->child_device_ctx->data; impl = choose_implementation(device, child_device_type); + ret = qsv_device_derive_from_child(ctx, impl, child_device, 0); + if (ret >= 0) { + ctx->internal->source_device = av_buffer_ref(priv->child_device_ctx); + child_device->internal->derived_devices[ctx->type] = av_buffer_create((uint8_t*)ctx, sizeof(*ctx), qsv_release_dummy, ctx, 0); + if (!child_device->internal->derived_devices[ctx->type]) + return AVERROR(ENOMEM); + } - return qsv_device_derive_from_child(ctx, impl, child_device, 0); + return ret; } const HWContextType ff_hwcontext_type_qsv = {