/* * Copyright (c) 2014-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 codechal_decode_sfc.cpp //! \brief Implements the decode interface extension for CSC and scaling via SFC. //! \details Downsampling in this case is supported by the SFC fixed function HW unit. //! #include "codechal_decode_sfc.h" #include "codechal_decoder.h" MOS_STATUS CodechalSfcState::AllocateResources() { MOS_STATUS eStatus = MOS_STATUS_SUCCESS; CODECHAL_HW_FUNCTION_ENTER; if (MhwSfcInterface::SFC_PIPE_MODE_VEBOX == m_sfcPipeMode) { CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnCreateSyncResource(m_osInterface, &m_resSyncObject)); } // Allocate AVS line buffer if (Mos_ResourceIsNull(&m_resAvsLineBuffer)) { MOS_ALLOC_GFXRES_PARAMS allocParamsForBufferLinear; MOS_ZeroMemory(&allocParamsForBufferLinear, sizeof(MOS_ALLOC_GFXRES_PARAMS)); allocParamsForBufferLinear.Type = MOS_GFXRES_BUFFER; allocParamsForBufferLinear.TileType = MOS_TILE_LINEAR; allocParamsForBufferLinear.Format = Format_Buffer; if (MhwSfcInterface::SFC_PIPE_MODE_VEBOX == m_sfcPipeMode) { allocParamsForBufferLinear.dwBytes = MOS_ROUNDUP_DIVIDE(m_inputSurface->dwHeight, 8) * 5 * MHW_SFC_CACHELINE_SIZE; } else { allocParamsForBufferLinear.dwBytes = MOS_ROUNDUP_DIVIDE(m_inputSurface->dwWidth, 8) * 3 * MHW_SFC_CACHELINE_SIZE; } allocParamsForBufferLinear.pBufName = "SfcAvsLineBuffer"; eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource( m_osInterface, &allocParamsForBufferLinear, &m_resAvsLineBuffer); if (eStatus != MOS_STATUS_SUCCESS) { CODECHAL_DECODE_ASSERTMESSAGE("Failed to allocate Sfc Avs Line Buffer."); return eStatus; } } // Allocate IEF line buffer //Initialize AVS parameters, try to do once if (m_scaling && !m_avsParams.piYCoefsX) { m_avsParams.Format = Format_None; m_avsParams.fScaleX = 0.0F; m_avsParams.fScaleY = 0.0F; m_avsParams.piYCoefsX = nullptr; uint32_t ycoeffTableSize = POLYPHASE_Y_COEFFICIENT_TABLE_SIZE_G9; uint32_t uvcoeffTableSize = POLYPHASE_UV_COEFFICIENT_TABLE_SIZE_G9; int32_t size = (ycoeffTableSize + uvcoeffTableSize) * 2; uint8_t *ptr = (uint8_t*)MOS_AllocAndZeroMemory(size); if (ptr == nullptr) { CODECHAL_DECODE_ASSERTMESSAGE("No memory to allocate AVS coefficient tables."); eStatus = MOS_STATUS_NO_SPACE; return eStatus; } m_avsParams.piYCoefsX = (int32_t *)ptr; ptr += ycoeffTableSize; m_avsParams.piUVCoefsX = (int32_t *)ptr; ptr += uvcoeffTableSize; m_avsParams.piYCoefsY = (int32_t *)ptr; ptr += ycoeffTableSize; m_avsParams.piUVCoefsY = (int32_t *)ptr; } return eStatus; } CodechalSfcState::~CodechalSfcState() { CODECHAL_HW_FUNCTION_ENTER; if (MhwSfcInterface::SFC_PIPE_MODE_VEBOX == m_sfcPipeMode) { m_osInterface->pfnDestroySyncResource(m_osInterface, &m_resSyncObject); } // Free AVS Line Buffer m_osInterface->pfnFreeResource(m_osInterface, &m_resAvsLineBuffer); // Free resLaceOrAceOrRgbHistogram m_osInterface->pfnFreeResource(m_osInterface, &m_resLaceOrAceOrRgbHistogram); // Free resStatisticsOutput m_osInterface->pfnFreeResource(m_osInterface, &m_resStatisticsOutput); // Free buffers in AVS parameters MOS_FreeMemory(m_avsParams.piYCoefsX); m_avsParams.piYCoefsX = nullptr; } MOS_STATUS CodechalSfcState::SetVeboxStateParams( PMHW_VEBOX_STATE_CMD_PARAMS veboxCmdParams) { MOS_STATUS eStatus = MOS_STATUS_SUCCESS; CODECHAL_HW_FUNCTION_ENTER; veboxCmdParams->bNoUseVeboxHeap = 1; veboxCmdParams->VeboxMode.ColorGamutExpansionEnable = 0; veboxCmdParams->VeboxMode.ColorGamutCompressionEnable = 0; // On SKL, GlobalIECP must be enabled when the output pipe is Vebox or SFC veboxCmdParams->VeboxMode.GlobalIECPEnable = 1; veboxCmdParams->VeboxMode.DNEnable = 0; veboxCmdParams->VeboxMode.DIEnable = 0; veboxCmdParams->VeboxMode.DNDIFirstFrame = 0; veboxCmdParams->VeboxMode.DIOutputFrames = 0; veboxCmdParams->VeboxMode.PipeSynchronizeDisable = 0; veboxCmdParams->VeboxMode.DemosaicEnable = 0; veboxCmdParams->VeboxMode.VignetteEnable = 0; veboxCmdParams->VeboxMode.AlphaPlaneEnable = 0; veboxCmdParams->VeboxMode.HotPixelFilteringEnable = 0; // 0-both slices enabled 1-Slice 0 enabled 2-Slice 1 enabled // On SKL GT3 and GT4, there are 2 Veboxes. But only Vebox0 can be used,Vebox1 cannot be used veboxCmdParams->VeboxMode.SingleSliceVeboxEnable = 1; veboxCmdParams->VeboxMode.LACECorrectionEnable = 0; veboxCmdParams->VeboxMode.DisableEncoderStatistics = 1; veboxCmdParams->VeboxMode.DisableTemporalDenoiseFilter = 1; veboxCmdParams->VeboxMode.SinglePipeIECPEnable = 0; veboxCmdParams->VeboxMode.SFCParallelWriteEnable = 0; veboxCmdParams->VeboxMode.ScalarMode = 0; veboxCmdParams->VeboxMode.ForwardGammaCorrectionEnable = 0; return eStatus; } MOS_STATUS CodechalSfcState::SetVeboxSurfaceStateParams( PMHW_VEBOX_SURFACE_STATE_CMD_PARAMS veboxSurfParams) { MOS_STATUS eStatus = MOS_STATUS_SUCCESS; CODECHAL_HW_FUNCTION_ENTER; // Initialize SurfInput veboxSurfParams->SurfInput.bActive = true; veboxSurfParams->SurfInput.Format = m_inputSurface->Format; veboxSurfParams->SurfInput.dwWidth = m_inputSurface->dwWidth; veboxSurfParams->SurfInput.dwHeight = m_inputSurface->UPlaneOffset.iYOffset; // For Planar formats, pParams->SurfInput.dwHeight will be assigned to VEBOX U.Y offset, which is only used for PLANAR surface formats. veboxSurfParams->SurfInput.dwUYoffset = m_inputSurface->UPlaneOffset.iYOffset; veboxSurfParams->SurfInput.dwPitch = m_inputSurface->dwPitch; veboxSurfParams->SurfInput.TileType = m_inputSurface->TileType; veboxSurfParams->SurfInput.TileModeGMM = m_inputSurface->TileModeGMM; veboxSurfParams->SurfInput.bGMMTileEnabled = m_inputSurface->bGMMTileEnabled; veboxSurfParams->SurfInput.pOsResource = &m_inputSurface->OsResource; veboxSurfParams->SurfInput.rcMaxSrc.left = 0; veboxSurfParams->SurfInput.rcMaxSrc.top = 0; veboxSurfParams->SurfInput.rcMaxSrc.right = MOS_ALIGN_CEIL(m_inputSurface->dwWidth, m_sfcInterface->m_veWidthAlignment); veboxSurfParams->SurfInput.rcMaxSrc.bottom = MOS_ALIGN_CEIL(m_inputSurface->dwHeight, m_sfcInterface->m_veHeightAlignment); // Initialize SurfSTMM veboxSurfParams->SurfSTMM.dwPitch = m_inputSurface->dwPitch; veboxSurfParams->bDIEnable = false; veboxSurfParams->bOutputValid = (m_veboxOutputSurface != nullptr) ? true : false; return eStatus; } MOS_STATUS CodechalSfcState::SetVeboxDiIecpParams( PMHW_VEBOX_DI_IECP_CMD_PARAMS veboxDiIecpParams) { uint32_t size = 0; MOS_STATUS eStatus = MOS_STATUS_SUCCESS; CODECHAL_HW_FUNCTION_ENTER; uint32_t height = m_inputSurface->dwHeight; uint32_t width = m_inputSurface->dwWidth; veboxDiIecpParams->dwStartingX = 0; veboxDiIecpParams->dwEndingX = width - 1; veboxDiIecpParams->dwCurrInputSurfOffset = m_inputSurface->dwOffset; veboxDiIecpParams->pOsResCurrInput = &m_inputSurface->OsResource; veboxDiIecpParams->CurrInputSurfCtrl.Value = 0; //Keep it here untill VPHAL moving to new CMD definition and remove this parameter definition. CodecHalGetResourceInfo( m_osInterface, m_inputSurface); veboxDiIecpParams->CurInputSurfMMCState = (MOS_MEMCOMP_STATE)(m_inputSurface->CompressionMode); // Allocate Resource to avoid Page Fault issue since HW will access it if (Mos_ResourceIsNull(&m_resLaceOrAceOrRgbHistogram)) { m_hwInterface->GetHcpInterface()->GetOsResLaceOrAceOrRgbHistogramBufferSize( width, height, &size); MOS_ALLOC_GFXRES_PARAMS allocParamsForBufferLinear; MOS_ZeroMemory(&allocParamsForBufferLinear, sizeof(MOS_ALLOC_GFXRES_PARAMS)); allocParamsForBufferLinear.Type = MOS_GFXRES_BUFFER; allocParamsForBufferLinear.TileType = MOS_TILE_LINEAR; allocParamsForBufferLinear.Format = Format_Buffer; allocParamsForBufferLinear.dwBytes = size; allocParamsForBufferLinear.pBufName = "ResLaceOrAceOrRgbHistogram"; m_osInterface->pfnAllocateResource( m_osInterface, &allocParamsForBufferLinear, &m_resLaceOrAceOrRgbHistogram); } veboxDiIecpParams->pOsResLaceOrAceOrRgbHistogram = &m_resLaceOrAceOrRgbHistogram; // Allocate Resource to avoid Page Fault issue since HW will access it if (Mos_ResourceIsNull(&m_resStatisticsOutput)) { m_hwInterface->GetHcpInterface()->GetOsResStatisticsOutputBufferSize( width, height, &size); MOS_ALLOC_GFXRES_PARAMS allocParamsForBufferLinear; MOS_ZeroMemory(&allocParamsForBufferLinear, sizeof(MOS_ALLOC_GFXRES_PARAMS)); allocParamsForBufferLinear.Type = MOS_GFXRES_BUFFER; allocParamsForBufferLinear.TileType = MOS_TILE_LINEAR; allocParamsForBufferLinear.Format = Format_Buffer; allocParamsForBufferLinear.dwBytes = size; allocParamsForBufferLinear.pBufName = "ResStatisticsOutput"; m_osInterface->pfnAllocateResource( m_osInterface, &allocParamsForBufferLinear, &m_resStatisticsOutput); } veboxDiIecpParams->pOsResStatisticsOutput = &m_resStatisticsOutput; return eStatus; } MOS_STATUS CodechalSfcState::SetSfcStateParams( PMHW_SFC_STATE_PARAMS sfcStateParams, PMHW_SFC_OUT_SURFACE_PARAMS outSurfaceParams) { MOS_STATUS eStatus = MOS_STATUS_SUCCESS; CODECHAL_HW_FUNCTION_ENTER; CODECHAL_HW_CHK_NULL_RETURN(sfcStateParams); CODECHAL_HW_CHK_STATUS_RETURN(UpdateInputInfo(sfcStateParams)); sfcStateParams->sfcPipeMode = m_sfcPipeMode; sfcStateParams->dwChromaDownSamplingMode = MEDIASTATE_SFC_CHROMA_DOWNSAMPLING_DISABLED; // IN: NV12 sfcStateParams->bAVSChromaUpsamplingEnable = m_scaling; if ((sfcStateParams->fAVSXScalingRatio > 1.0F) || (sfcStateParams->fAVSYScalingRatio > 1.0F)) { sfcStateParams->bBypassXAdaptiveFilter = false; sfcStateParams->bBypassYAdaptiveFilter = false; } else { sfcStateParams->bBypassXAdaptiveFilter = true; sfcStateParams->bBypassYAdaptiveFilter = true; } sfcStateParams->fChromaSubSamplingXSiteOffset = 0.0F; sfcStateParams->fChromaSubSamplingYSiteOffset = 0.0F; uint16_t widthAlignUnit = 1; uint16_t heightAlignUnit = 1; CODECHAL_DECODE_CHK_STATUS_RETURN(CodecHalGetResourceInfo( m_osInterface, m_sfcOutputSurface)); switch (m_sfcOutputSurface->Format) { case Format_NV12: case Format_P010: widthAlignUnit = 2; heightAlignUnit = 2; break; case Format_YUY2: case Format_UYVY: widthAlignUnit = 2; break; default: break; } // Default to Horizontal Left, Vertical Top sfcStateParams->dwChromaDownSamplingHorizontalCoef = (m_chromaSiting & MHW_CHROMA_SITING_HORZ_CENTER) ? MEDIASTATE_SFC_CHROMA_DOWNSAMPLING_COEF_4_OVER_8 : ((m_chromaSiting & MHW_CHROMA_SITING_HORZ_RIGHT) ? MEDIASTATE_SFC_CHROMA_DOWNSAMPLING_COEF_8_OVER_8 : MEDIASTATE_SFC_CHROMA_DOWNSAMPLING_COEF_0_OVER_8); sfcStateParams->dwChromaDownSamplingVerticalCoef = (m_chromaSiting & MHW_CHROMA_SITING_VERT_CENTER) ? MEDIASTATE_SFC_CHROMA_DOWNSAMPLING_COEF_4_OVER_8 : ((m_chromaSiting & MHW_CHROMA_SITING_VERT_BOTTOM) ? MEDIASTATE_SFC_CHROMA_DOWNSAMPLING_COEF_8_OVER_8 : MEDIASTATE_SFC_CHROMA_DOWNSAMPLING_COEF_0_OVER_8); outSurfaceParams->dwWidth = m_sfcOutputSurface->dwWidth; outSurfaceParams->dwHeight = m_sfcOutputSurface->dwHeight; outSurfaceParams->dwPitch = m_sfcOutputSurface->dwPitch; outSurfaceParams->TileType = m_sfcOutputSurface->TileType; outSurfaceParams->ChromaSiting = m_chromaSiting; outSurfaceParams->dwUYoffset = m_sfcOutputSurface->UPlaneOffset.iYOffset; outSurfaceParams->TileModeGMM = m_sfcOutputSurface->TileModeGMM; outSurfaceParams->bGMMTileEnabled = m_sfcOutputSurface->bGMMTileEnabled; sfcStateParams->dwOutputFrameWidth = MOS_ALIGN_CEIL(m_sfcOutputSurface->dwWidth, widthAlignUnit); sfcStateParams->dwOutputFrameHeight = MOS_ALIGN_CEIL(m_sfcOutputSurface->dwHeight, heightAlignUnit); sfcStateParams->OutputFrameFormat = m_sfcOutputSurface->Format; sfcStateParams->dwOutputSurfaceOffset = m_sfcOutputSurface->dwOffset; sfcStateParams->pOsResOutputSurface = &m_sfcOutputSurface->OsResource; sfcStateParams->pOsResAVSLineBuffer = &m_resAvsLineBuffer; sfcStateParams->dwSourceRegionHeight = MOS_ALIGN_FLOOR(m_inputSurfaceRegion.m_height, heightAlignUnit); sfcStateParams->dwSourceRegionWidth = MOS_ALIGN_FLOOR(m_inputSurfaceRegion.m_width, widthAlignUnit); sfcStateParams->dwSourceRegionVerticalOffset = MOS_ALIGN_CEIL(m_inputSurfaceRegion.m_y, heightAlignUnit); sfcStateParams->dwSourceRegionHorizontalOffset = MOS_ALIGN_CEIL(m_inputSurfaceRegion.m_x, widthAlignUnit); sfcStateParams->dwScaledRegionHeight = MOS_ALIGN_CEIL(m_outputSurfaceRegion.m_height, heightAlignUnit); sfcStateParams->dwScaledRegionWidth = MOS_ALIGN_CEIL(m_outputSurfaceRegion.m_width, widthAlignUnit); sfcStateParams->dwScaledRegionVerticalOffset = MOS_ALIGN_FLOOR(m_outputSurfaceRegion.m_y, heightAlignUnit); sfcStateParams->dwScaledRegionHorizontalOffset = MOS_ALIGN_FLOOR(m_outputSurfaceRegion.m_x, widthAlignUnit); sfcStateParams->fAVSXScalingRatio = m_scaleX; sfcStateParams->fAVSYScalingRatio = m_scaleY; sfcStateParams->fAlphaPixel = 1.0F; sfcStateParams->bColorFillEnable = m_colorFill; sfcStateParams->bCSCEnable = m_csc; // ARGB8,ABGR10 output format need to enable swap if (m_sfcOutputSurface->Format == Format_X8R8G8B8 || m_sfcOutputSurface->Format == Format_A8R8G8B8 || m_sfcOutputSurface->Format == Format_R10G10B10A2) { sfcStateParams->bRGBASwapEnable = true; } else { sfcStateParams->bRGBASwapEnable = false; } // CodecHal does not support SFC rotation sfcStateParams->RotationMode = MHW_ROTATION_IDENTITY; // For downsampling, expect output surface to be MMC disabled // For Jpeg, the only usage is CSC and the output surface format is RGB8, so also disable MMC sfcStateParams->bMMCEnable = false; sfcStateParams->MMCMode = MOS_MMC_DISABLED; return eStatus; } MOS_STATUS CodechalSfcState::SetSfcAvsStateParams() { MOS_STATUS eStatus = MOS_STATUS_SUCCESS; CODECHAL_HW_FUNCTION_ENTER; PMHW_SFC_AVS_STATE mhwSfcAvsState = &m_avsState; if (m_chromaSiting == MHW_CHROMA_SITING_NONE) { m_chromaSiting = MHW_CHROMA_SITING_HORZ_LEFT | MHW_CHROMA_SITING_VERT_CENTER; } mhwSfcAvsState->sfcPipeMode = m_sfcPipeMode; mhwSfcAvsState->dwInputHorizontalSiting = (m_chromaSiting & MHW_CHROMA_SITING_HORZ_CENTER) ? SFC_AVS_INPUT_SITING_COEF_4_OVER_8 : ((m_chromaSiting & MHW_CHROMA_SITING_HORZ_RIGHT) ? SFC_AVS_INPUT_SITING_COEF_8_OVER_8 : SFC_AVS_INPUT_SITING_COEF_0_OVER_8); mhwSfcAvsState->dwInputVerticalSitting = (m_chromaSiting & MHW_CHROMA_SITING_VERT_CENTER) ? SFC_AVS_INPUT_SITING_COEF_4_OVER_8 : ((m_chromaSiting & MHW_CHROMA_SITING_VERT_BOTTOM) ? SFC_AVS_INPUT_SITING_COEF_8_OVER_8 : SFC_AVS_INPUT_SITING_COEF_0_OVER_8); CODECHAL_HW_CHK_STATUS_RETURN(m_sfcInterface->SetSfcSamplerTable( &m_lumaTable, &m_chromaTable, &m_avsParams, m_inputSurface->Format, m_scaleX, m_scaleY, m_chromaSiting, (m_sfcPipeMode != MhwSfcInterface::SFC_PIPE_MODE_VDBOX) ? true : false, 0, 0)); m_lumaTable.sfcPipeMode = m_sfcPipeMode; m_chromaTable.sfcPipeMode = m_sfcPipeMode; return eStatus; } MOS_STATUS CodechalSfcState::SetSfcIefStateParams( PMHW_SFC_IEF_STATE_PARAMS iefStateParams) { MOS_STATUS eStatus = MOS_STATUS_SUCCESS; CODECHAL_HW_FUNCTION_ENTER; CODECHAL_HW_CHK_NULL_RETURN(iefStateParams); iefStateParams->sfcPipeMode = m_sfcPipeMode; iefStateParams->bIEFEnable = false; iefStateParams->bCSCEnable = true; iefStateParams->pfCscCoeff = m_cscCoeff; iefStateParams->pfCscInOffset = m_cscInOffset; iefStateParams->pfCscOutOffset = m_cscOutOffset; return eStatus; } MOS_STATUS CodechalSfcState::Initialize( DecodeProcessingParams *decodeProcParams, uint8_t sfcPipeMode) { MOS_STATUS eStatus = MOS_STATUS_SUCCESS; CODECHAL_HW_FUNCTION_ENTER; CODECHAL_HW_CHK_NULL_RETURN(m_decoder); CODECHAL_HW_CHK_NULL_RETURN(decodeProcParams); CODECHAL_HW_CHK_NULL_RETURN(decodeProcParams->m_inputSurface); CODECHAL_HW_CHK_NULL_RETURN(decodeProcParams->m_outputSurface); m_sfcPipeMode = sfcPipeMode; m_inputSurface = decodeProcParams->m_inputSurface; // Vebox o/p should not be written to memory for SFC, VeboxOutputSurface should be nullptr m_veboxOutputSurface = nullptr; m_sfcOutputSurface = decodeProcParams->m_outputSurface; uint16_t widthAlignUnit = 1; uint16_t heightAlignUnit = 1; switch (m_sfcOutputSurface->Format) { case Format_NV12: widthAlignUnit = 2; heightAlignUnit = 2; break; case Format_YUY2: case Format_UYVY: widthAlignUnit = 2; break; default: break; } // Calculate bScaling uint32_t sourceRegionWidth = MOS_ALIGN_FLOOR(decodeProcParams->m_inputSurfaceRegion.m_width, widthAlignUnit); uint32_t sourceRegionHeight = MOS_ALIGN_FLOOR(decodeProcParams->m_inputSurfaceRegion.m_height, heightAlignUnit); uint32_t outputRegionWidth = MOS_ALIGN_CEIL(decodeProcParams->m_outputSurfaceRegion.m_width, widthAlignUnit); uint32_t outputRegionHeight = MOS_ALIGN_CEIL(decodeProcParams->m_outputSurfaceRegion.m_height, heightAlignUnit); m_scaleX = (float)outputRegionWidth / (float)sourceRegionWidth; m_scaleY = (float)outputRegionHeight / (float)sourceRegionHeight; m_scaling = ((m_scaleX == 1.0F) && (m_scaleY == 1.0F)) ? false : true; m_colorFill = false; if (decodeProcParams->m_outputSurface->Format == Format_A8R8G8B8) { m_csc = true; } if (m_jpegInUse && m_jpegChromaType == jpegBGR) { m_csc = false; } if (m_csc) { if (m_jpegInUse && m_jpegChromaType == jpegRGB) { m_cscCoeff[0] = 1.000000000f; m_cscCoeff[1] = 0.000000000f; m_cscCoeff[2] = 0.000000000f; m_cscCoeff[3] = 0.000000000f; m_cscCoeff[4] = 1.000000000f; m_cscCoeff[5] = 0.000000000f; m_cscCoeff[6] = 0.000000000f; m_cscCoeff[7] = 0.000000000f; m_cscCoeff[8] = 1.000000000f; m_cscInOffset[0] = 0.000000000f; // Adjusted to S8.2 to accommodate VPHAL m_cscInOffset[1] = 0.000000000f; // Adjusted to S8.2 to accommodate VPHAL m_cscInOffset[2] = 0.000000000f; // Adjusted to S8.2 to accommodate VPHAL } else { if (m_inputSurface->Format != Format_400P) { m_cscCoeff[0] = 1.16438353f; m_cscCoeff[1] = 0.000000000f; m_cscCoeff[2] = 1.59602666f; m_cscCoeff[3] = 1.16438353f; m_cscCoeff[4] = -0.391761959f; m_cscCoeff[5] = -0.812967300f; m_cscCoeff[6] = 1.16438353f; m_cscCoeff[7] = 2.01723218f; m_cscCoeff[8] = 0.000000000f; } else { m_cscCoeff[0] = 1.16438353f; m_cscCoeff[1] = 0.000000000f; m_cscCoeff[2] = 0.000000000f; m_cscCoeff[3] = 1.16438353f; m_cscCoeff[4] = 0.000000000f; m_cscCoeff[5] = 0.000000000f; m_cscCoeff[6] = 1.16438353f; m_cscCoeff[7] = 0.000000000f; m_cscCoeff[8] = 0.000000000f; } m_cscInOffset[0] = -16.000000f; // Adjusted to S8.2 to accommodate VPHAL m_cscInOffset[1] = -128.000000f; // Adjusted to S8.2 to accommodate VPHAL m_cscInOffset[2] = -128.000000f; // Adjusted to S8.2 to accommodate VPHAL } m_cscOutOffset[0] = 0.000000000f; // Adjusted to S8.2 to accommodate VPHAL m_cscOutOffset[1] = 0.000000000f; // Adjusted to S8.2 to accommodate VPHAL m_cscOutOffset[2] = 0.000000000f; // Adjusted to S8.2 to accommodate VPHAL } m_chromaSiting = decodeProcParams->m_chromaSitingType; m_rotationMode = decodeProcParams->m_rotationState; eStatus = MOS_SecureMemcpy(&m_inputSurfaceRegion, sizeof(m_inputSurfaceRegion), &decodeProcParams->m_inputSurfaceRegion, sizeof(decodeProcParams->m_inputSurfaceRegion)); eStatus = MOS_SecureMemcpy(&m_outputSurfaceRegion, sizeof(m_outputSurfaceRegion), &decodeProcParams->m_outputSurfaceRegion, sizeof(decodeProcParams->m_outputSurfaceRegion)); CODECHAL_HW_CHK_STATUS_RETURN(AllocateResources()); if (MhwSfcInterface::SFC_PIPE_MODE_VEBOX == sfcPipeMode) { // Create VEBOX Context MOS_GPUCTX_CREATOPTIONS createOption; CODECHAL_HW_CHK_STATUS_RETURN(m_osInterface->pfnCreateGpuContext( m_osInterface, MOS_GPU_CONTEXT_VEBOX, MOS_GPU_NODE_VE, &createOption)); // Register Vebox GPU context with the Batch Buffer completion event // Ignore if creation fails CODECHAL_HW_CHK_STATUS_RETURN(m_osInterface->pfnRegisterBBCompleteNotifyEvent( m_osInterface, MOS_GPU_CONTEXT_VEBOX)); } return eStatus; } MOS_STATUS CodechalSfcState::AddSfcCommands( PMOS_COMMAND_BUFFER cmdBuffer) { MOS_STATUS eStatus = MOS_STATUS_SUCCESS; CODECHAL_HW_FUNCTION_ENTER; CODECHAL_HW_CHK_NULL_RETURN(cmdBuffer); if (m_sfcPipeOut == false) { return eStatus; } MHW_SFC_LOCK_PARAMS sfcLockParams; MOS_ZeroMemory(&sfcLockParams, sizeof(sfcLockParams)); sfcLockParams.sfcPipeMode = m_sfcPipeMode; sfcLockParams.bOutputToMemory = ((MhwSfcInterface::SFC_PIPE_MODE_VEBOX != m_sfcPipeMode) && !m_jpegInUse); MHW_SFC_STATE_PARAMS sfcStateParams; MOS_ZeroMemory(&sfcStateParams, sizeof(sfcStateParams)); MHW_SFC_OUT_SURFACE_PARAMS sfcOutSurfaceParams; MOS_ZeroMemory(&sfcOutSurfaceParams, sizeof(sfcOutSurfaceParams)); CODECHAL_HW_CHK_STATUS_RETURN(SetSfcStateParams(&sfcStateParams, &sfcOutSurfaceParams)); CODECHAL_HW_CHK_STATUS_RETURN(m_sfcInterface->AddSfcLock(cmdBuffer, &sfcLockParams)); CODECHAL_HW_CHK_STATUS_RETURN(m_sfcInterface->AddSfcState(cmdBuffer, &sfcStateParams, &sfcOutSurfaceParams)); if (m_scaling) { CODECHAL_HW_CHK_STATUS_RETURN(SetSfcAvsStateParams()); CODECHAL_HW_CHK_STATUS_RETURN(m_sfcInterface->AddSfcAvsState(cmdBuffer, &m_avsState)); CODECHAL_HW_CHK_STATUS_RETURN(m_sfcInterface->AddSfcAvsLumaTable(cmdBuffer, &m_lumaTable)); CODECHAL_HW_CHK_STATUS_RETURN(m_sfcInterface->AddSfcAvsChromaTable(cmdBuffer, &m_chromaTable)); } if (m_csc) { MHW_SFC_IEF_STATE_PARAMS sfcIefStateParams; MOS_ZeroMemory(&sfcIefStateParams, sizeof(sfcIefStateParams)); CODECHAL_HW_CHK_STATUS_RETURN(SetSfcIefStateParams(&sfcIefStateParams)); CODECHAL_HW_CHK_STATUS_RETURN(m_sfcInterface->AddSfcIefState(cmdBuffer, &sfcIefStateParams)); } CODECHAL_HW_CHK_STATUS_RETURN(m_sfcInterface->AddSfcFrameStart(cmdBuffer, m_sfcPipeMode)); return eStatus; } MOS_STATUS CodechalSfcState::RenderStart() { MOS_STATUS eStatus = MOS_STATUS_SUCCESS; CODECHAL_HW_FUNCTION_ENTER; MOS_SYNC_PARAMS syncParams = g_cInitSyncParams; syncParams.GpuContext = m_decoder->GetVideoContext(); syncParams.presSyncResource = &m_resSyncObject; CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnEngineSignal(m_osInterface, &syncParams)); syncParams = g_cInitSyncParams; syncParams.GpuContext = MOS_GPU_CONTEXT_VEBOX; syncParams.presSyncResource = &m_resSyncObject; CODECHAL_DECODE_CHK_STATUS_RETURN(m_osInterface->pfnEngineWait(m_osInterface, &syncParams)); // Switch GPU context to VEBOX m_osInterface->pfnSetGpuContext(m_osInterface, MOS_GPU_CONTEXT_VEBOX); // Reset allocation list and house keeping m_osInterface->pfnResetOsStates(m_osInterface); // Send command buffer header at the beginning MOS_COMMAND_BUFFER cmdBuffer; MOS_ZeroMemory(&cmdBuffer, sizeof(MOS_COMMAND_BUFFER)); CODECHAL_HW_CHK_STATUS_RETURN(m_osInterface->pfnGetCommandBuffer(m_osInterface, &cmdBuffer, 0)); CODECHAL_HW_CHK_STATUS_RETURN(m_decoder->SendPrologWithFrameTracking(&cmdBuffer, true)); // Setup cmd prameters MHW_VEBOX_STATE_CMD_PARAMS veboxStateCmdParams; MOS_ZeroMemory(&veboxStateCmdParams, sizeof(veboxStateCmdParams)); CODECHAL_HW_CHK_STATUS_RETURN(SetVeboxStateParams(&veboxStateCmdParams)); MHW_VEBOX_SURFACE_STATE_CMD_PARAMS veboxSurfaceStateCmdParams; MOS_ZeroMemory(&veboxSurfaceStateCmdParams, sizeof(veboxSurfaceStateCmdParams)); CODECHAL_HW_CHK_STATUS_RETURN(SetVeboxSurfaceStateParams(&veboxSurfaceStateCmdParams)); MHW_VEBOX_DI_IECP_CMD_PARAMS veboxDiIecpCmdParams; MOS_ZeroMemory(&veboxDiIecpCmdParams, sizeof(veboxDiIecpCmdParams)); CODECHAL_HW_CHK_STATUS_RETURN(SetVeboxDiIecpParams(&veboxDiIecpCmdParams)); // send Vebox and SFC cmds CODECHAL_HW_CHK_STATUS_RETURN(m_veboxInterface->AddVeboxState(&cmdBuffer, &veboxStateCmdParams, 0)); CODECHAL_HW_CHK_STATUS_RETURN(m_veboxInterface->AddVeboxSurfaces(&cmdBuffer, &veboxSurfaceStateCmdParams)); CODECHAL_HW_CHK_STATUS_RETURN(AddSfcCommands(&cmdBuffer)); CODECHAL_HW_CHK_STATUS_RETURN(m_veboxInterface->AddVeboxDiIecp(&cmdBuffer, &veboxDiIecpCmdParams)); CODECHAL_DECODE_CHK_STATUS_RETURN(m_hwInterface->GetMiInterface()->AddMiBatchBufferEnd( &cmdBuffer, nullptr)); m_osInterface->pfnReturnCommandBuffer(m_osInterface, &cmdBuffer, 0); CODECHAL_HW_CHK_STATUS_RETURN(m_osInterface->pfnSubmitCommandBuffer( m_osInterface, &cmdBuffer, m_decoder->GetVideoContextUsesNullHw())); m_osInterface->pfnFreeResource( m_osInterface, &veboxStateCmdParams.DummyIecpResource); return eStatus; } bool CodechalSfcState::IsSfcFormatSupported( MOS_FORMAT inputFormat, MOS_FORMAT outputFormat) { if ((inputFormat != Format_NV12) && (inputFormat != Format_400P) && (inputFormat != Format_IMC3) && (inputFormat != Format_422H) && (inputFormat != Format_444P) && (inputFormat != Format_P010)) { CODECHAL_DECODE_ASSERTMESSAGE("Unsupported Input Format '0x%08x' for SFC.", inputFormat); return false; } if (outputFormat != Format_A8R8G8B8 && outputFormat != Format_NV12 && outputFormat != Format_P010 && outputFormat != Format_YUY2) { CODECHAL_DECODE_ASSERTMESSAGE("Unsupported Output Format '0x%08x' for SFC.", outputFormat); return false; } return true; } bool CodechalSfcState::IsSfcOutputSupported( DecodeProcessingParams *decodeProcParams, uint8_t sfcPipeMode) { CODECHAL_HW_FUNCTION_ENTER; if (!m_sfcInterface || !decodeProcParams || !decodeProcParams->m_inputSurface || !decodeProcParams->m_outputSurface) { CODECHAL_DECODE_ASSERTMESSAGE("Invalid Parameters"); return false; } if (Mos_ResourceIsNull(&decodeProcParams->m_outputSurface->OsResource)) { CODECHAL_DECODE_NORMALMESSAGE("m_outputSurface->OsResource is Null"); return false; } PMOS_SURFACE srcSurface = decodeProcParams->m_inputSurface; PMOS_SURFACE destSurface = decodeProcParams->m_outputSurface; uint32_t srcSurfWidth, srcSurfHeight; if (MhwSfcInterface::SFC_PIPE_MODE_VEBOX == sfcPipeMode) { // Adjust SFC input surface alignment. // As VEBOX doesn't do scaling, input size equals to output size // For the VEBOX output to SFC, width is multiple of 16 and height is multiple of 4 srcSurface->dwWidth = MOS_ALIGN_CEIL(srcSurface->dwWidth, m_sfcInterface->m_veWidthAlignment); srcSurface->dwHeight = MOS_ALIGN_CEIL(srcSurface->dwHeight, m_sfcInterface->m_veHeightAlignment); srcSurfWidth = srcSurface->dwWidth; srcSurfHeight = srcSurface->dwHeight; } else { // Check original input size (for JPEG) if (!MOS_WITHIN_RANGE(srcSurface->dwWidth, m_sfcInterface->m_minWidth, m_sfcInterface->m_maxWidth) || !MOS_WITHIN_RANGE(srcSurface->dwHeight, m_sfcInterface->m_minHeight, m_sfcInterface->m_maxHeight)) { return false; } srcSurfWidth = MOS_ALIGN_CEIL(srcSurface->dwWidth, CODECHAL_SFC_ALIGNMENT_16); srcSurfHeight = MOS_ALIGN_CEIL(srcSurface->dwHeight, CODECHAL_SFC_ALIGNMENT_16); } // Check input size if (!MOS_WITHIN_RANGE(srcSurfWidth, m_sfcInterface->m_minWidth, m_sfcInterface->m_maxWidth) || !MOS_WITHIN_RANGE(srcSurfHeight, m_sfcInterface->m_minHeight, m_sfcInterface->m_maxHeight)) { return false; } // Adjust SFC output surface alignment. uint16_t widthAlignUnit = 1; uint16_t heightAlignUnit = 1; switch(destSurface->Format) { case Format_NV12: widthAlignUnit = 2; heightAlignUnit = 2; break; case Format_YUY2: case Format_UYVY: widthAlignUnit = 2; break; default: break; } uint32_t dstSurfWidth = MOS_ALIGN_CEIL(destSurface->dwWidth, widthAlignUnit); uint32_t dstSurfHeight = MOS_ALIGN_CEIL(destSurface->dwHeight, heightAlignUnit); // Check input and output format (limited only to current decode processing usage) if (!IsSfcFormatSupported(srcSurface->Format, destSurface->Format)) { return false; } // Check input region rectangles uint32_t sourceRegionWidth = MOS_ALIGN_FLOOR(decodeProcParams->m_inputSurfaceRegion.m_width, widthAlignUnit); uint32_t sourceRegionHeight = MOS_ALIGN_FLOOR(decodeProcParams->m_inputSurfaceRegion.m_height, heightAlignUnit); if ((sourceRegionWidth > srcSurface->dwWidth) || (sourceRegionHeight > srcSurface->dwHeight)) { return false; } // Check output size if (!MOS_WITHIN_RANGE(dstSurfWidth, m_sfcInterface->m_minWidth, m_sfcInterface->m_maxWidth) || !MOS_WITHIN_RANGE(dstSurfHeight, m_sfcInterface->m_minHeight, m_sfcInterface->m_maxHeight)) { return false; } // Check output region rectangles uint32_t outputRegionWidth = MOS_ALIGN_CEIL(decodeProcParams->m_outputSurfaceRegion.m_width, widthAlignUnit); uint32_t outputRegionHeight = MOS_ALIGN_CEIL(decodeProcParams->m_outputSurfaceRegion.m_height, heightAlignUnit); if ((outputRegionWidth > destSurface->dwWidth) || (outputRegionHeight > destSurface->dwHeight)) { return false; } // Check scaling ratio // SFC scaling range is [0.125, 8] for both X and Y direction. m_scaleX = (float)outputRegionWidth / (float)sourceRegionWidth; m_scaleY = (float)outputRegionHeight / (float)sourceRegionHeight; if (!MOS_WITHIN_RANGE(m_scaleX, m_sfcInterface->m_minScalingRatio, m_sfcInterface->m_maxScalingRatio) || !MOS_WITHIN_RANGE(m_scaleY, m_sfcInterface->m_minScalingRatio, m_sfcInterface->m_maxScalingRatio)) { return false; } return true; } MOS_STATUS CodechalSfcState::InitializeSfcState( CodechalDecode *inDecoder, CodechalHwInterface *hwInterface, PMOS_INTERFACE osInterface) { MOS_STATUS eStatus = MOS_STATUS_SUCCESS; CODECHAL_HW_FUNCTION_ENTER; CODECHAL_DECODE_CHK_NULL_RETURN(inDecoder); CODECHAL_DECODE_CHK_NULL_RETURN(hwInterface); CODECHAL_DECODE_CHK_NULL_RETURN(osInterface); CODECHAL_DECODE_CHK_NULL_RETURN(hwInterface->GetVeboxInterface()); CODECHAL_DECODE_CHK_NULL_RETURN(hwInterface->GetMiInterface()); m_decoder = inDecoder; m_osInterface = osInterface; m_hwInterface = hwInterface; m_veboxInterface = hwInterface->GetVeboxInterface(); m_sfcInterface = hwInterface->GetSfcInterface(); // No need to check null for pSfcInterface. It will be checked in IsSfcSupported(). m_miInterface = hwInterface->GetMiInterface(); m_mmcEnabled = m_decoder->IsDecoderMmcEnabled(); return eStatus; }