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