blob: e0338051a12ee0f42a3289e8be6efec2815cb0c8 [file] [log] [blame]
/*
* Copyright (c) 2016-2017, 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_encode_hevc.cpp
//! \brief Defines base class for HEVC dual-pipe encoder.
//!
#include "codechal_encode_hevc.h"
#include "codechal_mmc_encode_hevc.h"
uint32_t CodechalEncHevcState::GetStartCodeOffset(uint8_t* addr, uint32_t size)
{
CODECHAL_ENCODE_FUNCTION_ENTER;
uint32_t count = 0;
if (addr)
{
// count # 0 bytes before end of start code to determine header offset
// (ie. 00 00 00 00 01 = 4)
while (count < size && *addr != 0x01)
{
// Damage control if start code is non-existent or malformed
// so header will still be a reasonable size
if (*addr != 0)
break;
count++;
addr++;
}
}
return count + 1; // +1 to account for 01 byte
}
uint32_t CodechalEncHevcState::GetPicHdrSize()
{
CODECHAL_ENCODE_FUNCTION_ENTER;
uint32_t firstHdrSz = 0;
for(auto i = 0 ; i < HEVC_MAX_NAL_UNIT_TYPE ; i++)
{
if (m_nalUnitParams[i]->uiSize != 0)
{
firstHdrSz = m_nalUnitParams[i]->uiSize;
break;
}
}
uint8_t* hdrPtr = m_bsBuffer.pBase;
// hdr offset = # 0's + 01 byte (start code) + offset over temporal ID and NAL type byte
uint32_t hdrBegin = GetStartCodeOffset(hdrPtr, firstHdrSz) + HEVC_START_CODE_NAL_OFFSET;
uint32_t accum = 0, numEmuBytes = 0;
for(auto i = 0 ; i < HEVC_MAX_NAL_UNIT_TYPE ; i++)
{
if (m_nalUnitParams[i]->uiSize == 0)
continue;
uint32_t origSize = m_nalUnitParams[i]->uiSize;
if (m_hevcPicParams->bEmulationByteInsertion)
{
hdrPtr = m_bsBuffer.pBase + accum;
uint32_t hdrOffset = GetStartCodeOffset(hdrPtr, origSize);
hdrPtr += hdrOffset;
uint32_t zeroCount = 0;
for (uint32_t j = 0 ; j < origSize - hdrOffset ; j++)
{
// Check if Emulation Prevention Byte needed for hex 00 00 00/00 00 01/00 00 02/00 00 03
if (zeroCount == 2 && !(*hdrPtr & 0xFC))
{
zeroCount = 0;
numEmuBytes++; //increment by prevention byte
}
if (*hdrPtr == 0x00)
{
zeroCount++;
}
else
{
zeroCount = 0;
}
*hdrPtr++;
}
}
accum += origSize;
}
// Add emulation bytes found
accum += numEmuBytes;
// Make sure that header size is valid or cap to provided hdr size
hdrBegin = MOS_MIN(hdrBegin, accum);
// Hdr size is in # bits
return (accum - hdrBegin) * 8;
}
MOS_STATUS CodechalEncHevcState::ValidateRefFrameData(PCODEC_HEVC_ENCODE_SLICE_PARAMS slcParams)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_CHK_NULL_RETURN(slcParams);
uint8_t maxNumRef0 = 0;
uint8_t maxNumRef1 = 0;
GetMaxRefFrames(maxNumRef0, maxNumRef1);
if (slcParams->num_ref_idx_l0_active_minus1 > maxNumRef0 - 1)
{
CODECHAL_ENCODE_ASSERT(false);
slcParams->num_ref_idx_l0_active_minus1 = maxNumRef0 - 1;
}
if (slcParams->num_ref_idx_l1_active_minus1 > maxNumRef1 - 1)
{
CODECHAL_ENCODE_ASSERT(false);
slcParams->num_ref_idx_l1_active_minus1 = maxNumRef1 - 1;
}
return eStatus;
}
MOS_STATUS CodechalEncHevcState::SetSequenceStructs()
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
CODECHAL_ENCODE_CHK_STATUS_RETURN(CodechalEncodeHevcBase::SetSequenceStructs());
m_cqpEnabled = (m_hevcSeqParams->RateControlMethod == RATECONTROL_CQP);
if (m_hevcSeqParams->ParallelBRC == false)
{
m_brcBuffers.uiCurrBrcPakStasIdxForRead = m_brcBuffers.uiCurrBrcPakStasIdxForWrite = 0;
}
// check LCU size
if (m_2xMeSupported &&
m_hevcSeqParams->log2_max_coding_block_size_minus3 == 3)
{
// LCU64 support
m_isMaxLcu64 = true;
m_2xScalingEnabled = true;
}
else
{
if (m_hevcSeqParams->log2_max_coding_block_size_minus3 != 2)
{
CODECHAL_ENCODE_ASSERTMESSAGE("Invalid LCU.");
eStatus = MOS_STATUS_INVALID_PARAMETER;
return eStatus;
}
m_isMaxLcu64 = false;
m_2xScalingEnabled = false;
}
// allocate resources only needed in LCU64 kernel
if (m_firstFrame && m_isMaxLcu64)
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(AllocateEncResourcesLCU64());
}
if (m_hevcSeqParams->FrameRate.Denominator == 0)
{
eStatus = MOS_STATUS_INVALID_PARAMETER;
CODECHAL_ENCODE_ASSERTMESSAGE("FrameRate Denominator can not be zero.");
return eStatus;
}
uint8_t framerate = m_hevcSeqParams->FrameRate.Numerator / m_hevcSeqParams->FrameRate.Denominator;
m_slidingWindowSize = MOS_MIN(framerate, 60);
return eStatus;
}
MOS_STATUS CodechalEncHevcState::SetPictureStructs()
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
CODECHAL_ENCODE_CHK_STATUS_RETURN(CodechalEncodeHevcBase::SetPictureStructs());
// do not support interlaced coding now
if (CodecHal_PictureIsField(m_currOriginalPic))
{
eStatus = MOS_STATUS_INVALID_PARAMETER;
return eStatus;
}
// Set min/max QP values based on frame type if atleast one of them is non-zero
if (m_hevcPicParams->BRCMinQp || m_hevcPicParams->BRCMaxQp)
{
m_minMaxQpControlEnabled = true;
if (m_hevcPicParams->CodingType == I_TYPE)
{
m_maxQpForI = MOS_MIN(MOS_MAX(m_hevcPicParams->BRCMaxQp, 1), 51); // Clamp to the max QP to [1, 51] . Zero is not used by our Kernel.
m_minQpForI = MOS_MIN(MOS_MAX(m_hevcPicParams->BRCMinQp, 1), m_maxQpForI); // Clamp the min QP to [1, maxQP] to make sure minQP <= maxQP
if (!m_minMaxQpControlForP)
{
m_minQpForP = m_minQpForI;
m_maxQpForP = m_maxQpForI;
}
if (!m_minMaxQpControlForB)
{
m_minQpForB = m_minQpForI;
m_maxQpForB = m_maxQpForI;
}
}
else if (m_hevcPicParams->CodingType == P_TYPE)
{
m_minMaxQpControlForP = true;
m_maxQpForP = MOS_MIN(MOS_MAX(m_hevcPicParams->BRCMaxQp, 1), 51); // Clamp to the max QP to [1, 51]. Zero is not used by our Kernel.
m_minQpForP = MOS_MIN(MOS_MAX(m_hevcPicParams->BRCMinQp, 1), m_maxQpForP); // Clamp the min QP to [1, maxQP] to make sure minQP <= maxQP
if (!m_minMaxQpControlForB)
{
m_minQpForB = m_minQpForP;
m_maxQpForB = m_maxQpForP;
}
}
else if (m_hevcPicParams->CodingType == B_TYPE)
{
m_minMaxQpControlForB = true;
m_maxQpForB = MOS_MIN(MOS_MAX(m_hevcPicParams->BRCMaxQp, 1), 51); // Clamp to the max QP to [1, 51]. Zero is not used by our Kernel.
m_minQpForB = MOS_MIN(MOS_MAX(m_hevcPicParams->BRCMinQp, 1), m_maxQpForB); // Clamp the min QP to [1, maxQP] to make sure minQP <= maxQP
}
}
// CQP with Fast Surveillance [Distortion Surface needs to be allocated]
if (m_brcEnabled || m_hevcSeqParams->bVideoSurveillance || m_cqpEnabled)
{
m_brcDistortion = (m_pictureCodingType == I_TYPE) ? &m_brcBuffers.sBrcIntraDistortionBuffer : &m_brcBuffers.sMeBrcDistortionBuffer;
}
if (m_brcEnabled)
{
// For ICQ mode or when min/max QP used, ignore BRCPrecision sent by the app and set the number of passes internally
if ((m_hevcSeqParams->RateControlMethod == RATECONTROL_ICQ) || (m_minMaxQpControlEnabled))
{
m_numPasses = 0; // no IPCM for HEVC
}
else
{
m_numPasses = (uint8_t)(m_mfxInterface->GetBrcNumPakPasses() - 1); // 1 original plus extra to handle BRC
}
}
else
{
m_numPasses = 0; // no IPCM for HEVC
}
//add for FEI multiple Pass Pak
if (CodecHalIsFeiEncode(m_codecFunction))
{
CODECHAL_ENCODE_CHK_NULL_RETURN(m_hevcFeiPicParams);
if (m_hevcFeiPicParams->dwMaxFrameSize != 0)
{
m_numPasses = (uint8_t)m_hevcFeiPicParams->dwNumPasses;
}
}
return eStatus;
}
MOS_STATUS CodechalEncHevcState::SetSliceStructs()
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
CODECHAL_ENCODE_CHK_STATUS_RETURN(CodechalEncodeHevcBase::SetSliceStructs());
return eStatus;
}
MOS_STATUS CodechalEncHevcState::ReadBrcPakStats(
PMOS_COMMAND_BUFFER cmdBuffer)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
uint32_t offset = (m_encodeStatusBuf.wCurrIndex * m_encodeStatusBuf.dwReportSize) +
m_encodeStatusBuf.dwNumPassesOffset + // Num passes offset
sizeof(uint32_t)* 2; // pEncodeStatus is offset by 2 DWs in the resource
EncodeReadBrcPakStatsParams readBrcPakStatsParams;
readBrcPakStatsParams.pHwInterface = m_hwInterface;
readBrcPakStatsParams.presBrcPakStatisticBuffer = &m_brcBuffers.resBrcPakStatisticBuffer[m_brcBuffers.uiCurrBrcPakStasIdxForWrite];
readBrcPakStatsParams.presStatusBuffer = &m_encodeStatusBuf.resStatusBuffer;
readBrcPakStatsParams.dwStatusBufNumPassesOffset = offset;
readBrcPakStatsParams.ucPass = (uint8_t)GetCurrentPass();
readBrcPakStatsParams.VideoContext = m_videoContext;
CODECHAL_ENCODE_CHK_STATUS_RETURN(ReadBrcPakStatistics(
cmdBuffer,
&readBrcPakStatsParams));
return eStatus;
}
MOS_STATUS CodechalEncHevcState::AddHcpPipeModeSelectCmd(MOS_COMMAND_BUFFER* cmdBuffer)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
MHW_VDBOX_PIPE_MODE_SELECT_PARAMS pipeModeSelectParams;
SetHcpPipeModeSelectParams(pipeModeSelectParams);
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpPipeModeSelectCmd(cmdBuffer, &pipeModeSelectParams));
return eStatus;
}
MOS_STATUS CodechalEncHevcState::AddHcpSurfaceStateCmds(MOS_COMMAND_BUFFER* cmdBuffer)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
MHW_VDBOX_SURFACE_PARAMS srcSurfaceParams;
SetHcpSrcSurfaceParams(srcSurfaceParams);
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpSurfaceCmd(cmdBuffer, &srcSurfaceParams));
MHW_VDBOX_SURFACE_PARAMS reconSurfaceParams;
SetHcpReconSurfaceParams(reconSurfaceParams);
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpSurfaceCmd(cmdBuffer, &reconSurfaceParams));
return eStatus;
}
MOS_STATUS CodechalEncHevcState::AddHcpPictureStateCmd(MOS_COMMAND_BUFFER* cmdBuffer)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
MHW_VDBOX_HEVC_PIC_STATE picStateParams;
SetHcpPicStateParams(picStateParams);
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpPicStateCmd(cmdBuffer, &picStateParams));
return eStatus;
}
MOS_STATUS CodechalEncHevcState::ExecutePictureLevel()
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
PerfTagSetting perfTag;
CODECHAL_ENCODE_SET_PERFTAG_INFO(perfTag, CODECHAL_ENCODE_PERFTAG_CALL_PAK_ENGINE);
CODECHAL_ENCODE_CHK_STATUS_RETURN(VerifyCommandBufferSize());
if (!m_singleTaskPhaseSupportedInPak)
{
// Command buffer or patch list size are too small and so we cannot submit multiple pass of PAKs together
m_firstTaskInPhase = true;
m_lastTaskInPhase = true;
}
if (m_vdboxIndex > m_mfxInterface->GetMaxVdboxIndex())
{
CODECHAL_ENCODE_ASSERTMESSAGE("ERROR - vdbox index exceed the maximum");
eStatus = MOS_STATUS_INVALID_PARAMETER;
return eStatus;
}
MOS_COMMAND_BUFFER cmdBuffer;
CODECHAL_ENCODE_CHK_STATUS_RETURN(GetCommandBuffer(&cmdBuffer));
if ((!m_singleTaskPhaseSupported) || m_firstTaskInPhase)
{
// Send command buffer header at the beginning (OS dependent)
// frame tracking tag is only added in the last command buffer header
bool requestFrameTracking = m_singleTaskPhaseSupported ?
m_firstTaskInPhase :
m_lastTaskInPhase;
// When brc + 2 pass sao is enabled need to disable frame tracking for first cmd buffer
if (m_brcEnabled && m_hevcSeqParams->SAO_enabled_flag)
{
requestFrameTracking = false;
}
CODECHAL_ENCODE_CHK_STATUS_RETURN(SendPrologWithFrameTracking(&cmdBuffer, requestFrameTracking));
}
// Enable frame tracking for the last cmd buffer when brc + 2 pass sao is on
if (m_brcEnabled && m_hevcSeqParams->SAO_enabled_flag && m_currPass == m_uc2NdSaoPass)
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(SendPrologWithFrameTracking(&cmdBuffer, true));
}
if (m_brcEnabled &&
!IsFirstPass() &&
m_currPass != m_uc2NdSaoPass) // Only the regular BRC passes have the conditional batch buffer end
{
// Insert conditional batch buffer end
MHW_MI_CONDITIONAL_BATCH_BUFFER_END_PARAMS miConditionalBatchBufferEndParams;
MOS_ZeroMemory(
&miConditionalBatchBufferEndParams,
sizeof(MHW_MI_CONDITIONAL_BATCH_BUFFER_END_PARAMS));
uint32_t baseOffset = (m_encodeStatusBuf.wCurrIndex * m_encodeStatusBuf.dwReportSize) +
sizeof(uint32_t) * 2; // pEncodeStatus is offset by 2 DWs in the resource ;
CODECHAL_ENCODE_ASSERT((m_encodeStatusBuf.dwImageStatusMaskOffset & 7) == 0); // Make sure uint64_t aligned
CODECHAL_ENCODE_ASSERT((m_encodeStatusBuf.dwImageStatusMaskOffset + sizeof(uint32_t)) == m_encodeStatusBuf.dwImageStatusCtrlOffset);
miConditionalBatchBufferEndParams.presSemaphoreBuffer = &m_encodeStatusBuf.resStatusBuffer;
miConditionalBatchBufferEndParams.dwOffset = baseOffset + m_encodeStatusBuf.dwImageStatusMaskOffset;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiConditionalBatchBufferEndCmd(
&cmdBuffer,
&miConditionalBatchBufferEndParams));
auto mmioRegisters = m_hcpInterface->GetMmioRegisters(m_vdboxIndex);
MHW_MI_STORE_REGISTER_MEM_PARAMS miStoreRegMemParams;
MHW_MI_COPY_MEM_MEM_PARAMS miCpyMemMemParams;
// Write back the HCP image control register for RC6 may clean it out
MHW_MI_LOAD_REGISTER_MEM_PARAMS miLoadRegMemParams;
MOS_ZeroMemory(&miLoadRegMemParams, sizeof(miLoadRegMemParams));
miLoadRegMemParams.presStoreBuffer = &m_encodeStatusBuf.resStatusBuffer;
miLoadRegMemParams.dwOffset = baseOffset + m_encodeStatusBuf.dwImageStatusCtrlOffset;
miLoadRegMemParams.dwRegister = mmioRegisters->hcpEncImageStatusCtrlRegOffset;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiLoadRegisterMemCmd(&cmdBuffer, &miLoadRegMemParams));
MOS_ZeroMemory(&miStoreRegMemParams, sizeof(miStoreRegMemParams));
miStoreRegMemParams.presStoreBuffer = &m_brcBuffers.resBrcPakStatisticBuffer[m_brcBuffers.uiCurrBrcPakStasIdxForWrite];
miStoreRegMemParams.dwOffset = CODECHAL_OFFSETOF(CODECHAL_ENCODE_HEVC_PAK_STATS_BUFFER, HCP_IMAGE_STATUS_CONTROL_FOR_LAST_PASS);
miStoreRegMemParams.dwRegister = mmioRegisters->hcpEncImageStatusCtrlRegOffset;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreRegisterMemCmd(&cmdBuffer, &miStoreRegMemParams));
MOS_ZeroMemory(&miStoreRegMemParams, sizeof(miStoreRegMemParams));
miStoreRegMemParams.presStoreBuffer = &m_encodeStatusBuf.resStatusBuffer;
miStoreRegMemParams.dwOffset = baseOffset + m_encodeStatusBuf.dwImageStatusCtrlOfLastBRCPassOffset;
miStoreRegMemParams.dwRegister = mmioRegisters->hcpEncImageStatusCtrlRegOffset;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreRegisterMemCmd(&cmdBuffer, &miStoreRegMemParams));
}
if (IsFirstPass() && m_osInterface->bTagResourceSync)
{
// This is a short term solution to solve the sync tag issue: the sync tag write for PAK is inserted at the end of 2nd pass PAK BB
// which may be skipped in multi-pass PAK enabled case. The idea here is to insert the previous frame's tag at the beginning
// of the BB and keep the current frame's tag at the end of the BB. There will be a delay for tag update but it should be fine
// as long as Dec/VP/Enc won't depend on this PAK so soon.
PMOS_RESOURCE globalGpuContextSyncTagBuffer = nullptr;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnGetGpuStatusBufferResource(
m_osInterface,
globalGpuContextSyncTagBuffer));
CODECHAL_ENCODE_CHK_NULL_RETURN(globalGpuContextSyncTagBuffer);
MHW_MI_STORE_DATA_PARAMS params;
params.pOsResource = globalGpuContextSyncTagBuffer;
params.dwResourceOffset = m_osInterface->pfnGetGpuStatusTagOffset(m_osInterface, m_osInterface->CurrentGpuContextOrdinal);
uint32_t value = m_osInterface->pfnGetGpuStatusTag(m_osInterface, m_osInterface->CurrentGpuContextOrdinal);
params.dwValue = (value > 0) ? (value - 1) : 0;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiStoreDataImmCmd(&cmdBuffer, &params));
}
CODECHAL_ENCODE_CHK_STATUS_RETURN(StartStatusReport(&cmdBuffer, CODECHAL_NUM_MEDIA_STATES));
CODECHAL_ENCODE_CHK_STATUS_RETURN(AddHcpPipeModeSelectCmd(&cmdBuffer));
CODECHAL_ENCODE_CHK_STATUS_RETURN(AddHcpSurfaceStateCmds(&cmdBuffer));
CODECHAL_ENCODE_CHK_STATUS_RETURN(AddHcpPipeBufAddrCmd(&cmdBuffer));
MHW_VDBOX_IND_OBJ_BASE_ADDR_PARAMS indObjBaseAddrParams;
SetHcpIndObjBaseAddrParams(indObjBaseAddrParams);
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpIndObjBaseAddrCmd(&cmdBuffer, &indObjBaseAddrParams));
MHW_VDBOX_QM_PARAMS fqmParams, qmParams;
SetHcpQmStateParams(fqmParams, qmParams);
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpFqmStateCmd(&cmdBuffer, &fqmParams));
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpQmStateCmd(&cmdBuffer, &qmParams));
if (m_brcEnabled)
{
if (m_hevcSeqParams->SAO_enabled_flag && m_currPass == m_uc2NdSaoPass)
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(AddHcpPictureStateCmd(&cmdBuffer));
}
else
{
uint32_t picStateCmdOffset;
picStateCmdOffset = GetCurrentPass();
MHW_BATCH_BUFFER batchBuffer;
MOS_ZeroMemory(&batchBuffer, sizeof(batchBuffer));
batchBuffer.OsResource = m_brcBuffers.resBrcImageStatesWriteBuffer[m_currRecycledBufIdx];
batchBuffer.dwOffset = picStateCmdOffset * (m_brcBuffers.dwBrcHcpPicStateSize / CODECHAL_ENCODE_BRC_MAXIMUM_NUM_PASSES);
batchBuffer.bSecondLevel = true;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiBatchBufferStartCmd(
&cmdBuffer,
&batchBuffer));
}
}
else
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(AddHcpPictureStateCmd(&cmdBuffer));
}
// Send HEVC_VP9_RDOQ_STATE command
if (m_hevcRdoqEnabled)
{
MHW_VDBOX_HEVC_PIC_STATE picStateParams;
SetHcpPicStateParams(picStateParams);
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpHevcVp9RdoqStateCmd(&cmdBuffer, &picStateParams));
}
CODECHAL_ENCODE_CHK_STATUS_RETURN(ReturnCommandBuffer(&cmdBuffer));
return eStatus;
}
MOS_STATUS CodechalEncHevcState::AddHcpWeightOffsetStateCmd(
PMOS_COMMAND_BUFFER cmdBuffer,
PMHW_BATCH_BUFFER batchBuffer,
PCODEC_HEVC_ENCODE_SLICE_PARAMS hevcSlcParams)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
CODECHAL_ENCODE_CHK_NULL_RETURN(hevcSlcParams);
if (cmdBuffer == nullptr && batchBuffer == nullptr)
{
CODECHAL_ENCODE_ASSERTMESSAGE("There was no valid buffer to add the HW command to.");
return MOS_STATUS_NULL_POINTER;
}
MHW_VDBOX_HEVC_WEIGHTOFFSET_PARAMS hcpWeightOffsetParams;
MOS_ZeroMemory(&hcpWeightOffsetParams, sizeof(hcpWeightOffsetParams));
for (auto k = 0; k < 2; k++) // k=0: LIST_0, k=1: LIST_1
{
// Luma, Chroma offset
for (auto i = 0; i < CODEC_MAX_NUM_REF_FRAME_HEVC; i++)
{
hcpWeightOffsetParams.LumaOffsets[k][i] = (int16_t)hevcSlcParams->luma_offset[k][i];
// Cb, Cr
for (auto j = 0; j < 2; j++)
{
hcpWeightOffsetParams.ChromaOffsets[k][i][j] = (int16_t)hevcSlcParams->chroma_offset[k][i][j];
}
}
// Luma Weight
CODECHAL_ENCODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
&hcpWeightOffsetParams.LumaWeights[k],
sizeof(hcpWeightOffsetParams.LumaWeights[k]),
&hevcSlcParams->delta_luma_weight[k],
sizeof(hevcSlcParams->delta_luma_weight[k])));
// Chroma Weight
CODECHAL_ENCODE_CHK_STATUS_RETURN(MOS_SecureMemcpy(
&hcpWeightOffsetParams.ChromaWeights[k],
sizeof(hcpWeightOffsetParams.ChromaWeights[k]),
&hevcSlcParams->delta_chroma_weight[k],
sizeof(hevcSlcParams->delta_chroma_weight[k])));
}
if (hevcSlcParams->slice_type == CODECHAL_ENCODE_HEVC_P_SLICE || hevcSlcParams->slice_type == CODECHAL_ENCODE_HEVC_B_SLICE)
{
hcpWeightOffsetParams.ucList = LIST_0;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpWeightOffsetStateCmd(cmdBuffer, batchBuffer, &hcpWeightOffsetParams));
}
if (hevcSlcParams->slice_type == CODECHAL_ENCODE_HEVC_B_SLICE)
{
hcpWeightOffsetParams.ucList = LIST_1;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpWeightOffsetStateCmd(cmdBuffer, batchBuffer, &hcpWeightOffsetParams));
}
return eStatus;
}
//------------------------------------------------------------------------------------
// Build slices with header insertion
//------------------------------------------------------------------------------------
MOS_STATUS CodechalEncHevcState::SendHwSliceEncodeCommand(
PMOS_COMMAND_BUFFER cmdBuffer,
PMHW_VDBOX_HEVC_SLICE_STATE params)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
CODECHAL_ENCODE_CHK_NULL_RETURN(params);
CODECHAL_ENCODE_CHK_NULL_RETURN(params->pHevcPicIdx);
CODECHAL_ENCODE_CHK_NULL_RETURN(params->presDataBuffer);
CODECHAL_ENCODE_CHK_NULL_RETURN(params->pEncodeHevcSeqParams);
CODECHAL_ENCODE_CHK_NULL_RETURN(params->pEncodeHevcPicParams);
CODECHAL_ENCODE_CHK_NULL_RETURN(params->pEncodeHevcSliceParams);
CODECHAL_ENCODE_CHK_NULL_RETURN(params->pBsBuffer);
CODECHAL_ENCODE_CHK_NULL_RETURN(params->ppNalUnitParams);
PMHW_BATCH_BUFFER batchBufferInUse = nullptr;
PMOS_COMMAND_BUFFER cmdBufferInUse = nullptr;
if (params->bSingleTaskPhaseSupported)
{
CODECHAL_ENCODE_CHK_NULL_RETURN(params->pBatchBufferForPakSlices);
batchBufferInUse = params->pBatchBufferForPakSlices;
}
else
{
cmdBufferInUse = cmdBuffer;
}
// add HCP_REF_IDX command
CODECHAL_ENCODE_CHK_STATUS_RETURN(AddHcpRefIdxCmd(cmdBufferInUse, batchBufferInUse, params));
if (params->bWeightedPredInUse)
{
//add weghtoffset command
CODECHAL_ENCODE_CHK_STATUS_RETURN(AddHcpWeightOffsetStateCmd(cmdBufferInUse, batchBufferInUse, m_hevcSliceParams));
}
// add HEVC Slice state commands
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpSliceStateCmd(cmdBufferInUse, params));
// add HCP_PAK_INSERT_OBJECTS command
CODECHAL_ENCODE_CHK_STATUS_RETURN(AddHcpPakInsertNALUs(cmdBufferInUse, batchBufferInUse, params));
CODECHAL_ENCODE_CHK_STATUS_RETURN(AddHcpPakInsertSliceHeader(cmdBufferInUse, batchBufferInUse, params));
if (params->bSingleTaskPhaseSupported && batchBufferInUse)
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiBatchBufferEnd(nullptr, batchBufferInUse));
MHW_BATCH_BUFFER secondLevelBatchBuffer;
MOS_ZeroMemory(&secondLevelBatchBuffer, sizeof(MHW_BATCH_BUFFER));
secondLevelBatchBuffer.OsResource = batchBufferInUse->OsResource;
secondLevelBatchBuffer.dwOffset = params->dwBatchBufferForPakSlicesStartOffset;
secondLevelBatchBuffer.bSecondLevel = true;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiBatchBufferStartCmd(cmdBuffer, &secondLevelBatchBuffer));
}
// Insert Batch Buffer Start command to send HCP_PAK_OBJ data for LCUs in this slice
MHW_BATCH_BUFFER secondLevelBatchBuffer;
MOS_ZeroMemory(&secondLevelBatchBuffer, sizeof(MHW_BATCH_BUFFER));
secondLevelBatchBuffer.OsResource = *params->presDataBuffer;
secondLevelBatchBuffer.dwOffset = params->dwDataBufferOffset;
secondLevelBatchBuffer.bSecondLevel = true;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiBatchBufferStartCmd(cmdBuffer, &secondLevelBatchBuffer));
return eStatus;
}
MOS_STATUS CodechalEncHevcState::ExecuteSliceLevel()
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
CODECHAL_ENCODE_CHK_NULL_RETURN(m_slcData);
CODECHAL_ENCODE_CHK_STATUS_RETURN(SetBatchBufferForPakSlices());
MOS_COMMAND_BUFFER cmdBuffer;
CODECHAL_ENCODE_CHK_STATUS_RETURN(GetCommandBuffer(&cmdBuffer));
SetHcpSliceStateCommonParams(*m_sliceStateParams);
PCODEC_ENCODER_SLCDATA slcData = m_slcData;
for (uint32_t startLCU = 0, SlcCount = 0; SlcCount < m_numSlices; SlcCount++)
{
if (m_currPass == 0)
{
slcData[SlcCount].CmdOffset = startLCU * (m_hcpInterface->GetHcpPakObjSize()) * sizeof(uint32_t);
}
SetHcpSliceStateParams(*m_sliceStateParams, slcData, SlcCount);
CODECHAL_ENCODE_CHK_STATUS_RETURN(SendHwSliceEncodeCommand(&cmdBuffer, m_sliceStateParams));
startLCU += m_hevcSliceParams[SlcCount].NumLCUsInSlice;
m_batchBufferForPakSlicesStartOffset =
(uint32_t)m_batchBufferForPakSlices[m_currPakSliceIdx].iCurrent;
}
if (m_useBatchBufferForPakSlices)
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(Mhw_UnlockBb(
m_osInterface,
&m_batchBufferForPakSlices[m_currPakSliceIdx],
m_lastTaskInPhase));
}
// Insert end of sequence/stream if set
if (m_lastPicInStream || m_lastPicInSeq)
{
MHW_VDBOX_PAK_INSERT_PARAMS pakInsertObjectParams;
MOS_ZeroMemory(&pakInsertObjectParams, sizeof(pakInsertObjectParams));
pakInsertObjectParams.bLastPicInSeq = m_lastPicInSeq;
pakInsertObjectParams.bLastPicInStream = m_lastPicInStream;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hcpInterface->AddHcpPakInsertObject(&cmdBuffer, &pakInsertObjectParams));
}
CODECHAL_ENCODE_CHK_STATUS_RETURN(ReadHcpStatus(&cmdBuffer));
// BRC PAK statistics different for each pass
if (m_brcEnabled)
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(ReadBrcPakStats(&cmdBuffer));
}
if (!Mos_ResourceIsNull(&m_resFrameStatStreamOutBuffer))
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(ReadSseStatistics(&cmdBuffer));
}
CODECHAL_ENCODE_CHK_STATUS_RETURN(EndStatusReport(&cmdBuffer, CODECHAL_NUM_MEDIA_STATES));
if (!m_singleTaskPhaseSupported || m_lastTaskInPhase)
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_miInterface->AddMiBatchBufferEnd(&cmdBuffer, nullptr));
}
std::string pakPassName = "PAK_PASS" + std::to_string(static_cast<uint32_t>(m_currPass));
CODECHAL_DEBUG_TOOL(
CODECHAL_ENCODE_CHK_STATUS_RETURN( m_debugInterface->DumpCmdBuffer(
&cmdBuffer,
CODECHAL_NUM_MEDIA_STATES,
pakPassName.data()));)
CODECHAL_ENCODE_CHK_STATUS_RETURN(ReturnCommandBuffer(&cmdBuffer));
if ((!m_pakOnlyTest) && // In the PAK only test, no need to wait for ENC's completion
(m_currPass == 0) &&
!Mos_ResourceIsNull(&m_resSyncObjectRenderContextInUse))
{
MOS_SYNC_PARAMS syncParams = g_cInitSyncParams;
syncParams.GpuContext = m_videoContext;
syncParams.presSyncResource = &m_resSyncObjectRenderContextInUse;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnEngineWait(m_osInterface, &syncParams));
}
bool renderingFlags = m_videoContextUsesNullHw;
if (!m_singleTaskPhaseSupported || m_lastTaskInPhase)
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnSubmitCommandBuffer(m_osInterface, &cmdBuffer, renderingFlags));
CODECHAL_DEBUG_TOOL(
if (m_mmcState)
{
m_mmcState->UpdateUserFeatureKey(&m_reconSurface);
}
)
if ((m_currPass == m_numPasses) &&
m_signalEnc &&
m_currRefSync &&
!Mos_ResourceIsNull(&m_currRefSync->resSyncObject))
{
// signal semaphore
MOS_SYNC_PARAMS syncParams = g_cInitSyncParams;
syncParams.GpuContext = m_videoContext;
syncParams.presSyncResource = &m_currRefSync->resSyncObject;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnEngineSignal(m_osInterface, &syncParams));
m_currRefSync->uiSemaphoreObjCount++;
m_currRefSync->bInUsed = true;
}
}
// Reset parameters for next PAK execution
if (m_currPass == m_numPasses)
{
if (!m_singleTaskPhaseSupported)
{
m_osInterface->pfnResetPerfBufferID(m_osInterface);
}
m_currPakSliceIdx = (m_currPakSliceIdx + 1) % CODECHAL_HEVC_NUM_PAK_SLICE_BATCH_BUFFERS;
if (m_hevcSeqParams->ParallelBRC)
{
m_brcBuffers.uiCurrBrcPakStasIdxForWrite =
(m_brcBuffers.uiCurrBrcPakStasIdxForWrite + 1) % CODECHAL_ENCODE_RECYCLED_BUFFER_NUM;
}
m_newPpsHeader = 0;
m_newSeqHeader = 0;
m_frameNum++;
}
return eStatus;
}
//------------------------------------------------------------------------------
//| Purpose: Retrieves the HCP registers and stores them in the status report
//| Return: N/A
//------------------------------------------------------------------------------
MOS_STATUS CodechalEncHevcState::ReadHcpStatus(PMOS_COMMAND_BUFFER cmdBuffer)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
CODECHAL_ENCODE_CHK_NULL_RETURN(cmdBuffer);
CODECHAL_ENCODE_CHK_STATUS_RETURN(CodechalEncodeHevcBase::ReadHcpStatus(cmdBuffer));
CODECHAL_ENCODE_CHK_STATUS_RETURN(ReadImageStatus(cmdBuffer))
return eStatus;
}
uint8_t CodechalEncHevcState::CalculateROIRatio()
{
uint32_t roiSize = 0;
for (uint32_t i = 0; i < m_hevcPicParams->NumROI; ++i)
{
roiSize += (ENCODE_DP_HEVC_ROI_BLOCK_Width * (MOS_ABS(m_hevcPicParams->ROI[i].Top - m_hevcPicParams->ROI[i].Bottom) + 1 )) *
(ENCODE_DP_HEVC_ROI_BLOCK_HEIGHT * (MOS_ABS(m_hevcPicParams->ROI[i].Right - m_hevcPicParams->ROI[i].Left) + 1));
}
uint32_t roiRatio = 0;
if (roiSize)
{
uint32_t numMBs = m_picWidthInMb * m_picHeightInMb;
roiRatio = 2 * (numMBs * 256 / roiSize - 1);
roiRatio = MOS_MIN(51, roiRatio);
}
return (uint8_t)roiRatio;
}
int16_t CodechalEncHevcState::ComputeTemporalDifference(const CODEC_PICTURE& refPic)
{
int16_t diff_poc = 0;
if (!CodecHal_PictureIsInvalid(refPic))
{
diff_poc = m_hevcPicParams->CurrPicOrderCnt - m_hevcPicParams->RefFramePOCList[refPic.FrameIdx];
if(diff_poc < -128)
{
diff_poc = -128;
}
else if(diff_poc > 127)
{
diff_poc = 127;
}
}
return diff_poc;
}
MOS_STATUS CodechalEncHevcState::WaitForRefFrameReady(uint8_t mbCodeIdx)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
if (!m_refSync[mbCodeIdx].bInUsed)
{
return eStatus;
}
MOS_SYNC_PARAMS syncParams = g_cInitSyncParams;
syncParams.GpuContext = m_renderContext;
syncParams.presSyncResource = &m_refSync[mbCodeIdx].resSyncObject;
syncParams.uiSemaphoreCount = m_refSync[mbCodeIdx].uiSemaphoreObjCount;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_osInterface->pfnEngineWait(m_osInterface, &syncParams));
m_refSync[mbCodeIdx].uiSemaphoreObjCount = 0;
m_refSync[mbCodeIdx].bInUsed = false;
return eStatus;
}
MOS_STATUS CodechalEncHevcState::WaitForPak()
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
if (m_pictureCodingType == I_TYPE && !m_brcEnabled)
{
return eStatus;
}
if (!m_firstFrame && m_brcEnabled && !m_hevcSeqParams->ParallelBRC)
{
// When there is no parallel BRC, we still need to wait for previous PAK
CODECHAL_ENCODE_CHK_STATUS_RETURN(WaitForRefFrameReady(m_lastMbCodeIndex));
return eStatus;
}
// check all reference frames. If one of them has not be waited, then it needs to be wait and ensure it has been encoded completely.
auto slcParams = m_hevcSliceParams;
for (uint32_t s = 0; s < m_numSlices; s++, slcParams++)
{
for (auto ll = 0; ll < 2; ll++)
{
uint32_t uiNumRef = (ll == 0) ? slcParams->num_ref_idx_l0_active_minus1 :
slcParams->num_ref_idx_l1_active_minus1;
for (uint32_t i = 0; i <= uiNumRef; i++)
{
CODEC_PICTURE refPic = slcParams->RefPicList[ll][i];
if (!CodecHal_PictureIsInvalid(refPic) &&
!CodecHal_PictureIsInvalid(m_hevcPicParams->RefFrameList[refPic.FrameIdx]))
{
uint32_t idx = m_hevcPicParams->RefFrameList[refPic.FrameIdx].FrameIdx;
uint8_t mbCodeIdx = m_refList[idx]->ucMbCodeIdx;
CODECHAL_ENCODE_CHK_STATUS_RETURN(WaitForRefFrameReady(mbCodeIdx));
}
}
}
}
if (!m_firstTwoFrames && m_brcEnabled && m_hevcSeqParams->ParallelBRC)
{
// When parallel BRC, we still need to wait for the (N-2) PAK
CODECHAL_ENCODE_CHK_STATUS_RETURN(WaitForRefFrameReady(m_currMinus2MbCodeIndex));
return eStatus;
}
return eStatus;
}
MOS_STATUS CodechalEncHevcState::UserFeatureKeyReport()
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
CODECHAL_ENCODE_CHK_STATUS_RETURN(CodechalEncodeHevcBase::UserFeatureKeyReport());
CodecHalEncode_WriteKey(__MEDIA_USER_FEATURE_VALUE_HEVC_ENCODE_REGION_NUMBER_ID, m_numRegionsInSlice, m_osInterface->pOsContext);
return eStatus;
}
MOS_STATUS CodechalEncHevcState::InitSurfaceCodecParams2D(
CODECHAL_SURFACE_CODEC_PARAMS* params,
PMOS_SURFACE surface,
uint32_t cacheabilityControl,
uint32_t bindingTableOffset,
uint32_t verticalLineStride,
bool isWritable)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
CODECHAL_ENCODE_CHK_NULL_RETURN(params);
MOS_ZeroMemory(params, sizeof(*params));
params->bIs2DSurface = true;
params->bMediaBlockRW = true; // Use media block RW for DP 2D surface access
params->psSurface = surface;
params->dwCacheabilityControl = cacheabilityControl;
params->dwBindingTableOffset = bindingTableOffset;
params->dwVerticalLineStride = verticalLineStride;
params->bIsWritable =
params->bRenderTarget = isWritable;
return eStatus;
}
MOS_STATUS CodechalEncHevcState::InitSurfaceCodecParamsVME(
CODECHAL_SURFACE_CODEC_PARAMS* params,
PMOS_SURFACE surface,
uint32_t cacheabilityControl,
uint32_t bindingTableOffset)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
CODECHAL_ENCODE_CHK_NULL_RETURN(params);
MOS_ZeroMemory(params, sizeof(*params));
params->bUseAdvState = true;
params->psSurface = surface;
params->dwCacheabilityControl= cacheabilityControl;
params->dwBindingTableOffset = bindingTableOffset;
params->ucVDirection = CODECHAL_VDIRECTION_FRAME;
// surface has valid values and have support for the formats specified below
if (surface != nullptr && (surface->Format == Format_YUY2V || surface->Format == Format_Y216V))
{
params->dwWidthInUse = surface->dwWidth;
params->dwHeightInUse = surface->dwHeight;
}
return eStatus;
}
MOS_STATUS CodechalEncHevcState::InitSurfaceCodecParams1D(
CODECHAL_SURFACE_CODEC_PARAMS* params,
PMOS_RESOURCE buffer,
uint32_t size,
uint32_t offset,
uint32_t cacheabilityControl,
uint32_t bindingTableOffset,
bool isWritable)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
CODECHAL_ENCODE_CHK_NULL_RETURN(params);
MOS_ZeroMemory(params, sizeof(*params));
params->presBuffer = buffer;
params->dwSize = size;
params->dwOffset = offset;
params->dwCacheabilityControl = cacheabilityControl;
params->dwBindingTableOffset = bindingTableOffset;
params->bIsWritable =
params->bRenderTarget = isWritable;
return eStatus;
}
CodechalEncHevcState::CodechalEncHevcState(
CodechalHwInterface* hwInterface,
CodechalDebugInterface* debugInterface,
PCODECHAL_STANDARD_INFO standardInfo)
:CodechalEncodeHevcBase(hwInterface, debugInterface, standardInfo)
{
CODECHAL_ENCODE_FUNCTION_ENTER;
m_noMeKernelForPFrame = true;
// initialze class members
MOS_ZeroMemory(&m_formatConvertedSurface, sizeof(m_formatConvertedSurface));
MOS_ZeroMemory(&m_brcBuffers, sizeof(m_brcBuffers));
}
CodechalEncHevcState::~CodechalEncHevcState()
{
if (m_hmeKernel)
{
MOS_Delete(m_hmeKernel);
m_hmeKernel = nullptr;
}
}
MOS_STATUS CodechalEncHevcState::AllocateBrcResources()
{
CODECHAL_ENCODE_FUNCTION_ENTER;
// initiate allocation paramters and lock flags
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;
MOS_ALLOC_GFXRES_PARAMS allocParamsForBuffer2D;
MOS_ZeroMemory(&allocParamsForBuffer2D, sizeof(MOS_ALLOC_GFXRES_PARAMS));
allocParamsForBuffer2D.Type = MOS_GFXRES_2D;
allocParamsForBuffer2D.TileType = MOS_TILE_LINEAR;
allocParamsForBuffer2D.Format = Format_Buffer_2D;
MOS_LOCK_PARAMS lockFlagsWriteOnly;
MOS_ZeroMemory(&lockFlagsWriteOnly, sizeof(MOS_LOCK_PARAMS));
lockFlagsWriteOnly.WriteOnly = true;
// BRC history buffer
uint32_t size = m_brcHistoryBufferSize;
allocParamsForBufferLinear.dwBytes = size;
allocParamsForBufferLinear.pBufName = "BRC History Buffer";
MOS_STATUS eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
m_osInterface,
&allocParamsForBufferLinear,
&m_brcBuffers.resBrcHistoryBuffer);
if (eStatus != MOS_STATUS_SUCCESS)
{
CODECHAL_ENCODE_ASSERTMESSAGE("Failed to allocate BRC History Buffer.");
return eStatus;
}
uint8_t *data = (uint8_t *)m_osInterface->pfnLockResource(
m_osInterface,
&(m_brcBuffers.resBrcHistoryBuffer),
&lockFlagsWriteOnly);
if (data == nullptr)
{
CODECHAL_ENCODE_ASSERTMESSAGE("Failed to Lock BRC History Buffer.");
eStatus = MOS_STATUS_UNKNOWN;
return eStatus;
}
MOS_ZeroMemory(data, size);
m_osInterface->pfnUnlockResource(m_osInterface, &m_brcBuffers.resBrcHistoryBuffer);
// BRC Intra Distortion Surface
uint32_t width = MOS_ALIGN_CEIL((m_downscaledWidthInMb4x << 3), 64);
uint32_t height = MOS_ALIGN_CEIL((m_downscaledHeightInMb4x << 2), 8) << 1;
allocParamsForBuffer2D.dwWidth = width;
allocParamsForBuffer2D.dwHeight = height;
allocParamsForBuffer2D.pBufName = "BRC Distortion Surface Buffer";
CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(m_osInterface->pfnAllocateResource(
m_osInterface,
&allocParamsForBuffer2D,
&m_brcBuffers.sBrcIntraDistortionBuffer.OsResource),
"Failed to allocate ME BRC Distortion Buffer.");
CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHalGetResourceInfo(m_osInterface, &m_brcBuffers.sBrcIntraDistortionBuffer));
m_brcBuffers.sBrcIntraDistortionBuffer.bArraySpacing = true;
size = m_brcBuffers.sBrcIntraDistortionBuffer.dwHeight * m_brcBuffers.sBrcIntraDistortionBuffer.dwPitch;
CODECHAL_ENCODE_CHK_NULL_RETURN(data = (uint8_t *)m_osInterface->pfnLockResource(
m_osInterface,
&m_brcBuffers.sBrcIntraDistortionBuffer.OsResource,
&lockFlagsWriteOnly));
MOS_ZeroMemory(data, size);
m_osInterface->pfnUnlockResource(
m_osInterface, &m_brcBuffers.sBrcIntraDistortionBuffer.OsResource);
// PAK Statistics buffer
size = m_hevcBrcPakStatisticsSize;
allocParamsForBufferLinear.dwBytes = size;
allocParamsForBufferLinear.pBufName = "BRC PAK Statistics Buffer";
for (auto i = 0; i < CODECHAL_ENCODE_RECYCLED_BUFFER_NUM; i++)
{
eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
m_osInterface,
&allocParamsForBufferLinear,
&m_brcBuffers.resBrcPakStatisticBuffer[i]);
if (eStatus != MOS_STATUS_SUCCESS)
{
CODECHAL_ENCODE_ASSERTMESSAGE("Failed to allocate BRC PAK Statistics Buffer.");
return eStatus;
}
data = (uint8_t *)m_osInterface->pfnLockResource(
m_osInterface,
&(m_brcBuffers.resBrcPakStatisticBuffer[i]),
&lockFlagsWriteOnly);
if (data == nullptr)
{
CODECHAL_ENCODE_ASSERTMESSAGE("Failed to Lock BRC PAK Statistics Buffer.");
eStatus = MOS_STATUS_UNKNOWN;
return eStatus;
}
MOS_ZeroMemory(data, size);
m_osInterface->pfnUnlockResource(m_osInterface, &m_brcBuffers.resBrcPakStatisticBuffer[i]);
}
// PAK HCP_PICTURE_STATEs buffer
size = m_brcBuffers.dwBrcHcpPicStateSize;
allocParamsForBufferLinear.dwBytes = size;
allocParamsForBufferLinear.pBufName = "PAK HCP PICTURE State Read Buffer";
for (auto i = 0; i < CODECHAL_ENCODE_RECYCLED_BUFFER_NUM; i++)
{
eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
m_osInterface,
&allocParamsForBufferLinear,
&m_brcBuffers.resBrcImageStatesReadBuffer[i]);
if (eStatus != MOS_STATUS_SUCCESS)
{
CODECHAL_ENCODE_ASSERTMESSAGE("Failed to allocate HCP PICTURE State Read Buffer.");
return eStatus;
}
data = (uint8_t *)m_osInterface->pfnLockResource(
m_osInterface,
&(m_brcBuffers.resBrcImageStatesReadBuffer[i]),
&lockFlagsWriteOnly);
if (data == nullptr)
{
CODECHAL_ENCODE_ASSERTMESSAGE("Failed to Lock HCP PICTURE State Read Buffer.");
eStatus = MOS_STATUS_UNKNOWN;
return eStatus;
}
MOS_ZeroMemory(data, size);
m_osInterface->pfnUnlockResource(m_osInterface, &m_brcBuffers.resBrcImageStatesReadBuffer[i]);
}
allocParamsForBufferLinear.pBufName = "PAK HCP PICTURE State Write Buffer";
for (auto i = 0; i < CODECHAL_ENCODE_RECYCLED_BUFFER_NUM; i++)
{
eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
m_osInterface,
&allocParamsForBufferLinear,
&m_brcBuffers.resBrcImageStatesWriteBuffer[i]);
CODECHAL_ENCODE_CHK_STATUS_MESSAGE_RETURN(eStatus, "Failed to allocate HCP PICTURE State Write Buffer.");
data = (uint8_t *)m_osInterface->pfnLockResource(
m_osInterface,
&m_brcBuffers.resBrcImageStatesWriteBuffer[i],
&lockFlagsWriteOnly);
if (data == nullptr)
{
CODECHAL_ENCODE_ASSERTMESSAGE("Failed to Lock HCP PICTURE State Write Buffer.");
eStatus = MOS_STATUS_NULL_POINTER;
return eStatus;
}
MOS_ZeroMemory(data, size);
m_osInterface->pfnUnlockResource(m_osInterface, &m_brcBuffers.resBrcImageStatesWriteBuffer[i]);
}
// BRC constant data surface
allocParamsForBuffer2D.dwWidth = MOS_ALIGN_CEIL(m_brcBuffers.dwBrcConstantSurfaceWidth, 64);
allocParamsForBuffer2D.dwHeight = m_brcBuffers.dwBrcConstantSurfaceHeight;
allocParamsForBuffer2D.pBufName = "BRC Constant Data Buffer";
for (auto i = 0; i < CODECHAL_ENCODE_RECYCLED_BUFFER_NUM; i++)
{
eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
m_osInterface,
&allocParamsForBuffer2D,
&m_brcBuffers.sBrcConstantDataBuffer[i].OsResource);
if (eStatus != MOS_STATUS_SUCCESS)
{
CODECHAL_ENCODE_ASSERTMESSAGE("Failed to allocate BRC Constant Data Buffer.");
return eStatus;
}
CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHalGetResourceInfo(m_osInterface, &m_brcBuffers.sBrcConstantDataBuffer[i]));
m_brcBuffers.sBrcConstantDataBuffer[i].bArraySpacing = true;
}
// Use the Mb QP buffer in BrcBuffer for LCU-based Qp surface in HEVC
MOS_ZeroMemory(&m_brcBuffers.sBrcMbQpBuffer, sizeof(m_brcBuffers.sBrcMbQpBuffer));
// original picture size in MB units aligned to 64 bytes along width and 8 bytes along height
width = MOS_ALIGN_CEIL((m_downscaledWidthInMb4x * SCALE_FACTOR_4x), 64);
height = MOS_ALIGN_CEIL((m_downscaledHeightInMb4x * SCALE_FACTOR_4x), 8);
size = width * height;
allocParamsForBuffer2D.dwWidth = width;
allocParamsForBuffer2D.dwHeight = height;
allocParamsForBuffer2D.pBufName = "BRC MB QP Buffer";
eStatus = (MOS_STATUS)m_osInterface->pfnAllocateResource(
m_osInterface,
&allocParamsForBuffer2D,
&m_brcBuffers.sBrcMbQpBuffer.OsResource);
if (eStatus != MOS_STATUS_SUCCESS)
{
CODECHAL_ENCODE_ASSERTMESSAGE("Failed to allocate BRC MB QP Buffer.");
return eStatus;
}
CODECHAL_ENCODE_CHK_STATUS_RETURN(CodecHalGetResourceInfo(m_osInterface, &m_brcBuffers.sBrcMbQpBuffer));
m_brcBuffers.sBrcMbQpBuffer.bArraySpacing = true;
data = (uint8_t *)m_osInterface->pfnLockResource(
m_osInterface,
&(m_brcBuffers.sBrcMbQpBuffer.OsResource),
&lockFlagsWriteOnly);
if (data == nullptr)
{
CODECHAL_ENCODE_ASSERTMESSAGE("Failed to Lock BRC MB QP Buffer.");
eStatus = MOS_STATUS_UNKNOWN;
return eStatus;
}
MOS_ZeroMemory(data, size);
m_osInterface->pfnUnlockResource(
m_osInterface,
&m_brcBuffers.sBrcMbQpBuffer.OsResource);
// ROI surface
MOS_ZeroMemory(&m_brcBuffers.sBrcRoiSurface, sizeof(m_brcBuffers.sBrcRoiSurface));
// original picture size in MB units aligned to 64 bytes along width and 8 bytes along height
// ROI buffer size uses MB units for HEVC, not LCU
width = MOS_ALIGN_CEIL((m_downscaledWidthInMb4x << 4), 64);
height = MOS_ALIGN_CEIL((m_downscaledHeightInMb4x << 2), 8);
MOS_ZeroMemory(&m_brcBuffers.sBrcRoiSurface, sizeof(m_brcBuffers.sBrcRoiSurface));
m_brcBuffers.sBrcRoiSurface.TileType = MOS_TILE_LINEAR;
m_brcBuffers.sBrcRoiSurface.bArraySpacing = true;
m_brcBuffers.sBrcRoiSurface.Format = Format_Buffer_2D;
m_brcBuffers.sBrcRoiSurface.dwWidth = width;
m_brcBuffers.sBrcRoiSurface.dwPitch = width;
m_brcBuffers.sBrcRoiSurface.dwHeight = height;
CODECHAL_ENCODE_CHK_STATUS_RETURN(AllocateBuffer2D(
&m_brcBuffers.sBrcRoiSurface,
width,
height,
"ROI Buffer"));
return eStatus;
}
MOS_STATUS CodechalEncHevcState::FreeBrcResources()
{
CODECHAL_ENCODE_FUNCTION_ENTER;
m_osInterface->pfnFreeResource(
m_osInterface,
&m_brcBuffers.resBrcHistoryBuffer);
for (auto i = 0; i < CODECHAL_ENCODE_RECYCLED_BUFFER_NUM; i++)
{
m_osInterface->pfnFreeResource(
m_osInterface,
&m_brcBuffers.resBrcPakStatisticBuffer[i]);
m_osInterface->pfnFreeResource(
m_osInterface,
&m_brcBuffers.resBrcImageStatesReadBuffer[i]);
m_osInterface->pfnFreeResource(
m_osInterface,
&m_brcBuffers.resBrcImageStatesWriteBuffer[i]);
m_osInterface->pfnFreeResource(
m_osInterface,
&m_brcBuffers.sBrcConstantDataBuffer[i].OsResource);
}
m_osInterface->pfnFreeResource(
m_osInterface,
&m_brcBuffers.sBrcIntraDistortionBuffer.OsResource);
m_osInterface->pfnFreeResource(
m_osInterface,
&m_brcBuffers.sBrcMbQpBuffer.OsResource);
m_osInterface->pfnFreeResource(
m_osInterface,
&m_brcBuffers.sBrcRoiSurface.OsResource);
return MOS_STATUS_SUCCESS;
}
MOS_STATUS CodechalEncHevcState::AllocateEncStatsResources()
{
CODECHAL_ENCODE_FUNCTION_ENTER;
if (Mos_ResourceIsNull(&m_encStatsBuffers.m_puStatsSurface.OsResource))
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(AllocateBuffer2D(
&m_encStatsBuffers.m_puStatsSurface,
m_widthAlignedMaxLcu,
m_heightAlignedMaxLcu >> 5,
"32x32 PU statistics Data Dump surface"));
}
if (Mos_ResourceIsNull(&m_encStatsBuffers.m_8x8PuHaarDist.OsResource))
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(AllocateBuffer2D(
&m_encStatsBuffers.m_8x8PuHaarDist,
m_widthAlignedMaxLcu,
m_heightAlignedMaxLcu >> 4,
"8x8 PU Haar distortion for 16x16 surface"));
}
if (Mos_ResourceIsNull(&m_encStatsBuffers.m_8x8PuFrameStats.sResource))
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(AllocateBuffer(
&m_encStatsBuffers.m_8x8PuFrameStats,
m_8x8PuFrameStatsSize,
"8x8 PU frame statistics surface"));
}
if (Mos_ResourceIsNull(&m_encStatsBuffers.m_mbEncStatsSurface.OsResource))
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(AllocateBuffer2D(
&m_encStatsBuffers.m_mbEncStatsSurface,
m_widthAlignedMaxLcu,
m_heightAlignedMaxLcu >> 5,
"MB Enc Statistics data dump surface"));
}
if (Mos_ResourceIsNull(&m_encStatsBuffers.m_mbEncFrameStats.sResource))
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(AllocateBuffer(
&m_encStatsBuffers.m_mbEncFrameStats,
m_mbEncFrameStatsSize,
"MB Enc frame statistics surface"));
}
return MOS_STATUS_SUCCESS;
}
MOS_STATUS CodechalEncHevcState::FreeEncStatsResources()
{
CODECHAL_ENCODE_FUNCTION_ENTER;
m_osInterface->pfnFreeResource(
m_osInterface,
&m_encStatsBuffers.m_puStatsSurface.OsResource);
m_osInterface->pfnFreeResource(
m_osInterface,
&m_encStatsBuffers.m_8x8PuHaarDist.OsResource);
m_osInterface->pfnFreeResource(
m_osInterface,
&m_encStatsBuffers.m_8x8PuFrameStats.sResource);
m_osInterface->pfnFreeResource(
m_osInterface,
&m_encStatsBuffers.m_mbEncStatsSurface.OsResource);
m_osInterface->pfnFreeResource(
m_osInterface,
&m_encStatsBuffers.m_mbEncFrameStats.sResource);
return MOS_STATUS_SUCCESS;
}
bool CodechalEncHevcState::CheckSupportedFormat(PMOS_SURFACE surface)
{
CODECHAL_ENCODE_FUNCTION_ENTER;
bool isColorFormatSupported = false;
if (nullptr == surface)
{
CODECHAL_ENCODE_ASSERTMESSAGE("Invalid (nullptr) Pointer.");
return isColorFormatSupported;
}
switch (surface->Format)
{
case Format_NV12:
isColorFormatSupported = IS_Y_MAJOR_TILE_FORMAT(surface->TileType);
break;
case Format_P010:
isColorFormatSupported = true;
case Format_YUY2:
case Format_YUYV:
case Format_A8R8G8B8:
break;
default:
CODECHAL_ENCODE_ASSERTMESSAGE("Input surface color format = %d not supported!", surface->Format);
break;
}
return isColorFormatSupported;
}
MOS_STATUS CodechalEncHevcState::Initialize(CodechalSetting * settings)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
// common initilization
CODECHAL_ENCODE_CHK_STATUS_RETURN(CodechalEncodeHevcBase::Initialize(settings));
m_brcBuffers.dwBrcHcpPicStateSize = BRC_IMG_STATE_SIZE_PER_PASS * CODECHAL_ENCODE_BRC_MAXIMUM_NUM_PASSES;
m_brcBuffers.uiCurrBrcPakStasIdxForRead = 0;
//Reading buffer is with 2 frames late for BRC kernel uses the PAK statstic info of the frame before the previous frame
m_brcBuffers.uiCurrBrcPakStasIdxForWrite =
(m_brcBuffers.uiCurrBrcPakStasIdxForRead + 2) % CODECHAL_ENCODE_RECYCLED_BUFFER_NUM;
m_widthAlignedLcu32 = MOS_ALIGN_CEIL(m_frameWidth, 32);
m_heightAlignedLcu32 = MOS_ALIGN_CEIL(m_frameHeight, 32);
m_hucCommandsSize = m_hwInterface->m_hucCommandBufferSize * CODECHAL_HEVC_MAX_NUM_BRC_PASSES;
return eStatus;
}
MOS_STATUS CodechalEncHevcState::GetFrameBrcLevel()
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
if (m_lowDelay)
{
// LDB
if (m_pictureCodingType == I_TYPE)
{
if (m_hevcPicParams->HierarchLevelPlus1 == 0)
{
m_currFrameBrcLevel = HEVC_BRC_FRAME_TYPE_I;
}
else
{
CODECHAL_ENCODE_ASSERTMESSAGE("FrameLevel can only be 0 for I type for LDB\n");
return MOS_STATUS_INVALID_PARAMETER;
}
}
else if ((m_pictureCodingType == P_TYPE) || (m_pictureCodingType == B_TYPE))
{
if (m_hevcPicParams->HierarchLevelPlus1 == 0)
{
m_currFrameBrcLevel = HEVC_BRC_FRAME_TYPE_P_OR_LB;
}
else if (m_hevcPicParams->HierarchLevelPlus1 == 1)
{
m_currFrameBrcLevel = HEVC_BRC_FRAME_TYPE_B;
}
else if (m_hevcPicParams->HierarchLevelPlus1 == 2)
{
m_currFrameBrcLevel = HEVC_BRC_FRAME_TYPE_B1;
}
else if (m_hevcPicParams->HierarchLevelPlus1 == 3)
{
CODECHAL_ENCODE_ASSERTMESSAGE("FrameLevel 3 is not supported for LDB\n");
return MOS_STATUS_INVALID_PARAMETER;
}
else
{
CODECHAL_ENCODE_ASSERT(false);
return MOS_STATUS_INVALID_PARAMETER;
}
}
else if ((m_pictureCodingType == B1_TYPE) || (m_pictureCodingType == B2_TYPE))
{
CODECHAL_ENCODE_ASSERTMESSAGE("B1 & B2 Type is not supported for LDB\n");
return MOS_STATUS_INVALID_PARAMETER;
}
else
{
CODECHAL_ENCODE_ASSERT(false);
return MOS_STATUS_INVALID_PARAMETER;
}
}
else
{
// HB
if (m_pictureCodingType == I_TYPE)
{
m_currFrameBrcLevel = HEVC_BRC_FRAME_TYPE_I;
}
else if (m_pictureCodingType == B_TYPE)
{
m_currFrameBrcLevel = HEVC_BRC_FRAME_TYPE_B;
}
else if (m_pictureCodingType == B1_TYPE)
{
m_currFrameBrcLevel = HEVC_BRC_FRAME_TYPE_B1;
}
else if (m_pictureCodingType == B2_TYPE)
{
m_currFrameBrcLevel = HEVC_BRC_FRAME_TYPE_B2;
}
else if (m_pictureCodingType == P_TYPE)
{
m_currFrameBrcLevel = HEVC_BRC_FRAME_TYPE_P_OR_LB;
}
else
{
CODECHAL_ENCODE_ASSERT(false);
return MOS_STATUS_INVALID_PARAMETER;
}
}
return eStatus;
}
MOS_STATUS CodechalEncHevcState::InitializePicture(const EncoderParams& params)
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
CODECHAL_ENCODE_CHK_STATUS_RETURN(CodechalEncodeHevcBase::InitializePicture(params));
CODECHAL_ENCODE_CHK_STATUS_RETURN(GetFrameBrcLevel());
return eStatus;
}
MOS_STATUS CodechalEncHevcState::SetMeCurbeParams(
CodechalKernelHme::CurbeParam &curbeParams)
{
CODECHAL_ENCODE_FUNCTION_ENTER;
// Setup ME Params
MOS_ZeroMemory(&curbeParams, sizeof(curbeParams));
curbeParams.subPelMode = 3;
curbeParams.currOriginalPic = m_hevcPicParams->CurrOriginalPic;
curbeParams.qpPrimeY = m_hevcPicParams->QpY + m_hevcSliceParams->slice_qp_delta;
curbeParams.targetUsage = m_hevcSeqParams->TargetUsage;
curbeParams.maxMvLen = CODECHAL_ENCODE_HEVC_MAX_MV_LEN_AVC_LEVEL_51;
curbeParams.numRefIdxL0Minus1 = m_hevcSliceParams->num_ref_idx_l0_active_minus1;
curbeParams.numRefIdxL1Minus1 = m_hevcSliceParams->num_ref_idx_l1_active_minus1;
curbeParams.bmeMethodTable = m_bmeMethodTable;
curbeParams.meMethodTable = m_meMethodTable;
return MOS_STATUS_SUCCESS;
}
MOS_STATUS CodechalEncHevcState::SetMeSurfaceParams(
CodechalKernelHme::SurfaceParams &surfaceParams)
{
CODECHAL_ENCODE_FUNCTION_ENTER;
// Setup ME Params
MOS_ZeroMemory(&surfaceParams, sizeof(surfaceParams));
surfaceParams.mbaffEnabled = false;
surfaceParams.numRefIdxL0ActiveMinus1 = m_hevcSliceParams->num_ref_idx_l0_active_minus1;
surfaceParams.numRefIdxL1ActiveMinus1 = m_hevcSliceParams->num_ref_idx_l1_active_minus1;
surfaceParams.verticalLineStride = m_verticalLineStride;
surfaceParams.verticalLineStrideOffset = m_verticalLineStrideOffset;
surfaceParams.meBrcDistortionBuffer = &m_brcBuffers.sMeBrcDistortionBuffer;
surfaceParams.meBrcDistortionBottomFieldOffset = m_brcBuffers.dwMeBrcDistortionBottomFieldOffset;
surfaceParams.refList = &m_refList[0];
surfaceParams.picIdx = &m_picIdx[0];
surfaceParams.currOriginalPic = &m_currOriginalPic;
surfaceParams.refL0List = &(m_hevcSliceParams->RefPicList[LIST_0][0]);
surfaceParams.refL1List = &(m_hevcSliceParams->RefPicList[LIST_1][0]);
return MOS_STATUS_SUCCESS;
}
MOS_STATUS CodechalEncHevcState::EncodeMeKernel()
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
// Walker must be used for HME call and scaling one
CODECHAL_ENCODE_ASSERT(m_hwWalker);
if (m_hmeKernel && m_hmeKernel->Is4xMeEnabled())
{
CodechalKernelHme::CurbeParam curbeParam;
CODECHAL_ENCODE_CHK_STATUS_RETURN(SetMeCurbeParams(curbeParam));
CodechalKernelHme::SurfaceParams surfaceParam;
CODECHAL_ENCODE_CHK_STATUS_RETURN(SetMeSurfaceParams(surfaceParam));
if (m_hmeKernel->Is16xMeEnabled())
{
if (m_hmeKernel->Is32xMeEnabled())
{
surfaceParam.downScaledWidthInMb = m_downscaledWidthInMb32x;
surfaceParam.downScaledHeightInMb = m_downscaledFrameFieldHeightInMb32x;
surfaceParam.downScaledBottomFieldOffset = m_scaled32xBottomFieldOffset;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hmeKernel->Execute(curbeParam, surfaceParam, CodechalKernelHme::HmeLevel::hmeLevel32x));
}
surfaceParam.downScaledWidthInMb = m_downscaledWidthInMb16x;
surfaceParam.downScaledHeightInMb = m_downscaledFrameFieldHeightInMb16x;
surfaceParam.downScaledBottomFieldOffset = m_scaled16xBottomFieldOffset;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hmeKernel->Execute(curbeParam, surfaceParam, CodechalKernelHme::HmeLevel::hmeLevel16x));
}
surfaceParam.downScaledWidthInMb = m_downscaledWidthInMb4x;
surfaceParam.downScaledHeightInMb = m_downscaledFrameFieldHeightInMb4x;
surfaceParam.downScaledBottomFieldOffset = m_scaledBottomFieldOffset;
m_lastTaskInPhase = true;
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_hmeKernel->Execute(curbeParam, surfaceParam, CodechalKernelHme::HmeLevel::hmeLevel4x));
}
CODECHAL_ENCODE_CHK_STATUS_RETURN(DumpHMESurfaces());
return eStatus;
}
MOS_STATUS CodechalEncHevcState::DumpHMESurfaces()
{
CODECHAL_ENCODE_FUNCTION_ENTER;
CODECHAL_DEBUG_TOOL(
if (m_hmeEnabled) {
PMOS_SURFACE dumpBuffer = m_hmeKernel->GetSurface(CodechalKernelHme::SurfaceId::me4xMvDataBuffer);
if (dumpBuffer)
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpBuffer(
&dumpBuffer->OsResource,
CodechalDbgAttr::attrOutput,
"MvData",
dumpBuffer->dwHeight *dumpBuffer->dwPitch,
CodecHal_PictureIsBottomField(m_currOriginalPic) ? MOS_ALIGN_CEIL((m_downscaledWidthInMb4x * 32), 64) * (m_downscaledFrameFieldHeightInMb4x * 4) : 0,
CODECHAL_MEDIA_STATE_4X_ME));
}
dumpBuffer = m_hmeKernel->GetSurface(CodechalKernelHme::SurfaceId::me4xDistortionBuffer);
if (dumpBuffer)
{
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpBuffer(
&dumpBuffer->OsResource,
CodechalDbgAttr::attrOutput,
"MeDist",
dumpBuffer->dwHeight * dumpBuffer->dwPitch,
CodecHal_PictureIsBottomField(m_currOriginalPic) ? MOS_ALIGN_CEIL((m_downscaledWidthInMb4x * 8), 64) * MOS_ALIGN_CEIL((m_downscaledFrameFieldHeightInMb4x * 4), 8) : 0,
CODECHAL_MEDIA_STATE_4X_ME));
}
if (m_b16XMeEnabled)
{
dumpBuffer = m_hmeKernel->GetSurface(CodechalKernelHme::SurfaceId::me16xMvDataBuffer);
// &meOutputParams));
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpBuffer(
&dumpBuffer->OsResource,
CodechalDbgAttr::attrOutput,
"MvData",
dumpBuffer->dwHeight *dumpBuffer->dwPitch,
CodecHal_PictureIsBottomField(m_currOriginalPic) ? MOS_ALIGN_CEIL((m_downscaledWidthInMb16x * 32), 64) * (m_downscaledFrameFieldHeightInMb16x * 4) : 0,
CODECHAL_MEDIA_STATE_16X_ME));
if (m_b32XMeEnabled)
{
dumpBuffer = m_hmeKernel->GetSurface(CodechalKernelHme::SurfaceId::me32xMvDataBuffer);
CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpBuffer(
&dumpBuffer->OsResource,
CodechalDbgAttr::attrOutput,
"MvData",
dumpBuffer->dwHeight *dumpBuffer->dwPitch,
CodecHal_PictureIsBottomField(m_currOriginalPic) ? MOS_ALIGN_CEIL((m_downscaledWidthInMb32x * 32), 64) * (m_downscaledFrameFieldHeightInMb32x * 4) : 0,
CODECHAL_MEDIA_STATE_32X_ME));
}
}
})
return MOS_STATUS_SUCCESS;
}
MOS_STATUS CodechalEncHevcState::SetupROISurface()
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
MOS_LOCK_PARAMS ReadOnly;
MOS_ZeroMemory(&ReadOnly, sizeof(ReadOnly));
ReadOnly.ReadOnly = 1;
uint32_t * dataPtr = (uint32_t *)m_osInterface->pfnLockResource(m_osInterface, &m_brcBuffers.sBrcRoiSurface.OsResource, &ReadOnly);
if (!dataPtr)
{
eStatus = MOS_STATUS_INVALID_HANDLE;
return eStatus;
}
uint32_t bufferWidthInByte = m_brcBuffers.sBrcRoiSurface.dwPitch;
uint32_t bufferHeightInByte = MOS_ALIGN_CEIL((m_downscaledHeightInMb4x << 2), 8);
uint32_t numMBs = m_picWidthInMb * m_picHeightInMb;
for (uint32_t uMB = 0; uMB <= numMBs; uMB++)
{
int32_t curMbY = uMB / m_picWidthInMb;
int32_t curMbX = uMB - curMbY * m_picWidthInMb;
uint32_t outdata = 0;
for (int32_t roiIdx = (m_hevcPicParams->NumROI - 1); roiIdx >= 0; roiIdx--)
{
int32_t qpLevel;
if (m_roiValueInDeltaQp)
{
qpLevel = m_hevcPicParams->ROI[roiIdx].PriorityLevelOrDQp;
}
else
{
// QP Level sent to ROI surface is (priority * 5)
//qpLevel = m_hevcPicParams->ROI[roiIdx].PriorityLevelOrDQp * 6;
CODECHAL_ENCODE_ASSERTMESSAGE("error: ROI does not support priority level for now.");
return MOS_STATUS_INVALID_PARAMETER;
}
if (qpLevel == 0)
{
continue;
}
if ((curMbX >= (int32_t)m_hevcPicParams->ROI[roiIdx].Left) && (curMbX < (int32_t)m_hevcPicParams->ROI[roiIdx].Right) &&
(curMbY >= (int32_t)m_hevcPicParams->ROI[roiIdx].Top) && (curMbY < (int32_t)m_hevcPicParams->ROI[roiIdx].Bottom))
{
outdata = 15 | ((qpLevel & 0xFF) << 16);
}
else if (m_roiRegionSmoothEnabled)
{
if ((curMbX >= (int32_t)m_hevcPicParams->ROI[roiIdx].Left - 1) && (curMbX < (int32_t)m_hevcPicParams->ROI[roiIdx].Right + 1) &&
(curMbY >= (int32_t)m_hevcPicParams->ROI[roiIdx].Top - 1) && (curMbY < (int32_t)m_hevcPicParams->ROI[roiIdx].Bottom + 1))
{
outdata = 14 | ((qpLevel & 0xFF) << 16);
}
else if ((curMbX >= (int32_t)m_hevcPicParams->ROI[roiIdx].Left - 2) && (curMbX < (int32_t)m_hevcPicParams->ROI[roiIdx].Right + 2) &&
(curMbY >= (int32_t)m_hevcPicParams->ROI[roiIdx].Top - 2) && (curMbY < (int32_t)m_hevcPicParams->ROI[roiIdx].Bottom + 2))
{
outdata = 13 | ((qpLevel & 0xFF) << 16);
}
else if ((curMbX >= (int32_t)m_hevcPicParams->ROI[roiIdx].Left - 3) && (curMbX < (int32_t)m_hevcPicParams->ROI[roiIdx].Right + 3) &&
(curMbY >= (int32_t)m_hevcPicParams->ROI[roiIdx].Top - 3) && (curMbY < (int32_t)m_hevcPicParams->ROI[roiIdx].Bottom + 3))
{
outdata = 12 | ((qpLevel & 0xFF) << 16);
}
}
}
dataPtr[(curMbY * (bufferWidthInByte >> 2)) + curMbX] = outdata;
}
m_osInterface->pfnUnlockResource(m_osInterface, &m_brcBuffers.sBrcRoiSurface.OsResource);
uint32_t bufferSize = bufferWidthInByte * bufferHeightInByte;
CODECHAL_DEBUG_TOOL(CODECHAL_ENCODE_CHK_STATUS_RETURN(m_debugInterface->DumpBuffer(
&m_brcBuffers.sBrcRoiSurface.OsResource,
CodechalDbgAttr::attrROISurface,
"ROIInputSurface",
bufferSize,
0,
CODECHAL_NUM_MEDIA_STATES)));
return eStatus;
}
MOS_STATUS CodechalEncHevcState::GetRoundingIntraInterToUse()
{
MOS_STATUS eStatus = MOS_STATUS_SUCCESS;
CODECHAL_ENCODE_FUNCTION_ENTER;
if (m_hevcPicParams->CustomRoundingOffsetsParams.fields.EnableCustomRoudingIntra)
{
m_roundingIntraInUse = m_hevcPicParams->CustomRoundingOffsetsParams.fields.RoundingOffsetIntra;
}
else
{
if (m_hevcSeqParams->NumOfBInGop[1] != 0 || m_hevcSeqParams->NumOfBInGop[2] != 0)
{
//Hierachical B GOP
if (m_hevcPicParams->CodingType == I_TYPE ||
m_hevcPicParams->CodingType == P_TYPE)
{
m_roundingIntraInUse = 4;
}
else if (m_hevcPicParams->CodingType == B_TYPE)
{
m_roundingIntraInUse = 3;
}
else
{
m_roundingIntraInUse = 2;
}
}
else
{
m_roundingIntraInUse = 10;
}
}
if (m_hevcPicParams->CustomRoundingOffsetsParams.fields.EnableCustomRoudingInter)
{
m_roundingInterInUse = m_hevcPicParams->CustomRoundingOffsetsParams.fields.RoundingOffsetInter;
}
else
{
if (m_hevcSeqParams->NumOfBInGop[1] != 0 || m_hevcSeqParams->NumOfBInGop[2] != 0)
{
//Hierachical B GOP
if (m_hevcPicParams->CodingType == I_TYPE ||
m_hevcPicParams->CodingType == P_TYPE)
{
m_roundingInterInUse = 4;
}
else if (m_hevcPicParams->CodingType == B_TYPE)
{
m_roundingInterInUse = 3;
}
else
{
m_roundingInterInUse = 2;
}
}
else
{
m_roundingInterInUse = 4;
}
}
return eStatus;
}