xref: /aosp_15_r20/external/intel-media-driver/media_driver/linux/common/codec/ddi/media_libva_encoder.cpp (revision ba62d9d3abf0e404f2022b4cd7a85e107f48596f)
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