1 /*
2 * Copyright (c) 2018-2022, 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 //!
24 //! \file     encode_scalability_multipipe.cpp
25 //! \brief    Defines the common interface for encode scalability multipipe mode.
26 //!
27 
28 #include "encode_scalability_multipipe.h"
29 
30 #include "media_context.h"
31 #include "media_status_report.h"
32 #include "mhw_utilities.h"
33 #include "encode_status_report_defs.h"
34 #include "hal_oca_interface_next.h"
35 #include "mos_os_virtualengine_next.h"
36 #include "mos_interface.h"
37 
38 namespace encode
39 {
EncodeScalabilityMultiPipe(void * hwInterface,MediaContext * mediaContext,uint8_t componentType)40 EncodeScalabilityMultiPipe::EncodeScalabilityMultiPipe(void *hwInterface, MediaContext *mediaContext, uint8_t componentType) :
41     MediaScalabilityMultiPipe(mediaContext)
42 {
43     m_hwInterface   = (CodechalHwInterfaceNext *)hwInterface;
44     m_componentType = componentType;
45 }
46 
~EncodeScalabilityMultiPipe()47 EncodeScalabilityMultiPipe::~EncodeScalabilityMultiPipe()
48 {
49 }
AllocateSemaphore()50 MOS_STATUS EncodeScalabilityMultiPipe::AllocateSemaphore()
51 {
52     SCALABILITY_FUNCTION_ENTER;
53     SCALABILITY_CHK_NULL_RETURN(m_osInterface);
54     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
55 
56     uint32_t *      data = nullptr;
57     MOS_LOCK_PARAMS lockFlagsWriteOnly;
58     MOS_ZeroMemory(&lockFlagsWriteOnly, sizeof(MOS_LOCK_PARAMS));
59     lockFlagsWriteOnly.WriteOnly = 1;
60     MOS_ALLOC_GFXRES_PARAMS allocParamsForBufferLinear;
61     MOS_ZeroMemory(&allocParamsForBufferLinear, sizeof(MOS_ALLOC_GFXRES_PARAMS));
62     allocParamsForBufferLinear.TileType = MOS_TILE_LINEAR;
63     allocParamsForBufferLinear.Format   = Format_Buffer;
64     allocParamsForBufferLinear.Type     = MOS_GFXRES_BUFFER;
65     allocParamsForBufferLinear.dwBytes  = sizeof(uint32_t);
66     allocParamsForBufferLinear.pBufName = "Sync All Pipes SemaphoreMemory";
67 
68     for (auto i = 0; i < CODECHAL_GET_ARRAY_LENGTH(m_resSemaphoreAllPipes); i++)
69     {
70         SCALABILITY_CHK_STATUS_MESSAGE_RETURN(m_osInterface->pfnAllocateResource(
71                                                   m_osInterface,
72                                                   &allocParamsForBufferLinear,
73                                                   &m_resSemaphoreAllPipes[i]),
74             "Cannot create HW semaphore for scalability all pipes sync.");
75         data = (uint32_t *)m_osInterface->pfnLockResource(
76             m_osInterface,
77             &m_resSemaphoreAllPipes[i],
78             &lockFlagsWriteOnly);
79         SCALABILITY_CHK_NULL_RETURN(data);
80         *data = 0;
81         SCALABILITY_CHK_STATUS_RETURN(m_osInterface->pfnUnlockResource(
82             m_osInterface,
83             &m_resSemaphoreAllPipes[i]));
84     }
85 
86     allocParamsForBufferLinear.pBufName = "Sync One Pipe Wait SemaphoreMemory";
87 
88     for (auto i = 0; i < CODECHAL_GET_ARRAY_LENGTH(m_resSemaphoreOnePipeWait); i++)
89     {
90         SCALABILITY_CHK_STATUS_MESSAGE_RETURN(m_osInterface->pfnAllocateResource(
91                                                   m_osInterface,
92                                                   &allocParamsForBufferLinear,
93                                                   &m_resSemaphoreOnePipeWait[i]),
94             "Cannot create HW semaphore for scalability one pipe sync.");
95         data = (uint32_t *)m_osInterface->pfnLockResource(
96             m_osInterface,
97             &m_resSemaphoreOnePipeWait[i],
98             &lockFlagsWriteOnly);
99         SCALABILITY_CHK_NULL_RETURN(data);
100         *data = 0;
101         SCALABILITY_CHK_STATUS_RETURN(m_osInterface->pfnUnlockResource(
102             m_osInterface,
103             &m_resSemaphoreOnePipeWait[i]));
104     }
105 
106     allocParamsForBufferLinear.pBufName = "HW semaphore delay buffer";
107 
108     SCALABILITY_CHK_STATUS_MESSAGE_RETURN(m_osInterface->pfnAllocateResource(
109         m_osInterface,
110         &allocParamsForBufferLinear,
111         &m_resDelayMinus),
112         "Cannot create HW semaphore delay buffer.");
113     data = (uint32_t *)m_osInterface->pfnLockResource(
114         m_osInterface,
115         &m_resDelayMinus,
116         &lockFlagsWriteOnly);
117     SCALABILITY_CHK_NULL_RETURN(data);
118     *data = 0;
119     SCALABILITY_CHK_STATUS_RETURN(m_osInterface->pfnUnlockResource(
120         m_osInterface,
121         &m_resDelayMinus));
122 
123     allocParamsForBufferLinear.pBufName = "Sync One Pipe For Another SemaphoreMemory";
124 
125     SCALABILITY_CHK_STATUS_MESSAGE_RETURN(m_osInterface->pfnAllocateResource(
126                                               m_osInterface,
127                                               &allocParamsForBufferLinear,
128                                               &m_resSemaphoreOnePipeForAnother),
129         "Cannot create HW semaphore for scalability one pipe wait for another.");
130     data = (uint32_t *)m_osInterface->pfnLockResource(
131         m_osInterface,
132         &m_resSemaphoreOnePipeForAnother,
133         &lockFlagsWriteOnly);
134     SCALABILITY_CHK_NULL_RETURN(data);
135     *data = 0;
136     SCALABILITY_CHK_STATUS_RETURN(m_osInterface->pfnUnlockResource(
137         m_osInterface,
138         &m_resSemaphoreOnePipeForAnother));
139 
140     allocParamsForBufferLinear.pBufName = "Sync Other Pipes For One SemaphoreMemory";
141 
142     SCALABILITY_CHK_STATUS_MESSAGE_RETURN(m_osInterface->pfnAllocateResource(
143                                               m_osInterface,
144                                               &allocParamsForBufferLinear,
145                                               &m_resSemaphoreOtherPipesForOne),
146         "Cannot create HW semaphore for scalability other pipes wait for one.");
147     data = (uint32_t *)m_osInterface->pfnLockResource(
148         m_osInterface,
149         &m_resSemaphoreOtherPipesForOne,
150         &lockFlagsWriteOnly);
151     SCALABILITY_CHK_NULL_RETURN(data);
152     *data = 0;
153     SCALABILITY_CHK_STATUS_RETURN(m_osInterface->pfnUnlockResource(
154         m_osInterface,
155         &m_resSemaphoreOtherPipesForOne));
156 
157     return eStatus;
158 }
Initialize(const MediaScalabilityOption & option)159 MOS_STATUS EncodeScalabilityMultiPipe::Initialize(const MediaScalabilityOption &option)
160 {
161     SCALABILITY_FUNCTION_ENTER;
162 
163     SCALABILITY_CHK_NULL_RETURN(m_hwInterface);
164     m_osInterface = m_hwInterface->GetOsInterface();
165     SCALABILITY_CHK_NULL_RETURN(m_osInterface);
166     m_miItf = m_hwInterface->GetMiInterfaceNext();
167     SCALABILITY_CHK_NULL_RETURN(m_miItf);
168     m_userSettingPtr = m_osInterface->pfnGetUserSettingInstance(m_osInterface);
169     if (!m_userSettingPtr)
170     {
171         ENCODE_NORMALMESSAGE("Initialize m_userSettingPtr instance failed!");
172     }
173 
174     m_scalabilityOption = MOS_New(EncodeScalabilityOption, (const EncodeScalabilityOption &)option);
175     SCALABILITY_CHK_NULL_RETURN(m_scalabilityOption);
176 
177     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
178 
179     MediaUserSetting::Value outValue;
180     auto statusKey = ReadUserSetting(
181                         m_userSettingPtr,
182                         outValue,
183                         "Enable Frame Tracking",
184                         MediaUserSetting::Group::Sequence);
185 
186     if (statusKey == MOS_STATUS_SUCCESS)
187     {
188         m_frameTrackingEnabled = outValue.Get<bool>();
189     }
190     else
191     {
192         m_frameTrackingEnabled = m_osInterface->bEnableKmdMediaFrameTracking ? true : false;
193     }
194 
195     //virtual engine init with scalability
196     MOS_VIRTUALENGINE_INIT_PARAMS veInitParms;
197     MOS_ZeroMemory(&veInitParms, sizeof(veInitParms));
198     veInitParms.bScalabilitySupported = true;
199 
200     // Disabling the Secondary command buffer creation in MOS_VE
201     // To be programmed once Encode moves to using secondary command buffers in MOS VE interface
202     veInitParms.ucMaxNumPipesInUse             = MOS_MAX_ENGINE_INSTANCE_PER_CLASS;
203     veInitParms.ucNumOfSdryCmdBufSets          = 16;
204     veInitParms.ucMaxNumOfSdryCmdBufInOneFrame = veInitParms.ucMaxNumPipesInUse * m_maxNumBRCPasses;
205 
206     SCALABILITY_CHK_STATUS_RETURN(m_osInterface->pfnVirtualEngineInit(m_osInterface, &m_veHitParams, veInitParms));
207     SCALABILITY_CHK_NULL_RETURN(m_osInterface->osStreamState);
208     m_veState = m_osInterface->osStreamState->virtualEngineInterface;
209     SCALABILITY_CHK_NULL_RETURN(m_veState);
210     SCALABILITY_CHK_NULL_RETURN(m_veHitParams);
211 
212     m_pipeNum = m_scalabilityOption->GetNumPipe();
213     if (m_pipeNum > m_maxPipeNum)
214     {
215         SCALABILITY_ASSERTMESSAGE("numPipe exceed max supported pipe number!");
216         return MOS_STATUS_INVALID_PARAMETER;
217     }
218     m_pipeIndexForSubmit = m_pipeNum;
219 
220     PMOS_GPUCTX_CREATOPTIONS_ENHANCED gpuCtxCreateOption = MOS_New(MOS_GPUCTX_CREATOPTIONS_ENHANCED);
221     SCALABILITY_CHK_NULL_RETURN(gpuCtxCreateOption);
222     gpuCtxCreateOption->LRCACount = m_scalabilityOption->GetNumPipe();
223     gpuCtxCreateOption->UsingSFC  = false;
224 
225     EncodeScalabilityOption *scalabilityOption  =
226                     dynamic_cast<EncodeScalabilityOption *>(m_scalabilityOption);
227     if (scalabilityOption != nullptr && scalabilityOption->IsVdencEnabled())
228     {
229         gpuCtxCreateOption->Flags |=  (1 << 2);
230     }
231 #if (_DEBUG || _RELEASE_INTERNAL)
232     if (m_osInterface->bEnableDbgOvrdInVE)
233     {
234         gpuCtxCreateOption->DebugOverride = true;
235         for (uint32_t i = 0; i < m_osInterface->pfnGetVeEngineCount(m_osInterface->osStreamState); i++)
236         {
237             gpuCtxCreateOption->EngineInstance[i] =
238                 m_osInterface->pfnGetEngineLogicIdByIdx(m_osInterface->osStreamState, i);
239         }
240     }
241 #endif
242     m_gpuCtxCreateOption = (PMOS_GPUCTX_CREATOPTIONS)(gpuCtxCreateOption);
243 
244     //Allocate and init for semaphores
245     SCALABILITY_CHK_STATUS_RETURN(AllocateSemaphore());
246 
247     //Update encoder scalability status
248     SCALABILITY_CHK_STATUS_RETURN(m_osInterface->pfnSetMultiEngineEnabled(m_osInterface, COMPONENT_Encode, true));
249     return eStatus;
250 }
251 
GetGpuCtxCreationOption(MOS_GPUCTX_CREATOPTIONS * gpuCtxCreateOption)252 MOS_STATUS EncodeScalabilityMultiPipe::GetGpuCtxCreationOption(MOS_GPUCTX_CREATOPTIONS *gpuCtxCreateOption)
253 {
254     SCALABILITY_FUNCTION_ENTER;
255     SCALABILITY_CHK_NULL_RETURN(gpuCtxCreateOption);
256     SCALABILITY_CHK_NULL_RETURN(m_gpuCtxCreateOption);
257 
258     MOS_GPUCTX_CREATOPTIONS_ENHANCED *dest = dynamic_cast<MOS_GPUCTX_CREATOPTIONS_ENHANCED *>(gpuCtxCreateOption);
259     MOS_GPUCTX_CREATOPTIONS_ENHANCED *source = dynamic_cast<MOS_GPUCTX_CREATOPTIONS_ENHANCED *>(m_gpuCtxCreateOption);
260 
261     SCALABILITY_CHK_NULL_RETURN(dest);
262     SCALABILITY_CHK_NULL_RETURN(source);
263 
264     *dest = *source;
265     return MOS_STATUS_SUCCESS;
266 }
267 
Destroy()268 MOS_STATUS EncodeScalabilityMultiPipe::Destroy()
269 {
270     SCALABILITY_FUNCTION_ENTER;
271 
272     SCALABILITY_CHK_STATUS_RETURN(MediaScalability::Destroy());
273 
274     if (m_gpuCtxCreateOption)
275     {
276         MOS_Delete(m_gpuCtxCreateOption);
277     }
278     if (m_scalabilityOption)
279     {
280         MOS_Delete(m_scalabilityOption);
281     }
282 
283     for (auto i = 0; i < CODECHAL_GET_ARRAY_LENGTH(m_resSemaphoreAllPipes); i++)
284     {
285         m_osInterface->pfnFreeResource(m_osInterface, &m_resSemaphoreAllPipes[i]);
286     }
287     for (auto i = 0; i < CODECHAL_GET_ARRAY_LENGTH(m_resSemaphoreOnePipeWait); i++)
288     {
289         m_osInterface->pfnFreeResource(m_osInterface, &m_resSemaphoreOnePipeWait[i]);
290     }
291 
292     m_osInterface->pfnFreeResource(m_osInterface, &m_resSemaphoreOnePipeForAnother);
293 
294     m_osInterface->pfnFreeResource(m_osInterface, &m_resSemaphoreOtherPipesForOne);
295 
296     m_osInterface->pfnFreeResource(m_osInterface, &m_resDelayMinus);
297 
298     SCALABILITY_CHK_STATUS_RETURN(m_osInterface->pfnSetMultiEngineEnabled(m_osInterface, COMPONENT_Encode, false));
299 
300     return MOS_STATUS_SUCCESS;
301 }
302 
ResizeCommandBufferAndPatchList(uint32_t requestedCommandBufferSize,uint32_t requestedPatchListSize)303 MOS_STATUS EncodeScalabilityMultiPipe::ResizeCommandBufferAndPatchList(
304     uint32_t                    requestedCommandBufferSize,
305     uint32_t                    requestedPatchListSize)
306 {
307     SCALABILITY_FUNCTION_ENTER;
308     SCALABILITY_CHK_NULL_RETURN(m_hwInterface);
309 
310     return m_hwInterface->ResizeCommandBufferAndPatchList(requestedCommandBufferSize, requestedPatchListSize);
311 }
312 
313 //Move it to MediaScalabiliyt if decode&VP can share it. Curryt only EncodeMultiPipe/SiglePipe can share it.
VerifySpaceAvailable(uint32_t requestedSize,uint32_t requestedPatchListSize,bool & singleTaskPhaseSupportedInPak)314 MOS_STATUS EncodeScalabilityMultiPipe::VerifySpaceAvailable(uint32_t requestedSize, uint32_t requestedPatchListSize, bool &singleTaskPhaseSupportedInPak)
315 {
316     SCALABILITY_FUNCTION_ENTER;
317     SCALABILITY_CHK_NULL_RETURN(m_hwInterface);
318     SCALABILITY_CHK_NULL_RETURN(m_osInterface);
319 
320     MOS_STATUS eStatus           = MOS_STATUS_SUCCESS;
321     MOS_STATUS statusPatchList   = MOS_STATUS_SUCCESS;
322     MOS_STATUS statusCmdBuf      = MOS_STATUS_SUCCESS;
323 
324     bool bothPatchListAndCmdBufChkSuccess = false;
325     uint8_t looptimes = m_singleTaskPhaseSupported ? 2 : 1;
326 
327     for(auto i = 0 ; i < looptimes ; i++)
328     {
329         SCALABILITY_CHK_STATUS_RETURN(MediaScalability::VerifySpaceAvailable(
330             requestedSize, requestedPatchListSize, bothPatchListAndCmdBufChkSuccess));
331         if (bothPatchListAndCmdBufChkSuccess == true)
332         {
333             singleTaskPhaseSupportedInPak = m_singleTaskPhaseSupported;
334             return eStatus;
335         }
336 
337         if (requestedPatchListSize)
338         {
339             statusPatchList = (MOS_STATUS)m_osInterface->pfnVerifyPatchListSize(
340                 m_osInterface,
341                 requestedPatchListSize);
342         }
343         statusCmdBuf = (MOS_STATUS)m_osInterface->pfnVerifyCommandBufferSize(
344             m_osInterface,
345             requestedSize,
346             0);
347         if ((statusCmdBuf == MOS_STATUS_SUCCESS) && (statusPatchList == MOS_STATUS_SUCCESS))
348         {
349             singleTaskPhaseSupportedInPak = m_singleTaskPhaseSupported;
350             return eStatus;
351         }
352     }
353 
354     eStatus = MOS_STATUS_NO_SPACE;
355     SCALABILITY_ASSERTMESSAGE("Resize Command buffer failed with no space!");
356     return eStatus;
357 }
358 
VerifyCmdBuffer(uint32_t requestedSize,uint32_t requestedPatchListSize,bool & singleTaskPhaseSupportedInPak)359 MOS_STATUS EncodeScalabilityMultiPipe::VerifyCmdBuffer(uint32_t requestedSize, uint32_t requestedPatchListSize, bool &singleTaskPhaseSupportedInPak)
360 {
361     SCALABILITY_FUNCTION_ENTER;
362     SCALABILITY_CHK_NULL_RETURN(m_hwInterface);
363     SCALABILITY_CHK_NULL_RETURN(m_osInterface);
364 
365     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
366 
367     // Verify Primary Cmd buffer.
368     SCALABILITY_CHK_STATUS_RETURN(VerifySpaceAvailable(
369         requestedSize, requestedPatchListSize, singleTaskPhaseSupportedInPak));
370 
371     // Verify all pipes' secondary cmd buffers
372     for (uint8_t currentPipeVerify = 0; currentPipeVerify < m_pipeNum; currentPipeVerify++)
373     {
374         MOS_STATUS statusPatchList = MOS_STATUS_SUCCESS;
375         MOS_STATUS statusCmdBuf    = MOS_STATUS_SUCCESS;
376 
377 
378         //Verify 2nd level BB;
379         uint32_t bufIdxPlus1 = currentPipeVerify + 1;  //Make CMD buffer one next to one.
380 
381         eStatus = MOS_STATUS_NO_SPACE;
382         for (auto i = 0; (i < 3) && (eStatus != MOS_STATUS_SUCCESS); i++)
383         {
384             // Verify secondary cmd buffer
385             eStatus = (MOS_STATUS)m_osInterface->pfnVerifyCommandBufferSize(
386                 m_osInterface,
387                 requestedSize,
388                 bufIdxPlus1);
389             if (eStatus != MOS_STATUS_SUCCESS)
390             {
391                 SCALABILITY_CHK_STATUS_RETURN(m_osInterface->pfnResizeCommandBufferAndPatchList(
392                     m_osInterface,
393                     requestedSize,
394                     0,
395                     bufIdxPlus1));
396                 // Set status to NO_SPACE to enter the commaned buffer size verification on next loop.
397                 eStatus = MOS_STATUS_NO_SPACE;
398                 SCALABILITY_ASSERTMESSAGE("Verify Command buffer failed with no space!");
399             }
400         }
401     }
402     return eStatus;
403 }
404 
GetCmdBuffer(PMOS_COMMAND_BUFFER cmdBuffer,bool frameTrackingRequested)405 MOS_STATUS EncodeScalabilityMultiPipe::GetCmdBuffer(PMOS_COMMAND_BUFFER cmdBuffer, bool frameTrackingRequested)
406 {
407     SCALABILITY_FUNCTION_ENTER;
408     SCALABILITY_CHK_NULL_RETURN(cmdBuffer);
409     SCALABILITY_CHK_NULL_RETURN(m_osInterface);
410 
411     MOS_STATUS          eStatus = MOS_STATUS_SUCCESS;
412     PMOS_COMMAND_BUFFER scdryCmdBuffer;
413 
414     if (m_currentPipe >= m_pipeNum)
415     {
416         eStatus = MOS_STATUS_INVALID_PARAMETER;
417         SCALABILITY_ASSERTMESSAGE("Verify Command buffer failed with invalid parameter:currentPipe!");
418         return eStatus;
419     }
420     if (m_currentPass >= m_maxNumBRCPasses)
421     {
422         eStatus = MOS_STATUS_INVALID_PARAMETER;
423         SCALABILITY_ASSERTMESSAGE("Verify Command buffer failed with invalid parameter:currentPass!");
424         return eStatus;
425     }
426 
427     SCALABILITY_CHK_STATUS_RETURN(m_osInterface->pfnGetCommandBuffer(m_osInterface, &m_primaryCmdBuffer, 0));
428     uint32_t bufIdxPlus1 = m_currentPipe + 1;  //Make CMD buffer one next to one.
429     m_osInterface->pfnGetCommandBuffer(m_osInterface, &m_secondaryCmdBuffer[bufIdxPlus1 - 1], bufIdxPlus1);
430 
431     if (m_osInterface->apoMosEnabled)
432     {
433         int32_t submissionType = IsFirstPipe() ? SUBMISSION_TYPE_MULTI_PIPE_MASTER : SUBMISSION_TYPE_MULTI_PIPE_SLAVE;
434         if (IsLastPipe())
435         {
436             submissionType |= SUBMISSION_TYPE_MULTI_PIPE_FLAGS_LAST_PIPE;
437         }
438         SCALABILITY_CHK_NULL_RETURN(m_osInterface->osStreamState);
439         SCALABILITY_CHK_NULL_RETURN(m_osInterface->osStreamState->virtualEngineInterface);
440         SCALABILITY_CHK_STATUS_RETURN(m_osInterface->osStreamState->virtualEngineInterface->SetSubmissionType(&(m_secondaryCmdBuffer[bufIdxPlus1 - 1]), submissionType));
441     }
442     else
443     {
444         m_secondaryCmdBuffer[bufIdxPlus1 - 1].iSubmissionType =
445             IsFirstPipe() ? SUBMISSION_TYPE_MULTI_PIPE_MASTER : SUBMISSION_TYPE_MULTI_PIPE_SLAVE;
446 
447         if (IsLastPipe())
448         {
449             m_secondaryCmdBuffer[bufIdxPlus1 - 1].iSubmissionType |= SUBMISSION_TYPE_MULTI_PIPE_FLAGS_LAST_PIPE;
450         }
451     }
452     *cmdBuffer = m_secondaryCmdBuffer[bufIdxPlus1 - 1];
453 
454     SCALABILITY_CHK_NULL_RETURN(m_osInterface->osCpInterface);
455     SCALABILITY_CHK_NULL_RETURN(m_hwInterface);
456 
457     if (!m_attrReady)
458     {
459         SCALABILITY_CHK_STATUS_RETURN(SendAttrWithFrameTracking(m_primaryCmdBuffer, frameTrackingRequested));
460         m_attrReady = true;
461     }
462     return eStatus;
463 }
ReturnCmdBuffer(PMOS_COMMAND_BUFFER cmdBuffer)464 MOS_STATUS EncodeScalabilityMultiPipe::ReturnCmdBuffer(PMOS_COMMAND_BUFFER cmdBuffer)
465 {
466     SCALABILITY_FUNCTION_ENTER;
467     SCALABILITY_CHK_NULL_RETURN(cmdBuffer);
468     SCALABILITY_CHK_NULL_RETURN(m_osInterface);
469 
470     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
471 
472     if (m_currentPipe >= m_pipeNum)
473     {
474         eStatus = MOS_STATUS_INVALID_PARAMETER;
475         SCALABILITY_ASSERTMESSAGE("Verify Command buffer failed with invalid parameter:currentPipe!");
476         return eStatus;
477     }
478     if (m_currentPass >= m_maxNumBRCPasses)
479     {
480         eStatus = MOS_STATUS_INVALID_PARAMETER;
481         SCALABILITY_ASSERTMESSAGE("Verify Command buffer failed with invalid parameter:currentPass!");
482         return eStatus;
483     }
484     uint32_t bufIdxPlus1 = m_currentPipe + 1;  //Make CMD buffer one next to one.
485     m_secondaryCmdBuffer[bufIdxPlus1 - 1] = *cmdBuffer;  //Need to record the iOffset, ptr and other data of CMD buffer, it's not maintain in the mos.
486     m_osInterface->pfnReturnCommandBuffer(m_osInterface, &m_secondaryCmdBuffer[bufIdxPlus1 - 1], bufIdxPlus1);
487     m_primaryCmdBuffer.Attributes.bFrequencyBoost |= cmdBuffer->Attributes.bFrequencyBoost;
488     m_osInterface->pfnReturnCommandBuffer(m_osInterface, &m_primaryCmdBuffer, 0);
489     return eStatus;
490 }
SetHintParams()491 MOS_STATUS EncodeScalabilityMultiPipe::SetHintParams()
492 {
493     SCALABILITY_FUNCTION_ENTER;
494 
495     SCALABILITY_CHK_NULL_RETURN(m_osInterface);
496 
497     MOS_STATUS                   eStatus = MOS_STATUS_SUCCESS;
498     MOS_VIRTUALENGINE_SET_PARAMS veParams;
499     MOS_ZeroMemory(&veParams, sizeof(veParams));
500 
501     veParams.ucScalablePipeNum = m_pipeNum;
502     veParams.bScalableMode     = true;
503 
504     SCALABILITY_CHK_STATUS_RETURN(m_osInterface->pfnSetHintParams(m_osInterface, &veParams));
505     return eStatus;
506 }
PopulateHintParams(PMOS_COMMAND_BUFFER cmdBuffer)507 MOS_STATUS EncodeScalabilityMultiPipe::PopulateHintParams(PMOS_COMMAND_BUFFER cmdBuffer)
508 {
509     SCALABILITY_FUNCTION_ENTER;
510     SCALABILITY_CHK_NULL_RETURN(cmdBuffer);
511     SCALABILITY_CHK_NULL_RETURN(m_veHitParams);
512     SCALABILITY_CHK_NULL_RETURN(m_osInterface);
513 
514     MOS_STATUS            eStatus  = MOS_STATUS_SUCCESS;
515     PMOS_CMD_BUF_ATTRI_VE attriVe  = m_osInterface->pfnGetAttributeVeBuffer(cmdBuffer);
516     if (attriVe)
517     {
518         attriVe->VEngineHintParams     = *(m_veHitParams);
519         attriVe->bUseVirtualEngineHint = true;
520     }
521     return eStatus;
522 }
523 
SubmitCmdBuffer(PMOS_COMMAND_BUFFER cmdBuffer)524 MOS_STATUS EncodeScalabilityMultiPipe::SubmitCmdBuffer(PMOS_COMMAND_BUFFER cmdBuffer)
525 {
526     SCALABILITY_FUNCTION_ENTER;
527     SCALABILITY_CHK_NULL_RETURN(m_osInterface);
528 
529     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
530 
531     bool cmdBufferReadyForSubmit = IsPipeReadyToSubmit();
532 
533     // Hold the actual command buffer submission till last pipe
534     if (!cmdBufferReadyForSubmit)
535     {
536         return eStatus;
537     }
538 
539     // Add BB end for every secondary cmd buf when ready for submit
540     for (uint32_t pipe = 0; pipe < m_pipeNum; pipe++)
541     {
542         uint32_t bufIdxPlus1 = pipe + 1;
543 
544         MOS_COMMAND_BUFFER& cmdBufferToAddBbEnd = m_secondaryCmdBuffer[bufIdxPlus1 - 1];
545         SCALABILITY_CHK_STATUS_RETURN(m_osInterface->pfnGetCommandBuffer(m_osInterface, &cmdBufferToAddBbEnd, bufIdxPlus1));
546         SCALABILITY_CHK_STATUS_RETURN(m_miItf->AddMiBatchBufferEnd(&cmdBufferToAddBbEnd, nullptr));
547         SCALABILITY_CHK_STATUS_RETURN(Oca1stLevelBBEnd(cmdBufferToAddBbEnd));
548         m_osInterface->pfnReturnCommandBuffer(m_osInterface, &cmdBufferToAddBbEnd, bufIdxPlus1);
549     }
550 
551     m_attrReady = false;
552 
553     SCALABILITY_CHK_STATUS_RETURN(SetHintParams());
554     SCALABILITY_CHK_STATUS_RETURN(PopulateHintParams(&m_primaryCmdBuffer));
555 
556     SCALABILITY_CHK_STATUS_RETURN(m_osInterface->pfnSubmitCommandBuffer(m_osInterface, &m_primaryCmdBuffer, false));
557 
558     return eStatus;
559 }
SyncAllPipes(uint32_t semaphoreId,PMOS_COMMAND_BUFFER cmdBuffer)560 MOS_STATUS EncodeScalabilityMultiPipe::SyncAllPipes(uint32_t semaphoreId, PMOS_COMMAND_BUFFER cmdBuffer)
561 {
562     SCALABILITY_FUNCTION_ENTER;
563     SCALABILITY_CHK_NULL_RETURN(cmdBuffer);
564     SCALABILITY_CHK_NULL_RETURN(m_hwInterface);
565     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
566 
567     if (semaphoreId >= m_maxSemaphoreNum)
568     {
569         SCALABILITY_ASSERTMESSAGE("SyncAllPipes failed with invalid parameter:semaphoreId!");
570         return MOS_STATUS_INVALID_PARAMETER;
571     }
572     if (Mos_ResourceIsNull(&m_resSemaphoreAllPipes[semaphoreId]))
573     {
574         return MOS_STATUS_UNKNOWN;
575     }
576     //Not stop watch dog here, expect to stop it in the packet when needed.
577     //HW Semaphore cmd to make sure all pipes start encode at the same time
578     SCALABILITY_CHK_STATUS_RETURN(m_hwInterface->SendMiAtomicDwordCmd(&m_resSemaphoreAllPipes[semaphoreId], 1, MHW_MI_ATOMIC_INC, cmdBuffer));
579     SCALABILITY_CHK_STATUS_RETURN(m_hwInterface->SendHwSemaphoreWaitCmd(
580         &m_resSemaphoreAllPipes[semaphoreId],
581         m_pipeNum,
582         MHW_MI_SAD_EQUAL_SDD,
583         cmdBuffer));
584 
585     // Program some placeholder cmds to resolve the hazard between pipe sync
586     auto &storeDataParams            = m_miItf->MHW_GETPAR_F(MI_STORE_DATA_IMM)();
587     storeDataParams                  = {};
588     storeDataParams.pOsResource      = &m_resDelayMinus;
589     storeDataParams.dwResourceOffset = 0;
590     storeDataParams.dwValue          = 0xDE1A;
591 
592     for (uint32_t i = 0; i < m_numDelay; i++)
593     {
594         ENCODE_CHK_STATUS_RETURN(m_miItf->MHW_ADDCMD_F(MI_STORE_DATA_IMM)(cmdBuffer));
595     }
596 
597     //clean HW semaphore memory
598     SCALABILITY_CHK_STATUS_RETURN(m_hwInterface->SendMiAtomicDwordCmd(&m_resSemaphoreAllPipes[semaphoreId], 1, MHW_MI_ATOMIC_DEC, cmdBuffer));
599     return eStatus;
600 }
SyncOnePipeWaitOthers(PMOS_COMMAND_BUFFER cmdBuffer)601 MOS_STATUS EncodeScalabilityMultiPipe::SyncOnePipeWaitOthers(PMOS_COMMAND_BUFFER cmdBuffer)
602 {
603     SCALABILITY_FUNCTION_ENTER;
604     SCALABILITY_CHK_NULL_RETURN(cmdBuffer);
605 
606     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
607 
608     // Send MI_FLUSH command
609     auto &miFlushDwParams            = m_miItf->MHW_GETPAR_F(MI_FLUSH_DW)();
610     miFlushDwParams                  = {};
611     miFlushDwParams.bVideoPipelineCacheInvalidate = true;
612 
613     if (!Mos_ResourceIsNull(&m_resSemaphoreOnePipeWait[m_currentPipe]))
614     {
615         miFlushDwParams.pOsResource = &m_resSemaphoreOnePipeWait[m_currentPipe];
616         miFlushDwParams.dwDataDW1   = m_currentPass + 1;
617     }
618     SCALABILITY_CHK_STATUS_RETURN(m_miItf->MHW_ADDCMD_F(MI_FLUSH_DW)(cmdBuffer));
619 
620     if (IsFirstPipe())
621     {
622         // first pipe needs to ensure all other pipes are ready
623         for (uint32_t i = 1; i < m_pipeNum; i++)
624         {
625             if (!Mos_ResourceIsNull(&m_resSemaphoreOnePipeWait[i]))
626             {
627                 SCALABILITY_CHK_STATUS_RETURN(
628                     m_hwInterface->SendHwSemaphoreWaitCmd(
629                         &m_resSemaphoreOnePipeWait[i],
630                         m_currentPass + 1,
631                         MHW_MI_SAD_EQUAL_SDD,
632                         cmdBuffer));
633             }
634         }
635     }
636     return eStatus;
637 }
SyncPipe(uint32_t syncType,uint32_t semaphoreId,PMOS_COMMAND_BUFFER cmdBuffer)638 MOS_STATUS EncodeScalabilityMultiPipe::SyncPipe(uint32_t syncType, uint32_t semaphoreId, PMOS_COMMAND_BUFFER cmdBuffer)
639 {
640     SCALABILITY_FUNCTION_ENTER;
641     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
642     switch (syncType)
643     {
644     case syncAllPipes:
645         eStatus = SyncAllPipes(semaphoreId, cmdBuffer);
646         break;
647     case syncOnePipeWaitOthers:
648         eStatus = SyncOnePipeWaitOthers(cmdBuffer);
649         break;
650     case syncOnePipeForAnother:
651         eStatus = SyncOnePipeForAnother(cmdBuffer);
652         break;
653     case syncOtherPipesForOne:
654         eStatus = SyncOtherPipesForOne(cmdBuffer);
655         break;
656     default:
657         eStatus = MOS_STATUS_INVALID_PARAMETER;
658         break;
659     }
660     return eStatus;
661 }
ResetSemaphore(uint32_t syncType,uint32_t semaphoreId,PMOS_COMMAND_BUFFER cmdBuffer)662 MOS_STATUS EncodeScalabilityMultiPipe::ResetSemaphore(uint32_t syncType, uint32_t semaphoreId, PMOS_COMMAND_BUFFER cmdBuffer)
663 {
664     SCALABILITY_FUNCTION_ENTER;
665     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
666     switch (syncType)
667     {
668     case syncAllPipes:
669         if (semaphoreId >= m_maxSemaphoreNum)
670         {
671             SCALABILITY_ASSERTMESSAGE("SyncAllPipes failed with invalid parameter:semaphoreId!");
672             return MOS_STATUS_INVALID_PARAMETER;
673         }
674         if (!Mos_ResourceIsNull(&m_resSemaphoreAllPipes[semaphoreId]))
675         {
676             SCALABILITY_CHK_STATUS_RETURN(
677                 m_hwInterface->SendMiStoreDataImm(
678                     &m_resSemaphoreAllPipes[semaphoreId],
679                     0,
680                     cmdBuffer));
681         }
682         break;
683     case syncOnePipeWaitOthers:
684         if (!Mos_ResourceIsNull(&m_resSemaphoreOnePipeWait[semaphoreId]))
685         {
686             SCALABILITY_CHK_STATUS_RETURN(
687                 m_hwInterface->SendMiStoreDataImm(
688                     &m_resSemaphoreOnePipeWait[semaphoreId],
689                     0,
690                     cmdBuffer));
691         }
692         break;
693     case syncOnePipeForAnother:
694         if (!Mos_ResourceIsNull(&m_resSemaphoreOnePipeForAnother))
695         {
696             SCALABILITY_CHK_STATUS_RETURN(
697                 m_hwInterface->SendMiStoreDataImm(
698                     &m_resSemaphoreOnePipeForAnother,
699                     0,
700                     cmdBuffer));
701         }
702         break;
703     case syncOtherPipesForOne:
704         if (!Mos_ResourceIsNull(&m_resSemaphoreOtherPipesForOne))
705         {
706             SCALABILITY_CHK_STATUS_RETURN(
707                 m_hwInterface->SendMiStoreDataImm(
708                     &m_resSemaphoreOtherPipesForOne,
709                     0,
710                     cmdBuffer));
711         }
712         break;
713     default:
714         SCALABILITY_ASSERTMESSAGE("Reset semaphore failed with invalid parameter: syncType!");
715         eStatus = MOS_STATUS_INVALID_PARAMETER;
716         break;
717     }
718     return eStatus;
719 }
UpdateState(void * statePars)720 MOS_STATUS EncodeScalabilityMultiPipe::UpdateState(void *statePars)
721 {
722     SCALABILITY_FUNCTION_ENTER;
723     MOS_STATUS   eStatus         = MOS_STATUS_SUCCESS;
724     StateParams *encodeStatePars = (StateParams *)statePars;
725     if (encodeStatePars->currentPipe >= m_pipeNum)
726     {
727         eStatus = MOS_STATUS_INVALID_PARAMETER;
728         SCALABILITY_ASSERTMESSAGE("UpdateState failed with invalid parameter:currentPipe!");
729         return eStatus;
730     }
731     if (m_currentPass >= m_maxNumBRCPasses)
732     {
733         eStatus = MOS_STATUS_INVALID_PARAMETER;
734         SCALABILITY_ASSERTMESSAGE("UpdateState failed with invalid parameter:currentPass!");
735         return eStatus;
736     }
737     m_currentPipe              = encodeStatePars->currentPipe;
738     m_currentPass              = encodeStatePars->currentPass;
739     m_pipeIndexForSubmit       = encodeStatePars->pipeIndexForSubmit;
740     m_singleTaskPhaseSupported = encodeStatePars->singleTaskPhaseSupported;
741     m_statusReport             = encodeStatePars->statusReport;
742     m_currentRow               = encodeStatePars->currentRow;
743     m_currentSubPass           = encodeStatePars->currentSubPass;
744     return eStatus;
745 }
746 
SendAttrWithFrameTracking(MOS_COMMAND_BUFFER & cmdBuffer,bool frameTrackingRequested)747 MOS_STATUS EncodeScalabilityMultiPipe::SendAttrWithFrameTracking(
748     MOS_COMMAND_BUFFER &cmdBuffer,
749     bool                frameTrackingRequested)
750 {
751     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
752 
753     SCALABILITY_FUNCTION_ENTER;
754 
755     bool renderEngineUsed = m_mediaContext->IsRenderEngineUsed();
756 
757     // initialize command buffer attributes
758     cmdBuffer.Attributes.bTurboMode               = m_hwInterface->m_turboMode;
759     cmdBuffer.Attributes.bMediaPreemptionEnabled  = renderEngineUsed ? m_hwInterface->GetRenderInterfaceNext()->IsPreemptionEnabled() : 0;
760     cmdBuffer.Attributes.dwNumRequestedEUSlices   = m_hwInterface->m_numRequestedEuSlices;
761     cmdBuffer.Attributes.dwNumRequestedSubSlices  = m_hwInterface->m_numRequestedSubSlices;
762     cmdBuffer.Attributes.dwNumRequestedEUs        = m_hwInterface->m_numRequestedEus;
763     cmdBuffer.Attributes.bValidPowerGatingRequest = true;
764 
765     PMOS_RESOURCE resource = nullptr;
766     uint32_t      offset   = 0;
767 
768     if (frameTrackingRequested && m_frameTrackingEnabled)
769     {
770         m_statusReport->GetAddress(encode::statusReportGlobalCount, resource, offset);
771         cmdBuffer.Attributes.bEnableMediaFrameTracking    = true;
772         cmdBuffer.Attributes.resMediaFrameTrackingSurface = resource;
773         cmdBuffer.Attributes.dwMediaFrameTrackingTag      = m_statusReport->GetSubmittedCount() + 1;
774         // Set media frame tracking address offset(the offset from the encoder status buffer page)
775         cmdBuffer.Attributes.dwMediaFrameTrackingAddrOffset = 0;
776     }
777 
778     return eStatus;
779 }
780 
SyncOnePipeForAnother(PMOS_COMMAND_BUFFER cmdBuffer)781 MOS_STATUS EncodeScalabilityMultiPipe::SyncOnePipeForAnother(PMOS_COMMAND_BUFFER cmdBuffer)
782 {
783     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
784 
785     SCALABILITY_FUNCTION_ENTER;
786 
787     if (m_currentPipe == 0)
788     {
789         SCALABILITY_CHK_STATUS_RETURN(m_hwInterface->SendMiAtomicDwordCmd(&m_resSemaphoreOnePipeForAnother, 1, MHW_MI_ATOMIC_INC, cmdBuffer));
790     }
791     else
792     {
793         SCALABILITY_CHK_STATUS_RETURN(m_hwInterface->SendHwSemaphoreWaitCmd(
794             &m_resSemaphoreOnePipeForAnother,
795             1,
796             MHW_MI_SAD_EQUAL_SDD,
797             cmdBuffer));
798         //clean HW semaphore memory
799         SCALABILITY_CHK_STATUS_RETURN(m_hwInterface->SendMiAtomicDwordCmd(&m_resSemaphoreOnePipeForAnother, 1, MHW_MI_ATOMIC_DEC, cmdBuffer));
800     }
801 
802     return eStatus;
803 }
804 
SyncOtherPipesForOne(PMOS_COMMAND_BUFFER cmdBuffer)805 MOS_STATUS EncodeScalabilityMultiPipe::SyncOtherPipesForOne(PMOS_COMMAND_BUFFER cmdBuffer)
806 {
807     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
808 
809     SCALABILITY_FUNCTION_ENTER;
810 
811     if (m_currentPipe == 0)
812     {
813         SCALABILITY_CHK_STATUS_RETURN(m_hwInterface->SendMiAtomicDwordCmd(&m_resSemaphoreOtherPipesForOne, m_pipeNum - 1, MHW_MI_ATOMIC_INC, cmdBuffer));
814     }
815     else
816     {
817         SCALABILITY_CHK_STATUS_RETURN(m_hwInterface->SendHwSemaphoreWaitCmd(
818             &m_resSemaphoreOtherPipesForOne,
819             0,
820             MHW_MI_SAD_NOT_EQUAL_SDD,
821             cmdBuffer));
822         //clean HW semaphore memory
823         SCALABILITY_CHK_STATUS_RETURN(m_hwInterface->SendMiAtomicDwordCmd(&m_resSemaphoreOtherPipesForOne, 1, MHW_MI_ATOMIC_DEC, cmdBuffer));
824     }
825 
826     return eStatus;
827 }
828 
Oca1stLevelBBStart(MOS_COMMAND_BUFFER & cmdBuffer)829 MOS_STATUS EncodeScalabilityMultiPipe::Oca1stLevelBBStart(MOS_COMMAND_BUFFER &cmdBuffer)
830 {
831     MHW_MI_MMIOREGISTERS mmioRegister;
832     SCALABILITY_CHK_NULL_RETURN(m_hwInterface);
833 
834     auto vdencItf = m_hwInterface->GetVdencInterfaceNext();
835     SCALABILITY_CHK_NULL_RETURN(vdencItf);
836     bool validMmio = vdencItf->ConvertToMiRegister(MHW_VDBOX_NODE_1, mmioRegister);
837 
838     if (validMmio)
839     {
840         SCALABILITY_CHK_NULL_RETURN(m_osInterface);
841         SCALABILITY_CHK_NULL_RETURN(m_osInterface->pOsContext);
842 
843         HalOcaInterfaceNext::On1stLevelBBStart(
844             cmdBuffer,
845             (MOS_CONTEXT_HANDLE)m_osInterface->pOsContext,
846             m_osInterface->CurrentGpuContextHandle,
847             m_miItf,
848             mmioRegister);
849     }
850 
851     return MOS_STATUS_SUCCESS;
852 }
853 
Oca1stLevelBBEnd(MOS_COMMAND_BUFFER & cmdBuffer)854 MOS_STATUS EncodeScalabilityMultiPipe::Oca1stLevelBBEnd(MOS_COMMAND_BUFFER &cmdBuffer)
855 {
856     SCALABILITY_CHK_NULL_RETURN(m_osInterface);
857     HalOcaInterfaceNext::On1stLevelBBEnd(cmdBuffer, *m_osInterface);
858 
859     return MOS_STATUS_SUCCESS;
860 }
861 
862 }
863