1 /* 2 * Copyright (c) 2019, 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_back_annotation_packet.cpp 24 //! \brief Defines the interface for AV1 back annotation packet 25 //! 26 #include "encode_back_annotation_packet.h" 27 #include "encode_av1_tile.h" 28 29 namespace encode { Init()30 MOS_STATUS Av1BackAnnotationPkt::Init() 31 { 32 ENCODE_FUNC_CALL(); 33 ENCODE_CHK_STATUS_RETURN(EncodeHucPkt::Init()); 34 35 m_basicFeature = dynamic_cast<Av1BasicFeature *>(m_featureManager->GetFeature(Av1FeatureIDs::basicFeature)); 36 ENCODE_CHK_NULL_RETURN(m_basicFeature); 37 38 ENCODE_CHK_NULL_RETURN(m_pipeline); 39 m_statusReport = m_pipeline->GetStatusReportInstance(); 40 ENCODE_CHK_NULL_RETURN(m_statusReport); 41 42 ENCODE_CHK_STATUS_RETURN(m_statusReport->RegistObserver(this)); 43 44 return MOS_STATUS_SUCCESS; 45 } 46 AllocateResources()47 MOS_STATUS Av1BackAnnotationPkt::AllocateResources() 48 { 49 ENCODE_CHK_STATUS_RETURN(EncodeHucPkt::AllocateResources()); 50 51 MOS_ALLOC_GFXRES_PARAMS allocParamsForBufferLinear; 52 MOS_ZeroMemory(&allocParamsForBufferLinear, sizeof(MOS_ALLOC_GFXRES_PARAMS)); 53 allocParamsForBufferLinear.Type = MOS_GFXRES_BUFFER; 54 allocParamsForBufferLinear.TileType = MOS_TILE_LINEAR; 55 allocParamsForBufferLinear.Format = Format_Buffer; 56 57 for (auto k = 0; k < CODECHAL_ENCODE_RECYCLED_BUFFER_NUM; k++) 58 { 59 for (auto i = 0; i < VDENC_BRC_NUM_OF_PASSES; i++) 60 { 61 // BRC update DMEM 62 allocParamsForBufferLinear.dwBytes = MOS_ALIGN_CEIL(m_vdencbackAnnotationDmemBufferSize, CODECHAL_CACHELINE_SIZE); 63 allocParamsForBufferLinear.pBufName = "AV1 Back Annotation Dmem Buffer"; 64 allocParamsForBufferLinear.ResUsageType = MOS_HW_RESOURCE_USAGE_ENCODE_INTERNAL_WRITE; 65 m_vdencBackAnnotationDmemBuffer[k][i] = m_allocator->AllocateResource(allocParamsForBufferLinear, true); 66 67 allocParamsForBufferLinear.dwBytes = MOS_ALIGN_CEIL(m_vdencAv1HucCtrlBufferSize, CODECHAL_CACHELINE_SIZE); 68 allocParamsForBufferLinear.ResUsageType = MOS_HW_RESOURCE_USAGE_ENCODE_INTERNAL_WRITE; 69 allocParamsForBufferLinear.pBufName = "AV1 Back Annotation Huc Ctrl Buffer"; 70 m_vdencAv1HucCtrlBuffer[k][i] = m_allocator->AllocateResource(allocParamsForBufferLinear, true); 71 } 72 } 73 74 return MOS_STATUS_SUCCESS; 75 } 76 Prepare()77 MOS_STATUS Av1BackAnnotationPkt::Prepare() 78 { 79 ENCODE_FUNC_CALL(); 80 81 ENCODE_CHK_NULL_RETURN(m_basicFeature); 82 83 return MOS_STATUS_SUCCESS; 84 } 85 Submit(MOS_COMMAND_BUFFER * commandBuffer,uint8_t packetPhase)86 MOS_STATUS Av1BackAnnotationPkt::Submit(MOS_COMMAND_BUFFER *commandBuffer, uint8_t packetPhase) 87 { 88 ENCODE_FUNC_CALL(); 89 90 bool firstTaskInPhase = packetPhase & firstPacket; 91 bool requestProlog = false; 92 93 ENCODE_CHK_STATUS_RETURN(Execute(commandBuffer, true, requestProlog)); 94 95 CODECHAL_DEBUG_TOOL 96 ( 97 ENCODE_CHK_STATUS_RETURN(DumpBackAnnotation()); 98 ) 99 100 return MOS_STATUS_SUCCESS; 101 } 102 CalculateCommandSize(uint32_t & commandBufferSize,uint32_t & requestedPatchListSize)103 MOS_STATUS Av1BackAnnotationPkt::CalculateCommandSize(uint32_t &commandBufferSize, uint32_t &requestedPatchListSize) 104 { 105 ENCODE_FUNC_CALL(); 106 107 auto osInterface = m_hwInterface->GetOsInterface(); 108 ENCODE_CHK_NULL_RETURN(osInterface); 109 110 uint32_t hucCommandsSize = 0; 111 uint32_t hucPatchListSize = 0; 112 MHW_VDBOX_STATE_CMDSIZE_PARAMS stateCmdSizeParams; 113 114 ENCODE_CHK_STATUS_RETURN(m_hwInterface->GetHucStateCommandSize( 115 m_basicFeature->m_mode, (uint32_t*)&hucCommandsSize, (uint32_t*)&hucPatchListSize, &stateCmdSizeParams)); 116 117 commandBufferSize = hucCommandsSize; 118 requestedPatchListSize = osInterface->bUsesPatchList ? hucPatchListSize : 0; 119 120 // 4K align since allocation is in chunks of 4K bytes. 121 commandBufferSize = MOS_ALIGN_CEIL(commandBufferSize, CODECHAL_PAGE_SIZE); 122 123 return MOS_STATUS_SUCCESS; 124 } 125 SetDmemBuffer()126 MOS_STATUS Av1BackAnnotationPkt::SetDmemBuffer() 127 { 128 ENCODE_FUNC_CALL(); 129 130 MOS_STATUS eStatus = MOS_STATUS_SUCCESS; 131 132 int32_t currentPass = m_pipeline->GetCurrentPass(); 133 if (currentPass < 0 || currentPass >= CODECHAL_VDENC_BRC_NUM_OF_PASSES) 134 { 135 eStatus = MOS_STATUS_INVALID_PARAMETER; 136 return eStatus; 137 } 138 139 // Setup BrcInit DMEM 140 auto hucBackAnnotationDmem = (VdencAv1HucBackAnnotationDmem *) 141 m_allocator->LockResourceForWrite(m_vdencBackAnnotationDmemBuffer[m_pipeline->m_currRecycledBufIdx][currentPass]); 142 ENCODE_CHK_NULL_RETURN(hucBackAnnotationDmem); 143 MOS_ZeroMemory(hucBackAnnotationDmem, sizeof(VdencAv1HucBackAnnotationDmem)); 144 145 uint32_t numTilegroups = 0; 146 PCODEC_AV1_ENCODE_TILE_GROUP_PARAMS tileGroupParams = nullptr; 147 RUN_FEATURE_INTERFACE_RETURN(Av1EncodeTile, Av1FeatureIDs::encodeTile, GetTileGroupInfo, tileGroupParams, numTilegroups); 148 149 hucBackAnnotationDmem->tileGroupNumber = static_cast<uint8_t>(numTilegroups); 150 hucBackAnnotationDmem->backAnnotationType = AnnotationTypes::TileGroupOBU; 151 hucBackAnnotationDmem->firstTileGroupByteOffset = m_basicFeature->GetAppHdrSizeInBytes(); 152 153 ENCODE_CHK_STATUS_RETURN(m_allocator->UnLock(m_vdencBackAnnotationDmemBuffer[m_pipeline->m_currRecycledBufIdx][currentPass])); 154 155 return eStatus; 156 } 157 SetHucCtrlBuffer()158 MOS_STATUS Av1BackAnnotationPkt::SetHucCtrlBuffer() 159 { 160 ENCODE_FUNC_CALL(); 161 162 MOS_STATUS eStatus = MOS_STATUS_SUCCESS; 163 164 ENCODE_CHK_NULL_RETURN(m_basicFeature); 165 auto nalUnitParams = m_basicFeature->m_nalUnitParams; 166 ENCODE_CHK_NULL_RETURN(nalUnitParams); 167 168 int32_t currentPass = m_pipeline->GetCurrentPass(); 169 if (currentPass < 0 || currentPass >= CODECHAL_VDENC_BRC_NUM_OF_PASSES) 170 { 171 eStatus = MOS_STATUS_INVALID_PARAMETER; 172 return eStatus; 173 } 174 175 // Setup BrcInit DMEM 176 auto hucCtrlBuffer = (VdencAv1HucCtrlBigData *) 177 m_allocator->LockResourceForWrite(m_vdencAv1HucCtrlBuffer[m_pipeline->m_currRecycledBufIdx][currentPass]); 178 ENCODE_CHK_NULL_RETURN(hucCtrlBuffer); 179 MOS_ZeroMemory(hucCtrlBuffer, sizeof(VdencAv1HucCtrlBigData)); 180 181 uint32_t nalunitPosiSize = 0; 182 auto numOBUS = m_basicFeature->m_NumNalUnits; 183 184 RUN_FEATURE_INTERFACE_RETURN(Av1EncodeTile, Av1FeatureIDs::encodeTile, 185 SetHucCtrlBuffer, *hucCtrlBuffer); 186 187 ENCODE_CHK_STATUS_RETURN(m_allocator->UnLock(m_vdencAv1HucCtrlBuffer[m_pipeline->m_currRecycledBufIdx][currentPass])); 188 189 return eStatus; 190 } 191 Completed(void * mfxStatus,void * rcsStatus,void * statusReport)192 MOS_STATUS Av1BackAnnotationPkt::Completed(void *mfxStatus, void *rcsStatus, void *statusReport) 193 { 194 ENCODE_FUNC_CALL(); 195 196 ENCODE_CHK_NULL_RETURN(mfxStatus); 197 ENCODE_CHK_NULL_RETURN(statusReport); 198 199 if (!m_basicFeature->m_enableSWBackAnnotation) 200 { 201 return MOS_STATUS_SUCCESS; 202 } 203 204 ENCODE_CHK_STATUS_RETURN(EncodeHucPkt::Completed(mfxStatus, rcsStatus, statusReport)); 205 206 EncodeStatusMfx * encodeStatusMfx = (EncodeStatusMfx *)mfxStatus; 207 EncodeStatusReportData *statusReportData = (EncodeStatusReportData *)statusReport; 208 209 uint32_t statBufIdx = statusReportData->currOriginalPic.FrameIdx; 210 211 MOS_RESOURCE *tileSizeStatusBuffer = nullptr; 212 RUN_FEATURE_INTERFACE_RETURN(Av1EncodeTile, Av1FeatureIDs::encodeTile, GetTileRecordBuffer, statBufIdx, tileSizeStatusBuffer); 213 214 const Av1ReportTileGroupParams *tileGroupParams = nullptr; 215 RUN_FEATURE_INTERFACE_RETURN(Av1EncodeTile, Av1FeatureIDs::encodeTile, GetTileGroupReportParams, statBufIdx, tileGroupParams); 216 ENCODE_CHK_NULL_RETURN(tileGroupParams); 217 218 uint32_t numTilegroups = tileGroupParams->TileGroupNum; 219 220 PakHwTileSizeRecord *tileRecord = 221 (PakHwTileSizeRecord *)m_allocator->LockResourceForRead(tileSizeStatusBuffer); 222 ENCODE_CHK_NULL_RETURN(tileRecord); 223 224 uint32_t obuSizeBytesOffset = 0; 225 if (statusReportData->av1EnableFrameOBU) 226 { 227 obuSizeBytesOffset = statusReportData->av1FrameHdrOBUSizeByteOffset; 228 } 229 else 230 { 231 obuSizeBytesOffset = tileRecord[0].Length - tileRecord[0].TileSize - tileGroupParams->TileGroupOBUSizeInBytes - m_numBytesOfOBUSize; 232 233 // tile_start_and_end_present_flag is in bitstream, indicates more than 1 tile, so tile_size_minus_1 exists in bitstream 234 if (tileGroupParams->TileGroupOBUSizeInBytes && (tileGroupParams->TileGroupStart != tileGroupParams->TileGroupEnd)) 235 { 236 obuSizeBytesOffset -= TILE_SIZE_BYTES; 237 } 238 } 239 240 PCODEC_REF_LIST currRefList = (PCODEC_REF_LIST)statusReportData->currRefList; 241 ENCODE_CHK_NULL_RETURN(currRefList); 242 uint8_t *bitstream = (uint8_t *)m_allocator->LockResourceForWrite( 243 &currRefList->resBitstreamBuffer); 244 ENCODE_CHK_NULL_RETURN(bitstream); 245 246 uint32_t payLoadSize = 0; 247 uint8_t buffer[m_numBytesOfOBUSize] = {}; 248 for (uint32_t i = 0; i < numTilegroups; i++, tileGroupParams++) 249 { 250 uint32_t streamSizePerTG = 0; 251 for (uint32_t j = tileGroupParams->TileGroupStart; j <= tileGroupParams->TileGroupEnd; j++) 252 { 253 if (tileRecord[j].Length == 0) 254 { 255 statusReportData->codecStatus = CODECHAL_STATUS_INCOMPLETE; 256 return MOS_STATUS_SUCCESS; 257 } 258 if (j == tileGroupParams->TileGroupStart) 259 { 260 auto tileSizeBytes = (j == tileGroupParams->TileGroupEnd) ? 261 tileGroupParams->TileGroupOBUSizeInBytes : tileGroupParams->TileGroupOBUSizeInBytes + TILE_SIZE_BYTES; 262 payLoadSize += tileRecord[j].TileSize + tileSizeBytes; 263 } 264 else 265 { 266 payLoadSize += tileRecord[j].Length; 267 } 268 } 269 streamSizePerTG += payLoadSize; 270 271 //needs to decode the size from the one passed by MSDK 272 if (statusReportData->av1EnableFrameOBU) 273 { 274 uint32_t frameHdrObuSize = tileRecord[0].Length - tileRecord[0].TileSize - obuSizeBytesOffset - 275 m_numBytesOfOBUSize - 1/*tile group OBU header size*/ - tileGroupParams->TileGroupOBUSizeInBytes; 276 277 // tile_start_and_end_present_flag is in bitstream, indicates more than 1 tile, so tile_size_minus_1 exists in bitstream 278 if (tileGroupParams->TileGroupOBUSizeInBytes && (tileGroupParams->TileGroupStart != tileGroupParams->TileGroupEnd)) 279 { 280 frameHdrObuSize -= TILE_SIZE_BYTES; 281 } 282 283 payLoadSize += frameHdrObuSize + 1/*tile group OBU header size*/; 284 } 285 286 // fixed 4 bytes solution 287 uint8_t payLoadByte = 0; 288 for (auto k = 0; k < m_numBytesOfOBUSize; k++) 289 { 290 payLoadByte = payLoadSize & 0x7f; 291 payLoadSize >>= 7; 292 293 if (k != m_numBytesOfOBUSize - 1) 294 { 295 payLoadByte |= 0x80; // Signal that more bytes follow. 296 } 297 298 *(buffer + k) = payLoadByte; 299 } 300 301 MOS_SecureMemcpy( 302 bitstream + obuSizeBytesOffset, 303 (uint32_t)m_numBytesOfOBUSize, 304 buffer, 305 (uint32_t)m_numBytesOfOBUSize); 306 307 //reset pay load size for next TG 308 payLoadSize = 0; 309 // calculate next TileGroupBaseOffset 310 obuSizeBytesOffset += streamSizePerTG + 1/*tile group OBU header size*/ + m_numBytesOfOBUSize; 311 } 312 313 if (bitstream) 314 { 315 m_allocator->UnLock(&currRefList->resBitstreamBuffer); 316 } 317 318 if (tileRecord) 319 { 320 // clean-up the tile status report buffer 321 MOS_ZeroMemory(tileRecord, sizeof(tileRecord[0]) * statusReportData->numberTilesInFrame); 322 m_allocator->UnLock(tileSizeStatusBuffer); 323 } 324 325 return MOS_STATUS_SUCCESS; 326 } 327 328 #if USE_CODECHAL_DEBUG_TOOL DumpBackAnnotation()329 MOS_STATUS Av1BackAnnotationPkt::DumpBackAnnotation() 330 { 331 ENCODE_FUNC_CALL(); 332 333 int32_t currentPass = m_pipeline->GetCurrentPass(); 334 335 CodechalDebugInterface *debugInterface = m_pipeline->GetDebugInterface(); 336 ENCODE_CHK_NULL_RETURN(debugInterface); 337 338 ENCODE_CHK_STATUS_RETURN(debugInterface->DumpHucDmem( 339 m_vdencBackAnnotationDmemBuffer[m_pipeline->m_currRecycledBufIdx][currentPass], 340 m_vdencbackAnnotationDmemBufferSize, 341 currentPass, 342 hucRegionDumpBackAnnotation)); 343 344 return MOS_STATUS_SUCCESS; 345 } 346 DumpOutput()347 MOS_STATUS Av1BackAnnotationPkt::DumpOutput() 348 { 349 ENCODE_FUNC_CALL(); 350 ENCODE_CHK_STATUS_RETURN(DumpRegion(0, "_PakTileSizeStreamout", false, hucRegionDumpBackAnnotation)); 351 352 ENCODE_CHK_STATUS_RETURN(DumpRegion(3, "_Bitstream", false, hucRegionDumpBackAnnotation)); 353 ENCODE_CHK_STATUS_RETURN(DumpRegion(4, "_HucCtrl", false, hucRegionDumpBackAnnotation)); 354 355 return MOS_STATUS_SUCCESS; 356 } 357 #endif 358 } 359