1 /*
2 * Copyright (c) 2009-2020, Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22 //!
23 //! \file media_libva_encoder.cpp
24 //! \brief libva(and its extension) encoder implementation
25 //!
26 #include <unistd.h>
27 #include "media_libva_encoder.h"
28 #include "media_ddi_encode_base.h"
29 #include "media_libva_util.h"
30 #include "media_libva_caps.h"
31 #include "media_ddi_factory.h"
32
33 #include "hwinfo_linux.h"
34 #include "codechal_memdecomp.h"
35 #include "media_interfaces_codechal.h"
36 #include "media_interfaces_codechal_next.h"
37 #include "media_interfaces_mmd.h"
38 #include "cm_device_rt.h"
39
40 typedef MediaDdiFactoryNoArg<DdiEncodeBase> DdiEncodeFactory;
41
DdiEncode_GetEncContextFromContextID(VADriverContextP ctx,VAContextID vaCtxID)42 PDDI_ENCODE_CONTEXT DdiEncode_GetEncContextFromContextID(VADriverContextP ctx, VAContextID vaCtxID)
43 {
44 uint32_t ctxType;
45 return (PDDI_ENCODE_CONTEXT)DdiMedia_GetContextFromContextID(ctx, vaCtxID, &ctxType);
46 }
47
DdiEncode_RemoveFromStatusReportQueue(PDDI_ENCODE_CONTEXT encCtx,PDDI_MEDIA_BUFFER buf)48 VAStatus DdiEncode_RemoveFromStatusReportQueue(
49 PDDI_ENCODE_CONTEXT encCtx,
50 PDDI_MEDIA_BUFFER buf)
51
52 {
53 DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
54 DDI_CHK_NULL(encCtx->m_encode, "nullptr encCtx->m_encode", VA_STATUS_ERROR_INVALID_CONTEXT);
55 DDI_CHK_NULL(buf, "nullptr buf", VA_STATUS_ERROR_INVALID_PARAMETER);
56
57 VAStatus vaStatus = encCtx->m_encode->RemoveFromStatusReportQueue(buf);
58
59 return vaStatus;
60 }
61
DdiEncode_RemoveFromEncStatusReportQueue(PDDI_ENCODE_CONTEXT encCtx,PDDI_MEDIA_BUFFER buf,DDI_ENCODE_FEI_ENC_BUFFER_TYPE typeIdx)62 VAStatus DdiEncode_RemoveFromEncStatusReportQueue(
63 PDDI_ENCODE_CONTEXT encCtx,
64 PDDI_MEDIA_BUFFER buf,
65 DDI_ENCODE_FEI_ENC_BUFFER_TYPE typeIdx)
66 {
67 DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
68 DDI_CHK_NULL(encCtx->m_encode, "nullptr encCtx->m_encode", VA_STATUS_ERROR_INVALID_CONTEXT);
69 DDI_CHK_NULL(buf, "nullptr buf", VA_STATUS_ERROR_INVALID_PARAMETER);
70
71 VAStatus vaStatus = encCtx->m_encode->RemoveFromEncStatusReportQueue(buf, typeIdx);
72
73 return vaStatus;
74 }
75
DdiEncode_RemoveFromPreEncStatusReportQueue(PDDI_ENCODE_CONTEXT encCtx,PDDI_MEDIA_BUFFER buf,DDI_ENCODE_PRE_ENC_BUFFER_TYPE typeIdx)76 VAStatus DdiEncode_RemoveFromPreEncStatusReportQueue(
77 PDDI_ENCODE_CONTEXT encCtx,
78 PDDI_MEDIA_BUFFER buf,
79 DDI_ENCODE_PRE_ENC_BUFFER_TYPE typeIdx)
80 {
81 DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
82 DDI_CHK_NULL(encCtx->m_encode, "nullptr encCtx->m_encode", VA_STATUS_ERROR_INVALID_CONTEXT);
83 DDI_CHK_NULL(buf, "nullptr buf", VA_STATUS_ERROR_INVALID_PARAMETER);
84
85 VAStatus vaStatus = encCtx->m_encode->RemoveFromPreEncStatusReportQueue(buf, typeIdx);
86
87 return vaStatus;
88 }
89
DdiEncode_CodedBufferExistInStatusReport(PDDI_ENCODE_CONTEXT encCtx,PDDI_MEDIA_BUFFER buf)90 bool DdiEncode_CodedBufferExistInStatusReport(
91 PDDI_ENCODE_CONTEXT encCtx,
92 PDDI_MEDIA_BUFFER buf)
93 {
94 DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
95 DDI_CHK_NULL(encCtx->m_encode, "nullptr encCtx->m_encode", VA_STATUS_ERROR_INVALID_CONTEXT);
96 DDI_CHK_NULL(buf, "nullptr buf", VA_STATUS_ERROR_INVALID_PARAMETER);
97
98 return encCtx->m_encode->CodedBufferExistInStatusReport(buf);
99 }
100
DdiEncode_EncBufferExistInStatusReport(PDDI_ENCODE_CONTEXT encCtx,PDDI_MEDIA_BUFFER buf,DDI_ENCODE_FEI_ENC_BUFFER_TYPE typeIdx)101 bool DdiEncode_EncBufferExistInStatusReport(
102 PDDI_ENCODE_CONTEXT encCtx,
103 PDDI_MEDIA_BUFFER buf,
104 DDI_ENCODE_FEI_ENC_BUFFER_TYPE typeIdx)
105 {
106 DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
107 DDI_CHK_NULL(encCtx->m_encode, "nullptr encCtx->m_encode", VA_STATUS_ERROR_INVALID_CONTEXT);
108 DDI_CHK_NULL(buf, "nullptr buf", VA_STATUS_ERROR_INVALID_PARAMETER);
109
110 return encCtx->m_encode->EncBufferExistInStatusReport(buf, typeIdx);
111 }
112
DdiEncode_PreEncBufferExistInStatusReport(PDDI_ENCODE_CONTEXT encCtx,PDDI_MEDIA_BUFFER buf,DDI_ENCODE_PRE_ENC_BUFFER_TYPE typeIdx)113 bool DdiEncode_PreEncBufferExistInStatusReport(
114 PDDI_ENCODE_CONTEXT encCtx,
115 PDDI_MEDIA_BUFFER buf,
116 DDI_ENCODE_PRE_ENC_BUFFER_TYPE typeIdx)
117 {
118 DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
119 DDI_CHK_NULL(encCtx->m_encode, "nullptr encCtx->m_encode", VA_STATUS_ERROR_INVALID_CONTEXT);
120 DDI_CHK_NULL(buf, "nullptr buf", VA_STATUS_ERROR_INVALID_PARAMETER);
121
122 return encCtx->m_encode->PreEncBufferExistInStatusReport(buf, typeIdx);
123 }
124
DdiEncode_EncStatusReport(PDDI_ENCODE_CONTEXT encCtx,DDI_MEDIA_BUFFER * mediaBuf,void ** buf)125 VAStatus DdiEncode_EncStatusReport(
126 PDDI_ENCODE_CONTEXT encCtx,
127 DDI_MEDIA_BUFFER *mediaBuf,
128 void **buf)
129 {
130 DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
131 DDI_CHK_NULL(encCtx->m_encode, "nullptr encCtx->m_encode", VA_STATUS_ERROR_INVALID_CONTEXT);
132 DDI_CHK_NULL(mediaBuf, "nullptr mediaBuf", VA_STATUS_ERROR_INVALID_PARAMETER);
133 DDI_CHK_NULL(buf, "nullptr buf", VA_STATUS_ERROR_INVALID_PARAMETER);
134
135 VAStatus vaStatus = encCtx->m_encode->EncStatusReport(mediaBuf, buf);
136
137 return vaStatus;
138 }
139
DdiEncode_PreEncStatusReport(PDDI_ENCODE_CONTEXT encCtx,DDI_MEDIA_BUFFER * mediaBuf,void ** buf)140 VAStatus DdiEncode_PreEncStatusReport(
141 PDDI_ENCODE_CONTEXT encCtx,
142 DDI_MEDIA_BUFFER *mediaBuf,
143 void **buf)
144 {
145 DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
146 DDI_CHK_NULL(encCtx->m_encode, "nullptr encCtx->m_encode", VA_STATUS_ERROR_INVALID_CONTEXT);
147 DDI_CHK_NULL(mediaBuf, "nullptr mediaBuf", VA_STATUS_ERROR_INVALID_PARAMETER);
148 DDI_CHK_NULL(buf, "nullptr buf", VA_STATUS_ERROR_INVALID_PARAMETER);
149
150 VAStatus vaStatus = encCtx->m_encode->PreEncStatusReport(mediaBuf, buf);
151
152 return vaStatus;
153 }
154
DdiEncode_StatusReport(PDDI_ENCODE_CONTEXT encCtx,DDI_MEDIA_BUFFER * mediaBuf,void ** buf)155 VAStatus DdiEncode_StatusReport(
156 PDDI_ENCODE_CONTEXT encCtx,
157 DDI_MEDIA_BUFFER *mediaBuf,
158 void **buf)
159 {
160 PERF_UTILITY_AUTO(__FUNCTION__, PERF_ENCODE, PERF_LEVEL_DDI);
161
162 DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
163 DDI_CHK_NULL(encCtx->m_encode, "nullptr encCtx->m_encode", VA_STATUS_ERROR_INVALID_CONTEXT);
164 DDI_CHK_NULL(mediaBuf, "nullptr mediaBuf", VA_STATUS_ERROR_INVALID_PARAMETER);
165 DDI_CHK_NULL(buf, "nullptr buf", VA_STATUS_ERROR_INVALID_PARAMETER);
166
167 VAStatus vaStatus = encCtx->m_encode->StatusReport(mediaBuf, buf);
168
169 return vaStatus;
170 }
171
172 //!
173 //! \brief Clean and free encode context structure
174 //!
175 //! \param [in] encCtx
176 //! Pointer to ddi encode context
177 //!
DdiEncodeCleanUp(PDDI_ENCODE_CONTEXT encCtx)178 void DdiEncodeCleanUp(PDDI_ENCODE_CONTEXT encCtx)
179 {
180 if (encCtx->m_encode)
181 {
182 MOS_Delete(encCtx->m_encode);
183 encCtx->m_encode = nullptr;
184 }
185
186 if (encCtx->pCpDdiInterface)
187 {
188 Delete_DdiCpInterface(encCtx->pCpDdiInterface);
189 encCtx->pCpDdiInterface = nullptr;
190 }
191
192 MOS_FreeMemory(encCtx);
193 encCtx = nullptr;
194
195 return;
196 }
197
198 /*
199 * vpgEncodeCreateContext - Create an encode context
200 * dpy: display
201 * config_id: configuration for the encode context
202 * picture_width: encode picture width
203 * picture_height: encode picture height
204 * flag: any combination of the following:
205 * VA_PROGRESSIVE (only progressive frame pictures in the sequence when set)
206 * render_targets: render targets (surfaces) tied to the context
207 * num_render_targets: number of render targets in the above array
208 * context: created context id upon return
209 */
DdiEncode_CreateContext(VADriverContextP ctx,VAConfigID config_id,int32_t picture_width,int32_t picture_height,int32_t flag,VASurfaceID * render_targets,int32_t num_render_targets,VAContextID * context)210 VAStatus DdiEncode_CreateContext(
211 VADriverContextP ctx,
212 VAConfigID config_id,
213 int32_t picture_width,
214 int32_t picture_height,
215 int32_t flag,
216 VASurfaceID *render_targets,
217 int32_t num_render_targets,
218 VAContextID *context)
219 {
220 PERF_UTILITY_AUTO(__FUNCTION__, PERF_ENCODE, PERF_LEVEL_DDI);
221
222 DDI_CHK_NULL(ctx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT);
223 DDI_CHK_NULL(ctx->pDriverData, "nullptr ctx->pDriverData", VA_STATUS_ERROR_INVALID_CONTEXT);
224
225 PDDI_MEDIA_CONTEXT mediaDrvCtx = DdiMedia_GetMediaContext(ctx);
226 DDI_CHK_NULL(mediaDrvCtx->m_caps, "nullptr m_caps", VA_STATUS_ERROR_INVALID_CONTEXT);
227
228 VAProfile profile;
229 VAEntrypoint entrypoint;
230 uint32_t rcMode = 0;
231 uint32_t feiFunction = 0;
232 VAStatus vaStatus = mediaDrvCtx->m_caps->GetEncConfigAttr(
233 config_id + DDI_CODEC_GEN_CONFIG_ATTRIBUTES_ENC_BASE,
234 &profile,
235 &entrypoint,
236 &rcMode,
237 &feiFunction);
238 DDI_CHK_RET(vaStatus, "Invalide config_id!");
239
240 vaStatus = mediaDrvCtx->m_caps->CheckEncodeResolution(
241 profile,
242 picture_width,
243 picture_height);
244 if (vaStatus != VA_STATUS_SUCCESS)
245 {
246 return VA_STATUS_ERROR_RESOLUTION_NOT_SUPPORTED;
247 }
248
249 if (num_render_targets > DDI_MEDIA_MAX_SURFACE_NUMBER_CONTEXT)
250 {
251 return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
252 }
253
254 std::string encodeKey = mediaDrvCtx->m_caps->GetEncodeCodecKey(profile, entrypoint, feiFunction);
255 DdiEncodeBase *ddiEncode = DdiEncodeFactory::CreateCodec(encodeKey);
256 DDI_CHK_NULL(ddiEncode, "nullptr ddiEncode", VA_STATUS_ERROR_UNIMPLEMENTED);
257
258 // first create encoder context
259 ddiEncode->m_encodeCtx = (PDDI_ENCODE_CONTEXT)MOS_AllocAndZeroMemory(sizeof(DDI_ENCODE_CONTEXT));
260 DDI_CHK_NULL(ddiEncode->m_encodeCtx, "nullptr ddiEncode->m_encodeCtx", VA_STATUS_ERROR_ALLOCATION_FAILED);
261
262 PDDI_ENCODE_CONTEXT encCtx = ddiEncode->m_encodeCtx;
263 encCtx->m_encode = ddiEncode;
264
265 //initialize DDI level cp interface
266 MOS_CONTEXT mosCtx = { };
267 encCtx->pCpDdiInterface = Create_DdiCpInterface(mosCtx);
268 if (nullptr == encCtx->pCpDdiInterface)
269 {
270 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
271 DdiEncodeCleanUp(encCtx);
272 return vaStatus;
273 }
274
275 // Get the buf manager for codechal create
276 mosCtx.bufmgr = mediaDrvCtx->pDrmBufMgr;
277 mosCtx.m_gpuContextMgr = mediaDrvCtx->m_gpuContextMgr;
278 mosCtx.m_cmdBufMgr = mediaDrvCtx->m_cmdBufMgr;
279 mosCtx.fd = mediaDrvCtx->fd;
280 mosCtx.iDeviceId = mediaDrvCtx->iDeviceId;
281 mosCtx.m_skuTable = mediaDrvCtx->SkuTable;
282 mosCtx.m_waTable = mediaDrvCtx->WaTable;
283 mosCtx.m_gtSystemInfo = *mediaDrvCtx->pGtSystemInfo;
284 mosCtx.m_platform = mediaDrvCtx->platform;
285
286 mosCtx.ppMediaMemDecompState = &mediaDrvCtx->pMediaMemDecompState;
287 mosCtx.pfnMemoryDecompress = mediaDrvCtx->pfnMemoryDecompress;
288 mosCtx.pfnMediaMemoryCopy = mediaDrvCtx->pfnMediaMemoryCopy;
289 mosCtx.pfnMediaMemoryCopy2D = mediaDrvCtx->pfnMediaMemoryCopy2D;
290 mosCtx.ppMediaCopyState = &mediaDrvCtx->pMediaCopyState;
291 mosCtx.m_gtSystemInfo = *mediaDrvCtx->pGtSystemInfo;
292 mosCtx.m_auxTableMgr = mediaDrvCtx->m_auxTableMgr;
293 mosCtx.pGmmClientContext = mediaDrvCtx->pGmmClientContext;
294
295 mosCtx.m_osDeviceContext = mediaDrvCtx->m_osDeviceContext;
296 mosCtx.m_apoMosEnabled = mediaDrvCtx->m_apoMosEnabled;
297
298 mosCtx.m_userSettingPtr = mediaDrvCtx->m_userSettingPtr;
299
300 mosCtx.pPerfData = (PERF_DATA *)MOS_AllocAndZeroMemory(sizeof(PERF_DATA));
301 if (nullptr == mosCtx.pPerfData)
302 {
303 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
304 DdiEncodeCleanUp(encCtx);
305 return vaStatus;
306 }
307
308 encCtx->vaEntrypoint = entrypoint;
309 encCtx->vaProfile = profile;
310 encCtx->uiRCMethod = rcMode;
311 encCtx->wModeType = mediaDrvCtx->m_caps->GetEncodeCodecMode(profile, entrypoint);
312 encCtx->codecFunction = mediaDrvCtx->m_caps->GetEncodeCodecFunction(profile, entrypoint, feiFunction);
313
314 if (entrypoint == VAEntrypointEncSliceLP)
315 {
316 encCtx->bVdencActive = true;
317 }
318
319 //Both dual pipe and LP pipe should support 10bit for below profiles
320 // - HEVCMain10 profile
321 // - VAProfileVP9Profile2
322 // - VAProfileVP9Profile3
323 if (profile == VAProfileVP9Profile2 ||
324 profile == VAProfileVP9Profile3)
325 {
326 encCtx->m_encode->m_is10Bit = true;
327 }
328
329 if (profile == VAProfileVP9Profile1 ||
330 profile == VAProfileVP9Profile3)
331 {
332 encCtx->m_encode->m_chromaFormat = DdiEncodeBase::yuv444;
333 }
334
335 CODECHAL_STANDARD_INFO standardInfo;
336 MOS_ZeroMemory(&standardInfo, sizeof(CODECHAL_STANDARD_INFO));
337 standardInfo.CodecFunction = encCtx->codecFunction;
338 standardInfo.Mode = encCtx->wModeType;
339 Codechal *pCodecHal = CodechalDevice::CreateFactory(
340 nullptr,
341 &mosCtx,
342 &standardInfo,
343 nullptr);
344 if (pCodecHal == nullptr)
345 {
346 pCodecHal = CodechalDeviceNext::CreateFactory(
347 nullptr,
348 &mosCtx,
349 &standardInfo,
350 nullptr);
351
352 if (nullptr == pCodecHal)
353 {
354 // add anything necessary here to free the resource
355 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
356 DdiEncodeCleanUp(encCtx);
357 return vaStatus;
358 }
359 }
360
361 encCtx->pCodecHal = pCodecHal;
362
363 // Setup some initial data
364 encCtx->dworiFrameWidth = picture_width;
365 encCtx->dworiFrameHeight = picture_height;
366 encCtx->wPicWidthInMB = (uint16_t)(DDI_CODEC_NUM_MACROBLOCKS_WIDTH(picture_width));
367 encCtx->wPicHeightInMB = (uint16_t)(DDI_CODEC_NUM_MACROBLOCKS_HEIGHT(picture_height));
368 encCtx->dwFrameWidth = encCtx->wPicWidthInMB * CODECHAL_MACROBLOCK_WIDTH;
369 encCtx->dwFrameHeight = encCtx->wPicHeightInMB * CODECHAL_MACROBLOCK_HEIGHT;
370 //recoder old resolution for dynamic resolution change
371 encCtx->wContextPicWidthInMB = encCtx->wPicWidthInMB;
372 encCtx->wContextPicHeightInMB = encCtx->wPicHeightInMB;
373 encCtx->wOriPicWidthInMB = encCtx->wPicWidthInMB;
374 encCtx->wOriPicHeightInMB = encCtx->wPicHeightInMB;
375 encCtx->targetUsage = TARGETUSAGE_RT_SPEED;
376 // Attach PMEDIDA_DRIVER_CONTEXT
377 encCtx->pMediaCtx = mediaDrvCtx;
378
379 encCtx->pCpDdiInterface->SetCpFlags(flag);
380 encCtx->pCpDdiInterface->SetCpParams(CP_TYPE_NONE, encCtx->m_encode->m_codechalSettings);
381
382 vaStatus = encCtx->m_encode->ContextInitialize(encCtx->m_encode->m_codechalSettings);
383
384 if (vaStatus != VA_STATUS_SUCCESS)
385 {
386 DdiEncodeCleanUp(encCtx);
387 return vaStatus;
388 }
389
390 MOS_STATUS eStatus = pCodecHal->Allocate(encCtx->m_encode->m_codechalSettings);
391
392 #ifdef _MMC_SUPPORTED
393 PMOS_INTERFACE osInterface = pCodecHal->GetOsInterface();
394 if (osInterface != nullptr &&
395 !osInterface->apoMosEnabled &&
396 MEDIA_IS_SKU(osInterface->pfnGetSkuTable(osInterface), FtrMemoryCompression) &&
397 !mediaDrvCtx->pMediaMemDecompState)
398 {
399 mediaDrvCtx->pMediaMemDecompState =
400 static_cast<MediaMemDecompState*>(MmdDevice::CreateFactory(&mosCtx));
401 }
402 #endif
403
404 if (eStatus != MOS_STATUS_SUCCESS)
405 {
406 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
407 DdiEncodeCleanUp(encCtx);
408 return vaStatus;
409 }
410
411 vaStatus = encCtx->m_encode->InitCompBuffer();
412 if (vaStatus != VA_STATUS_SUCCESS)
413 {
414 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
415 DdiEncodeCleanUp(encCtx);
416 return vaStatus;
417 }
418
419 // register the render target surfaces for this encoder instance
420 // This is a must as driver has the constraint, 127 surfaces per context
421 for (int32_t i = 0; i < num_render_targets; i++)
422 {
423 DDI_MEDIA_SURFACE *surface;
424
425 surface = DdiMedia_GetSurfaceFromVASurfaceID(mediaDrvCtx, render_targets[i]);
426 if (nullptr == surface)
427 {
428 DDI_ASSERTMESSAGE("DDI: invalid render target %d in vpgEncodeCreateContext.", i);
429 vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
430 DdiEncodeCleanUp(encCtx);
431 return vaStatus;
432 }
433 encCtx->RTtbl.pRT[i] = surface;
434 encCtx->RTtbl.iNumRenderTargets++;
435 }
436
437 // convert PDDI_ENCODE_CONTEXT to VAContextID
438 DdiMediaUtil_LockMutex(&mediaDrvCtx->EncoderMutex);
439 PDDI_MEDIA_VACONTEXT_HEAP_ELEMENT vaContextHeapElmt = DdiMediaUtil_AllocPVAContextFromHeap(mediaDrvCtx->pEncoderCtxHeap);
440 if (nullptr == vaContextHeapElmt)
441 {
442 DdiMediaUtil_UnLockMutex(&mediaDrvCtx->EncoderMutex);
443 vaStatus = VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
444 DdiEncodeCleanUp(encCtx);
445 return vaStatus;
446 }
447
448 vaContextHeapElmt->pVaContext = (void*)encCtx;
449 mediaDrvCtx->uiNumEncoders++;
450 *context = (VAContextID)(vaContextHeapElmt->uiVaContextID + DDI_MEDIA_VACONTEXTID_OFFSET_ENCODER);
451 DdiMediaUtil_UnLockMutex(&mediaDrvCtx->EncoderMutex);
452
453 return vaStatus;
454 }
455
456 /*
457 * vaDestroyContext - Destroy a context
458 * dpy: display
459 * context: context to be destroyed
460 */
DdiEncode_DestroyContext(VADriverContextP ctx,VAContextID context)461 VAStatus DdiEncode_DestroyContext(VADriverContextP ctx, VAContextID context)
462 {
463 DDI_CHK_NULL(ctx, "nullptr ctx", VA_STATUS_ERROR_INVALID_CONTEXT);
464 DDI_CHK_NULL(ctx->pDriverData, "nullptr ctx->pDriverData", VA_STATUS_ERROR_INVALID_CONTEXT);
465
466 PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
467 DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
468
469 // assume the VAContextID is encoder ID
470 PDDI_ENCODE_CONTEXT encCtx = DdiEncode_GetEncContextFromContextID(ctx, context);
471 DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
472 DDI_CHK_NULL(encCtx->pCodecHal, "nullptr encCtx->pCodecHal", VA_STATUS_ERROR_INVALID_CONTEXT);
473
474 Codechal *codecHal = encCtx->pCodecHal;
475
476 if (nullptr != encCtx->m_encode)
477 {
478 encCtx->m_encode->FreeCompBuffer();
479 if(nullptr != encCtx->m_encode->m_codechalSettings)
480 {
481 MOS_Delete(encCtx->m_encode->m_codechalSettings);
482 encCtx->m_encode->m_codechalSettings = nullptr;
483 }
484 }
485
486 if (codecHal->GetOsInterface() && codecHal->GetOsInterface()->pOsContext)
487 {
488 MOS_FreeMemory(codecHal->GetOsInterface()->pOsContext->pPerfData);
489 codecHal->GetOsInterface()->pOsContext->pPerfData = nullptr;
490 }
491
492 // destroy codechal
493 codecHal->Destroy();
494 MOS_Delete(codecHal);
495
496 if (encCtx->pCpDdiInterface)
497 {
498 Delete_DdiCpInterface(encCtx->pCpDdiInterface);
499 encCtx->pCpDdiInterface = nullptr;
500 }
501
502 if (nullptr != encCtx->m_encode)
503 {
504 MOS_Delete(encCtx->m_encode);
505 encCtx->m_encode = nullptr;
506 }
507
508 MOS_FreeMemory(encCtx);
509 encCtx = nullptr;
510
511 uint32_t encIndex = (uint32_t)context;
512 encIndex &= DDI_MEDIA_MASK_VACONTEXTID;
513
514 DdiMediaUtil_LockMutex(&mediaCtx->EncoderMutex);
515 DdiMediaUtil_ReleasePVAContextFromHeap(mediaCtx->pEncoderCtxHeap, encIndex);
516 mediaCtx->uiNumEncoders--;
517 DdiMediaUtil_UnLockMutex(&mediaCtx->EncoderMutex);
518
519 return VA_STATUS_SUCCESS;
520 }
521
522 /*
523 * Creates a buffer for "num_elements" elements of "size" bytes and
524 * initalize with "data".
525 * if "data" is null, then the contents of the buffer data store
526 * are undefined.
527 * Basically there are two ways to get buffer data to the server side. One is
528 * to call vaCreateBuffer() with a non-null "data", which results the data being
529 * copied to the data store on the server side. A different method that
530 * eliminates this copy is to pass null as "data" when calling vaCreateBuffer(),
531 * and then use vaMapBuffer() to map the data store from the server side to the
532 * client address space for access.
533 * Note: image buffers are created by the library, not the client. Please see
534 * vaCreateImage on how image buffers are managed.
535 */
536
DdiEncode_CreateBuffer(VADriverContextP ctx,VAContextID context,VABufferType type,uint32_t size,uint32_t num_elements,void * data,VABufferID * buf_id)537 VAStatus DdiEncode_CreateBuffer(
538 VADriverContextP ctx,
539 VAContextID context,
540 VABufferType type,
541 uint32_t size,
542 uint32_t num_elements,
543 void *data,
544 VABufferID *buf_id)
545 {
546 DDI_CHK_NULL(ctx, "nullptr context!", VA_STATUS_ERROR_INVALID_CONTEXT);
547
548 DDI_ENCODE_CONTEXT *encCtx = DdiEncode_GetEncContextFromContextID(ctx, context);
549 DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
550 DDI_CHK_NULL(encCtx->m_encode, "nullptr encCtx->m_encode", VA_STATUS_ERROR_INVALID_CONTEXT);
551
552 VAStatus vaStatus = encCtx->m_encode->CreateBuffer(ctx, type, size, num_elements, data, buf_id);
553
554 return vaStatus;
555 }
556
557 /*
558 * Get ready to encode a picture
559 */
DdiEncode_BeginPicture(VADriverContextP ctx,VAContextID context,VASurfaceID render_target)560 VAStatus DdiEncode_BeginPicture(
561 VADriverContextP ctx,
562 VAContextID context,
563 VASurfaceID render_target)
564 {
565 PERF_UTILITY_AUTO(__FUNCTION__, PERF_ENCODE, PERF_LEVEL_DDI);
566
567 DDI_FUNCTION_ENTER();
568
569 DDI_CHK_NULL(ctx, "nullptr context in vpgEncodeBeginPicture!", VA_STATUS_ERROR_INVALID_CONTEXT);
570
571 // assume the VAContextID is encoder ID
572 PDDI_ENCODE_CONTEXT encCtx = DdiEncode_GetEncContextFromContextID(ctx, context);
573 DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
574 DDI_CHK_NULL(encCtx->m_encode, "nullptr encCtx->m_encode", VA_STATUS_ERROR_INVALID_CONTEXT);
575
576 VAStatus vaStatus = encCtx->m_encode->BeginPicture(ctx, context, render_target);
577 DDI_FUNCTION_EXIT(vaStatus);
578 return vaStatus;
579 }
580
581 /*
582 * Send encode buffers to the server.
583 * Buffers are automatically destroyed afterwards
584 */
DdiEncode_RenderPicture(VADriverContextP ctx,VAContextID context,VABufferID * buffers,int32_t num_buffers)585 VAStatus DdiEncode_RenderPicture(
586 VADriverContextP ctx,
587 VAContextID context,
588 VABufferID *buffers,
589 int32_t num_buffers)
590 {
591 VAStatus vaStatus = VA_STATUS_SUCCESS;
592 int32_t numOfBuffers = num_buffers;
593 int32_t priority = 0;
594 int32_t priorityIndexInBuffers = -1;
595 bool updatePriority = false;
596
597 PERF_UTILITY_AUTO(__FUNCTION__, PERF_ENCODE, PERF_LEVEL_DDI);
598
599 DDI_FUNCTION_ENTER();
600
601 DDI_CHK_NULL(ctx, "nullptr context in vpgEncodeRenderPicture!", VA_STATUS_ERROR_INVALID_CONTEXT);
602
603 // assume the VAContextID is encoder ID
604 PDDI_ENCODE_CONTEXT encCtx = DdiEncode_GetEncContextFromContextID(ctx, context);
605 DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
606 DDI_CHK_NULL(encCtx->m_encode, "nullptr encCtx->m_encode", VA_STATUS_ERROR_INVALID_CONTEXT);
607
608 priorityIndexInBuffers = DdiMedia_GetGpuPriority(ctx, buffers, numOfBuffers, &updatePriority, &priority);
609 if (priorityIndexInBuffers != -1)
610 {
611 if(updatePriority)
612 {
613 vaStatus = DdiEncode_SetGpuPriority(encCtx, priority);
614 if(vaStatus != VA_STATUS_SUCCESS)
615 return vaStatus;
616 }
617 MovePriorityBufferIdToEnd(buffers, priorityIndexInBuffers, numOfBuffers);
618 numOfBuffers--;
619 }
620 if (numOfBuffers == 0)
621 return vaStatus;
622
623 vaStatus = encCtx->m_encode->RenderPicture(ctx, context, buffers, numOfBuffers);
624 DDI_FUNCTION_EXIT(vaStatus);
625 return vaStatus;
626 }
627
DdiEncode_EndPicture(VADriverContextP ctx,VAContextID context)628 VAStatus DdiEncode_EndPicture(VADriverContextP ctx, VAContextID context)
629 {
630 PERF_UTILITY_AUTO(__FUNCTION__, PERF_ENCODE, PERF_LEVEL_DDI);
631
632 DDI_FUNCTION_ENTER();
633
634 DDI_CHK_NULL(ctx, "nullptr context in vpgEncodeEndPicture!", VA_STATUS_ERROR_INVALID_CONTEXT);
635
636 // assume the VAContextID is encoder ID
637 PDDI_ENCODE_CONTEXT encCtx = DdiEncode_GetEncContextFromContextID(ctx, context);
638 DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
639 DDI_CHK_NULL(encCtx->m_encode, "nullptr encCtx->m_encode", VA_STATUS_ERROR_INVALID_CONTEXT);
640
641 VAStatus vaStatus = encCtx->m_encode->EndPicture(ctx, context);
642 DDI_FUNCTION_EXIT(vaStatus);
643 return vaStatus;
644 }
645
DdiEncode_MfeSubmit(VADriverContextP ctx,VAMFContextID mfe_context,VAContextID * contexts,int32_t num_contexts)646 VAStatus DdiEncode_MfeSubmit(
647 VADriverContextP ctx,
648 VAMFContextID mfe_context,
649 VAContextID *contexts,
650 int32_t num_contexts
651 )
652 {
653 PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
654 DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
655
656 uint32_t ctxType = DDI_MEDIA_CONTEXT_TYPE_NONE;
657 PDDI_ENCODE_MFE_CONTEXT encodeMfeContext = (PDDI_ENCODE_MFE_CONTEXT)DdiMedia_GetContextFromContextID(ctx, mfe_context, &ctxType);
658 DDI_CHK_NULL(encodeMfeContext, "nullptr encodeMfeContext", VA_STATUS_ERROR_INVALID_CONTEXT);
659
660 std::vector<PDDI_ENCODE_CONTEXT> encodeContexts;
661 PDDI_ENCODE_CONTEXT encodeContext = nullptr;
662 int32_t validContextNumber = 0;
663 // Set mfe encoder params for this submission
664 for (int32_t i = 0; i < num_contexts; i++)
665 {
666 encodeContext = DdiEncode_GetEncContextFromContextID(ctx, contexts[i]);
667 DDI_CHK_NULL(encodeContext, "nullptr encodeContext", VA_STATUS_ERROR_INVALID_CONTEXT);
668 CodechalEncoderState *encoder = dynamic_cast<CodechalEncoderState *>(encodeContext->pCodecHal);
669 DDI_CHK_NULL(encoder, "nullptr codechal encoder", VA_STATUS_ERROR_INVALID_CONTEXT);
670
671 if (!encoder->m_mfeEnabled ||
672 encoder->m_mfeEncodeSharedState != encodeMfeContext->mfeEncodeSharedState)
673 {
674 return VA_STATUS_ERROR_INVALID_CONTEXT;
675 }
676
677 // make sure the context has called BeginPicture&RenderPicture&EndPicture
678 if (encodeContext->RTtbl.pRT[0] == nullptr
679 || encodeContext->dwNumSlices <= 0
680 || encodeContext->EncodeParams.pBSBuffer != encodeContext->pbsBuffer)
681 {
682 return VA_STATUS_ERROR_INVALID_PARAMETER;
683 }
684
685 encoder->m_mfeEncodeParams.submitIndex = i;
686 encoder->m_mfeEncodeParams.submitNumber = num_contexts;
687 encodeContexts.push_back(encodeContext);
688 validContextNumber++;
689 }
690
691 CmDevice *device = encodeMfeContext->mfeEncodeSharedState->pCmDev;
692 CmTask *task = encodeMfeContext->mfeEncodeSharedState->pCmTask;
693 CmQueue *queue = encodeMfeContext->mfeEncodeSharedState->pCmQueue;
694 CodechalEncodeMdfKernelResource *resMbencKernel = encodeMfeContext->mfeEncodeSharedState->resMbencKernel;
695 SurfaceIndex *vmeSurface = encodeMfeContext->mfeEncodeSharedState->vmeSurface;
696 SurfaceIndex *commonSurface = encodeMfeContext->mfeEncodeSharedState->commonSurface;
697
698
699 MOS_ZeroMemory(encodeMfeContext->mfeEncodeSharedState, sizeof(MfeSharedState));
700
701 encodeMfeContext->mfeEncodeSharedState->pCmDev = device;
702 encodeMfeContext->mfeEncodeSharedState->pCmTask = task;
703 encodeMfeContext->mfeEncodeSharedState->pCmQueue = queue;
704 encodeMfeContext->mfeEncodeSharedState->resMbencKernel = resMbencKernel;
705 encodeMfeContext->mfeEncodeSharedState->vmeSurface = vmeSurface;
706 encodeMfeContext->mfeEncodeSharedState->commonSurface = commonSurface;
707
708 encodeMfeContext->mfeEncodeSharedState->encoders.clear();
709
710 // Call Enc functions for all the sub contexts
711 MOS_STATUS status = MOS_STATUS_SUCCESS;
712 for (int32_t i = 0; i < validContextNumber; i++)
713 {
714 encodeContext = encodeContexts[i];
715 if (encodeContext->vaEntrypoint != VAEntrypointFEI )
716 {
717 encodeContext->EncodeParams.ExecCodecFunction = CODECHAL_FUNCTION_ENC;
718 }
719 else
720 {
721 encodeContext->EncodeParams.ExecCodecFunction = CODECHAL_FUNCTION_FEI_ENC;
722 }
723
724 CodechalEncoderState *encoder = dynamic_cast<CodechalEncoderState *>(encodeContext->pCodecHal);
725 DDI_CHK_NULL(encoder, "nullptr encoder", VA_STATUS_ERROR_INVALID_CONTEXT);
726
727 encodeMfeContext->mfeEncodeSharedState->encoders.push_back(encoder);
728
729 status = encoder->Execute(&encodeContext->EncodeParams);
730 if (MOS_STATUS_SUCCESS != status)
731 {
732 DDI_ASSERTMESSAGE("DDI:Failed in Execute Enc!");
733 return VA_STATUS_ERROR_ENCODING_ERROR;
734 }
735 }
736
737 // Call Pak functions for all the sub contexts
738 for (int32_t i = 0; i < validContextNumber; i++)
739 {
740 encodeContext = encodeContexts[i];
741 if (encodeContext->vaEntrypoint != VAEntrypointFEI )
742 {
743 encodeContext->EncodeParams.ExecCodecFunction = CODECHAL_FUNCTION_PAK;
744 }
745 else
746 {
747 encodeContext->EncodeParams.ExecCodecFunction = CODECHAL_FUNCTION_FEI_PAK;
748 }
749
750 CodechalEncoderState *encoder = dynamic_cast<CodechalEncoderState *>(encodeContext->pCodecHal);
751 DDI_CHK_NULL(encoder, "nullptr encoder", VA_STATUS_ERROR_INVALID_CONTEXT);
752
753 status = encoder->Execute(&encodeContext->EncodeParams);
754 if (MOS_STATUS_SUCCESS != status)
755 {
756 DDI_ASSERTMESSAGE("DDI:Failed in Execute Pak!");
757 return VA_STATUS_ERROR_ENCODING_ERROR;
758 }
759 }
760
761 return VA_STATUS_SUCCESS;
762 }
763
DdiEncode_SetGpuPriority(PDDI_ENCODE_CONTEXT encCtx,int32_t priority)764 VAStatus DdiEncode_SetGpuPriority(
765 PDDI_ENCODE_CONTEXT encCtx,
766 int32_t priority
767 )
768 {
769 DDI_CHK_NULL(encCtx, "nullptr encCtx", VA_STATUS_ERROR_INVALID_CONTEXT);
770
771 if(encCtx->pCodecHal != nullptr)
772 {
773 PMOS_INTERFACE osInterface = encCtx->pCodecHal->GetOsInterface();
774 DDI_CHK_NULL(osInterface, "nullptr osInterface.", VA_STATUS_ERROR_ALLOCATION_FAILED);
775
776 //Set Gpu priority for encoder
777 osInterface->pfnSetGpuPriority(osInterface, priority);
778
779 //Get the CMRT osInterface of encode
780 CodechalEncoderState *encoder = dynamic_cast<CodechalEncoderState *>(encCtx->pCodecHal);
781 DDI_CHK_NULL(encoder, "nullptr encoder", VA_STATUS_ERROR_INVALID_CONTEXT);
782
783 if(encoder->m_cmDev != nullptr)
784 {
785 //Set Gpu priority for CMRT OsInterface
786 CmDeviceRTBase *cm_device = dynamic_cast<CmDeviceRTBase *>(encoder->m_cmDev);
787 DDI_CHK_NULL(cm_device, "nullptr cm_device", VA_STATUS_ERROR_INVALID_PARAMETER);
788
789 PCM_HAL_STATE cm_hal_state = cm_device->GetHalState();
790 if(cm_hal_state->osInterface != nullptr)
791 cm_hal_state->osInterface->pfnSetGpuPriority(cm_hal_state->osInterface, priority);
792 }
793 }
794
795 return VA_STATUS_SUCCESS;
796 }
797
798