1 /* 2 * Copyright (c) 2019-2020, Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included 12 * in all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 //! 23 //! \file encode_hevc_dss.cpp 24 //! \brief Defines the common interface for hevc encode dynamic slice feature 25 //! 26 27 #include "encode_hevc_basic_feature.h" 28 #include "encode_hevc_dss.h" 29 #include "encode_hevc_vdenc_feature_manager.h" 30 #include "encode_hevc_vdenc_const_settings.h" 31 32 namespace encode 33 { HevcEncodeDss(MediaFeatureManager * featureManager,EncodeAllocator * allocator,CodechalHwInterfaceNext * hwInterface,void * constSettings)34 HevcEncodeDss::HevcEncodeDss( 35 MediaFeatureManager *featureManager, 36 EncodeAllocator *allocator, 37 CodechalHwInterfaceNext *hwInterface, 38 void *constSettings) : 39 MediaFeature(constSettings), 40 m_allocator(allocator), 41 m_hwInterface(hwInterface) 42 { 43 if (!hwInterface || !constSettings || !allocator) 44 return; 45 46 auto encFeatureManager = dynamic_cast<EncodeHevcVdencFeatureManager *>(featureManager); 47 if (nullptr != encFeatureManager) 48 { 49 m_basicFeature = dynamic_cast<EncodeBasicFeature *>(encFeatureManager->GetFeature(FeatureIDs::basicFeature)); 50 } 51 } 52 /* 53 HevcEncodeDss::~HevcEncodeDss() 54 { 55 //FreeDSSResources(); 56 } 57 */ Init(void * setting)58 MOS_STATUS HevcEncodeDss::Init(void *setting) 59 { 60 ENCODE_FUNC_CALL(); 61 62 m_hcpItf = m_hwInterface->GetHcpInterfaceNext(); 63 ENCODE_CHK_NULL_RETURN(m_hcpItf); 64 65 m_miItf = m_hwInterface->GetMiInterfaceNext(); 66 ENCODE_CHK_NULL_RETURN(m_miItf); 67 68 m_vdencItf = m_hwInterface->GetVdencInterfaceNext(); 69 ENCODE_CHK_NULL_RETURN(m_vdencItf); 70 71 ENCODE_CHK_STATUS_RETURN(AllocateResources()); 72 73 return MOS_STATUS_SUCCESS; 74 } 75 AllocateResources()76 MOS_STATUS HevcEncodeDss::AllocateResources() 77 { 78 ENCODE_FUNC_CALL(); 79 MOS_STATUS eStatus = MOS_STATUS_SUCCESS; 80 81 ENCODE_CHK_NULL_RETURN(m_allocator); 82 ENCODE_CHK_NULL_RETURN(m_basicFeature); 83 ENCODE_CHK_NULL_RETURN(m_basicFeature->m_recycleBuf); 84 ENCODE_CHK_NULL_RETURN(m_hwInterface); 85 ENCODE_CHK_NULL_RETURN(m_hwInterface->GetOsInterface()); 86 87 MOS_ALLOC_GFXRES_PARAMS allocParamsForBufferLinear; 88 MOS_ZeroMemory(&allocParamsForBufferLinear, sizeof(MOS_ALLOC_GFXRES_PARAMS)); 89 allocParamsForBufferLinear.Type = MOS_GFXRES_BUFFER; 90 allocParamsForBufferLinear.TileType = MOS_TILE_LINEAR; 91 allocParamsForBufferLinear.Format = Format_Buffer; 92 93 // Slice Count buffer 1 DW = 4 Bytes 94 allocParamsForBufferLinear.dwBytes = MOS_ALIGN_CEIL(4, CODECHAL_CACHELINE_SIZE); 95 allocParamsForBufferLinear.pBufName = "Slice Count Buffer"; 96 allocParamsForBufferLinear.ResUsageType = MOS_HW_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_NOCACHE; 97 m_resSliceCountBuffer = m_allocator->AllocateResource(allocParamsForBufferLinear, false); 98 99 // VDEncMode Timer buffer 1 DW = 4 Bytes 100 allocParamsForBufferLinear.dwBytes = MOS_ALIGN_CEIL(4, CODECHAL_CACHELINE_SIZE); 101 allocParamsForBufferLinear.pBufName = "VDEncMode Timer Buffer"; 102 allocParamsForBufferLinear.ResUsageType = MOS_HW_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_NOCACHE; 103 m_resVDEncModeTimerBuffer = m_allocator->AllocateResource(allocParamsForBufferLinear, false); 104 105 return eStatus; 106 } 107 Update(void * params)108 MOS_STATUS HevcEncodeDss::Update(void *params) 109 { 110 ENCODE_FUNC_CALL(); 111 ENCODE_CHK_NULL_RETURN(params); 112 113 EncoderParams *encodeParams = (EncoderParams *)params; 114 m_hevcSeqParams = static_cast<PCODEC_HEVC_ENCODE_SEQUENCE_PARAMS>(encodeParams->pSeqParams); 115 116 uint32_t frameWidth = (m_hevcSeqParams->wFrameWidthInMinCbMinus1 + 1) << (m_hevcSeqParams->log2_min_coding_block_size_minus3 + 3); 117 uint32_t frameHeight = (m_hevcSeqParams->wFrameHeightInMinCbMinus1 + 1) << (m_hevcSeqParams->log2_min_coding_block_size_minus3 + 3); 118 if (m_hevcSeqParams->SliceSizeControl && frameWidth * frameHeight < ENCODE_HEVC_MIN_DSS_PIC_WIDTH * ENCODE_HEVC_MIN_DSS_PIC_HEIGHT) 119 { 120 MOS_STATUS eStatus = MOS_STATUS_INVALID_PARAMETER; 121 ENCODE_CHK_STATUS_MESSAGE_RETURN(eStatus, "DSS is not supported when frame resolution less than 320p"); 122 } 123 124 return MOS_STATUS_SUCCESS; 125 } 126 ReadHcpStatus(MHW_VDBOX_NODE_IND vdboxIndex,MOS_COMMAND_BUFFER & cmdBuffer)127 MOS_STATUS HevcEncodeDss::ReadHcpStatus( 128 MHW_VDBOX_NODE_IND vdboxIndex, 129 MOS_COMMAND_BUFFER &cmdBuffer) 130 { 131 ENCODE_FUNC_CALL(); 132 133 MOS_STATUS eStatus = MOS_STATUS_SUCCESS; 134 135 auto mmioRegisters = m_hcpItf->GetMmioRegisters(vdboxIndex); 136 ENCODE_CHK_NULL_RETURN(mmioRegisters); 137 138 auto AddMiStoreRegisterMemCmd = [&](PMOS_RESOURCE &res, uint32_t dwRegister) { 139 auto &miStoreRegMemParams = m_miItf->MHW_GETPAR_F(MI_STORE_REGISTER_MEM)(); 140 miStoreRegMemParams = {}; 141 miStoreRegMemParams.presStoreBuffer = res; 142 miStoreRegMemParams.dwOffset = 0; 143 miStoreRegMemParams.dwRegister = dwRegister; 144 ENCODE_CHK_STATUS_RETURN(m_miItf->MHW_ADDCMD_F(MI_STORE_REGISTER_MEM)(&cmdBuffer)); 145 return MOS_STATUS_SUCCESS; 146 }; 147 148 ENCODE_CHK_STATUS_RETURN(AddMiStoreRegisterMemCmd(m_resSliceCountBuffer, mmioRegisters->hcpEncSliceCountRegOffset)); 149 ENCODE_CHK_STATUS_RETURN(AddMiStoreRegisterMemCmd(m_resVDEncModeTimerBuffer, mmioRegisters->hcpEncVdencModeTimerRegOffset)); 150 151 return eStatus; 152 } 153 ReadSliceSizeForSinglePipe(EncodePipeline * pipeline,MOS_COMMAND_BUFFER & cmdBuffer)154 MOS_STATUS HevcEncodeDss::ReadSliceSizeForSinglePipe(EncodePipeline *pipeline, MOS_COMMAND_BUFFER &cmdBuffer) 155 { 156 MOS_STATUS eStatus = MOS_STATUS_SUCCESS; 157 158 ENCODE_FUNC_CALL(); 159 MediaStatusReport *statusReport = pipeline->GetStatusReportInstance(); 160 MOS_RESOURCE *osResource = nullptr; 161 uint32_t offset = 0; 162 statusReport->GetAddress(statusReportSliceReport, osResource, offset); 163 164 uint32_t sizeOfSliceSizesBuffer = MOS_ALIGN_CEIL(CODECHAL_HEVC_MAX_NUM_SLICES_LVL_6 * CODECHAL_CACHELINE_SIZE, CODECHAL_PAGE_SIZE); 165 166 uint32_t currIndex = statusReport->GetIndex(statusReport->GetSubmittedCount()); 167 168 if (pipeline->IsFirstPass()) 169 { 170 // Create/ Initialize slice report buffer once per frame, to be used across passes 171 if (Mos_ResourceIsNull(&m_resSliceReport[currIndex])) 172 { 173 MOS_ALLOC_GFXRES_PARAMS allocParamsForBufferLinear; 174 MOS_ZeroMemory(&allocParamsForBufferLinear, sizeof(MOS_ALLOC_GFXRES_PARAMS)); 175 allocParamsForBufferLinear.Type = MOS_GFXRES_BUFFER; 176 allocParamsForBufferLinear.TileType = MOS_TILE_LINEAR; 177 allocParamsForBufferLinear.Format = Format_Buffer; 178 allocParamsForBufferLinear.dwBytes = sizeOfSliceSizesBuffer; 179 allocParamsForBufferLinear.pBufName = "SliceReport"; 180 allocParamsForBufferLinear.ResUsageType = MOS_HW_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_NOCACHE; 181 MOS_RESOURCE *allocatedresource = m_allocator->AllocateResource(allocParamsForBufferLinear, false); 182 ENCODE_CHK_NULL_RETURN(allocatedresource); 183 m_resSliceReport[currIndex] = *allocatedresource; 184 } 185 186 // Clear slice size structure to be sent in EncodeStatusReport buffer 187 uint8_t *data = (uint8_t *)m_allocator->LockResourceForWrite(&m_resSliceReport[currIndex]); 188 ENCODE_CHK_NULL_RETURN(data); 189 MOS_ZeroMemory(data, sizeOfSliceSizesBuffer); 190 m_allocator->UnLock(&m_resSliceReport[currIndex]); 191 192 // Set slice size pointer in slice size structure 193 auto &miFlushDwParams = m_miItf->MHW_GETPAR_F(MI_FLUSH_DW)(); 194 miFlushDwParams = {}; 195 miFlushDwParams.pOsResource = osResource; 196 miFlushDwParams.dwResourceOffset = offset + CODECHAL_OFFSETOF(EncodeStatusSliceReport, sliceSize); 197 miFlushDwParams.dwDataDW1 = (uint32_t)((uint64_t)&m_resSliceReport[currIndex] & 0xFFFFFFFF); 198 miFlushDwParams.dwDataDW2 = (uint32_t)(((uint64_t)&m_resSliceReport[currIndex] & 0xFFFFFFFF00000000) >> 32); 199 miFlushDwParams.bQWordEnable = 1; 200 ENCODE_CHK_STATUS_RETURN(m_miItf->MHW_ADDCMD_F(MI_FLUSH_DW)(&cmdBuffer)); 201 } 202 203 // Copy Slize size data buffer from PAK to be sent back to App 204 ENCODE_CHK_STATUS_RETURN(CopyDataBlock( 205 m_basicFeature->m_recycleBuf->GetBuffer(LcuBaseAddressBuffer, 0), 206 0, 207 &m_resSliceReport[currIndex], 208 0, 209 sizeOfSliceSizesBuffer, 210 cmdBuffer)); 211 212 auto &miCpyMemMemParams = m_miItf->MHW_GETPAR_F(MI_COPY_MEM_MEM)(); 213 miCpyMemMemParams = {}; 214 miCpyMemMemParams.presSrc = m_basicFeature->m_recycleBuf->GetBuffer(FrameStatStreamOutBuffer, 0); // Slice size overflow is in m_resFrameStatStreamOutBuffer DW0[16] 215 miCpyMemMemParams.dwSrcOffset = 0; 216 miCpyMemMemParams.presDst = osResource; 217 miCpyMemMemParams.dwDstOffset = offset; 218 ENCODE_CHK_STATUS_RETURN(m_miItf->MHW_ADDCMD_F(MI_COPY_MEM_MEM)(&cmdBuffer)); 219 220 miCpyMemMemParams = {}; 221 miCpyMemMemParams.presSrc = m_resSliceCountBuffer; // Number of slice sizes are stored in this buffer. Updated at runtime 222 miCpyMemMemParams.dwSrcOffset = 0; 223 miCpyMemMemParams.presDst = osResource; 224 miCpyMemMemParams.dwDstOffset = offset + 1; 225 ENCODE_CHK_STATUS_RETURN(m_miItf->MHW_ADDCMD_F(MI_COPY_MEM_MEM)(&cmdBuffer)); 226 227 return eStatus; 228 } 229 ReadSliceSize(EncodePipeline * pipeline,MOS_COMMAND_BUFFER & cmdBuffer)230 MOS_STATUS HevcEncodeDss::ReadSliceSize(EncodePipeline *pipeline, MOS_COMMAND_BUFFER &cmdBuffer) 231 { 232 MOS_STATUS eStatus = MOS_STATUS_SUCCESS; 233 234 ENCODE_FUNC_CALL(); 235 MediaStatusReport *statusReport = pipeline->GetStatusReportInstance(); 236 237 // In multi-tile multi-pipe mode, use PAK integration kernel output 238 // PAK integration kernel accumulates frame statistics across tiles, which should be used to setup slice size report 239 MOS_RESOURCE *osResource = nullptr; 240 uint32_t offset = 0; 241 242 statusReport->GetAddress(statusReportSliceReport, osResource, offset); 243 244 uint32_t sizeOfSliceSizesBuffer = MOS_ALIGN_CEIL(CODECHAL_HEVC_MAX_NUM_SLICES_LVL_6 * CODECHAL_CACHELINE_SIZE, CODECHAL_PAGE_SIZE); 245 246 uint32_t currIndex = statusReport->GetIndex(statusReport->GetSubmittedCount()); 247 248 if (pipeline->IsFirstPipe()) 249 { 250 if (pipeline->IsFirstPass()) 251 { 252 // Create/ Initialize slice report buffer once per frame, to be used across passes 253 if (Mos_ResourceIsNull(&m_resSliceReport[currIndex])) 254 { 255 MOS_ALLOC_GFXRES_PARAMS allocParamsForBufferLinear; 256 MOS_ZeroMemory(&allocParamsForBufferLinear, sizeof(MOS_ALLOC_GFXRES_PARAMS)); 257 allocParamsForBufferLinear.Type = MOS_GFXRES_BUFFER; 258 allocParamsForBufferLinear.TileType = MOS_TILE_LINEAR; 259 allocParamsForBufferLinear.Format = Format_Buffer; 260 allocParamsForBufferLinear.dwBytes = sizeOfSliceSizesBuffer; 261 allocParamsForBufferLinear.pBufName = "SliceReport"; 262 allocParamsForBufferLinear.ResUsageType = MOS_HW_RESOURCE_USAGE_ENCODE_INTERNAL_READ_WRITE_NOCACHE; 263 MOS_RESOURCE *allocatedresource = m_allocator->AllocateResource(allocParamsForBufferLinear, false); 264 ENCODE_CHK_NULL_RETURN(allocatedresource); 265 m_resSliceReport[currIndex] = *allocatedresource; 266 } 267 268 // Clear slice size structure to be sent in EncodeStatusReportNext buffer 269 uint8_t *data = (uint8_t *)m_allocator->LockResourceForWrite(&m_resSliceReport[currIndex]); 270 ENCODE_CHK_NULL_RETURN(data); 271 MOS_ZeroMemory(data, sizeOfSliceSizesBuffer); 272 m_allocator->UnLock(&m_resSliceReport[currIndex]); 273 274 // Set slice size pointer in slice size structure 275 auto &miFlushDwParams = m_miItf->MHW_GETPAR_F(MI_FLUSH_DW)(); 276 miFlushDwParams = {}; 277 miFlushDwParams.pOsResource = osResource; 278 miFlushDwParams.dwResourceOffset = offset + CODECHAL_OFFSETOF(EncodeStatusSliceReport, sliceSize); 279 miFlushDwParams.dwDataDW1 = (uint32_t)((uint64_t)&m_resSliceReport[currIndex] & 0xFFFFFFFF); 280 miFlushDwParams.dwDataDW2 = (uint32_t)(((uint64_t)&m_resSliceReport[currIndex] & 0xFFFFFFFF00000000) >> 32); 281 miFlushDwParams.bQWordEnable = 1; 282 ENCODE_CHK_STATUS_RETURN(m_miItf->MHW_ADDCMD_F(MI_FLUSH_DW)(&cmdBuffer)); 283 } 284 285 uint32_t statBufIdx = 0; 286 MOS_RESOURCE *tileStatisticsBuffer = nullptr; 287 RUN_FEATURE_INTERFACE_RETURN(HevcEncodeTile, FeatureIDs::encodeTile, GetStatisticsBufferIndex, statBufIdx); 288 RUN_FEATURE_INTERFACE_RETURN(HevcEncodeTile, FeatureIDs::encodeTile, GetTileBasedStatisticsBuffer, statBufIdx, tileStatisticsBuffer); 289 ENCODE_CHK_NULL_RETURN(tileStatisticsBuffer); 290 291 HevcTileStatusInfo hevcTileStatsOffset; 292 HevcTileStatusInfo hevcFrameStatsOffset; 293 HevcTileStatusInfo hevcStatsSize; 294 RUN_FEATURE_INTERFACE_RETURN(HevcEncodeTile, FeatureIDs::encodeTile, GetTileStatusInfo, hevcTileStatsOffset, hevcFrameStatsOffset, hevcStatsSize); 295 296 // Copy Slize size data buffer from PAK to be sent back to App 297 ENCODE_CHK_STATUS_RETURN(CopyDataBlock( 298 tileStatisticsBuffer, 299 hevcTileStatsOffset.hevcSliceStreamout, 300 &m_resSliceReport[currIndex], 301 0, 302 sizeOfSliceSizesBuffer, 303 cmdBuffer)); 304 305 MOS_RESOURCE *resHuCPakAggregatedFrameStatsBuffer = nullptr; 306 RUN_FEATURE_INTERFACE_RETURN(HevcEncodeTile, FeatureIDs::encodeTile, GetHucPakAggregatedFrameStatsBuffer, resHuCPakAggregatedFrameStatsBuffer); 307 ENCODE_CHK_NULL_RETURN(resHuCPakAggregatedFrameStatsBuffer); 308 309 auto &miCpyMemMemParams = m_miItf->MHW_GETPAR_F(MI_COPY_MEM_MEM)(); 310 miCpyMemMemParams = {}; 311 miCpyMemMemParams.presSrc = resHuCPakAggregatedFrameStatsBuffer; // Slice size overflow is in m_resFrameStatStreamOutBuffer DW0[16] 312 miCpyMemMemParams.dwSrcOffset = hevcFrameStatsOffset.hevcPakStatistics; 313 miCpyMemMemParams.presDst = osResource; 314 miCpyMemMemParams.dwDstOffset = offset; // Slice size overflow is at DW0 EncodeStatusSliceReport 315 ENCODE_CHK_STATUS_RETURN(m_miItf->MHW_ADDCMD_F(MI_COPY_MEM_MEM)(&cmdBuffer)); 316 } 317 318 return eStatus; 319 } 320 CopyDataBlock(PMOS_RESOURCE sourceSurface,uint32_t sourceOffset,PMOS_RESOURCE destSurface,uint32_t destOffset,uint32_t copySize,MOS_COMMAND_BUFFER & cmdBuffer)321 MOS_STATUS HevcEncodeDss::CopyDataBlock( 322 PMOS_RESOURCE sourceSurface, 323 uint32_t sourceOffset, 324 PMOS_RESOURCE destSurface, 325 uint32_t destOffset, 326 uint32_t copySize, 327 MOS_COMMAND_BUFFER &cmdBuffer) 328 { 329 MOS_STATUS eStatus = MOS_STATUS_SUCCESS; 330 331 ENCODE_FUNC_CALL(); 332 333 CodechalHucStreamoutParams hucStreamOutParams; 334 MOS_ZeroMemory(&hucStreamOutParams, sizeof(hucStreamOutParams)); 335 336 // Ind Obj Addr command 337 hucStreamOutParams.dataBuffer = sourceSurface; 338 hucStreamOutParams.dataSize = copySize + sourceOffset; 339 hucStreamOutParams.dataOffset = MOS_ALIGN_FLOOR(sourceOffset, CODECHAL_PAGE_SIZE); 340 hucStreamOutParams.streamOutObjectBuffer = destSurface; 341 hucStreamOutParams.streamOutObjectSize = copySize + destOffset; 342 hucStreamOutParams.streamOutObjectOffset = MOS_ALIGN_FLOOR(destOffset, CODECHAL_PAGE_SIZE); 343 344 // Stream object params 345 hucStreamOutParams.indStreamInLength = copySize; 346 hucStreamOutParams.inputRelativeOffset = sourceOffset - hucStreamOutParams.dataOffset; 347 hucStreamOutParams.outputRelativeOffset = destOffset - hucStreamOutParams.streamOutObjectOffset; 348 349 ENCODE_CHK_STATUS_RETURN(m_hwInterface->PerformHucStreamOut( 350 &hucStreamOutParams, 351 &cmdBuffer)); 352 353 // wait Huc completion (use HEVC bit for now) 354 auto &vdPipeFlushParams = m_vdencItf->MHW_GETPAR_F(VD_PIPELINE_FLUSH)(); 355 vdPipeFlushParams = {}; 356 vdPipeFlushParams.flushHEVC = true; 357 vdPipeFlushParams.waitDoneHEVC = true; 358 ENCODE_CHK_STATUS_RETURN(m_vdencItf->MHW_ADDCMD_F(VD_PIPELINE_FLUSH)(&cmdBuffer)); 359 360 // Flush the engine to ensure memory written out 361 auto &flushDwParams = m_miItf->MHW_GETPAR_F(MI_FLUSH_DW)(); 362 flushDwParams = {}; 363 flushDwParams.bVideoPipelineCacheInvalidate = true; 364 ENCODE_CHK_STATUS_RETURN(m_miItf->MHW_ADDCMD_F(MI_FLUSH_DW)(&cmdBuffer)); 365 366 return eStatus; 367 } 368 GetDssBuffer(PMOS_RESOURCE & resSliceCountBuffer,PMOS_RESOURCE & resVDEncModeTimerBuffer)369 MOS_STATUS HevcEncodeDss::GetDssBuffer(PMOS_RESOURCE &resSliceCountBuffer, PMOS_RESOURCE &resVDEncModeTimerBuffer) 370 { 371 MOS_STATUS eStatus = MOS_STATUS_SUCCESS; 372 373 ENCODE_FUNC_CALL(); 374 375 ENCODE_CHK_NULL_RETURN(m_resSliceCountBuffer); 376 ENCODE_CHK_NULL_RETURN(m_resVDEncModeTimerBuffer); 377 378 resSliceCountBuffer = m_resSliceCountBuffer; 379 resVDEncModeTimerBuffer = m_resVDEncModeTimerBuffer; 380 381 return eStatus; 382 } 383 }