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