1 /*
2 * Copyright (c) 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 //! \file     vp_pipeline_adapter_base.cpp
24 //! \brief    vp pipeline adapter base clarification
25 //! \details  vp pipeline adapter base clarification inlcuding:
26 //!           some marcro, enum, structure, function
27 //!
28 #include "vp_pipeline_adapter_base.h"
29 #include "media_interfaces_vphal.h"
30 #include "vp_platform_interface.h"
31 #include "vp_debug.h"
32 #include "vp_user_setting.h"
33 #include "renderhal_platform_interface.h"
34 
VpPipelineAdapterBase(vp::VpPlatformInterface & vpPlatformInterface,MOS_STATUS & eStatus,bool clearViewMode)35 VpPipelineAdapterBase::VpPipelineAdapterBase(
36     vp::VpPlatformInterface &vpPlatformInterface,
37     MOS_STATUS              &eStatus,
38     bool                    clearViewMode) :
39     m_vpPlatformInterface(vpPlatformInterface)
40 {
41     m_osInterface = m_vpPlatformInterface.GetOsInterface();
42     if (m_osInterface)
43     {
44         m_userSettingPtr = m_osInterface->pfnGetUserSettingInstance(m_osInterface);
45     }
46     VpUserSetting::InitVpUserSetting(m_userSettingPtr, clearViewMode);
47 
48     eStatus = MOS_STATUS_SUCCESS;
49 }
50 
GetVpMhwInterface(VP_MHWINTERFACE & vpMhwinterface)51 MOS_STATUS VpPipelineAdapterBase::GetVpMhwInterface(
52     VP_MHWINTERFACE &vpMhwinterface)
53 {
54     VP_FUNC_CALL();
55 
56     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
57     bool       sfcNeeded                          = false;
58     bool       veboxNeeded                        = false;
59     std::shared_ptr<mhw::vebox::Itf> veboxItf     = nullptr;
60     std::shared_ptr<mhw::sfc::Itf>   sfcItf       = nullptr;
61     std::shared_ptr<mhw::mi::Itf>    miItf        = nullptr;
62     m_osInterface = m_vpPlatformInterface.GetOsInterface();
63     if (m_osInterface == nullptr)
64     {
65         eStatus = MOS_STATUS_NULL_POINTER;
66         return eStatus;
67     }
68 
69     // Initialize platform, sku, wa tables
70     m_osInterface->pfnGetPlatform(m_osInterface, &m_platform);
71     m_skuTable = m_osInterface->pfnGetSkuTable(m_osInterface);
72     m_waTable  = m_osInterface->pfnGetWaTable(m_osInterface);
73 
74     m_vprenderHal = (PRENDERHAL_INTERFACE)MOS_AllocAndZeroMemory(sizeof(*m_vprenderHal));
75     if (m_vprenderHal == nullptr)
76     {
77         VP_PUBLIC_CHK_STATUS_RETURN(MOS_STATUS_NULL_POINTER);
78     }
79 
80     eStatus = RenderHal_InitInterface(
81         m_vprenderHal,
82         &m_cpInterface,
83         m_osInterface);
84 
85     VPHAL_DBG_OCA_DUMPER_CREATE(m_vprenderHal);
86 
87     if (MOS_FAILED(eStatus))
88     {
89         MOS_OS_ASSERTMESSAGE("VpPipelineAdapterBase construct failed due to base class returned failure: eStatus = %d.", eStatus);
90         return eStatus;
91     }
92 
93     veboxNeeded = MEDIA_IS_SKU(m_skuTable, FtrVERing);
94     sfcNeeded   = MEDIA_IS_SKU(m_skuTable, FtrSFCPipe);
95     SetMhwMiItf(m_vprenderHal->pRenderHalPltInterface->GetMhwMiItf());
96     if ((veboxNeeded || sfcNeeded) && !m_clearVideoViewMode)
97     {
98         eStatus = VphalDevice::CreateVPMhwInterfaces(sfcNeeded, veboxNeeded, veboxItf, sfcItf, miItf, m_osInterface);
99         if (eStatus == MOS_STATUS_SUCCESS)
100         {
101             SetMhwVeboxItf(veboxItf);
102             SetMhwSfcItf(sfcItf);
103         }
104         else
105         {
106             VP_PUBLIC_ASSERTMESSAGE("Allocate MhwInterfaces failed");
107             VP_PUBLIC_CHK_STATUS_RETURN(MOS_STATUS_NO_SPACE);
108         }
109     }
110 
111     vpMhwinterface.m_platform       = m_platform;
112     vpMhwinterface.m_waTable        = m_waTable;
113     vpMhwinterface.m_skuTable       = m_skuTable;
114     vpMhwinterface.m_osInterface    = m_osInterface;
115     vpMhwinterface.m_renderHal      = m_vprenderHal;
116     vpMhwinterface.m_cpInterface    = m_cpInterface;
117     vpMhwinterface.m_statusTable    = &m_statusTable;
118     m_vpPlatformInterface.SetMhwSfcItf(m_sfcItf);
119     m_vpPlatformInterface.SetMhwVeboxItf(m_veboxItf);
120     m_vpPlatformInterface.SetMhwMiItf(m_miItf);
121     vpMhwinterface.m_vpPlatformInterface = &m_vpPlatformInterface;
122 
123     return eStatus;
124 }
125 
~VpPipelineAdapterBase()126 VpPipelineAdapterBase::~VpPipelineAdapterBase()
127 {
128     MOS_STATUS eStatus;
129 
130     // Wait for all cmd before destroy gpu resource
131     if (m_osInterface && m_osInterface->pfnWaitAllCmdCompletion && m_osInterface->bDeallocateOnExit)
132     {
133         VP_PUBLIC_NORMALMESSAGE("WaitAllCmdCompletion in VpPipelineAdapterBase::~VpPipelineAdapterBase");
134         m_osInterface->pfnWaitAllCmdCompletion(m_osInterface);
135     }
136 
137     if (m_vprenderHal)
138     {
139         VPHAL_DBG_OCA_DUMPER_DESTORY(m_vprenderHal);
140         if (m_vprenderHal->pfnDestroy)
141         {
142             eStatus = m_vprenderHal->pfnDestroy(m_vprenderHal);
143             if (eStatus != MOS_STATUS_SUCCESS)
144             {
145                 VP_PUBLIC_ASSERTMESSAGE("Failed to destroy RenderHal, eStatus:%d.\n", eStatus);
146             }
147         }
148         MOS_FreeMemory(m_vprenderHal);
149     }
150 
151     if (m_cpInterface)
152     {
153         if (m_osInterface)
154         {
155             m_osInterface->pfnDeleteMhwCpInterface(m_cpInterface);
156             m_cpInterface = nullptr;
157         }
158         else
159         {
160             VP_PUBLIC_ASSERTMESSAGE("Failed to destroy cpInterface.");
161         }
162     }
163 
164     if (m_sfcItf)
165     {
166         m_sfcItf = nullptr;
167     }
168 
169     if (m_veboxItf)
170     {
171         eStatus    = m_veboxItf->DestroyHeap();
172         m_veboxItf = nullptr;
173     }
174 
175     // Destroy OS interface objects (CBs, etc)
176     if (m_osInterface)
177     {
178         if (m_osInterface->bDeallocateOnExit)
179         {
180             m_osInterface->pfnDestroy(m_osInterface, true);
181 
182             // Deallocate OS interface structure (except if externally provided)
183             MOS_FreeMemory(m_osInterface);
184         }
185     }
186 
187     vp::VpPlatformInterface *pIntf = &m_vpPlatformInterface;
188     MOS_Delete(pIntf);
189 }
190 
191 //!
192 //! \brief    Get Status Report
193 //! \details  Get Status Report, will return back to app indicating if related frame id is done by gpu
194 //! \param    [out] pQueryReport
195 //!           Pointer to pQueryReport, the status query report array.
196 //! \param    [in] wStatusNum
197 //!           The size of array pQueryReport.
198 //! \return   MOS_STATUS
199 //!           Return MOS_STATUS_SUCCESS if successful, otherwise failed
GetStatusReport(PQUERY_STATUS_REPORT_APP pQueryReport,uint16_t wStatusNum)200 MOS_STATUS VpPipelineAdapterBase::GetStatusReport(
201     PQUERY_STATUS_REPORT_APP pQueryReport,
202     uint16_t                 wStatusNum)
203 {
204     VP_FUNC_CALL();
205     MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
206 
207 #if (!EMUL)  // this function is dummy for emul
208     uint32_t            i;
209     uint32_t            uiTableLen;
210     PVPHAL_STATUS_TABLE pStatusTable;
211     PMOS_CONTEXT        pOsContext;
212     uint32_t            uiIndex;
213     uint32_t            uiNewHead;
214     PVPHAL_STATUS_ENTRY pStatusEntry;
215     bool                bMarkNotReadyForRemains = false;
216 
217     VP_PUBLIC_CHK_NULL(pQueryReport);
218     VP_PUBLIC_CHK_NULL(m_osInterface);
219     VP_PUBLIC_CHK_NULL(m_osInterface->pOsContext);
220 
221     // it should be ok if we don't consider the null render
222     // eNullRender = m_pOsInterface->pfnGetNullHWRenderFlags(m_pOsInterface);
223 
224     pOsContext   = m_osInterface->pOsContext;
225     pStatusTable = &m_statusTable;
226     uiNewHead    = pStatusTable->uiHead;  // uiNewHead start from previous head value
227     // entry length from head to tail
228     if (pStatusTable->uiCurrent < pStatusTable->uiHead)
229     {
230         uiTableLen = pStatusTable->uiCurrent + VPHAL_STATUS_TABLE_MAX_SIZE - pStatusTable->uiHead;
231     }
232     else
233     {
234         uiTableLen = pStatusTable->uiCurrent - pStatusTable->uiHead;
235     }
236 
237     // step 1 - update pStatusEntry from driver if command associated with the dwTag is done by gpu
238     for (i = 0; i < wStatusNum && i < uiTableLen; i++)
239     {
240         uint32_t dwGpuTag;  // hardware tag updated by gpu command pipectl
241         bool     bDoneByGpu;
242         bool     bFailedOnSubmitCmd;
243 
244         uiIndex      = (pStatusTable->uiHead + i) & (VPHAL_STATUS_TABLE_MAX_SIZE - 1);
245         pStatusEntry = &pStatusTable->aTableEntries[uiIndex];
246 
247         // for tasks using CM, different streamIndexes may be used
248         uint32_t oldStreamIndex = m_osInterface->streamIndex;
249         if (pStatusEntry->isStreamIndexSet)
250         {
251             m_osInterface->streamIndex = pStatusEntry->streamIndex;
252         }
253 
254         if (bMarkNotReadyForRemains)
255         {
256             // the status is set as VPREP_NOTREADY while submitting commands
257             pQueryReport[i].dwStatus         = pStatusEntry->dwStatus;
258             pQueryReport[i].StatusFeedBackID = pStatusEntry->StatusFeedBackID;
259             continue;
260         }
261 
262         dwGpuTag            = m_osInterface->pfnGetGpuStatusSyncTag(m_osInterface, pStatusEntry->GpuContextOrdinal);
263         bDoneByGpu          = (dwGpuTag >= pStatusEntry->dwTag);
264         bFailedOnSubmitCmd  = (pStatusEntry->dwStatus == VPREP_ERROR);
265 
266 #if (_DEBUG || _RELEASE_INTERNAL)
267         MOS_NULL_RENDERING_FLAGS NullRender = m_osInterface->pfnGetNullHWRenderFlags(m_osInterface);
268         if (NullRender.Value != 0)
269         {
270             bDoneByGpu = true;
271         }
272 #endif
273 
274         if (bFailedOnSubmitCmd)
275         {
276             uiNewHead = (uiIndex + 1) & (VPHAL_STATUS_TABLE_MAX_SIZE - 1);
277         }
278         else if (bDoneByGpu)
279         {
280             pStatusEntry->dwStatus = VPREP_OK;
281             uiNewHead              = (uiIndex + 1) & (VPHAL_STATUS_TABLE_MAX_SIZE - 1);
282         }
283         else
284         {  // here we have the first not ready entry.
285 #if (LINUX || ANDROID)
286             uiNewHead = (uiIndex + 1) & (VPHAL_STATUS_TABLE_MAX_SIZE - 1);
287 #else
288             uiNewHead = uiIndex;
289 #endif
290 
291             bMarkNotReadyForRemains = true;
292         }
293 
294         if (m_osInterface->pfnIsGPUHung(m_osInterface))
295         {
296             pStatusEntry->dwStatus = VPREP_NOTREADY;
297         }
298 
299         pQueryReport[i].dwStatus         = pStatusEntry->dwStatus;
300         pQueryReport[i].StatusFeedBackID = pStatusEntry->StatusFeedBackID;
301 
302         if (pStatusEntry->isStreamIndexSet)
303         {
304             m_osInterface->streamIndex = oldStreamIndex;
305         }
306     }
307     pStatusTable->uiHead = uiNewHead;
308 
309     // step 2 - mark VPREP_NOTAVAILABLE for unused entry
310     for (/* continue from previous i */; i < wStatusNum; i++)
311     {
312         pQueryReport[i].dwStatus         = VPREP_NOTAVAILABLE;
313         pQueryReport[i].StatusFeedBackID = 0;
314     }
315 
316 finish:
317 #else
318     MOS_UNUSED(pQueryReport);
319     MOS_UNUSED(wStatusNum);
320 #endif  // end (!EMUL && !ANDROID)
321     return eStatus;
322 }
323 
GetStatusReportEntryLength(uint32_t * puiLength)324 MOS_STATUS VpPipelineAdapterBase::GetStatusReportEntryLength(
325     uint32_t*                      puiLength)
326 {
327     MOS_STATUS                     eStatus = MOS_STATUS_SUCCESS;
328 #if(!EMUL)        // this function is dummy for emul
329     PVPHAL_STATUS_TABLE            pStatusTable;
330 
331     VP_PUBLIC_CHK_NULL(puiLength);
332 
333     pStatusTable = &m_statusTable;
334 
335     // entry length from head to tail
336     if (pStatusTable->uiCurrent < pStatusTable->uiHead)
337     {
338         *puiLength = pStatusTable->uiCurrent + VPHAL_STATUS_TABLE_MAX_SIZE - pStatusTable->uiHead;
339     }
340     else
341     {
342         *puiLength = pStatusTable->uiCurrent - pStatusTable->uiHead;
343     }
344 
345 finish:
346 #else
347     MOS_UNUSED(puiLength);
348 #endif
349     return eStatus;
350 }
351