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