blob: 71e8a6bacc55d0ce96390aa775113897f39e95de [file] [log] [blame]
/*
* Copyright (c) 2012-2020, 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_render_sfc_base.cpp
//! \brief VPHAL SFC rendering component
//! \details The SFC renderer supports Scaling, IEF, CSC/ColorFill and Rotation.
//! It's responsible for setting up HW states and generating the SFC
//! commands.
//!
#include "vphal_render_vebox_base.h"
#include "vphal_render_ief.h"
#include "vphal_render_sfc_base.h"
#if __VPHAL_SFC_SUPPORTED
//!
//! \brief Constants used to derive Line Buffer sizes
//!
#define SFC_CACHELINE_SIZE_IN_BYTES (512 / 8)
#define SFC_AVS_LINEBUFFER_SIZE_PER_VERTICAL_PIXEL (5 * SFC_CACHELINE_SIZE_IN_BYTES / 8)
#define SFC_IEF_LINEBUFFER_SIZE_PER_VERTICAL_PIXEL (1 * SFC_CACHELINE_SIZE_IN_BYTES / 4)
//!
//! \brief Initialize SFC Output Surface Command parameters
//! \details Initialize MHW SFC Output Surface Command parameters from SFC Pipe output Surface
//! \param [in] pSfcPipeOutSurface
//! pointer to SFC Pipe output Surface
//! \param [out] pMhwOutSurfParams
//! pointer to SFC Output Surface Command parameters
//! \return MOS_STATUS
//!
MOS_STATUS VpHal_InitMhwOutSurfParams(
PVPHAL_SURFACE pSfcPipeOutSurface,
PMHW_SFC_OUT_SURFACE_PARAMS pMhwOutSurfParams)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
VPHAL_RENDER_CHK_NULL(pSfcPipeOutSurface);
VPHAL_RENDER_CHK_NULL(pMhwOutSurfParams);
MOS_ZeroMemory(pMhwOutSurfParams, sizeof(*pMhwOutSurfParams));
pMhwOutSurfParams->ChromaSiting = pSfcPipeOutSurface->ChromaSiting;
pMhwOutSurfParams->dwWidth = pSfcPipeOutSurface->dwWidth;
pMhwOutSurfParams->dwHeight = pSfcPipeOutSurface->dwHeight;
pMhwOutSurfParams->dwPitch = pSfcPipeOutSurface->dwPitch;
pMhwOutSurfParams->TileType = pSfcPipeOutSurface->TileType;
pMhwOutSurfParams->TileModeGMM = pSfcPipeOutSurface->TileModeGMM;
pMhwOutSurfParams->bGMMTileEnabled = pSfcPipeOutSurface->bGMMTileEnabled;
pMhwOutSurfParams->pOsResource = &(pSfcPipeOutSurface->OsResource);
pMhwOutSurfParams->Format = pSfcPipeOutSurface->Format;
pMhwOutSurfParams->bCompressible = pSfcPipeOutSurface->bCompressible;
pMhwOutSurfParams->dwCompressionFormat = pSfcPipeOutSurface->CompressionFormat;
pMhwOutSurfParams->dwSurfaceXOffset = pSfcPipeOutSurface->YPlaneOffset.iXOffset;
pMhwOutSurfParams->dwSurfaceYOffset = pSfcPipeOutSurface->YPlaneOffset.iYOffset;
if (pSfcPipeOutSurface->dwPitch > 0)
{
pMhwOutSurfParams->dwUYoffset = ((pSfcPipeOutSurface->UPlaneOffset.iSurfaceOffset - pSfcPipeOutSurface->YPlaneOffset.iSurfaceOffset) / pSfcPipeOutSurface->dwPitch) + pSfcPipeOutSurface->UPlaneOffset.iYOffset;
}
finish:
return eStatus;
}
//!
//! \brief Get SFC Rotation mode parameter
//! \details Get MHW SFC Rotation mode parameter
//! \param [in] Rotation
//! VPHAL roration mode parameter
//! \return MHW_ROTATION
//!
MHW_ROTATION VpHal_GetMhwRotationParam(VPHAL_ROTATION Rotation)
{
switch (Rotation)
{
case VPHAL_ROTATION_90:
return MHW_ROTATION_90; // 90 Degree Rotation
case VPHAL_ROTATION_180:
return MHW_ROTATION_180; // 180 Degree Rotation
case VPHAL_ROTATION_270:
return MHW_ROTATION_270; // 270 Degree Rotation
case VPHAL_MIRROR_HORIZONTAL:
return MHW_MIRROR_HORIZONTAL; // Horizontal Mirror
case VPHAL_MIRROR_VERTICAL:
return MHW_MIRROR_VERTICAL; // Vertical Mirror
case VPHAL_ROTATE_90_MIRROR_VERTICAL:
return MHW_ROTATION_270; // 270 Degree rotation and Horizontal Mirror
case VPHAL_ROTATE_90_MIRROR_HORIZONTAL:
return MHW_ROTATION_90; // 90 Degree rotation and Horizontal Mirror
default:
case VPHAL_ROTATION_IDENTITY:
return MHW_ROTATION_IDENTITY;
}
}
//!
//! \brief Get SFC Scaling mode parameter
//! \details Get MHW SFC Scaling mode parameter
//! \param [in] Scaling mode
//! VPHAL Scaling mode parameter
//! \return MHW_SCALING_MODE
//!
MHW_SCALING_MODE VpHal_GetMhwScalingModeParam(VPHAL_SCALING_MODE ScalingMode)
{
switch (ScalingMode)
{
case VPHAL_SCALING_NEAREST:
return MHW_SCALING_NEAREST; // Nearest interpolation
case VPHAL_SCALING_BILINEAR:
return MHW_SCALING_BILINEAR; // Bilinear interpolation
case VPHAL_SCALING_AVS:
case VPHAL_SCALING_ADV_QUALITY:
default:
return MHW_SCALING_AVS;
}
}
bool VphalSfcState::IsFormatMMCSupported(
MOS_FORMAT Format)
{
// Check if Sample Format is supported
if ((Format != Format_NV12) &&
(Format != Format_UYVY) &&
(Format != Format_YUYV))
{
VPHAL_RENDER_NORMALMESSAGE("Unsupported Format '0x%08x' for SFC MMC.", Format);
return false;
}
return true;
}
VphalSfcState::VphalSfcState(
PMOS_INTERFACE osInterface,
PRENDERHAL_INTERFACE renderHal,
PMHW_SFC_INTERFACE sfcInterface)
{
VPHAL_RENDER_ASSERT(osInterface);
VPHAL_RENDER_ASSERT(renderHal);
VPHAL_RENDER_ASSERT(sfcInterface);
m_renderHal = renderHal;
m_sfcInterface = sfcInterface;
m_osInterface = osInterface;
// Allocate AVS state
VpHal_RndrCommonInitAVSParams(
&m_AvsParameters,
POLYPHASE_Y_COEFFICIENT_TABLE_SIZE_G9,
POLYPHASE_UV_COEFFICIENT_TABLE_SIZE_G9);
}
VphalSfcState::~VphalSfcState()
{
VpHal_RndrCommonDestroyAVSParams(&m_AvsParameters);
MOS_FreeMemAndSetNull(m_renderData.SfcStateParams);
}
bool VphalSfcState::IsOutputCapable(
bool isColorFill,
PVPHAL_SURFACE src,
PVPHAL_SURFACE renderTarget)
{
bool isOutputCapable = false;
VPHAL_RENDER_NORMALMESSAGE(
"isColorFill %d, \
src->rcDst.top %d, \
src->rcDst.left %d, \
renderTarget->TileType %d, \
renderTarget->Format %d",
isColorFill,
src->rcDst.top,
src->rcDst.left,
renderTarget->TileType,
renderTarget->Format);
// H/W does not support ColorFill, the (OffsetX, OffsetY)
// of scaled region not being (0, 0) or the tile type not being
// Tile_Y on NV12/P010/P016 output surface. Disable SFC even if other
// features are supported.
if ((isColorFill ||
src->rcDst.top != 0 ||
src->rcDst.left != 0 ||
renderTarget->TileType != MOS_TILE_Y) &&
(renderTarget->Format == Format_NV12 ||
renderTarget->Format == Format_P010 ||
renderTarget->Format == Format_P016))
{
isOutputCapable = false;
}
else
{
isOutputCapable = true;
}
return isOutputCapable;
}
void VphalSfcState::AdjustBoundary(
PVPHAL_SURFACE pSurface,
uint32_t* pdwSurfaceWidth,
uint32_t* pdwSurfaceHeight)
{
uint32_t dwVeboxHeight;
uint32_t dwVeboxWidth;
uint32_t dwVeboxBottom;
uint32_t dwVeboxRight;
MEDIA_WA_TABLE *pWaTable = nullptr;
VPHAL_RENDER_CHK_NULL_NO_STATUS(m_sfcInterface);
VPHAL_RENDER_CHK_NULL_NO_STATUS(m_osInterface);
VPHAL_RENDER_CHK_NULL_NO_STATUS(pSurface);
VPHAL_RENDER_CHK_NULL_NO_STATUS(pdwSurfaceWidth);
VPHAL_RENDER_CHK_NULL_NO_STATUS(pdwSurfaceHeight);
pWaTable = m_osInterface->pfnGetWaTable(m_osInterface);
VPHAL_RENDER_CHK_NULL_NO_STATUS(pWaTable);
if (MEDIA_IS_WA(pWaTable, WaVeboxInputHeight16Aligned) &&
(pSurface->Format == Format_NV12 ||
pSurface->Format == Format_P010 ||
pSurface->Format == Format_P016))
{
m_sfcInterface->m_veHeightAlignment = 16;
}
else
{
m_sfcInterface->m_veHeightAlignment = MHW_SFC_VE_HEIGHT_ALIGN;
}
// For the VEBOX output to SFC, the width is multiple of 16 and height
// is multiple of 4
dwVeboxHeight = pSurface->dwHeight;
dwVeboxWidth = pSurface->dwWidth;
dwVeboxBottom = (uint32_t)pSurface->rcMaxSrc.bottom;
dwVeboxRight = (uint32_t)pSurface->rcMaxSrc.right;
if(pSurface->bDirectionalScalar)
{
dwVeboxHeight *= 2;
dwVeboxWidth *= 2;
dwVeboxBottom *= 2;
dwVeboxRight *= 2;
}
*pdwSurfaceHeight = MOS_ALIGN_CEIL(
MOS_MIN(dwVeboxHeight, MOS_MAX(dwVeboxBottom, MHW_VEBOX_MIN_HEIGHT)),
m_sfcInterface->m_veHeightAlignment);
*pdwSurfaceWidth = MOS_ALIGN_CEIL(
MOS_MIN(dwVeboxWidth, MOS_MAX(dwVeboxRight, MHW_VEBOX_MIN_WIDTH)),
m_sfcInterface->m_veWidthAlignment);
finish:
return;
}
bool VphalSfcState::IsOutputPipeSfcFeasible(
PCVPHAL_RENDER_PARAMS pcRenderParams,
PVPHAL_SURFACE pSrcSurface,
PVPHAL_SURFACE pRenderTarget)
{
VPHAL_RENDER_NORMALMESSAGE(
"IsDisabled %d, \
uDstCount %d, \
Rotation %d, \
pTarget[0]->TileType %d, \
IsFormatSupported %d, \
InputFormat %d, \
OutputFormat %d, \
pCompAlpha %p, \
pDeinterlaceParams %p, \
bQueryVariance %d",
IsDisabled(),
pcRenderParams->uDstCount,
pSrcSurface->Rotation,
pcRenderParams->pTarget[0]->TileType,
IsFormatSupported(pSrcSurface, pcRenderParams->pTarget[0], pcRenderParams->pCompAlpha),
pSrcSurface->Format,
pcRenderParams->pTarget[0]->Format,
pcRenderParams->pCompAlpha,
pSrcSurface->pDeinterlaceParams,
pSrcSurface->bQueryVariance);
//!
//! \brief SFC can be the output pipe when the following conditions are all met
//! 1. User feature keys value "SFC Disable" is false
//! 2. Single render target only
//! 3. Rotation disabled or ONLY Rotation enabled when the SFC output is Y-tile
//! 4. i/o format is supported by SFC, taking into account the alpha fill info
//! 5. Comp DI(ARGB/ABGR) is disabled
//! 6. Variance Query is disabled
//!
if (IsDisabled() == false &&
pcRenderParams->uDstCount == 1 &&
(pSrcSurface->Rotation == VPHAL_ROTATION_IDENTITY ||
(pSrcSurface->Rotation <= VPHAL_ROTATION_270 &&
pcRenderParams->pTarget[0]->TileType == MOS_TILE_Y)) &&
IsFormatSupported(pSrcSurface, pcRenderParams->pTarget[0], pcRenderParams->pCompAlpha) &&
(pSrcSurface->pDeinterlaceParams == nullptr ||
(pSrcSurface->Format != Format_A8R8G8B8 && pSrcSurface->Format != Format_A8B8G8R8)) &&
pSrcSurface->bQueryVariance == false)
{
// For platforms with VEBOX disabled but procamp enabled, go Render path
if (MEDIA_IS_SKU(m_renderHal->pSkuTable, FtrDisableVEBoxFeatures) && pSrcSurface->pProcampParams != nullptr)
{
return false;
}
return true;
}
return false;
}
VPHAL_OUTPUT_PIPE_MODE VphalSfcState::GetOutputPipe(
PVPHAL_SURFACE pSrc,
PVPHAL_SURFACE pRenderTarget,
PCVPHAL_RENDER_PARAMS pcRenderParams)
{
float fScaleX;
float fScaleY;
uint32_t dwSurfaceWidth;
uint32_t dwSurfaceHeight;
VPHAL_OUTPUT_PIPE_MODE OutputPipe;
bool bColorFill;
uint16_t wWidthAlignUnit;
uint16_t wHeightAlignUnit;
uint32_t dwSourceRegionWidth;
uint32_t dwSourceRegionHeight;
uint32_t dwOutputRegionWidth;
uint32_t dwOutputRegionHeight;
uint32_t dwSfcMaxWidth;
uint32_t dwSfcMaxHeight;
uint32_t dwSfcMinWidth;
uint32_t dwSfcMinHeight;
OutputPipe = VPHAL_OUTPUT_PIPE_MODE_COMP;
VPHAL_RENDER_CHK_NULL_NO_STATUS(m_sfcInterface);
VPHAL_RENDER_CHK_NULL_NO_STATUS(pSrc);
VPHAL_RENDER_CHK_NULL_NO_STATUS(pRenderTarget);
VPHAL_RENDER_CHK_NULL_NO_STATUS(pcRenderParams);
dwSfcMaxWidth = m_sfcInterface->m_maxWidth;
dwSfcMaxHeight = m_sfcInterface->m_maxHeight;
dwSfcMinWidth = m_sfcInterface->m_minWidth;
dwSfcMinHeight = m_sfcInterface->m_minHeight;
wWidthAlignUnit = 1;
wHeightAlignUnit = 1;
// Check if the feature can be supported by SFC output pipe
if (!IsOutputPipeSfcFeasible(pcRenderParams, pSrc, pRenderTarget))
{
VPHAL_RENDER_NORMALMESSAGE("Feature or surface format not supported by SFC Pipe.");
OutputPipe = VPHAL_OUTPUT_PIPE_MODE_COMP;
return OutputPipe;
}
// Get the SFC input surface size from Vebox
AdjustBoundary(
pSrc,
&dwSurfaceWidth,
&dwSurfaceHeight);
// Apply alignment restriction to the source and scaled regions.
switch(pRenderTarget->Format)
{
case Format_NV12:
wWidthAlignUnit = 2;
wHeightAlignUnit = 2;
break;
case Format_YUY2:
case Format_UYVY:
wWidthAlignUnit = 2;
break;
default:
break;
}
// Region of the input frame which needs to be processed by SFC
dwSourceRegionHeight = MOS_ALIGN_FLOOR(
MOS_MIN((uint32_t)(pSrc->rcSrc.bottom - pSrc->rcSrc.top), dwSurfaceHeight),
wHeightAlignUnit);
dwSourceRegionWidth = MOS_ALIGN_FLOOR(
MOS_MIN((uint32_t)(pSrc->rcSrc.right - pSrc->rcSrc.left), dwSurfaceWidth),
wWidthAlignUnit);
// Size of the Output Region over the Render Target
dwOutputRegionHeight = MOS_ALIGN_CEIL(
(uint32_t)(pSrc->rcDst.bottom - pSrc->rcDst.top),
wHeightAlignUnit);
dwOutputRegionWidth = MOS_ALIGN_CEIL(
(uint32_t)(pSrc->rcDst.right - pSrc->rcDst.left),
wWidthAlignUnit);
// SFC i/o width and height should fall into the range of [128, 4K]
if (OUT_OF_BOUNDS(dwSurfaceWidth, dwSfcMinWidth, dwSfcMaxWidth) ||
OUT_OF_BOUNDS(dwSurfaceHeight, dwSfcMinHeight, dwSfcMaxHeight) ||
OUT_OF_BOUNDS(dwSourceRegionWidth, dwSfcMinWidth, dwSfcMaxWidth) ||
OUT_OF_BOUNDS(dwSourceRegionHeight, dwSfcMinHeight, dwSfcMaxHeight) ||
OUT_OF_BOUNDS(dwOutputRegionWidth, dwSfcMinWidth, dwSfcMaxWidth) ||
OUT_OF_BOUNDS(dwOutputRegionHeight, dwSfcMinHeight, dwSfcMaxHeight) ||
OUT_OF_BOUNDS(pRenderTarget->dwWidth, dwSfcMinWidth, dwSfcMaxWidth) ||
OUT_OF_BOUNDS(pRenderTarget->dwHeight, dwSfcMinHeight, dwSfcMaxHeight))
{
VPHAL_RENDER_NORMALMESSAGE("Surface dimensions not supported by SFC Pipe.");
OutputPipe = VPHAL_OUTPUT_PIPE_MODE_COMP;
return OutputPipe;
}
// Size of the Output Region over the Render Target
dwOutputRegionHeight = MOS_MIN(dwOutputRegionHeight, pRenderTarget->dwHeight);
dwOutputRegionWidth = MOS_MIN(dwOutputRegionWidth, pRenderTarget->dwWidth);
// Calculate the scaling ratio
// Both source region and scaled region are pre-rotated
if (pSrc->Rotation == VPHAL_ROTATION_IDENTITY ||
pSrc->Rotation == VPHAL_ROTATION_180 ||
pSrc->Rotation == VPHAL_MIRROR_HORIZONTAL ||
pSrc->Rotation == VPHAL_MIRROR_VERTICAL)
{
fScaleX = (float)dwOutputRegionWidth / (float)dwSourceRegionWidth;
fScaleY = (float)dwOutputRegionHeight / (float)dwSourceRegionHeight;
}
else
{
// VPHAL_ROTATION_90 || VPHAL_ROTATION_270 || VPHAL_ROTATE_90_MIRROR_VERTICAL || VPHAL_ROTATE_90_MIRROR_HORIZONTAL
fScaleX = (float)dwOutputRegionHeight / (float)dwSourceRegionWidth;
fScaleY = (float)dwOutputRegionWidth / (float)dwSourceRegionHeight;
}
// SFC scaling range is [0.125, 8] for both X and Y direction.
if ((fScaleX < 0.125F) || (fScaleX > 8.0F) ||
(fScaleY < 0.125F) || (fScaleY > 8.0F))
{
VPHAL_RENDER_NORMALMESSAGE("Scaling factor not supported by SFC Pipe.");
OutputPipe = VPHAL_OUTPUT_PIPE_MODE_COMP;
return OutputPipe;
}
if (MEDIA_IS_WA(m_renderHal->pWaTable, WaDisableSFCSrcCrop) &&
dwSurfaceHeight > 1120 &&
(((pSrc->rcSrc.left > 0) || (dwSurfaceWidth - pSrc->rcSrc.right > 0)) ||
((pSrc->rcSrc.bottom > 1120) && (pSrc->rcSrc.bottom < (int32_t)dwSurfaceHeight)) ||
((pSrc->rcSrc.top > 1120) && (pSrc->rcSrc.top < (int32_t)dwSurfaceHeight)) ||
(pSrc->rcSrc.bottom < (int32_t)dwSurfaceHeight)))
{
VPHAL_RENDER_NORMALMESSAGE("Fallback to comp path as SW WA for SFC Cropping TDR.");
OutputPipe = VPHAL_OUTPUT_PIPE_MODE_COMP;
return OutputPipe;
}
// if ScalingPreference == Composition, switch to use composition path
// This flag can be set by app.
if (pSrc->ScalingPreference == VPHAL_SCALING_PREFER_COMP)
{
VPHAL_RENDER_NORMALMESSAGE("DDI set ScalingPreference to Composition to use render for scaling.");
OutputPipe = VPHAL_OUTPUT_PIPE_MODE_COMP;
return OutputPipe;
}
bColorFill = (pcRenderParams->pColorFillParams &&
(!RECT1_CONTAINS_RECT2(pSrc->rcDst, pRenderTarget->rcDst))) ?
true : false;
if (IsOutputCapable(bColorFill, pSrc, pRenderTarget))
{
OutputPipe = VPHAL_OUTPUT_PIPE_MODE_SFC;
}
else
{
OutputPipe = VPHAL_OUTPUT_PIPE_MODE_COMP;
}
finish:
return OutputPipe;
}
void VphalSfcState::DetermineCscParams(
PVPHAL_SURFACE src,
PVPHAL_SURFACE renderTarget)
{
// Determine if CSC is required in SFC pipe
if (IS_RGB_CSPACE(src->ColorSpace))
{
if (IS_YUV_CSPACE(renderTarget->ColorSpace))
{
m_renderData.SfcInputCspace = renderTarget->ColorSpace;
}
else if (MEDIA_IS_HDCONTENT(src->dwWidth, src->dwHeight))
{
m_renderData.SfcInputCspace = CSpace_BT709;
}
else
{
m_renderData.SfcInputCspace = CSpace_BT601;
}
}
else
{
m_renderData.SfcInputCspace = src->ColorSpace;
}
if (m_renderData.SfcInputCspace != renderTarget->ColorSpace)
{
m_renderData.bCSC = true;
}
}
void VphalSfcState::DetermineInputFormat(
PVPHAL_SURFACE src,
PVPHAL_VEBOX_RENDER_DATA veboxRenderData)
{
// Determine SFC input surface format
if (IS_RGB_FORMAT(src->Format))
{
m_renderData.SfcInputFormat = Format_AYUV;
}
else if (veboxRenderData->bDeinterlace)
{
m_renderData.SfcInputFormat = Format_YUY2;
}
else
{
m_renderData.SfcInputFormat = src->Format;
}
}
void VphalSfcState::SetRenderingFlags(
PVPHAL_COLORFILL_PARAMS pColorFillParams,
PVPHAL_ALPHA_PARAMS pAlphaParams,
PVPHAL_SURFACE pSrc,
PVPHAL_SURFACE pRenderTarget,
PVPHAL_VEBOX_RENDER_DATA pRenderData)
{
PRENDERHAL_INTERFACE pRenderHal;
float fScaleX;
float fScaleY;
uint32_t dwSurfaceWidth;
uint32_t dwSurfaceHeight;
uint16_t wWidthAlignUnit;
uint16_t wHeightAlignUnit;
uint32_t dwSourceRegionWidth;
uint32_t dwSourceRegionHeight;
uint32_t dwOutputRegionWidth;
uint32_t dwOutputRegionHeight;
uint32_t dwVeboxBottom;
uint32_t dwVeboxRight;
VPHAL_COLORPACK dstColorPack;
VPHAL_RENDER_CHK_NULL_NO_STATUS(pSrc);
VPHAL_RENDER_CHK_NULL_NO_STATUS(pRenderTarget);
pRenderHal = m_renderHal;
wWidthAlignUnit = 1;
wHeightAlignUnit = 1;
dwVeboxBottom = (uint32_t)pSrc->rcSrc.bottom;
dwVeboxRight = (uint32_t)pSrc->rcSrc.right;
dstColorPack = VpHal_GetSurfaceColorPack(pRenderTarget->Format);
// Get the SFC input surface size from Vebox
AdjustBoundary(
pSrc,
&dwSurfaceWidth,
&dwSurfaceHeight);
// Apply alignment restriction to the source and scaled regions.
switch (dstColorPack)
{
case VPHAL_COLORPACK_420:
wWidthAlignUnit = 2;
wHeightAlignUnit = 2;
break;
case VPHAL_COLORPACK_422:
wWidthAlignUnit = 2;
break;
default:
break;
}
if(pSrc->bDirectionalScalar)
{
dwVeboxBottom *= 2;
dwVeboxRight *= 2;
}
// Region of the input frame which needs to be processed by SFC
dwSourceRegionHeight = MOS_ALIGN_FLOOR(
MOS_MIN((uint32_t)(dwVeboxBottom - pSrc->rcSrc.top), dwSurfaceHeight),
wHeightAlignUnit);
dwSourceRegionWidth = MOS_ALIGN_FLOOR(
MOS_MIN((uint32_t)(dwVeboxRight - pSrc->rcSrc.left), dwSurfaceWidth),
wWidthAlignUnit);
// Size of the Output Region over the Render Target
dwOutputRegionHeight = MOS_ALIGN_CEIL(
MOS_MIN((uint32_t)(pSrc->rcDst.bottom - pSrc->rcDst.top), pRenderTarget->dwHeight),
wHeightAlignUnit);
dwOutputRegionWidth = MOS_ALIGN_CEIL(
MOS_MIN((uint32_t)(pSrc->rcDst.right - pSrc->rcDst.left), pRenderTarget->dwWidth),
wWidthAlignUnit);
// Calculate the scaling ratio
// Both source region and scaled region are pre-rotated
if (pSrc->Rotation == VPHAL_ROTATION_IDENTITY ||
pSrc->Rotation == VPHAL_ROTATION_180 ||
pSrc->Rotation == VPHAL_MIRROR_HORIZONTAL ||
pSrc->Rotation == VPHAL_MIRROR_VERTICAL)
{
fScaleX = (float)dwOutputRegionWidth / (float)dwSourceRegionWidth;
fScaleY = (float)dwOutputRegionHeight / (float)dwSourceRegionHeight;
}
else
{
// VPHAL_ROTATION_90 || VPHAL_ROTATION_270 || VPHAL_ROTATE_90_MIRROR_VERTICAL || VPHAL_ROTATE_90_MIRROR_HORIZONTAL
fScaleX = (float)dwOutputRegionHeight / (float)dwSourceRegionWidth;
fScaleY = (float)dwOutputRegionWidth / (float)dwSourceRegionHeight;
}
// Set RenderData flags
m_renderData.bScaling = ((fScaleX == 1.0F) && (fScaleY == 1.0F)) ?
false : true;
m_renderData.bColorFill = (pColorFillParams && pSrc->InterlacedScalingType == ISCALING_NONE &&
(!RECT1_CONTAINS_RECT2(pSrc->rcDst, pRenderTarget->rcDst))) ?
true : false;
m_renderData.bIEF = (pSrc->pIEFParams &&
pSrc->pIEFParams->bEnabled &&
(pSrc->pIEFParams->fIEFFactor > 0.0f)) ?
true : false;
// Determine if CSC is required in SFC pipe
DetermineCscParams(
pSrc,
pRenderTarget);
// Determine SFC input surface format
DetermineInputFormat(
pSrc,
pRenderData);
m_renderData.fScaleX = fScaleX;
m_renderData.fScaleY = fScaleY;
m_renderData.pColorFillParams = m_renderData.bColorFill ? pColorFillParams : nullptr;
m_renderData.pAvsParams = &m_AvsParameters;
m_renderData.pAlphaParams = pAlphaParams;
m_renderData.pSfcPipeOutSurface = pRenderTarget;
m_renderData.SfcRotation = pSrc->Rotation;
m_renderData.SfcScalingMode = pSrc->ScalingMode;
// In SFC, we have a lot of HW restrictions on Chroma Sitting Programming.
// So prevent any invalid input for SFC to avoid HW problems.
// Prevent invalid input for input surface and format.
m_renderData.SfcSrcChromaSiting = pSrc->ChromaSiting;
if (m_renderData.SfcSrcChromaSiting == MHW_CHROMA_SITING_NONE)
{
m_renderData.SfcSrcChromaSiting = (CHROMA_SITING_HORZ_LEFT | CHROMA_SITING_VERT_CENTER);
}
switch (VpHal_GetSurfaceColorPack(m_renderData.SfcInputFormat))
{
case VPHAL_COLORPACK_422:
m_renderData.SfcSrcChromaSiting = (m_renderData.SfcSrcChromaSiting & 0x7) | CHROMA_SITING_VERT_TOP;
break;
case VPHAL_COLORPACK_444:
m_renderData.SfcSrcChromaSiting = CHROMA_SITING_HORZ_LEFT | CHROMA_SITING_VERT_TOP;
break;
default:
break;
}
// Prevent invalid input for output surface and format
if (pRenderTarget->ChromaSiting == MHW_CHROMA_SITING_NONE)
{
pRenderTarget->ChromaSiting = (CHROMA_SITING_HORZ_LEFT | CHROMA_SITING_VERT_CENTER);
}
switch (dstColorPack)
{
case VPHAL_COLORPACK_422:
pRenderTarget->ChromaSiting = (pRenderTarget->ChromaSiting & 0x7) | CHROMA_SITING_VERT_TOP;
break;
case VPHAL_COLORPACK_444:
pRenderTarget->ChromaSiting = CHROMA_SITING_HORZ_LEFT | CHROMA_SITING_VERT_TOP;
break;
default:
break;
}
m_renderData.bForcePolyPhaseCoefs = VpHal_IsChromaUpSamplingNeeded(pSrc, pRenderTarget);
// Cache Render Target pointer
pRenderData->pRenderTarget = pRenderTarget;
VPHAL_RENDER_NORMALMESSAGE(
"RenderData: bScaling %d, bColorFill %d, bIEF %d, SfcInputFormat %d, SfcRotation %d, SfcScalingMode %d, SfcSrcChromaSiting %d",
m_renderData.bScaling,
m_renderData.bColorFill,
m_renderData.bIEF,
m_renderData.SfcInputFormat,
m_renderData.SfcRotation,
m_renderData.SfcScalingMode,
m_renderData.SfcSrcChromaSiting);
finish:
return;
}
bool VphalSfcState::IsFormatSupported(
PVPHAL_SURFACE pSrcSurface,
PVPHAL_SURFACE pOutSurface,
PVPHAL_ALPHA_PARAMS pAlphaParams)
{
// Init to false for in case the input parameters are nullptr
bool ret = false;
VPHAL_RENDER_CHK_NULL_NO_STATUS(pSrcSurface);
VPHAL_RENDER_CHK_NULL_NO_STATUS(pOutSurface);
// Default to true
ret = true;
// Check if Input Format is supported
if (!IsInputFormatSupported(pSrcSurface))
{
VPHAL_RENDER_NORMALMESSAGE("Unsupported Source Format '0x%08x' for SFC.", pSrcSurface->Format);
ret = false;
return ret;
}
// SFC can not support fp16 output. HDR path is the only way to handle any fp16 output.
// Before entering into HDR path, it is possible that we need to use SFC to do P010->ARGB10.
// As for SFC is needed or not, we use bHDRSfc to decide.
if (pOutSurface->Format == Format_A16R16G16B16F ||
pOutSurface->Format == Format_A16B16G16R16F)
{
ret = false;
return ret;
}
// Check if Output Format is supported
if (!IsOutputFormatSupported(pOutSurface))
{
ret = false;
return ret;
}
// Check if the input/output combination is supported, given certain alpha fill mode.
// So far SFC only supports filling constant alpha.
if (pAlphaParams &&
pAlphaParams->AlphaMode == VPHAL_ALPHA_FILL_MODE_SOURCE_STREAM)
{
if ((pOutSurface->Format == Format_A8R8G8B8 ||
pOutSurface->Format == Format_A8B8G8R8 ||
pOutSurface->Format == Format_R10G10B10A2 ||
pOutSurface->Format == Format_B10G10R10A2 ||
pOutSurface->Format == Format_Y410 ||
pOutSurface->Format == Format_Y416 ||
pOutSurface->Format == Format_AYUV) &&
(pSrcSurface->Format == Format_A8B8G8R8 ||
pSrcSurface->Format == Format_A8R8G8B8 ||
pSrcSurface->Format == Format_Y410 ||
pSrcSurface->Format == Format_Y416 ||
pSrcSurface->Format == Format_AYUV))
{
ret = false;
}
}
finish:
return ret;
}
void VphalSfcState::FreeResources()
{
// Free AVS Line Buffer surface for SFC
m_osInterface->pfnFreeResource(
m_osInterface,
&m_AVSLineBufferSurface.OsResource);
// Free IEF Line Buffer surface for SFC
m_osInterface->pfnFreeResource(
m_osInterface,
&m_IEFLineBufferSurface.OsResource);
// Free SFD Line Buffer surface for SFC
m_osInterface->pfnFreeResource(
m_osInterface,
&m_SFDLineBufferSurface.OsResource);
return;
}
MOS_STATUS VphalSfcState::AllocateResources()
{
MOS_STATUS eStatus;
uint32_t dwWidth;
uint32_t dwHeight;
uint32_t dwSize;
bool bAllocated;
PMHW_SFC_STATE_PARAMS pSfcStateParams;
eStatus = MOS_STATUS_UNKNOWN;
bAllocated = false;
pSfcStateParams = m_renderData.SfcStateParams;
VPHAL_RENDER_CHK_NULL(pSfcStateParams);
// Allocate AVS Line Buffer surface----------------------------------------------
dwWidth = 1;
dwHeight = pSfcStateParams->dwInputFrameHeight * SFC_AVS_LINEBUFFER_SIZE_PER_VERTICAL_PIXEL;
dwSize = dwWidth * dwHeight;
VPHAL_RENDER_CHK_STATUS(VpHal_ReAllocateSurface(
m_osInterface,
&m_AVSLineBufferSurface,
"SfcAVSLineBufferSurface",
Format_Buffer,
MOS_GFXRES_BUFFER,
MOS_TILE_LINEAR,
dwSize,
1,
false,
MOS_MMC_DISABLED,
&bAllocated));
// Allocate IEF Line Buffer surface----------------------------------------------
dwWidth = 1;
dwHeight = pSfcStateParams->dwScaledRegionHeight * SFC_IEF_LINEBUFFER_SIZE_PER_VERTICAL_PIXEL;
dwSize = dwWidth * dwHeight;
VPHAL_RENDER_CHK_STATUS(VpHal_ReAllocateSurface(
m_osInterface,
&m_IEFLineBufferSurface,
"SfcIEFLineBufferSurface",
Format_Buffer,
MOS_GFXRES_BUFFER,
MOS_TILE_LINEAR,
dwSize,
1,
false,
MOS_MMC_DISABLED,
&bAllocated));
// Allocate SFD Line Buffer surface----------------------------------------------
if (NEED_SFD_LINE_BUFFER(pSfcStateParams->dwScaledRegionHeight))
{
dwSize = SFD_LINE_BUFFER_SIZE(pSfcStateParams->dwScaledRegionHeight);
VPHAL_RENDER_CHK_STATUS(VpHal_ReAllocateSurface(
m_osInterface,
&m_SFDLineBufferSurface,
"SfcSFDLineBufferSurface",
Format_Buffer,
MOS_GFXRES_BUFFER,
MOS_TILE_LINEAR,
dwSize,
1,
false,
MOS_MMC_DISABLED,
&bAllocated));
}
finish:
if (eStatus != MOS_STATUS_SUCCESS)
{
FreeResources();
}
return eStatus;
}
void VphalSfcState::GetOutputWidthHeightAlignUnit(
MOS_FORMAT outputFormat,
uint16_t &widthAlignUnit,
uint16_t &heightAlignUnit,
bool isInterlacedScaling)
{
widthAlignUnit = 1;
heightAlignUnit = 1;
switch (VpHal_GetSurfaceColorPack(outputFormat))
{
case VPHAL_COLORPACK_420:
widthAlignUnit = 2;
heightAlignUnit = 2;
break;
case VPHAL_COLORPACK_422:
widthAlignUnit = 2;
break;
default:
break;
}
}
void VphalSfcState::SetSfcStateInputOrderingMode(
PVPHAL_VEBOX_RENDER_DATA veboxRenderData,
PMHW_SFC_STATE_PARAMS sfcStateParams)
{
sfcStateParams->dwVDVEInputOrderingMode = MEDIASTATE_SFC_INPUT_ORDERING_VE_4x8;
}
MOS_STATUS VphalSfcState::SetSfcStateParams(
PVPHAL_VEBOX_RENDER_DATA pRenderData,
PVPHAL_SURFACE pSrcSurface,
PVPHAL_SURFACE pOutSurface)
{
MOS_STATUS eStatus;
PMOS_INTERFACE pOsInterface;
PMHW_SFC_STATE_PARAMS pSfcStateParams;
PVPHAL_ALPHA_PARAMS pAlphaParams;
VPHAL_COLOR_SAMPLE_8 Src;
VPHAL_CSPACE src_cspace, dst_cspace;
uint16_t wOutputWidthAlignUnit;
uint16_t wOutputHeightAlignUnit;
uint16_t wInputWidthAlignUnit;
uint16_t wInputHeightAlignUnit;
uint32_t dwSurfaceWidth;
uint32_t dwSurfaceHeight;
uint32_t dwVeboxBottom;
uint32_t dwVeboxRight;
VPHAL_GET_SURFACE_INFO Info;
VPHAL_COLORPACK dstColorPack;
VPHAL_RENDER_CHK_NULL(pSrcSurface);
VPHAL_RENDER_CHK_NULL(pOutSurface);
eStatus = MOS_STATUS_UNKNOWN;
pOsInterface = m_osInterface;
pSfcStateParams = m_renderData.SfcStateParams;
pAlphaParams = m_renderData.pAlphaParams;
wOutputWidthAlignUnit = 1;
wOutputHeightAlignUnit = 1;
wInputWidthAlignUnit = 1;
wInputHeightAlignUnit = 1;
dwVeboxBottom = (uint32_t)pSrcSurface->rcSrc.bottom;
dwVeboxRight = (uint32_t)pSrcSurface->rcSrc.right;
dstColorPack = VpHal_GetSurfaceColorPack(pOutSurface->Format);
VPHAL_RENDER_CHK_NULL(pSfcStateParams);
MOS_ZeroMemory(pSfcStateParams, sizeof(*pSfcStateParams));
pSfcStateParams->sfcPipeMode = MEDIASTATE_SFC_PIPE_VE_TO_SFC;
// Setup General params
// Set chroma subsampling type according to the Vebox output, but
// when Vebox is bypassed, set it according to the source surface format.
if (pRenderData->bIECP)
{
pSfcStateParams->dwInputChromaSubSampling = MEDIASTATE_SFC_CHROMA_SUBSAMPLING_444;
m_renderData.SfcSrcChromaSiting = MHW_CHROMA_SITING_HORZ_LEFT | MHW_CHROMA_SITING_VERT_TOP;
pSfcStateParams->b8tapChromafiltering = true;
}
else if (pRenderData->bDeinterlace)
{
pSfcStateParams->dwInputChromaSubSampling = MEDIASTATE_SFC_CHROMA_SUBSAMPLING_422H;
pSfcStateParams->b8tapChromafiltering = false;
}
else
{
if (m_renderData.SfcInputFormat == Format_NV12 ||
(m_renderData.SfcInputFormat == Format_P010) ||
(m_renderData.SfcInputFormat == Format_P016))
{
pSfcStateParams->dwInputChromaSubSampling = MEDIASTATE_SFC_CHROMA_SUBSAMPLING_420;
pSfcStateParams->b8tapChromafiltering = false;
}
else if (VpHal_GetSurfaceColorPack(m_renderData.SfcInputFormat) == VPHAL_COLORPACK_422)
{
pSfcStateParams->dwInputChromaSubSampling = MEDIASTATE_SFC_CHROMA_SUBSAMPLING_422H;
pSfcStateParams->b8tapChromafiltering = false;
}
else if (VpHal_GetSurfaceColorPack(m_renderData.SfcInputFormat) == VPHAL_COLORPACK_444)
{
pSfcStateParams->dwInputChromaSubSampling = MEDIASTATE_SFC_CHROMA_SUBSAMPLING_444;
pSfcStateParams->b8tapChromafiltering = true;
}
else
{
pSfcStateParams->dwInputChromaSubSampling = MEDIASTATE_SFC_CHROMA_SUBSAMPLING_400;
pSfcStateParams->b8tapChromafiltering = false;
}
}
// Default to Horizontal Left, Vertical Top
pSfcStateParams->dwChromaDownSamplingVerticalCoef = (pOutSurface->ChromaSiting & MHW_CHROMA_SITING_VERT_CENTER) ?
MEDIASTATE_SFC_CHROMA_DOWNSAMPLING_COEF_4_OVER_8 :
MEDIASTATE_SFC_CHROMA_DOWNSAMPLING_COEF_0_OVER_8;
pSfcStateParams->dwChromaDownSamplingHorizontalCoef = (pOutSurface->ChromaSiting & MHW_CHROMA_SITING_HORZ_CENTER) ?
MEDIASTATE_SFC_CHROMA_DOWNSAMPLING_COEF_4_OVER_8 :
MEDIASTATE_SFC_CHROMA_DOWNSAMPLING_COEF_0_OVER_8;
// Set the Pre-AVS chroma downsampling param according to SFC i/o chroma subsampling type
switch (pSfcStateParams->dwInputChromaSubSampling)
{
case MEDIASTATE_SFC_CHROMA_SUBSAMPLING_444:
if (dstColorPack == VPHAL_COLORPACK_420)
{
pSfcStateParams->dwChromaDownSamplingMode = MEDIASTATE_SFC_CHROMA_DOWNSAMPLING_444TO420;
}
else if (dstColorPack == VPHAL_COLORPACK_422)
{
pSfcStateParams->dwChromaDownSamplingMode = MEDIASTATE_SFC_CHROMA_DOWNSAMPLING_444TO422;
}
break;
case MEDIASTATE_SFC_CHROMA_SUBSAMPLING_422H:
if (dstColorPack == VPHAL_COLORPACK_420)
{
pSfcStateParams->dwChromaDownSamplingMode = MEDIASTATE_SFC_CHROMA_DOWNSAMPLING_422TO420;
}
break;
default:
pSfcStateParams->dwChromaDownSamplingMode = MEDIASTATE_SFC_CHROMA_DOWNSAMPLING_DISABLED;
break;
}
VPHAL_RENDER_NORMALMESSAGE("SfcStateParams: dwInputChromaSubSampling %d, b8tapChromafiltering %d, dwChromaDownSamplingMode %d.",
pSfcStateParams->dwInputChromaSubSampling,
pSfcStateParams->b8tapChromafiltering,
pSfcStateParams->dwChromaDownSamplingMode);
SetSfcStateInputOrderingMode(pRenderData, pSfcStateParams);
pSfcStateParams->OutputFrameFormat = pOutSurface->Format;
pSfcStateParams->fChromaSubSamplingXSiteOffset = 0.0F;
pSfcStateParams->fChromaSubSamplingYSiteOffset = 0.0F;
// Setup all parameters in SFC_STATE related to Scaling and AVS
pSfcStateParams->dwAVSFilterMode = (m_renderData.SfcScalingMode == VPHAL_SCALING_BILINEAR) ?
MEDIASTATE_SFC_AVS_FILTER_BILINEAR :
MEDIASTATE_SFC_AVS_FILTER_8x8;
// Get the SFC input surface size from Vebox
AdjustBoundary(
pSrcSurface,
&dwSurfaceWidth,
&dwSurfaceHeight);
// This should be set to the height and width of the frame streaming from Vebox
pSfcStateParams->dwInputFrameHeight = dwSurfaceHeight;
pSfcStateParams->dwInputFrameWidth = dwSurfaceWidth;
// Apply alignment restriction to the Region of the output frame.
GetOutputWidthHeightAlignUnit(
pSfcStateParams->OutputFrameFormat,
wOutputWidthAlignUnit,
wOutputHeightAlignUnit,
pSrcSurface->bInterlacedScaling);
// Apply alignment restriction to Region of the input frame.
GetInputWidthHeightAlignUnit(
m_renderData.SfcInputFormat,
pSfcStateParams->OutputFrameFormat,
wInputWidthAlignUnit,
wInputHeightAlignUnit);
if(pSrcSurface->bDirectionalScalar)
{
dwVeboxBottom *= 2;
dwVeboxRight *= 2;
}
// This should be set to the height and width of the Render Target
pSfcStateParams->dwOutputFrameHeight = MOS_ALIGN_CEIL(pOutSurface->dwHeight, wOutputHeightAlignUnit);
pSfcStateParams->dwOutputFrameWidth = MOS_ALIGN_CEIL(pOutSurface->dwWidth, wOutputWidthAlignUnit);
// Region of the input frame which needs to be processed by SFC
pSfcStateParams->dwSourceRegionVerticalOffset = MOS_ALIGN_CEIL((uint32_t)pSrcSurface->rcSrc.top, wInputHeightAlignUnit);
pSfcStateParams->dwSourceRegionHorizontalOffset = MOS_ALIGN_CEIL((uint32_t)pSrcSurface->rcSrc.left, wInputWidthAlignUnit);
pSfcStateParams->dwSourceRegionHeight = MOS_ALIGN_FLOOR(
MOS_MIN((uint32_t)(dwVeboxBottom - pSrcSurface->rcSrc.top), pSfcStateParams->dwInputFrameHeight),
wInputHeightAlignUnit);
pSfcStateParams->dwSourceRegionWidth = MOS_ALIGN_FLOOR(
MOS_MIN((uint32_t)(dwVeboxRight - pSrcSurface->rcSrc.left), pSfcStateParams->dwInputFrameWidth),
wInputWidthAlignUnit);
// Size of the Scaled Region over the Render Target
pSfcStateParams->dwScaledRegionHeight = MOS_ALIGN_CEIL(MOS_UF_ROUND(m_renderData.fScaleY * pSfcStateParams->dwSourceRegionHeight), wOutputHeightAlignUnit);
pSfcStateParams->dwScaledRegionWidth = MOS_ALIGN_CEIL(MOS_UF_ROUND(m_renderData.fScaleX * pSfcStateParams->dwSourceRegionWidth), wOutputWidthAlignUnit);
// Scaled region is pre-rotated. Adjust its width and height with those of the output frame
if (m_renderData.SfcRotation == VPHAL_ROTATION_IDENTITY ||
m_renderData.SfcRotation == VPHAL_ROTATION_180 ||
m_renderData.SfcRotation == VPHAL_MIRROR_HORIZONTAL ||
m_renderData.SfcRotation == VPHAL_MIRROR_VERTICAL)
{
pSfcStateParams->dwScaledRegionHeight = MOS_MIN(pSfcStateParams->dwScaledRegionHeight, pSfcStateParams->dwOutputFrameHeight);
pSfcStateParams->dwScaledRegionWidth = MOS_MIN(pSfcStateParams->dwScaledRegionWidth, pSfcStateParams->dwOutputFrameWidth);
}
else
{
pSfcStateParams->dwScaledRegionHeight = MOS_MIN(pSfcStateParams->dwScaledRegionHeight, pSfcStateParams->dwOutputFrameWidth);
pSfcStateParams->dwScaledRegionWidth = MOS_MIN(pSfcStateParams->dwScaledRegionWidth, pSfcStateParams->dwOutputFrameHeight);
}
// Refine the Scaling ratios in the X and Y direction. SFC output Scaled size may be changed based on the restriction of SFC alignment.
// The scaling ratio could be changed and not equal to the fScaleX/Y.
// Driver must make sure that the scaling ratio should be matched with the output/input size before send to HW
pSfcStateParams->fAVSXScalingRatio = (float)pSfcStateParams->dwScaledRegionWidth / (float)pSfcStateParams->dwSourceRegionWidth;
pSfcStateParams->fAVSYScalingRatio = (float)pSfcStateParams->dwScaledRegionHeight / (float)pSfcStateParams->dwSourceRegionHeight;
pSfcStateParams->dwScaledRegionVerticalOffset = MOS_ALIGN_FLOOR((uint32_t)pSrcSurface->rcDst.top, wOutputHeightAlignUnit);
pSfcStateParams->dwScaledRegionHorizontalOffset = MOS_ALIGN_FLOOR((uint32_t)pSrcSurface->rcDst.left, wOutputWidthAlignUnit);
// Enable Adaptive Filtering for YUV input only, if it is being upscaled
// in either direction. We must check for this before clamping the SF.
if (IS_YUV_FORMAT(m_renderData.SfcInputFormat) &&
(m_renderData.fScaleX > 1.0F ||
m_renderData.fScaleY > 1.0F))
{
pSfcStateParams->bBypassXAdaptiveFilter = false;
pSfcStateParams->bBypassYAdaptiveFilter = false;
}
else
{
pSfcStateParams->bBypassXAdaptiveFilter = true;
pSfcStateParams->bBypassYAdaptiveFilter = true;
}
if (IS_RGB_FORMAT(m_renderData.SfcInputFormat) &&
pSfcStateParams->b8tapChromafiltering == true)
{
pSfcStateParams->bRGBAdaptive = true;
}
else
{
pSfcStateParams->bRGBAdaptive = false;
}
pSfcStateParams->bAVSChromaUpsamplingEnable = (m_renderData.bScaling || m_renderData.bForcePolyPhaseCoefs);
// Rotation params
if (m_renderData.SfcRotation <= VPHAL_ROTATION_270)
{
// Rotation only
pSfcStateParams->RotationMode = VpHal_GetMhwRotationParam(m_renderData.SfcRotation);
pSfcStateParams->bMirrorEnable = false;
}
else if (m_renderData.SfcRotation <= VPHAL_MIRROR_VERTICAL)
{
// Mirror only
pSfcStateParams->dwMirrorType = VpHal_GetMhwRotationParam(m_renderData.SfcRotation) - 4;
pSfcStateParams->RotationMode = MHW_ROTATION_IDENTITY;
pSfcStateParams->bMirrorEnable = true;
}
else
{
// Rotation + Mirror
pSfcStateParams->dwMirrorType = MHW_MIRROR_HORIZONTAL;
pSfcStateParams->RotationMode = VpHal_GetMhwRotationParam(m_renderData.SfcRotation);
pSfcStateParams->bMirrorEnable = true;
}
VPHAL_RENDER_NORMALMESSAGE("SfcStateParams: dwMirrorType %d, RotationMode %d, bMirrorEnable %d.",
pSfcStateParams->dwMirrorType,
pSfcStateParams->RotationMode,
pSfcStateParams->bMirrorEnable);
// ColorFill params
if (m_renderData.bColorFill)
{
pSfcStateParams->bColorFillEnable = true;
Src.dwValue = m_renderData.pColorFillParams->Color;
src_cspace = m_renderData.pColorFillParams->CSpace;
dst_cspace = pOutSurface->ColorSpace;
// Convert BG color only if not done so before. CSC is expensive!
if ((m_colorFillColorSrc.dwValue != Src.dwValue) ||
(m_colorFillSrcCspace != src_cspace) ||
(m_colorFillRTCspace != dst_cspace))
{
// Clean history Dst BG Color if hit unsupported format
if (!VpHal_CSC_8(&m_colorFillColorDst, &Src, src_cspace, dst_cspace))
{
MOS_ZeroMemory(&m_colorFillColorDst, sizeof(m_colorFillColorDst));
}
// store the values for next iteration
m_colorFillColorSrc = Src;
m_colorFillSrcCspace = src_cspace;
m_colorFillRTCspace = dst_cspace;
}
if (IS_YUV_FORMAT(pOutSurface->Format) || IS_ALPHA_YUV_FORMAT(pOutSurface->Format))
{
pSfcStateParams->fColorFillYRPixel = (float)m_colorFillColorDst.Y / 255.0F;
pSfcStateParams->fColorFillUGPixel = (float)m_colorFillColorDst.U / 255.0F;
pSfcStateParams->fColorFillVBPixel = (float)m_colorFillColorDst.V / 255.0F;
}
else
{
// Swap the channel here because HW only natively supports XBGR output
if ((pOutSurface->Format == Format_A8R8G8B8) || (pOutSurface->Format == Format_X8R8G8B8) || (pOutSurface->Format == Format_R10G10B10A2))
{
pSfcStateParams->fColorFillYRPixel = (float)m_colorFillColorDst.B / 255.0F;
pSfcStateParams->fColorFillUGPixel = (float)m_colorFillColorDst.G / 255.0F;
pSfcStateParams->fColorFillVBPixel = (float)m_colorFillColorDst.R / 255.0F;
}
else
{
pSfcStateParams->fColorFillYRPixel = (float)m_colorFillColorDst.R / 255.0F;
pSfcStateParams->fColorFillUGPixel = (float)m_colorFillColorDst.G / 255.0F;
pSfcStateParams->fColorFillVBPixel = (float)m_colorFillColorDst.B / 255.0F;
}
}
pSfcStateParams->fColorFillAPixel = (float)Src.A / 255.0F;
}
if (pAlphaParams)
{
switch (pAlphaParams->AlphaMode)
{
case VPHAL_ALPHA_FILL_MODE_NONE:
if (pOutSurface->Format == Format_A8R8G8B8 ||
pOutSurface->Format == Format_A8B8G8R8 ||
pOutSurface->Format == Format_R10G10B10A2 ||
pOutSurface->Format == Format_B10G10R10A2 ||
pOutSurface->Format == Format_AYUV ||
pOutSurface->Format == Format_Y410 ||
pOutSurface->Format == Format_Y416)
{
pSfcStateParams->fAlphaPixel = pAlphaParams->fAlpha;
pSfcStateParams->fColorFillAPixel = pAlphaParams->fAlpha;
}
else
{
pSfcStateParams->fAlphaPixel = 1.0F;
}
break;
case VPHAL_ALPHA_FILL_MODE_BACKGROUND:
pSfcStateParams->fAlphaPixel = m_renderData.bColorFill ?
pSfcStateParams->fColorFillAPixel : 1.0F;
break;
case VPHAL_ALPHA_FILL_MODE_SOURCE_STREAM:
case VPHAL_ALPHA_FILL_MODE_OPAQUE:
default:
pSfcStateParams->fAlphaPixel = 1.0F;
pSfcStateParams->fColorFillAPixel = 1.0F;
}
}
else
{
pSfcStateParams->fAlphaPixel = 1.0F;
}
// CSC params
pSfcStateParams->bCSCEnable = m_renderData.bCSC;
// ARGB8,ABGR10 output format need to enable swap
if (pOutSurface->Format == Format_X8R8G8B8 ||
pOutSurface->Format == Format_A8R8G8B8 ||
pOutSurface->Format == Format_R10G10B10A2)
{
pSfcStateParams->bRGBASwapEnable = true;
}
else
{
pSfcStateParams->bRGBASwapEnable = false;
}
if (IS_RGB_CSPACE(pSrcSurface->ColorSpace))
{
pSfcStateParams->bInputColorSpace = true;
}
else
{
pSfcStateParams->bInputColorSpace = false;
}
VPHAL_RENDER_NORMALMESSAGE("SfcStateParams: bCSCEnable %d, bRGBASwapEnable %d, bMirrorEnable %d.",
pSfcStateParams->bCSCEnable,
pSfcStateParams->bRGBASwapEnable,
pSfcStateParams->bMirrorEnable);
// Set MMC status
VPHAL_RENDER_CHK_STATUS(SetSfcMmcStatus(
pRenderData,
pOutSurface,
pSfcStateParams));
VPHAL_RENDER_CHK_STATUS(AllocateResources());
// Set OS resources used by SFC state
pSfcStateParams->pOsResAVSLineBuffer = &m_AVSLineBufferSurface.OsResource;
pSfcStateParams->pOsResIEFLineBuffer = &m_IEFLineBufferSurface.OsResource;
pSfcStateParams->pOsResOutputSurface = &pOutSurface->OsResource;
MOS_ZeroMemory(&Info, sizeof(VPHAL_GET_SURFACE_INFO));
Info.S3dChannel = pOutSurface->Channel;
Info.ArraySlice = m_currentChannel;
VPHAL_RENDER_CHK_STATUS(VpHal_GetSurfaceInfo(
pOsInterface,
&Info,
pOutSurface));
pSfcStateParams->dwOutputSurfaceOffset = pOutSurface->YPlaneOffset.iSurfaceOffset;
pSfcStateParams->wOutputSurfaceUXOffset = (uint16_t) pOutSurface->UPlaneOffset.iXOffset;
pSfcStateParams->wOutputSurfaceUYOffset = (uint16_t) pOutSurface->UPlaneOffset.iYOffset;
pSfcStateParams->wOutputSurfaceVXOffset = (uint16_t) pOutSurface->VPlaneOffset.iXOffset;
pSfcStateParams->wOutputSurfaceVYOffset = (uint16_t) pOutSurface->VPlaneOffset.iYOffset;
finish:
return eStatus;
}
MOS_STATUS VphalSfcState::SetSfcMmcStatus(
PVPHAL_VEBOX_RENDER_DATA renderData,
PVPHAL_SURFACE outSurface,
PMHW_SFC_STATE_PARAMS sfcStateParams)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
if (IsFormatMMCSupported(outSurface->Format) && // SFC output MMC only support several format
(renderData->Component == COMPONENT_VPreP) && // SFC output MMC only enable in Vprep
(renderData->bEnableMMC == true) &&
(outSurface->bCompressible == true) &&
(outSurface->TileType == MOS_TILE_Y))
{
if ((m_renderData.fScaleX >= 0.5F) &&
(m_renderData.fScaleY >= 0.5F))
{
sfcStateParams->bMMCEnable = true;
sfcStateParams->MMCMode = MOS_MMC_HORIZONTAL;
}
else if ((m_renderData.fScaleX < 0.5F) &&
(m_renderData.fScaleY < 0.5F))
{
sfcStateParams->bMMCEnable = true;
sfcStateParams->MMCMode = MOS_MMC_VERTICAL;
}
else
{
sfcStateParams->bMMCEnable = false;
sfcStateParams->MMCMode = MOS_MMC_DISABLED;
}
VPHAL_RENDER_NORMALMESSAGE("SfcStateParams: bMMCEnable %d, MMCMode %d.",
sfcStateParams->bMMCEnable,
sfcStateParams->MMCMode);
// Set mmc status output surface for output surface
m_osInterface->pfnSetMemoryCompressionMode(m_osInterface, &outSurface->OsResource, MOS_MEMCOMP_STATE(sfcStateParams->MMCMode));
}
return eStatus;
}
MOS_STATUS VphalSfcState::SetAvsStateParams()
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
PMHW_SFC_AVS_STATE pMhwAvsState = nullptr;
MHW_SCALING_MODE scalingMode = MHW_SCALING_AVS;
bool bUse8x8Filter = false;
VPHAL_RENDER_CHK_NULL(m_sfcInterface);
pMhwAvsState = &m_avsState.AvsStateParams;
MOS_ZeroMemory(pMhwAvsState, sizeof(MHW_SFC_AVS_STATE));
if (m_renderData.bScaling ||
m_renderData.bForcePolyPhaseCoefs)
{
pMhwAvsState->dwInputHorizontalSiting = (m_renderData.SfcSrcChromaSiting & MHW_CHROMA_SITING_HORZ_CENTER) ? SFC_AVS_INPUT_SITING_COEF_4_OVER_8 : ((m_renderData.SfcSrcChromaSiting & MHW_CHROMA_SITING_HORZ_RIGHT) ? SFC_AVS_INPUT_SITING_COEF_8_OVER_8 : SFC_AVS_INPUT_SITING_COEF_0_OVER_8);
pMhwAvsState->dwInputVerticalSitting = (m_renderData.SfcSrcChromaSiting & MHW_CHROMA_SITING_VERT_CENTER) ? SFC_AVS_INPUT_SITING_COEF_4_OVER_8 : ((m_renderData.SfcSrcChromaSiting & MHW_CHROMA_SITING_VERT_BOTTOM) ? SFC_AVS_INPUT_SITING_COEF_8_OVER_8 : SFC_AVS_INPUT_SITING_COEF_0_OVER_8);
if (m_renderData.SfcSrcChromaSiting == MHW_CHROMA_SITING_NONE)
{
m_renderData.SfcSrcChromaSiting = MHW_CHROMA_SITING_HORZ_LEFT | MHW_CHROMA_SITING_VERT_TOP;
if (VpHal_GetSurfaceColorPack(m_renderData.SfcInputFormat) == VPHAL_COLORPACK_420) // For 420, default is Left & Center, else default is Left & Top
{
pMhwAvsState->dwInputVerticalSitting = SFC_AVS_INPUT_SITING_COEF_4_OVER_8;
}
}
m_renderData.pAvsParams->bForcePolyPhaseCoefs = m_renderData.bForcePolyPhaseCoefs;
scalingMode = VpHal_GetMhwScalingModeParam(m_renderData.SfcScalingMode);
VPHAL_RENDER_CHK_STATUS(m_sfcInterface->SetSfcAVSScalingMode(scalingMode));
if (m_renderData.SfcStateParams)
{
pMhwAvsState->dwAVSFilterMode = m_renderData.SfcStateParams->dwAVSFilterMode;
}
else
{
pMhwAvsState->dwAVSFilterMode = MEDIASTATE_SFC_AVS_FILTER_8x8;
}
if (pMhwAvsState->dwAVSFilterMode == MEDIASTATE_SFC_AVS_FILTER_8x8)
{
bUse8x8Filter = true;
}
VPHAL_RENDER_CHK_STATUS(m_sfcInterface->SetSfcSamplerTable(
&m_avsState.LumaCoeffs,
&m_avsState.ChromaCoeffs,
m_renderData.pAvsParams,
m_renderData.SfcInputFormat,
m_renderData.fScaleX,
m_renderData.fScaleY,
m_renderData.SfcSrcChromaSiting,
bUse8x8Filter,
0,
0));
}
finish:
return eStatus;
}
void VphalSfcState::SetIefStateCscParams(
PMHW_SFC_STATE_PARAMS sfcStateParams,
PMHW_SFC_IEF_STATE_PARAMS iefStateParams)
{
// Setup CSC params
if (m_renderData.bCSC)
{
sfcStateParams->bCSCEnable = true;
iefStateParams->bCSCEnable = true;
// Calculate matrix if not done so before. CSC is expensive!
if ((m_cscInputCspace != m_renderData.SfcInputCspace) ||
(m_cscRTCspace != m_renderData.pSfcPipeOutSurface->ColorSpace))
{
// Get the matrix to use for conversion
VpHal_GetCscMatrix(
m_renderData.SfcInputCspace,
m_renderData.pSfcPipeOutSurface->ColorSpace,
m_cscCoeff,
m_cscInOffset,
m_cscOutOffset);
// Store it for next BLT
m_cscInputCspace = m_renderData.SfcInputCspace;
m_cscRTCspace = m_renderData.pSfcPipeOutSurface->ColorSpace;
}
// Copy the values into IEF Params
iefStateParams->pfCscCoeff = m_cscCoeff;
iefStateParams->pfCscInOffset = m_cscInOffset;
iefStateParams->pfCscOutOffset = m_cscOutOffset;
}
}
void VphalSfcState::SetIefStateParams(
PVPHAL_VEBOX_RENDER_DATA veboxRenderData,
PMHW_SFC_STATE_PARAMS sfcStateParams,
PVPHAL_SURFACE inputSurface)
{
PMHW_SFC_IEF_STATE_PARAMS iefStateParams;
MOS_UNUSED(veboxRenderData);
VPHAL_RENDER_CHK_NULL_NO_STATUS(sfcStateParams);
VPHAL_RENDER_CHK_NULL_NO_STATUS(inputSurface);
iefStateParams = &m_renderData.IEFStateParams;
MOS_ZeroMemory(iefStateParams, sizeof(*iefStateParams));
// Setup IEF and STE params
if (m_renderData.bIEF)
{
Ief ief(
inputSurface);
ief.SetHwState(
sfcStateParams,
iefStateParams);
} // end of setup IEF and STE params
// Setup CSC params
SetIefStateCscParams(
sfcStateParams,
iefStateParams);
finish:
return;
}
MOS_STATUS VphalSfcState::UpdateRenderingFlags(
PVPHAL_SURFACE pSrcSurface,
PVPHAL_SURFACE pOutSurface,
PVPHAL_VEBOX_RENDER_DATA pRenderData)
{
MOS_STATUS eStatus;
MOS_UNUSED(pSrcSurface);
MOS_UNUSED(pOutSurface);
MOS_UNUSED(pRenderData);
eStatus = MOS_STATUS_SUCCESS;
return eStatus;
}
MOS_STATUS VphalSfcState::SetupSfcState(
PVPHAL_SURFACE pSrcSurface,
PVPHAL_SURFACE pOutSurface,
PVPHAL_VEBOX_RENDER_DATA pRenderData)
{
MOS_STATUS eStatus;
PMOS_INTERFACE pOsInterface;
PRENDERHAL_INTERFACE pRenderHal;
VPHAL_RENDER_CHK_NULL(pSrcSurface);
VPHAL_RENDER_CHK_NULL(pOutSurface);
VPHAL_RENDER_CHK_NULL(pRenderData);
eStatus = MOS_STATUS_UNKNOWN;
pOsInterface = m_osInterface;
pRenderHal = m_renderHal;
// Update SFC rendering flags if any
VPHAL_RENDER_CHK_STATUS(UpdateRenderingFlags(
pSrcSurface,
pOutSurface,
pRenderData));
// Setup params related to SFC_STATE
VPHAL_RENDER_CHK_STATUS(SetSfcStateParams(
pRenderData,
pSrcSurface,
pOutSurface));
// Setup params related to SFC_AVS_STATE
VPHAL_RENDER_CHK_STATUS(SetAvsStateParams());
// Setup params related to SFC_IEF_STATE
if (m_renderData.bIEF ||
m_renderData.bCSC)
{
SetIefStateParams(
pRenderData,
m_renderData.SfcStateParams,
pSrcSurface);
}
finish:
return eStatus;
}
MOS_STATUS VphalSfcState::SendSfcCmd(
PVPHAL_VEBOX_RENDER_DATA pRenderData,
PMOS_COMMAND_BUFFER pCmdBuffer)
{
PMHW_SFC_INTERFACE pSfcInterface;
MHW_SFC_LOCK_PARAMS SfcLockParams;
MOS_STATUS eStatus;
MHW_SFC_OUT_SURFACE_PARAMS OutSurfaceParam;
VPHAL_RENDER_CHK_NULL(m_sfcInterface);
VPHAL_RENDER_CHK_NULL(m_osInterface);
VPHAL_RENDER_CHK_NULL(pRenderData);
VPHAL_RENDER_CHK_NULL(pCmdBuffer);
eStatus = MOS_STATUS_SUCCESS;
pSfcInterface = m_sfcInterface;
// Ensure VEBOX can write
m_osInterface->pfnSyncOnResource(
m_osInterface,
&m_renderData.pSfcPipeOutSurface->OsResource,
MOS_GPU_CONTEXT_VEBOX,
true);
if (m_renderData.pSfcPipeOutSurface->bOverlay)
{
m_osInterface->pfnSyncOnOverlayResource(
m_osInterface,
&m_renderData.pSfcPipeOutSurface->OsResource,
MOS_GPU_CONTEXT_VEBOX);
}
// Setup params for SFC Lock command
SfcLockParams.sfcPipeMode = MhwSfcInterface::SFC_PIPE_MODE_VEBOX;
SfcLockParams.bOutputToMemory = (pRenderData->bDeinterlace || pRenderData->bDenoise);
// Send SFC_LOCK command to acquire SFC pipe for Vebox
VPHAL_RENDER_CHK_STATUS(pSfcInterface->AddSfcLock(
pCmdBuffer,
&SfcLockParams));
VPHAL_RENDER_CHK_STATUS(VpHal_InitMhwOutSurfParams(
m_renderData.pSfcPipeOutSurface,
&OutSurfaceParam));
// Send SFC MMCD cmd
VPHAL_RENDER_CHK_STATUS(RenderSfcMmcCMD(
pSfcInterface,
m_renderHal->pMhwMiInterface,
m_osInterface,
&OutSurfaceParam,
pCmdBuffer));
// Send SFC_STATE command
VPHAL_RENDER_CHK_STATUS(pSfcInterface->AddSfcState(
pCmdBuffer,
m_renderData.SfcStateParams,
&OutSurfaceParam));
// Send SFC_AVS_STATE command
VPHAL_RENDER_CHK_STATUS(pSfcInterface->AddSfcAvsState(
pCmdBuffer,
&m_avsState.AvsStateParams));
if (m_renderData.bScaling ||
m_renderData.bForcePolyPhaseCoefs)
{
// Send SFC_AVS_LUMA_TABLE command
VPHAL_RENDER_CHK_STATUS(pSfcInterface->AddSfcAvsLumaTable(
pCmdBuffer,
&m_avsState.LumaCoeffs));
// Send SFC_AVS_CHROMA_TABLE command
VPHAL_RENDER_CHK_STATUS(pSfcInterface->AddSfcAvsChromaTable(
pCmdBuffer,
&m_avsState.ChromaCoeffs));
}
// Send SFC_IEF_STATE command
if (m_renderData.bIEF || m_renderData.bCSC)
{
VPHAL_RENDER_CHK_STATUS(pSfcInterface->AddSfcIefState(
pCmdBuffer,
&m_renderData.IEFStateParams));
}
// Send SFC_FRAME_START command to start processing a frame
VPHAL_RENDER_CHK_STATUS(pSfcInterface->AddSfcFrameStart(
pCmdBuffer,
MhwSfcInterface::SFC_PIPE_MODE_VEBOX));
finish:
return eStatus;
}
#endif // __VPHAL_SFC_SUPPORTED