| /* |
| * Copyright (c) 2011-2021, 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_renderer.cpp |
| //! \brief VPHAL top level rendering component and the entry to low level renderers |
| //! \details The top renderer is responsible for coordinating the sequence of calls to low level renderers, e.g. DNDI or Comp |
| //! |
| #include "vphal_renderer.h" |
| #include "vphal_debug.h" |
| #include "vpkrnheader.h" |
| #include "vphal_render_composite.h" |
| |
| // Slice Shutdown User feature keys |
| #define VPHAL_SSD_CONTROL "SSD Control" |
| |
| //==<FUNCTIONS>================================================================= |
| |
| //! |
| //! \brief Initialize AVS parameters shared by Renderers |
| //! \details Initialize the members of the AVS parameter and allocate memory for its coefficient tables |
| //! \param [in,out] pAVS_Params |
| //! Pointer to MHW AVS parameter |
| //! \param [in] uiYCoeffTableSize |
| //! Size of the Y coefficient table |
| //! \param [in] uiUVCoeffTableSize |
| //! Size of the UV coefficient table |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VpHal_RenderInitAVSParams( |
| PMHW_AVS_PARAMS pAVS_Params, |
| uint32_t uiYCoeffTableSize, |
| uint32_t uiUVCoeffTableSize) |
| { |
| MOS_STATUS eStatus; |
| int32_t size; |
| char* ptr; |
| |
| VPHAL_RENDER_ASSERT(pAVS_Params); |
| VPHAL_RENDER_ASSERT(uiYCoeffTableSize > 0); |
| VPHAL_RENDER_ASSERT(uiUVCoeffTableSize > 0); |
| eStatus = MOS_STATUS_SUCCESS; |
| |
| // Init AVS parameters |
| pAVS_Params->Format = Format_None; |
| pAVS_Params->fScaleX = 0.0F; |
| pAVS_Params->fScaleY = 0.0F; |
| pAVS_Params->piYCoefsX = nullptr; |
| |
| // Allocate AVS coefficients, One set each for X and Y |
| size = (uiYCoeffTableSize + uiUVCoeffTableSize) * 2; |
| |
| ptr = (char*)MOS_AllocAndZeroMemory(size); |
| if (ptr == nullptr) |
| { |
| VPHAL_RENDER_ASSERTMESSAGE("No memory to allocate AVS coefficient tables."); |
| eStatus = MOS_STATUS_NO_SPACE; |
| goto finish; |
| } |
| |
| pAVS_Params->piYCoefsX = (int32_t*)ptr; |
| |
| ptr += uiYCoeffTableSize; |
| pAVS_Params->piUVCoefsX = (int32_t*)ptr; |
| |
| ptr += uiUVCoeffTableSize; |
| pAVS_Params->piYCoefsY = (int32_t*)ptr; |
| |
| ptr += uiYCoeffTableSize; |
| pAVS_Params->piUVCoefsY = (int32_t*)ptr; |
| |
| finish: |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Destroy AVS parameters shared by Renderers |
| //! \details Free the memory of AVS parameter's coefficient tables |
| //! \param [in,out] pAVS_Params |
| //! Pointer to VPHAL AVS parameter |
| //! \return void |
| //! |
| void VpHal_RenderDestroyAVSParams( |
| PMHW_AVS_PARAMS pAVS_Params) |
| { |
| MOS_SafeFreeMemory(pAVS_Params->piYCoefsX); |
| pAVS_Params->piYCoefsX = nullptr; |
| } |
| |
| //! |
| //! \brief Get the size in byte from that in pixel |
| //! \details Size_in_byte = size_in_pixel x byte/pixel |
| //! \param [in] pOsInterface |
| //! Pointer to OS interface |
| //! \param [in] Format |
| //! The format which determines the value of byte/pixel |
| //! \param [in] dwPixels |
| //! The size in pixel |
| //! \return uint32_t |
| //! Return the size in byte |
| //! |
| uint32_t VpHal_PixelsToBytes( |
| PMOS_INTERFACE pOsInterface, |
| MOS_FORMAT Format, |
| uint32_t dwPixels) |
| { |
| MOS_STATUS eStatus; |
| uint32_t iBpp; |
| uint32_t dwBpp; |
| |
| eStatus = MOS_STATUS_SUCCESS; |
| dwBpp = 0; |
| VPHAL_RENDER_CHK_STATUS(pOsInterface->pfnGetBitsPerPixel(pOsInterface, Format, &iBpp)); |
| dwBpp = dwPixels * (iBpp>>3); |
| |
| finish: |
| return dwBpp; |
| } |
| |
| //! |
| //! \brief Save/Restore fwd references for the primary |
| //! \details Based on the flag passed in to save or restore the forward references |
| //! of the primary |
| //! \param [in,out] pRenderer |
| //! VPHAL renderer pointer |
| //! \param [in,out] pPrimarySurf |
| //! Pointer to the primary surface |
| //! \param [in] bSave |
| //! Save - true or restore - false the fwd references |
| //! \return void |
| //! |
| void VpHal_SaveRestorePrimaryFwdRefs( |
| VphalRenderer *pRenderer, |
| PVPHAL_SURFACE pPrimarySurf, |
| bool bSave) |
| { |
| PVPHAL_SURFACE pFwdRef; |
| uint32_t uiSources; |
| uint32_t uiIndex; |
| |
| VPHAL_RENDER_ASSERT(pRenderer); |
| VPHAL_RENDER_ASSERT(pPrimarySurf && (pPrimarySurf->SurfType == SURF_IN_PRIMARY)); |
| |
| pFwdRef = nullptr; |
| uiSources = 0; |
| uiIndex = 0; |
| |
| if (bSave) |
| { |
| pFwdRef = pPrimarySurf->pFwdRef; |
| |
| while(pFwdRef) |
| { |
| pRenderer->pPrimaryFwdRef[uiIndex] = pFwdRef; |
| pFwdRef = pFwdRef->pFwdRef; |
| uiIndex++; |
| if (uiIndex >= VPHAL_MAX_FUTURE_FRAMES) |
| { |
| break; |
| } |
| } |
| } |
| else |
| { |
| pFwdRef = pPrimarySurf; |
| |
| while (pRenderer->pPrimaryFwdRef[uiIndex]) |
| { |
| pFwdRef->pFwdRef = pRenderer->pPrimaryFwdRef[uiIndex]; |
| pRenderer->pPrimaryFwdRef[uiIndex] = nullptr; |
| pFwdRef = pFwdRef->pFwdRef; |
| uiIndex++; |
| if (uiIndex >= VPHAL_MAX_FUTURE_FRAMES) |
| { |
| break; |
| } |
| } |
| } |
| } |
| |
| //! |
| //! \brief Align the src/dst surface rectangle and surface width/height |
| //! \details The surface rects and width/height need to be aligned according to the surface format |
| //! \param [in,out] pSurface |
| //! Pointer to the surface |
| //! \param [in] formatForDstRect |
| //! Format for Dst Rect |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VpHal_RndrRectSurfaceAlignment( |
| PVPHAL_SURFACE pSurface, |
| MOS_FORMAT formatForDstRect) |
| { |
| uint16_t wWidthAlignUnit; |
| uint16_t wHeightAlignUnit; |
| uint16_t wWidthAlignUnitForDstRect; |
| uint16_t wHeightAlignUnitForDstRect; |
| MOS_STATUS eStatus; |
| |
| eStatus = MOS_STATUS_SUCCESS; |
| |
| VpHal_RndrGetAlignUnit(&wWidthAlignUnit, &wHeightAlignUnit, pSurface->Format); |
| VpHal_RndrGetAlignUnit(&wWidthAlignUnitForDstRect, &wHeightAlignUnitForDstRect, formatForDstRect); |
| |
| // The source rectangle is floored to the aligned unit to |
| // get rid of invalid data(ex: an odd numbered src rectangle with NV12 format |
| // will have invalid UV data for the last line of Y data). |
| pSurface->rcSrc.bottom = MOS_ALIGN_FLOOR((uint32_t)pSurface->rcSrc.bottom, wHeightAlignUnit); |
| pSurface->rcSrc.right = MOS_ALIGN_FLOOR((uint32_t)pSurface->rcSrc.right, wWidthAlignUnit); |
| |
| pSurface->rcSrc.top = MOS_ALIGN_CEIL((uint32_t)pSurface->rcSrc.top, wHeightAlignUnit); |
| pSurface->rcSrc.left = MOS_ALIGN_CEIL((uint32_t)pSurface->rcSrc.left, wWidthAlignUnit); |
| |
| // The Destination rectangle is rounded to the upper alignment unit to prevent the loss of |
| // data which was present in the source rectangle |
| pSurface->rcDst.bottom = MOS_ALIGN_CEIL((uint32_t)pSurface->rcDst.bottom, wHeightAlignUnitForDstRect); |
| pSurface->rcDst.right = MOS_ALIGN_CEIL((uint32_t)pSurface->rcDst.right, wWidthAlignUnitForDstRect); |
| |
| pSurface->rcDst.top = MOS_ALIGN_FLOOR((uint32_t)pSurface->rcDst.top, wHeightAlignUnitForDstRect); |
| pSurface->rcDst.left = MOS_ALIGN_FLOOR((uint32_t)pSurface->rcDst.left, wWidthAlignUnitForDstRect); |
| |
| if (pSurface->SurfType == SURF_OUT_RENDERTARGET) |
| { |
| pSurface->dwHeight = MOS_ALIGN_CEIL(pSurface->dwHeight, wHeightAlignUnit); |
| pSurface->dwWidth = MOS_ALIGN_CEIL(pSurface->dwWidth, wWidthAlignUnit); |
| } |
| else |
| { |
| pSurface->dwHeight = MOS_ALIGN_FLOOR(pSurface->dwHeight, wHeightAlignUnit); |
| pSurface->dwWidth = MOS_ALIGN_FLOOR(pSurface->dwWidth, wWidthAlignUnit); |
| } |
| |
| if ((pSurface->rcSrc.top == pSurface->rcSrc.bottom) || |
| (pSurface->rcSrc.left == pSurface->rcSrc.right) || |
| (pSurface->rcDst.top == pSurface->rcDst.bottom) || |
| (pSurface->rcDst.left == pSurface->rcDst.right) || |
| (pSurface->dwWidth == 0) || |
| (pSurface->dwHeight == 0)) |
| { |
| VPHAL_RENDER_ASSERTMESSAGE("Surface Parameter is invalid."); |
| eStatus = MOS_STATUS_INVALID_PARAMETER; |
| } |
| |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Prepare input surface list for top level render processing |
| //! \details Prepare the inputs, e.g. adjust src/dst rectangles of stereo input or allocate |
| //! and copy intermediate surfaces. |
| //! \param [in,out] pRenderParams |
| //! Pointer to VPHAL render parameter |
| //! \param [in,out] pSrcLeft |
| //! Pointer to left frame list |
| //! \param [in,out] pSrcRight |
| //! Pointer to right frame list |
| //! \param [out] puiRenderPasses |
| //! Pointer to times of the rendering. |
| //! The value is 2 for S3D and 1 for the other cases. |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalRenderer::PrepareSources( |
| PVPHAL_RENDER_PARAMS pRenderParams, |
| PVPHAL_SURFACE *pSrcLeft, |
| PVPHAL_SURFACE *pSrcRight, |
| uint32_t *puiRenderPasses) |
| { |
| MOS_STATUS eStatus; |
| PVPHAL_SURFACE pcSrc; |
| uint32_t uiLeftCount; |
| uint32_t uiRightCount; |
| uint32_t uiSources; |
| uint32_t uiTargets; |
| uint32_t uiIndex; |
| PMOS_RESOURCE ppSource[VPHAL_MAX_SOURCES] = { nullptr }; |
| PMOS_RESOURCE ppTarget[VPHAL_MAX_TARGETS] = { nullptr }; |
| eStatus = MOS_STATUS_SUCCESS; |
| uiLeftCount = 0; |
| uiRightCount = 0; |
| uiIndex = 0; |
| uiSources = 0; |
| uiTargets = 0; |
| |
| VPHAL_RENDER_CHK_NULL(m_pOsInterface); |
| |
| for (uiSources=0, uiIndex=0; |
| (uiIndex < pRenderParams->uSrcCount) && (uiIndex < VPHAL_MAX_SOURCES); |
| uiIndex++) |
| { |
| pcSrc = pRenderParams->pSrc[uiIndex]; |
| |
| if (pcSrc == nullptr) |
| { |
| continue; |
| } |
| |
| ppSource[uiSources] = &pcSrc->OsResource; |
| |
| pSrcLeft[uiLeftCount++] = pcSrc; |
| |
| uiSources++; |
| } |
| |
| //gather render target list |
| for (uiTargets = 0, uiIndex = 0; |
| (uiIndex < pRenderParams->uDstCount) && (uiIndex < VPHAL_MAX_TARGETS); |
| uiIndex++) |
| { |
| pcSrc = pRenderParams->pTarget[uiIndex]; |
| |
| if (pcSrc) |
| { |
| ppTarget[uiTargets] = &pcSrc->OsResource; |
| uiTargets++; |
| } |
| } |
| |
| VPHAL_RENDER_ASSERT(uiRightCount == 0); |
| |
| pRenderParams->uSrcCount = uiLeftCount; |
| *puiRenderPasses = 1; |
| |
| finish: |
| VPHAL_RENDER_ASSERT(eStatus == MOS_STATUS_SUCCESS); |
| |
| if ((nullptr != m_pOsInterface) && (nullptr != m_pOsInterface->osCpInterface)) |
| { |
| eStatus = m_pOsInterface->osCpInterface->PrepareResources( |
| (void **)ppSource, uiSources, |
| (void **)ppTarget, uiTargets); |
| } |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Get surface info for all input source |
| //! \details Get surface info for the input surface and its reference surfaces |
| //! \param [in] pRenderParams |
| //! Pointer to VPHAL render parameter |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalRenderer::GetSurfaceInfoForSrc( |
| PVPHAL_RENDER_PARAMS pRenderParams) |
| { |
| MOS_STATUS eStatus; |
| PVPHAL_SURFACE pSrcSurface; // Current source surface |
| PVPHAL_SURFACE pSurface; // Ptr to surface |
| uint32_t uiSources; // Number of Sources |
| uint32_t uiIndex; // Current source index |
| uint32_t i; |
| VPHAL_GET_SURFACE_INFO Info; |
| |
| eStatus = MOS_STATUS_SUCCESS; |
| pSrcSurface = nullptr; |
| |
| // Loop through the sources |
| for (uiSources = 0, uiIndex = 0; |
| uiSources < pRenderParams->uSrcCount && uiIndex < VPHAL_MAX_SOURCES; |
| uiIndex++) |
| { |
| pSrcSurface = pRenderParams->pSrc[uiIndex]; |
| |
| if (pSrcSurface == nullptr) |
| { |
| continue; |
| } |
| uiSources++; |
| |
| if (Mos_ResourceIsNull(&pSrcSurface->OsResource)) |
| { |
| VPHAL_RENDER_ASSERTMESSAGE("Input resource is not valid."); |
| eStatus = MOS_STATUS_UNKNOWN; |
| goto finish; |
| } |
| |
| MOS_ZeroMemory(&Info, sizeof(VPHAL_GET_SURFACE_INFO)); |
| |
| VPHAL_RENDER_CHK_STATUS(VpHal_GetSurfaceInfo( |
| m_pOsInterface, |
| &Info, |
| pSrcSurface)); |
| |
| // Get resource info for Backward References, if any |
| pSurface = pSrcSurface->pBwdRef; |
| for (i = 0; i < pSrcSurface->uBwdRefCount; i++) |
| { |
| VPHAL_RENDER_ASSERT(pSurface); // Must have valid reference pointer |
| if (pSurface) |
| { |
| MOS_ZeroMemory(&Info, sizeof(VPHAL_GET_SURFACE_INFO)); |
| |
| VPHAL_RENDER_CHK_STATUS(VpHal_GetSurfaceInfo( |
| m_pOsInterface, |
| &Info, |
| pSurface)); |
| |
| // point to the next bwd ref |
| pSurface = pSurface->pBwdRef; |
| } |
| } |
| |
| // Get resource info for Forward References, if any |
| pSurface = pSrcSurface->pFwdRef; |
| for (i = 0; i < pSrcSurface->uFwdRefCount; i++) |
| { |
| VPHAL_RENDER_ASSERT(pSurface); // Must have valid reference pointer |
| if (pSurface) |
| { |
| MOS_ZeroMemory(&Info, sizeof(VPHAL_GET_SURFACE_INFO)); |
| |
| VPHAL_RENDER_CHK_STATUS(VpHal_GetSurfaceInfo( |
| m_pOsInterface, |
| &Info, |
| pSurface)); |
| |
| // point to the next fwd ref |
| pSurface = pSurface->pFwdRef; |
| } |
| } |
| } |
| |
| finish: |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Adjust surface parameter |
| //! \param [in] pRenderParams |
| //! Pointer to VPHAL render parameter |
| //! \param [in,out] pSrcSurface |
| //! Pointer to VPHAL surface |
| //! \param [in] pGtSystemInfo |
| //! Pointer to GT system information structure |
| //! \param [in] bHybridDecoderFlag |
| //! Hybrid Decoder or not |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalRenderer::AdjustSurfaceParam( |
| PVPHAL_RENDER_PARAMS pRenderParams, |
| PVPHAL_SURFACE pSrcSurface, |
| MEDIA_SYSTEM_INFO *pGtSystemInfo, |
| bool bHybridDecoderFlag) |
| { |
| MOS_STATUS eStatus = MOS_STATUS_SUCCESS; |
| |
| VPHAL_RENDER_CHK_NULL(pSrcSurface); |
| VPHAL_RENDER_CHK_NULL(pRenderParams); |
| VPHAL_RENDER_CHK_NULL(pGtSystemInfo); |
| |
| // Disable VP features for 4K (Sku flag or Hybrid) |
| if (pSrcSurface->rcSrc.bottom >= pSrcSurface->rcSrc.top + VPHAL_RNDR_4K_HEIGHT) |
| { |
| // VEBOX timing on KBL ULT might be about 2x ms when DN is on, and it seems to be |
| // in relation to the lag problem on WMP after scaling up & down the playback window. |
| // Disable DN for 4K to resolve this phenomenon. |
| if (bSkuDisableDNFor4K && |
| pSrcSurface->pDenoiseParams) |
| { |
| pSrcSurface->pDenoiseParams->bAutoDetect = false; |
| pSrcSurface->pDenoiseParams->bEnableChroma = false; |
| pSrcSurface->pDenoiseParams->bEnableLuma = false; |
| } |
| |
| // Disable features if needed |
| if (bSkuDisableVpFor4K || bHybridDecoderFlag) |
| { |
| // Denoise |
| if (pSrcSurface->pDenoiseParams) |
| { |
| pSrcSurface->pDenoiseParams->bAutoDetect = false; |
| pSrcSurface->pDenoiseParams->bEnableChroma = false; |
| pSrcSurface->pDenoiseParams->bEnableLuma = false; |
| } |
| |
| // Sharpness(IEF) |
| if (pSrcSurface->pIEFParams) |
| { |
| pSrcSurface->pIEFParams->bEnabled = false; |
| } |
| |
| // STE, TCC |
| if (pSrcSurface->pColorPipeParams) |
| { |
| pSrcSurface->pColorPipeParams->bEnableSTE = false; |
| pSrcSurface->pColorPipeParams->bEnableTCC = false; |
| } |
| } |
| } |
| |
| // IEF is only for Y luma component |
| if (IS_RGB_FORMAT(pSrcSurface->Format) && pSrcSurface->pIEFParams) |
| { |
| VPHAL_RENDER_NORMALMESSAGE("IEF is only for Y luma component, and IEF is always disabled for RGB input."); |
| pSrcSurface->pIEFParams->bEnabled = false; |
| pSrcSurface->pIEFParams->fIEFFactor = 0.0f; |
| } |
| |
| finish: |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Process render parameter |
| //! \param [in,out] pRenderParams |
| //! Pointer to VPHAL render parameter |
| //! \param [in,out] pRenderPassData |
| //! Pointer to the VPHAL render pass data |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalRenderer::ProcessRenderParameter( |
| PVPHAL_RENDER_PARAMS pRenderParams, |
| RenderpassData *pRenderPassData) |
| { |
| MOS_STATUS eStatus; |
| MEDIA_SYSTEM_INFO *pGtSystemInfo; |
| uint32_t uiIndex; |
| PVPHAL_SURFACE pSrcSurface; |
| PVPHAL_SURFACE pPrimarySurface; |
| PVPHAL_PROCAMP_PARAMS pProcampParams; |
| bool bSingleSliceMode; |
| bool bSliceReconfig; |
| bool bHybridDecoderFlag; |
| int32_t decoderFlag; |
| |
| #ifdef ANDROID |
| RECT PrimOrigDstRect; |
| bool bDstRectWANeeded = false; |
| #endif |
| |
| eStatus = MOS_STATUS_SUCCESS; |
| bHybridDecoderFlag = false; |
| bSliceReconfig = false; |
| pPrimarySurface = nullptr; |
| |
| // Get the hybrid decoder flag |
| VPHAL_RENDER_CHK_STATUS(m_pOsInterface->pfnGetHybridDecoderRunningFlag(m_pOsInterface, &decoderFlag)); |
| bHybridDecoderFlag = decoderFlag ? true : false; |
| |
| // Get the GT system information |
| pGtSystemInfo = m_pOsInterface->pfnGetGtSystemInfo(m_pOsInterface); |
| VPHAL_RENDER_CHK_NULL(pGtSystemInfo); |
| |
| pRender[VPHAL_RENDER_ID_COMPOSITE]->SetStatusReportParams(this, pRenderParams); |
| pRender[VPHAL_RENDER_ID_VEBOX+uiCurrentChannel]->SetStatusReportParams(this, pRenderParams); |
| |
| // Decide whether Hdr path should be chosen. |
| VPHAL_RENDER_CHK_STATUS(GetHdrPathNeededFlag(pRenderParams, pRenderPassData)); |
| if (pRenderPassData->bHdrNeeded) |
| { |
| VPHAL_RNDR_SET_STATUS_REPORT_PARAMS(pHdrState, this, pRenderParams); |
| } |
| |
| VPHAL_RNDR_SET_STATUS_REPORT_PARAMS(&Align16State, this, pRenderParams); |
| // Loop through the sources |
| for (uiIndex = 0; |
| uiIndex < VPHAL_MAX_SOURCES && uiIndex < pRenderParams->uSrcCount; |
| uiIndex++) |
| { |
| pSrcSurface = pRenderParams->pSrc[uiIndex]; |
| |
| if (pSrcSurface == nullptr) |
| { |
| continue; |
| } |
| |
| // We need to block invalid frame sizes of 0 or negative values from |
| // entering the VP render core since IVB hardware had problem of |
| // handling these cases. EU payload of the same values, U, V, |
| // deltaU, deltaV, are all 0s, and are the same for 16 thread entries, |
| // which will be discarded by the kernel. |
| if ((pSrcSurface->rcSrc.top >= pSrcSurface->rcSrc.bottom) || |
| (pSrcSurface->rcSrc.left >= pSrcSurface->rcSrc.right) || |
| (pSrcSurface->rcDst.top >= pSrcSurface->rcDst.bottom) || |
| (pSrcSurface->rcDst.left >= pSrcSurface->rcDst.right)) |
| { |
| eStatus = MOS_STATUS_INVALID_PARAMETER; |
| VPHAL_RENDER_ASSERTMESSAGE("Invalid Rectangle Values."); |
| goto finish; |
| } |
| |
| #ifdef ANDROID |
| // If the dst rect of primary layer is exactly covered by sublayers, say primary.left == sublayer.left, |
| // the primary layer should not be seen from the left side. But VpHal_RndrRectSurfaceAlignment() might adjust |
| // the primary layer dst rect for alignment. It looks like the primary layer is shifted left for one or two pixels, |
| // and user will see a thin line on the left side, which is a bad user experience. |
| // In such cases, just make the sublayer's dst rect still aligned with primary layer. |
| if (bDstRectWANeeded) |
| { |
| pSrcSurface->rcDst.left = (pSrcSurface->rcDst.left == PrimOrigDstRect.left ) ? pPrimarySurface->rcDst.left : pSrcSurface->rcDst.left; |
| pSrcSurface->rcDst.top = (pSrcSurface->rcDst.top == PrimOrigDstRect.top ) ? pPrimarySurface->rcDst.top : pSrcSurface->rcDst.top; |
| pSrcSurface->rcDst.right = (pSrcSurface->rcDst.right == PrimOrigDstRect.right ) ? pPrimarySurface->rcDst.right : pSrcSurface->rcDst.right; |
| pSrcSurface->rcDst.bottom = (pSrcSurface->rcDst.bottom == PrimOrigDstRect.bottom) ? pPrimarySurface->rcDst.bottom : pSrcSurface->rcDst.bottom; |
| } |
| #endif |
| |
| if (pSrcSurface->SurfType == SURF_IN_PRIMARY) |
| { |
| #ifdef ANDROID |
| bDstRectWANeeded = true; |
| PrimOrigDstRect = pSrcSurface->rcDst; |
| #endif |
| pRenderPassData->pPrimarySurface = pPrimarySurface = pSrcSurface; |
| pRenderPassData->uiPrimaryIndex = uiIndex; |
| |
| // align rectangle and source surface |
| VPHAL_RENDER_CHK_STATUS(VpHal_RndrRectSurfaceAlignment(pSrcSurface, pRenderParams->pTarget[0] ? pRenderParams->pTarget[0]->Format : pSrcSurface->Format)); |
| |
| // update max Src rect in both pRenderer and primary surface |
| VpHal_RenderInitMaxRect(this, pSrcSurface); |
| } |
| |
| // Add Procamp limitation before Render pass selected |
| // Brightness[-100.0,100.0], Contrast & Saturation[0.0,10.0] |
| pProcampParams = pSrcSurface->pProcampParams; |
| if (pProcampParams && pProcampParams->bEnabled) |
| { |
| pProcampParams->fBrightness = MOS_MIN(MOS_MAX(-100.0f, pProcampParams->fBrightness), 100.0f); |
| pProcampParams->fContrast = MOS_MIN(MOS_MAX( 0.0f, pProcampParams->fContrast), 10.0f); |
| pProcampParams->fSaturation = MOS_MIN(MOS_MAX( 0.0f, pProcampParams->fSaturation), 10.0f); |
| } |
| |
| AdjustSurfaceParam(pRenderParams, pSrcSurface, pGtSystemInfo, bHybridDecoderFlag); |
| } |
| |
| // Check if Slice Shutdown can be enabled |
| // Vebox performance is not impacted by slice shutdown |
| if (!(pPrimarySurface == nullptr || // Valid Layer |
| pRenderPassData->bHdrNeeded || // HDR Disabled |
| pRenderParams->Component == COMPONENT_VPreP)) // VpostP usage |
| { |
| bSliceReconfig = true; |
| } |
| |
| // Check if Slice Shutdown can be enabled |
| if ((uiSsdControl == VPHAL_SSD_ENABLE) || // Force Enable in User feature keys |
| (bSliceReconfig && // Default mode |
| uiSsdControl == VPHAL_SSD_DEFAULT)) |
| { |
| bSingleSliceMode = true; |
| } |
| else |
| { |
| bSingleSliceMode = false; |
| } |
| |
| pRender[VPHAL_RENDER_ID_COMPOSITE]->SetSingleSliceMode(bSingleSliceMode); |
| |
| finish: |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Render function for the pass |
| //! \details The render function coordinates the advanced renderers and basic |
| //! renders in one pass |
| //! \param [in,out] pRenderParams |
| //! Pointer to VPHAL render parameter |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalRenderer::RenderPass( |
| PVPHAL_RENDER_PARAMS pRenderParams) |
| { |
| MOS_STATUS eStatus; |
| uint32_t uiIndex_in; // Current source index |
| uint32_t uiIndex_out; // current target index |
| PVPHAL_VEBOX_EXEC_STATE pVeboxExecState; |
| RenderpassData RenderPassData; |
| |
| VPHAL_RENDER_ASSERT(m_pRenderHal); |
| |
| eStatus = MOS_STATUS_SUCCESS; |
| uiIndex_in = 0; |
| uiIndex_out = 0; |
| pVeboxExecState = &VeboxExecState[uiCurrentChannel]; |
| MOS_ZeroMemory(&RenderPassData, sizeof(RenderPassData)); |
| |
| RenderPassData.AllocateTempOutputSurfaces(); |
| RenderPassData.bCompNeeded = true; |
| |
| // Get surface info for all input source |
| VPHAL_RENDER_CHK_STATUS(GetSurfaceInfoForSrc(pRenderParams)); |
| |
| // Process render parameters |
| VPHAL_RENDER_CHK_STATUS(ProcessRenderParameter(pRenderParams, &RenderPassData)); |
| |
| // Loop through the sources |
| for (uiIndex_in = 0; uiIndex_in < pRenderParams->uSrcCount; uiIndex_in++) |
| { |
| if (pRenderParams->pSrc[uiIndex_in] == nullptr) |
| { |
| continue; |
| } |
| |
| //------------------------------------------ |
| VPHAL_RNDR_DUMP_SURF( |
| this, uiIndex_in, VPHAL_DBG_DUMP_TYPE_PRE_ALL, pRenderParams->pSrc[uiIndex_in]); |
| //------------------------------------------ |
| |
| RenderPassData.pOriginalSrcSurface = pRenderParams->pSrc[uiIndex_in]; |
| RenderPassData.pSrcSurface = pRenderParams->pSrc[uiIndex_in]; |
| RenderPassData.uiSrcIndex = uiIndex_in; |
| |
| if (VpHal_RndrIsFast1toNSupport(&Fast1toNState, pRenderParams, pRenderParams->pSrc[uiIndex_in])) |
| { |
| // new 1toN path for multi ouput with scaling only case. |
| VPHAL_RENDER_NORMALMESSAGE("Enter fast 1to N render."); |
| VPHAL_RENDER_CHK_STATUS(RenderFast1toNComposite(pRenderParams, &RenderPassData)); |
| } |
| else |
| { |
| // loop through the dst for every src input. |
| // backup the render params to execute as dst_count=1 to compatible with legacy logic. |
| VPHAL_RENDER_PARAMS StoreRenderParams = *pRenderParams; |
| pRenderParams->uDstCount = 1; |
| for (uiIndex_out = 0; uiIndex_out < StoreRenderParams.uDstCount; uiIndex_out++) |
| { |
| if (StoreRenderParams.pTarget[uiIndex_out] == nullptr) |
| { |
| continue; |
| } |
| // update the first target point |
| pRenderParams->pTarget[0] = StoreRenderParams.pTarget[uiIndex_out]; |
| pRenderParams->pTarget[0]->b16UsrPtr = StoreRenderParams.pTarget[uiIndex_out]->b16UsrPtr; |
| if (StoreRenderParams.uDstCount > 1) |
| { |
| // for multi output, support different scaling ratio but doesn't support cropping. |
| RenderPassData.pSrcSurface->rcDst.top = pRenderParams->pTarget[0]->rcSrc.top; |
| RenderPassData.pSrcSurface->rcDst.left = pRenderParams->pTarget[0]->rcSrc.left; |
| RenderPassData.pSrcSurface->rcDst.bottom = pRenderParams->pTarget[0]->rcSrc.bottom; |
| RenderPassData.pSrcSurface->rcDst.right = pRenderParams->pTarget[0]->rcSrc.right; |
| } |
| |
| RenderSingleStream(pRenderParams, &RenderPassData); |
| |
| if (!RenderPassData.bCompNeeded && |
| pRenderParams->pTarget[0] && |
| pRenderParams->pTarget[0]->bFastColorFill) |
| { |
| // with fast color fill enabled, we seperate target surface into two parts: |
| // (1) upper rectangle rendered by vebox |
| // (2) bottom rectangle with back ground color fill by composition |
| pRenderParams->uSrcCount = 0; // set to zero for color fill |
| pRenderParams->pTarget[0]->rcDst.top = pRenderParams->pSrc[0]->rcDst.bottom; |
| RenderPassData.bCompNeeded = true; |
| VPHAL_RENDER_ASSERTMESSAGE("Critical: enter fast color fill"); |
| } |
| if (RenderPassData.b2CSCNeeded) |
| { |
| // Second CSC in render, set input of render with output of vebox. |
| pRenderParams->pSrc[uiIndex_in] = RenderPassData.pOutSurface; |
| } |
| if (RenderPassData.bCompNeeded && |
| (uiIndex_in == pRenderParams->uSrcCount-1 || // compatible with N:1 case, only render at the last input. |
| pRenderParams->uSrcCount == 0)) // fast color fill |
| { |
| VPHAL_RENDER_CHK_STATUS(RenderComposite(pRenderParams, &RenderPassData)); |
| } |
| else if (VpHal_RndrIsHdrPathNeeded(this, pRenderParams, &RenderPassData) && |
| (pHdrState && |
| !pHdrState->bBypassHdrKernelPath)) |
| { |
| VPHAL_RENDER_CHK_STATUS(VpHal_RndrRenderHDR(this, pRenderParams, &RenderPassData)); |
| } |
| } |
| // restore render pointer and count. |
| pRenderParams->pTarget[0] = StoreRenderParams.pTarget[0]; |
| pRenderParams->pTarget[0]->b16UsrPtr = StoreRenderParams.pTarget[0]->b16UsrPtr; |
| pRenderParams->uDstCount = StoreRenderParams.uDstCount; |
| } |
| } |
| |
| // Report Render modes |
| UpdateReport(pRenderParams, &RenderPassData); |
| |
| //------------------------------------------ |
| VPHAL_RNDR_DUMP_SURF_PTR_ARRAY( |
| this, pRenderParams->pTarget, VPHAL_MAX_TARGETS, |
| pRenderParams->uDstCount, VPHAL_DBG_DUMP_TYPE_POST_ALL); |
| //------------------------------------------ |
| |
| if (RenderPassData.pPrimarySurface) |
| { |
| VpHal_SaveRestorePrimaryFwdRefs( |
| this, |
| pRenderParams->pSrc[RenderPassData.uiPrimaryIndex] = RenderPassData.pPrimarySurface, |
| false /*restore*/); |
| } |
| |
| finish: |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Render single stream |
| //! \param [in] pRenderParams |
| //! Pointer to VPHAL render parameter |
| //! \param [in,out] pRenderPassData |
| //! Pointer to the VPHAL render pass data |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalRenderer::RenderSingleStream( |
| PVPHAL_RENDER_PARAMS pRenderParams, |
| RenderpassData *pRenderPassData) |
| { |
| MOS_STATUS eStatus; |
| |
| eStatus = MOS_STATUS_SUCCESS; |
| |
| if (pRenderPassData->pSrcSurface->SurfType == SURF_IN_PRIMARY) |
| { |
| |
| VpHal_SaveRestorePrimaryFwdRefs( |
| this, |
| pRenderPassData->pPrimarySurface, |
| true /*save*/); |
| |
| //-- DNDI/IECP----------------------------------------------------- |
| VPHAL_RNDR_DUMP_SURF( |
| this, pRenderPassData->uiSrcIndex, VPHAL_DBG_DUMP_TYPE_PRE_DNDI, pRenderPassData->pSrcSurface); |
| |
| VPHAL_RENDER_CHK_STATUS(VpHal_RndrRenderVebox( |
| this, |
| pRenderParams, |
| pRenderPassData)); |
| |
| if (pRenderPassData->bSFCScalingOnly) |
| { |
| // set the output surface which from the Vebox+SFC as input surface, and let comp to do composite. |
| VPHAL_RENDER_CHK_NULL(pRenderPassData->pOutSurface); |
| pRenderPassData->bCompNeeded = true; |
| pRenderPassData->bSFCScalingOnly = false; |
| pRenderPassData->pSrcSurface = pRenderPassData->pOutSurface; |
| pRenderPassData->pSrcSurface->SurfType = SURF_IN_PRIMARY; |
| } |
| |
| if (pRenderPassData->bOutputGenerated) |
| { |
| pRenderPassData->pSrcSurface = pRenderPassData->pOutSurface; |
| pRenderPassData->MoveToNextTempOutputSurface(); |
| } |
| else |
| { |
| // Do not perform any more operations if Comp is not needed |
| if (pRenderPassData->bCompNeeded == false) |
| { |
| VPHAL_RENDER_NORMALMESSAGE("VEBOX/SFC modified Render Target, skipping further processing."); |
| goto finish; |
| } |
| } |
| |
| VPHAL_RNDR_DUMP_SURF( |
| this, pRenderPassData->uiSrcIndex, VPHAL_DBG_DUMP_TYPE_POST_DNDI, pRenderPassData->pSrcSurface); |
| |
| // We'll continue even if Advanced render fails |
| if ((eStatus == MOS_STATUS_SUCCESS) && (pRenderPassData->bCompNeeded || pRenderPassData->bHdrNeeded)) |
| { |
| pRenderParams->pSrc[pRenderPassData->uiSrcIndex] = pRenderPassData->pSrcSurface; |
| } |
| |
| if (pRenderPassData->bHdrNeeded && (pHdrState && !pHdrState->bBypassHdrKernelPath)) |
| { |
| pRenderPassData->bCompNeeded = false; |
| } |
| } |
| |
| finish: |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Compose input streams as fast 1toN |
| //! \details Use composite render to multi output streams |
| //! \param [in] pRenderParams |
| //! Pointer to VPHAL render parameter |
| //! \param [in,out] pRenderPassData |
| //! Pointer to the VPHAL render pass data |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalRenderer::RenderFast1toNComposite( |
| PVPHAL_RENDER_PARAMS pRenderParams, |
| RenderpassData *pRenderPassData) |
| { |
| MOS_STATUS eStatus; |
| eStatus = MOS_STATUS_SUCCESS; |
| if (pRenderPassData->pSrcSurface->SurfType == SURF_IN_PRIMARY) |
| { |
| VpHal_SaveRestorePrimaryFwdRefs( |
| this, |
| pRenderPassData->pPrimarySurface, |
| true /*save*/); |
| pRenderParams->pSrc[pRenderPassData->uiSrcIndex] = pRenderPassData->pSrcSurface; |
| eStatus = Fast1toNState.pfnRender(&Fast1toNState, pRenderParams); |
| } |
| |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Compose input streams |
| //! \details Use composite render to compose input streams |
| //! \param [in] pRenderParams |
| //! Pointer to VPHAL render parameter |
| //! \param [in,out] pRenderPassData |
| //! Pointer to the VPHAL render pass data |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalRenderer::RenderComposite( |
| PVPHAL_RENDER_PARAMS pRenderParams, |
| RenderpassData *pRenderPassData) |
| { |
| MOS_STATUS eStatus; |
| |
| eStatus = MOS_STATUS_SUCCESS; |
| |
| //------------------------------------------ |
| VPHAL_RNDR_DUMP_SURF_PTR_ARRAY( |
| this, pRenderParams->pSrc, VPHAL_MAX_SOURCES, |
| pRenderParams->uSrcCount, VPHAL_DBG_DUMP_TYPE_PRE_COMP); |
| //------------------------------------------ |
| |
| if (pRenderPassData->pSrcSurface && |
| (pRenderPassData->pSrcSurface->b16UsrPtr || |
| pRenderParams->pTarget[0]->b16UsrPtr) && |
| (VpHal_RndrIs16Align(&Align16State, pRenderParams))) |
| { |
| // process 16aligned usrptr mode. |
| VPHAL_RENDER_CHK_STATUS(Align16State.pfnRender(&Align16State, pRenderParams)); |
| } |
| else |
| { |
| // fallback to legacy path |
| VPHAL_RENDER_CHK_STATUS(pRender[VPHAL_RENDER_ID_COMPOSITE]->Render(pRenderParams, nullptr)); |
| } |
| |
| //------------------------------------------ |
| VPHAL_RNDR_DUMP_SURF_PTR_ARRAY( |
| this, pRenderParams->pSrc, VPHAL_MAX_SOURCES, |
| pRenderParams->uSrcCount, VPHAL_DBG_DUMP_TYPE_POST_COMP); |
| |
| VPHAL_RNDR_DUMP_SURF_PTR_ARRAY( |
| this, pRenderParams->pTarget, VPHAL_MAX_TARGETS, |
| pRenderParams->uDstCount, VPHAL_DBG_DUMP_TYPE_POST_COMP); |
| //------------------------------------------ |
| |
| finish: |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Update report data |
| //! \details Update report data from each feature render |
| //! \param [in] pRenderParams |
| //! Pointer to VPHAL render parameter |
| //! \param [in,out] pRenderPassData |
| //! Pointer to the VPHAL render pass data |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| void VphalRenderer::UpdateReport( |
| PVPHAL_RENDER_PARAMS pRenderParams, |
| RenderpassData *pRenderPassData) |
| { |
| VPHAL_GET_SURFACE_INFO Info; |
| |
| pRender[VPHAL_RENDER_ID_COMPOSITE]->CopyReporting(m_reporting); |
| |
| if (pRenderPassData->pPrimarySurface && pRenderPassData->pPrimarySurface->bCompressible) |
| { |
| m_reporting->PrimaryCompressible = true; |
| m_reporting->PrimaryCompressMode = (uint8_t)(pRenderPassData->pPrimarySurface->CompressionMode); |
| } |
| |
| if (pRenderParams->pTarget[0]->bCompressible) |
| { |
| MOS_ZeroMemory(&Info, sizeof(VPHAL_GET_SURFACE_INFO)); |
| |
| VpHal_GetSurfaceInfo(m_pOsInterface, &Info, pRenderParams->pTarget[0]); |
| m_reporting->RTCompressible = true; |
| m_reporting->RTCompressMode = (uint8_t)(pRenderParams->pTarget[0]->CompressionMode); |
| } |
| } |
| |
| //! |
| //! \brief Check if Vphal renderer support some formats |
| //! \param [in] pcRenderParams |
| //! Const pointer to VPHAL render parameter |
| //! \return bool |
| //! Return true if successful, false failed |
| //! |
| bool VphalRenderer::IsFormatSupported( |
| PCVPHAL_RENDER_PARAMS pcRenderParams) |
| { |
| bool bFormatSupported = true; |
| |
| VPHAL_RENDER_ASSERT(pcRenderParams); |
| |
| // Protection mechanism |
| // P010 output support from SKL+ |
| if (m_pSkuTable) |
| { |
| if (pcRenderParams->pTarget[0]) |
| { |
| switch (pcRenderParams->pTarget[0]->Format) |
| { |
| case Format_P010: |
| bFormatSupported = MEDIA_IS_SKU(m_pSkuTable, FtrVpP010Output) ? true : false; |
| break; |
| case Format_P016: |
| bFormatSupported = MEDIA_IS_SKU(m_pSkuTable, FtrVpP010Output) ? true : false; |
| break; |
| case Format_Y210: |
| bFormatSupported = MEDIA_IS_SKU(m_pSkuTable, FtrVp10BitSupport) ? true : false; |
| break; |
| case Format_Y410: |
| bFormatSupported = MEDIA_IS_SKU(m_pSkuTable, FtrVp10BitSupport) ? true : false; |
| break; |
| case Format_Y216: |
| bFormatSupported = MEDIA_IS_SKU(m_pSkuTable, FtrVp16BitSupport) ? true : false; |
| break; |
| case Format_Y416: |
| bFormatSupported = MEDIA_IS_SKU(m_pSkuTable, FtrVp16BitSupport) ? true : false; |
| break; |
| default: |
| break; |
| } |
| } |
| } |
| |
| return bFormatSupported; |
| } |
| |
| //! |
| //! \brief Main render function |
| //! \details The top level renderer function, which may contain multiple |
| //! passes of rendering |
| //! \param [in] pcRenderParams |
| //! Const pointer to VPHAL render parameter |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalRenderer::Render( |
| PCVPHAL_RENDER_PARAMS pcRenderParams) |
| { |
| MOS_STATUS eStatus; |
| PMOS_INTERFACE pOsInterface; |
| PRENDERHAL_INTERFACE pRenderHal; |
| VPHAL_RENDER_PARAMS RenderParams; // Make a copy of render params |
| PVPHAL_SURFACE pSrcLeft[VPHAL_MAX_SOURCES]; // Array of sources referring to left view stereo content |
| PVPHAL_SURFACE pSrcRight[VPHAL_MAX_SOURCES]; // Array of sources referring to right view stereo content |
| uint32_t uiRenderPasses; // Number of rendering passes in this one call to VpHal_RndrRender() |
| uint32_t uiCurrentRenderPass; // Current render pass |
| uint32_t uiDst; |
| VPHAL_GET_SURFACE_INFO Info; |
| |
| //-------------------------------------------- |
| VPHAL_RENDER_ASSERT(pcRenderParams); |
| VPHAL_RENDER_ASSERT(m_pOsInterface); |
| VPHAL_RENDER_ASSERT(m_pRenderHal); |
| VPHAL_RENDER_ASSERT(pKernelDllState); |
| VPHAL_RENDER_ASSERT(pRender[VPHAL_RENDER_ID_COMPOSITE]); |
| //-------------------------------------------- |
| |
| eStatus = MOS_STATUS_SUCCESS; |
| pOsInterface = m_pOsInterface; |
| pRenderHal = m_pRenderHal; |
| |
| // Validate render target |
| if (pcRenderParams->pTarget[0] == nullptr || |
| Mos_ResourceIsNull(&(pcRenderParams->pTarget[0]->OsResource))) |
| { |
| VPHAL_RENDER_ASSERTMESSAGE("Invalid Render Target."); |
| eStatus = MOS_STATUS_UNKNOWN; |
| goto finish; |
| } |
| |
| // Protection mechanism, Only SKL+ support P010 output. |
| if (IsFormatSupported(pcRenderParams) == false) |
| { |
| VPHAL_RENDER_ASSERTMESSAGE("Invalid Render Target Output Format."); |
| eStatus = MOS_STATUS_UNKNOWN; |
| goto finish; |
| } |
| |
| VPHAL_DBG_STATE_DUMP_SET_CURRENT_FRAME_COUNT(uiFrameCounter); |
| |
| // Validate max number sources |
| if (pcRenderParams->uSrcCount > VPHAL_MAX_SOURCES) |
| { |
| VPHAL_RENDER_ASSERTMESSAGE("Invalid number of samples."); |
| eStatus = MOS_STATUS_UNKNOWN; |
| goto finish; |
| } |
| |
| // Validate max number targets |
| if (pcRenderParams->uDstCount > VPHAL_MAX_TARGETS) |
| { |
| VPHAL_RENDER_ASSERTMESSAGE("Invalid number of targets."); |
| eStatus = MOS_STATUS_UNKNOWN; |
| goto finish; |
| } |
| |
| // Copy the Render Params structure (so we can update it) |
| RenderParams = *pcRenderParams; |
| |
| VPHAL_DBG_PARAMETERS_DUMPPER_DUMP_XML(&RenderParams); |
| |
| // Get resource information for render target |
| MOS_ZeroMemory(&Info, sizeof(VPHAL_GET_SURFACE_INFO)); |
| |
| for (uiDst = 0; uiDst < RenderParams.uDstCount; uiDst++) |
| { |
| VPHAL_RENDER_CHK_STATUS(VpHal_GetSurfaceInfo( |
| m_pOsInterface, |
| &Info, |
| RenderParams.pTarget[uiDst])); |
| } |
| |
| // Set the component info |
| m_pOsInterface->Component = pcRenderParams->Component; |
| |
| // Init component(DDI entry point) info for perf measurement |
| m_pOsInterface->pfnSetPerfTag(m_pOsInterface, VPHAL_NONE); |
| |
| // Increment frame ID for performance measurement |
| m_pOsInterface->pfnIncPerfFrameID(m_pOsInterface); |
| |
| // Enable Turbo mode if sku present and DDI requests it |
| if (m_pSkuTable && MEDIA_IS_SKU(m_pSkuTable, FtrMediaTurboMode)) |
| { |
| m_pRenderHal->bTurboMode = RenderParams.bTurboMode; |
| } |
| |
| // Reset feature reporting |
| m_reporting->InitReportValue(); |
| |
| MOS_ZeroMemory(pSrcLeft, sizeof(PVPHAL_SURFACE) * VPHAL_MAX_SOURCES); |
| MOS_ZeroMemory(pSrcRight, sizeof(PVPHAL_SURFACE) * VPHAL_MAX_SOURCES); |
| |
| VPHAL_RENDER_CHK_STATUS(PrepareSources( |
| &RenderParams, |
| pSrcLeft, |
| pSrcRight, |
| &uiRenderPasses)); |
| |
| //Update GpuContext |
| if (MEDIA_IS_SKU(m_pSkuTable, FtrCCSNode)) |
| { |
| MOS_GPU_CONTEXT currentGpuContext = m_pOsInterface->pfnGetGpuContext(m_pOsInterface); |
| UpdateRenderGpuContext(currentGpuContext); |
| } |
| // align rectangle and source surface |
| for (uiDst = 0; uiDst < RenderParams.uDstCount; uiDst++) |
| { |
| VPHAL_RENDER_CHK_STATUS(VpHal_RndrRectSurfaceAlignment(RenderParams.pTarget[uiDst], RenderParams.pTarget[uiDst]->Format)); |
| } |
| |
| for (uiCurrentRenderPass = 0; |
| uiCurrentRenderPass < uiRenderPasses; |
| uiCurrentRenderPass++) |
| { |
| // Assign source surfaces for current rendering pass |
| MOS_SecureMemcpy( |
| RenderParams.pSrc, |
| sizeof(PVPHAL_SURFACE) * VPHAL_MAX_SOURCES, |
| (uiCurrentRenderPass == 0) ? pSrcLeft : pSrcRight, |
| sizeof(PVPHAL_SURFACE) * VPHAL_MAX_SOURCES); |
| |
| MOS_ZeroMemory(&Info, sizeof(VPHAL_GET_SURFACE_INFO)); |
| |
| for (uiDst = 0; uiDst < RenderParams.uDstCount; uiDst++) |
| { |
| Info.S3dChannel = RenderParams.pTarget[uiDst]->Channel; |
| Info.ArraySlice = uiCurrentRenderPass; |
| |
| VPHAL_RENDER_CHK_STATUS(VpHal_GetSurfaceInfo( |
| m_pOsInterface, |
| &Info, |
| RenderParams.pTarget[uiDst])); |
| } |
| |
| // Update channel. 0 = mono or stereo left, 1 = stereo right |
| uiCurrentChannel = uiCurrentRenderPass; |
| |
| VPHAL_RENDER_CHK_STATUS(RenderPass(&RenderParams)); |
| } |
| |
| finish: |
| uiFrameCounter++; |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Update Render Gpu Context |
| //! \details Update Render Gpu Context |
| //! \param [in] renderGpuContext |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalRenderer::UpdateRenderGpuContext(MOS_GPU_CONTEXT currentGpuContext) |
| { |
| MOS_STATUS eStatus = MOS_STATUS_SUCCESS; |
| MOS_GPU_CONTEXT renderGpuContext; |
| MOS_GPU_NODE renderGpuNode; |
| MOS_GPUCTX_CREATOPTIONS createOption; |
| PVPHAL_VEBOX_STATE pVeboxState = nullptr; |
| int i = 0; |
| |
| if (MEDIA_IS_SKU(m_pSkuTable, FtrRAMode) && |
| m_pOsInterface->osCpInterface->IsCpEnabled() && |
| (m_pOsInterface->osCpInterface->IsHMEnabled() || m_pOsInterface->osCpInterface->IsSMEnabled())) |
| { |
| if (currentGpuContext == MOS_GPU_CONTEXT_COMPUTE || |
| currentGpuContext == MOS_GPU_CONTEXT_COMPUTE_RA) // CCS |
| { |
| renderGpuContext = MOS_GPU_CONTEXT_COMPUTE_RA; |
| renderGpuNode = MOS_GPU_NODE_COMPUTE; |
| } |
| else // RCS |
| { |
| renderGpuContext = MOS_GPU_CONTEXT_RENDER_RA; |
| renderGpuNode = MOS_GPU_NODE_3D; |
| } |
| createOption.RAMode = 1; |
| } |
| else |
| { |
| if (currentGpuContext == MOS_GPU_CONTEXT_COMPUTE || |
| currentGpuContext == MOS_GPU_CONTEXT_COMPUTE_RA) // CCS |
| { |
| renderGpuContext = MOS_GPU_CONTEXT_COMPUTE; |
| renderGpuNode = MOS_GPU_NODE_COMPUTE; |
| } |
| else // RCS |
| { |
| renderGpuContext = MOS_GPU_CONTEXT_RENDER; |
| renderGpuNode = MOS_GPU_NODE_3D; |
| } |
| createOption.RAMode = 0; |
| } |
| |
| // no gpucontext will be created if the gpu context has been created before. |
| VPHAL_PUBLIC_CHK_STATUS(m_pOsInterface->pfnCreateGpuContext( |
| m_pOsInterface, |
| renderGpuContext, |
| renderGpuNode, |
| &createOption)); |
| |
| VPHAL_PUBLIC_CHK_STATUS(m_pOsInterface->pfnSetGpuContext( |
| m_pOsInterface, |
| renderGpuContext)); |
| |
| // Register Render GPU context with the event |
| VPHAL_PUBLIC_CHK_STATUS(m_pOsInterface->pfnRegisterBBCompleteNotifyEvent( |
| m_pOsInterface, |
| renderGpuContext)); |
| |
| //update sub render status one by one |
| for (i = 0; i < VPHAL_RENDER_ID_COUNT - 1; i++) |
| { // VPHAL_RENDER_ID_COMPOSITE is not inherited from vphal_vebox_state, skip it. |
| pVeboxState = (PVPHAL_VEBOX_STATE)(pRender[i]); |
| if (pVeboxState != nullptr) |
| { |
| pVeboxState->UpdateRenderGpuContext(renderGpuContext); |
| } |
| } |
| finish: |
| VPHAL_RENDER_NORMALMESSAGE("gpucontext switch from %d to %d", currentGpuContext, renderGpuContext); |
| return eStatus; |
| } |
| |
| MOS_STATUS VphalRenderer::SetRenderGpuContext(VPHAL_RENDER_PARAMS& RenderParams) |
| { |
| MOS_GPU_CONTEXT currentGpuContext = m_renderGpuContext; |
| |
| if (currentGpuContext != MOS_GPU_CONTEXT_RENDER) |
| { |
| bool bLumaKeyEnabled = false; |
| for (uint32_t uiSources = 0; uiSources < RenderParams.uSrcCount; uiSources++) |
| { |
| VPHAL_SURFACE* pSrc = (VPHAL_SURFACE*)RenderParams.pSrc[uiSources]; |
| bLumaKeyEnabled = (pSrc && pSrc->pLumaKeyParams) ? true : false; |
| if (bLumaKeyEnabled) |
| { |
| break; |
| } |
| } |
| if (bLumaKeyEnabled) |
| { |
| currentGpuContext = MOS_GPU_CONTEXT_RENDER; |
| } |
| } |
| |
| UpdateRenderGpuContext(currentGpuContext); |
| |
| return MOS_STATUS_SUCCESS; |
| } |
| |
| //! |
| //! \brief Release intermediate surfaces |
| //! \details Release intermediate surfaces created for main render function |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalRenderer::FreeIntermediateSurfaces() |
| { |
| // Free IntermediateSurface |
| if (m_pOsInterface) |
| { |
| m_pOsInterface->pfnFreeResource(m_pOsInterface, &IntermediateSurface.OsResource); |
| } |
| |
| MOS_SafeFreeMemory(IntermediateSurface.pBlendingParams); |
| MOS_SafeFreeMemory(IntermediateSurface.pIEFParams); |
| MOS_SafeFreeMemory(IntermediateSurface.pHDRParams); |
| |
| return MOS_STATUS_SUCCESS; |
| } |
| |
| //! |
| //! \brief Initialize the VPHAL renderer |
| //! \details Initialize all the renderers supported including VEBOX, Composite. |
| //! \param [in] pSettings |
| //! Const pointer to VPHAL settings |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalRenderer::Initialize( |
| const VphalSettings *pSettings, |
| bool isApoEnabled) |
| { |
| void* pKernelBin; |
| void* pFcPatchBin; |
| MOS_STATUS eStatus; |
| PMOS_INTERFACE pOsInterface; |
| PRENDERHAL_INTERFACE pRenderHal; |
| int32_t iResult; |
| MHW_KERNEL_PARAM MhwKernelParam; |
| Kdll_KernelCache *pKernelCache; |
| Kdll_CacheEntry *pCacheEntryTable; |
| |
| pKernelBin = nullptr; |
| pFcPatchBin = nullptr; |
| eStatus = MOS_STATUS_UNKNOWN; |
| pOsInterface = m_pOsInterface; |
| pRenderHal = m_pRenderHal; |
| iResult = 0; |
| pKernelBin = nullptr; |
| pFcPatchBin = nullptr; |
| |
| MOS_ZeroMemory(&MhwKernelParam, sizeof(MHW_KERNEL_PARAM)); |
| |
| //--------------------------------------- |
| VPHAL_RENDER_CHK_NULL(pSettings); |
| VPHAL_RENDER_CHK_NULL(m_pOsInterface); |
| VPHAL_RENDER_CHK_NULL(m_pRenderHal); |
| //--------------------------------------- |
| m_isApoEnabled = isApoEnabled; |
| m_renderGpuContext = m_pOsInterface->pfnGetGpuContext(m_pOsInterface); |
| |
| Align16State.pPerfData = &PerfData; |
| Fast1toNState.pPerfData = &PerfData; |
| // Current KDLL expects a writable memory for kernel binary. For that reason, |
| // we need to copy the memory to a new location so that KDLL can overwrite. |
| // !!! WARNING !!! |
| // We MUST NOT create a writable global memory since it can cause issues |
| // in multi-device cases (multiple threads operating on the memory) |
| // NOTE: KDLL will release the allocated memory. |
| pKernelBin = MOS_AllocMemory(dwKernelBinSize); |
| VPHAL_RENDER_CHK_NULL(pKernelBin); |
| MOS_SecureMemcpy(pKernelBin, |
| dwKernelBinSize, |
| pcKernelBin, |
| dwKernelBinSize); |
| |
| if ((pcFcPatchBin != nullptr) && (dwFcPatchBinSize != 0)) |
| { |
| pFcPatchBin = MOS_AllocMemory(dwFcPatchBinSize); |
| VPHAL_RENDER_CHK_NULL(pFcPatchBin); |
| MOS_SecureMemcpy(pFcPatchBin, |
| dwFcPatchBinSize, |
| pcFcPatchBin, |
| dwFcPatchBinSize); |
| } |
| |
| // Allocate KDLL state (Kernel Dynamic Linking) |
| pKernelDllState = KernelDll_AllocateStates( |
| pKernelBin, |
| dwKernelBinSize, |
| pFcPatchBin, |
| dwFcPatchBinSize, |
| pKernelDllRules, |
| m_modifyKdllFunctionPointers); |
| if (!pKernelDllState) |
| { |
| VPHAL_RENDER_ASSERTMESSAGE("Failed to allocate KDLL state."); |
| goto finish; |
| } |
| |
| // Set up SIP debug kernel if enabled |
| if (m_pRenderHal->bIsaAsmDebugEnable) |
| { |
| pKernelCache = &pKernelDllState->ComponentKernelCache; |
| pCacheEntryTable = pKernelCache->pCacheEntries; |
| VPHAL_RENDER_CHK_NULL(pCacheEntryTable); |
| |
| MOS_ZeroMemory(&MhwKernelParam, sizeof(MhwKernelParam)); |
| MhwKernelParam.pBinary = pCacheEntryTable[IDR_VP_SIP_Debug].pBinary; |
| MhwKernelParam.iSize = pCacheEntryTable[IDR_VP_SIP_Debug].iSize; |
| iResult = m_pRenderHal->pfnLoadDebugKernel( |
| m_pRenderHal, |
| &MhwKernelParam); |
| |
| if (iResult != 0) |
| { |
| m_pRenderHal->bIsaAsmDebugEnable = false; |
| } |
| } |
| |
| VeboxExecState[0].Mode = VEBOX_EXEC_MODE_0; |
| VeboxExecState[0].bDIOutputPair01 = true; |
| VeboxExecState[0].bSpeculativeCopy = false; |
| VeboxExecState[0].bEnable = (pSettings->veboxParallelExecution == VEBOX_EXECUTION_OVERRIDE_ENABLE); |
| VeboxExecState[1] = VeboxExecState[0]; |
| |
| // Initialize VEBOX renderer |
| VPHAL_RENDER_CHK_STATUS(pRender[VPHAL_RENDER_ID_VEBOX]->Initialize( |
| pSettings, |
| pKernelDllState)); |
| |
| VPHAL_RENDER_CHK_STATUS(pRender[VPHAL_RENDER_ID_VEBOX2]->Initialize( |
| pSettings, |
| pKernelDllState)); |
| |
| // Initialize Compositing renderer |
| VPHAL_RENDER_CHK_STATUS(pRender[VPHAL_RENDER_ID_COMPOSITE]->Initialize( |
| pSettings, |
| pKernelDllState)); |
| |
| // Initialize 16 Alignment Interface and renderer |
| VpHal_16AlignInitInterface(&Align16State, m_pRenderHal); |
| VPHAL_RENDER_CHK_STATUS(Align16State.pfnInitialize( |
| &Align16State, |
| pSettings, |
| pKernelDllState)) |
| |
| // Initialize fast 1to N Interface and render |
| VpHal_Fast1toNInitInterface(&Fast1toNState, m_pRenderHal); |
| VPHAL_RENDER_CHK_STATUS(Fast1toNState.pfnInitialize( |
| &Fast1toNState, |
| pSettings, |
| pKernelDllState)) |
| |
| eStatus = AllocateDebugDumper(); |
| if (eStatus != MOS_STATUS_SUCCESS) |
| { |
| VPHAL_RENDER_ASSERTMESSAGE("Debug dumper allocate failed!"); |
| goto finish; |
| } |
| |
| if (MEDIA_IS_SKU(m_pSkuTable, FtrVpDisableFor4K)) |
| { |
| bSkuDisableVpFor4K = true; |
| } |
| else |
| { |
| bSkuDisableVpFor4K = false; |
| } |
| |
| // Initialize Hdr renderer |
| if (MEDIA_IS_SKU(m_pSkuTable, FtrHDR) && pHdrState) |
| { |
| VPHAL_RENDER_CHK_STATUS(pHdrState->pfnInitialize( |
| pHdrState, |
| pSettings, |
| pKernelDllState)); |
| } |
| |
| eStatus = MOS_STATUS_SUCCESS; |
| |
| finish: |
| if (eStatus != MOS_STATUS_SUCCESS) |
| { |
| if (pKernelBin) |
| { |
| MOS_SafeFreeMemory(pKernelBin); |
| if (pKernelDllState && pKernelDllState->ComponentKernelCache.pCache == pKernelBin) |
| { |
| pKernelDllState->ComponentKernelCache.pCache = nullptr; |
| } |
| pKernelBin = nullptr; |
| } |
| |
| if (pFcPatchBin) |
| { |
| MOS_SafeFreeMemory(pFcPatchBin); |
| if (pKernelDllState && pKernelDllState->CmFcPatchCache.pCache == pFcPatchBin) |
| { |
| pKernelDllState->CmFcPatchCache.pCache = nullptr; |
| } |
| pFcPatchBin = nullptr; |
| } |
| } |
| return eStatus; |
| } |
| |
| //! |
| //! \brief VPHAL renderer destructor |
| //! \details Destory the resources allocated for the renderers |
| //! including VEBOX and Composite. |
| //! |
| VphalRenderer::~VphalRenderer() |
| { |
| VPHAL_RENDER_CHK_NULL_NO_STATUS(m_pOsInterface); |
| |
| FreeIntermediateSurfaces(); |
| |
| MOS_Delete(m_reporting); |
| |
| for (int32_t i = 0; i < VPHAL_RENDER_ID_COUNT; i++) |
| { |
| if (pRender[i]) |
| { |
| pRender[i]->Destroy(); |
| MOS_Delete(pRender[i]); |
| pRender[i] = nullptr; |
| } |
| } |
| |
| // Destroy Kernel DLL objects (cache, hash table, states) |
| if (pKernelDllState) |
| { |
| KernelDll_ReleaseStates(pKernelDllState); |
| } |
| |
| // Destroy resources allocated for 16 Alignment |
| if (Align16State.pfnDestroy) |
| { |
| Align16State.pfnDestroy(&Align16State); |
| } |
| |
| // Destory resources allocated for fast1toN |
| if (Fast1toNState.pfnDestroy) |
| { |
| Fast1toNState.pfnDestroy(&Fast1toNState); |
| } |
| |
| // Destroy resources allocated for Hdr |
| if (MEDIA_IS_SKU(m_pSkuTable, FtrHDR) && pHdrState && pHdrState->pfnDestroy) |
| { |
| pHdrState->pfnDestroy(pHdrState); |
| MOS_Delete(pHdrState); |
| } |
| |
| // Destroy surface dumper |
| VPHAL_DBG_SURF_DUMP_DESTORY(m_surfaceDumper); |
| |
| // Destroy state dumper |
| VPHAL_DBG_STATE_DUMPPER_DESTORY(m_pRenderHal->pStateDumper); |
| |
| // Destroy vphal parameter dump |
| VPHAL_DBG_PARAMETERS_DUMPPER_DESTORY(m_parameterDumper); |
| |
| finish: |
| return; |
| } |
| |
| //! |
| //! \brief Get the aligned the surface height and width unit |
| //! \details Accoring to the format of the surface, get the aligned unit for the surface |
| //! width and height |
| //! \param [in,out] pwWidthAlignUnit |
| //! Pointer to the surface width alignment unit |
| //! \param [in,out] pwHeightAlignUnit |
| //! Pointer to the surface height alignment unit |
| //! \param [in] format |
| //! The format of the surface |
| //! \return void |
| //! |
| void VpHal_RndrGetAlignUnit( |
| uint16_t* pwWidthAlignUnit, |
| uint16_t* pwHeightAlignUnit, |
| MOS_FORMAT format) |
| { |
| switch (format) |
| { |
| case Format_YV12: |
| case Format_I420: |
| case Format_IYUV: |
| case Format_IMC1: |
| case Format_IMC2: |
| case Format_IMC3: |
| case Format_IMC4: |
| case Format_NV12: |
| case Format_P010: |
| case Format_P016: |
| *pwWidthAlignUnit = 2; |
| *pwHeightAlignUnit = 2; |
| break; |
| |
| case Format_YVU9: |
| *pwWidthAlignUnit = 4; |
| *pwHeightAlignUnit = 4; |
| break; |
| |
| case Format_YUY2: |
| case Format_UYVY: |
| case Format_YUYV: |
| case Format_YVYU: |
| case Format_VYUY: |
| case Format_P208: |
| case Format_Y210: |
| case Format_Y216: |
| *pwWidthAlignUnit = 2; |
| *pwHeightAlignUnit = 1; |
| break; |
| |
| case Format_NV11: |
| *pwWidthAlignUnit = 4; |
| *pwHeightAlignUnit = 1; |
| break; |
| |
| default: |
| *pwWidthAlignUnit = 1; |
| *pwHeightAlignUnit = 1; |
| break; |
| } |
| } |
| |
| //! |
| //! \brief Set packed YUV component offsets |
| //! \details Accoring to the format of the surface, set packed YUV component offsets |
| //! \param [in] format |
| //! The format of the surface |
| //! \param [in,out] pOffsetY |
| //! The offset of Y |
| //! \param [in,out] pOffsetU |
| //! The offset of U |
| //! \param [in,out] pOffsetV |
| //! The offset of V |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VpHal_RndrSetYUVComponents( |
| MOS_FORMAT format, |
| uint8_t* pOffsetY, |
| uint8_t* pOffsetU, |
| uint8_t* pOffsetV) |
| { |
| MOS_STATUS eStatus = MOS_STATUS_SUCCESS; |
| |
| switch (format) |
| { |
| case Format_PA: |
| case Format_YUY2: |
| case Format_YUYV: |
| *pOffsetY = 0; |
| *pOffsetU = 1; |
| *pOffsetV = 3; |
| break; |
| |
| case Format_UYVY: |
| *pOffsetY = 1; |
| *pOffsetU = 0; |
| *pOffsetV = 2; |
| break; |
| |
| case Format_YVYU: |
| *pOffsetY = 0; |
| *pOffsetU = 3; |
| *pOffsetV = 1; |
| break; |
| |
| case Format_VYUY: |
| *pOffsetY = 1; |
| *pOffsetU = 2; |
| *pOffsetV = 0; |
| break; |
| |
| case Format_Y210: |
| *pOffsetY = 0; |
| *pOffsetU = 2; |
| *pOffsetV = 6; |
| break; |
| |
| default: |
| VPHAL_RENDER_ASSERTMESSAGE("Unknown Packed YUV Format."); |
| eStatus = MOS_STATUS_UNKNOWN; |
| } |
| |
| return eStatus; |
| } |
| |
| //! |
| //! \brief VphalRenderer constructor |
| //! \details Based on the HW and OS info, initialize the renderer interfaces |
| //! \param [in] pRenderHal |
| //! Pointer to RenderHal Interface Structure |
| //! \param [in,out] pStatus |
| //! Pointer to the MOS_STATUS flag. |
| //! Will assign this flag to MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| VphalRenderer::VphalRenderer( |
| PRENDERHAL_INTERFACE pRenderHal, |
| MOS_STATUS *pStatus) : |
| Align16State(), |
| Fast1toNState(), |
| VeboxExecState(), |
| pRender(), |
| pPrimaryFwdRef(), |
| bVeboxUsedForCapPipe(false), |
| uiCurrentChannel(0), |
| pKernelDllRules(nullptr), |
| pKernelDllState(nullptr), |
| pcKernelBin(nullptr), |
| dwKernelBinSize(0), |
| pcFcPatchBin(nullptr), |
| dwFcPatchBinSize(0), |
| uiFrameCounter(0), |
| #if (_DEBUG || _RELEASE_INTERNAL) |
| m_surfaceDumper(nullptr), |
| m_parameterDumper(nullptr), |
| #endif |
| m_statusTable(nullptr), |
| maxSrcRect(), |
| pHdrState(nullptr), |
| m_pRenderHal(pRenderHal), |
| m_pOsInterface(pRenderHal ? pRenderHal->pOsInterface : nullptr), |
| m_pSkuTable(nullptr), |
| m_pWaTable(nullptr), |
| m_modifyKdllFunctionPointers(nullptr), |
| uiSsdControl(0), |
| bDpRotationUsed(false), |
| bSkuDisableVpFor4K(false), |
| bSkuDisableLaceFor4K(false), |
| bSkuDisableDNFor4K(false), |
| PerfData(), |
| m_reporting(nullptr), |
| m_renderGpuContext(MOS_GPU_CONTEXT_INVALID_HANDLE) |
| { |
| MOS_STATUS eStatus; |
| MOS_USER_FEATURE_VALUE_DATA UserFeatureData; |
| |
| VPHAL_RENDER_CHK_NULL(m_pRenderHal); |
| VPHAL_RENDER_CHK_NULL(m_pOsInterface); |
| |
| MOS_ZeroMemory(&pRender, sizeof(pRender)); |
| |
| // Read Slice Shutdown (SSD Control) User Feature Key once during initialization |
| MOS_ZeroMemory(&UserFeatureData, sizeof(UserFeatureData)); |
| eStatus = MOS_UserFeature_ReadValue_ID( |
| nullptr, |
| __VPHAL_RNDR_SSD_CONTROL_ID, |
| &UserFeatureData, |
| m_pOsInterface->pOsContext); |
| if (eStatus == MOS_STATUS_SUCCESS) |
| { |
| uiSsdControl = UserFeatureData.u32Data; |
| } |
| |
| // Do not fail if User feature keys is not present |
| eStatus = MOS_STATUS_SUCCESS; |
| |
| // Get SKU table |
| m_pSkuTable = m_pOsInterface->pfnGetSkuTable(m_pOsInterface); |
| m_pWaTable = m_pOsInterface->pfnGetWaTable(m_pOsInterface); |
| |
| finish: |
| if (pStatus) |
| { |
| *pStatus = eStatus; |
| } |
| } |
| |
| //! |
| //! \brief Search for the best match BB according to the render BB arguments |
| //! \details Based on the params of the BB, search the BB table and try to get |
| //! the best match |
| //! \param [in] pBatchBufferTable |
| //! Point to the BB table to be searched |
| //! \param [in] pInputBbParams |
| //! Point to the BB params required for the BB needed |
| //! \param [in] iBbSize |
| //! The BB size required for the BB needed |
| //! \param [out] ppBatchBuffer |
| //! Point to the addr of the best matched BB. Point to nullptr if there's no. |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VpHal_RenderGetBestMatchBB( |
| PVPHAL_BATCH_BUFFER_TABLE pBatchBufferTable, |
| PVPHAL_BATCH_BUFFER_PARAMS pInputBbParams, |
| int32_t iBbSize, |
| PMHW_BATCH_BUFFER *ppBatchBuffer) |
| { |
| PMHW_BATCH_BUFFER pBbEntry; |
| PMHW_BATCH_BUFFER pBestMatch; |
| PVPHAL_BATCH_BUFFER_PARAMS pSearchBbParams; |
| void* pInputBbArgs; |
| void* pSearchBbArgs; |
| VPHAL_BB_TYPE BbType; |
| int32_t i; |
| int32_t iBbCount; |
| int32_t iBbArgSize; |
| MOS_STATUS eStatus; |
| |
| pBestMatch = nullptr; |
| pBbEntry = pBatchBufferTable->pBatchBufferHeader; |
| iBbCount = *pBatchBufferTable->piBatchBufferCount; |
| BbType = pInputBbParams->iType; |
| pInputBbArgs = &pInputBbParams->BbArgs; |
| iBbArgSize = pInputBbParams->iSize; |
| eStatus = MOS_STATUS_UNKNOWN; |
| |
| for (i = iBbCount; i > 0; i--, pBbEntry++) |
| { |
| pSearchBbParams = (PVPHAL_BATCH_BUFFER_PARAMS)pBbEntry->pPrivateData; |
| |
| // Must have adequate size and the batch buffer type must be the same |
| if (!pSearchBbParams || |
| pBbEntry->iSize < iBbSize || |
| pSearchBbParams->iType != BbType) |
| { |
| continue; |
| } |
| |
| // Point to the start address of the union |
| pSearchBbArgs = &(pSearchBbParams->BbArgs); |
| |
| // BB args must be the same to find the best match(DnDi, Frc and Istab) |
| if (memcmp(pInputBbArgs, pSearchBbArgs, iBbArgSize)) |
| { |
| continue; |
| } |
| |
| // Match -> reuse the BB regardless of the running state |
| pBestMatch = pBbEntry; |
| ((PVPHAL_BATCH_BUFFER_PARAMS)pBestMatch->pPrivateData)->bMatch = true; |
| |
| break; |
| } |
| |
| *ppBatchBuffer = pBestMatch; |
| eStatus = MOS_STATUS_SUCCESS; |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Search from existing BBs for a match. If none, allocate new BB |
| //! \details Based on the params of the BB, search the BB table and try to get |
| //! the best match. If none, try to get an old unused BB to reuse. If |
| //! still none, allocate one new BB |
| //! \param [in] pBatchBufferTable |
| //! Pointer to the BB table to be searched |
| //! \param [in] pInputBbParams |
| //! Pointer to the BB params required for the BB needed |
| //! \param [in] iBbSize |
| //! The BB size required for the BB needed |
| //! \param [in] pRenderHal |
| //! Pointer to RenderHal Interface Structure |
| //! \param [out] ppBatchBuffer |
| //! Pointer to the addr of the available BB. Point to nullptr if there's no |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VpHal_RenderAllocateBB( |
| PVPHAL_BATCH_BUFFER_TABLE pBatchBufferTable, |
| PVPHAL_BATCH_BUFFER_PARAMS pInputBbParams, |
| int32_t iBbSize, |
| PRENDERHAL_INTERFACE pRenderHal, |
| PMHW_BATCH_BUFFER *ppBatchBuffer) |
| { |
| PMHW_BATCH_BUFFER pOldest; // Oldest BB entry |
| PMHW_BATCH_BUFFER pBatchBuffer; // Available BB allocation |
| PMHW_BATCH_BUFFER pBbEntry; // 2nd level BBs array entry |
| PVPHAL_BATCH_BUFFER_PARAMS pSearchBbParams; // Search BB parameters |
| PVPHAL_BATCH_BUFFER_PARAMS pBbParams; |
| int32_t i; |
| int32_t iBbCount; |
| VPHAL_BB_TYPE BbType; |
| int32_t iBbArgSize; |
| MOS_STATUS eStatus; |
| |
| pOldest = nullptr; |
| pBatchBuffer = nullptr; |
| pBbEntry = pBatchBufferTable->pBatchBufferHeader; |
| iBbCount = *pBatchBufferTable->piBatchBufferCount; |
| BbType = pInputBbParams->iType; |
| iBbArgSize = pInputBbParams->iSize; |
| eStatus = MOS_STATUS_UNKNOWN; |
| |
| switch (BbType) |
| { |
| case VPHAL_BB_TYPE_COMPOSITING: |
| VPHAL_RENDER_CHK_STATUS(CompositeState::GetBestMatchBB( |
| pBatchBufferTable, |
| pInputBbParams, |
| iBbSize, |
| &pBatchBuffer)); |
| break; |
| |
| case VPHAL_BB_TYPE_ADVANCED: |
| VPHAL_RENDER_CHK_STATUS(VpHal_RenderGetBestMatchBB( |
| pBatchBufferTable, |
| pInputBbParams, |
| iBbSize, |
| &pBatchBuffer)); |
| break; |
| |
| case VPHAL_BB_TYPE_GENERIC: |
| break; |
| |
| default: |
| VPHAL_RENDER_ASSERTMESSAGE("Unsupported batch buffer type."); |
| eStatus = MOS_STATUS_UNKNOWN; |
| goto finish; |
| } |
| |
| if (pBatchBuffer) |
| { |
| // Best available batch buffer found |
| eStatus = MOS_STATUS_SUCCESS; |
| goto finish; |
| } |
| |
| // Search for an old unused BB to reuse |
| for (i = iBbCount; i > 0; i--, pBbEntry++) |
| { |
| pSearchBbParams = (PVPHAL_BATCH_BUFFER_PARAMS)pBbEntry->pPrivateData; |
| |
| if (pSearchBbParams == nullptr || |
| pSearchBbParams->iType != BbType) |
| { |
| continue; |
| } |
| |
| // Save oldest entry, regardless of size/in-use |
| if (pOldest == nullptr || |
| (int32_t)(pBbEntry->dwSyncTag - pOldest->dwSyncTag) < 0) |
| { |
| pOldest = pBbEntry; |
| } |
| |
| // Skip busy or small batch buffers |
| if (pBbEntry->bBusy || pBbEntry->iSize < iBbSize) |
| { |
| continue; |
| } |
| |
| // Use the oldest BB with suitable size and not in use |
| if (pBatchBuffer == nullptr || |
| (int32_t)(pBbEntry->dwSyncTag - pBatchBuffer->dwSyncTag) < 0) |
| { |
| pBatchBuffer = pBbEntry; |
| pBatchBuffer->iCurrent = 0; |
| pBatchBuffer->iRemaining = pBatchBuffer->iSize; |
| } |
| } |
| |
| // No available BB to use - allocate new |
| if (!pBatchBuffer) |
| { |
| iBbSize = MOS_ALIGN_CEIL(iBbSize, VPHAL_BB_ALIGN_SIZE); |
| |
| if (pOldest == nullptr || |
| (pOldest->bBusy && |
| iBbCount < pBatchBufferTable->iBbCountMax)) |
| { |
| pOldest = nullptr; |
| i = iBbCount++; |
| |
| pBatchBuffer = pBatchBufferTable->pBatchBufferHeader + i; |
| pBatchBuffer->pPrivateData = pBatchBufferTable->pBbParamsHeader + i; |
| |
| *pBatchBufferTable->piBatchBufferCount = iBbCount; |
| } |
| |
| // Release old buffer - may be even in use (delayed release) |
| if (pOldest) |
| { |
| if (pRenderHal->pfnFreeBB(pRenderHal, pOldest) != MOS_STATUS_SUCCESS) |
| { |
| VPHAL_RENDER_ASSERTMESSAGE("Failed to release batch buffer."); |
| eStatus = MOS_STATUS_UNKNOWN; |
| goto finish; |
| } |
| |
| pBatchBuffer = pOldest; |
| } |
| |
| // Allocate new buffer |
| if (pRenderHal->pfnAllocateBB(pRenderHal, pBatchBuffer, iBbSize) != MOS_STATUS_SUCCESS) |
| { |
| VPHAL_RENDER_ASSERTMESSAGE("Failed to allocate batch buffer."); |
| pBatchBuffer = nullptr; |
| eStatus = MOS_STATUS_UNKNOWN; |
| goto finish; |
| } |
| } |
| |
| // Set batch buffer args |
| pBbParams = (PVPHAL_BATCH_BUFFER_PARAMS)pBatchBuffer->pPrivateData; |
| pBbParams->bMatch = false; |
| pBbParams->iType = BbType; |
| pBbParams->iSize = iBbArgSize; |
| pBbParams->BbArgs = pInputBbParams->BbArgs; |
| |
| eStatus = MOS_STATUS_SUCCESS; |
| |
| finish: |
| *ppBatchBuffer = pBatchBuffer; |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Update max src rect in VphalRenderer and primary surface based |
| //! on src rectangle info from primary video |
| //! \details Add max src rect for consistent statistics surface layout. Update |
| //! the max src rect of the surface and its reference surfaces |
| //! \param [in,out] pRenderer |
| //! VPHAL renderer pointer |
| //! \param [in,out] pSurface |
| //! Pointer to the surface |
| //! \return void |
| //! |
| void VpHal_RenderInitMaxRect( |
| VphalRenderer *pRenderer, |
| PVPHAL_SURFACE pSurface) |
| { |
| PVPHAL_SURFACE pRef; |
| uint32_t i; |
| |
| pSurface->bMaxRectChanged = |
| (pSurface->rcSrc.right > pRenderer->maxSrcRect.right || |
| pSurface->rcSrc.bottom > pRenderer->maxSrcRect.bottom) ? |
| true : false; |
| |
| // calcualte max srcRect in pRenderParams |
| pRenderer->maxSrcRect.right = MOS_MAX( |
| pRenderer->maxSrcRect.right, pSurface->rcSrc.right); |
| pRenderer->maxSrcRect.bottom = MOS_MAX( |
| pRenderer->maxSrcRect.bottom, pSurface->rcSrc.bottom); |
| |
| // copy max src rect to primary video |
| pSurface->rcMaxSrc = pRenderer->maxSrcRect; |
| |
| // copy max src rect to forward reference video |
| pRef = pSurface->pFwdRef; |
| for (i = 0; i < pSurface->uFwdRefCount; i++) |
| { |
| // check surface validity |
| VPHAL_RENDER_CHK_NULL_NO_STATUS(pRef); |
| |
| pRef->rcMaxSrc = pRenderer->maxSrcRect; |
| |
| // get next forward reference |
| pRef = pRef->pFwdRef; |
| } |
| |
| // copy max src rect to backward reference video |
| pRef = pSurface->pBwdRef; |
| for (i = 0; i < pSurface->uBwdRefCount; i++) |
| { |
| // check surface validity |
| VPHAL_RENDER_CHK_NULL_NO_STATUS(pRef); |
| |
| pRef->rcMaxSrc = pRenderer->maxSrcRect; |
| |
| // get next backward reference |
| pRef = pRef->pBwdRef; |
| } |
| |
| finish: |
| return; |
| } |
| |
| //! |
| //! \brief Allocate surface dumper |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalRenderer::CreateSurfaceDumper() |
| { |
| #if (_DEBUG || _RELEASE_INTERNAL) |
| VPHAL_DBG_SURF_DUMP_CREATE() |
| VPHAL_RENDER_CHK_NULL_RETURN(m_surfaceDumper); |
| #endif |
| return MOS_STATUS_SUCCESS; |
| } |
| |
| MOS_STATUS VphalRenderer::AllocateDebugDumper() |
| { |
| PRENDERHAL_INTERFACE pRenderHal = m_pRenderHal; |
| MOS_STATUS eStatus = MOS_STATUS_SUCCESS; |
| // Allocate feature report |
| m_reporting = MOS_New(VphalFeatureReport); |
| if (m_reporting == nullptr) |
| { |
| VPHAL_RENDER_ASSERTMESSAGE("Invalid null pointer!"); |
| eStatus = MOS_STATUS_NULL_POINTER; |
| goto finish; |
| } |
| |
| #if (_DEBUG || _RELEASE_INTERNAL) |
| |
| // Initialize Surface Dumper |
| VPHAL_RENDER_CHK_STATUS(CreateSurfaceDumper()); |
| |
| // Initialize State Dumper |
| VPHAL_DBG_STATE_DUMPPER_CREATE() |
| if (pRenderHal->pStateDumper == nullptr) |
| { |
| VPHAL_RENDER_ASSERTMESSAGE("Invalid null pointer!"); |
| eStatus = MOS_STATUS_NULL_POINTER; |
| goto finish; |
| } |
| |
| VPHAL_DBG_PARAMETERS_DUMPPER_CREATE() |
| |
| if (m_parameterDumper == nullptr) |
| { |
| VPHAL_RENDER_ASSERTMESSAGE("Invalid null pointer!"); |
| eStatus = MOS_STATUS_NULL_POINTER; |
| goto finish; |
| } |
| |
| // if m_isApoEnabled is false dump in legacy path, otherwise in APO path |
| if (!m_isApoEnabled) |
| { |
| SkuWaTable_DUMPPER_DUMP_XML(m_pSkuTable, m_pWaTable); |
| } |
| |
| #endif |
| |
| finish: |
| if (eStatus != MOS_STATUS_SUCCESS) |
| { |
| if (m_reporting) |
| { |
| MOS_Delete(m_reporting); |
| m_reporting = nullptr; |
| } |
| |
| #if (_DEBUG || _RELEASE_INTERNAL) |
| |
| if (m_surfaceDumper) |
| { |
| VPHAL_DBG_SURF_DUMP_DESTORY(m_surfaceDumper) |
| } |
| |
| if (pRenderHal->pStateDumper) |
| { |
| VPHAL_DBG_STATE_DUMPPER_DESTORY(pRenderHal->pStateDumper) |
| } |
| #endif |
| |
| } |
| |
| return eStatus; |
| } |
| |
| //! |
| //! \brief Get Hdr path needed flag |
| //! \details Get Hdr path needed flag |
| //! \param pRenderParams |
| //! [in] Pointer to VPHAL render parameter |
| //! \param pRenderPassData |
| //! [in,out] Pointer to the VPHAL render pass data |
| //! \return MOS_STATUS |
| //! Return MOS_STATUS_SUCCESS if successful, otherwise failed |
| //! |
| MOS_STATUS VphalRenderer::GetHdrPathNeededFlag( |
| PVPHAL_RENDER_PARAMS pRenderParams, |
| RenderpassData *pRenderPassData) |
| { |
| MOS_STATUS eStatus; |
| uint32_t uiIndex; |
| PVPHAL_SURFACE pSrcSurface; |
| PVPHAL_SURFACE pTargetSurface; |
| bool bToneMapping; |
| bool bBt2020Output; |
| bool bMultiLayerBt2020; |
| |
| //-------------------------------------------- |
| VPHAL_RENDER_CHK_NULL(pRenderParams); |
| VPHAL_RENDER_CHK_NULL(pRenderPassData); |
| VPHAL_RENDER_CHK_NULL(pRenderParams->pTarget[0]); |
| //-------------------------------------------- |
| |
| eStatus = MOS_STATUS_SUCCESS; |
| uiIndex = 0; |
| pSrcSurface = nullptr; |
| pTargetSurface = nullptr; |
| bToneMapping = false; |
| bBt2020Output = false; |
| bMultiLayerBt2020 = false; |
| |
| // Loop through the sources |
| for (uiIndex = 0; |
| uiIndex < VPHAL_MAX_SOURCES && uiIndex < pRenderParams->uSrcCount; |
| uiIndex++) |
| { |
| pSrcSurface = pRenderParams->pSrc[uiIndex]; |
| if (pSrcSurface == nullptr) |
| { |
| continue; |
| } |
| pTargetSurface = pRenderParams->pTarget[0]; |
| |
| // Need to use HDR to process BT601/BT709->BT2020 |
| if (IS_COLOR_SPACE_BT2020(pRenderParams->pTarget[0]->ColorSpace) && |
| !IS_COLOR_SPACE_BT2020(pSrcSurface->ColorSpace)) |
| { |
| bBt2020Output = true; |
| } |
| |
| if ((pSrcSurface->pHDRParams && (pSrcSurface->pHDRParams->EOTF != VPHAL_HDR_EOTF_TRADITIONAL_GAMMA_SDR)) || |
| (pTargetSurface->pHDRParams && (pTargetSurface->pHDRParams->EOTF != VPHAL_HDR_EOTF_TRADITIONAL_GAMMA_SDR))) |
| { |
| bToneMapping = true; |
| } |
| |
| if (IS_COLOR_SPACE_BT2020(pSrcSurface->ColorSpace) && pRenderParams->uSrcCount > 1) |
| { |
| bMultiLayerBt2020 = true; |
| } |
| } |
| |
| pRenderPassData->bHdrNeeded = bBt2020Output || bToneMapping || bMultiLayerBt2020; |
| |
| // Error handling for illegal Hdr cases on unsupported m_Platform |
| if ((pRenderPassData->bHdrNeeded) && (!MEDIA_IS_SKU(m_pSkuTable, FtrHDR))) |
| { |
| eStatus = MOS_STATUS_SUCCESS; |
| VPHAL_RENDER_ASSERTMESSAGE("Illegal Hdr cases on unsupported m_Platform, turn off HDR."); |
| pRenderPassData->bHdrNeeded = false; |
| } |
| |
| if (pRenderPassData->bHdrNeeded) |
| { |
| pRenderPassData->bCompNeeded = false; |
| } |
| |
| if (!pRenderPassData->bHdrNeeded && |
| pRenderParams->pSrc[0] && |
| pRenderParams->pTarget[0] && |
| IS_COLOR_SPACE_BT2020(pRenderParams->pSrc[0]->ColorSpace) && |
| !IS_COLOR_SPACE_BT2020(pRenderParams->pTarget[0]->ColorSpace) && |
| MEDIA_IS_SKU(m_pSkuTable, FtrDisableVEBoxFeatures)) |
| { |
| eStatus = MOS_STATUS_INVALID_PARAMETER; |
| VPHAL_RENDER_ASSERTMESSAGE("Invalid Params for This Platform."); |
| } |
| |
| finish: |
| return eStatus; |
| } |