• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © Microsoft 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 (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "d3d12_common.h"
25 
26 #include "d3d12_util.h"
27 #include "d3d12_context.h"
28 #include "d3d12_format.h"
29 #include "d3d12_resource.h"
30 #include "d3d12_screen.h"
31 #include "d3d12_surface.h"
32 #include "d3d12_video_enc.h"
33 #if VIDEO_CODEC_H264ENC
34 #include "d3d12_video_enc_h264.h"
35 #endif
36 #if VIDEO_CODEC_H265ENC
37 #include "d3d12_video_enc_hevc.h"
38 #endif
39 #if VIDEO_CODEC_AV1ENC
40 #include "d3d12_video_enc_av1.h"
41 #endif
42 #include "d3d12_video_buffer.h"
43 #include "d3d12_video_texture_array_dpb_manager.h"
44 #include "d3d12_video_array_of_textures_dpb_manager.h"
45 #include "d3d12_video_encoder_references_manager_h264.h"
46 #include "d3d12_video_encoder_references_manager_hevc.h"
47 #include "d3d12_video_encoder_references_manager_av1.h"
48 #include "d3d12_residency.h"
49 
50 #include "vl/vl_video_buffer.h"
51 #include "util/format/u_format.h"
52 #include "util/u_inlines.h"
53 #include "util/u_memory.h"
54 #include "util/u_video.h"
55 
56 #include <cmath>
57 
58 D3D12_VIDEO_ENCODER_CODEC
d3d12_video_encoder_convert_codec_to_d3d12_enc_codec(enum pipe_video_profile profile)59 d3d12_video_encoder_convert_codec_to_d3d12_enc_codec(enum pipe_video_profile profile)
60 {
61    switch (u_reduce_video_profile(profile)) {
62       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
63       {
64          return D3D12_VIDEO_ENCODER_CODEC_H264;
65       } break;
66       case PIPE_VIDEO_FORMAT_HEVC:
67       {
68          return D3D12_VIDEO_ENCODER_CODEC_HEVC;
69       } break;
70       case PIPE_VIDEO_FORMAT_AV1:
71       {
72          return D3D12_VIDEO_ENCODER_CODEC_AV1;
73       } break;
74       case PIPE_VIDEO_FORMAT_MPEG12:
75       case PIPE_VIDEO_FORMAT_MPEG4:
76       case PIPE_VIDEO_FORMAT_VC1:
77       case PIPE_VIDEO_FORMAT_JPEG:
78       case PIPE_VIDEO_FORMAT_VP9:
79       case PIPE_VIDEO_FORMAT_UNKNOWN:
80       default:
81       {
82          unreachable("Unsupported pipe_video_profile");
83       } break;
84    }
85 }
86 
87 size_t
d3d12_video_encoder_pool_current_index(struct d3d12_video_encoder * pD3D12Enc)88 d3d12_video_encoder_pool_current_index(struct d3d12_video_encoder *pD3D12Enc)
89 {
90    return static_cast<size_t>(pD3D12Enc->m_fenceValue % D3D12_VIDEO_ENC_ASYNC_DEPTH);
91 }
92 
93 size_t
d3d12_video_encoder_metadata_current_index(struct d3d12_video_encoder * pD3D12Enc)94 d3d12_video_encoder_metadata_current_index(struct d3d12_video_encoder *pD3D12Enc)
95 {
96    return static_cast<size_t>(pD3D12Enc->m_fenceValue % D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT);
97 }
98 
99 void
d3d12_video_encoder_flush(struct pipe_video_codec * codec)100 d3d12_video_encoder_flush(struct pipe_video_codec *codec)
101 {
102    struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
103    assert(pD3D12Enc);
104    assert(pD3D12Enc->m_spD3D12VideoDevice);
105    assert(pD3D12Enc->m_spEncodeCommandQueue);
106 
107    if (pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].encode_result & PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED) {
108       debug_printf("WARNING: [d3d12_video_encoder] d3d12_video_encoder_flush - Frame submission %" PRIu64 " failed. Encoder lost, please recreate pipe_video_codec object \n", pD3D12Enc->m_fenceValue);
109       assert(false);
110       return;
111    }
112 
113    // Flush any work batched (ie. shaders blit on input texture, etc or bitstream headers buffer_subdata batched upload)
114    // and Wait the m_spEncodeCommandQueue for GPU upload completion
115    // before recording EncodeFrame below.
116    struct pipe_fence_handle *completion_fence = NULL;
117    debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush - Flushing pD3D12Enc->base.context and GPU sync between Video/Context queues before flushing Video Encode Queue.\n");
118    pD3D12Enc->base.context->flush(pD3D12Enc->base.context, &completion_fence, PIPE_FLUSH_ASYNC | PIPE_FLUSH_HINT_FINISH);
119    assert(completion_fence);
120    struct d3d12_fence *casted_completion_fence = d3d12_fence(completion_fence);
121    pD3D12Enc->m_spEncodeCommandQueue->Wait(casted_completion_fence->cmdqueue_fence, casted_completion_fence->value);
122    pD3D12Enc->m_pD3D12Screen->base.fence_reference(&pD3D12Enc->m_pD3D12Screen->base, &completion_fence, NULL);
123 
124    struct d3d12_fence *input_surface_fence = pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_InputSurfaceFence;
125    if (input_surface_fence)
126       pD3D12Enc->m_spEncodeCommandQueue->Wait(input_surface_fence->cmdqueue_fence, input_surface_fence->value);
127 
128    if (!pD3D12Enc->m_bPendingWorkNotFlushed) {
129       debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush started. Nothing to flush, all up to date.\n");
130    } else {
131       debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush started. Will flush video queue work async"
132                     " on fenceValue: %" PRIu64 "\n",
133                     pD3D12Enc->m_fenceValue);
134 
135       HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->GetDeviceRemovedReason();
136       if (hr != S_OK) {
137          debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush"
138                          " - D3D12Device was removed BEFORE commandlist "
139                          "execution with HR %x.\n",
140                          hr);
141          goto flush_fail;
142       }
143 
144       if (pD3D12Enc->m_transitionsBeforeCloseCmdList.size() > 0) {
145          pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(static_cast<UINT>(pD3D12Enc->m_transitionsBeforeCloseCmdList.size()),
146                                                            pD3D12Enc->m_transitionsBeforeCloseCmdList.data());
147          pD3D12Enc->m_transitionsBeforeCloseCmdList.clear();
148       }
149 
150       hr = pD3D12Enc->m_spEncodeCommandList->Close();
151       if (FAILED(hr)) {
152          debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush - Can't close command list with HR %x\n", hr);
153          goto flush_fail;
154       }
155 
156       ID3D12CommandList *ppCommandLists[1] = { pD3D12Enc->m_spEncodeCommandList.Get() };
157       pD3D12Enc->m_spEncodeCommandQueue->ExecuteCommandLists(1, ppCommandLists);
158       pD3D12Enc->m_spEncodeCommandQueue->Signal(pD3D12Enc->m_spFence.Get(), pD3D12Enc->m_fenceValue);
159 
160       // Validate device was not removed
161       hr = pD3D12Enc->m_pD3D12Screen->dev->GetDeviceRemovedReason();
162       if (hr != S_OK) {
163          debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush"
164                          " - D3D12Device was removed AFTER commandlist "
165                          "execution with HR %x, but wasn't before.\n",
166                          hr);
167          goto flush_fail;
168       }
169 
170       pD3D12Enc->m_fenceValue++;
171       pD3D12Enc->m_bPendingWorkNotFlushed = false;
172    }
173    return;
174 
175 flush_fail:
176    debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush failed for fenceValue: %" PRIu64 "\n", pD3D12Enc->m_fenceValue);
177    pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
178    pD3D12Enc->m_spEncodedFrameMetadata[d3d12_video_encoder_metadata_current_index(pD3D12Enc)].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
179    assert(false);
180 }
181 
182 bool
d3d12_video_encoder_ensure_fence_finished(struct pipe_video_codec * codec,ID3D12Fence * fence,uint64_t fenceValueToWaitOn,uint64_t timeout_ns)183 d3d12_video_encoder_ensure_fence_finished(struct pipe_video_codec *codec, ID3D12Fence *fence, uint64_t fenceValueToWaitOn, uint64_t timeout_ns)
184 {
185       bool wait_result = true;
186       struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
187       HRESULT hr = S_OK;
188       uint64_t completedValue = fence->GetCompletedValue();
189 
190       debug_printf("[d3d12_video_encoder] d3d12_video_encoder_ensure_fence_finished - Waiting for fence (with timeout_ns %" PRIu64 ") to finish with "
191                     "fenceValue: %" PRIu64 " - Current Fence Completed Value %" PRIu64 "\n",
192                     timeout_ns, fenceValueToWaitOn, completedValue);
193 
194       if(completedValue < fenceValueToWaitOn) {
195 
196          HANDLE              event = { };
197          int                 event_fd = 0;
198          event = d3d12_fence_create_event(&event_fd);
199 
200          hr = fence->SetEventOnCompletion(fenceValueToWaitOn, event);
201          if (FAILED(hr)) {
202             debug_printf(
203                "[d3d12_video_encoder] d3d12_video_encoder_ensure_fence_finished - SetEventOnCompletion for fenceValue %" PRIu64 " failed with HR %x\n",
204                fenceValueToWaitOn, hr);
205             goto ensure_fence_finished_fail;
206          }
207 
208          debug_printf("[d3d12_video_encoder] d3d12_video_encoder_ensure_fence_finished - Waiting on fence to be done with "
209                "fenceValue: %" PRIu64 " - current CompletedValue: %" PRIu64 "\n",
210                fenceValueToWaitOn,
211                completedValue);
212 
213          wait_result = d3d12_fence_wait_event(event, event_fd, timeout_ns);
214          d3d12_fence_close_event(event, event_fd);
215       } else {
216          debug_printf("[d3d12_video_encoder] d3d12_video_encoder_ensure_fence_finished - Fence already done with "
217                "fenceValue: %" PRIu64 " - current CompletedValue: %" PRIu64 "\n",
218                fenceValueToWaitOn,
219                completedValue);
220       }
221       return wait_result;
222 
223 ensure_fence_finished_fail:
224    debug_printf("[d3d12_video_encoder] d3d12_video_encoder_ensure_fence_finished failed for fenceValue: %" PRIu64 "\n", fenceValueToWaitOn);
225    pD3D12Enc->m_inflightResourcesPool[fenceValueToWaitOn % D3D12_VIDEO_ENC_ASYNC_DEPTH].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
226    pD3D12Enc->m_spEncodedFrameMetadata[fenceValueToWaitOn % D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
227    assert(false);
228    return false;
229 }
230 
231 bool
d3d12_video_encoder_sync_completion(struct pipe_video_codec * codec,ID3D12Fence * fence,uint64_t fenceValueToWaitOn,uint64_t timeout_ns)232 d3d12_video_encoder_sync_completion(struct pipe_video_codec *codec,
233                                     ID3D12Fence *fence,
234                                     uint64_t fenceValueToWaitOn,
235                                     uint64_t timeout_ns)
236 {
237       struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
238       assert(pD3D12Enc);
239       assert(pD3D12Enc->m_spD3D12VideoDevice);
240       assert(pD3D12Enc->m_spEncodeCommandQueue);
241       HRESULT hr = S_OK;
242 
243       bool wait_result = d3d12_video_encoder_ensure_fence_finished(codec, fence, fenceValueToWaitOn, timeout_ns);
244       assert(wait_result);
245 
246       debug_printf("[d3d12_video_encoder] d3d12_video_encoder_sync_completion - resetting ID3D12CommandAllocator %p...\n",
247          pD3D12Enc->m_inflightResourcesPool[fenceValueToWaitOn % D3D12_VIDEO_ENC_ASYNC_DEPTH].m_spCommandAllocator.Get());
248       hr = pD3D12Enc->m_inflightResourcesPool[fenceValueToWaitOn % D3D12_VIDEO_ENC_ASYNC_DEPTH].m_spCommandAllocator->Reset();
249       if(FAILED(hr)) {
250          debug_printf("failed with %x.\n", hr);
251          goto sync_with_token_fail;
252       }
253 
254       // Release references granted on end_frame for this inflight operations
255       pD3D12Enc->m_inflightResourcesPool[fenceValueToWaitOn % D3D12_VIDEO_ENC_ASYNC_DEPTH].m_spEncoder.Reset();
256       pD3D12Enc->m_inflightResourcesPool[fenceValueToWaitOn % D3D12_VIDEO_ENC_ASYNC_DEPTH].m_spEncoderHeap.Reset();
257       pD3D12Enc->m_inflightResourcesPool[fenceValueToWaitOn % D3D12_VIDEO_ENC_ASYNC_DEPTH].m_References.reset();
258       pD3D12Enc->m_inflightResourcesPool[fenceValueToWaitOn % D3D12_VIDEO_ENC_ASYNC_DEPTH].m_InputSurfaceFence = NULL;
259 
260       // Validate device was not removed
261       hr = pD3D12Enc->m_pD3D12Screen->dev->GetDeviceRemovedReason();
262       if (hr != S_OK) {
263          debug_printf("[d3d12_video_encoder] d3d12_video_encoder_sync_completion"
264                          " - D3D12Device was removed AFTER d3d12_video_encoder_ensure_fence_finished "
265                          "execution with HR %x, but wasn't before.\n",
266                          hr);
267          goto sync_with_token_fail;
268       }
269 
270       debug_printf(
271          "[d3d12_video_encoder] d3d12_video_encoder_sync_completion - GPU execution finalized for fenceValue: %" PRIu64 "\n",
272          fenceValueToWaitOn);
273 
274       return wait_result;
275 
276 sync_with_token_fail:
277    debug_printf("[d3d12_video_encoder] d3d12_video_encoder_sync_completion failed for fenceValue: %" PRIu64 "\n", fenceValueToWaitOn);
278    pD3D12Enc->m_inflightResourcesPool[fenceValueToWaitOn % D3D12_VIDEO_ENC_ASYNC_DEPTH].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
279    pD3D12Enc->m_spEncodedFrameMetadata[fenceValueToWaitOn % D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
280    assert(false);
281    return false;
282 }
283 
284 /**
285  * Destroys a d3d12_video_encoder
286  * Call destroy_XX for applicable XX nested member types before deallocating
287  * Destroy methods should check != nullptr on their input target argument as this method can be called as part of
288  * cleanup from failure on the creation method
289  */
290 void
d3d12_video_encoder_destroy(struct pipe_video_codec * codec)291 d3d12_video_encoder_destroy(struct pipe_video_codec *codec)
292 {
293    if (codec == nullptr) {
294       return;
295    }
296 
297    struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
298 
299       // Flush pending work before destroying
300    if(pD3D12Enc->m_bPendingWorkNotFlushed){
301       uint64_t curBatchFence = pD3D12Enc->m_fenceValue;
302       d3d12_video_encoder_flush(codec);
303       d3d12_video_encoder_sync_completion(codec, pD3D12Enc->m_spFence.Get(), curBatchFence, OS_TIMEOUT_INFINITE);
304    }
305 
306    if (pD3D12Enc->m_nalPrefixTmpBuffer)
307       pD3D12Enc->m_screen->resource_destroy(pD3D12Enc->m_screen, pD3D12Enc->m_nalPrefixTmpBuffer);
308 
309    // Call d3d12_video_encoder dtor to make ComPtr and other member's destructors work
310    delete pD3D12Enc;
311 }
312 
313 static const char *
d3d12_video_encoder_friendly_frame_type_h264(D3D12_VIDEO_ENCODER_FRAME_TYPE_H264 picType)314 d3d12_video_encoder_friendly_frame_type_h264(D3D12_VIDEO_ENCODER_FRAME_TYPE_H264 picType)
315 {
316    switch (picType) {
317       case D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME:
318       {
319          return "H264_P_FRAME";
320       } break;
321       case D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME:
322       {
323          return "H264_B_FRAME";
324       } break;
325       case D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_I_FRAME:
326       {
327          return "H264_I_FRAME";
328       } break;
329       case D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME:
330       {
331          return "H264_IDR_FRAME";
332       } break;
333       default:
334       {
335          unreachable("Unsupported pipe_h2645_enc_picture_type");
336       } break;
337    }
338 }
339 
340 void
d3d12_video_encoder_update_picparams_tracking(struct d3d12_video_encoder * pD3D12Enc,struct pipe_video_buffer * srcTexture,struct pipe_picture_desc * picture)341 d3d12_video_encoder_update_picparams_tracking(struct d3d12_video_encoder *pD3D12Enc,
342                                               struct pipe_video_buffer *  srcTexture,
343                                               struct pipe_picture_desc *  picture)
344 {
345    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA currentPicParams =
346       d3d12_video_encoder_get_current_picture_param_settings(pD3D12Enc);
347 
348    enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
349    bool bUsedAsReference = false;
350    switch (codec) {
351 #if VIDEO_CODEC_H264ENC
352       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
353       {
354          d3d12_video_encoder_update_current_frame_pic_params_info_h264(pD3D12Enc, srcTexture, picture, currentPicParams, bUsedAsReference);
355       } break;
356 #endif
357 #if VIDEO_CODEC_H265ENC
358       case PIPE_VIDEO_FORMAT_HEVC:
359       {
360          d3d12_video_encoder_update_current_frame_pic_params_info_hevc(pD3D12Enc, srcTexture, picture, currentPicParams, bUsedAsReference);
361       } break;
362 #endif
363 #if VIDEO_CODEC_AV1ENC
364       case PIPE_VIDEO_FORMAT_AV1:
365       {
366          d3d12_video_encoder_update_current_frame_pic_params_info_av1(pD3D12Enc, srcTexture, picture, currentPicParams, bUsedAsReference);
367       } break;
368 #endif
369       default:
370       {
371          unreachable("Unsupported pipe_video_format");
372       } break;
373    }
374 
375    size_t current_metadata_slot = d3d12_video_encoder_metadata_current_index(pD3D12Enc);
376    debug_printf("d3d12_video_encoder_update_picparams_tracking submission saving snapshot for fenceValue %" PRIu64 " current_metadata_slot %" PRIu64 " - POC %d picture_type %s LayoutMode %d SlicesCount %d IRMode %d IRIndex %d\n",
377                 pD3D12Enc->m_fenceValue,
378                 static_cast<uint64_t>(current_metadata_slot),
379                 pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_encoderPicParamsDesc.m_H264PicData.PictureOrderCountNumber,
380                 d3d12_video_encoder_friendly_frame_type_h264(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_encoderPicParamsDesc.m_H264PicData.FrameType),
381                 pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_encoderSliceConfigMode,
382                 pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_H264.NumberOfSlicesPerFrame,
383                 static_cast<uint32_t>(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_IntraRefresh.Mode),
384                 pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_IntraRefreshCurrentFrameIndex);
385 }
386 
387 bool
d3d12_video_encoder_uses_direct_dpb(enum pipe_video_format codec)388 d3d12_video_encoder_uses_direct_dpb(enum pipe_video_format codec)
389 {
390    switch (codec) {
391 #if VIDEO_CODEC_H264ENC
392       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
393       {
394          return true;
395       } break;
396 #endif
397 #if VIDEO_CODEC_H265ENC
398       case PIPE_VIDEO_FORMAT_HEVC:
399       {
400          return true;
401       } break;
402 #endif
403 #if VIDEO_CODEC_AV1ENC
404       case PIPE_VIDEO_FORMAT_AV1:
405       {
406         return false;
407       } break;
408 #endif
409       default:
410       {
411          unreachable("Unsupported pipe_video_format");
412       } break;
413    }
414 }
415 
416 bool
d3d12_video_encoder_reconfigure_encoder_objects(struct d3d12_video_encoder * pD3D12Enc,struct pipe_video_buffer * srcTexture,struct pipe_picture_desc * picture)417 d3d12_video_encoder_reconfigure_encoder_objects(struct d3d12_video_encoder *pD3D12Enc,
418                                                 struct pipe_video_buffer *  srcTexture,
419                                                 struct pipe_picture_desc *  picture)
420 {
421    bool codecChanged =
422       ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_codec) != 0);
423    bool profileChanged =
424       ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_profile) != 0);
425    bool levelChanged =
426       ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_level) != 0);
427    bool codecConfigChanged =
428       ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_codec_config) != 0);
429    bool inputFormatChanged =
430       ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_input_format) != 0);
431    bool resolutionChanged =
432       ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_resolution) != 0);
433    bool rateControlChanged =
434       ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_rate_control) != 0);
435    bool slicesChanged =
436       ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_slices) != 0);
437    bool gopChanged =
438       ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_gop) != 0);
439    bool motionPrecisionLimitChanged = ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags &
440                                         d3d12_video_encoder_config_dirty_flag_motion_precision_limit) != 0);
441    bool irChanged = ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags &
442                                         d3d12_video_encoder_config_dirty_flag_intra_refresh) != 0);
443 
444    // Events that that trigger a re-creation of the reference picture manager
445    // Stores codec agnostic textures so only input format, resolution and gop (num dpb references) affects this
446    if (!pD3D12Enc->m_upDPBManager
447        // || codecChanged
448        // || profileChanged
449        // || levelChanged
450        // || codecConfigChanged
451        || inputFormatChanged ||
452        resolutionChanged
453        // || rateControlChanged
454        // || slicesChanged
455        || gopChanged
456        // || motionPrecisionLimitChanged
457    ) {
458       if (!pD3D12Enc->m_upDPBManager) {
459          debug_printf("[d3d12_video_encoder] d3d12_video_encoder_reconfigure_encoder_objects - Creating Reference "
460                        "Pictures Manager for the first time\n");
461       } else {
462          debug_printf("[d3d12_video_encoder] Reconfiguration triggered -> Re-creating Reference Pictures Manager\n");
463       }
464 
465       enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
466       if (!d3d12_video_encoder_uses_direct_dpb(codec))
467       {
468          D3D12_RESOURCE_FLAGS resourceAllocFlags =
469             D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
470          bool     fArrayOfTextures = ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
471                                  D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RECONSTRUCTED_FRAMES_REQUIRE_TEXTURE_ARRAYS) == 0);
472          uint32_t texturePoolSize  = d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc);
473          assert(texturePoolSize < UINT16_MAX);
474          pD3D12Enc->m_upDPBStorageManager.reset();
475          if (fArrayOfTextures) {
476             pD3D12Enc->m_upDPBStorageManager = std::make_unique<d3d12_array_of_textures_dpb_manager>(
477                static_cast<uint16_t>(texturePoolSize),
478                pD3D12Enc->m_pD3D12Screen->dev,
479                pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
480                pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
481                resourceAllocFlags,
482                true,   // setNullSubresourcesOnAllZero - D3D12 Video Encode expects nullptr pSubresources if AoT,
483                pD3D12Enc->m_NodeMask,
484                /*use underlying pool, we can't reuse upper level allocations, need D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY*/
485                true);
486          } else {
487             pD3D12Enc->m_upDPBStorageManager = std::make_unique<d3d12_texture_array_dpb_manager>(
488                static_cast<uint16_t>(texturePoolSize),
489                pD3D12Enc->m_pD3D12Screen->dev,
490                pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
491                pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
492                resourceAllocFlags,
493                pD3D12Enc->m_NodeMask);
494          }
495       }
496 
497       d3d12_video_encoder_create_reference_picture_manager(pD3D12Enc, picture);
498    }
499 
500    bool reCreatedEncoder = false;
501    // Events that that trigger a re-creation of the encoder
502    if (!pD3D12Enc->m_spVideoEncoder || codecChanged ||
503        profileChanged
504        // || levelChanged // Only affects encoder heap
505        || codecConfigChanged ||
506        inputFormatChanged
507        // || resolutionChanged // Only affects encoder heap
508        // Only re-create if there is NO SUPPORT for reconfiguring rateControl on the fly
509        || (rateControlChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
510                                    D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_RECONFIGURATION_AVAILABLE) ==
511                                   0 /*checking the flag is NOT set*/))
512        // Only re-create if there is NO SUPPORT for reconfiguring slices on the fly
513        || (slicesChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
514                               D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SUBREGION_LAYOUT_RECONFIGURATION_AVAILABLE) ==
515                              0 /*checking the flag is NOT set*/))
516        // Only re-create if there is NO SUPPORT for reconfiguring gop on the fly
517        || (gopChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
518                            D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SEQUENCE_GOP_RECONFIGURATION_AVAILABLE) ==
519                           0 /*checking the flag is NOT set*/)) ||
520        motionPrecisionLimitChanged) {
521       if (!pD3D12Enc->m_spVideoEncoder) {
522          debug_printf("[d3d12_video_encoder] d3d12_video_encoder_reconfigure_encoder_objects - Creating "
523                        "D3D12VideoEncoder for the first time\n");
524       } else {
525          debug_printf("[d3d12_video_encoder] Reconfiguration triggered -> Re-creating D3D12VideoEncoder\n");
526          reCreatedEncoder = true;
527       }
528 
529       D3D12_VIDEO_ENCODER_DESC encoderDesc = { pD3D12Enc->m_NodeMask,
530                                                D3D12_VIDEO_ENCODER_FLAG_NONE,
531                                                pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc,
532                                                d3d12_video_encoder_get_current_profile_desc(pD3D12Enc),
533                                                pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
534                                                d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc),
535                                                pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit };
536 
537       // Create encoder
538       pD3D12Enc->m_spVideoEncoder.Reset();
539       HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CreateVideoEncoder(&encoderDesc,
540                                                              IID_PPV_ARGS(pD3D12Enc->m_spVideoEncoder.GetAddressOf()));
541       if (FAILED(hr)) {
542          debug_printf("CreateVideoEncoder failed with HR %x\n", hr);
543          return false;
544       }
545    }
546 
547    bool reCreatedEncoderHeap = false;
548    // Events that that trigger a re-creation of the encoder heap
549    if (!pD3D12Enc->m_spVideoEncoderHeap || codecChanged || profileChanged ||
550        levelChanged
551        // || codecConfigChanged // Only affects encoder
552        || inputFormatChanged   // Might affect internal textures in the heap
553        || resolutionChanged
554        // Only re-create if there is NO SUPPORT for reconfiguring rateControl on the fly
555        || (rateControlChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
556                                    D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_RECONFIGURATION_AVAILABLE) ==
557                                   0 /*checking the flag is NOT set*/))
558        // Only re-create if there is NO SUPPORT for reconfiguring slices on the fly
559        || (slicesChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
560                               D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SUBREGION_LAYOUT_RECONFIGURATION_AVAILABLE) ==
561                              0 /*checking the flag is NOT set*/))
562        // Only re-create if there is NO SUPPORT for reconfiguring gop on the fly
563        || (gopChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
564                            D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SEQUENCE_GOP_RECONFIGURATION_AVAILABLE) ==
565                           0 /*checking the flag is NOT set*/))
566        // || motionPrecisionLimitChanged // Only affects encoder
567    ) {
568       if (!pD3D12Enc->m_spVideoEncoderHeap) {
569          debug_printf("[d3d12_video_encoder] d3d12_video_encoder_reconfigure_encoder_objects - Creating "
570                        "D3D12VideoEncoderHeap for the first time\n");
571       } else {
572          debug_printf("[d3d12_video_encoder] Reconfiguration triggered -> Re-creating D3D12VideoEncoderHeap\n");
573          reCreatedEncoderHeap = true;
574       }
575 
576       D3D12_VIDEO_ENCODER_HEAP_DESC heapDesc = { pD3D12Enc->m_NodeMask,
577                                                  D3D12_VIDEO_ENCODER_HEAP_FLAG_NONE,
578                                                  pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc,
579                                                  d3d12_video_encoder_get_current_profile_desc(pD3D12Enc),
580                                                  d3d12_video_encoder_get_current_level_desc(pD3D12Enc),
581                                                  // resolution list count
582                                                  1,
583                                                  // resolution list
584                                                  &pD3D12Enc->m_currentEncodeConfig.m_currentResolution };
585 
586       // Create encoder heap
587       pD3D12Enc->m_spVideoEncoderHeap.Reset();
588       HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CreateVideoEncoderHeap(&heapDesc,
589                                                                            IID_PPV_ARGS(pD3D12Enc->m_spVideoEncoderHeap.GetAddressOf()));
590       if (FAILED(hr)) {
591          debug_printf("CreateVideoEncoderHeap failed with HR %x\n", hr);
592          return false;
593       }
594    }
595 
596    // If on-the-fly reconfiguration happened without object recreation, set
597    // D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_*_CHANGED reconfiguration flags in EncodeFrame
598 
599    // When driver workaround for rate control reconfig is active we cannot send to the driver the
600    // D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_RATE_CONTROL_CHANGE since it's not actually reporting
601    // support for setting it.
602    if ((pD3D12Enc->driver_workarounds & d3d12_video_encoder_driver_workaround_rate_control_reconfig) == 0) {
603       if (rateControlChanged &&
604          ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
605             D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_RECONFIGURATION_AVAILABLE) !=
606          0 /*checking if the flag it's actually set*/) &&
607          (pD3D12Enc->m_fenceValue > 1) && (!reCreatedEncoder || !reCreatedEncoderHeap)) {
608          pD3D12Enc->m_currentEncodeConfig.m_seqFlags |= D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_RATE_CONTROL_CHANGE;
609       }
610    }
611 
612    if (slicesChanged &&
613        ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
614          D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SUBREGION_LAYOUT_RECONFIGURATION_AVAILABLE) !=
615         0 /*checking if the flag it's actually set*/) &&
616        (pD3D12Enc->m_fenceValue > 1) && (!reCreatedEncoder || !reCreatedEncoderHeap)) {
617       pD3D12Enc->m_currentEncodeConfig.m_seqFlags |= D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_SUBREGION_LAYOUT_CHANGE;
618    }
619 
620    if (gopChanged &&
621        ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
622          D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SEQUENCE_GOP_RECONFIGURATION_AVAILABLE) !=
623         0 /*checking if the flag it's actually set*/) &&
624        (pD3D12Enc->m_fenceValue > 1) && (!reCreatedEncoder || !reCreatedEncoderHeap)) {
625       pD3D12Enc->m_currentEncodeConfig.m_seqFlags |= D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_GOP_SEQUENCE_CHANGE;
626    }
627 
628    if(irChanged)
629       pD3D12Enc->m_currentEncodeConfig.m_seqFlags |= D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_REQUEST_INTRA_REFRESH;
630 
631    return true;
632 }
633 
634 void
d3d12_video_encoder_create_reference_picture_manager(struct d3d12_video_encoder * pD3D12Enc,struct pipe_picture_desc * picture)635 d3d12_video_encoder_create_reference_picture_manager(struct d3d12_video_encoder *pD3D12Enc, struct pipe_picture_desc *  picture)
636 {
637    pD3D12Enc->m_upDPBManager.reset();
638    pD3D12Enc->m_upBitstreamBuilder.reset();
639    enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
640    switch (codec) {
641 #if VIDEO_CODEC_H264ENC
642       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
643       {
644          pD3D12Enc->m_upDPBManager = std::make_unique<d3d12_video_encoder_references_manager_h264>();
645          pD3D12Enc->m_upBitstreamBuilder = std::make_unique<d3d12_video_bitstream_builder_h264>();
646       } break;
647 #endif
648 #if VIDEO_CODEC_H265ENC
649       case PIPE_VIDEO_FORMAT_HEVC:
650       {
651          pD3D12Enc->m_upDPBManager = std::make_unique<d3d12_video_encoder_references_manager_hevc>();
652          pD3D12Enc->m_upBitstreamBuilder = std::make_unique<d3d12_video_bitstream_builder_hevc>();
653       } break;
654 #endif
655 #if VIDEO_CODEC_AV1ENC
656       case PIPE_VIDEO_FORMAT_AV1:
657       {
658          bool hasInterFrames =
659             (pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_AV1SequenceStructure.InterFramePeriod > 0) &&
660             ((pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_AV1SequenceStructure.IntraDistance == 0) ||
661              (pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_AV1SequenceStructure.InterFramePeriod <
662               pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_AV1SequenceStructure.IntraDistance));
663 
664          pD3D12Enc->m_upDPBManager = std::make_unique<d3d12_video_encoder_references_manager_av1>(
665             hasInterFrames,
666             *pD3D12Enc->m_upDPBStorageManager
667          );
668 
669          // We use packed headers and pist encode execution syntax for AV1
670          pD3D12Enc->m_upBitstreamBuilder = std::make_unique<d3d12_video_bitstream_builder_av1>();
671       } break;
672 #endif
673       default:
674       {
675          unreachable("Unsupported pipe_video_format");
676       } break;
677    }
678 }
679 
680 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA
d3d12_video_encoder_get_current_slice_param_settings(struct d3d12_video_encoder * pD3D12Enc)681 d3d12_video_encoder_get_current_slice_param_settings(struct d3d12_video_encoder *pD3D12Enc)
682 {
683    enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
684    switch (codec) {
685 #if VIDEO_CODEC_H264ENC
686       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
687       {
688          D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA subregionData = {};
689          if (pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode !=
690              D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME) {
691             subregionData.pSlicesPartition_H264 =
692                &pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_H264;
693             subregionData.DataSize = sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES);
694          }
695          return subregionData;
696       } break;
697 #endif
698 #if VIDEO_CODEC_H265ENC
699       case PIPE_VIDEO_FORMAT_HEVC:
700       {
701          D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA subregionData = {};
702          if (pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode !=
703              D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME) {
704             subregionData.pSlicesPartition_HEVC =
705                &pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_HEVC;
706             subregionData.DataSize = sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES);
707          }
708          return subregionData;
709       } break;
710 #endif
711 #if VIDEO_CODEC_AV1ENC
712       case PIPE_VIDEO_FORMAT_AV1:
713       {
714          D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA subregionData = {};
715          if (pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode !=
716              D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME) {
717             subregionData.pTilesPartition_AV1 =
718                &pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_TilesConfig_AV1.TilesPartition;
719             subregionData.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES);
720          }
721          return subregionData;
722       } break;
723 #endif
724       default:
725       {
726          unreachable("Unsupported pipe_video_format");
727       } break;
728    }
729 }
730 
731 D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA
d3d12_video_encoder_get_current_picture_param_settings(struct d3d12_video_encoder * pD3D12Enc)732 d3d12_video_encoder_get_current_picture_param_settings(struct d3d12_video_encoder *pD3D12Enc)
733 {
734    enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
735    switch (codec) {
736 #if VIDEO_CODEC_H264ENC
737       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
738       {
739          D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curPicParamsData = {};
740          curPicParamsData.pH264PicData = &pD3D12Enc->m_currentEncodeConfig.m_encoderPicParamsDesc.m_H264PicData;
741          curPicParamsData.DataSize     = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderPicParamsDesc.m_H264PicData);
742          return curPicParamsData;
743       } break;
744 #endif
745 #if VIDEO_CODEC_H265ENC
746       case PIPE_VIDEO_FORMAT_HEVC:
747       {
748          return ConvertHEVCPicParamsFromProfile(pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile,
749                                                 &pD3D12Enc->m_currentEncodeConfig.m_encoderPicParamsDesc.m_HEVCPicData);
750       } break;
751 #endif
752 #if VIDEO_CODEC_AV1ENC
753       case PIPE_VIDEO_FORMAT_AV1:
754       {
755          D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curPicParamsData = {};
756          curPicParamsData.pAV1PicData = &pD3D12Enc->m_currentEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData;
757          curPicParamsData.DataSize     = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderPicParamsDesc.m_AV1PicData);
758          return curPicParamsData;
759       } break;
760 #endif
761       default:
762       {
763          unreachable("Unsupported pipe_video_format");
764       } break;
765    }
766 }
767 
768 D3D12_VIDEO_ENCODER_RATE_CONTROL
d3d12_video_encoder_get_current_rate_control_settings(struct d3d12_video_encoder * pD3D12Enc)769 d3d12_video_encoder_get_current_rate_control_settings(struct d3d12_video_encoder *pD3D12Enc)
770 {
771    D3D12_VIDEO_ENCODER_RATE_CONTROL curRateControlDesc = {};
772    curRateControlDesc.Mode            = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Mode;
773    curRateControlDesc.Flags           = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Flags;
774    curRateControlDesc.TargetFrameRate = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_FrameRate;
775 
776    if ((curRateControlDesc.Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT) != 0)
777    {
778       switch (pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Mode) {
779          case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_ABSOLUTE_QP_MAP:
780          {
781             curRateControlDesc.ConfigParams.pConfiguration_CQP1 = nullptr;
782             curRateControlDesc.ConfigParams.DataSize           = 0;
783          } break;
784          case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP:
785          {
786             curRateControlDesc.ConfigParams.pConfiguration_CQP1 =
787                &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_CQP1;
788             curRateControlDesc.ConfigParams.DataSize =
789                sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_CQP1);
790          } break;
791          case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR:
792          {
793             curRateControlDesc.ConfigParams.pConfiguration_CBR1 =
794                &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_CBR1;
795             curRateControlDesc.ConfigParams.DataSize =
796                sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_CBR1);
797          } break;
798          case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR:
799          {
800             curRateControlDesc.ConfigParams.pConfiguration_VBR1 =
801                &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_VBR1;
802             curRateControlDesc.ConfigParams.DataSize =
803                sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_VBR1);
804          } break;
805          case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR:
806          {
807             curRateControlDesc.ConfigParams.pConfiguration_QVBR1 =
808                &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_QVBR1;
809             curRateControlDesc.ConfigParams.DataSize =
810                sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_QVBR1);
811          } break;
812          default:
813          {
814             unreachable("Unsupported D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE");
815          } break;
816       }
817    }
818    else
819    {
820       switch (pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Mode) {
821          case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_ABSOLUTE_QP_MAP:
822          {
823             curRateControlDesc.ConfigParams.pConfiguration_CQP = nullptr;
824             curRateControlDesc.ConfigParams.DataSize           = 0;
825          } break;
826          case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP:
827          {
828             curRateControlDesc.ConfigParams.pConfiguration_CQP =
829                &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_CQP;
830             curRateControlDesc.ConfigParams.DataSize =
831                sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_CQP);
832          } break;
833          case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR:
834          {
835             curRateControlDesc.ConfigParams.pConfiguration_CBR =
836                &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_CBR;
837             curRateControlDesc.ConfigParams.DataSize =
838                sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_CBR);
839          } break;
840          case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR:
841          {
842             curRateControlDesc.ConfigParams.pConfiguration_VBR =
843                &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_VBR;
844             curRateControlDesc.ConfigParams.DataSize =
845                sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_VBR);
846          } break;
847          case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR:
848          {
849             curRateControlDesc.ConfigParams.pConfiguration_QVBR =
850                &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_QVBR;
851             curRateControlDesc.ConfigParams.DataSize =
852                sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Config.m_Configuration_QVBR);
853          } break;
854          default:
855          {
856             unreachable("Unsupported D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE");
857          } break;
858       }
859    }
860 
861    return curRateControlDesc;
862 }
863 
864 D3D12_VIDEO_ENCODER_LEVEL_SETTING
d3d12_video_encoder_get_current_level_desc(struct d3d12_video_encoder * pD3D12Enc)865 d3d12_video_encoder_get_current_level_desc(struct d3d12_video_encoder *pD3D12Enc)
866 {
867    enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
868    switch (codec) {
869 #if VIDEO_CODEC_H264ENC
870       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
871       {
872          D3D12_VIDEO_ENCODER_LEVEL_SETTING curLevelDesc = {};
873          curLevelDesc.pH264LevelSetting = &pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting;
874          curLevelDesc.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting);
875          return curLevelDesc;
876       } break;
877 #endif
878 #if VIDEO_CODEC_H265ENC
879       case PIPE_VIDEO_FORMAT_HEVC:
880       {
881          D3D12_VIDEO_ENCODER_LEVEL_SETTING curLevelDesc = {};
882          curLevelDesc.pHEVCLevelSetting = &pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting;
883          curLevelDesc.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_HEVCLevelSetting);
884          return curLevelDesc;
885       } break;
886 #endif
887 #if VIDEO_CODEC_AV1ENC
888       case PIPE_VIDEO_FORMAT_AV1:
889       {
890          D3D12_VIDEO_ENCODER_LEVEL_SETTING curLevelDesc = {};
891          curLevelDesc.pAV1LevelSetting = &pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_AV1LevelSetting;
892          curLevelDesc.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_AV1LevelSetting);
893          return curLevelDesc;
894       } break;
895 #endif
896       default:
897       {
898          unreachable("Unsupported pipe_video_format");
899       } break;
900    }
901 }
902 
903 void
d3d12_video_encoder_build_pre_encode_codec_headers(struct d3d12_video_encoder * pD3D12Enc,bool & postEncodeHeadersNeeded,uint64_t & preEncodeGeneratedHeadersByteSize,std::vector<uint64_t> & pWrittenCodecUnitsSizes)904 d3d12_video_encoder_build_pre_encode_codec_headers(struct d3d12_video_encoder *pD3D12Enc,
905                                                    bool &postEncodeHeadersNeeded,
906                                                    uint64_t &preEncodeGeneratedHeadersByteSize,
907                                                    std::vector<uint64_t> &pWrittenCodecUnitsSizes)
908 {
909    enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
910    switch (codec) {
911 #if VIDEO_CODEC_H264ENC
912       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
913       {
914          postEncodeHeadersNeeded = false;
915          preEncodeGeneratedHeadersByteSize = d3d12_video_encoder_build_codec_headers_h264(pD3D12Enc, pWrittenCodecUnitsSizes);
916       } break;
917 #endif
918 #if VIDEO_CODEC_H265ENC
919       case PIPE_VIDEO_FORMAT_HEVC:
920       {
921          postEncodeHeadersNeeded = false;
922          preEncodeGeneratedHeadersByteSize = d3d12_video_encoder_build_codec_headers_hevc(pD3D12Enc, pWrittenCodecUnitsSizes);
923       } break;
924 #endif
925 #if VIDEO_CODEC_AV1ENC
926       case PIPE_VIDEO_FORMAT_AV1:
927       {
928          pD3D12Enc->m_BitstreamHeadersBuffer.resize(0);
929          postEncodeHeadersNeeded = true;
930          preEncodeGeneratedHeadersByteSize = 0;
931          pWrittenCodecUnitsSizes.clear();
932       } break;
933 #endif
934       default:
935       {
936          unreachable("Unsupported pipe_video_format");
937       } break;
938    }
939 }
940 
941 D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE
d3d12_video_encoder_get_current_gop_desc(struct d3d12_video_encoder * pD3D12Enc)942 d3d12_video_encoder_get_current_gop_desc(struct d3d12_video_encoder *pD3D12Enc)
943 {
944    enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
945    switch (codec) {
946 #if VIDEO_CODEC_H264ENC
947       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
948       {
949          D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE curGOPDesc = {};
950          curGOPDesc.pH264GroupOfPictures =
951             &pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures;
952          curGOPDesc.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures);
953          return curGOPDesc;
954       } break;
955 #endif
956 #if VIDEO_CODEC_H265ENC
957       case PIPE_VIDEO_FORMAT_HEVC:
958       {
959          D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE curGOPDesc = {};
960          curGOPDesc.pHEVCGroupOfPictures =
961             &pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures;
962          curGOPDesc.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_HEVCGroupOfPictures);
963          return curGOPDesc;
964       } break;
965 #endif
966 #if VIDEO_CODEC_AV1ENC
967       case PIPE_VIDEO_FORMAT_AV1:
968       {
969          D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE curGOPDesc = {};
970          curGOPDesc.pAV1SequenceStructure =
971             &pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_AV1SequenceStructure;
972          curGOPDesc.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_AV1SequenceStructure);
973          return curGOPDesc;
974       } break;
975 #endif
976       default:
977       {
978          unreachable("Unsupported pipe_video_format");
979       } break;
980    }
981 }
982 
983 D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION
d3d12_video_encoder_get_current_codec_config_desc(struct d3d12_video_encoder * pD3D12Enc)984 d3d12_video_encoder_get_current_codec_config_desc(struct d3d12_video_encoder *pD3D12Enc)
985 {
986    enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
987    switch (codec) {
988 #if VIDEO_CODEC_H264ENC
989       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
990       {
991          D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION codecConfigDesc = {};
992          codecConfigDesc.pH264Config = &pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_H264Config;
993          codecConfigDesc.DataSize =
994             sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_H264Config);
995          return codecConfigDesc;
996       } break;
997 #endif
998 #if VIDEO_CODEC_H265ENC
999       case PIPE_VIDEO_FORMAT_HEVC:
1000       {
1001          D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION codecConfigDesc = {};
1002          codecConfigDesc.pHEVCConfig = &pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig;
1003          codecConfigDesc.DataSize =
1004             sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_HEVCConfig);
1005          return codecConfigDesc;
1006       } break;
1007 #endif
1008 #if VIDEO_CODEC_AV1ENC
1009       case PIPE_VIDEO_FORMAT_AV1:
1010       {
1011          D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION codecConfigDesc = {};
1012          codecConfigDesc.pAV1Config = &pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config;
1013          codecConfigDesc.DataSize =
1014             sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config);
1015          return codecConfigDesc;
1016       } break;
1017 #endif
1018       default:
1019       {
1020          unreachable("Unsupported pipe_video_format");
1021       } break;
1022    }
1023 }
1024 
1025 D3D12_VIDEO_ENCODER_CODEC
d3d12_video_encoder_get_current_codec(struct d3d12_video_encoder * pD3D12Enc)1026 d3d12_video_encoder_get_current_codec(struct d3d12_video_encoder *pD3D12Enc)
1027 {
1028    enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
1029    switch (codec) {
1030 #if VIDEO_CODEC_H264ENC
1031       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
1032       {
1033          return D3D12_VIDEO_ENCODER_CODEC_H264;
1034       } break;
1035 #endif
1036 #if VIDEO_CODEC_H265ENC
1037       case PIPE_VIDEO_FORMAT_HEVC:
1038       {
1039          return D3D12_VIDEO_ENCODER_CODEC_HEVC;
1040       } break;
1041 #endif
1042 #if VIDEO_CODEC_AV1ENC
1043       case PIPE_VIDEO_FORMAT_AV1:
1044       {
1045          return D3D12_VIDEO_ENCODER_CODEC_AV1;
1046       } break;
1047 #endif
1048       default:
1049       {
1050          unreachable("Unsupported pipe_video_format");
1051       } break;
1052    }
1053 }
1054 
1055 static void
d3d12_video_encoder_disable_rc_vbv_sizes(struct D3D12EncodeRateControlState & rcState)1056 d3d12_video_encoder_disable_rc_vbv_sizes(struct D3D12EncodeRateControlState & rcState)
1057 {
1058    rcState.m_Flags &= ~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
1059    switch (rcState.m_Mode) {
1060       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR:
1061       {
1062          rcState.m_Config.m_Configuration_CBR.VBVCapacity = 0;
1063          rcState.m_Config.m_Configuration_CBR.InitialVBVFullness = 0;
1064       } break;
1065       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR:
1066       {
1067          rcState.m_Config.m_Configuration_VBR.VBVCapacity = 0;
1068          rcState.m_Config.m_Configuration_VBR.InitialVBVFullness = 0;
1069       } break;
1070       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR:
1071       {
1072          rcState.m_Config.m_Configuration_QVBR1.VBVCapacity = 0;
1073          rcState.m_Config.m_Configuration_QVBR1.InitialVBVFullness = 0;
1074       } break;
1075       default:
1076       {
1077          unreachable("Unsupported D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE for VBV Sizes");
1078       } break;
1079    }
1080 }
1081 
1082 static void
d3d12_video_encoder_disable_rc_maxframesize(struct D3D12EncodeRateControlState & rcState)1083 d3d12_video_encoder_disable_rc_maxframesize(struct D3D12EncodeRateControlState & rcState)
1084 {
1085    rcState.m_Flags &= ~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
1086    rcState.max_frame_size = 0;
1087    switch (rcState.m_Mode) {
1088       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR:
1089       {
1090          rcState.m_Config.m_Configuration_CBR.MaxFrameBitSize = 0;
1091       } break;
1092       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR:
1093       {
1094          rcState.m_Config.m_Configuration_VBR.MaxFrameBitSize = 0;
1095       } break;
1096       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR:
1097       {
1098          rcState.m_Config.m_Configuration_QVBR.MaxFrameBitSize = 0;
1099       } break;
1100       default:
1101       {
1102          unreachable("Unsupported D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE for VBV Sizes");
1103       } break;
1104    }
1105 }
1106 
1107 static bool
d3d12_video_encoder_is_qualitylevel_in_range(struct D3D12EncodeRateControlState & rcState,UINT MaxQualityVsSpeed)1108 d3d12_video_encoder_is_qualitylevel_in_range(struct D3D12EncodeRateControlState & rcState, UINT MaxQualityVsSpeed)
1109 {
1110    switch (rcState.m_Mode) {
1111       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP:
1112       {
1113          return rcState.m_Config.m_Configuration_CQP1.QualityVsSpeed <= MaxQualityVsSpeed;
1114       } break;
1115       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR:
1116       {
1117          return rcState.m_Config.m_Configuration_CBR1.QualityVsSpeed <= MaxQualityVsSpeed;
1118       } break;
1119       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR:
1120       {
1121          return rcState.m_Config.m_Configuration_VBR1.QualityVsSpeed <= MaxQualityVsSpeed;
1122       } break;
1123       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR:
1124       {
1125          return rcState.m_Config.m_Configuration_QVBR1.QualityVsSpeed <= MaxQualityVsSpeed;
1126       } break;
1127       default:
1128       {
1129          unreachable("Unsupported D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE");
1130       } break;
1131    }
1132 }
1133 
1134 static void
d3d12_video_encoder_disable_rc_qualitylevels(struct D3D12EncodeRateControlState & rcState)1135 d3d12_video_encoder_disable_rc_qualitylevels(struct D3D12EncodeRateControlState & rcState)
1136 {
1137    rcState.m_Flags &= ~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
1138    switch (rcState.m_Mode) {
1139       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP:
1140       {
1141          rcState.m_Config.m_Configuration_CQP1.QualityVsSpeed = 0;
1142       } break;
1143       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR:
1144       {
1145          rcState.m_Config.m_Configuration_CBR1.QualityVsSpeed = 0;
1146       } break;
1147       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR:
1148       {
1149          rcState.m_Config.m_Configuration_VBR1.QualityVsSpeed = 0;
1150       } break;
1151       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR:
1152       {
1153          rcState.m_Config.m_Configuration_QVBR1.QualityVsSpeed = 0;
1154       } break;
1155       default:
1156       {
1157          unreachable("Unsupported D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE");
1158       } break;
1159    }
1160 }
1161 
1162 static void
d3d12_video_encoder_disable_rc_deltaqp(struct D3D12EncodeRateControlState & rcState)1163 d3d12_video_encoder_disable_rc_deltaqp(struct D3D12EncodeRateControlState & rcState)
1164 {
1165    rcState.m_Flags &= ~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP;
1166 }
1167 
1168 static void
d3d12_video_encoder_disable_rc_minmaxqp(struct D3D12EncodeRateControlState & rcState)1169 d3d12_video_encoder_disable_rc_minmaxqp(struct D3D12EncodeRateControlState & rcState)
1170 {
1171    rcState.m_Flags &= ~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
1172    switch (rcState.m_Mode) {
1173       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR:
1174       {
1175          rcState.m_Config.m_Configuration_CBR.MinQP = 0;
1176          rcState.m_Config.m_Configuration_CBR.MaxQP = 0;
1177       } break;
1178       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR:
1179       {
1180          rcState.m_Config.m_Configuration_VBR.MinQP = 0;
1181          rcState.m_Config.m_Configuration_VBR.MaxQP = 0;
1182       } break;
1183       case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR:
1184       {
1185          rcState.m_Config.m_Configuration_QVBR.MinQP = 0;
1186          rcState.m_Config.m_Configuration_QVBR.MaxQP = 0;
1187       } break;
1188       default:
1189       {
1190          unreachable("Unsupported D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE for VBV Sizes");
1191       } break;
1192    }
1193 }
1194 
1195 static void
d3d12_video_encoder_disable_rc_extended1_to_legacy(struct D3D12EncodeRateControlState & rcState)1196 d3d12_video_encoder_disable_rc_extended1_to_legacy(struct D3D12EncodeRateControlState & rcState)
1197 {
1198    rcState.m_Flags &= ~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
1199    // Also remove features that require extension1 enabled (eg. quality levels)
1200    rcState.m_Flags &= ~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED;
1201    // rcState.m_Configuration_XXX and m_Configuration_XXX1 are unions, can be aliased
1202    // as the m_Configuration_XXX1 extensions are binary backcompat with m_Configuration_XXX
1203 }
1204 
1205 ///
1206 /// Call d3d12_video_encoder_query_d3d12_driver_caps and see if any optional feature requested
1207 /// is not supported, disable it, query again until finding a negotiated cap/feature set
1208 /// Note that with fallbacks, the upper layer will not get exactly the encoding seetings they requested
1209 /// but for very particular settings it's better to continue with warnings than failing the whole encoding process
1210 ///
d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(struct d3d12_video_encoder * pD3D12Enc,D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 & capEncoderSupportData1)1211 bool d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(struct d3d12_video_encoder *pD3D12Enc, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 &capEncoderSupportData1) {
1212 
1213    ///
1214    /// Check for general support
1215    /// Check for validation errors (some drivers return general support but also validation errors anyways, work around for those unexpected cases)
1216    ///
1217 
1218    bool configSupported = d3d12_video_encoder_query_d3d12_driver_caps(pD3D12Enc, /*inout*/ capEncoderSupportData1)
1219     && (((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_GENERAL_SUPPORT_OK) != 0)
1220                         && (capEncoderSupportData1.ValidationFlags == D3D12_VIDEO_ENCODER_VALIDATION_FLAG_NONE));
1221 
1222    ///
1223    /// If D3D12_FEATURE_VIDEO_ENCODER_SUPPORT is not supported, try falling back to unsetting optional features and check for caps again
1224    ///
1225 
1226    if (!configSupported) {
1227       debug_printf("[d3d12_video_encoder] WARNING: D3D12_FEATURE_VIDEO_ENCODER_SUPPORT is not supported, trying fallback to unsetting optional features\n");
1228 
1229       bool isRequestingVBVSizesSupported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_VBV_SIZE_CONFIG_AVAILABLE) != 0);
1230       bool isClientRequestingVBVSizes = ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES) != 0);
1231 
1232       if(isClientRequestingVBVSizes && !isRequestingVBVSizesSupported) {
1233          debug_printf("[d3d12_video_encoder] WARNING: Requested D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES with VBVCapacity and InitialVBVFullness is not supported, will continue encoding unsetting this feature as fallback.\n");
1234          d3d12_video_encoder_disable_rc_vbv_sizes(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex]);
1235       }
1236 
1237       bool isRequestingPeakFrameSizeSupported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_MAX_FRAME_SIZE_AVAILABLE) != 0);
1238       bool isClientRequestingPeakFrameSize = ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE) != 0);
1239 
1240       if(isClientRequestingPeakFrameSize && !isRequestingPeakFrameSizeSupported) {
1241          debug_printf("[d3d12_video_encoder] WARNING: Requested D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE with MaxFrameBitSize but the feature is not supported, will continue encoding unsetting this feature as fallback.\n");
1242          d3d12_video_encoder_disable_rc_maxframesize(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex]);
1243       }
1244 
1245       bool isRequestingQPRangesSupported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_ADJUSTABLE_QP_RANGE_AVAILABLE) != 0);
1246       bool isClientRequestingQPRanges = ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE) != 0);
1247 
1248       if(isClientRequestingQPRanges && !isRequestingQPRangesSupported) {
1249          debug_printf("[d3d12_video_encoder] WARNING: Requested D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE with QPMin QPMax but the feature is not supported, will continue encoding unsetting this feature as fallback.\n");
1250          d3d12_video_encoder_disable_rc_minmaxqp(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex]);
1251       }
1252 
1253       bool isRequestingDeltaQPSupported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_DELTA_QP_AVAILABLE) != 0);
1254       bool isClientRequestingDeltaQP = ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0);
1255 
1256       if(isClientRequestingDeltaQP && !isRequestingDeltaQPSupported) {
1257          debug_printf("[d3d12_video_encoder] WARNING: Requested D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP but the feature is not supported, will continue encoding unsetting this feature as fallback.\n");
1258          d3d12_video_encoder_disable_rc_deltaqp(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex]);
1259       }
1260 
1261       bool isRequestingExtended1RCSupported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_EXTENSION1_SUPPORT) != 0);
1262       bool isClientRequestingExtended1RC = ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT) != 0);
1263 
1264       if(isClientRequestingExtended1RC && !isRequestingExtended1RCSupported) {
1265          debug_printf("[d3d12_video_encoder] WARNING: Requested D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT but the feature is not supported, will continue encoding unsetting this feature and dependent features as fallback.\n");
1266          d3d12_video_encoder_disable_rc_extended1_to_legacy(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex]);
1267       }
1268 
1269       /* d3d12_video_encoder_disable_rc_extended1_to_legacy may change m_Flags */
1270       if ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT) != 0)
1271       { // Quality levels also requires D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT
1272          bool isRequestingQualityLevelsSupported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_QUALITY_VS_SPEED_AVAILABLE) != 0);
1273          bool isClientRequestingQualityLevels = ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED) != 0);
1274 
1275          if (isClientRequestingQualityLevels)
1276          {
1277             if (!isRequestingQualityLevelsSupported) {
1278                debug_printf("[d3d12_video_encoder] WARNING: Requested D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED but the feature is not supported, will continue encoding unsetting this feature as fallback.\n");
1279                d3d12_video_encoder_disable_rc_qualitylevels(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex]);
1280             } else if (!d3d12_video_encoder_is_qualitylevel_in_range(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex], capEncoderSupportData1.MaxQualityVsSpeed)) {
1281                debug_printf("[d3d12_video_encoder] WARNING: Requested D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QUALITY_VS_SPEED but the value is out of supported range, will continue encoding unsetting this feature as fallback.\n");
1282                d3d12_video_encoder_disable_rc_qualitylevels(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex]);
1283             }
1284          }
1285       }
1286 
1287       /* Try fallback for multi-slice/tile not supported with single subregion mode */
1288       if ((capEncoderSupportData1.ValidationFlags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_SUBREGION_LAYOUT_MODE_NOT_SUPPORTED) != 0) {
1289          pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME;
1290          debug_printf("[d3d12_video_encoder] WARNING: Requested slice/tile mode not supported by driver, will continue encoding with single subregion encoding.\n");
1291       }
1292 
1293       ///
1294       /// Try fallback configuration
1295       ///
1296       configSupported = d3d12_video_encoder_query_d3d12_driver_caps(pD3D12Enc, /*inout*/ capEncoderSupportData1)
1297          && (((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_GENERAL_SUPPORT_OK) != 0)
1298                         && (capEncoderSupportData1.ValidationFlags == D3D12_VIDEO_ENCODER_VALIDATION_FLAG_NONE));
1299    }
1300 
1301    if (pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh.IntraRefreshDuration >
1302       pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxIntraRefreshFrameDuration)
1303    {
1304       debug_printf("[d3d12_video_encoder] Desired duration of intrarefresh %d is not supported (higher than max "
1305                   "reported IR duration %d in query caps) for current resolution.\n",
1306                   pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh.IntraRefreshDuration,
1307                   pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxIntraRefreshFrameDuration);
1308       return false;
1309    }
1310 
1311    if(!configSupported) {
1312       debug_printf("[d3d12_video_encoder] Cap negotiation failed, see more details below:\n");
1313 
1314       if ((capEncoderSupportData1.ValidationFlags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_CODEC_NOT_SUPPORTED) != 0) {
1315          debug_printf("[d3d12_video_encoder] Requested codec is not supported\n");
1316       }
1317 
1318       if ((capEncoderSupportData1.ValidationFlags &
1319          D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RESOLUTION_NOT_SUPPORTED_IN_LIST) != 0) {
1320          debug_printf("[d3d12_video_encoder] Requested resolution is not supported\n");
1321       }
1322 
1323       if ((capEncoderSupportData1.ValidationFlags &
1324          D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RATE_CONTROL_CONFIGURATION_NOT_SUPPORTED) != 0) {
1325          debug_printf("[d3d12_video_encoder] Requested bitrate or rc config is not supported\n");
1326       }
1327 
1328       if ((capEncoderSupportData1.ValidationFlags &
1329          D3D12_VIDEO_ENCODER_VALIDATION_FLAG_CODEC_CONFIGURATION_NOT_SUPPORTED) != 0) {
1330          debug_printf("[d3d12_video_encoder] Requested codec config is not supported\n");
1331       }
1332 
1333       if ((capEncoderSupportData1.ValidationFlags &
1334          D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RATE_CONTROL_MODE_NOT_SUPPORTED) != 0) {
1335          debug_printf("[d3d12_video_encoder] Requested rate control mode is not supported\n");
1336       }
1337 
1338       if ((capEncoderSupportData1.ValidationFlags &
1339          D3D12_VIDEO_ENCODER_VALIDATION_FLAG_INTRA_REFRESH_MODE_NOT_SUPPORTED) != 0) {
1340          debug_printf("[d3d12_video_encoder] Requested intra refresh config is not supported\n");
1341       }
1342 
1343       if ((capEncoderSupportData1.ValidationFlags &
1344          D3D12_VIDEO_ENCODER_VALIDATION_FLAG_SUBREGION_LAYOUT_MODE_NOT_SUPPORTED) != 0) {
1345          debug_printf("[d3d12_video_encoder] Requested subregion layout mode is not supported\n");
1346       }
1347 
1348       if ((capEncoderSupportData1.ValidationFlags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_INPUT_FORMAT_NOT_SUPPORTED) !=
1349          0) {
1350          debug_printf("[d3d12_video_encoder] Requested input dxgi format is not supported\n");
1351       }
1352    }
1353 
1354    if (memcmp(&pD3D12Enc->m_prevFrameEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex],
1355               &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex],
1356               sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex])) != 0) {
1357       pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_rate_control;
1358    }
1359 
1360    return configSupported;
1361 }
1362 
d3d12_video_encoder_query_d3d12_driver_caps(struct d3d12_video_encoder * pD3D12Enc,D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 & capEncoderSupportData1)1363 bool d3d12_video_encoder_query_d3d12_driver_caps(struct d3d12_video_encoder *pD3D12Enc, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 &capEncoderSupportData1) {
1364    capEncoderSupportData1.NodeIndex                                = pD3D12Enc->m_NodeIndex;
1365    capEncoderSupportData1.Codec                                    = d3d12_video_encoder_get_current_codec(pD3D12Enc);
1366    capEncoderSupportData1.InputFormat            = pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format;
1367    capEncoderSupportData1.RateControl            = d3d12_video_encoder_get_current_rate_control_settings(pD3D12Enc);
1368    capEncoderSupportData1.IntraRefresh           = pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh.Mode;
1369    capEncoderSupportData1.SubregionFrameEncoding = pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode;
1370    capEncoderSupportData1.ResolutionsListCount   = 1;
1371    capEncoderSupportData1.pResolutionList        = &pD3D12Enc->m_currentEncodeConfig.m_currentResolution;
1372    capEncoderSupportData1.CodecGopSequence       = d3d12_video_encoder_get_current_gop_desc(pD3D12Enc);
1373    capEncoderSupportData1.MaxReferenceFramesInDPB =
1374       std::max(2u, d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc)) - 1u; // we only want the number of references (not the current pic slot too)
1375    capEncoderSupportData1.CodecConfiguration = d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc);
1376 
1377    enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
1378    switch (codec) {
1379 #if VIDEO_CODEC_H264ENC
1380       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
1381       {
1382          capEncoderSupportData1.SuggestedProfile.pH264Profile =
1383             &pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_H264Profile;
1384          capEncoderSupportData1.SuggestedProfile.DataSize =
1385             sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_H264Profile);
1386          capEncoderSupportData1.SuggestedLevel.pH264LevelSetting =
1387             &pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_H264LevelSetting;
1388          capEncoderSupportData1.SuggestedLevel.DataSize =
1389             sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_H264LevelSetting);
1390       } break;
1391 #endif
1392 #if VIDEO_CODEC_H265ENC
1393       case PIPE_VIDEO_FORMAT_HEVC:
1394       {
1395          capEncoderSupportData1.SuggestedProfile.pHEVCProfile =
1396             &pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_HEVCProfile;
1397          capEncoderSupportData1.SuggestedProfile.DataSize =
1398             sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_HEVCProfile);
1399          capEncoderSupportData1.SuggestedLevel.pHEVCLevelSetting =
1400             &pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting;
1401          capEncoderSupportData1.SuggestedLevel.DataSize =
1402             sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_HEVCLevelSetting);
1403       } break;
1404 #endif
1405 #if VIDEO_CODEC_AV1ENC
1406       case PIPE_VIDEO_FORMAT_AV1:
1407       {
1408          capEncoderSupportData1.SuggestedProfile.pAV1Profile =
1409             &pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_AV1Profile;
1410          capEncoderSupportData1.SuggestedProfile.DataSize =
1411             sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_AV1Profile);
1412          capEncoderSupportData1.SuggestedLevel.pAV1LevelSetting =
1413             &pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_AV1LevelSetting;
1414          capEncoderSupportData1.SuggestedLevel.DataSize =
1415             sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_AV1LevelSetting);
1416       } break;
1417 #endif
1418       default:
1419       {
1420          unreachable("Unsupported pipe_video_format");
1421       } break;
1422    }
1423 
1424    // prepare inout storage for the resolution dependent result.
1425    capEncoderSupportData1.pResolutionDependentSupport =
1426       &pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps;
1427 
1428    capEncoderSupportData1.SubregionFrameEncodingData = d3d12_video_encoder_get_current_slice_param_settings(pD3D12Enc);
1429    HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1,
1430                                                                          &capEncoderSupportData1,
1431                                                                          sizeof(capEncoderSupportData1));
1432    if (FAILED(hr)) {
1433       debug_printf("CheckFeatureSupport D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1 failed with HR %x\n", hr);
1434       debug_printf("Falling back to check previous query version D3D12_FEATURE_VIDEO_ENCODER_SUPPORT...\n");
1435 
1436       // D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 extends D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT
1437       // in a binary compatible way, so just cast it and try with the older query D3D12_FEATURE_VIDEO_ENCODER_SUPPORT
1438       D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT * casted_down_cap_data = reinterpret_cast<D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT*>(&capEncoderSupportData1);
1439 
1440       //
1441       // Remove legacy query parameters for features not supported in older OS when using older OS support query
1442       // since the D3D12 older runtime will not recognize the new flags and structures
1443       // Update both encoder current config and re-generate support cap rate control input
1444       //
1445       pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc
1446          [pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Flags &= ~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENSION1_SUPPORT;
1447 
1448       d3d12_video_encoder_disable_rc_qualitylevels(
1449             pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex]);
1450 
1451       capEncoderSupportData1.RateControl = d3d12_video_encoder_get_current_rate_control_settings(pD3D12Enc);
1452 
1453       hr = pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_SUPPORT,
1454                                                                          casted_down_cap_data,
1455                                                                          sizeof(D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT));
1456       if (FAILED(hr)) {
1457          debug_printf("CheckFeatureSupport D3D12_FEATURE_VIDEO_ENCODER_SUPPORT failed with HR %x\n", hr);
1458          return false;
1459       }
1460    }
1461 
1462    // Workaround for drivers supporting rate control reconfiguration but not reporting it
1463    // and having issues with encoder state/heap objects recreation
1464    if (pD3D12Enc->m_pD3D12Screen->vendor_id == 0x8086 /* HW_VENDOR_INTEL */) {
1465       // If IHV driver doesn't report reconfiguration, force doing the reconfiguration without object recreation
1466       if ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_RECONFIGURATION_AVAILABLE) == 0) {
1467          pD3D12Enc->driver_workarounds |= d3d12_video_encoder_driver_workaround_rate_control_reconfig;
1468          capEncoderSupportData1.SupportFlags |= D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_RECONFIGURATION_AVAILABLE;
1469       }
1470    }
1471 
1472    pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags    = capEncoderSupportData1.SupportFlags;
1473    pD3D12Enc->m_currentEncodeCapabilities.m_ValidationFlags = capEncoderSupportData1.ValidationFlags;
1474    return true;
1475 }
1476 
d3d12_video_encoder_check_subregion_mode_support(struct d3d12_video_encoder * pD3D12Enc,D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedSlicesMode)1477 bool d3d12_video_encoder_check_subregion_mode_support(struct d3d12_video_encoder *pD3D12Enc,
1478                                     D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedSlicesMode
1479    )
1480 {
1481    D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE capDataSubregionLayout = { };
1482    capDataSubregionLayout.NodeIndex = pD3D12Enc->m_NodeIndex;
1483    capDataSubregionLayout.Codec = d3d12_video_encoder_get_current_codec(pD3D12Enc);
1484    capDataSubregionLayout.Profile = d3d12_video_encoder_get_current_profile_desc(pD3D12Enc);
1485    capDataSubregionLayout.Level = d3d12_video_encoder_get_current_level_desc(pD3D12Enc);
1486    capDataSubregionLayout.SubregionMode = requestedSlicesMode;
1487    HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE, &capDataSubregionLayout, sizeof(capDataSubregionLayout));
1488    if (FAILED(hr)) {
1489       debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
1490       return false;
1491    }
1492    return capDataSubregionLayout.IsSupported;
1493 }
1494 
1495 D3D12_VIDEO_ENCODER_PROFILE_DESC
d3d12_video_encoder_get_current_profile_desc(struct d3d12_video_encoder * pD3D12Enc)1496 d3d12_video_encoder_get_current_profile_desc(struct d3d12_video_encoder *pD3D12Enc)
1497 {
1498    enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
1499    switch (codec) {
1500 #if VIDEO_CODEC_H264ENC
1501       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
1502       {
1503          D3D12_VIDEO_ENCODER_PROFILE_DESC curProfDesc = {};
1504          curProfDesc.pH264Profile = &pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile;
1505          curProfDesc.DataSize     = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile);
1506          return curProfDesc;
1507       } break;
1508 #endif
1509 #if VIDEO_CODEC_H265ENC
1510       case PIPE_VIDEO_FORMAT_HEVC:
1511       {
1512          D3D12_VIDEO_ENCODER_PROFILE_DESC curProfDesc = {};
1513          curProfDesc.pHEVCProfile = &pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile;
1514          curProfDesc.DataSize     = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_HEVCProfile);
1515          return curProfDesc;
1516       } break;
1517 #endif
1518 #if VIDEO_CODEC_AV1ENC
1519       case PIPE_VIDEO_FORMAT_AV1:
1520       {
1521          D3D12_VIDEO_ENCODER_PROFILE_DESC curProfDesc = {};
1522          curProfDesc.pAV1Profile = &pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_AV1Profile;
1523          curProfDesc.DataSize     = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_AV1Profile);
1524          return curProfDesc;
1525       } break;
1526 #endif
1527       default:
1528       {
1529          unreachable("Unsupported pipe_video_format");
1530       } break;
1531    }
1532 }
1533 
1534 uint32_t
d3d12_video_encoder_get_current_max_dpb_capacity(struct d3d12_video_encoder * pD3D12Enc)1535 d3d12_video_encoder_get_current_max_dpb_capacity(struct d3d12_video_encoder *pD3D12Enc)
1536 {
1537    enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
1538    switch (codec) {
1539 #if VIDEO_CODEC_H264ENC
1540       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
1541       {
1542          return PIPE_H264_MAX_REFERENCES + 1u /* current frame reconstructed picture */;
1543       } break;
1544 #endif
1545 #if VIDEO_CODEC_H265ENC
1546       case PIPE_VIDEO_FORMAT_HEVC:
1547       {
1548          return PIPE_H265_MAX_REFERENCES + 1u /* current frame reconstructed picture */;
1549       } break;
1550 #endif
1551 #if VIDEO_CODEC_AV1ENC
1552       case PIPE_VIDEO_FORMAT_AV1:
1553       {
1554          return PIPE_AV1_MAX_REFERENCES + 1u /* current frame reconstructed picture */;
1555       } break;
1556 #endif
1557       default:
1558       {
1559          unreachable("Unsupported pipe_video_format");
1560       } break;
1561    }
1562 }
1563 
1564 bool
d3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encoder * pD3D12Enc,D3D12_VIDEO_SAMPLE srcTextureDesc,struct pipe_picture_desc * picture)1565 d3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encoder *pD3D12Enc,
1566                                                         D3D12_VIDEO_SAMPLE srcTextureDesc,
1567                                                         struct pipe_picture_desc *  picture)
1568 {
1569    pD3D12Enc->m_prevFrameEncodeConfig = pD3D12Enc->m_currentEncodeConfig;
1570 
1571    enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
1572    switch (codec) {
1573 #if VIDEO_CODEC_H264ENC
1574       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
1575       {
1576          return d3d12_video_encoder_update_current_encoder_config_state_h264(pD3D12Enc, srcTextureDesc, picture);
1577       } break;
1578 #endif
1579 #if VIDEO_CODEC_H265ENC
1580       case PIPE_VIDEO_FORMAT_HEVC:
1581       {
1582          return d3d12_video_encoder_update_current_encoder_config_state_hevc(pD3D12Enc, srcTextureDesc, picture);
1583       } break;
1584 #endif
1585 #if VIDEO_CODEC_AV1ENC
1586       case PIPE_VIDEO_FORMAT_AV1:
1587       {
1588          return d3d12_video_encoder_update_current_encoder_config_state_av1(pD3D12Enc, srcTextureDesc, picture);
1589       } break;
1590 #endif
1591       default:
1592       {
1593          unreachable("Unsupported pipe_video_format");
1594       } break;
1595    }
1596 }
1597 
1598 bool
d3d12_video_encoder_create_command_objects(struct d3d12_video_encoder * pD3D12Enc)1599 d3d12_video_encoder_create_command_objects(struct d3d12_video_encoder *pD3D12Enc)
1600 {
1601    assert(pD3D12Enc->m_spD3D12VideoDevice);
1602 
1603    D3D12_COMMAND_QUEUE_DESC commandQueueDesc = { D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE };
1604    HRESULT                  hr               = pD3D12Enc->m_pD3D12Screen->dev->CreateCommandQueue(
1605       &commandQueueDesc,
1606       IID_PPV_ARGS(pD3D12Enc->m_spEncodeCommandQueue.GetAddressOf()));
1607    if (FAILED(hr)) {
1608       debug_printf("[d3d12_video_encoder] d3d12_video_encoder_create_command_objects - Call to CreateCommandQueue "
1609                       "failed with HR %x\n",
1610                       hr);
1611       return false;
1612    }
1613 
1614    hr = pD3D12Enc->m_pD3D12Screen->dev->CreateFence(0, D3D12_FENCE_FLAG_SHARED, IID_PPV_ARGS(&pD3D12Enc->m_spFence));
1615    if (FAILED(hr)) {
1616       debug_printf(
1617          "[d3d12_video_encoder] d3d12_video_encoder_create_command_objects - Call to CreateFence failed with HR %x\n",
1618          hr);
1619       return false;
1620    }
1621 
1622    for (auto& inputResource : pD3D12Enc->m_inflightResourcesPool)
1623    {
1624       // Create associated command allocator for Encode, Resolve operations
1625       hr = pD3D12Enc->m_pD3D12Screen->dev->CreateCommandAllocator(
1626          D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE,
1627          IID_PPV_ARGS(inputResource.m_spCommandAllocator.GetAddressOf()));
1628       if (FAILED(hr)) {
1629          debug_printf("[d3d12_video_encoder] d3d12_video_encoder_create_command_objects - Call to "
1630                         "CreateCommandAllocator failed with HR %x\n",
1631                         hr);
1632          return false;
1633       }
1634    }
1635 
1636    ComPtr<ID3D12Device4> spD3D12Device4;
1637    if (FAILED(pD3D12Enc->m_pD3D12Screen->dev->QueryInterface(
1638           IID_PPV_ARGS(spD3D12Device4.GetAddressOf())))) {
1639       debug_printf(
1640          "[d3d12_video_encoder] d3d12_video_encoder_create_encoder - D3D12 Device has no Video encode support\n");
1641       return false;
1642    }
1643 
1644    hr = spD3D12Device4->CreateCommandList1(0,
1645                         D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE,
1646                         D3D12_COMMAND_LIST_FLAG_NONE,
1647                         IID_PPV_ARGS(pD3D12Enc->m_spEncodeCommandList.GetAddressOf()));
1648 
1649    if (FAILED(hr)) {
1650       debug_printf("[d3d12_video_encoder] d3d12_video_encoder_create_command_objects - Call to CreateCommandList "
1651                       "failed with HR %x\n",
1652                       hr);
1653       return false;
1654    }
1655 
1656    return true;
1657 }
1658 
1659 static inline void
d3d12_video_encoder_reallocate_prefix_nal_buffer(struct d3d12_video_encoder * pD3D12Enc,pipe_resource ** out_buffer,uint32_t byte_size)1660 d3d12_video_encoder_reallocate_prefix_nal_buffer(struct d3d12_video_encoder *pD3D12Enc,
1661                                                  pipe_resource** out_buffer,
1662                                                  uint32_t byte_size)
1663 {
1664    if (*out_buffer != NULL)
1665    {
1666       debug_printf("[d3d12_video_encoder_reallocate_prefix_nal_buffer] Destroying existing buffer at address: 0x%p byte size: %d\n", *out_buffer, (*out_buffer)->width0);
1667       pD3D12Enc->m_screen->resource_destroy(pD3D12Enc->m_screen, *out_buffer);
1668       *out_buffer = NULL;
1669    }
1670 
1671    struct pipe_resource templ = { };
1672    memset(&templ, 0, sizeof(templ));
1673    templ.target = PIPE_BUFFER;
1674    templ.usage = PIPE_USAGE_DEFAULT;
1675    templ.format = PIPE_FORMAT_R8_UINT;
1676    templ.width0 = byte_size;
1677    templ.height0 = 1;
1678    templ.depth0 = 1;
1679    templ.array_size = 1;
1680    *out_buffer = pD3D12Enc->m_screen->resource_create(pD3D12Enc->m_screen, &templ);
1681    assert(*out_buffer);
1682    debug_printf("[d3d12_video_encoder_reallocate_prefix_nal_buffer] Created new buffer at address: 0x%p byte size: %d\n", *out_buffer, (*out_buffer)->width0);
1683 }
1684 
1685 struct pipe_video_codec *
d3d12_video_encoder_create_encoder(struct pipe_context * context,const struct pipe_video_codec * codec)1686 d3d12_video_encoder_create_encoder(struct pipe_context *context, const struct pipe_video_codec *codec)
1687 {
1688    ///
1689    /// Initialize d3d12_video_encoder
1690    ///
1691 
1692    // Not using new doesn't call ctor and the initializations in the class declaration are lost
1693    struct d3d12_video_encoder *pD3D12Enc = new d3d12_video_encoder;
1694 
1695    pD3D12Enc->m_spEncodedFrameMetadata.resize(D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT, {nullptr, 0, 0});
1696    pD3D12Enc->m_inflightResourcesPool.resize(D3D12_VIDEO_ENC_ASYNC_DEPTH, { 0 });
1697 
1698    pD3D12Enc->base         = *codec;
1699    pD3D12Enc->m_screen     = context->screen;
1700    pD3D12Enc->base.context = context;
1701    pD3D12Enc->base.width   = codec->width;
1702    pD3D12Enc->base.height  = codec->height;
1703    pD3D12Enc->base.max_references  = codec->max_references;
1704    // Only fill methods that are supported by the d3d12 encoder, leaving null the rest (ie. encode_* / encode_macroblock)
1705    pD3D12Enc->base.destroy          = d3d12_video_encoder_destroy;
1706    pD3D12Enc->base.begin_frame      = d3d12_video_encoder_begin_frame;
1707    pD3D12Enc->base.encode_bitstream = d3d12_video_encoder_encode_bitstream;
1708    pD3D12Enc->base.end_frame        = d3d12_video_encoder_end_frame;
1709    pD3D12Enc->base.flush            = d3d12_video_encoder_flush;
1710    pD3D12Enc->base.get_encode_headers = d3d12_video_encoder_get_encode_headers;
1711    pD3D12Enc->base.get_feedback     = d3d12_video_encoder_get_feedback;
1712    pD3D12Enc->base.create_dpb_buffer = d3d12_video_create_dpb_buffer;
1713    pD3D12Enc->base.fence_wait       = d3d12_video_encoder_fence_wait;
1714 
1715    struct d3d12_context *pD3D12Ctx = (struct d3d12_context *) context;
1716    pD3D12Enc->m_pD3D12Screen       = d3d12_screen(pD3D12Ctx->base.screen);
1717 
1718    if (FAILED(pD3D12Enc->m_pD3D12Screen->dev->QueryInterface(
1719           IID_PPV_ARGS(pD3D12Enc->m_spD3D12VideoDevice.GetAddressOf())))) {
1720       debug_printf(
1721          "[d3d12_video_encoder] d3d12_video_encoder_create_encoder - D3D12 Device has no Video encode support\n");
1722       goto failed;
1723    }
1724 
1725    if (!d3d12_video_encoder_create_command_objects(pD3D12Enc)) {
1726       debug_printf("[d3d12_video_encoder] d3d12_video_encoder_create_encoder - Failure on "
1727                       "d3d12_video_encoder_create_command_objects\n");
1728       goto failed;
1729    }
1730 
1731    // Cache quality levels cap
1732    pD3D12Enc->max_quality_levels = context->screen->get_video_param(context->screen, codec->profile,
1733                                     codec->entrypoint,
1734                                     PIPE_VIDEO_CAP_ENC_QUALITY_LEVEL);
1735 
1736    return &pD3D12Enc->base;
1737 
1738 failed:
1739    if (pD3D12Enc != nullptr) {
1740       d3d12_video_encoder_destroy((struct pipe_video_codec *) pD3D12Enc);
1741    }
1742 
1743    return nullptr;
1744 }
1745 
1746 bool
d3d12_video_encoder_prepare_output_buffers(struct d3d12_video_encoder * pD3D12Enc,struct pipe_video_buffer * srcTexture,struct pipe_picture_desc * picture)1747 d3d12_video_encoder_prepare_output_buffers(struct d3d12_video_encoder *pD3D12Enc,
1748                                            struct pipe_video_buffer *  srcTexture,
1749                                            struct pipe_picture_desc *  picture)
1750 {
1751    pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.NodeIndex = pD3D12Enc->m_NodeIndex;
1752    pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.Codec =
1753       pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc;
1754    pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.Profile =
1755       d3d12_video_encoder_get_current_profile_desc(pD3D12Enc);
1756    pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.InputFormat =
1757       pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format;
1758    pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.PictureTargetResolution =
1759       pD3D12Enc->m_currentEncodeConfig.m_currentResolution;
1760 
1761    HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(
1762       D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS,
1763       &pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps,
1764       sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps));
1765 
1766    if (FAILED(hr)) {
1767       debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
1768       return false;
1769    }
1770 
1771    if (!pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.IsSupported) {
1772       debug_printf("[d3d12_video_encoder] D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS arguments are not supported.\n");
1773       return false;
1774    }
1775 
1776    size_t current_metadata_slot = d3d12_video_encoder_metadata_current_index(pD3D12Enc);
1777 
1778    enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
1779    d3d12_video_encoder_calculate_metadata_resolved_buffer_size(
1780       codec,
1781       pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput,
1782       pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].bufferSize);
1783 
1784    D3D12_HEAP_PROPERTIES Properties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
1785    if ((pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].spBuffer == nullptr) ||
1786        (GetDesc(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].spBuffer.Get()).Width <
1787         pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].bufferSize)) {
1788       CD3DX12_RESOURCE_DESC resolvedMetadataBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(
1789          pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].bufferSize);
1790 
1791       pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].spBuffer.Reset();
1792       HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CreateCommittedResource(
1793          &Properties,
1794          D3D12_HEAP_FLAG_NONE,
1795          &resolvedMetadataBufferDesc,
1796          D3D12_RESOURCE_STATE_COMMON,
1797          nullptr,
1798          IID_PPV_ARGS(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].spBuffer.GetAddressOf()));
1799 
1800       if (FAILED(hr)) {
1801          debug_printf("CreateCommittedResource failed with HR %x\n", hr);
1802          return false;
1803       }
1804    }
1805 
1806    if ((pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_spMetadataOutputBuffer == nullptr) ||
1807        (GetDesc(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_spMetadataOutputBuffer.Get()).Width <
1808         pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.MaxEncoderOutputMetadataBufferSize)) {
1809       CD3DX12_RESOURCE_DESC metadataBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(
1810          pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.MaxEncoderOutputMetadataBufferSize);
1811 
1812       pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_spMetadataOutputBuffer.Reset();
1813       HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CreateCommittedResource(
1814          &Properties,
1815          D3D12_HEAP_FLAG_NONE,
1816          &metadataBufferDesc,
1817          D3D12_RESOURCE_STATE_COMMON,
1818          nullptr,
1819          IID_PPV_ARGS(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_spMetadataOutputBuffer.GetAddressOf()));
1820 
1821       if (FAILED(hr)) {
1822          debug_printf("CreateCommittedResource failed with HR %x\n", hr);
1823          return false;
1824       }
1825    }
1826    return true;
1827 }
1828 
1829 bool
d3d12_video_encoder_reconfigure_session(struct d3d12_video_encoder * pD3D12Enc,struct pipe_video_buffer * srcTexture,struct pipe_picture_desc * picture)1830 d3d12_video_encoder_reconfigure_session(struct d3d12_video_encoder *pD3D12Enc,
1831                                         struct pipe_video_buffer *  srcTexture,
1832                                         struct pipe_picture_desc *  picture)
1833 {
1834    assert(pD3D12Enc->m_spD3D12VideoDevice);
1835    D3D12_VIDEO_SAMPLE srcTextureDesc = {};
1836    srcTextureDesc.Width = srcTexture->width;
1837    srcTextureDesc.Height = srcTexture->height;
1838    srcTextureDesc.Format.Format = d3d12_get_format(srcTexture->buffer_format);
1839    if(!d3d12_video_encoder_update_current_encoder_config_state(pD3D12Enc, srcTextureDesc, picture)) {
1840       debug_printf("d3d12_video_encoder_update_current_encoder_config_state failed!\n");
1841       return false;
1842    }
1843    if(!d3d12_video_encoder_reconfigure_encoder_objects(pD3D12Enc, srcTexture, picture)) {
1844       debug_printf("d3d12_video_encoder_reconfigure_encoder_objects failed!\n");
1845       return false;
1846    }
1847    d3d12_video_encoder_update_picparams_tracking(pD3D12Enc, srcTexture, picture);
1848    if(!d3d12_video_encoder_prepare_output_buffers(pD3D12Enc, srcTexture, picture)) {
1849       debug_printf("d3d12_video_encoder_prepare_output_buffers failed!\n");
1850       return false;
1851    }
1852 
1853    // Save frame size expectation snapshot from record time to resolve at get_feedback time (after execution)
1854    size_t current_metadata_slot = d3d12_video_encoder_metadata_current_index(pD3D12Enc);
1855    pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].expected_max_frame_size =
1856       pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].max_frame_size;
1857 
1858    pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].expected_max_slice_size =
1859       (pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode == D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION) ?
1860       pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_H264.MaxBytesPerSlice : 0;
1861 
1862    return true;
1863 }
1864 
1865 /**
1866  * start encoding of a new frame
1867  */
1868 void
d3d12_video_encoder_begin_frame(struct pipe_video_codec * codec,struct pipe_video_buffer * target,struct pipe_picture_desc * picture)1869 d3d12_video_encoder_begin_frame(struct pipe_video_codec * codec,
1870                                 struct pipe_video_buffer *target,
1871                                 struct pipe_picture_desc *picture)
1872 {
1873    // Do nothing here. Initialize happens on encoder creation, re-config (if any) happens in
1874    // d3d12_video_encoder_encode_bitstream
1875    struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
1876    assert(pD3D12Enc);
1877    HRESULT hr = S_OK;
1878    debug_printf("[d3d12_video_encoder] d3d12_video_encoder_begin_frame started for fenceValue: %" PRIu64 "\n",
1879                  pD3D12Enc->m_fenceValue);
1880 
1881    ///
1882    /// Wait here to make sure the next in flight resource set is empty before using it
1883    ///
1884    uint64_t fenceValueToWaitOn = static_cast<uint64_t>(std::max(static_cast<int64_t>(0l), static_cast<int64_t>(pD3D12Enc->m_fenceValue) - static_cast<int64_t>(D3D12_VIDEO_ENC_ASYNC_DEPTH) ));
1885 
1886    debug_printf("[d3d12_video_encoder] d3d12_video_encoder_begin_frame Waiting for completion of in flight resource sets with previous work with fenceValue: %" PRIu64 "\n",
1887                  fenceValueToWaitOn);
1888 
1889    d3d12_video_encoder_ensure_fence_finished(codec, pD3D12Enc->m_spFence.Get(), fenceValueToWaitOn, OS_TIMEOUT_INFINITE);
1890 
1891    if (!d3d12_video_encoder_reconfigure_session(pD3D12Enc, target, picture)) {
1892       debug_printf("[d3d12_video_encoder] d3d12_video_encoder_begin_frame - Failure on "
1893                       "d3d12_video_encoder_reconfigure_session\n");
1894       goto fail;
1895    }
1896 
1897    hr = pD3D12Enc->m_spEncodeCommandList->Reset(pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_spCommandAllocator.Get());
1898    if (FAILED(hr)) {
1899       debug_printf(
1900          "[d3d12_video_encoder] d3d12_video_encoder_flush - resetting ID3D12GraphicsCommandList failed with HR %x\n",
1901          hr);
1902       goto fail;
1903    }
1904 
1905    pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_InputSurfaceFence = (struct d3d12_fence*) *picture->fence;
1906    pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_OK;
1907    pD3D12Enc->m_spEncodedFrameMetadata[d3d12_video_encoder_metadata_current_index(pD3D12Enc)].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_OK;
1908 
1909    debug_printf("[d3d12_video_encoder] d3d12_video_encoder_begin_frame finalized for fenceValue: %" PRIu64 "\n",
1910                  pD3D12Enc->m_fenceValue);
1911    return;
1912 
1913 fail:
1914    debug_printf("[d3d12_video_encoder] d3d12_video_encoder_begin_frame failed for fenceValue: %" PRIu64 "\n",
1915                 pD3D12Enc->m_fenceValue);
1916    pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
1917    pD3D12Enc->m_spEncodedFrameMetadata[d3d12_video_encoder_metadata_current_index(pD3D12Enc)].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
1918    assert(false);
1919 }
1920 
1921 void
d3d12_video_encoder_calculate_metadata_resolved_buffer_size(enum pipe_video_format codec,uint32_t maxSliceNumber,uint64_t & bufferSize)1922 d3d12_video_encoder_calculate_metadata_resolved_buffer_size(enum pipe_video_format codec, uint32_t maxSliceNumber, uint64_t &bufferSize)
1923 {
1924    bufferSize = sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA) +
1925                 (maxSliceNumber * sizeof(D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA));
1926 
1927    switch (codec) {
1928 #if VIDEO_CODEC_H264ENC
1929       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
1930          break;
1931 #endif
1932 #if VIDEO_CODEC_H265ENC
1933       case PIPE_VIDEO_FORMAT_HEVC:
1934          break;
1935 #endif
1936 #if VIDEO_CODEC_AV1ENC
1937       case PIPE_VIDEO_FORMAT_AV1:
1938       {
1939          size_t extra_av1_size = d3d12_video_encoder_calculate_metadata_resolved_buffer_size_av1(maxSliceNumber);
1940          bufferSize += extra_av1_size;
1941       } break;
1942 #endif
1943       default:
1944       {
1945          unreachable("Unsupported pipe_video_format");
1946       } break;
1947    }
1948 }
1949 
1950 // Returns the number of slices that the output will contain for fixed slicing modes
1951 // and the maximum number of slices the output might contain for dynamic slicing modes (eg. max bytes per slice)
1952 uint32_t
d3d12_video_encoder_calculate_max_slices_count_in_output(D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE slicesMode,const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES * slicesConfig,uint32_t MaxSubregionsNumberFromCaps,D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC sequenceTargetResolution,uint32_t SubregionBlockPixelsSize)1953 d3d12_video_encoder_calculate_max_slices_count_in_output(
1954    D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE                          slicesMode,
1955    const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES *slicesConfig,
1956    uint32_t                                                                 MaxSubregionsNumberFromCaps,
1957    D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC                              sequenceTargetResolution,
1958    uint32_t                                                                 SubregionBlockPixelsSize)
1959 {
1960    uint32_t pic_width_in_subregion_units =
1961       static_cast<uint32_t>(std::ceil(sequenceTargetResolution.Width / static_cast<double>(SubregionBlockPixelsSize)));
1962    uint32_t pic_height_in_subregion_units =
1963       static_cast<uint32_t>(std::ceil(sequenceTargetResolution.Height / static_cast<double>(SubregionBlockPixelsSize)));
1964    uint32_t total_picture_subregion_units = pic_width_in_subregion_units * pic_height_in_subregion_units;
1965    uint32_t maxSlices                     = 0u;
1966    switch (slicesMode) {
1967       case D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME:
1968       {
1969          maxSlices = 1u;
1970       } break;
1971       case D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION:
1972       {
1973          maxSlices = MaxSubregionsNumberFromCaps;
1974       } break;
1975       case D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED:
1976       {
1977          maxSlices = static_cast<uint32_t>(
1978             std::ceil(total_picture_subregion_units / static_cast<double>(slicesConfig->NumberOfCodingUnitsPerSlice)));
1979       } break;
1980       case D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION:
1981       {
1982          maxSlices = static_cast<uint32_t>(
1983             std::ceil(pic_height_in_subregion_units / static_cast<double>(slicesConfig->NumberOfRowsPerSlice)));
1984       } break;
1985       case D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME:
1986       {
1987          maxSlices = slicesConfig->NumberOfSlicesPerFrame;
1988       } break;
1989       default:
1990       {
1991          unreachable("Unsupported D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE");
1992       } break;
1993    }
1994 
1995    return maxSlices;
1996 }
1997 
1998 /**
1999  * encode a bitstream
2000  */
2001 void
d3d12_video_encoder_encode_bitstream(struct pipe_video_codec * codec,struct pipe_video_buffer * source,struct pipe_resource * destination,void ** feedback)2002 d3d12_video_encoder_encode_bitstream(struct pipe_video_codec * codec,
2003                                      struct pipe_video_buffer *source,
2004                                      struct pipe_resource *    destination,
2005                                      void **                   feedback)
2006 {
2007    struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
2008    assert(pD3D12Enc);
2009    debug_printf("[d3d12_video_encoder] d3d12_video_encoder_encode_bitstream started for fenceValue: %" PRIu64 "\n",
2010                  pD3D12Enc->m_fenceValue);
2011    assert(pD3D12Enc->m_spD3D12VideoDevice);
2012    assert(pD3D12Enc->m_spEncodeCommandQueue);
2013    assert(pD3D12Enc->m_pD3D12Screen);
2014 
2015    if (pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].encode_result & PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED) {
2016       debug_printf("WARNING: [d3d12_video_encoder] d3d12_video_encoder_encode_bitstream - Frame submission %" PRIu64 " failed. Encoder lost, please recreate pipe_video_codec object\n", pD3D12Enc->m_fenceValue);
2017       assert(false);
2018       return;
2019    }
2020 
2021    struct d3d12_video_buffer *pInputVideoBuffer = (struct d3d12_video_buffer *) source;
2022    assert(pInputVideoBuffer);
2023    ID3D12Resource *pInputVideoD3D12Res        = d3d12_resource_resource(pInputVideoBuffer->texture);
2024    uint32_t        inputVideoD3D12Subresource = 0u;
2025 
2026    struct d3d12_resource *pOutputBitstreamBuffer = (struct d3d12_resource *) destination;
2027 
2028    // Make them permanently resident for video use
2029    d3d12_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, pOutputBitstreamBuffer);
2030    d3d12_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, pInputVideoBuffer->texture);
2031 
2032    size_t current_metadata_slot = d3d12_video_encoder_metadata_current_index(pD3D12Enc);
2033 
2034    /* Warning if the previous finished async execution stored was read not by get_feedback()
2035       before overwriting. This should be handled correctly by the app by calling vaSyncBuffer/vaSyncSurface
2036       without having the async depth going beyond D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT frames without syncing */
2037    if(!pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].bRead) {
2038       debug_printf("WARNING: [d3d12_video_encoder] d3d12_video_encoder_encode_bitstream - overwriting metadata slot %" PRIu64 " before calling get_feedback", static_cast<uint64_t>(current_metadata_slot));
2039       assert(false);
2040    }
2041    pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].bRead = false;
2042 
2043    ///
2044    /// Record Encode operation
2045    ///
2046 
2047    ///
2048    /// pInputVideoBuffer and pOutputBitstreamBuffer are passed externally
2049    /// and could be tracked by pipe_context and have pending ops. Flush any work on them and transition to
2050    /// D3D12_RESOURCE_STATE_COMMON before issuing work in Video command queue below. After the video work is done in the
2051    /// GPU, transition back to D3D12_RESOURCE_STATE_COMMON
2052    ///
2053    /// Note that unlike the D3D12TranslationLayer codebase, the state tracker here doesn't (yet) have any kind of
2054    /// multi-queue support, so it wouldn't implicitly synchronize when trying to transition between a graphics op and a
2055    /// video op.
2056    ///
2057 
2058    d3d12_transition_resource_state(
2059       d3d12_context(pD3D12Enc->base.context),
2060       pInputVideoBuffer->texture,
2061       D3D12_RESOURCE_STATE_COMMON,
2062       D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
2063    d3d12_transition_resource_state(d3d12_context(pD3D12Enc->base.context),
2064                                    pOutputBitstreamBuffer,
2065                                    D3D12_RESOURCE_STATE_COMMON,
2066                                    D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
2067    d3d12_apply_resource_states(d3d12_context(pD3D12Enc->base.context), false);
2068 
2069    d3d12_resource_wait_idle(d3d12_context(pD3D12Enc->base.context),
2070                             pInputVideoBuffer->texture,
2071                             false /*wantToWrite*/);
2072    d3d12_resource_wait_idle(d3d12_context(pD3D12Enc->base.context), pOutputBitstreamBuffer, true /*wantToWrite*/);
2073 
2074    ///
2075    /// Process pre-encode bitstream headers
2076    ///
2077 
2078    // Decide the D3D12 buffer EncodeFrame will write to based on pre-post encode headers generation policy
2079    ID3D12Resource *pOutputBufferD3D12Res = nullptr;
2080 
2081    d3d12_video_encoder_build_pre_encode_codec_headers(pD3D12Enc,
2082                                                       pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].postEncodeHeadersNeeded,
2083                                                       pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize,
2084                                                       pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].pWrittenCodecUnitsSizes);
2085    assert(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize == pD3D12Enc->m_BitstreamHeadersBuffer.size());
2086    pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersBytePadding = 0;
2087 
2088    // Save the pipe destination buffer the headers need to be written to in get_feedback if post encode headers needed or H264 SVC NAL prefixes, etc
2089    pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].comp_bit_destination = &pOutputBitstreamBuffer->base.b;
2090 
2091    // Only upload headers now and leave prefix offset space gap in compressed bitstream if the codec builds headers before execution.
2092    if (!pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].postEncodeHeadersNeeded)
2093    {
2094 
2095       // Headers are written before encode execution, have EncodeFrame write directly into the pipe destination buffer
2096       pOutputBufferD3D12Res = d3d12_resource_resource(pOutputBitstreamBuffer);
2097 
2098       // It can happen that codecs like H264/HEVC don't write pre-headers for all frames (ie. reuse previous PPS)
2099       if (pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize > 0)
2100       {
2101          // If driver needs offset alignment for bitstream resource, we will pad zeroes on the codec header to this end.
2102          if (
2103             (pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.CompressedBitstreamBufferAccessAlignment > 1)
2104             && ((pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize % pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.CompressedBitstreamBufferAccessAlignment) != 0)
2105          ) {
2106             uint64_t new_size = align64(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize, pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.CompressedBitstreamBufferAccessAlignment);
2107             pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersBytePadding = new_size - pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize;
2108             pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize = new_size;
2109             pD3D12Enc->m_BitstreamHeadersBuffer.resize(static_cast<size_t>(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize), 0);
2110          }
2111 
2112          // Upload the CPU buffers with the bitstream headers to the compressed bitstream resource in the interval
2113          // [0..pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize)
2114          // Note: The buffer_subdata is queued in pD3D12Enc->base.context but doesn't execute immediately
2115          // Will flush and sync this batch in d3d12_video_encoder_flush with the rest of the Video Encode Queue GPU work
2116 
2117          pD3D12Enc->base.context->buffer_subdata(
2118             pD3D12Enc->base.context,         // context
2119             &pOutputBitstreamBuffer->base.b, // dst buffer
2120             PIPE_MAP_WRITE,                  // usage PIPE_MAP_x
2121             0,                               // offset
2122             static_cast<unsigned int>(pD3D12Enc->m_BitstreamHeadersBuffer.size()),
2123             pD3D12Enc->m_BitstreamHeadersBuffer.data());
2124       }
2125    }
2126    else
2127    {
2128       assert(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize == 0);
2129       if (pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].spStagingBitstream == nullptr) {
2130          D3D12_HEAP_PROPERTIES Properties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
2131          CD3DX12_RESOURCE_DESC resolvedMetadataBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(D3D12_DEFAULT_COMPBIT_STAGING_SIZE);
2132          HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CreateCommittedResource(
2133             &Properties,
2134             D3D12_HEAP_FLAG_NONE,
2135             &resolvedMetadataBufferDesc,
2136             D3D12_RESOURCE_STATE_COMMON,
2137             nullptr,
2138             IID_PPV_ARGS(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].spStagingBitstream.GetAddressOf()));
2139 
2140          if (FAILED(hr)) {
2141             debug_printf("CreateCommittedResource failed with HR %x\n", hr);
2142             pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
2143             pD3D12Enc->m_spEncodedFrameMetadata[d3d12_video_encoder_metadata_current_index(pD3D12Enc)].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
2144             assert(false);
2145             return;
2146          }
2147       }
2148 
2149       // Headers are written after execution, have EncodeFrame write into a staging buffer
2150       // and then get_feedback will pack the finalized bitstream and copy into comp_bit_destination
2151       pOutputBufferD3D12Res = pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].spStagingBitstream.Get();
2152    }
2153 
2154    memset(&pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_FenceData,
2155             0,
2156             sizeof(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_FenceData));
2157    pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_FenceData.value = pD3D12Enc->m_fenceValue;
2158    pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_FenceData.cmdqueue_fence = pD3D12Enc->m_spFence.Get();
2159    *feedback = (void*) &pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_FenceData;
2160 
2161    std::vector<D3D12_RESOURCE_BARRIER> rgCurrentFrameStateTransitions = {
2162       CD3DX12_RESOURCE_BARRIER::Transition(pInputVideoD3D12Res,
2163                                            D3D12_RESOURCE_STATE_COMMON,
2164                                            D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ),
2165       CD3DX12_RESOURCE_BARRIER::Transition(pOutputBufferD3D12Res,
2166                                            D3D12_RESOURCE_STATE_COMMON,
2167                                            D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE),
2168       CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_spMetadataOutputBuffer.Get(),
2169                                            D3D12_RESOURCE_STATE_COMMON,
2170                                            D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE)
2171    };
2172 
2173    pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(static_cast<UINT>(rgCurrentFrameStateTransitions.size()),
2174                                                      rgCurrentFrameStateTransitions.data());
2175 
2176    D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE reconPicOutputTextureDesc =
2177       pD3D12Enc->m_upDPBManager->get_current_frame_recon_pic_output_allocation();
2178    D3D12_VIDEO_ENCODE_REFERENCE_FRAMES referenceFramesDescriptor =
2179       pD3D12Enc->m_upDPBManager->get_current_reference_frames();
2180    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAGS picCtrlFlags = D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_NONE;
2181 
2182    // Transition DPB reference pictures to read mode
2183    std::vector<D3D12_RESOURCE_BARRIER> rgReferenceTransitions;
2184    if ((referenceFramesDescriptor.NumTexture2Ds > 0) ||
2185        (pD3D12Enc->m_upDPBManager->is_current_frame_used_as_reference())) {
2186 
2187       if (reconPicOutputTextureDesc.pReconstructedPicture != nullptr)
2188          picCtrlFlags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE;
2189 
2190       // Check if array of textures vs texture array
2191 
2192       if (referenceFramesDescriptor.pSubresources == nullptr) {
2193 
2194          // Reserve allocation for AoT transitions count
2195          rgReferenceTransitions.reserve(static_cast<size_t>(referenceFramesDescriptor.NumTexture2Ds +
2196             ((reconPicOutputTextureDesc.pReconstructedPicture != nullptr) ? 1u : 0u)));
2197 
2198          // Array of resources mode for reference pictures
2199 
2200          // Transition all subresources of each reference frame independent resource allocation
2201          for (uint32_t referenceIdx = 0; referenceIdx < referenceFramesDescriptor.NumTexture2Ds; referenceIdx++) {
2202             rgReferenceTransitions.push_back(
2203                CD3DX12_RESOURCE_BARRIER::Transition(referenceFramesDescriptor.ppTexture2Ds[referenceIdx],
2204                                                     D3D12_RESOURCE_STATE_COMMON,
2205                                                     D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ));
2206          }
2207 
2208          // Transition all subresources the output recon pic independent resource allocation
2209          if (reconPicOutputTextureDesc.pReconstructedPicture != nullptr) {
2210             rgReferenceTransitions.push_back(
2211                CD3DX12_RESOURCE_BARRIER::Transition(reconPicOutputTextureDesc.pReconstructedPicture,
2212                                                     D3D12_RESOURCE_STATE_COMMON,
2213                                                     D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE));
2214          }
2215       } else if (referenceFramesDescriptor.NumTexture2Ds > 0) {
2216 
2217          // texture array mode for reference pictures
2218 
2219          // In Texture array mode, the dpb storage allocator uses the same texture array for all the input
2220          // reference pics in ppTexture2Ds and also for the pReconstructedPicture output allocations, just different
2221          // subresources.
2222 
2223          CD3DX12_RESOURCE_DESC referencesTexArrayDesc(GetDesc(referenceFramesDescriptor.ppTexture2Ds[0]));
2224 
2225 #if MESA_DEBUG
2226    // the reconpic output should be all the same texarray allocation
2227    if((reconPicOutputTextureDesc.pReconstructedPicture) && (referenceFramesDescriptor.NumTexture2Ds > 0))
2228       assert(referenceFramesDescriptor.ppTexture2Ds[0] == reconPicOutputTextureDesc.pReconstructedPicture);
2229 
2230    for (uint32_t refIndex = 0; refIndex < referenceFramesDescriptor.NumTexture2Ds; refIndex++) {
2231             // all reference frames inputs should be all the same texarray allocation
2232             assert(referenceFramesDescriptor.ppTexture2Ds[0] ==
2233                    referenceFramesDescriptor.ppTexture2Ds[refIndex]);
2234    }
2235 #endif
2236 
2237          // Reserve allocation for texture array transitions count
2238          rgReferenceTransitions.reserve(
2239             static_cast<size_t>(pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.PlaneCount * referencesTexArrayDesc.DepthOrArraySize));
2240 
2241          for (uint32_t referenceSubresource = 0; referenceSubresource < referencesTexArrayDesc.DepthOrArraySize;
2242               referenceSubresource++) {
2243 
2244             uint32_t MipLevel, PlaneSlice, ArraySlice;
2245             D3D12DecomposeSubresource(referenceSubresource,
2246                                       referencesTexArrayDesc.MipLevels,
2247                                       referencesTexArrayDesc.ArraySize(),
2248                                       MipLevel,
2249                                       ArraySlice,
2250                                       PlaneSlice);
2251 
2252             for (PlaneSlice = 0; PlaneSlice < pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.PlaneCount;
2253                  PlaneSlice++) {
2254 
2255                uint32_t planeOutputSubresource =
2256                   referencesTexArrayDesc.CalcSubresource(MipLevel, ArraySlice, PlaneSlice);
2257 
2258                rgReferenceTransitions.push_back(CD3DX12_RESOURCE_BARRIER::Transition(
2259                   // Always same allocation in texarray mode
2260                   referenceFramesDescriptor.ppTexture2Ds[0],
2261                   D3D12_RESOURCE_STATE_COMMON,
2262                   // If this is the subresource for the reconpic output allocation, transition to ENCODE_WRITE
2263                   // Otherwise, it's a subresource for an input reference picture, transition to ENCODE_READ
2264                   (referenceSubresource == reconPicOutputTextureDesc.ReconstructedPictureSubresource) ?
2265                      D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE :
2266                      D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
2267                   planeOutputSubresource));
2268             }
2269          }
2270       }
2271 
2272       if (rgReferenceTransitions.size() > 0) {
2273          pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(static_cast<uint32_t>(rgReferenceTransitions.size()),
2274                                                            rgReferenceTransitions.data());
2275       }
2276    }
2277 
2278    // Update current frame pic params state after reconfiguring above.
2279    D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA currentPicParams =
2280       d3d12_video_encoder_get_current_picture_param_settings(pD3D12Enc);
2281 
2282    if (!pD3D12Enc->m_upDPBManager->get_current_frame_picture_control_data(currentPicParams)) {
2283       debug_printf("[d3d12_video_encoder_encode_bitstream] get_current_frame_picture_control_data failed!\n");
2284       pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
2285       pD3D12Enc->m_spEncodedFrameMetadata[d3d12_video_encoder_metadata_current_index(pD3D12Enc)].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
2286       assert(false);
2287       return;
2288    }
2289 
2290    // Stores D3D12_VIDEO_ENCODER_AV1_REFERENCE_PICTURE_DESCRIPTOR in the associated metadata
2291    // for header generation after execution (if applicable)
2292    if (pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].postEncodeHeadersNeeded) {
2293       d3d12_video_encoder_store_current_picture_references(pD3D12Enc, current_metadata_slot);
2294    }
2295 
2296    const D3D12_VIDEO_ENCODER_ENCODEFRAME_INPUT_ARGUMENTS inputStreamArguments = {
2297       // D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_DESC
2298       { // D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS
2299         pD3D12Enc->m_currentEncodeConfig.m_seqFlags,
2300         // D3D12_VIDEO_ENCODER_INTRA_REFRESH
2301         pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh,
2302         d3d12_video_encoder_get_current_rate_control_settings(pD3D12Enc),
2303         // D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC
2304         pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
2305         pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
2306         d3d12_video_encoder_get_current_slice_param_settings(pD3D12Enc),
2307         d3d12_video_encoder_get_current_gop_desc(pD3D12Enc) },
2308       // D3D12_VIDEO_ENCODER_PICTURE_CONTROL_DESC
2309       { // uint32_t IntraRefreshFrameIndex;
2310         pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex,
2311         // D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAGS Flags;
2312         picCtrlFlags,
2313         // D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA PictureControlCodecData;
2314         currentPicParams,
2315         // D3D12_VIDEO_ENCODE_REFERENCE_FRAMES ReferenceFrames;
2316         referenceFramesDescriptor },
2317       pInputVideoD3D12Res,
2318       inputVideoD3D12Subresource,
2319       static_cast<UINT>(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize)
2320       // budgeting. - User can also calculate headers fixed size beforehand (eg. no VUI,
2321       // etc) and build them with final values after EncodeFrame is executed
2322    };
2323 
2324    const D3D12_VIDEO_ENCODER_ENCODEFRAME_OUTPUT_ARGUMENTS outputStreamArguments = {
2325       // D3D12_VIDEO_ENCODER_COMPRESSED_BITSTREAM
2326       {
2327          pOutputBufferD3D12Res,
2328          pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize,
2329       },
2330       // D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE
2331       reconPicOutputTextureDesc,
2332       // D3D12_VIDEO_ENCODER_ENCODE_OPERATION_METADATA_BUFFER
2333       { pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_spMetadataOutputBuffer.Get(), 0 }
2334    };
2335 
2336    debug_printf("DX12 EncodeFrame submission fenceValue %" PRIu64 " current_metadata_slot %" PRIu64 " - POC %d picture_type %s LayoutMode %d SlicesCount %d IRMode %d IRIndex %d\n",
2337                 pD3D12Enc->m_fenceValue,
2338                 static_cast<uint64_t>(current_metadata_slot),
2339                 inputStreamArguments.PictureControlDesc.PictureControlCodecData.pH264PicData->PictureOrderCountNumber,
2340                 d3d12_video_encoder_friendly_frame_type_h264(inputStreamArguments.PictureControlDesc.PictureControlCodecData.pH264PicData->FrameType),
2341                 inputStreamArguments.SequenceControlDesc.SelectedLayoutMode,
2342                 inputStreamArguments.SequenceControlDesc.FrameSubregionsLayoutData.pSlicesPartition_H264 ? inputStreamArguments.SequenceControlDesc.FrameSubregionsLayoutData.pSlicesPartition_H264->NumberOfSlicesPerFrame : 1u,
2343                 static_cast<uint32_t>(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_IntraRefresh.Mode),
2344                 pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_IntraRefreshCurrentFrameIndex);
2345 
2346    // Record EncodeFrame
2347    pD3D12Enc->m_spEncodeCommandList->EncodeFrame(pD3D12Enc->m_spVideoEncoder.Get(),
2348                                                  pD3D12Enc->m_spVideoEncoderHeap.Get(),
2349                                                  &inputStreamArguments,
2350                                                  &outputStreamArguments);
2351 
2352    D3D12_RESOURCE_BARRIER rgResolveMetadataStateTransitions[] = {
2353       CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].spBuffer.Get(),
2354                                            D3D12_RESOURCE_STATE_COMMON,
2355                                            D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE),
2356       CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_spMetadataOutputBuffer.Get(),
2357                                            D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
2358                                            D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ),
2359       CD3DX12_RESOURCE_BARRIER::Transition(pInputVideoD3D12Res,
2360                                            D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
2361                                            D3D12_RESOURCE_STATE_COMMON),
2362       CD3DX12_RESOURCE_BARRIER::Transition(pOutputBufferD3D12Res,
2363                                            D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
2364                                            D3D12_RESOURCE_STATE_COMMON)
2365    };
2366 
2367    pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(_countof(rgResolveMetadataStateTransitions),
2368                                                      rgResolveMetadataStateTransitions);
2369 
2370    const D3D12_VIDEO_ENCODER_RESOLVE_METADATA_INPUT_ARGUMENTS inputMetadataCmd = {
2371       pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc,
2372       d3d12_video_encoder_get_current_profile_desc(pD3D12Enc),
2373       pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
2374       // D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC
2375       pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
2376       { pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_spMetadataOutputBuffer.Get(), 0 }
2377    };
2378 
2379    const D3D12_VIDEO_ENCODER_RESOLVE_METADATA_OUTPUT_ARGUMENTS outputMetadataCmd = {
2380       /*If offset were to change, has to be aligned to pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.EncoderMetadataBufferAccessAlignment*/
2381       { pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].spBuffer.Get(), 0 }
2382    };
2383    pD3D12Enc->m_spEncodeCommandList->ResolveEncoderOutputMetadata(&inputMetadataCmd, &outputMetadataCmd);
2384 
2385    debug_printf("[d3d12_video_encoder_encode_bitstream] EncodeFrame slot %" PRIu64 " encoder %p encoderheap %p input tex %p output bitstream %p raw metadata buf %p resolved metadata buf %p Command allocator %p\n",
2386                static_cast<uint64_t>(d3d12_video_encoder_pool_current_index(pD3D12Enc)),
2387                pD3D12Enc->m_spVideoEncoder.Get(),
2388                pD3D12Enc->m_spVideoEncoderHeap.Get(),
2389                inputStreamArguments.pInputFrame,
2390                outputStreamArguments.Bitstream.pBuffer,
2391                inputMetadataCmd.HWLayoutMetadata.pBuffer,
2392                outputMetadataCmd.ResolvedLayoutMetadata.pBuffer,
2393                pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_spCommandAllocator.Get());
2394 
2395    // Transition DPB reference pictures back to COMMON
2396    if ((referenceFramesDescriptor.NumTexture2Ds > 0) ||
2397        (pD3D12Enc->m_upDPBManager->is_current_frame_used_as_reference())) {
2398       for (auto &BarrierDesc : rgReferenceTransitions) {
2399          std::swap(BarrierDesc.Transition.StateBefore, BarrierDesc.Transition.StateAfter);
2400       }
2401 
2402       if (rgReferenceTransitions.size() > 0) {
2403          pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(static_cast<uint32_t>(rgReferenceTransitions.size()),
2404                                                            rgReferenceTransitions.data());
2405       }
2406    }
2407 
2408    D3D12_RESOURCE_BARRIER rgRevertResolveMetadataStateTransitions[] = {
2409       CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].spBuffer.Get(),
2410                                            D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
2411                                            D3D12_RESOURCE_STATE_COMMON),
2412       CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_spMetadataOutputBuffer.Get(),
2413                                            D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
2414                                            D3D12_RESOURCE_STATE_COMMON),
2415    };
2416 
2417    pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(_countof(rgRevertResolveMetadataStateTransitions),
2418                                                      rgRevertResolveMetadataStateTransitions);
2419 
2420    debug_printf("[d3d12_video_encoder] d3d12_video_encoder_encode_bitstream finalized for fenceValue: %" PRIu64 "\n",
2421                  pD3D12Enc->m_fenceValue);
2422 }
2423 
2424 void
d3d12_video_encoder_get_feedback(struct pipe_video_codec * codec,void * feedback,unsigned * output_buffer_size,struct pipe_enc_feedback_metadata * pMetadata)2425 d3d12_video_encoder_get_feedback(struct pipe_video_codec *codec,
2426                                   void *feedback,
2427                                   unsigned *output_buffer_size,
2428                                   struct pipe_enc_feedback_metadata* pMetadata)
2429 {
2430    struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
2431    assert(pD3D12Enc);
2432 
2433    struct d3d12_fence *feedback_fence = (struct d3d12_fence *) feedback;
2434    uint64_t requested_metadata_fence = feedback_fence->value;
2435 
2436    struct pipe_enc_feedback_metadata opt_metadata;
2437    memset(&opt_metadata, 0, sizeof(opt_metadata));
2438 
2439    HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->GetDeviceRemovedReason();
2440    if (hr != S_OK) {
2441       opt_metadata.encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
2442       debug_printf("Error: d3d12_video_encoder_get_feedback for Encode GPU command for fence %" PRIu64 " failed with GetDeviceRemovedReason: %x\n",
2443                      requested_metadata_fence,
2444                      hr);
2445       assert(false);
2446       if(pMetadata)
2447          *pMetadata = opt_metadata;
2448       return;
2449    }
2450 
2451    size_t current_metadata_slot = static_cast<size_t>(requested_metadata_fence % D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT);
2452    opt_metadata.encode_result = pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].encode_result;
2453    if (opt_metadata.encode_result & PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED) {
2454       debug_printf("Error: d3d12_video_encoder_get_feedback for Encode GPU command for fence %" PRIu64 " failed on submission with encode_result: %x\n",
2455                      requested_metadata_fence,
2456                      opt_metadata.encode_result);
2457       assert(false);
2458       if(pMetadata)
2459          *pMetadata = opt_metadata;
2460       return;
2461    }
2462 
2463    bool wait_res = d3d12_video_encoder_sync_completion(codec, feedback_fence->cmdqueue_fence, requested_metadata_fence, OS_TIMEOUT_INFINITE);
2464    if (!wait_res) {
2465       opt_metadata.encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
2466       debug_printf("Error: d3d12_video_encoder_get_feedback for Encode GPU command for fence %" PRIu64 " failed on d3d12_video_encoder_sync_completion\n",
2467                      requested_metadata_fence);
2468       assert(false);
2469       if(pMetadata)
2470          *pMetadata = opt_metadata;
2471       return;
2472    }
2473 
2474    opt_metadata.encode_result = pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].encode_result;
2475    if (opt_metadata.encode_result & PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED) {
2476       debug_printf("Error: d3d12_video_encoder_get_feedback for Encode GPU command for fence %" PRIu64 " failed on GPU fence wait with encode_result: %x\n",
2477                      requested_metadata_fence,
2478                      opt_metadata.encode_result);
2479       assert(false);
2480       if(pMetadata)
2481          *pMetadata = opt_metadata;
2482       return;
2483    }
2484 
2485    debug_printf("d3d12_video_encoder_get_feedback with feedback: %" PRIu64 ", resources slot %" PRIu64 " metadata resolved ID3D12Resource buffer %p metadata required size %" PRIu64 "\n",
2486       requested_metadata_fence,
2487       (requested_metadata_fence % D3D12_VIDEO_ENC_ASYNC_DEPTH),
2488       pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].spBuffer.Get(),
2489       pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].bufferSize);
2490 
2491    if((pD3D12Enc->m_fenceValue - requested_metadata_fence) > D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT)
2492    {
2493       debug_printf("[d3d12_video_encoder_get_feedback] Requested metadata for fence %" PRIu64 " at current fence %" PRIu64
2494          " is too far back in time for the ring buffer of size %" PRIu64 " we keep track off - "
2495          " Please increase the D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT environment variable and try again.\n",
2496          requested_metadata_fence,
2497          pD3D12Enc->m_fenceValue,
2498          static_cast<uint64_t>(D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT));
2499       opt_metadata.encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
2500       assert(false);
2501       if(pMetadata)
2502          *pMetadata = opt_metadata;
2503       return;
2504    }
2505 
2506    // Extract encode metadata
2507    D3D12_VIDEO_ENCODER_OUTPUT_METADATA                       encoderMetadata;
2508    std::vector<D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA> pSubregionsMetadata;
2509    d3d12_video_encoder_extract_encode_metadata(
2510       pD3D12Enc,
2511       pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].spBuffer.Get(),
2512       pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].bufferSize,
2513       encoderMetadata,
2514       pSubregionsMetadata);
2515 
2516    // Validate encoder output metadata
2517    if ((encoderMetadata.EncodeErrorFlags != D3D12_VIDEO_ENCODER_ENCODE_ERROR_FLAG_NO_ERROR) || (encoderMetadata.EncodedBitstreamWrittenBytesCount == 0)) {
2518       opt_metadata.encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
2519       debug_printf("[d3d12_video_encoder] Encode GPU command for fence %" PRIu64 " failed - EncodeErrorFlags: %" PRIu64 "\n",
2520                      requested_metadata_fence,
2521                      encoderMetadata.EncodeErrorFlags);
2522       assert(false);
2523       if(pMetadata)
2524          *pMetadata = opt_metadata;
2525       return;
2526    }
2527 
2528    uint64_t unpadded_frame_size = 0;
2529    if(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].postEncodeHeadersNeeded)
2530    {
2531       *output_buffer_size = d3d12_video_encoder_build_post_encode_codec_bitstream(
2532          pD3D12Enc,
2533          requested_metadata_fence,
2534          pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot]
2535       );
2536       for (uint32_t i = 0; i < pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].pWrittenCodecUnitsSizes.size(); i++)
2537       {
2538          opt_metadata.codec_unit_metadata[opt_metadata.codec_unit_metadata_count].size = pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].pWrittenCodecUnitsSizes[i];
2539          opt_metadata.codec_unit_metadata[opt_metadata.codec_unit_metadata_count].offset = unpadded_frame_size;
2540          unpadded_frame_size += opt_metadata.codec_unit_metadata[opt_metadata.codec_unit_metadata_count].size;
2541          opt_metadata.codec_unit_metadata_count++;
2542       }
2543    }
2544    else
2545    {
2546 #if VIDEO_CODEC_H264ENC
2547       // Add H264 temporal layers slice nal prefixes if necessary
2548       if ((D3D12_VIDEO_ENCODER_CODEC_H264 == pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_encoderCodecDesc)
2549            && (pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_svcprefix_slice_header)
2550            && (pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_encoderCodecSpecificSequenceStateDescH264.num_temporal_layers > 1))
2551       {
2552          if (!pD3D12Enc->m_nalPrefixTmpBuffer)
2553             d3d12_video_encoder_reallocate_prefix_nal_buffer(pD3D12Enc,
2554                                                              &pD3D12Enc->m_nalPrefixTmpBuffer,
2555                                                              D3D12_DEFAULT_COMPBIT_STAGING_SIZE);
2556          assert (pD3D12Enc->m_nalPrefixTmpBuffer);
2557 
2558          //
2559          // Copy slices from driver comp_bit_destination into m_nalPrefixTmpBuffer with collated slices NAL prefixes
2560          //
2561          // Skip SPS, PPS, etc first preEncodeGeneratedHeadersByteSize bytes in src_driver_buffer_read_bytes
2562          uint32_t src_driver_buffer_read_bytes = static_cast<uint32_t>(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize);
2563          uint32_t dst_tmp_buffer_written_bytes = 0;
2564          uint32_t num_slices = static_cast<uint32_t>(pSubregionsMetadata.size());
2565          std::vector<std::vector<uint8_t> > prefix_nal_bufs;
2566          prefix_nal_bufs.resize(num_slices);
2567          size_t written_prefix_nal_bytes = 0;
2568          for (uint32_t cur_slice_idx = 0; cur_slice_idx < num_slices; cur_slice_idx++)
2569          {
2570             // At the end of the loop we're inserting at pSubregionsMetadata.insert(std::next(pSubregionsMetadata.begin()
2571             // so we have to 2x the loop current index to index the current slice, skipping the prefix NALs of the previously processed slices
2572             D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA cur_subregion_metadata = pSubregionsMetadata[2 * cur_slice_idx];
2573 
2574             d3d12_video_encoder_build_slice_svc_prefix_nalu_h264(pD3D12Enc,
2575                                                                  pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot],
2576                                                                  prefix_nal_bufs[cur_slice_idx],
2577                                                                  prefix_nal_bufs[cur_slice_idx].begin(),
2578                                                                  written_prefix_nal_bytes);
2579 
2580             // Upload nal prefix to m_nalPrefixTmpBuffer
2581             pD3D12Enc->base.context->buffer_subdata(pD3D12Enc->base.context,               // context
2582                                                     pD3D12Enc->m_nalPrefixTmpBuffer,       // dst buffer
2583                                                     PIPE_MAP_WRITE,                        // dst usage PIPE_MAP_x
2584                                                     dst_tmp_buffer_written_bytes,          // dst offset
2585                                                     static_cast<unsigned>(written_prefix_nal_bytes), // src size
2586                                                     prefix_nal_bufs[cur_slice_idx].data());                // src void* buffer
2587             dst_tmp_buffer_written_bytes += static_cast<uint32_t>(written_prefix_nal_bytes);
2588 
2589             // Copy slice (padded as-is) cur_subregion_metadata.bSize at src_driver_buffer_read_bytes into m_nalPrefixTmpBuffer AFTER the prefix nal (written_prefix_nal_bytes) to m_nalPrefixTmpBuffer
2590             struct pipe_box src_box = {};
2591             u_box_3d(src_driver_buffer_read_bytes,                   // x
2592                      0,                                              // y
2593                      0,                                              // z
2594                      static_cast<int>(cur_subregion_metadata.bSize), // width
2595                      1,                                              // height
2596                      1,                                              // depth
2597                      &src_box
2598             );
2599 
2600             pD3D12Enc->base.context->resource_copy_region(pD3D12Enc->base.context,                                                         // ctx
2601                                                           pD3D12Enc->m_nalPrefixTmpBuffer,                                                 // dst
2602                                                           0,                                                                               // dst_level
2603                                                           dst_tmp_buffer_written_bytes,                                                    // dstX - Skip the other headers in the final bitstream (e.g SPS, PPS, etc)
2604                                                           0,                                                                               // dstY
2605                                                           0,                                                                               // dstZ
2606                                                           pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].comp_bit_destination, // src
2607                                                           0,                                                                               // src level
2608                                                           &src_box);
2609             src_driver_buffer_read_bytes += static_cast<uint32_t>(cur_subregion_metadata.bSize);
2610             dst_tmp_buffer_written_bytes += static_cast<uint32_t>(cur_subregion_metadata.bSize);
2611 
2612             // Insert prefix NAL before current slice in cur_subregion_metadata so it's treated as just another NAL below for reporting metadata
2613             pSubregionsMetadata.insert(std::next(pSubregionsMetadata.begin(), 2 * cur_slice_idx), { /* bSize */ written_prefix_nal_bytes, /* bStartOffset */ 0, /* bHeaderSize */ 0 });
2614          }
2615 
2616          //
2617          // Copy from m_nalPrefixTmpBuffer with prefixes and slices back into comp_bit_destination
2618          //
2619 
2620          // Make sure we have enough space in destination buffer
2621          if (dst_tmp_buffer_written_bytes >
2622             (pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize + pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].comp_bit_destination->width0))
2623          {
2624             opt_metadata.encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED;
2625             debug_printf("[d3d12_video_encoder] Insufficient compressed buffer size passed from frontend while building the H264 SVC NAL prefixes.\n");
2626             assert(false);
2627             if(pMetadata)
2628                *pMetadata = opt_metadata;
2629             return;
2630          }
2631 
2632          // Do the copy
2633          struct pipe_box src_box = {};
2634          u_box_3d(0,                                              // x
2635                   0,                                              // y
2636                   0,                                              // z
2637                   static_cast<int>(dst_tmp_buffer_written_bytes), // width
2638                   1,                                              // height
2639                   1,                                              // depth
2640                   &src_box
2641          );
2642 
2643          pD3D12Enc->base.context->resource_copy_region(pD3D12Enc->base.context,                                                                    // ctx
2644                                                        pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].comp_bit_destination,             // dst
2645                                                        0,                                                                                           // dst_level
2646                                                        static_cast<unsigned int>(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersByteSize),// dstX - Skip the other headers in the final bitstream (e.g SPS, PPS, etc)
2647                                                        0,                                                                                           // dstY
2648                                                        0,                                                                                           // dstZ
2649                                                        pD3D12Enc->m_nalPrefixTmpBuffer,                                                             // src
2650                                                        0,                                                                                           // src level
2651                                                        &src_box);
2652 
2653          //
2654          // Flush copies in batch and wait on this CPU thread for GPU work completion
2655          //
2656          {
2657             struct pipe_fence_handle *pUploadGPUCompletionFence = NULL;
2658             pD3D12Enc->base.context->flush(pD3D12Enc->base.context,
2659                                           &pUploadGPUCompletionFence,
2660                                           PIPE_FLUSH_ASYNC | PIPE_FLUSH_HINT_FINISH);
2661             assert(pUploadGPUCompletionFence);
2662             pD3D12Enc->m_pD3D12Screen->base.fence_finish(&pD3D12Enc->m_pD3D12Screen->base,
2663                                                          NULL,
2664                                                          pUploadGPUCompletionFence,
2665                                                          OS_TIMEOUT_INFINITE);
2666             pD3D12Enc->m_pD3D12Screen->base.fence_reference(&pD3D12Enc->m_pD3D12Screen->base,
2667                                                             &pUploadGPUCompletionFence,
2668                                                             NULL);
2669          }
2670       }
2671 #endif // VIDEO_CODEC_H264ENC
2672 
2673       *output_buffer_size = 0;
2674       for (uint32_t i = 0; i < pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].pWrittenCodecUnitsSizes.size() ; i++) {
2675          unpadded_frame_size += pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].pWrittenCodecUnitsSizes[i];
2676          opt_metadata.codec_unit_metadata[opt_metadata.codec_unit_metadata_count].size = pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].pWrittenCodecUnitsSizes[i];
2677          opt_metadata.codec_unit_metadata[opt_metadata.codec_unit_metadata_count].offset = *output_buffer_size;
2678          *output_buffer_size += static_cast<unsigned int>(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].pWrittenCodecUnitsSizes[i]);
2679          opt_metadata.codec_unit_metadata_count++;
2680       }
2681 
2682       // Add padding between pre encode headers (e.g EncodeFrame driver offset alignment) and the first slice
2683       *output_buffer_size += static_cast<unsigned int>(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].preEncodeGeneratedHeadersBytePadding);
2684 
2685       debug_printf("D3D12 backend readback submission for frame with fence %" PRIu64 " current_metadata_slot %" PRIu64 " - PictureOrderCountNumber %d FrameType %s num_slice_descriptors %d IRMode %d IRIndex %d\n",
2686          requested_metadata_fence,
2687          static_cast<uint64_t>(current_metadata_slot),
2688          pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_encoderPicParamsDesc.m_H264PicData.PictureOrderCountNumber,
2689          d3d12_video_encoder_friendly_frame_type_h264(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_encoderPicParamsDesc.m_H264PicData.FrameType),
2690          static_cast<uint32_t>(pSubregionsMetadata.size()),
2691          static_cast<uint32_t>(pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_IntraRefresh.Mode),
2692          pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_associatedEncodeConfig.m_IntraRefreshCurrentFrameIndex);
2693 
2694       for (uint32_t i = 0; i < pSubregionsMetadata.size(); i++)
2695       {
2696          uint64_t unpadded_slice_size = pSubregionsMetadata[i].bSize - pSubregionsMetadata[i].bStartOffset;
2697          unpadded_frame_size += unpadded_slice_size;
2698          opt_metadata.codec_unit_metadata[opt_metadata.codec_unit_metadata_count].flags = PIPE_VIDEO_CODEC_UNIT_LOCATION_FLAG_SINGLE_NALU;
2699          opt_metadata.codec_unit_metadata[opt_metadata.codec_unit_metadata_count].size = unpadded_slice_size;
2700          opt_metadata.codec_unit_metadata[opt_metadata.codec_unit_metadata_count].offset = *output_buffer_size;
2701          *output_buffer_size += static_cast<unsigned int>(pSubregionsMetadata[i].bSize);
2702          if ((pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].expected_max_slice_size > 0) &&
2703              (unpadded_slice_size > pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].expected_max_slice_size))
2704             opt_metadata.codec_unit_metadata[opt_metadata.codec_unit_metadata_count].flags |= PIPE_VIDEO_CODEC_UNIT_LOCATION_FLAG_MAX_SLICE_SIZE_OVERFLOW;
2705          opt_metadata.codec_unit_metadata_count++;
2706       }
2707    }
2708 
2709    if ((pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].expected_max_frame_size > 0) &&
2710       (unpadded_frame_size > pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].expected_max_frame_size))
2711       opt_metadata.encode_result |= PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_MAX_FRAME_SIZE_OVERFLOW;
2712 
2713    opt_metadata.average_frame_qp = static_cast<unsigned int>(encoderMetadata.EncodeStats.AverageQP);
2714 
2715    opt_metadata.present_metadata = (PIPE_VIDEO_FEEDBACK_METADATA_TYPE_BITSTREAM_SIZE |
2716                                     PIPE_VIDEO_FEEDBACK_METADATA_TYPE_ENCODE_RESULT |
2717                                     PIPE_VIDEO_FEEDBACK_METADATA_TYPE_CODEC_UNIT_LOCATION |
2718                                     PIPE_VIDEO_FEEDBACK_METADATA_TYPE_MAX_FRAME_SIZE_OVERFLOW |
2719                                     PIPE_VIDEO_FEEDBACK_METADATA_TYPE_MAX_SLICE_SIZE_OVERFLOW |
2720                                     PIPE_VIDEO_FEEDBACK_METADATA_TYPE_AVERAGE_FRAME_QP);
2721 
2722    if (pMetadata)
2723       *pMetadata = opt_metadata;
2724 
2725    debug_printf("[d3d12_video_encoder_get_feedback] Requested metadata for encoded frame at fence %" PRIu64 " is:\n"
2726                 "\tfeedback was requested at current fence: %" PRIu64 "\n"
2727                 "\toutput_buffer_size (including padding): %d\n"
2728                 "\tunpadded_frame_size: %" PRIu64 "\n"
2729                 "\ttotal padding: %" PRIu64 "\n"
2730                 "\tcodec_unit_metadata_count: %d\n",
2731                 pD3D12Enc->m_fenceValue,
2732                 requested_metadata_fence,
2733                 *output_buffer_size,
2734                 unpadded_frame_size,
2735                 static_cast<uint64_t>(static_cast<uint64_t>(*output_buffer_size) - unpadded_frame_size),
2736                 opt_metadata.codec_unit_metadata_count);
2737 
2738    for (uint32_t i = 0; i < opt_metadata.codec_unit_metadata_count; i++) {
2739       debug_printf("\tcodec_unit_metadata[%d].offset: %" PRIu64" - codec_unit_metadata[%d].size: %" PRIu64" \n",
2740          i,
2741          opt_metadata.codec_unit_metadata[i].offset,
2742          i,
2743          opt_metadata.codec_unit_metadata[i].size);
2744    }
2745 
2746    pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].bRead = true;
2747 }
2748 
2749 unsigned
d3d12_video_encoder_build_post_encode_codec_bitstream(struct d3d12_video_encoder * pD3D12Enc,uint64_t associated_fence_value,EncodedBitstreamResolvedMetadata & associatedMetadata)2750 d3d12_video_encoder_build_post_encode_codec_bitstream(struct d3d12_video_encoder * pD3D12Enc,
2751                                              uint64_t associated_fence_value,
2752                                              EncodedBitstreamResolvedMetadata& associatedMetadata)
2753 {
2754    enum pipe_video_format codec_format = u_reduce_video_profile(pD3D12Enc->base.profile);
2755    switch (codec_format) {
2756 #if VIDEO_CODEC_H264ENC
2757       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
2758       {
2759          return 0;
2760       } break;
2761 #endif
2762 #if VIDEO_CODEC_H265ENC
2763       case PIPE_VIDEO_FORMAT_HEVC:
2764       {
2765          return 0;
2766       } break; // Do not need post encode values in headers
2767 #endif
2768 #if VIDEO_CODEC_AV1ENC
2769       case PIPE_VIDEO_FORMAT_AV1:
2770       {
2771          return d3d12_video_encoder_build_post_encode_codec_bitstream_av1(
2772             // Current encoder
2773             pD3D12Enc,
2774             // associated fence value
2775             associated_fence_value,
2776             // Metadata desc
2777             associatedMetadata
2778          );
2779       } break;
2780 #endif
2781       default:
2782          unreachable("Unsupported pipe_video_format");
2783    }
2784 }
2785 
2786 void
d3d12_video_encoder_extract_encode_metadata(struct d3d12_video_encoder * pD3D12Enc,ID3D12Resource * pResolvedMetadataBuffer,uint64_t resourceMetadataSize,D3D12_VIDEO_ENCODER_OUTPUT_METADATA & parsedMetadata,std::vector<D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA> & pSubregionsMetadata)2787 d3d12_video_encoder_extract_encode_metadata(
2788    struct d3d12_video_encoder *                               pD3D12Enc,
2789    ID3D12Resource *                                           pResolvedMetadataBuffer,   // input
2790    uint64_t                                                   resourceMetadataSize,      // input
2791    D3D12_VIDEO_ENCODER_OUTPUT_METADATA &                      parsedMetadata,            // output
2792    std::vector<D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA> &pSubregionsMetadata        // output
2793 )
2794 {
2795    struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pD3D12Enc->m_pD3D12Screen;
2796    assert(pD3D12Screen);
2797    pipe_resource *pPipeResolvedMetadataBuffer =
2798       d3d12_resource_from_resource(&pD3D12Screen->base, pResolvedMetadataBuffer);
2799    assert(pPipeResolvedMetadataBuffer);
2800    assert(resourceMetadataSize < INT_MAX);
2801    struct pipe_box box;
2802    u_box_3d(0,                                        // x
2803             0,                                        // y
2804             0,                                        // z
2805             static_cast<int>(resourceMetadataSize),   // width
2806             1,                                        // height
2807             1,                                        // depth
2808             &box);
2809    struct pipe_transfer *mapTransfer;
2810    unsigned mapUsage = PIPE_MAP_READ;
2811    void *                pMetadataBufferSrc = pD3D12Enc->base.context->buffer_map(pD3D12Enc->base.context,
2812                                                                   pPipeResolvedMetadataBuffer,
2813                                                                   0,
2814                                                                   mapUsage,
2815                                                                   &box,
2816                                                                   &mapTransfer);
2817 
2818    assert(mapUsage & PIPE_MAP_READ);
2819    assert(pPipeResolvedMetadataBuffer->usage == PIPE_USAGE_DEFAULT);
2820    // Note: As we're calling buffer_map with PIPE_MAP_READ on a pPipeResolvedMetadataBuffer which has pipe_usage_default
2821    // buffer_map itself will do all the synchronization and waits so once the function returns control here
2822    // the contents of mapTransfer are ready to be accessed.
2823 
2824    // Clear output
2825    memset(&parsedMetadata, 0, sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA));
2826 
2827    // Calculate sizes
2828    uint64_t encoderMetadataSize = sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA);
2829 
2830    // Copy buffer to the appropriate D3D12_VIDEO_ENCODER_OUTPUT_METADATA memory layout
2831    parsedMetadata = *reinterpret_cast<D3D12_VIDEO_ENCODER_OUTPUT_METADATA *>(pMetadataBufferSrc);
2832 
2833    // As specified in D3D12 Encode spec, the array base for metadata for the slices
2834    // (D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA[]) is placed in memory immediately after the
2835    // D3D12_VIDEO_ENCODER_OUTPUT_METADATA structure
2836    D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA *pFrameSubregionMetadata =
2837       reinterpret_cast<D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA *>(reinterpret_cast<uint8_t *>(pMetadataBufferSrc) +
2838                                                                        encoderMetadataSize);
2839 
2840    // Copy fields into D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA
2841    assert(parsedMetadata.WrittenSubregionsCount < SIZE_MAX);
2842    pSubregionsMetadata.resize(static_cast<size_t>(parsedMetadata.WrittenSubregionsCount));
2843    for (uint32_t sliceIdx = 0; sliceIdx < parsedMetadata.WrittenSubregionsCount; sliceIdx++) {
2844       pSubregionsMetadata[sliceIdx].bHeaderSize  = pFrameSubregionMetadata[sliceIdx].bHeaderSize;
2845       pSubregionsMetadata[sliceIdx].bSize        = pFrameSubregionMetadata[sliceIdx].bSize;
2846       pSubregionsMetadata[sliceIdx].bStartOffset = pFrameSubregionMetadata[sliceIdx].bStartOffset;
2847    }
2848 
2849    // Unmap the buffer tmp storage
2850    pipe_buffer_unmap(pD3D12Enc->base.context, mapTransfer);
2851    pipe_resource_reference(&pPipeResolvedMetadataBuffer, NULL);
2852 }
2853 
2854 /**
2855  * end encoding of the current frame
2856  */
2857 int
d3d12_video_encoder_end_frame(struct pipe_video_codec * codec,struct pipe_video_buffer * target,struct pipe_picture_desc * picture)2858 d3d12_video_encoder_end_frame(struct pipe_video_codec * codec,
2859                               struct pipe_video_buffer *target,
2860                               struct pipe_picture_desc *picture)
2861 {
2862    struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
2863    assert(pD3D12Enc);
2864    debug_printf("[d3d12_video_encoder] d3d12_video_encoder_end_frame started for fenceValue: %" PRIu64 "\n",
2865                  pD3D12Enc->m_fenceValue);
2866 
2867    if (pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].encode_result != PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_OK) {
2868       debug_printf("WARNING: [d3d12_video_encoder] d3d12_video_encoder_end_frame - Frame submission %" PRIu64 " failed. Encoder lost, please recreate pipe_video_codec object\n", pD3D12Enc->m_fenceValue);
2869       assert(false);
2870       return 1;
2871    }
2872 
2873    // Signal finish of current frame encoding to the picture management tracker
2874    pD3D12Enc->m_upDPBManager->end_frame();
2875 
2876    // Save extra references of Encoder, EncoderHeap and DPB allocations in case
2877    // there's a reconfiguration that trigers the construction of new objects
2878    pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_spEncoder = pD3D12Enc->m_spVideoEncoder;
2879    pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_spEncoderHeap = pD3D12Enc->m_spVideoEncoderHeap;
2880    pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_References = pD3D12Enc->m_upDPBStorageManager;
2881 
2882    debug_printf("[d3d12_video_encoder] d3d12_video_encoder_end_frame finalized for fenceValue: %" PRIu64 "\n",
2883                  pD3D12Enc->m_fenceValue);
2884 
2885    pD3D12Enc->m_bPendingWorkNotFlushed = true;
2886 
2887    size_t current_metadata_slot = d3d12_video_encoder_metadata_current_index(pD3D12Enc);
2888    *picture->fence = (pipe_fence_handle *) &pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_FenceData;
2889 
2890    return 0;
2891 }
2892 
2893 void
d3d12_video_encoder_store_current_picture_references(d3d12_video_encoder * pD3D12Enc,uint64_t current_metadata_slot)2894 d3d12_video_encoder_store_current_picture_references(d3d12_video_encoder *pD3D12Enc,
2895                                                      uint64_t current_metadata_slot)
2896 {
2897    enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
2898    switch (codec) {
2899 #if VIDEO_CODEC_H264ENC
2900       case PIPE_VIDEO_FORMAT_MPEG4_AVC:
2901       {
2902          // Not needed (not post encode headers)
2903       } break;
2904 #endif
2905 #if VIDEO_CODEC_H265ENC
2906       case PIPE_VIDEO_FORMAT_HEVC:
2907       {
2908          // Not needed (not post encode headers)
2909       } break;
2910 #endif
2911 #if VIDEO_CODEC_AV1ENC
2912       case PIPE_VIDEO_FORMAT_AV1:
2913       {
2914          d3d12_video_encoder_store_current_picture_references_av1(pD3D12Enc, current_metadata_slot);
2915       } break;
2916 #endif
2917       default:
2918       {
2919          unreachable("Unsupported pipe_video_format");
2920       } break;
2921    }
2922 }
2923 
d3d12_video_encoder_get_encode_headers(struct pipe_video_codec * codec,struct pipe_picture_desc * picture,void * bitstream_buf,unsigned * bitstream_buf_size)2924 int d3d12_video_encoder_get_encode_headers([[maybe_unused]] struct pipe_video_codec *codec,
2925                                            [[maybe_unused]] struct pipe_picture_desc *picture,
2926                                            [[maybe_unused]] void* bitstream_buf,
2927                                            [[maybe_unused]] unsigned *bitstream_buf_size)
2928 {
2929 #if (VIDEO_CODEC_H264ENC || VIDEO_CODEC_H265ENC)
2930    struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
2931    D3D12_VIDEO_SAMPLE srcTextureDesc = {};
2932    srcTextureDesc.Width = pD3D12Enc->base.width;
2933    srcTextureDesc.Height = pD3D12Enc->base.height;
2934    srcTextureDesc.Format.Format = d3d12_get_format(picture->input_format);
2935    if(!d3d12_video_encoder_update_current_encoder_config_state(pD3D12Enc, srcTextureDesc, picture))
2936       return EINVAL;
2937 
2938    if (!pD3D12Enc->m_upBitstreamBuilder) {
2939 #if VIDEO_CODEC_H264ENC
2940       if (u_reduce_video_profile(pD3D12Enc->base.profile) == PIPE_VIDEO_FORMAT_MPEG4_AVC)
2941          pD3D12Enc->m_upBitstreamBuilder = std::make_unique<d3d12_video_bitstream_builder_h264>();
2942 #endif
2943 #if VIDEO_CODEC_H265ENC
2944       if (u_reduce_video_profile(pD3D12Enc->base.profile) == PIPE_VIDEO_FORMAT_HEVC)
2945          pD3D12Enc->m_upBitstreamBuilder = std::make_unique<d3d12_video_bitstream_builder_hevc>();
2946 #endif
2947    }
2948    bool postEncodeHeadersNeeded = false;
2949    uint64_t preEncodeGeneratedHeadersByteSize = 0;
2950    std::vector<uint64_t> pWrittenCodecUnitsSizes;
2951    pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_sequence_header;
2952    d3d12_video_encoder_build_pre_encode_codec_headers(pD3D12Enc,
2953                                                       postEncodeHeadersNeeded,
2954                                                       preEncodeGeneratedHeadersByteSize,
2955                                                       pWrittenCodecUnitsSizes);
2956    if (preEncodeGeneratedHeadersByteSize > *bitstream_buf_size)
2957       return ENOMEM;
2958 
2959    *bitstream_buf_size = static_cast<unsigned>(pD3D12Enc->m_BitstreamHeadersBuffer.size());
2960    memcpy(bitstream_buf,
2961           pD3D12Enc->m_BitstreamHeadersBuffer.data(),
2962           *bitstream_buf_size);
2963    return 0;
2964 #else
2965    return ENOTSUP;
2966 #endif
2967 }
2968 
2969 template void
2970 d3d12_video_encoder_update_picparams_region_of_interest_qpmap(struct d3d12_video_encoder *pD3D12Enc,
2971                                                               const struct pipe_enc_roi *roi_config,
2972                                                               int32_t min_delta_qp,
2973                                                               int32_t max_delta_qp,
2974                                                               std::vector<int16_t>& pQPMap);
2975 
2976 template void
2977 d3d12_video_encoder_update_picparams_region_of_interest_qpmap(struct d3d12_video_encoder *pD3D12Enc,
2978                                                               const struct pipe_enc_roi *roi_config,
2979                                                               int32_t min_delta_qp,
2980                                                               int32_t max_delta_qp,
2981                                                               std::vector<int8_t>& pQPMap);
2982 
2983 template<typename T>
2984 void
d3d12_video_encoder_update_picparams_region_of_interest_qpmap(struct d3d12_video_encoder * pD3D12Enc,const struct pipe_enc_roi * roi_config,int32_t min_delta_qp,int32_t max_delta_qp,std::vector<T> & pQPMap)2985 d3d12_video_encoder_update_picparams_region_of_interest_qpmap(struct d3d12_video_encoder *pD3D12Enc,
2986                                                               const struct pipe_enc_roi *roi_config,
2987                                                               int32_t min_delta_qp,
2988                                                               int32_t max_delta_qp,
2989                                                               std::vector<T>& pQPMap)
2990 {
2991    static_assert(ARRAY_SIZE(roi_config->region) == PIPE_ENC_ROI_REGION_NUM_MAX);
2992    assert(roi_config->num > 0);
2993    assert(roi_config->num <= PIPE_ENC_ROI_REGION_NUM_MAX);
2994    assert(min_delta_qp < 0);
2995    assert(max_delta_qp > 0);
2996 
2997    // Set all the QP blocks with zero QP Delta, then only fill in the regions that have a non-zero delta value
2998    uint32_t QPMapRegionPixelsSize = pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.QPMapRegionPixelsSize;
2999    size_t pic_width_in_qpmap_block_units = static_cast<size_t>(std::ceil(pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width /
3000       static_cast<double>(QPMapRegionPixelsSize)));
3001    size_t pic_height_in_qpmap_block_units = static_cast<size_t>(std::ceil(pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height /
3002       static_cast<double>(QPMapRegionPixelsSize)));
3003    size_t total_picture_qpmap_block_units = pic_width_in_qpmap_block_units * pic_height_in_qpmap_block_units;
3004    pQPMap.resize(total_picture_qpmap_block_units, 0u);
3005 
3006    // Loop in reverse for priority of overlapping regions as per p_video_state roi parameter docs
3007    for (int32_t i = (roi_config->num - 1); i >= 0 ; i--)
3008    {
3009       auto& cur_region = roi_config->region[i];
3010       if (cur_region.valid)
3011       {
3012          uint32_t bucket_start_block_x = cur_region.x / QPMapRegionPixelsSize;
3013          uint32_t bucket_start_block_y = cur_region.y / QPMapRegionPixelsSize;
3014          uint32_t bucket_end_block_x = static_cast<uint32_t>(std::ceil((cur_region.x + cur_region.width) / static_cast<double>(QPMapRegionPixelsSize)) - 1);
3015          uint32_t bucket_end_block_y = static_cast<uint32_t>(std::ceil((cur_region.y + cur_region.height) / static_cast<double>(QPMapRegionPixelsSize)) - 1);
3016          for (uint32_t i = bucket_start_block_x; i <= bucket_end_block_x; i++)
3017             for (uint32_t j = bucket_start_block_y; j <= bucket_end_block_y; j++)
3018                pQPMap[(j * pic_width_in_qpmap_block_units) + i] = static_cast<T>(CLAMP(cur_region.qp_value, min_delta_qp, max_delta_qp));
3019       }
3020    }
3021 }
3022 
3023 int
d3d12_video_encoder_fence_wait(struct pipe_video_codec * codec,struct pipe_fence_handle * _fence,uint64_t timeout)3024 d3d12_video_encoder_fence_wait(struct pipe_video_codec *codec,
3025                                struct pipe_fence_handle *_fence,
3026                                uint64_t timeout)
3027 {
3028    struct d3d12_fence *fence = (struct d3d12_fence *) _fence;
3029    assert(fence);
3030 
3031    bool wait_res =
3032       d3d12_video_encoder_sync_completion(codec, fence->cmdqueue_fence, fence->value, timeout);
3033 
3034    // Return semantics based on p_video_codec interface
3035    // ret == 0 -> Encode in progress
3036    // ret != 0 -> Encode completed
3037    return wait_res ? 1 : 0;
3038 }
3039