Skip to content

Commit 36beb85

Browse files
committed
vc1: move decode lifecycle handling behind codec callbacks
1 parent 96487c3 commit 36beb85

4 files changed

Lines changed: 237 additions & 114 deletions

File tree

‎src/jpeg.c‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,8 @@ static const VAProfile jpegSupportedProfiles[] = {
755755
VAProfileJPEGBaseline,
756756
};
757757

758-
static void jpegBeginPicture(NVContext *ctx) {
758+
static void jpegBeginPicture(NVContext *ctx, VASurfaceID renderTarget) {
759+
(void) renderTarget;
759760
resetJPEGPictureState(ctx);
760761
}
761762

‎src/vabackend.c‎

Lines changed: 46 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,14 @@ static void* getObjectPtr(NVDriver *drv, ObjectType type, VAGenericID id) {
486486
return NULL;
487487
}
488488

489+
NVSurface *nvGetSurface(NVDriver *drv, VASurfaceID id) {
490+
return getObjectPtr(drv, OBJECT_TYPE_SURFACE, id);
491+
}
492+
493+
NVBuffer *nvGetBuffer(NVDriver *drv, VABufferID id) {
494+
return getObjectPtr(drv, OBJECT_TYPE_BUFFER, id);
495+
}
496+
489497
static Object getObjectByPtr(NVDriver *drv, ObjectType type, void *ptr) {
490498
Object ret = NULL;
491499
if (ptr != NULL) {
@@ -500,7 +508,6 @@ static Object getObjectByPtr(NVDriver *drv, ObjectType type, void *ptr) {
500508
}
501509
return ret;
502510
}
503-
504511
static void setSurfaceResolving(NVSurface *surface, bool resolving);
505512

506513
// Requires drv->objectCreationMutex to be held by the caller.
@@ -1650,6 +1657,10 @@ static void setSurfaceResolving(NVSurface *surface, bool resolving) {
16501657
pthread_mutex_unlock(&surface->mutex);
16511658
}
16521659

1660+
void nvSetSurfaceResolving(NVSurface *surface, bool resolving) {
1661+
setSurfaceResolving(surface, resolving);
1662+
}
1663+
16531664
static void waitSurfaceResolved(NVSurface *surface) {
16541665
if (surface == NULL) {
16551666
return;
@@ -1883,11 +1894,8 @@ static VAStatus nvDestroySurfaces(
18831894
ARRAY_FOR_EACH(Object, o, &drv->objects)
18841895
if (o->type == OBJECT_TYPE_CONTEXT) {
18851896
NVContext *nvCtx = (NVContext*) o->obj;
1886-
if (nvCtx->cudaCodec == cudaVideoCodec_VC1 && nvCtx->vc1FieldPending &&
1887-
nvCtx->vc1FieldSurface == surface_list[i]) {
1888-
nvCtx->vc1FieldPending = false;
1889-
surface->decodeFailed = true;
1890-
setSurfaceResolving(surface, false);
1897+
if (nvCtx->codec != NULL && nvCtx->codec->surfaceDestroyed != NULL) {
1898+
nvCtx->codec->surfaceDestroyed(nvCtx, surface_list[i], surface);
18911899
}
18921900
// nvEndPicture may wait on the most recently queued surface before
18931901
// resizing the decoder's display area; don't let it point at a
@@ -3120,29 +3128,6 @@ static bool copySurfaceBackingImage(NVDriver *drv, NVSurface *src, NVSurface *ds
31203128
return true;
31213129
}
31223130

3123-
static void cancelVC1FieldLocked(NVDriver *drv, NVContext *ctx) {
3124-
if (!ctx->vc1FieldPending) return;
3125-
NVSurface *surface = getObjectPtr(drv, OBJECT_TYPE_SURFACE, ctx->vc1FieldSurface);
3126-
if (surface != NULL) {
3127-
surface->decodeFailed = true;
3128-
setSurfaceResolving(surface, false);
3129-
}
3130-
ctx->vc1FieldPending = false;
3131-
}
3132-
3133-
static void abortVC1Picture(NVDriver *drv, NVContext *ctx) {
3134-
pthread_mutex_lock(&drv->objectCreationMutex);
3135-
cancelVC1FieldLocked(drv, ctx);
3136-
NVSurface *surface = getObjectPtr(drv, OBJECT_TYPE_SURFACE, ctx->vc1RenderSurface);
3137-
if (surface != NULL) {
3138-
surface->decodeFailed = true;
3139-
setSurfaceResolving(surface, false);
3140-
}
3141-
pthread_mutex_unlock(&drv->objectCreationMutex);
3142-
ctx->bitstreamBuffer.size = 0;
3143-
ctx->sliceOffsets.size = 0;
3144-
}
3145-
31463131
static VAStatus nvBeginPicture(
31473132
VADriverContextP ctx,
31483133
VAContextID context,
@@ -3194,9 +3179,12 @@ static VAStatus nvBeginPicture(
31943179
pthread_mutex_unlock(&drv->objectCreationMutex);
31953180
return VA_STATUS_ERROR_INVALID_CONTEXT;
31963181
}
3197-
if (nvCtx->cudaCodec == cudaVideoCodec_VC1 && nvCtx->vc1PictureActive) {
3198-
pthread_mutex_unlock(&drv->objectCreationMutex);
3199-
return VA_STATUS_ERROR_OPERATION_FAILED;
3182+
if (nvCtx->codec->checkPicture != NULL) {
3183+
VAStatus status = nvCtx->codec->checkPicture(nvCtx, NV_PICTURE_BEGIN);
3184+
if (status != VA_STATUS_SUCCESS) {
3185+
pthread_mutex_unlock(&drv->objectCreationMutex);
3186+
return status;
3187+
}
32003188
}
32013189
nvCtx->activeDecodeCalls++;
32023190
pthread_mutex_unlock(&drv->objectCreationMutex);
@@ -3235,14 +3223,13 @@ static VAStatus nvBeginPicture(
32353223
setSurfaceResolving(surface, true);
32363224

32373225
memset(&nvCtx->pPicParams, 0, sizeof(CUVIDPICPARAMS));
3238-
nvCtx->vc1RenderSurface = render_target;
32393226
nvCtx->renderTarget = surface;
32403227
nvCtx->displayTarget = surface;
32413228
nvCtx->renderTarget->progressiveFrame = true; //assume we're producing progressive frame unless the codec says otherwise
32423229
nvSurfaceResetColorMetadata(nvCtx->renderTarget);
32433230
nvCtx->pPicParams.CurrPicIdx = nvCtx->renderTarget->pictureIdx;
32443231
if (nvCtx->codec != NULL && nvCtx->codec->beginPicture != NULL) {
3245-
nvCtx->codec->beginPicture(nvCtx);
3232+
nvCtx->codec->beginPicture(nvCtx, render_target);
32463233
}
32473234

32483235
endDecodeCall(drv, nvCtx);
@@ -3320,46 +3307,39 @@ static VAStatus nvRenderPicture(
33203307
pthread_mutex_unlock(&drv->objectCreationMutex);
33213308
return VA_STATUS_ERROR_INVALID_CONTEXT;
33223309
}
3323-
if (nvCtx->cudaCodec == cudaVideoCodec_VC1 && !nvCtx->vc1PictureActive) {
3324-
pthread_mutex_unlock(&drv->objectCreationMutex);
3325-
return VA_STATUS_ERROR_OPERATION_FAILED;
3310+
if (nvCtx->codec->checkPicture != NULL) {
3311+
VAStatus status = nvCtx->codec->checkPicture(nvCtx, NV_PICTURE_RENDER);
3312+
if (status != VA_STATUS_SUCCESS) {
3313+
pthread_mutex_unlock(&drv->objectCreationMutex);
3314+
return status;
3315+
}
33263316
}
33273317
nvCtx->activeDecodeCalls++;
33283318
pthread_mutex_unlock(&drv->objectCreationMutex);
33293319

33303320
CUVIDPICPARAMS *picParams = &nvCtx->pPicParams;
33313321

3332-
if (nvCtx->cudaCodec == cudaVideoCodec_VC1 &&
3333-
(num_buffers < 0 || (num_buffers != 0 && buffers == NULL))) {
3334-
nvCtx->vc1PictureStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
3322+
if (nvCtx->codec->renderPicture != NULL) {
3323+
VAStatus status = nvCtx->codec->renderPicture(nvCtx, buffers, num_buffers);
3324+
endDecodeCall(drv, nvCtx);
3325+
return status;
33353326
}
33363327
for (int i = 0; i < num_buffers; i++) {
3337-
if (nvCtx->cudaCodec == cudaVideoCodec_VC1 && nvCtx->vc1PictureStatus != VA_STATUS_SUCCESS) break;
33383328
NVBuffer *buf = (NVBuffer*) getObjectPtr(drv, OBJECT_TYPE_BUFFER, buffers[i]);
33393329
if (buf == NULL || buf->ptr == NULL || (unsigned int) buf->bufferType >= VABufferTypeMax) {
3340-
if (nvCtx->cudaCodec == cudaVideoCodec_VC1) {
3341-
nvCtx->vc1PictureStatus = VA_STATUS_ERROR_INVALID_BUFFER;
3342-
break;
3343-
}
33443330
LOG("Invalid buffer detected, skipping: %d", buffers[i]);
33453331
continue;
33463332
}
33473333
HandlerFunc func = nvCtx->codec->handlers[buf->bufferType];
33483334
if (func != NULL) {
33493335
func(nvCtx, buf, picParams);
33503336
} else {
3351-
if (nvCtx->cudaCodec == cudaVideoCodec_VC1) {
3352-
nvCtx->vc1PictureStatus = VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE;
3353-
break;
3354-
}
33553337
LOG("Unhandled buffer type: %d", buf->bufferType);
33563338
}
33573339
}
33583340

3359-
VAStatus status = nvCtx->cudaCodec == cudaVideoCodec_VC1 ? nvCtx->vc1PictureStatus : VA_STATUS_SUCCESS;
3360-
if (status != VA_STATUS_SUCCESS) abortVC1Picture(drv, nvCtx);
33613341
endDecodeCall(drv, nvCtx);
3362-
return status;
3342+
return VA_STATUS_SUCCESS;
33633343
}
33643344

33653345
/* Whether the decoder's display area differs from the size of the frame that
@@ -3436,31 +3416,21 @@ static VAStatus nvEndPicture(
34363416
pthread_mutex_unlock(&drv->objectCreationMutex);
34373417
return VA_STATUS_ERROR_INVALID_CONTEXT;
34383418
}
3439-
if (nvCtx->cudaCodec == cudaVideoCodec_VC1 && !nvCtx->vc1PictureActive) {
3440-
pthread_mutex_unlock(&drv->objectCreationMutex);
3441-
return VA_STATUS_ERROR_OPERATION_FAILED;
3419+
if (nvCtx->codec->checkPicture != NULL) {
3420+
VAStatus status = nvCtx->codec->checkPicture(nvCtx, NV_PICTURE_END);
3421+
if (status != VA_STATUS_SUCCESS) {
3422+
pthread_mutex_unlock(&drv->objectCreationMutex);
3423+
return status;
3424+
}
34423425
}
3443-
if (nvCtx->cudaCodec == cudaVideoCodec_VC1) nvCtx->vc1PictureActive = false;
34443426
nvCtx->activeDecodeCalls++;
34453427
pthread_mutex_unlock(&drv->objectCreationMutex);
34463428

34473429
CUVIDPICPARAMS *picParams = &nvCtx->pPicParams;
34483430

3449-
if (nvCtx->cudaCodec == cudaVideoCodec_VC1) {
3450-
VAStatus status = nvCtx->vc1PictureStatus;
3451-
if (status == VA_STATUS_SUCCESS && (!nvCtx->vc1PictureParameters || picParams->nNumSlices == 0 ||
3452-
nvCtx->lastSliceParamsCount != 0)) status = VA_STATUS_ERROR_INVALID_BUFFER;
3453-
pthread_mutex_lock(&drv->objectCreationMutex);
3454-
if (status == VA_STATUS_SUCCESS && picParams->field_pic_flag && picParams->second_field) {
3455-
if (!nvCtx->vc1FieldPending || nvCtx->vc1FieldSurface != nvCtx->vc1RenderSurface)
3456-
status = VA_STATUS_ERROR_INVALID_PARAMETER;
3457-
} else {
3458-
cancelVC1FieldLocked(drv, nvCtx);
3459-
if (status == VA_STATUS_SUCCESS) setSurfaceResolving(nvCtx->renderTarget, true);
3460-
}
3461-
pthread_mutex_unlock(&drv->objectCreationMutex);
3431+
if (nvCtx->codec->prepareDecode != NULL) {
3432+
VAStatus status = nvCtx->codec->prepareDecode(nvCtx);
34623433
if (status != VA_STATUS_SUCCESS) {
3463-
abortVC1Picture(drv, nvCtx);
34643434
endDecodeCall(drv, nvCtx);
34653435
return status;
34663436
}
@@ -3472,7 +3442,7 @@ static VAStatus nvEndPicture(
34723442
nvCtx->sliceOffsets.size = 0;
34733443

34743444
if (CHECK_CUDA_RESULT(cu->cuCtxPushCurrent(drv->cudaContext))) {
3475-
if (nvCtx->cudaCodec == cudaVideoCodec_VC1) abortVC1Picture(drv, nvCtx);
3445+
if (nvCtx->codec->abortPicture != NULL) nvCtx->codec->abortPicture(nvCtx);
34763446
endDecodeCall(drv, nvCtx);
34773447
return VA_STATUS_ERROR_OPERATION_FAILED;
34783448
}
@@ -3492,7 +3462,7 @@ static VAStatus nvEndPicture(
34923462
nvCtx->decoderHasDecoded = true;
34933463
}
34943464
if (CHECK_CUDA_RESULT(cu->cuCtxPopCurrent(NULL))) {
3495-
if (nvCtx->cudaCodec == cudaVideoCodec_VC1) abortVC1Picture(drv, nvCtx);
3465+
if (nvCtx->codec->abortPicture != NULL) nvCtx->codec->abortPicture(nvCtx);
34963466
endDecodeCall(drv, nvCtx);
34973467
return VA_STATUS_ERROR_OPERATION_FAILED;
34983468
}
@@ -3506,28 +3476,13 @@ static VAStatus nvEndPicture(
35063476
}
35073477
//LOG("Decoded frame successfully to idx: %d (%p)", picParams->CurrPicIdx, nvCtx->renderTarget);
35083478

3509-
// A VC-1 field picture is not displayable until its second field finishes.
3510-
// Queueing the first field lets the resolver publish the shared surface too early.
3511-
if (nvCtx->profile == VAProfileVC1Advanced &&
3512-
picParams->field_pic_flag && !picParams->second_field) {
3513-
if (status != VA_STATUS_SUCCESS) {
3514-
abortVC1Picture(drv, nvCtx);
3515-
} else {
3516-
pthread_mutex_lock(&drv->objectCreationMutex);
3517-
nvCtx->vc1FieldPending = true;
3518-
nvCtx->vc1FieldSurface = nvCtx->vc1RenderSurface;
3519-
pthread_mutex_unlock(&drv->objectCreationMutex);
3520-
}
3479+
// Codecs can defer publication until a complete output picture is available.
3480+
NVSurface *surface = nvCtx->displayTarget != NULL ? nvCtx->displayTarget : nvCtx->renderTarget;
3481+
surface->topFieldFirst = !picParams->bottom_field_flag;
3482+
if (nvCtx->codec->finishDecode != NULL && !nvCtx->codec->finishDecode(nvCtx, status)) {
35213483
endDecodeCall(drv, nvCtx);
35223484
return status;
35233485
}
3524-
3525-
if (nvCtx->cudaCodec == cudaVideoCodec_VC1) {
3526-
pthread_mutex_lock(&drv->objectCreationMutex);
3527-
nvCtx->vc1FieldPending = false;
3528-
pthread_mutex_unlock(&drv->objectCreationMutex);
3529-
}
3530-
NVSurface *surface = nvCtx->displayTarget != NULL ? nvCtx->displayTarget : nvCtx->renderTarget;
35313486
if (surface != nvCtx->renderTarget) {
35323487
setSurfaceResolving(surface, true);
35333488
setSurfaceResolving(nvCtx->renderTarget, false);
@@ -3538,8 +3493,6 @@ static VAStatus nvEndPicture(
35383493
pthread_mutex_lock(&drv->objectCreationMutex);
35393494
surface->contextId = context;
35403495
pthread_mutex_unlock(&drv->objectCreationMutex);
3541-
if (nvCtx->cudaCodec != cudaVideoCodec_VC1)
3542-
surface->topFieldFirst = !picParams->bottom_field_flag;
35433496
surface->secondField = picParams->second_field;
35443497
surface->decodeFailed = status != VA_STATUS_SUCCESS;
35453498

‎src/vabackend.h‎

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -280,14 +280,6 @@ typedef struct _NVContext
280280
pthread_mutex_t surfaceCreationMutex;
281281
int surfaceCount;
282282
bool firstKeyframeValid;
283-
// VC-1 fields share one output surface; only the completed pair is resolved.
284-
VAStatus vc1PictureStatus;
285-
bool vc1PictureParameters;
286-
bool vc1PictureActive;
287-
bool vc1FieldPending;
288-
VASurfaceID vc1FieldSurface;
289-
VASurfaceID vc1RenderSurface;
290-
291283
} NVContext;
292284

293285
typedef struct
@@ -302,7 +294,12 @@ typedef struct
302294

303295
typedef void (*HandlerFunc)(NVContext*, NVBuffer* , CUVIDPICPARAMS*);
304296
typedef cudaVideoCodec (*ComputeCudaCodec)(VAProfile);
305-
typedef void (*CodecBeginPictureFunc)(NVContext*);
297+
typedef enum {
298+
NV_PICTURE_BEGIN,
299+
NV_PICTURE_RENDER,
300+
NV_PICTURE_END,
301+
} NVPictureOperation;
302+
typedef void (*CodecBeginPictureFunc)(NVContext*, VASurfaceID);
306303

307304
// Internals exposed for the stats subsystem (src/stats.c).
308305
pid_t nv_gettid(void);
@@ -316,10 +313,31 @@ struct _NVCodec {
316313
int supportedProfileCount;
317314
const VAProfile *supportedProfiles;
318315
CodecBeginPictureFunc beginPicture;
316+
// Optional lifecycle hooks. checkPicture and surfaceDestroyed run with
317+
// objectCreationMutex held; the other hooks run during an active decode call.
318+
// checkPicture may reject a call before the backend changes its target.
319+
VAStatus (*checkPicture)(NVContext*, NVPictureOperation);
320+
// Override buffer dispatch when a codec needs submission error reporting.
321+
VAStatus (*renderPicture)(NVContext*, VABufferID*, int);
322+
// Validate the assembled picture before CUDA submission; release any
323+
// codec-owned pending output on failure before returning the error.
324+
VAStatus (*prepareDecode)(NVContext*);
325+
// Called after decode with default field order set. May adjust metadata;
326+
// return false to defer resolution or release an incomplete failed output.
327+
bool (*finishDecode)(NVContext*, VAStatus);
328+
// Release codec-owned pending output when CUDA context push/pop fails.
329+
void (*abortPicture)(NVContext*);
330+
void (*surfaceDestroyed)(NVContext*, VASurfaceID, NVSurface*);
319331
};
320332

321333
typedef struct _NVCodec NVCodec;
322334

335+
// Codec helpers. Surface lookup must stay under objectCreationMutex while the
336+
// returned pointer is used; buffer lookup has the same lifetime as RenderPicture.
337+
NVSurface *nvGetSurface(NVDriver *drv, VASurfaceID id);
338+
NVBuffer *nvGetBuffer(NVDriver *drv, VABufferID id);
339+
void nvSetSurfaceResolving(NVSurface *surface, bool resolving);
340+
323341
typedef struct
324342
{
325343
uint32_t bppc; // bytes per pixel per channel

0 commit comments

Comments
 (0)