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