1 /*
2 * Copyright (c) 2018-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 
23 //!
24 //! \file     encode_huc.cpp
25 //! \brief    Defines the common interface for encode huc implementation
26 //! \details  The encode huc interface is further sub-divided by different huc usage,
27 //!           this file is for the base interface which is shared by all.
28 //!
29 
30 #include "encode_huc.h"
31 #include "codechal_debug.h"
32 #include <algorithm>
33 
34 namespace encode
35 {
Init()36     MOS_STATUS EncodeHucPkt::Init()
37     {
38         HUC_CHK_STATUS_RETURN(CmdPacket::Init());
39         m_allocator = m_pipeline->GetEncodeAllocator();
40         HUC_CHK_STATUS_RETURN(AllocateResources());
41 
42         ENCODE_CHK_NULL_RETURN(m_pipeline);
43         m_statusReport = m_pipeline->GetStatusReportInstance();
44         ENCODE_CHK_NULL_RETURN(m_statusReport);
45         ENCODE_CHK_STATUS_RETURN(m_statusReport->RegistObserver(this));
46 
47         HUC_CHK_NULL_RETURN(m_hwInterface);
48         m_skuFtrEnableMediaKernels = MEDIA_IS_SKU(m_hwInterface->GetSkuTable(), FtrEnableMediaKernels);
49         m_hucItf = m_hwInterface->GetHucInterfaceNext();
50         HUC_CHK_NULL_RETURN(m_hucItf);
51         m_hucStatus2ImemLoadedMask = m_hucItf->GetHucStatus2ImemLoadedMask();
52 
53         return MOS_STATUS_SUCCESS;
54     }
55 
IsHuCStsUpdNeeded()56     bool EncodeHucPkt::IsHuCStsUpdNeeded()
57     {
58         bool enabled = false;
59 #if _SW_BRC
60         enabled = m_swBrc && m_swBrc->SwBrcEnabled();
61  #endif  // !_SW_BRC
62         return enabled;
63     }
64 
AllocateResources()65     MOS_STATUS EncodeHucPkt::AllocateResources()
66     {
67         MOS_ALLOC_GFXRES_PARAMS allocParamsForBufferLinear;
68         MOS_ZeroMemory(&allocParamsForBufferLinear, sizeof(MOS_ALLOC_GFXRES_PARAMS));
69         allocParamsForBufferLinear.Type = MOS_GFXRES_BUFFER;
70         allocParamsForBufferLinear.TileType = MOS_TILE_LINEAR;
71         allocParamsForBufferLinear.Format = Format_Buffer;
72 
73         // HUC STATUS 2 Buffer for HuC status check in COND_BB_END
74         allocParamsForBufferLinear.dwBytes = sizeof(uint64_t);
75         allocParamsForBufferLinear.pBufName = "HUC STATUS 2 Buffer";
76         allocParamsForBufferLinear.ResUsageType = MOS_HW_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_NOCACHE;
77         PMOS_RESOURCE allocatedbuffer       = m_allocator->AllocateResource(allocParamsForBufferLinear, true);
78         ENCODE_CHK_NULL_RETURN(allocatedbuffer);
79         m_resHucStatus2Buffer = allocatedbuffer;
80 
81         return MOS_STATUS_SUCCESS;
82     }
83 
StoreHuCStatus2Register(PMOS_COMMAND_BUFFER cmdBuffer,bool storeHucStatus2Needed)84     MOS_STATUS EncodeHucPkt::StoreHuCStatus2Register(PMOS_COMMAND_BUFFER cmdBuffer, bool storeHucStatus2Needed)
85     {
86         HUC_CHK_NULL_RETURN(cmdBuffer);
87         HUC_CHK_NULL_RETURN(m_statusReport);
88 
89         auto mmioRegisters = m_hucItf->GetMmioRegisters(m_vdboxIndex);
90         HUC_CHK_NULL_RETURN(mmioRegisters);
91 
92         PMOS_RESOURCE osResource = nullptr;
93         uint32_t      offset     = 0;
94 
95         ENCODE_CHK_STATUS_RETURN(m_statusReport->GetAddress(statusReportHucStatus2Reg, osResource, offset));
96 
97         auto &storeRegParams             = m_miItf->MHW_GETPAR_F(MI_STORE_REGISTER_MEM)();
98         storeRegParams                   = {};
99         storeRegParams.presStoreBuffer   = osResource;
100         storeRegParams.dwOffset          = offset;
101         storeRegParams.dwRegister        = mmioRegisters->hucStatus2RegOffset;
102         HUC_CHK_STATUS_RETURN(m_miItf->MHW_ADDCMD_F(MI_STORE_REGISTER_MEM)(cmdBuffer));
103 
104         if (storeHucStatus2Needed)
105         {
106             // Write HUC_STATUS2 mask - bit 6 - valid IMEM loaded
107             auto &storeDataParams            = m_miItf->MHW_GETPAR_F(MI_STORE_DATA_IMM)();
108             storeDataParams                  = {};
109             storeDataParams.pOsResource      = m_resHucStatus2Buffer;
110             storeDataParams.dwResourceOffset = 0;
111             storeDataParams.dwValue          = m_hucItf->GetHucStatus2ImemLoadedMask();
112             HUC_CHK_STATUS_RETURN(m_miItf->MHW_ADDCMD_F(MI_STORE_DATA_IMM)(cmdBuffer));
113 
114             // Store HUC_STATUS2 register
115             auto &storeRegParams             = m_miItf->MHW_GETPAR_F(MI_STORE_REGISTER_MEM)();
116             storeRegParams                   = {};
117             storeRegParams.presStoreBuffer   = m_resHucStatus2Buffer;
118             storeRegParams.dwOffset          = sizeof(uint32_t);
119             storeRegParams.dwRegister        = mmioRegisters->hucStatus2RegOffset;
120             HUC_CHK_STATUS_RETURN(m_miItf->MHW_ADDCMD_F(MI_STORE_REGISTER_MEM)(cmdBuffer));
121         }
122 
123         return MOS_STATUS_SUCCESS;
124     }
125 
SendPrologCmds(MOS_COMMAND_BUFFER & cmdBuffer)126     MOS_STATUS EncodeHucPkt::SendPrologCmds(
127         MOS_COMMAND_BUFFER &cmdBuffer)
128     {
129         MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
130 
131         ENCODE_FUNC_CALL();
132         bool mmcEnabled = false;
133 #ifdef _MMC_SUPPORTED
134         EncodeMemComp *mmcState = m_pipeline->GetMmcState();
135         ENCODE_CHK_NULL_RETURN(mmcState);
136         mmcEnabled = mmcState->IsMmcEnabled();
137         ENCODE_CHK_STATUS_RETURN(mmcState->SendPrologCmd(&cmdBuffer, false));
138 #endif
139 
140         MHW_GENERIC_PROLOG_PARAMS genericPrologParams;
141         MOS_ZeroMemory(&genericPrologParams, sizeof(genericPrologParams));
142         ENCODE_CHK_NULL_RETURN(m_hwInterface);
143         genericPrologParams.pOsInterface = m_hwInterface->GetOsInterface();
144         std::shared_ptr<void> m_miItf     = m_hwInterface->GetMiInterfaceNext();
145         genericPrologParams.pvMiInterface = nullptr;
146         genericPrologParams.bMmcEnabled   = mmcEnabled;
147         ENCODE_CHK_STATUS_RETURN(Mhw_SendGenericPrologCmdNext(&cmdBuffer, &genericPrologParams, m_miItf));
148 
149         return eStatus;
150     }
151 
AddForceWakeup(MOS_COMMAND_BUFFER & cmdBuffer)152     MOS_STATUS EncodeHucPkt::AddForceWakeup(MOS_COMMAND_BUFFER &cmdBuffer)
153     {
154         ENCODE_FUNC_CALL();
155 
156         auto &forceWakeupParams                     = m_miItf->MHW_GETPAR_F(MI_FORCE_WAKEUP)();
157         forceWakeupParams                           = {};
158         forceWakeupParams.bMFXPowerWellControl      = true;
159         forceWakeupParams.bMFXPowerWellControlMask  = true;
160         forceWakeupParams.bHEVCPowerWellControl     = true;
161         forceWakeupParams.bHEVCPowerWellControlMask = true;
162 
163         ENCODE_CHK_STATUS_RETURN(m_miItf->MHW_ADDCMD_F(MI_FORCE_WAKEUP)(&cmdBuffer));
164 
165         return MOS_STATUS_SUCCESS;
166     }
167 
SetPerfTag(uint16_t type,uint16_t mode,uint16_t picCodingType)168     void EncodeHucPkt::SetPerfTag(uint16_t type, uint16_t mode, uint16_t picCodingType)
169     {
170         ENCODE_FUNC_CALL();
171 
172         PerfTagSetting perfTag;
173         perfTag.Value             = 0;
174         perfTag.Mode              = mode & CODECHAL_ENCODE_MODE_BIT_MASK;
175         perfTag.CallType          = type;
176         perfTag.PictureCodingType = picCodingType > 3 ? 0 : picCodingType;
177         m_osInterface->pfnSetPerfTag(m_osInterface, perfTag.Value);
178         m_osInterface->pfnIncPerfBufferID(m_osInterface);
179     }
180 
StartPerfCollect(MOS_COMMAND_BUFFER & cmdBuffer)181     MOS_STATUS EncodeHucPkt::StartPerfCollect(MOS_COMMAND_BUFFER& cmdBuffer)
182     {
183         MediaPerfProfiler *perfProfiler = MediaPerfProfiler::Instance();
184         ENCODE_CHK_NULL_RETURN(perfProfiler);
185         ENCODE_CHK_STATUS_RETURN(perfProfiler->AddPerfCollectStartCmd(
186             (void *)m_pipeline, m_osInterface, m_miItf, &cmdBuffer));
187 
188         return MOS_STATUS_SUCCESS;
189     }
190 
EndPerfCollect(MOS_COMMAND_BUFFER & cmdBuffer)191     MOS_STATUS EncodeHucPkt::EndPerfCollect(MOS_COMMAND_BUFFER& cmdBuffer)
192     {
193         MediaPerfProfiler *perfProfiler = MediaPerfProfiler::Instance();
194         ENCODE_CHK_NULL_RETURN(perfProfiler);
195         ENCODE_CHK_STATUS_RETURN(perfProfiler->AddPerfCollectEndCmd(
196             (void *)m_pipeline, m_osInterface, m_miItf, &cmdBuffer));
197 
198         return MOS_STATUS_SUCCESS;
199     }
200 
AddAllCmds_HUC_PIPE_MODE_SELECT(PMOS_COMMAND_BUFFER cmdBuffer) const201      MOS_STATUS EncodeHucPkt::AddAllCmds_HUC_PIPE_MODE_SELECT(PMOS_COMMAND_BUFFER cmdBuffer) const
202     {
203         MHW_MI_CHK_NULL(cmdBuffer);
204 
205         //for gen 11, we need to add MFX wait for both KIN and VRT before and after HUC Pipemode select...
206         auto &mfxWaitParams                 = m_miItf->MHW_GETPAR_F(MFX_WAIT)();
207         mfxWaitParams                       = {};
208         mfxWaitParams.iStallVdboxPipeline   = true;
209         MHW_MI_CHK_STATUS(m_miItf->MHW_ADDCMD_F(MFX_WAIT)(cmdBuffer));
210 
211         SETPAR_AND_ADDCMD(HUC_PIPE_MODE_SELECT, m_hucItf, cmdBuffer);
212 
213         //for gen 11, we need to add MFX wait for both KIN and VRT before and after HUC Pipemode select...
214         mfxWaitParams                       = {};
215         mfxWaitParams.iStallVdboxPipeline   = true;
216         MHW_MI_CHK_STATUS(m_miItf->MHW_ADDCMD_F(MFX_WAIT)(cmdBuffer));
217 
218         return MOS_STATUS_SUCCESS;
219     }
220 
AddAllCmds_HUC_IMEM_STATE(PMOS_COMMAND_BUFFER cmdBuffer) const221     MOS_STATUS EncodeHucPkt::AddAllCmds_HUC_IMEM_STATE(PMOS_COMMAND_BUFFER cmdBuffer) const
222     {
223         MHW_MI_CHK_NULL(cmdBuffer);
224 
225         SETPAR_AND_ADDCMD(HUC_IMEM_STATE, m_hucItf, cmdBuffer);
226 
227         auto &mfxWaitParams                 = m_miItf->MHW_GETPAR_F(MFX_WAIT)();
228         mfxWaitParams                       = {};
229         mfxWaitParams.iStallVdboxPipeline   = true;
230         MHW_MI_CHK_STATUS(m_miItf->MHW_ADDCMD_F(MFX_WAIT)(cmdBuffer));
231 
232         return MOS_STATUS_SUCCESS;
233     }
234 
Execute(PMOS_COMMAND_BUFFER cmdBuffer,bool storeHucStatus2Needed,bool prologNeeded,HuCFunction function)235     MOS_STATUS EncodeHucPkt::Execute(PMOS_COMMAND_BUFFER cmdBuffer, bool storeHucStatus2Needed, bool prologNeeded, HuCFunction function)
236     {
237         HUC_CHK_NULL_RETURN(cmdBuffer);
238 
239 #if _SW_BRC
240         HUC_CHK_STATUS_RETURN(InitSwBrc(function));
241         if (function != NONE_BRC && m_swBrc && m_swBrc->SwBrcEnabled())
242         {
243             SETPAR(HUC_DMEM_STATE, m_hucItf);
244             SETPAR(HUC_VIRTUAL_ADDR_STATE, m_hucItf);
245 
246             auto &virtualAddrParams = m_hucItf->MHW_GETPAR_F(HUC_VIRTUAL_ADDR_STATE)();
247             auto &dmemParams = m_hucItf->MHW_GETPAR_F(HUC_DMEM_STATE)();
248 
249             CODECHAL_DEBUG_TOOL(
250                 ENCODE_CHK_STATUS_RETURN(DumpInput());)
251 
252             EncodeBasicFeature *basicFeature = dynamic_cast<EncodeBasicFeature *>(m_featureManager->GetFeature(FeatureIDs::basicFeature));
253             HUC_CHK_NULL_RETURN(basicFeature);
254             return m_swBrc->SwBrcImpl(
255                 function,
256                 virtualAddrParams,
257                 dmemParams,
258                 basicFeature->m_recycleBuf->GetBuffer(VdencBrcPakMmioBuffer, 0));
259         }
260 #endif  // !_SW_BRC
261 
262         if (prologNeeded)
263         {
264             ENCODE_CHK_STATUS_RETURN(AddForceWakeup(*cmdBuffer));
265             ENCODE_CHK_STATUS_RETURN(SendPrologCmds(*cmdBuffer));
266         }
267 
268         ENCODE_CHK_STATUS_RETURN(StartPerfCollect(*cmdBuffer));
269 
270         AddAllCmds_HUC_IMEM_STATE(cmdBuffer);
271         AddAllCmds_HUC_PIPE_MODE_SELECT(cmdBuffer);
272 
273         SETPAR_AND_ADDCMD(HUC_DMEM_STATE, m_hucItf, cmdBuffer);
274         SETPAR_AND_ADDCMD(HUC_VIRTUAL_ADDR_STATE, m_hucItf, cmdBuffer);
275 
276         m_enableHucStatusReport = true;
277         HUC_CHK_STATUS_RETURN(StoreHuCStatus2Register(cmdBuffer, storeHucStatus2Needed));
278 
279         SETPAR_AND_ADDCMD(HUC_START, m_hucItf, cmdBuffer);
280 
281         CODECHAL_DEBUG_TOOL(
282             ENCODE_CHK_STATUS_RETURN(DumpInput());)
283 
284         SETPAR_AND_ADDCMD(VD_PIPELINE_FLUSH, m_vdencItf, cmdBuffer);
285 
286         // Flush the engine to ensure memory written out
287         auto &flushDwParams                         = m_miItf->MHW_GETPAR_F(MI_FLUSH_DW)();
288         flushDwParams                               = {};
289         flushDwParams.bVideoPipelineCacheInvalidate = true;
290         HUC_CHK_STATUS_RETURN(m_miItf->MHW_ADDCMD_F(MI_FLUSH_DW)(cmdBuffer));
291 
292         ENCODE_CHK_STATUS_RETURN(EndPerfCollect(*cmdBuffer));
293         HUC_CHK_STATUS_RETURN(StoreHuCStatusRegister(cmdBuffer));
294 
295         return MOS_STATUS_SUCCESS;
296     }
297 
MHW_SETPAR_DECL_SRC(VD_PIPELINE_FLUSH,EncodeHucPkt)298     MHW_SETPAR_DECL_SRC(VD_PIPELINE_FLUSH, EncodeHucPkt)
299     {
300         params.waitDoneHEVC = true;
301         params.flushHEVC = true;
302         return MOS_STATUS_SUCCESS;
303     }
304 
Completed(void * mfxStatus,void * rcsStatus,void * statusReport)305     MOS_STATUS EncodeHucPkt::Completed(void *mfxStatus, void *rcsStatus, void *statusReport)
306     {
307         ENCODE_FUNC_CALL();
308 
309         if (!m_enableHucStatusReport)
310         {
311             return MOS_STATUS_SUCCESS;
312         }
313 
314         ENCODE_CHK_NULL_RETURN(mfxStatus);
315         ENCODE_CHK_NULL_RETURN(statusReport);
316 
317         EncodeStatusMfx *encodeStatusMfx = (EncodeStatusMfx *)mfxStatus;
318 
319         MOS_USER_FEATURE_VALUE_WRITE_DATA userFeatureWriteData;
320         MOS_ZeroMemory(&userFeatureWriteData, sizeof(MOS_USER_FEATURE_VALUE_WRITE_DATA));
321 
322         if (!m_skuFtrEnableMediaKernels)
323         {
324             ENCODE_ASSERTMESSAGE("Failed to load HuC firmware!");
325 
326             // Reporting
327             ReportUserSetting(
328                 m_userSettingPtr,
329                 "HuC Firmware Load Failed",
330                 1,
331                 MediaUserSetting::Group::Sequence);
332 
333             return MOS_STATUS_HUC_KERNEL_FAILED;
334         }
335         else if (!(encodeStatusMfx->hucStatus2Reg & m_hucStatus2ImemLoadedMask))
336         {
337             ENCODE_ASSERTMESSAGE("HuC status2 indicates Valid Imem Load failed!");
338 
339             // Reporting
340             ReportUserSetting(
341                 m_userSettingPtr,
342                 "HuC Valid Imem Load Failed",
343                 1,
344                 MediaUserSetting::Group::Sequence);
345 
346 #if (_DEBUG || _RELEASE_INTERNAL)
347             ReportUserSettingForDebug(
348                 m_userSettingPtr,
349                 "Huc Status2 Value",
350                 encodeStatusMfx->hucStatus2Reg,
351                 MediaUserSetting::Group::Sequence);
352 #endif
353 
354             return MOS_STATUS_HUC_KERNEL_FAILED;
355         }
356 #if (_DEBUG || _RELEASE_INTERNAL)
357         else
358         {
359             EncodeStatusReportData* encodeStatusReport = (EncodeStatusReportData *)statusReport;
360             std::string hucStatusReport = "HuC Status Value is " + std::to_string(encodeStatusMfx->hucStatusReg) +
361                 " for Frame number #" + std::to_string(encodeStatusReport->statusReportNumber) + ".";
362             ENCODE_NORMALMESSAGE(hucStatusReport.c_str());
363         }
364 #endif
365 
366         return MOS_STATUS_SUCCESS;
367     }
368 
StoreHuCStatusRegister(PMOS_COMMAND_BUFFER cmdBuffer)369     MOS_STATUS EncodeHucPkt::StoreHuCStatusRegister(PMOS_COMMAND_BUFFER cmdBuffer)
370     {
371         HUC_CHK_NULL_RETURN(cmdBuffer);
372         HUC_CHK_NULL_RETURN(m_statusReport);
373 
374         auto mmioRegisters = m_hucItf->GetMmioRegisters(m_vdboxIndex);
375         HUC_CHK_NULL_RETURN(mmioRegisters);
376 
377         PMOS_RESOURCE osResource = nullptr;
378         uint32_t      offset     = 0;
379 
380         ENCODE_CHK_STATUS_RETURN(m_statusReport->GetAddress(statusReportHucStatusReg, osResource, offset));
381 
382         // Store HUC_STATUS register
383         auto &storeRegParams             = m_miItf->MHW_GETPAR_F(MI_STORE_REGISTER_MEM)();
384         storeRegParams                   = {};
385         storeRegParams.presStoreBuffer   = osResource;
386         storeRegParams.dwOffset          = offset;
387         storeRegParams.dwRegister        = mmioRegisters->hucStatusRegOffset;
388         HUC_CHK_STATUS_RETURN(m_miItf->MHW_ADDCMD_F(MI_STORE_REGISTER_MEM)(cmdBuffer));
389 
390         return MOS_STATUS_SUCCESS;
391     }
392 
393 #if _SW_BRC
InitSwBrc(HuCFunction function)394     MOS_STATUS EncodeHucPkt::InitSwBrc(HuCFunction function)
395     {
396         if (m_swBrc == nullptr)
397         {
398             EncodeBasicFeature* basicFeature = dynamic_cast<EncodeBasicFeature*>(m_featureManager->GetFeature(FeatureIDs::basicFeature));
399             HUC_CHK_NULL_RETURN(basicFeature);
400             m_swBrc = EncodeSwBrc::CreateFactory(basicFeature->m_mode, m_allocator, m_hwInterface->GetOsInterface(), function);
401         }
402         return MOS_STATUS_SUCCESS;
403     }
404  #endif  // !_SW_BRC
405 
406 #if USE_CODECHAL_DEBUG_TOOL
DumpRegion(uint32_t regionNum,const char * regionName,bool inputBuffer,CodechalHucRegionDumpType dumpType,uint32_t size)407     MOS_STATUS EncodeHucPkt::DumpRegion(
408         uint32_t regionNum,
409         const char *regionName,
410         bool inputBuffer,
411         CodechalHucRegionDumpType dumpType,
412         uint32_t size)
413     {
414         auto virtualAddrParams = m_hucItf->MHW_GETPAR_F(HUC_VIRTUAL_ADDR_STATE)();
415         auto bufferToDump      = virtualAddrParams.regionParams[regionNum].presRegion;
416         auto offset            = virtualAddrParams.regionParams[regionNum].dwOffset;
417 
418         CodechalDebugInterface *debugInterface = m_pipeline->GetDebugInterface();
419         ENCODE_CHK_NULL_RETURN(debugInterface);
420 
421         if (bufferToDump)
422         {
423             // Dump the full region when size = 0 or exceed the region size, else dump the size indicated
424             GMM_SIZE_PARAM GmmSizeParam = GMM_MAIN_SURF;
425             uint32_t bufferSize         = (uint32_t)bufferToDump->pGmmResInfo->GetSize(GmmSizeParam);
426             ENCODE_CHK_STATUS_RETURN(debugInterface->DumpHucRegion(
427                 bufferToDump,
428                 offset,
429                 size ? size : bufferSize,
430                 regionNum,
431                 regionName,
432                 inputBuffer,
433                 m_pipeline->GetCurrentPass(),
434                 dumpType));
435         }
436 
437         return MOS_STATUS_SUCCESS;
438     }
439 #endif
440 }
441