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