1 /*
2 * Copyright (c) 2015-2021, 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 //! \file     media_libva_common.cpp
23 //! \brief    libva(and its extension) interface implemantation common functions
24 //!
25 
26 #include "media_libva.h"
27 #include "media_libva_util.h"
28 #include "media_ddi_prot.h"
29 #include "mos_solo_generic.h"
30 #include "mos_interface.h"
31 #include "media_libva_caps.h"
32 
DdiMedia_GetVaContextFromHeap(PDDI_MEDIA_HEAP mediaHeap,uint32_t index,PMEDIA_MUTEX_T mutex)33 static void* DdiMedia_GetVaContextFromHeap(PDDI_MEDIA_HEAP  mediaHeap, uint32_t index, PMEDIA_MUTEX_T mutex)
34 {
35     PDDI_MEDIA_VACONTEXT_HEAP_ELEMENT  vaCtxHeapElmt = nullptr;
36     void                              *context = nullptr;
37 
38     DdiMediaUtil_LockMutex(mutex);
39     if(nullptr == mediaHeap || index >= mediaHeap->uiAllocatedHeapElements)
40     {
41         DdiMediaUtil_UnLockMutex(mutex);
42         return nullptr;
43     }
44     vaCtxHeapElmt  = (PDDI_MEDIA_VACONTEXT_HEAP_ELEMENT)mediaHeap->pHeapBase;
45     vaCtxHeapElmt += index;
46     context        = vaCtxHeapElmt->pVaContext;
47     DdiMediaUtil_UnLockMutex(mutex);
48 
49     return context;
50 }
51 
DdiMedia_MediaSurfaceToMosResource(DDI_MEDIA_SURFACE * mediaSurface,MOS_RESOURCE * mosResource)52 void DdiMedia_MediaSurfaceToMosResource(DDI_MEDIA_SURFACE *mediaSurface, MOS_RESOURCE  *mosResource)
53 {
54     DDI_CHK_NULL(mediaSurface, "nullptr mediaSurface",);
55     DDI_CHK_NULL(mosResource, "nullptr mosResource",);
56     DDI_ASSERT(mosResource->bo);
57 
58     MosInterface::ConvertResourceFromDdi(mediaSurface, mosResource, OS_SPECIFIC_RESOURCE_SURFACE, 0);
59 
60     Mos_Solo_SetOsResource(mediaSurface->pGmmResourceInfo, mosResource);
61 
62     return;
63 }
64 
DdiMedia_MediaBufferToMosResource(DDI_MEDIA_BUFFER * mediaBuffer,MOS_RESOURCE * mosResource)65 void DdiMedia_MediaBufferToMosResource(DDI_MEDIA_BUFFER *mediaBuffer, MOS_RESOURCE *mosResource)
66 {
67     DDI_CHK_NULL(mediaBuffer, "nullptr mediaBuffer",);
68     DDI_CHK_NULL(mosResource, "nullptr mosResource",);
69     DDI_ASSERT(mediaBuffer->bo);
70 
71     MosInterface::ConvertResourceFromDdi(mediaBuffer, mosResource, OS_SPECIFIC_RESOURCE_BUFFER, 0);
72 
73     Mos_Solo_SetOsResource(mediaBuffer->pGmmResourceInfo, mosResource);
74 
75     return;
76 }
77 
DdiMedia_GetContextFromContextID(VADriverContextP ctx,VAContextID vaCtxID,uint32_t * ctxType)78 void* DdiMedia_GetContextFromContextID (VADriverContextP ctx, VAContextID vaCtxID, uint32_t *ctxType)
79 {
80     PDDI_MEDIA_CONTEXT       mediaCtx = nullptr;
81     uint32_t                 index = 0;
82 
83     DDI_CHK_NULL(ctx, "nullptr ctx", nullptr);
84     DDI_CHK_NULL(ctxType, "nullptr ctxType", nullptr);
85 
86     mediaCtx  = DdiMedia_GetMediaContext(ctx);
87     index    = vaCtxID & DDI_MEDIA_MASK_VACONTEXTID;
88 
89     if (index >= DDI_MEDIA_MAX_INSTANCE_NUMBER)
90         return nullptr;
91     if ((vaCtxID&DDI_MEDIA_MASK_VACONTEXT_TYPE) == DDI_MEDIA_VACONTEXTID_OFFSET_PROT)
92     {
93         DDI_VERBOSEMESSAGE("Protected session detected: 0x%x", vaCtxID);
94         *ctxType = DDI_MEDIA_CONTEXT_TYPE_PROTECTED;
95         index = index & DDI_MEDIA_MASK_VAPROTECTEDSESSION_ID;
96         return DdiMedia_GetVaContextFromHeap(mediaCtx->pProtCtxHeap, index, &mediaCtx->ProtMutex);
97     }
98     else if ((vaCtxID&DDI_MEDIA_MASK_VACONTEXT_TYPE) == DDI_MEDIA_VACONTEXTID_OFFSET_DECODER)
99     {
100         DDI_VERBOSEMESSAGE("Decode context detected: 0x%x", vaCtxID);
101         *ctxType = DDI_MEDIA_CONTEXT_TYPE_DECODER;
102         return DdiMedia_GetVaContextFromHeap(mediaCtx->pDecoderCtxHeap, index, &mediaCtx->DecoderMutex);
103     }
104     else if ((vaCtxID&DDI_MEDIA_MASK_VACONTEXT_TYPE) == DDI_MEDIA_VACONTEXTID_OFFSET_ENCODER)
105     {
106         *ctxType = DDI_MEDIA_CONTEXT_TYPE_ENCODER;
107         return DdiMedia_GetVaContextFromHeap(mediaCtx->pEncoderCtxHeap, index, &mediaCtx->EncoderMutex);
108     }
109     else if ((vaCtxID & DDI_MEDIA_MASK_VACONTEXT_TYPE) == DDI_MEDIA_VACONTEXTID_OFFSET_VP)
110     {
111         *ctxType = DDI_MEDIA_CONTEXT_TYPE_VP;
112         return DdiMedia_GetVaContextFromHeap(mediaCtx->pVpCtxHeap, index, &mediaCtx->VpMutex);
113     }
114     else if ((vaCtxID & DDI_MEDIA_MASK_VACONTEXT_TYPE) == DDI_MEDIA_VACONTEXTID_OFFSET_CM)
115     {
116         *ctxType = DDI_MEDIA_CONTEXT_TYPE_CM;
117         return DdiMedia_GetVaContextFromHeap(mediaCtx->pCmCtxHeap, index, &mediaCtx->CmMutex);
118     }
119     else if ((vaCtxID & DDI_MEDIA_MASK_VACONTEXT_TYPE) == DDI_MEDIA_VACONTEXTID_OFFSET_MFE)
120     {
121         *ctxType = DDI_MEDIA_CONTEXT_TYPE_MFE;
122         return DdiMedia_GetVaContextFromHeap(mediaCtx->pMfeCtxHeap, index, &mediaCtx->MfeMutex);
123     }
124     else
125     {
126         DDI_ASSERTMESSAGE("Invalid context: 0x%x", vaCtxID);
127         *ctxType = DDI_MEDIA_CONTEXT_TYPE_NONE;
128         return nullptr;
129     }
130 
131 }
132 
DdiMedia_GetSurfaceFromVASurfaceID(PDDI_MEDIA_CONTEXT mediaCtx,VASurfaceID surfaceID)133 DDI_MEDIA_SURFACE* DdiMedia_GetSurfaceFromVASurfaceID (PDDI_MEDIA_CONTEXT mediaCtx, VASurfaceID surfaceID)
134 {
135     uint32_t                         i = 0;
136     PDDI_MEDIA_SURFACE_HEAP_ELEMENT  surfaceElement = nullptr;
137     PDDI_MEDIA_SURFACE               surface = nullptr;
138 
139     DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", nullptr);
140 
141     i                = (uint32_t)surfaceID;
142     bool validSurface = (i != VA_INVALID_SURFACE);
143     if(validSurface)
144     {
145         DDI_CHK_LESS(i, mediaCtx->pSurfaceHeap->uiAllocatedHeapElements, "invalid surface id", nullptr);
146         DdiMediaUtil_LockMutex(&mediaCtx->SurfaceMutex);
147         surfaceElement  = (PDDI_MEDIA_SURFACE_HEAP_ELEMENT)mediaCtx->pSurfaceHeap->pHeapBase;
148         surfaceElement += i;
149         surface         = surfaceElement->pSurface;
150         DdiMediaUtil_UnLockMutex(&mediaCtx->SurfaceMutex);
151     }
152 
153     return surface;
154 }
155 
DdiMedia_GetVASurfaceIDFromSurface(PDDI_MEDIA_SURFACE surface)156 VASurfaceID DdiMedia_GetVASurfaceIDFromSurface(PDDI_MEDIA_SURFACE surface)
157 {
158     DDI_CHK_NULL(surface, "nullptr surface", VA_INVALID_SURFACE);
159 
160     PDDI_MEDIA_SURFACE_HEAP_ELEMENT  surfaceElement = (PDDI_MEDIA_SURFACE_HEAP_ELEMENT)surface->pMediaCtx->pSurfaceHeap->pHeapBase;
161     for(uint32_t i = 0; i < surface->pMediaCtx->pSurfaceHeap->uiAllocatedHeapElements; i ++)
162     {
163         if(surface == surfaceElement->pSurface)
164         {
165             return surfaceElement->uiVaSurfaceID;
166         }
167         surfaceElement ++;
168     }
169     return VA_INVALID_SURFACE;
170 }
171 
DdiMedia_ReplaceSurfaceWithNewFormat(PDDI_MEDIA_SURFACE surface,DDI_MEDIA_FORMAT expectedFormat)172 PDDI_MEDIA_SURFACE DdiMedia_ReplaceSurfaceWithNewFormat(PDDI_MEDIA_SURFACE surface, DDI_MEDIA_FORMAT expectedFormat)
173 {
174     DDI_CHK_NULL(surface, "nullptr surface", nullptr);
175 
176     PDDI_MEDIA_SURFACE_HEAP_ELEMENT  surfaceElement = (PDDI_MEDIA_SURFACE_HEAP_ELEMENT)surface->pMediaCtx->pSurfaceHeap->pHeapBase;
177     PDDI_MEDIA_CONTEXT mediaCtx = surface->pMediaCtx;
178 
179     //check some conditions
180     if(expectedFormat == surface->format)
181     {
182         return surface;
183     }
184     //create new dst surface and copy the structure
185     PDDI_MEDIA_SURFACE dstSurface = (DDI_MEDIA_SURFACE *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_SURFACE));
186     if (nullptr == surfaceElement)
187     {
188         MOS_FreeMemory(dstSurface);
189         return nullptr;
190     }
191 
192     MOS_SecureMemcpy(dstSurface,sizeof(DDI_MEDIA_SURFACE),surface,sizeof(DDI_MEDIA_SURFACE));
193     DDI_CHK_NULL(dstSurface, "nullptr dstSurface", nullptr);
194     dstSurface->format = expectedFormat;
195     dstSurface->uiLockedBufID = VA_INVALID_ID;
196     dstSurface->uiLockedImageID = VA_INVALID_ID;
197     dstSurface->pSurfDesc = nullptr;
198     //lock surface heap
199     DdiMediaUtil_LockMutex(&mediaCtx->SurfaceMutex);
200     uint32_t i;
201     //get current element heap and index
202     for(i = 0; i < mediaCtx->pSurfaceHeap->uiAllocatedHeapElements; i ++)
203     {
204         if(surface == surfaceElement->pSurface)
205         {
206             break;
207         }
208         surfaceElement ++;
209     }
210     //if cant find
211     if(i == surface->pMediaCtx->pSurfaceHeap->uiAllocatedHeapElements)
212     {
213         DdiMediaUtil_LockMutex(&mediaCtx->SurfaceMutex);
214         MOS_FreeMemory(dstSurface);
215         return nullptr;
216     }
217     //FreeSurface
218     DdiMediaUtil_FreeSurface(surface);
219     MOS_FreeMemory(surface);
220     //CreateNewSurface
221     DdiMediaUtil_CreateSurface(dstSurface,mediaCtx);
222     surfaceElement->pSurface = dstSurface;
223 
224     DdiMediaUtil_UnLockMutex(&mediaCtx->SurfaceMutex);
225 
226     return dstSurface;
227 }
228 
DdiMedia_ReplaceSurfaceWithVariant(PDDI_MEDIA_SURFACE surface,VAEntrypoint entrypoint)229 PDDI_MEDIA_SURFACE DdiMedia_ReplaceSurfaceWithVariant(PDDI_MEDIA_SURFACE surface, VAEntrypoint entrypoint)
230 {
231     DDI_CHK_NULL(surface, "nullptr surface", nullptr);
232 
233     PDDI_MEDIA_CONTEXT mediaCtx = surface->pMediaCtx;
234     uint32_t aligned_width, aligned_height;
235     DDI_MEDIA_FORMAT aligned_format;
236 
237     //check some conditions
238     if(surface->uiVariantFlag)
239     {
240         return surface;
241     }
242 
243     VASurfaceID vaID = DdiMedia_GetVASurfaceIDFromSurface(surface);
244     if(VA_INVALID_SURFACE == vaID)
245     {
246         return nullptr;
247     }
248 
249     DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
250     PDDI_MEDIA_SURFACE_HEAP_ELEMENT  surfaceElement = (PDDI_MEDIA_SURFACE_HEAP_ELEMENT)surface->pMediaCtx->pSurfaceHeap->pHeapBase;
251     DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
252     if (nullptr == surfaceElement)
253     {
254         return nullptr;
255     }
256     DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
257     surfaceElement += vaID;
258     DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
259 
260     aligned_format = surface->format;
261     switch (surface->format)
262     {
263         case Media_Format_AYUV:
264 #if VA_CHECK_VERSION(1, 13, 0)
265         case Media_Format_XYUV:
266 #endif
267             aligned_width = MOS_ALIGN_CEIL(surface->iWidth, 128);
268             aligned_height = MOS_ALIGN_CEIL(surface->iHeight * 3 / 4, 64);
269             break;
270         case Media_Format_Y410:
271             aligned_width = MOS_ALIGN_CEIL(surface->iWidth, 64);
272             aligned_height = MOS_ALIGN_CEIL(surface->iHeight * 3 / 2, 64);
273             break;
274         case Media_Format_Y216:
275 #if VA_CHECK_VERSION(1, 9, 0)
276         case Media_Format_Y212:
277 #endif
278         case Media_Format_Y210:
279             aligned_width = (surface->iWidth + 1) >> 1;
280             aligned_height = surface->iHeight * 2;
281             aligned_format = Media_Format_Y216;
282             break;
283         case Media_Format_YUY2:
284             aligned_width = (surface->iWidth + 1) >> 1;
285             aligned_height = surface->iHeight * 2;
286             break;
287         case Media_Format_P016:
288         case Media_Format_P012:
289         case Media_Format_P010:
290             aligned_height = surface->iHeight;
291             aligned_width = surface->iWidth;
292             if(entrypoint == VAEntrypointEncSlice)
293             {
294                 aligned_width = surface->iWidth * 2;
295                 aligned_format = Media_Format_NV12;
296             }
297             else
298             {
299                 aligned_format = Media_Format_P016;
300             }
301             break;
302         default:
303             return surface;
304        }
305 
306     //create new dst surface and copy the structure
307     PDDI_MEDIA_SURFACE dstSurface = (DDI_MEDIA_SURFACE *)MOS_AllocAndZeroMemory(sizeof(DDI_MEDIA_SURFACE));
308 
309     MOS_SecureMemcpy(dstSurface,sizeof(DDI_MEDIA_SURFACE),surface,sizeof(DDI_MEDIA_SURFACE));
310     DDI_CHK_NULL(dstSurface, "nullptr dstSurface", nullptr);
311 
312     dstSurface->uiVariantFlag = 1;
313     dstSurface->format = aligned_format;
314     dstSurface->iWidth = aligned_width;
315     dstSurface->iHeight = aligned_height;
316    //CreateNewSurface
317     if(DdiMediaUtil_CreateSurface(dstSurface,mediaCtx) != VA_STATUS_SUCCESS)
318     {
319         MOS_FreeMemory(dstSurface);
320         return surface;
321     }
322     //replace the surface
323     DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
324     surfaceElement = (PDDI_MEDIA_SURFACE_HEAP_ELEMENT)surface->pMediaCtx->pSurfaceHeap->pHeapBase;
325     surfaceElement += vaID;
326     surfaceElement->pSurface = dstSurface;
327     DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
328     //FreeSurface
329     DdiMediaUtil_FreeSurface(surface);
330     MOS_FreeMemory(surface);
331 
332     return dstSurface;
333 }
334 
DdiMedia_GetBufferFromVABufferID(PDDI_MEDIA_CONTEXT mediaCtx,VABufferID bufferID)335 DDI_MEDIA_BUFFER* DdiMedia_GetBufferFromVABufferID (PDDI_MEDIA_CONTEXT mediaCtx, VABufferID bufferID)
336 {
337     uint32_t                       i = 0;
338     PDDI_MEDIA_BUFFER_HEAP_ELEMENT bufHeapElement = nullptr;
339     PDDI_MEDIA_BUFFER              buf = nullptr;
340 
341     i                = (uint32_t)bufferID;
342     DDI_CHK_LESS(i, mediaCtx->pBufferHeap->uiAllocatedHeapElements, "invalid buffer id", nullptr);
343     DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
344     bufHeapElement  = (PDDI_MEDIA_BUFFER_HEAP_ELEMENT)mediaCtx->pBufferHeap->pHeapBase;
345     bufHeapElement += i;
346     buf             = bufHeapElement->pBuffer;
347     DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
348 
349     return buf;
350 }
351 
DdiMedia_DestroyBufFromVABufferID(PDDI_MEDIA_CONTEXT mediaCtx,VABufferID bufferID)352 bool DdiMedia_DestroyBufFromVABufferID (PDDI_MEDIA_CONTEXT mediaCtx, VABufferID bufferID)
353 {
354     DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
355     DdiMediaUtil_ReleasePMediaBufferFromHeap(mediaCtx->pBufferHeap, bufferID);
356     mediaCtx->uiNumBufs--;
357     DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
358     return true;
359 }
360 
DdiMedia_GetContextFromVABufferID(PDDI_MEDIA_CONTEXT mediaCtx,VABufferID bufferID)361 void* DdiMedia_GetContextFromVABufferID (PDDI_MEDIA_CONTEXT mediaCtx, VABufferID bufferID)
362 {
363     uint32_t                       i;
364     PDDI_MEDIA_BUFFER_HEAP_ELEMENT bufHeapElement;
365     void *                         ctx;
366 
367     i                = (uint32_t)bufferID;
368     DDI_CHK_LESS(i, mediaCtx->pBufferHeap->uiAllocatedHeapElements, "invalid buffer id", nullptr);
369     DdiMediaUtil_LockMutex(&mediaCtx->BufferMutex);
370     bufHeapElement  = (PDDI_MEDIA_BUFFER_HEAP_ELEMENT)mediaCtx->pBufferHeap->pHeapBase;
371     bufHeapElement += bufferID;
372     ctx            = bufHeapElement->pCtx;
373     DdiMediaUtil_UnLockMutex(&mediaCtx->BufferMutex);
374 
375     return ctx;
376 }
377 
DdiMedia_GetGpuPriority(VADriverContextP ctx,VABufferID * buffers,int32_t numBuffers,bool * updatePriority,int32_t * priority)378 int32_t DdiMedia_GetGpuPriority (VADriverContextP ctx, VABufferID *buffers, int32_t numBuffers, bool *updatePriority, int32_t *priority)
379 {
380     void *        data;
381     uint32_t      updateSessionPriority  = 0;
382     uint32_t      priorityValue          = 0;
383     int32_t       priorityIndexInBuf     = -1;
384 
385     DDI_CHK_NULL(ctx, "nullptr context in DdiMedia_GetGpuPriority!", -1);
386 
387     PDDI_MEDIA_CONTEXT mediaCtx = DdiMedia_GetMediaContext(ctx);
388     DDI_CHK_NULL(mediaCtx, "nullptr mediaCtx", -1);
389 #if VA_CHECK_VERSION(1, 10, 0)
390     for (int32_t i = 0; i < numBuffers; i++)
391     {
392         DDI_MEDIA_BUFFER *buf = DdiMedia_GetBufferFromVABufferID(mediaCtx, buffers[i]);
393         DDI_CHK_NULL(buf, "Invalid buffer.", -1);
394 
395         if((int32_t)buf->uiType == VAContextParameterUpdateBufferType)
396         {
397             //Read the priority from the VAContextParameterUpdateBuffer
398             DdiMedia_MapBuffer(ctx, buffers[i], &data);
399             DDI_CHK_NULL(data, "nullptr data.", -1);
400 
401             VAContextParameterUpdateBuffer *ContextParamBuf = (VAContextParameterUpdateBuffer *)data;
402             DDI_CHK_NULL(ContextParamBuf, "nullptr ContextParamBuf.", -1);
403 
404             updateSessionPriority   = ContextParamBuf->flags.bits.context_priority_update;
405             priorityValue           = ContextParamBuf->context_priority.bits.priority;
406 
407             if (updateSessionPriority)
408             {
409                 *updatePriority = true;
410                 if(priorityValue >= 0 && priorityValue <= CONTEXT_PRIORITY_MAX)
411                 {
412                     *priority = priorityValue - CONTEXT_PRIORITY_MAX/2;
413                 }
414                 else
415                 {
416                     *priority = 0;
417                 }
418             }
419             else
420             {
421                 *updatePriority = false;
422                 *priority = 0;
423             }
424 
425             DdiMedia_UnmapBuffer(ctx, buffers[i]);
426             priorityIndexInBuf = i;
427             break;
428         }
429     }
430 #endif
431     return priorityIndexInBuf;
432 }
433 
434 //Move the priority bufferID to the end of buffers
MovePriorityBufferIdToEnd(VABufferID * buffers,int32_t priorityIndexInBuf,int32_t numBuffers)435 void MovePriorityBufferIdToEnd (VABufferID *buffers, int32_t priorityIndexInBuf, int32_t numBuffers)
436 {
437     VABufferID    vaBufferID = 0;
438     if( (numBuffers > 1) && (priorityIndexInBuf < numBuffers -1) )
439     {
440         vaBufferID = buffers[priorityIndexInBuf];
441         while(priorityIndexInBuf < (numBuffers - 1) )
442         {
443             buffers[priorityIndexInBuf] = buffers[priorityIndexInBuf+1];
444             priorityIndexInBuf++;
445         }
446         buffers[numBuffers -1] = vaBufferID;
447     }
448 }
449 
450