PR #23809 opened by KawaiiEngine
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23809
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23809.patch

`cuda_transfer_data()` can enqueue asynchronous copies for earlier planes
before a later source or destination `cuArrayGetPlane()` lookup, or a later
`cuMemcpy2DAsync()`, fails. The current error exits pop the CUDA context and
return while that earlier work may still reference caller-owned frame
buffers.

Track whether at least one copy was successfully queued. On those later
pre-completion errors, perform a best-effort stream synchronization before
context cleanup. The primary lookup/enqueue error remains the return value;
cleanup synchronization and `cuCtxPopCurrent()` errors remain log-only.

Successful H2D and D2D transfers remain asynchronous. The existing host
download synchronization path is unchanged.

Validation:

- CUDA-enabled MSVC `libavutil` rebuild passed without warnings.
- Real CUDA NV12 H2D/D2H round trip passed on an NVIDIA GeForce RTX 4060
  Laptop GPU (driver 610.62).
- A deterministic function-table harness passed 14/14 cases, including
  later source/destination CUarray-plane lookup failures, later copy-enqueue
  failure, cleanup-sync failure, context-pop failure, successful H2D/D2D,
  and successful host download.
- Successful H2D and D2D traces were `PCCO`, with no stream synchronization.
- `git diff --check` and `tools/patcheck` passed.
- The available FATE subset passed: 159 tests; `SAMPLES` was not configured.


>From 9df9905a2a4ce91eb646274672f52f47cf4437a7 Mon Sep 17 00:00:00 2001
From: "KawaiiEngine (Sashimiso)"
 <[email protected]>
Date: Wed, 15 Jul 2026 05:39:29 +0900
Subject: [PATCH] avutil/hwcontext_cuda: drain queued copies on transfer error

cuda_transfer_data() can enqueue copies for earlier planes before a
later cuArrayGetPlane() or cuMemcpy2DAsync() fails. Returning at that
point can let queued work outlive caller-owned AVFrame buffers.

Track whether a copy was successfully queued and synchronize the stream
on these later failures. Synchronization is best-effort: its errors and
cuCtxPopCurrent() errors stay logged without replacing the primary
failure.

Successful H2D and D2D transfers remain asynchronous, and the normal
host-download synchronization path is unchanged.

Signed-off-by: KawaiiEngine (Sashimiso) 
<[email protected]>
---
 libavutil/hwcontext_cuda.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/libavutil/hwcontext_cuda.c b/libavutil/hwcontext_cuda.c
index 61fbf52885..93c68fb051 100644
--- a/libavutil/hwcontext_cuda.c
+++ b/libavutil/hwcontext_cuda.c
@@ -520,7 +520,7 @@ static int cuda_transfer_data(AVHWFramesContext *ctx, 
AVFrame *dst,
     CudaFunctions             *cu = hwctx->internal->cuda_dl;
 
     CUcontext dummy;
-    int i, ret;
+    int i, ret, copy_queued = 0;
 
     {
         enum AVPixelFormat src_fmt = cuda_frame_hw_format(src);
@@ -578,7 +578,7 @@ static int cuda_transfer_data(AVHWFramesContext *ctx, 
AVFrame *dst,
                 src_is_nonplanar_cuarray = 1;
             } else if (cures != CUDA_SUCCESS) {
                 ret = CHECK_CU(cures);
-                goto exit;
+                goto fail;
             }
 
             cpy.srcMemoryType = CU_MEMORYTYPE_ARRAY;
@@ -601,7 +601,7 @@ static int cuda_transfer_data(AVHWFramesContext *ctx, 
AVFrame *dst,
                 dst_is_nonplanar_cuarray = 1;
             } else if (cures != CUDA_SUCCESS) {
                 ret = CHECK_CU(cures);
-                goto exit;
+                goto fail;
             }
 
             cpy.dstMemoryType = CU_MEMORYTYPE_ARRAY;
@@ -613,7 +613,8 @@ static int cuda_transfer_data(AVHWFramesContext *ctx, 
AVFrame *dst,
 
         ret = CHECK_CU(cu->cuMemcpy2DAsync(&cpy, hwctx->stream));
         if (ret < 0)
-            goto exit;
+            goto fail;
+        copy_queued = 1;
 
         if (src_is_nonplanar_cuarray || dst_is_nonplanar_cuarray)
             break;
@@ -625,6 +626,9 @@ static int cuda_transfer_data(AVHWFramesContext *ctx, 
AVFrame *dst,
             goto exit;
     }
 
+fail:
+    if (ret < 0 && copy_queued)
+        CHECK_CU(cu->cuStreamSynchronize(hwctx->stream));
 exit:
     CHECK_CU(cu->cuCtxPopCurrent(&dummy));
 
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to