| /* |
| * Copyright (c) 2009-2018, Intel Corporation |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included |
| * in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| * OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| //! |
| //! \file vphal.cpp |
| //! \brief Vphal Interface Definition |
| //! \details Vphal Interface Definition Including: |
| //! const and function |
| //! |
| #include "vphal.h" |
| #include "mos_os.h" |
| #include "mhw_vebox.h" |
| #include "renderhal.h" |
| #include "vphal_renderer.h" |
| #include "mos_solo_generic.h" |
| #include "media_interfaces_vphal.h" |
| #include "media_interfaces_mhw.h" |
| |
| void VphalFeatureReport::InitReportValue() |
| { |
| IECP = false; |
| IEF = false; |
| Denoise = false; |
| ChromaDenoise = false; |
| DeinterlaceMode = VPHAL_DI_REPORT_PROGRESSIVE; |
| ScalingMode = VPHAL_SCALING_NEAREST; |
| OutputPipeMode = VPHAL_OUTPUT_PIPE_MODE_COMP; |
| VPMMCInUse = false; |
| RTCompressible = false; |
| RTCompressMode = 0; |
| FFDICompressible = false; |
| FFDICompressMode = 0; |
| FFDNCompressible = false; |
| FFDNCompressMode = 0; |
| STMMCompressible = false; |
| STMMCompressMode = 0; |
| ScalerCompressible = false; |
| ScalerCompressMode = 0; |
| PrimaryCompressible = false; |
| PrimaryCompressMode = 0; |
| CompositionMode = VPHAL_NO_COMPOSITION; |
| DiScdMode = false; |
| VEFeatureInUse = false; |
| HDRMode = VPHAL_HDR_MODE_NONE; |
| } |
| |
| //! |
| //! \brief Allocate VPHAL Resources |
| //! \details Allocate VPHAL Resources |
| //! - Allocate and initialize HW states |
| //! - Allocate and initialize renderer states |
| //! \param [in] pVpHalSettings |
| //! Pointer to VPHAL Settings |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalState::Allocate( |
| const VphalSettings *pVpHalSettings) |
| { |
| MHW_VEBOX_GPUNODE_LIMIT GpuNodeLimit; |
| RENDERHAL_SETTINGS RenderHalSettings; |
| MOS_GPU_NODE VeboxGpuNode; |
| MOS_GPU_CONTEXT VeboxGpuContext; |
| MOS_STATUS eStatus; |
| |
| VPHAL_PUBLIC_CHK_NULL(pVpHalSettings); |
| VPHAL_PUBLIC_CHK_NULL(m_renderHal); |
| |
| // Create Render GPU Context |
| { |
| MOS_GPUCTX_CREATOPTIONS createOption; |
| VPHAL_PUBLIC_CHK_STATUS(m_osInterface->pfnCreateGpuContext( |
| m_osInterface, |
| m_renderGpuContext, |
| m_renderGpuNode, |
| &createOption)); |
| } |
| |
| // Set current GPU context |
| VPHAL_PUBLIC_CHK_STATUS(m_osInterface->pfnSetGpuContext( |
| m_osInterface, |
| m_renderGpuContext)); |
| |
| // Register Render GPU context with the event |
| VPHAL_PUBLIC_CHK_STATUS(m_osInterface->pfnRegisterBBCompleteNotifyEvent( |
| m_osInterface, |
| m_renderGpuContext)); |
| |
| if (MEDIA_IS_SKU(m_skuTable, FtrVERing) && m_veboxInterface) |
| { |
| GpuNodeLimit.bSfcInUse = MEDIA_IS_SKU(m_skuTable, FtrSFCPipe); |
| |
| // Check GPU Node decide logic together in this function |
| VPHAL_HW_CHK_STATUS(m_veboxInterface->FindVeboxGpuNodeToUse(&GpuNodeLimit)); |
| |
| VeboxGpuNode = (MOS_GPU_NODE)(GpuNodeLimit.dwGpuNodeToUse); |
| VeboxGpuContext = (VeboxGpuNode == MOS_GPU_NODE_VE) ? MOS_GPU_CONTEXT_VEBOX : MOS_GPU_CONTEXT_VEBOX2; |
| |
| // Create VEBOX/VEBOX2 Context |
| VPHAL_PUBLIC_CHK_STATUS(m_veboxInterface->CreateGpuContext( |
| m_osInterface, |
| VeboxGpuContext, |
| VeboxGpuNode)); |
| |
| // Register Vebox GPU context with the Batch Buffer completion event |
| // Ignore if creation fails |
| VPHAL_PUBLIC_CHK_STATUS(m_osInterface->pfnRegisterBBCompleteNotifyEvent( |
| m_osInterface, |
| MOS_GPU_CONTEXT_VEBOX)); |
| } |
| |
| // Allocate and initialize HW states |
| RenderHalSettings.iMediaStates = pVpHalSettings->mediaStates; |
| VPHAL_PUBLIC_CHK_STATUS(m_renderHal->pfnInitialize(m_renderHal, &RenderHalSettings)); |
| |
| if (m_veboxInterface && |
| m_veboxInterface->m_veboxSettings.uiNumInstances > 0 && |
| m_veboxInterface->m_veboxHeap == nullptr) |
| { |
| // Allocate VEBOX Heap |
| VPHAL_PUBLIC_CHK_STATUS(m_veboxInterface->CreateHeap()); |
| } |
| |
| // Create renderer |
| VPHAL_RENDER_CHK_STATUS(CreateRenderer()); |
| |
| // Allocate and initialize renderer states |
| VPHAL_PUBLIC_CHK_STATUS(m_renderer->Initialize(pVpHalSettings)); |
| |
| finish: |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Check if need to apply AVS for specified surface |
| //! \details Check if need to apply AVS for specified surface |
| //! \param pSurf |
| //! [in] Pointer to VPHAL_SURFACE |
| //! \return bool |
| //! Return true if the input surface needs AVS scaling |
| //! |
| static bool IsSurfNeedAvs( |
| PVPHAL_SURFACE pSurf) |
| { |
| VPHAL_PUBLIC_CHK_NULL_NO_STATUS(pSurf); |
| |
| // Not perform AVS for surface with alpha channel. |
| if (pSurf->Format == Format_AYUV || pSurf->Format == Format_AUYV) |
| { |
| return false; |
| } |
| |
| if (pSurf->SurfType == SURF_IN_PRIMARY || |
| pSurf->SurfType == SURF_IN_SUBSTREAM) |
| { |
| if (pSurf->pBlendingParams) |
| { |
| return false; |
| } |
| |
| if (IS_YUV_FORMAT(pSurf->Format)) |
| { |
| return true; |
| } |
| } |
| finish: |
| return false; |
| } |
| |
| //! |
| //! \brief Check if all surfaces format order in pcRenderParams is suitable to enable multiple avs rendering (YUV is prior than RGB) |
| //! \details In VpHal_RenderWithAvsForMultiStreams() we group YUV surfaces in phase one and the others in phase two. |
| //! However, if there are 2+ overlapped source surfaces, e.g., pSrc[0]=B8G8R8A8 and pSrc[1]=NV12. |
| //! We don't enable multiple avs rendering for such case since we expect pSrc[1] is above pSrc[0] on target. |
| //! If multiple avs rendering is enabled, the compositing order is reverse and turns out pSrc[1] is below pSrc[0], |
| //! which is the case need to prevent. |
| //! \param pcRenderParams |
| //! [in] Pointer to const VPHAL_RENDER_PARAMS |
| //! \return bool |
| //! Allow to enable multiple avs rendering |
| //! |
| static bool IsYuvPriorRgbInCompositeOrder( |
| PCVPHAL_RENDER_PARAMS pcRenderParams) |
| { |
| bool bHasRgbSurface = false; |
| uint32_t uiLastYuvIdx = 0; |
| uint32_t uiFirstRgbIdx = 0; |
| uint32_t iSourceIdx; |
| |
| VPHAL_PUBLIC_CHK_NULL_NO_STATUS(pcRenderParams); |
| |
| for (iSourceIdx = 0; iSourceIdx < pcRenderParams->uSrcCount; iSourceIdx++) |
| { |
| PVPHAL_SURFACE pSurf = pcRenderParams->pSrc[iSourceIdx]; |
| if (IsSurfNeedAvs(pSurf)) |
| { |
| uiLastYuvIdx = iSourceIdx; |
| } |
| else if (!bHasRgbSurface) |
| { |
| bHasRgbSurface = true; |
| uiFirstRgbIdx = iSourceIdx; |
| } |
| } |
| |
| finish: |
| if (!bHasRgbSurface) |
| { // return true if not contain any RGB surface |
| return true; |
| } |
| return (uiLastYuvIdx < uiFirstRgbIdx); |
| } |
| |
| //! |
| //! \brief Check if need to apply AVS scaling for multiple surfaces |
| //! \details Check if need to apply AVS scaling for multiple surfaces |
| //! \param pcRenderParams |
| //! [in] Pointer to const VPHAL_RENDER_PARAMS |
| //! \return bool |
| //! Return true if neeeded to enable AVS for all primary surfaces. |
| //! |
| static bool VpHal_IsAvsSampleForMultiStreamsEnabled( |
| PCVPHAL_RENDER_PARAMS pcRenderParams) |
| { |
| int32_t iSourceIdx; |
| int32_t iSourceBIdx; |
| int32_t iAvsSurfaceCnt = 0; |
| bool bEnableAvsForMultiSurface = false; |
| |
| VPHAL_PUBLIC_CHK_NULL_NO_STATUS(pcRenderParams); |
| |
| //disable if only one or zero source |
| if (pcRenderParams->uSrcCount <= 1) |
| { |
| goto finish; |
| } |
| |
| for (iSourceIdx = 0; iSourceIdx < VPHAL_MAX_SOURCES; iSourceIdx++) |
| { |
| PVPHAL_SURFACE pSrcSurf = pcRenderParams->pSrc[iSourceIdx]; |
| if (pSrcSurf && pSrcSurf->SurfType == SURF_IN_PRIMARY) |
| { |
| // VPHAL_SCALING_PREFER_SFC_FOR_VEBOX means scaling mode is FastMode, don't apply AVS for multiples |
| if (pSrcSurf->ScalingPreference == VPHAL_SCALING_PREFER_SFC_FOR_VEBOX) |
| { |
| goto finish; |
| } |
| |
| if (!IS_YUV_FORMAT(pSrcSurf->Format)) |
| { |
| goto finish; |
| } |
| |
| // disabled if need denoise or deinterlace |
| if (pSrcSurf->pDenoiseParams || pSrcSurf->pDeinterlaceParams) |
| { |
| goto finish; |
| } |
| |
| if (0 < pSrcSurf->uFwdRefCount || 0 < pSrcSurf->uBwdRefCount) |
| { |
| goto finish; |
| } |
| } |
| if (pSrcSurf && IsSurfNeedAvs(pSrcSurf)) |
| { |
| iAvsSurfaceCnt++; |
| } |
| } |
| |
| if (iAvsSurfaceCnt <= 1) |
| { |
| goto finish; |
| } |
| |
| if (!IsYuvPriorRgbInCompositeOrder(pcRenderParams)) |
| { |
| goto finish; |
| } |
| |
| // disable if any AVS surface overlay to other AVS surface. |
| for (iSourceIdx = 0; iSourceIdx < VPHAL_MAX_SOURCES; iSourceIdx++) |
| { |
| PVPHAL_SURFACE pSrcSurfA = pcRenderParams->pSrc[iSourceIdx]; |
| if (pSrcSurfA && IsSurfNeedAvs(pSrcSurfA)) |
| { |
| for (iSourceBIdx = iSourceIdx + 1; iSourceBIdx < VPHAL_MAX_SOURCES; iSourceBIdx++) |
| { |
| PVPHAL_SURFACE pSrcSurfB = pcRenderParams->pSrc[iSourceBIdx]; |
| if (pSrcSurfB && IsSurfNeedAvs(pSrcSurfB) && |
| !RECT1_OUTSIDE_RECT2(pSrcSurfA->rcDst, pSrcSurfB->rcDst)) // not outside means overlay |
| { |
| goto finish; |
| } |
| } |
| } |
| } |
| |
| bEnableAvsForMultiSurface = true; |
| finish: |
| return bEnableAvsForMultiSurface; |
| } |
| |
| //! |
| //! \brief Rendering with AVS scaling for multiple surfaces |
| //! \details Rendering with AVS scaling for multiple surfaces |
| //! Currently composition kernel only allows first primary surface with AVS. |
| //! To apply AVS for multiple surfaces, this function do the following steps: |
| //! (1) separating each AVS surface into different phases containing only one primary |
| //! (2) rendering with individual primary, and let first pass with color filler |
| //! (3) rendering remaining non-AVS substreams, if any, with intermediate surface in one phase to allow alpha blending. |
| //! \param pRenderer |
| //! [in] Pointer to VphalRenderer |
| //! \param pcRenderParams |
| //! [in] Pointer to const VPHAL_RENDER_PARAMS |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| static MOS_STATUS VpHal_RenderWithAvsForMultiStreams( |
| VphalRenderer *pRenderer, |
| PCVPHAL_RENDER_PARAMS pcRenderParams) |
| { |
| int32_t iSourceIdx; |
| VPHAL_RENDER_PARAMS RenderParams; |
| VPHAL_COLORFILL_PARAMS colorFillForFirstRenderPass; |
| bool bColorFillForFirstRender; |
| bool bHasNonAvsSubstream; |
| MOS_STATUS eStatusSingleRender; |
| PVPHAL_SURFACE pIntermediateSurface; |
| PVPHAL_SURFACE pBackGroundSurface; |
| MOS_STATUS eStatus = MOS_STATUS_SUCCESS; |
| VPHAL_SCALING_PREFERENCE ePrimaryScalingPreference = VPHAL_SCALING_PREFER_SFC; |
| VPHAL_RENDER_PARAMS *pRenderParams; |
| |
| VPHAL_PUBLIC_CHK_NULL(pRenderer); |
| VPHAL_PUBLIC_CHK_NULL(pRenderer->GetOsInterface()); |
| VPHAL_PUBLIC_CHK_NULL(pcRenderParams); |
| VPHAL_PUBLIC_CHK_NULL(pcRenderParams->pTarget[0]); |
| |
| pRenderParams = |
| (VPHAL_RENDER_PARAMS*)pcRenderParams; |
| |
| if (pcRenderParams->pColorFillParams) |
| { |
| colorFillForFirstRenderPass = *pcRenderParams->pColorFillParams; |
| } |
| else |
| { |
| colorFillForFirstRenderPass.bYCbCr = false; |
| colorFillForFirstRenderPass.Color = 0; |
| colorFillForFirstRenderPass.CSpace = CSpace_sRGB; |
| } |
| |
| pIntermediateSurface = &pRenderer->IntermediateSurface; |
| |
| // check if having non-AVS substream |
| bHasNonAvsSubstream = false; |
| pBackGroundSurface = nullptr; |
| for (iSourceIdx = 0; iSourceIdx < VPHAL_MAX_SOURCES; iSourceIdx++) |
| { |
| PVPHAL_SURFACE pSurf = (PVPHAL_SURFACE)pcRenderParams->pSrc[iSourceIdx]; |
| if (pSurf && pSurf->SurfType == SURF_IN_SUBSTREAM) |
| { |
| if (!IS_YUV_FORMAT(pSurf->Format)) |
| { |
| bHasNonAvsSubstream = true; |
| } |
| } |
| |
| if (pSurf && pSurf->SurfType == SURF_IN_BACKGROUND) |
| { |
| pBackGroundSurface = pSurf; |
| } |
| |
| // keep scaling preference of primary for later usage |
| if (pSurf && pSurf->SurfType == SURF_IN_PRIMARY) |
| { |
| ePrimaryScalingPreference = pSurf->ScalingPreference; |
| } |
| } |
| |
| // create an intermediate surface if having non-AVS substream, as phase 1 output and phase 2 input. |
| if (bHasNonAvsSubstream) |
| { |
| bool bAllocated; |
| uint32_t dwTempWidth = pcRenderParams->pTarget[0]->dwWidth; |
| uint32_t dwTempHeight = pcRenderParams->pTarget[0]->dwHeight; |
| |
| // Allocate/Reallocate temporary output |
| if (dwTempWidth > pRenderer->IntermediateSurface.dwWidth || |
| dwTempHeight > pRenderer->IntermediateSurface.dwHeight) |
| { |
| dwTempWidth = MOS_MAX(dwTempWidth , pRenderer->IntermediateSurface.dwWidth); |
| dwTempHeight = MOS_MAX(dwTempHeight, pRenderer->IntermediateSurface.dwHeight); |
| dwTempWidth = MOS_ALIGN_CEIL(dwTempWidth , VPHAL_BUFFER_SIZE_INCREMENT); |
| dwTempHeight = MOS_ALIGN_CEIL(dwTempHeight, VPHAL_BUFFER_SIZE_INCREMENT); |
| |
| eStatusSingleRender = VpHal_ReAllocateSurface( |
| pRenderer->GetOsInterface(), |
| &pRenderer->IntermediateSurface, |
| "RenderIntermediateSurface", |
| pcRenderParams->pTarget[0]->Format, |
| MOS_GFXRES_2D, |
| pcRenderParams->pTarget[0]->TileType, |
| dwTempWidth, |
| dwTempHeight, |
| false, |
| MOS_MMC_DISABLED, |
| &bAllocated); |
| |
| if (MOS_SUCCEEDED(eStatusSingleRender)) |
| { |
| pIntermediateSurface->SurfType = SURF_IN_PRIMARY; |
| pIntermediateSurface->SampleType = SAMPLE_PROGRESSIVE; |
| pIntermediateSurface->ColorSpace = pcRenderParams->pTarget[0]->ColorSpace; |
| pIntermediateSurface->ExtendedGamut = pcRenderParams->pTarget[0]->ExtendedGamut; |
| pIntermediateSurface->rcSrc = pcRenderParams->pTarget[0]->rcSrc; |
| pIntermediateSurface->rcDst = pcRenderParams->pTarget[0]->rcDst; |
| pIntermediateSurface->ScalingMode = VPHAL_SCALING_AVS; |
| pIntermediateSurface->bIEF = false; |
| } |
| else |
| { |
| eStatus = eStatusSingleRender; |
| bHasNonAvsSubstream = false; |
| VPHAL_PUBLIC_ASSERTMESSAGE("Failed to create intermediate surface, eStatus: %d.\n", eStatus); |
| } |
| } |
| } |
| |
| // phase 1: render each AVS surface in separated pass |
| bColorFillForFirstRender = true; |
| RenderParams = *pRenderParams; |
| RenderParams.uDstCount = 1; |
| MOS_ZeroMemory(RenderParams.pSrc, sizeof(PVPHAL_SURFACE) * VPHAL_MAX_SOURCES); |
| |
| for (iSourceIdx = 0; iSourceIdx < VPHAL_MAX_SOURCES; iSourceIdx++) |
| { |
| VPHAL_SURFACE SinglePassSource; |
| PVPHAL_SURFACE pSurf = (PVPHAL_SURFACE)pcRenderParams->pSrc[iSourceIdx]; |
| RenderParams.uSrcCount = 0; |
| |
| if (pSurf && IsSurfNeedAvs(pSurf)) |
| { |
| SinglePassSource = *(pSurf); |
| SinglePassSource.SurfType = SURF_IN_PRIMARY; |
| SinglePassSource.ScalingMode = VPHAL_SCALING_AVS; |
| SinglePassSource.ScalingPreference = ePrimaryScalingPreference; |
| |
| RenderParams.pTarget[0] = (bHasNonAvsSubstream ? pIntermediateSurface : pcRenderParams->pTarget[0]); |
| |
| if (bColorFillForFirstRender) // apply color-fill for the first rendering |
| { |
| bColorFillForFirstRender = false; |
| RenderParams.pColorFillParams = &colorFillForFirstRenderPass; |
| |
| if (pBackGroundSurface) |
| { |
| RenderParams.pSrc[RenderParams.uSrcCount] = pBackGroundSurface; |
| RenderParams.uSrcCount++; |
| } |
| } |
| else |
| { |
| RenderParams.pTarget[0]->rcDst = SinglePassSource.rcDst; |
| RenderParams.pColorFillParams = nullptr; |
| } |
| |
| RenderParams.pSrc[RenderParams.uSrcCount] = &SinglePassSource; |
| RenderParams.uSrcCount++; |
| |
| // continue the next pfnRender even if single pass failed, but return eStatus failed. |
| eStatusSingleRender = pRenderer->Render((PCVPHAL_RENDER_PARAMS)(&RenderParams)); |
| if (MOS_FAILED(eStatusSingleRender)) |
| { |
| eStatus = eStatusSingleRender; |
| VPHAL_PUBLIC_ASSERTMESSAGE("Failed to redner for primary streams, eStatus: %d.\n", eStatus); |
| } |
| } |
| } |
| |
| // phase 2: if having non-AVS substream, render them with previous output in one pass. |
| if (bHasNonAvsSubstream) |
| { |
| RenderParams = *pRenderParams; |
| MOS_ZeroMemory(RenderParams.pSrc, sizeof(PVPHAL_SURFACE) * VPHAL_MAX_SOURCES); |
| |
| pIntermediateSurface->rcSrc = pcRenderParams->pTarget[0]->rcSrc; |
| pIntermediateSurface->rcDst = pcRenderParams->pTarget[0]->rcDst; |
| RenderParams.pSrc[0] = pIntermediateSurface; |
| RenderParams.uSrcCount = 1; |
| RenderParams.uDstCount = 1; |
| |
| for (iSourceIdx = 0; iSourceIdx < VPHAL_MAX_SOURCES && RenderParams.uSrcCount < VPHAL_MAX_SOURCES; iSourceIdx++) |
| { |
| PVPHAL_SURFACE pSurf = pcRenderParams->pSrc[iSourceIdx]; |
| bool bIsSurfForPhase2 = (pSurf && |
| (!IsSurfNeedAvs(pSurf)) && |
| (pSurf->SurfType != SURF_IN_BACKGROUND)); |
| if (bIsSurfForPhase2) |
| { |
| RenderParams.pSrc[RenderParams.uSrcCount] = pSurf; |
| RenderParams.uSrcCount++; |
| } |
| } |
| |
| eStatusSingleRender = pRenderer->Render((PCVPHAL_RENDER_PARAMS)(&RenderParams)); |
| if (MOS_FAILED(eStatusSingleRender)) |
| { |
| eStatus = eStatusSingleRender; |
| VPHAL_PUBLIC_ASSERTMESSAGE("Failed to redner for substreams, eStatus: %d.\n", eStatus); |
| } |
| |
| //Free the temporary surface |
| pRenderer->GetOsInterface()->pfnFreeResource(pRenderer->GetOsInterface(), &(pIntermediateSurface->OsResource)); |
| |
| } |
| |
| finish: |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Performs VP Rendering |
| //! \details Performs VP Rendering |
| //! - call default render of video |
| //! \param [in] pcRenderParams |
| //! Pointer to Render Params |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalState::Render( |
| PCVPHAL_RENDER_PARAMS pcRenderParams) |
| { |
| MOS_STATUS eStatus; |
| VPHAL_RENDER_PARAMS RenderParams; |
| |
| VPHAL_PUBLIC_CHK_NULL(pcRenderParams); |
| RenderParams = *pcRenderParams; |
| |
| if (VpHal_IsAvsSampleForMultiStreamsEnabled(pcRenderParams)) |
| { |
| eStatus = VpHal_RenderWithAvsForMultiStreams(m_renderer, pcRenderParams); |
| goto finish; |
| } |
| |
| // default render of video |
| RenderParams.bIsDefaultStream = true; |
| eStatus = m_renderer->Render((PCVPHAL_RENDER_PARAMS)(&RenderParams)); |
| |
| finish: |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Get feature reporting from renderer |
| //! \details Get feature reporting from renderer |
| //! \return VphalFeatureReport* |
| //! Pointer to VphalFeatureReport: rendering features reported |
| //! |
| VphalFeatureReport* VphalState::GetRenderFeatureReport() |
| { |
| VPHAL_PUBLIC_ASSERT(m_renderer); |
| |
| return m_renderer->GetReport(); |
| } |
| |
| //! |
| //! \brief VphalState Constructor |
| //! \details Creates instance of VphalState |
| //! - Return pointer to initialized VPHAL state, but not yet fully allocated |
| //! - Caller must call pfnAllocate to allocate all VPHAL states and objects. |
| //! \param [in] pOsInterface |
| //! OS interface, if provided externally - may be nullptr |
| //! \param [in] pOsDriverContext |
| //! OS driver context (UMD context, pShared, ...) |
| //! \param [in,out] peStatus |
| //! Pointer to the MOS_STATUS flag. |
| //! Will assign this flag to MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| VphalState::VphalState( |
| PMOS_INTERFACE pOsInterface, |
| PMOS_CONTEXT pOsDriverContext, |
| MOS_STATUS *peStatus) : |
| m_gpuAppTaskEvent(nullptr), |
| m_platform(), |
| m_skuTable(nullptr), |
| m_waTable(nullptr), |
| m_osInterface(pOsInterface), |
| m_renderHal(nullptr), |
| m_veboxInterface(nullptr), |
| m_cpInterface(nullptr), |
| m_sfcInterface(nullptr), |
| m_renderer(nullptr), |
| m_renderGpuNode(MOS_GPU_NODE_3D), |
| m_renderGpuContext(MOS_GPU_CONTEXT_RENDER) |
| { |
| MOS_STATUS eStatus; |
| |
| eStatus = MOS_STATUS_UNKNOWN; |
| |
| VPHAL_PUBLIC_CHK_NULL(m_osInterface); |
| |
| // Initialize platform, sku, wa tables |
| m_osInterface->pfnGetPlatform(m_osInterface, &m_platform); |
| m_skuTable = m_osInterface->pfnGetSkuTable(m_osInterface); |
| m_waTable = m_osInterface->pfnGetWaTable (m_osInterface); |
| |
| m_renderHal = (PRENDERHAL_INTERFACE)MOS_AllocAndZeroMemory(sizeof(*m_renderHal)); |
| VPHAL_PUBLIC_CHK_NULL(m_renderHal); |
| VPHAL_PUBLIC_CHK_STATUS(RenderHal_InitInterface( |
| m_renderHal, |
| &m_cpInterface, |
| m_osInterface)); |
| |
| if (MEDIA_IS_SKU(m_skuTable, FtrVERing) || |
| MEDIA_IS_SKU(m_skuTable, FtrSFCPipe)) |
| { |
| MhwInterfaces *mhwInterfaces = nullptr; |
| MhwInterfaces::CreateParams params; |
| MOS_ZeroMemory(¶ms, sizeof(params)); |
| params.Flags.m_sfc = MEDIA_IS_SKU(m_skuTable, FtrSFCPipe); |
| params.Flags.m_vebox = MEDIA_IS_SKU(m_skuTable, FtrVERing); |
| |
| mhwInterfaces = MhwInterfaces::CreateFactory(params, pOsInterface); |
| if (mhwInterfaces) |
| { |
| SetMhwVeboxInterface(mhwInterfaces->m_veboxInterface); |
| SetMhwSfcInterface(mhwInterfaces->m_sfcInterface); |
| |
| // MhwInterfaces always create CP and MI interfaces, so we have to delete those we don't need. |
| MOS_Delete(mhwInterfaces->m_miInterface); |
| Delete_MhwCpInterface(mhwInterfaces->m_cpInterface); |
| mhwInterfaces->m_cpInterface = nullptr; |
| MOS_Delete(mhwInterfaces); |
| } |
| else |
| { |
| VPHAL_DEBUG_ASSERTMESSAGE("Allocate MhwInterfaces failed"); |
| eStatus = MOS_STATUS_NO_SPACE; |
| } |
| } |
| |
| finish: |
| if(peStatus) |
| { |
| *peStatus = eStatus; |
| } |
| } |
| |
| //! |
| //! \brief Vphal Destructor |
| //! \details Destroys VPHAL and all internal states and objects |
| //! \return void |
| //! |
| VphalState::~VphalState() |
| { |
| MOS_STATUS eStatus; |
| |
| // Destroy rendering objects (intermediate surfaces, BBs, etc) |
| if (m_renderer) |
| { |
| MOS_Delete(m_renderer); |
| m_renderer = nullptr; |
| } |
| |
| if (m_renderHal) |
| { |
| if (m_renderHal->pfnDestroy) |
| { |
| eStatus = m_renderHal->pfnDestroy(m_renderHal); |
| if (eStatus != MOS_STATUS_SUCCESS) |
| { |
| VPHAL_PUBLIC_ASSERTMESSAGE("Failed to destroy RenderHal, eStatus:%d.\n", eStatus); |
| } |
| } |
| MOS_FreeMemory(m_renderHal); |
| } |
| |
| if (m_cpInterface) |
| { |
| Delete_MhwCpInterface(m_cpInterface); |
| m_cpInterface = nullptr; |
| } |
| |
| if (m_sfcInterface) |
| { |
| MOS_Delete(m_sfcInterface); |
| m_sfcInterface = nullptr; |
| } |
| |
| if (m_veboxInterface) |
| { |
| eStatus = m_veboxInterface->DestroyHeap(); |
| MOS_Delete(m_veboxInterface); |
| m_veboxInterface = nullptr; |
| if (eStatus != MOS_STATUS_SUCCESS) |
| { |
| VPHAL_PUBLIC_ASSERTMESSAGE("Failed to destroy Vebox Interface, eStatus:%d.\n", eStatus); |
| } |
| } |
| |
| // Destroy OS interface objects (CBs, etc) |
| if (m_osInterface) |
| { |
| if (m_osInterface->bDeallocateOnExit) |
| { |
| m_osInterface->pfnDestroy(m_osInterface, true); |
| |
| // Deallocate OS interface structure (except if externally provided) |
| MOS_FreeMemory(m_osInterface); |
| } |
| } |
| } |
| |
| VphalState* VphalState::VphalStateFactory( |
| PMOS_INTERFACE pOsInterface, |
| PMOS_CONTEXT pOsDriverContext, |
| MOS_STATUS *peStatus) |
| { |
| return VphalDevice::CreateFactory(pOsInterface, pOsDriverContext, peStatus); |
| } |
| |
| //! |
| //! \brief Get Status Report |
| //! \details Get Status Report, will return back to app indicating if related frame id is done by gpu |
| //! \param [out] pQueryReport |
| //! Pointer to pQueryReport, the status query report array. |
| //! \param [in] wStatusNum |
| //! The size of array pQueryReport. |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| MOS_STATUS VphalState::GetStatusReport( |
| PQUERY_STATUS_REPORT_APP pQueryReport, |
| uint16_t wStatusNum) |
| { |
| MOS_STATUS eStatus = MOS_STATUS_SUCCESS; |
| |
| #if (!EMUL) // this function is dummy for emul |
| uint32_t i; |
| uint32_t uiTableLen; |
| PVPHAL_STATUS_TABLE pStatusTable; |
| PMOS_CONTEXT pOsContext; |
| uint32_t uiIndex; |
| uint32_t uiNewHead; |
| PVPHAL_STATUS_ENTRY pStatusEntry; |
| bool bMarkNotReadyForRemains = false; |
| |
| VPHAL_PUBLIC_CHK_NULL(pQueryReport); |
| VPHAL_PUBLIC_CHK_NULL(m_osInterface); |
| VPHAL_PUBLIC_CHK_NULL(m_osInterface->pOsContext); |
| |
| // it should be ok if we don't consider the null render |
| // eNullRender = m_pOsInterface->pfnGetNullHWRenderFlags(m_pOsInterface); |
| |
| pOsContext = m_osInterface->pOsContext; |
| pStatusTable = &m_statusTable; |
| uiNewHead = pStatusTable->uiHead; // uiNewHead start from previous head value |
| // entry length from head to tail |
| uiTableLen = (pStatusTable->uiCurrent - pStatusTable->uiHead) & (VPHAL_STATUS_TABLE_MAX_SIZE - 1); |
| |
| // step 1 - update pStatusEntry from driver if command associated with the dwTag is done by gpu |
| for (i = 0; i < wStatusNum && i < uiTableLen; i++) |
| { |
| uint32_t dwGpuTag; // hardware tag updated by gpu command pipectl |
| bool bDoneByGpu; |
| bool bFailedOnSubmitCmd; |
| |
| uiIndex = (pStatusTable->uiHead + i) & (VPHAL_STATUS_TABLE_MAX_SIZE - 1); |
| pStatusEntry = &pStatusTable->aTableEntries[uiIndex]; |
| |
| if (bMarkNotReadyForRemains) |
| { |
| // the status is set as VPREP_NOTREADY while submitting commands |
| pQueryReport[i].dwStatus = pStatusEntry->dwStatus; |
| pQueryReport[i].StatusFeedBackID = pStatusEntry->StatusFeedBackID; |
| continue; |
| } |
| #if (LINUX || ANDROID) |
| dwGpuTag = pOsContext->GetGPUTag(m_osInterface, pStatusEntry->GpuContextOrdinal); |
| #else |
| dwGpuTag = pOsContext->GetGPUTag(pOsContext->GetGpuContextHandle(pStatusEntry->GpuContextOrdinal, m_osInterface->streamIndex)); |
| #endif |
| bDoneByGpu = (dwGpuTag >= pStatusEntry->dwTag); |
| bFailedOnSubmitCmd = (pStatusEntry->dwStatus == VPREP_ERROR); |
| |
| #if (_DEBUG || _RELEASE_INTERNAL) |
| MOS_NULL_RENDERING_FLAGS NullRender = m_osInterface->pfnGetNullHWRenderFlags(m_osInterface); |
| if (NullRender.Value != 0) |
| { |
| bDoneByGpu = true; |
| } |
| #endif |
| |
| if (bFailedOnSubmitCmd) |
| { |
| uiNewHead = (uiIndex + 1) & (VPHAL_STATUS_TABLE_MAX_SIZE - 1); |
| } |
| else if (bDoneByGpu) |
| { |
| pStatusEntry->dwStatus = VPREP_OK; |
| uiNewHead = (uiIndex + 1) & (VPHAL_STATUS_TABLE_MAX_SIZE - 1); |
| } |
| else |
| { // here we have the first not ready entry. |
| #if (LINUX || ANDROID) |
| uiNewHead = (uiIndex + 1) & (VPHAL_STATUS_TABLE_MAX_SIZE - 1); |
| #else |
| uiNewHead = uiIndex; |
| #endif |
| |
| bMarkNotReadyForRemains = true; |
| } |
| |
| if (m_osInterface->pfnIsGPUHung(m_osInterface)) |
| { |
| pStatusEntry->dwStatus = VPREP_NOTREADY; |
| } |
| |
| pQueryReport[i].dwStatus = pStatusEntry->dwStatus; |
| pQueryReport[i].StatusFeedBackID = pStatusEntry->StatusFeedBackID; |
| } |
| pStatusTable->uiHead = uiNewHead; |
| |
| // step 2 - mark VPREP_NOTAVAILABLE for unused entry |
| for (/* continue from previous i */; i < wStatusNum; i++) |
| { |
| pQueryReport[i].dwStatus = VPREP_NOTAVAILABLE; |
| pQueryReport[i].StatusFeedBackID = 0; |
| } |
| |
| finish: |
| #else |
| MOS_UNUSED(pQueryReport); |
| MOS_UNUSED(wStatusNum); |
| #endif // end (!EMUL && !ANDROID) |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Get Status Report's entry length from head to tail |
| //! \details Get Status Report's entry length from head to tail |
| //! \param [out] puiLength |
| //! Pointer to the entry length |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalState::GetStatusReportEntryLength( |
| uint32_t* puiLength) |
| { |
| MOS_STATUS eStatus = MOS_STATUS_SUCCESS; |
| #if(!EMUL) // this function is dummy for emul |
| PVPHAL_STATUS_TABLE pStatusTable; |
| |
| VPHAL_PUBLIC_CHK_NULL(puiLength); |
| |
| pStatusTable = &m_statusTable; |
| |
| // entry length from head to tail |
| *puiLength = (pStatusTable->uiCurrent - pStatusTable->uiHead) & (VPHAL_STATUS_TABLE_MAX_SIZE - 1); |
| finish: |
| #else |
| MOS_UNUSED(puiLength); |
| #endif |
| return eStatus; |
| } |