1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © Microsoft Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "d3d12_common.h"
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include "d3d12_util.h"
27bf215546Sopenharmony_ci#include "d3d12_context.h"
28bf215546Sopenharmony_ci#include "d3d12_format.h"
29bf215546Sopenharmony_ci#include "d3d12_resource.h"
30bf215546Sopenharmony_ci#include "d3d12_screen.h"
31bf215546Sopenharmony_ci#include "d3d12_surface.h"
32bf215546Sopenharmony_ci#include "d3d12_video_enc.h"
33bf215546Sopenharmony_ci#include "d3d12_video_enc_h264.h"
34bf215546Sopenharmony_ci#include "d3d12_video_buffer.h"
35bf215546Sopenharmony_ci#include "d3d12_video_texture_array_dpb_manager.h"
36bf215546Sopenharmony_ci#include "d3d12_video_array_of_textures_dpb_manager.h"
37bf215546Sopenharmony_ci#include "d3d12_video_encoder_references_manager_h264.h"
38bf215546Sopenharmony_ci#include "d3d12_residency.h"
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_ci#include "vl/vl_video_buffer.h"
41bf215546Sopenharmony_ci#include "util/format/u_format.h"
42bf215546Sopenharmony_ci#include "util/u_inlines.h"
43bf215546Sopenharmony_ci#include "util/u_memory.h"
44bf215546Sopenharmony_ci#include "util/u_video.h"
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci#include <cmath>
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_ci/**
49bf215546Sopenharmony_ci * flush any outstanding command buffers to the hardware
50bf215546Sopenharmony_ci * should be called before a video_buffer is acessed by the gallium frontend again
51bf215546Sopenharmony_ci */
52bf215546Sopenharmony_civoid
53bf215546Sopenharmony_cid3d12_video_encoder_flush(struct pipe_video_codec *codec)
54bf215546Sopenharmony_ci{
55bf215546Sopenharmony_ci   struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
56bf215546Sopenharmony_ci   assert(pD3D12Enc);
57bf215546Sopenharmony_ci   assert(pD3D12Enc->m_spD3D12VideoDevice);
58bf215546Sopenharmony_ci   assert(pD3D12Enc->m_spEncodeCommandQueue);
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_ci   // Flush buffer_subdata batch and Wait the m_spEncodeCommandQueue for GPU upload completion
61bf215546Sopenharmony_ci   // before recording EncodeFrame below.
62bf215546Sopenharmony_ci   struct pipe_fence_handle *completion_fence = NULL;
63bf215546Sopenharmony_ci   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");
64bf215546Sopenharmony_ci   pD3D12Enc->base.context->flush(pD3D12Enc->base.context, &completion_fence, PIPE_FLUSH_ASYNC | PIPE_FLUSH_HINT_FINISH);
65bf215546Sopenharmony_ci   assert(completion_fence);
66bf215546Sopenharmony_ci   struct d3d12_fence *casted_completion_fence = d3d12_fence(completion_fence);
67bf215546Sopenharmony_ci   pD3D12Enc->m_spEncodeCommandQueue->Wait(casted_completion_fence->cmdqueue_fence, casted_completion_fence->value);
68bf215546Sopenharmony_ci   pD3D12Enc->m_pD3D12Screen->base.fence_reference(&pD3D12Enc->m_pD3D12Screen->base, &completion_fence, NULL);
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_ci   if (!pD3D12Enc->m_needsGPUFlush) {
71bf215546Sopenharmony_ci      debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush started. Nothing to flush, all up to date.\n");
72bf215546Sopenharmony_ci   } else {
73bf215546Sopenharmony_ci      debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush started. Will flush video queue work and CPU wait "
74bf215546Sopenharmony_ci                    "on fenceValue: %d\n",
75bf215546Sopenharmony_ci                    pD3D12Enc->m_fenceValue);
76bf215546Sopenharmony_ci
77bf215546Sopenharmony_ci      HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->GetDeviceRemovedReason();
78bf215546Sopenharmony_ci      if (hr != S_OK) {
79bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush"
80bf215546Sopenharmony_ci                         " - D3D12Device was removed BEFORE commandlist "
81bf215546Sopenharmony_ci                         "execution with HR %x.\n",
82bf215546Sopenharmony_ci                         hr);
83bf215546Sopenharmony_ci         goto flush_fail;
84bf215546Sopenharmony_ci      }
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_ci      // Close and execute command list and wait for idle on CPU blocking
87bf215546Sopenharmony_ci      // this method before resetting list and allocator for next submission.
88bf215546Sopenharmony_ci
89bf215546Sopenharmony_ci      if (pD3D12Enc->m_transitionsBeforeCloseCmdList.size() > 0) {
90bf215546Sopenharmony_ci         pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(pD3D12Enc->m_transitionsBeforeCloseCmdList.size(),
91bf215546Sopenharmony_ci                                                           pD3D12Enc->m_transitionsBeforeCloseCmdList.data());
92bf215546Sopenharmony_ci         pD3D12Enc->m_transitionsBeforeCloseCmdList.clear();
93bf215546Sopenharmony_ci      }
94bf215546Sopenharmony_ci
95bf215546Sopenharmony_ci      hr = pD3D12Enc->m_spEncodeCommandList->Close();
96bf215546Sopenharmony_ci      if (FAILED(hr)) {
97bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush - Can't close command list with HR %x\n", hr);
98bf215546Sopenharmony_ci         goto flush_fail;
99bf215546Sopenharmony_ci      }
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_ci      ID3D12CommandList *ppCommandLists[1] = { pD3D12Enc->m_spEncodeCommandList.Get() };
102bf215546Sopenharmony_ci      pD3D12Enc->m_spEncodeCommandQueue->ExecuteCommandLists(1, ppCommandLists);
103bf215546Sopenharmony_ci      pD3D12Enc->m_spEncodeCommandQueue->Signal(pD3D12Enc->m_spFence.Get(), pD3D12Enc->m_fenceValue);
104bf215546Sopenharmony_ci      pD3D12Enc->m_spFence->SetEventOnCompletion(pD3D12Enc->m_fenceValue, nullptr);
105bf215546Sopenharmony_ci      debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush - ExecuteCommandLists finished on signal with "
106bf215546Sopenharmony_ci                    "fenceValue: %d\n",
107bf215546Sopenharmony_ci                    pD3D12Enc->m_fenceValue);
108bf215546Sopenharmony_ci
109bf215546Sopenharmony_ci      hr = pD3D12Enc->m_spCommandAllocator->Reset();
110bf215546Sopenharmony_ci      if (FAILED(hr)) {
111bf215546Sopenharmony_ci         debug_printf(
112bf215546Sopenharmony_ci            "[d3d12_video_encoder] d3d12_video_encoder_flush - resetting ID3D12CommandAllocator failed with HR %x\n",
113bf215546Sopenharmony_ci            hr);
114bf215546Sopenharmony_ci         goto flush_fail;
115bf215546Sopenharmony_ci      }
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci      hr = pD3D12Enc->m_spEncodeCommandList->Reset(pD3D12Enc->m_spCommandAllocator.Get());
118bf215546Sopenharmony_ci      if (FAILED(hr)) {
119bf215546Sopenharmony_ci         debug_printf(
120bf215546Sopenharmony_ci            "[d3d12_video_encoder] d3d12_video_encoder_flush - resetting ID3D12GraphicsCommandList failed with HR %x\n",
121bf215546Sopenharmony_ci            hr);
122bf215546Sopenharmony_ci         goto flush_fail;
123bf215546Sopenharmony_ci      }
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci      // Validate device was not removed
126bf215546Sopenharmony_ci      hr = pD3D12Enc->m_pD3D12Screen->dev->GetDeviceRemovedReason();
127bf215546Sopenharmony_ci      if (hr != S_OK) {
128bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush"
129bf215546Sopenharmony_ci                         " - D3D12Device was removed AFTER commandlist "
130bf215546Sopenharmony_ci                         "execution with HR %x, but wasn't before.\n",
131bf215546Sopenharmony_ci                         hr);
132bf215546Sopenharmony_ci         goto flush_fail;
133bf215546Sopenharmony_ci      }
134bf215546Sopenharmony_ci
135bf215546Sopenharmony_ci      debug_printf(
136bf215546Sopenharmony_ci         "[d3d12_video_encoder] d3d12_video_encoder_flush - GPU signaled execution finalized for fenceValue: %d\n",
137bf215546Sopenharmony_ci         pD3D12Enc->m_fenceValue);
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci      pD3D12Enc->m_fenceValue++;
140bf215546Sopenharmony_ci      pD3D12Enc->m_needsGPUFlush = false;
141bf215546Sopenharmony_ci   }
142bf215546Sopenharmony_ci   return;
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_ciflush_fail:
145bf215546Sopenharmony_ci   debug_printf("[d3d12_video_encoder] d3d12_video_encoder_flush failed for fenceValue: %d\n", pD3D12Enc->m_fenceValue);
146bf215546Sopenharmony_ci   assert(false);
147bf215546Sopenharmony_ci}
148bf215546Sopenharmony_ci
149bf215546Sopenharmony_ci/**
150bf215546Sopenharmony_ci * Destroys a d3d12_video_encoder
151bf215546Sopenharmony_ci * Call destroy_XX for applicable XX nested member types before deallocating
152bf215546Sopenharmony_ci * Destroy methods should check != nullptr on their input target argument as this method can be called as part of
153bf215546Sopenharmony_ci * cleanup from failure on the creation method
154bf215546Sopenharmony_ci */
155bf215546Sopenharmony_civoid
156bf215546Sopenharmony_cid3d12_video_encoder_destroy(struct pipe_video_codec *codec)
157bf215546Sopenharmony_ci{
158bf215546Sopenharmony_ci   if (codec == nullptr) {
159bf215546Sopenharmony_ci      return;
160bf215546Sopenharmony_ci   }
161bf215546Sopenharmony_ci
162bf215546Sopenharmony_ci   d3d12_video_encoder_flush(codec);   // Flush pending work before destroying.
163bf215546Sopenharmony_ci
164bf215546Sopenharmony_ci   struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
165bf215546Sopenharmony_ci
166bf215546Sopenharmony_ci   // Call d3d12_video_encoder dtor to make ComPtr and other member's destructors work
167bf215546Sopenharmony_ci   delete pD3D12Enc;
168bf215546Sopenharmony_ci}
169bf215546Sopenharmony_ci
170bf215546Sopenharmony_civoid
171bf215546Sopenharmony_cid3d12_video_encoder_update_picparams_tracking(struct d3d12_video_encoder *pD3D12Enc,
172bf215546Sopenharmony_ci                                              struct pipe_video_buffer *  srcTexture,
173bf215546Sopenharmony_ci                                              struct pipe_picture_desc *  picture)
174bf215546Sopenharmony_ci{
175bf215546Sopenharmony_ci   D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA currentPicParams =
176bf215546Sopenharmony_ci      d3d12_video_encoder_get_current_picture_param_settings(pD3D12Enc);
177bf215546Sopenharmony_ci
178bf215546Sopenharmony_ci   enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
179bf215546Sopenharmony_ci   bool bUsedAsReference = false;
180bf215546Sopenharmony_ci   switch (codec) {
181bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
182bf215546Sopenharmony_ci      {
183bf215546Sopenharmony_ci         d3d12_video_encoder_update_current_frame_pic_params_info_h264(pD3D12Enc, srcTexture, picture, currentPicParams, bUsedAsReference);
184bf215546Sopenharmony_ci      } break;
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci      default:
187bf215546Sopenharmony_ci      {
188bf215546Sopenharmony_ci         unreachable("Unsupported pipe_video_format");
189bf215546Sopenharmony_ci      } break;
190bf215546Sopenharmony_ci   }
191bf215546Sopenharmony_ci
192bf215546Sopenharmony_ci   pD3D12Enc->m_upDPBManager->begin_frame(currentPicParams, bUsedAsReference);
193bf215546Sopenharmony_ci}
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_cibool
196bf215546Sopenharmony_cid3d12_video_encoder_reconfigure_encoder_objects(struct d3d12_video_encoder *pD3D12Enc,
197bf215546Sopenharmony_ci                                                struct pipe_video_buffer *  srcTexture,
198bf215546Sopenharmony_ci                                                struct pipe_picture_desc *  picture)
199bf215546Sopenharmony_ci{
200bf215546Sopenharmony_ci   bool codecChanged =
201bf215546Sopenharmony_ci      ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_codec) != 0);
202bf215546Sopenharmony_ci   bool profileChanged =
203bf215546Sopenharmony_ci      ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_profile) != 0);
204bf215546Sopenharmony_ci   bool levelChanged =
205bf215546Sopenharmony_ci      ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_level) != 0);
206bf215546Sopenharmony_ci   bool codecConfigChanged =
207bf215546Sopenharmony_ci      ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_codec_config) != 0);
208bf215546Sopenharmony_ci   bool inputFormatChanged =
209bf215546Sopenharmony_ci      ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_input_format) != 0);
210bf215546Sopenharmony_ci   bool resolutionChanged =
211bf215546Sopenharmony_ci      ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_resolution) != 0);
212bf215546Sopenharmony_ci   bool rateControlChanged =
213bf215546Sopenharmony_ci      ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_rate_control) != 0);
214bf215546Sopenharmony_ci   bool slicesChanged =
215bf215546Sopenharmony_ci      ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_slices) != 0);
216bf215546Sopenharmony_ci   bool gopChanged =
217bf215546Sopenharmony_ci      ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_gop) != 0);
218bf215546Sopenharmony_ci   bool motionPrecisionLimitChanged = ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags &
219bf215546Sopenharmony_ci                                        d3d12_video_encoder_config_dirty_flag_motion_precision_limit) != 0);
220bf215546Sopenharmony_ci
221bf215546Sopenharmony_ci   // Events that that trigger a re-creation of the reference picture manager
222bf215546Sopenharmony_ci   // Stores codec agnostic textures so only input format, resolution and gop (num dpb references) affects this
223bf215546Sopenharmony_ci   if (!pD3D12Enc->m_upDPBManager
224bf215546Sopenharmony_ci       // || codecChanged
225bf215546Sopenharmony_ci       // || profileChanged
226bf215546Sopenharmony_ci       // || levelChanged
227bf215546Sopenharmony_ci       // || codecConfigChanged
228bf215546Sopenharmony_ci       || inputFormatChanged ||
229bf215546Sopenharmony_ci       resolutionChanged
230bf215546Sopenharmony_ci       // || rateControlChanged
231bf215546Sopenharmony_ci       // || slicesChanged
232bf215546Sopenharmony_ci       || gopChanged
233bf215546Sopenharmony_ci       // || motionPrecisionLimitChanged
234bf215546Sopenharmony_ci   ) {
235bf215546Sopenharmony_ci      if (!pD3D12Enc->m_upDPBManager) {
236bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] d3d12_video_encoder_reconfigure_encoder_objects - Creating Reference "
237bf215546Sopenharmony_ci                       "Pictures Manager for the first time\n");
238bf215546Sopenharmony_ci      } else {
239bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] Reconfiguration triggered -> Re-creating Reference Pictures Manager\n");
240bf215546Sopenharmony_ci      }
241bf215546Sopenharmony_ci
242bf215546Sopenharmony_ci      D3D12_RESOURCE_FLAGS resourceAllocFlags =
243bf215546Sopenharmony_ci         D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
244bf215546Sopenharmony_ci      bool     fArrayOfTextures = ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
245bf215546Sopenharmony_ci                                D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RECONSTRUCTED_FRAMES_REQUIRE_TEXTURE_ARRAYS) == 0);
246bf215546Sopenharmony_ci      uint32_t texturePoolSize  = d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc) +
247bf215546Sopenharmony_ci                                 1u;   // adding an extra slot as we also need to count the current frame output recon
248bf215546Sopenharmony_ci                                       // allocation along max reference frame allocations
249bf215546Sopenharmony_ci      assert(texturePoolSize < UINT16_MAX);
250bf215546Sopenharmony_ci      if (fArrayOfTextures) {
251bf215546Sopenharmony_ci         pD3D12Enc->m_upDPBStorageManager = std::make_unique<d3d12_array_of_textures_dpb_manager>(
252bf215546Sopenharmony_ci            static_cast<uint16_t>(texturePoolSize),
253bf215546Sopenharmony_ci            pD3D12Enc->m_pD3D12Screen->dev,
254bf215546Sopenharmony_ci            pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
255bf215546Sopenharmony_ci            pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
256bf215546Sopenharmony_ci            (D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE),
257bf215546Sopenharmony_ci            true,   // setNullSubresourcesOnAllZero - D3D12 Video Encode expects nullptr pSubresources if AoT,
258bf215546Sopenharmony_ci            pD3D12Enc->m_NodeMask,
259bf215546Sopenharmony_ci            /*use underlying pool, we can't reuse upper level allocations, need D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY*/
260bf215546Sopenharmony_ci            true);
261bf215546Sopenharmony_ci      } else {
262bf215546Sopenharmony_ci         pD3D12Enc->m_upDPBStorageManager = std::make_unique<d3d12_texture_array_dpb_manager>(
263bf215546Sopenharmony_ci            static_cast<uint16_t>(texturePoolSize),
264bf215546Sopenharmony_ci            pD3D12Enc->m_pD3D12Screen->dev,
265bf215546Sopenharmony_ci            pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
266bf215546Sopenharmony_ci            pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
267bf215546Sopenharmony_ci            resourceAllocFlags,
268bf215546Sopenharmony_ci            pD3D12Enc->m_NodeMask);
269bf215546Sopenharmony_ci      }
270bf215546Sopenharmony_ci      d3d12_video_encoder_create_reference_picture_manager(pD3D12Enc);
271bf215546Sopenharmony_ci   }
272bf215546Sopenharmony_ci
273bf215546Sopenharmony_ci   bool reCreatedEncoder = false;
274bf215546Sopenharmony_ci   // Events that that trigger a re-creation of the encoder
275bf215546Sopenharmony_ci   if (!pD3D12Enc->m_spVideoEncoder || codecChanged ||
276bf215546Sopenharmony_ci       profileChanged
277bf215546Sopenharmony_ci       // || levelChanged // Only affects encoder heap
278bf215546Sopenharmony_ci       || codecConfigChanged ||
279bf215546Sopenharmony_ci       inputFormatChanged
280bf215546Sopenharmony_ci       // || resolutionChanged // Only affects encoder heap
281bf215546Sopenharmony_ci       // Only re-create if there is NO SUPPORT for reconfiguring rateControl on the fly
282bf215546Sopenharmony_ci       || (rateControlChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
283bf215546Sopenharmony_ci                                   D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_RECONFIGURATION_AVAILABLE) ==
284bf215546Sopenharmony_ci                                  0 /*checking the flag is NOT set*/))
285bf215546Sopenharmony_ci       // Only re-create if there is NO SUPPORT for reconfiguring slices on the fly
286bf215546Sopenharmony_ci       || (slicesChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
287bf215546Sopenharmony_ci                              D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SUBREGION_LAYOUT_RECONFIGURATION_AVAILABLE) ==
288bf215546Sopenharmony_ci                             0 /*checking the flag is NOT set*/))
289bf215546Sopenharmony_ci       // Only re-create if there is NO SUPPORT for reconfiguring gop on the fly
290bf215546Sopenharmony_ci       || (gopChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
291bf215546Sopenharmony_ci                           D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SEQUENCE_GOP_RECONFIGURATION_AVAILABLE) ==
292bf215546Sopenharmony_ci                          0 /*checking the flag is NOT set*/)) ||
293bf215546Sopenharmony_ci       motionPrecisionLimitChanged) {
294bf215546Sopenharmony_ci      if (!pD3D12Enc->m_spVideoEncoder) {
295bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] d3d12_video_encoder_reconfigure_encoder_objects - Creating "
296bf215546Sopenharmony_ci                       "D3D12VideoEncoder for the first time\n");
297bf215546Sopenharmony_ci      } else {
298bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] Reconfiguration triggered -> Re-creating D3D12VideoEncoder\n");
299bf215546Sopenharmony_ci         reCreatedEncoder = true;
300bf215546Sopenharmony_ci      }
301bf215546Sopenharmony_ci
302bf215546Sopenharmony_ci      D3D12_VIDEO_ENCODER_DESC encoderDesc = { pD3D12Enc->m_NodeMask,
303bf215546Sopenharmony_ci                                               D3D12_VIDEO_ENCODER_FLAG_NONE,
304bf215546Sopenharmony_ci                                               pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc,
305bf215546Sopenharmony_ci                                               d3d12_video_encoder_get_current_profile_desc(pD3D12Enc),
306bf215546Sopenharmony_ci                                               pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
307bf215546Sopenharmony_ci                                               d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc),
308bf215546Sopenharmony_ci                                               pD3D12Enc->m_currentEncodeConfig.m_encoderMotionPrecisionLimit };
309bf215546Sopenharmony_ci
310bf215546Sopenharmony_ci      // Create encoder
311bf215546Sopenharmony_ci      HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CreateVideoEncoder(&encoderDesc,
312bf215546Sopenharmony_ci                                                             IID_PPV_ARGS(pD3D12Enc->m_spVideoEncoder.GetAddressOf()));
313bf215546Sopenharmony_ci      if (FAILED(hr)) {
314bf215546Sopenharmony_ci         debug_printf("CreateVideoEncoder failed with HR %x\n", hr);
315bf215546Sopenharmony_ci         return false;
316bf215546Sopenharmony_ci      }
317bf215546Sopenharmony_ci   }
318bf215546Sopenharmony_ci
319bf215546Sopenharmony_ci   bool reCreatedEncoderHeap = false;
320bf215546Sopenharmony_ci   // Events that that trigger a re-creation of the encoder heap
321bf215546Sopenharmony_ci   if (!pD3D12Enc->m_spVideoEncoderHeap || codecChanged || profileChanged ||
322bf215546Sopenharmony_ci       levelChanged
323bf215546Sopenharmony_ci       // || codecConfigChanged // Only affects encoder
324bf215546Sopenharmony_ci       || inputFormatChanged   // Might affect internal textures in the heap
325bf215546Sopenharmony_ci       || resolutionChanged
326bf215546Sopenharmony_ci       // Only re-create if there is NO SUPPORT for reconfiguring rateControl on the fly
327bf215546Sopenharmony_ci       || (rateControlChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
328bf215546Sopenharmony_ci                                   D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_RECONFIGURATION_AVAILABLE) ==
329bf215546Sopenharmony_ci                                  0 /*checking the flag is NOT set*/))
330bf215546Sopenharmony_ci       // Only re-create if there is NO SUPPORT for reconfiguring slices on the fly
331bf215546Sopenharmony_ci       || (slicesChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
332bf215546Sopenharmony_ci                              D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SUBREGION_LAYOUT_RECONFIGURATION_AVAILABLE) ==
333bf215546Sopenharmony_ci                             0 /*checking the flag is NOT set*/))
334bf215546Sopenharmony_ci       // Only re-create if there is NO SUPPORT for reconfiguring gop on the fly
335bf215546Sopenharmony_ci       || (gopChanged && ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
336bf215546Sopenharmony_ci                           D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SEQUENCE_GOP_RECONFIGURATION_AVAILABLE) ==
337bf215546Sopenharmony_ci                          0 /*checking the flag is NOT set*/))
338bf215546Sopenharmony_ci       // || motionPrecisionLimitChanged // Only affects encoder
339bf215546Sopenharmony_ci   ) {
340bf215546Sopenharmony_ci      if (!pD3D12Enc->m_spVideoEncoderHeap) {
341bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] d3d12_video_encoder_reconfigure_encoder_objects - Creating "
342bf215546Sopenharmony_ci                       "D3D12VideoEncoderHeap for the first time\n");
343bf215546Sopenharmony_ci      } else {
344bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] Reconfiguration triggered -> Re-creating D3D12VideoEncoderHeap\n");
345bf215546Sopenharmony_ci         reCreatedEncoderHeap = true;
346bf215546Sopenharmony_ci      }
347bf215546Sopenharmony_ci
348bf215546Sopenharmony_ci      D3D12_VIDEO_ENCODER_HEAP_DESC heapDesc = { pD3D12Enc->m_NodeMask,
349bf215546Sopenharmony_ci                                                 D3D12_VIDEO_ENCODER_HEAP_FLAG_NONE,
350bf215546Sopenharmony_ci                                                 pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc,
351bf215546Sopenharmony_ci                                                 d3d12_video_encoder_get_current_profile_desc(pD3D12Enc),
352bf215546Sopenharmony_ci                                                 d3d12_video_encoder_get_current_level_desc(pD3D12Enc),
353bf215546Sopenharmony_ci                                                 // resolution list count
354bf215546Sopenharmony_ci                                                 1,
355bf215546Sopenharmony_ci                                                 // resolution list
356bf215546Sopenharmony_ci                                                 &pD3D12Enc->m_currentEncodeConfig.m_currentResolution };
357bf215546Sopenharmony_ci
358bf215546Sopenharmony_ci      // Create encoder heap
359bf215546Sopenharmony_ci      HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CreateVideoEncoderHeap(&heapDesc,
360bf215546Sopenharmony_ci                                                                           IID_PPV_ARGS(pD3D12Enc->m_spVideoEncoderHeap.GetAddressOf()));
361bf215546Sopenharmony_ci      if (FAILED(hr)) {
362bf215546Sopenharmony_ci         debug_printf("CreateVideoEncoderHeap failed with HR %x\n", hr);
363bf215546Sopenharmony_ci         return false;
364bf215546Sopenharmony_ci      }
365bf215546Sopenharmony_ci   }
366bf215546Sopenharmony_ci
367bf215546Sopenharmony_ci   // If on-the-fly reconfiguration happened without object recreation, set
368bf215546Sopenharmony_ci   // D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_*_CHANGED reconfiguration flags in EncodeFrame
369bf215546Sopenharmony_ci   if (rateControlChanged &&
370bf215546Sopenharmony_ci       ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
371bf215546Sopenharmony_ci         D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_RECONFIGURATION_AVAILABLE) !=
372bf215546Sopenharmony_ci        0 /*checking if the flag it's actually set*/) &&
373bf215546Sopenharmony_ci       (pD3D12Enc->m_fenceValue > 1) && (!reCreatedEncoder || !reCreatedEncoderHeap)) {
374bf215546Sopenharmony_ci      pD3D12Enc->m_currentEncodeConfig.m_seqFlags |= D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_RATE_CONTROL_CHANGE;
375bf215546Sopenharmony_ci   }
376bf215546Sopenharmony_ci
377bf215546Sopenharmony_ci   if (slicesChanged &&
378bf215546Sopenharmony_ci       ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
379bf215546Sopenharmony_ci         D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SUBREGION_LAYOUT_RECONFIGURATION_AVAILABLE) !=
380bf215546Sopenharmony_ci        0 /*checking if the flag it's actually set*/) &&
381bf215546Sopenharmony_ci       (pD3D12Enc->m_fenceValue > 1) && (!reCreatedEncoder || !reCreatedEncoderHeap)) {
382bf215546Sopenharmony_ci      pD3D12Enc->m_currentEncodeConfig.m_seqFlags |= D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_SUBREGION_LAYOUT_CHANGE;
383bf215546Sopenharmony_ci   }
384bf215546Sopenharmony_ci
385bf215546Sopenharmony_ci   if (gopChanged &&
386bf215546Sopenharmony_ci       ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
387bf215546Sopenharmony_ci         D3D12_VIDEO_ENCODER_SUPPORT_FLAG_SEQUENCE_GOP_RECONFIGURATION_AVAILABLE) !=
388bf215546Sopenharmony_ci        0 /*checking if the flag it's actually set*/) &&
389bf215546Sopenharmony_ci       (pD3D12Enc->m_fenceValue > 1) && (!reCreatedEncoder || !reCreatedEncoderHeap)) {
390bf215546Sopenharmony_ci      pD3D12Enc->m_currentEncodeConfig.m_seqFlags |= D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_GOP_SEQUENCE_CHANGE;
391bf215546Sopenharmony_ci   }
392bf215546Sopenharmony_ci   return true;
393bf215546Sopenharmony_ci}
394bf215546Sopenharmony_ci
395bf215546Sopenharmony_civoid
396bf215546Sopenharmony_cid3d12_video_encoder_create_reference_picture_manager(struct d3d12_video_encoder *pD3D12Enc)
397bf215546Sopenharmony_ci{
398bf215546Sopenharmony_ci   enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
399bf215546Sopenharmony_ci   switch (codec) {
400bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
401bf215546Sopenharmony_ci      {
402bf215546Sopenharmony_ci         bool gopHasPFrames =
403bf215546Sopenharmony_ci            (pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures.PPicturePeriod > 0) &&
404bf215546Sopenharmony_ci            ((pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures.GOPLength == 0) ||
405bf215546Sopenharmony_ci             (pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures.PPicturePeriod <
406bf215546Sopenharmony_ci              pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures.GOPLength));
407bf215546Sopenharmony_ci
408bf215546Sopenharmony_ci         pD3D12Enc->m_upDPBManager = std::make_unique<d3d12_video_encoder_references_manager_h264>(
409bf215546Sopenharmony_ci            gopHasPFrames,
410bf215546Sopenharmony_ci            *pD3D12Enc->m_upDPBStorageManager,
411bf215546Sopenharmony_ci            // Max number of frames to be used as a reference, without counting the current recon picture
412bf215546Sopenharmony_ci            d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc)
413bf215546Sopenharmony_ci         );
414bf215546Sopenharmony_ci
415bf215546Sopenharmony_ci         pD3D12Enc->m_upBitstreamBuilder = std::make_unique<d3d12_video_bitstream_builder_h264>();
416bf215546Sopenharmony_ci      } break;
417bf215546Sopenharmony_ci
418bf215546Sopenharmony_ci      default:
419bf215546Sopenharmony_ci      {
420bf215546Sopenharmony_ci         unreachable("Unsupported pipe_video_format");
421bf215546Sopenharmony_ci      } break;
422bf215546Sopenharmony_ci   }
423bf215546Sopenharmony_ci}
424bf215546Sopenharmony_ci
425bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA
426bf215546Sopenharmony_cid3d12_video_encoder_get_current_slice_param_settings(struct d3d12_video_encoder *pD3D12Enc)
427bf215546Sopenharmony_ci{
428bf215546Sopenharmony_ci   enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
429bf215546Sopenharmony_ci   switch (codec) {
430bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
431bf215546Sopenharmony_ci      {
432bf215546Sopenharmony_ci         D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA subregionData = {};
433bf215546Sopenharmony_ci         if (pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode !=
434bf215546Sopenharmony_ci             D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME) {
435bf215546Sopenharmony_ci            subregionData.pSlicesPartition_H264 =
436bf215546Sopenharmony_ci               &pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigDesc.m_SlicesPartition_H264;
437bf215546Sopenharmony_ci            subregionData.DataSize = sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES);
438bf215546Sopenharmony_ci         }
439bf215546Sopenharmony_ci         return subregionData;
440bf215546Sopenharmony_ci      } break;
441bf215546Sopenharmony_ci
442bf215546Sopenharmony_ci      default:
443bf215546Sopenharmony_ci      {
444bf215546Sopenharmony_ci         unreachable("Unsupported pipe_video_format");
445bf215546Sopenharmony_ci      } break;
446bf215546Sopenharmony_ci   }
447bf215546Sopenharmony_ci}
448bf215546Sopenharmony_ci
449bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA
450bf215546Sopenharmony_cid3d12_video_encoder_get_current_picture_param_settings(struct d3d12_video_encoder *pD3D12Enc)
451bf215546Sopenharmony_ci{
452bf215546Sopenharmony_ci   enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
453bf215546Sopenharmony_ci   switch (codec) {
454bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
455bf215546Sopenharmony_ci      {
456bf215546Sopenharmony_ci         D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curPicParamsData = {};
457bf215546Sopenharmony_ci         curPicParamsData.pH264PicData = &pD3D12Enc->m_currentEncodeConfig.m_encoderPicParamsDesc.m_H264PicData;
458bf215546Sopenharmony_ci         curPicParamsData.DataSize     = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderPicParamsDesc.m_H264PicData);
459bf215546Sopenharmony_ci         return curPicParamsData;
460bf215546Sopenharmony_ci      } break;
461bf215546Sopenharmony_ci
462bf215546Sopenharmony_ci      default:
463bf215546Sopenharmony_ci      {
464bf215546Sopenharmony_ci         unreachable("Unsupported pipe_video_format");
465bf215546Sopenharmony_ci      } break;
466bf215546Sopenharmony_ci   }
467bf215546Sopenharmony_ci}
468bf215546Sopenharmony_ci
469bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_RATE_CONTROL
470bf215546Sopenharmony_cid3d12_video_encoder_get_current_rate_control_settings(struct d3d12_video_encoder *pD3D12Enc)
471bf215546Sopenharmony_ci{
472bf215546Sopenharmony_ci   D3D12_VIDEO_ENCODER_RATE_CONTROL curRateControlDesc = {};
473bf215546Sopenharmony_ci   curRateControlDesc.Mode            = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode;
474bf215546Sopenharmony_ci   curRateControlDesc.Flags           = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags;
475bf215546Sopenharmony_ci   curRateControlDesc.TargetFrameRate = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_FrameRate;
476bf215546Sopenharmony_ci
477bf215546Sopenharmony_ci   switch (pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode) {
478bf215546Sopenharmony_ci      case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_ABSOLUTE_QP_MAP:
479bf215546Sopenharmony_ci      {
480bf215546Sopenharmony_ci         curRateControlDesc.ConfigParams.pConfiguration_CQP = nullptr;
481bf215546Sopenharmony_ci         curRateControlDesc.ConfigParams.DataSize           = 0;
482bf215546Sopenharmony_ci      } break;
483bf215546Sopenharmony_ci      case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP:
484bf215546Sopenharmony_ci      {
485bf215546Sopenharmony_ci         curRateControlDesc.ConfigParams.pConfiguration_CQP =
486bf215546Sopenharmony_ci            &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP;
487bf215546Sopenharmony_ci         curRateControlDesc.ConfigParams.DataSize =
488bf215546Sopenharmony_ci            sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CQP);
489bf215546Sopenharmony_ci      } break;
490bf215546Sopenharmony_ci      case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CBR:
491bf215546Sopenharmony_ci      {
492bf215546Sopenharmony_ci         curRateControlDesc.ConfigParams.pConfiguration_CBR =
493bf215546Sopenharmony_ci            &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR;
494bf215546Sopenharmony_ci         curRateControlDesc.ConfigParams.DataSize =
495bf215546Sopenharmony_ci            sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR);
496bf215546Sopenharmony_ci      } break;
497bf215546Sopenharmony_ci      case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_VBR:
498bf215546Sopenharmony_ci      {
499bf215546Sopenharmony_ci         curRateControlDesc.ConfigParams.pConfiguration_VBR =
500bf215546Sopenharmony_ci            &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR;
501bf215546Sopenharmony_ci         curRateControlDesc.ConfigParams.DataSize =
502bf215546Sopenharmony_ci            sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR);
503bf215546Sopenharmony_ci      } break;
504bf215546Sopenharmony_ci      case D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR:
505bf215546Sopenharmony_ci      {
506bf215546Sopenharmony_ci         curRateControlDesc.ConfigParams.pConfiguration_QVBR =
507bf215546Sopenharmony_ci            &pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR;
508bf215546Sopenharmony_ci         curRateControlDesc.ConfigParams.DataSize =
509bf215546Sopenharmony_ci            sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR);
510bf215546Sopenharmony_ci      } break;
511bf215546Sopenharmony_ci      default:
512bf215546Sopenharmony_ci      {
513bf215546Sopenharmony_ci         unreachable("Unsupported D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE");
514bf215546Sopenharmony_ci      } break;
515bf215546Sopenharmony_ci   }
516bf215546Sopenharmony_ci
517bf215546Sopenharmony_ci   return curRateControlDesc;
518bf215546Sopenharmony_ci}
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_LEVEL_SETTING
521bf215546Sopenharmony_cid3d12_video_encoder_get_current_level_desc(struct d3d12_video_encoder *pD3D12Enc)
522bf215546Sopenharmony_ci{
523bf215546Sopenharmony_ci   enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
524bf215546Sopenharmony_ci   switch (codec) {
525bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
526bf215546Sopenharmony_ci      {
527bf215546Sopenharmony_ci         D3D12_VIDEO_ENCODER_LEVEL_SETTING curLevelDesc = {};
528bf215546Sopenharmony_ci         curLevelDesc.pH264LevelSetting = &pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting;
529bf215546Sopenharmony_ci         curLevelDesc.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderLevelDesc.m_H264LevelSetting);
530bf215546Sopenharmony_ci         return curLevelDesc;
531bf215546Sopenharmony_ci      } break;
532bf215546Sopenharmony_ci
533bf215546Sopenharmony_ci      default:
534bf215546Sopenharmony_ci      {
535bf215546Sopenharmony_ci         unreachable("Unsupported pipe_video_format");
536bf215546Sopenharmony_ci      } break;
537bf215546Sopenharmony_ci   }
538bf215546Sopenharmony_ci}
539bf215546Sopenharmony_ci
540bf215546Sopenharmony_ciuint32_t
541bf215546Sopenharmony_cid3d12_video_encoder_build_codec_headers(struct d3d12_video_encoder *pD3D12Enc)
542bf215546Sopenharmony_ci{
543bf215546Sopenharmony_ci   enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
544bf215546Sopenharmony_ci   switch (codec) {
545bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
546bf215546Sopenharmony_ci      {
547bf215546Sopenharmony_ci         return d3d12_video_encoder_build_codec_headers_h264(pD3D12Enc);
548bf215546Sopenharmony_ci
549bf215546Sopenharmony_ci      } break;
550bf215546Sopenharmony_ci
551bf215546Sopenharmony_ci      default:
552bf215546Sopenharmony_ci      {
553bf215546Sopenharmony_ci         unreachable("Unsupported pipe_video_format");
554bf215546Sopenharmony_ci      } break;
555bf215546Sopenharmony_ci   }
556bf215546Sopenharmony_ci   return 0u;
557bf215546Sopenharmony_ci}
558bf215546Sopenharmony_ci
559bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE
560bf215546Sopenharmony_cid3d12_video_encoder_get_current_gop_desc(struct d3d12_video_encoder *pD3D12Enc)
561bf215546Sopenharmony_ci{
562bf215546Sopenharmony_ci   enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
563bf215546Sopenharmony_ci   switch (codec) {
564bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
565bf215546Sopenharmony_ci      {
566bf215546Sopenharmony_ci         D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE curGOPDesc = {};
567bf215546Sopenharmony_ci         curGOPDesc.pH264GroupOfPictures =
568bf215546Sopenharmony_ci            &pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures;
569bf215546Sopenharmony_ci         curGOPDesc.DataSize = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures);
570bf215546Sopenharmony_ci         return curGOPDesc;
571bf215546Sopenharmony_ci      } break;
572bf215546Sopenharmony_ci
573bf215546Sopenharmony_ci      default:
574bf215546Sopenharmony_ci      {
575bf215546Sopenharmony_ci         unreachable("Unsupported pipe_video_format");
576bf215546Sopenharmony_ci      } break;
577bf215546Sopenharmony_ci   }
578bf215546Sopenharmony_ci}
579bf215546Sopenharmony_ci
580bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_CODEC_CONFIGURATION
581bf215546Sopenharmony_cid3d12_video_encoder_get_current_codec_config_desc(struct d3d12_video_encoder *pD3D12Enc)
582bf215546Sopenharmony_ci{
583bf215546Sopenharmony_ci   enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
584bf215546Sopenharmony_ci   switch (codec) {
585bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
586bf215546Sopenharmony_ci      {
587bf215546Sopenharmony_ci         D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION codecConfigDesc = {};
588bf215546Sopenharmony_ci         codecConfigDesc.pH264Config = &pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_H264Config;
589bf215546Sopenharmony_ci         codecConfigDesc.DataSize =
590bf215546Sopenharmony_ci            sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_H264Config);
591bf215546Sopenharmony_ci         return codecConfigDesc;
592bf215546Sopenharmony_ci      } break;
593bf215546Sopenharmony_ci
594bf215546Sopenharmony_ci      default:
595bf215546Sopenharmony_ci      {
596bf215546Sopenharmony_ci         unreachable("Unsupported pipe_video_format");
597bf215546Sopenharmony_ci      } break;
598bf215546Sopenharmony_ci   }
599bf215546Sopenharmony_ci}
600bf215546Sopenharmony_ci
601bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_CODEC
602bf215546Sopenharmony_cid3d12_video_encoder_get_current_codec(struct d3d12_video_encoder *pD3D12Enc)
603bf215546Sopenharmony_ci{
604bf215546Sopenharmony_ci   enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
605bf215546Sopenharmony_ci   switch (codec) {
606bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
607bf215546Sopenharmony_ci      {
608bf215546Sopenharmony_ci         return D3D12_VIDEO_ENCODER_CODEC_H264;
609bf215546Sopenharmony_ci      } break;
610bf215546Sopenharmony_ci      default:
611bf215546Sopenharmony_ci      {
612bf215546Sopenharmony_ci         unreachable("Unsupported pipe_video_format");
613bf215546Sopenharmony_ci      } break;
614bf215546Sopenharmony_ci   }
615bf215546Sopenharmony_ci}
616bf215546Sopenharmony_ci
617bf215546Sopenharmony_ci///
618bf215546Sopenharmony_ci/// Call d3d12_video_encoder_query_d3d12_driver_caps and see if any optional feature requested
619bf215546Sopenharmony_ci/// is not supported, disable it, query again until finding a negotiated cap/feature set
620bf215546Sopenharmony_ci/// Note that with fallbacks, the upper layer will not get exactly the encoding seetings they requested
621bf215546Sopenharmony_ci/// but for very particular settings it's better to continue with warnings than failing the whole encoding process
622bf215546Sopenharmony_ci///
623bf215546Sopenharmony_cibool d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(struct d3d12_video_encoder *pD3D12Enc, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT &capEncoderSupportData) {
624bf215546Sopenharmony_ci
625bf215546Sopenharmony_ci   ///
626bf215546Sopenharmony_ci   /// Check for general support
627bf215546Sopenharmony_ci   /// Check for validation errors (some drivers return general support but also validation errors anyways, work around for those unexpected cases)
628bf215546Sopenharmony_ci   ///
629bf215546Sopenharmony_ci
630bf215546Sopenharmony_ci   bool configSupported = d3d12_video_encoder_query_d3d12_driver_caps(pD3D12Enc, /*inout*/ capEncoderSupportData)
631bf215546Sopenharmony_ci    && (((capEncoderSupportData.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_GENERAL_SUPPORT_OK) != 0)
632bf215546Sopenharmony_ci                        && (capEncoderSupportData.ValidationFlags == D3D12_VIDEO_ENCODER_VALIDATION_FLAG_NONE));
633bf215546Sopenharmony_ci
634bf215546Sopenharmony_ci   ///
635bf215546Sopenharmony_ci   /// If rate control config is not supported, try falling back and check for caps again
636bf215546Sopenharmony_ci   ///
637bf215546Sopenharmony_ci
638bf215546Sopenharmony_ci   if ((capEncoderSupportData.ValidationFlags & (D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RATE_CONTROL_CONFIGURATION_NOT_SUPPORTED | D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RATE_CONTROL_MODE_NOT_SUPPORTED)) != 0) {
639bf215546Sopenharmony_ci
640bf215546Sopenharmony_ci      if (D3D12_VIDEO_ENC_FALLBACK_RATE_CONTROL_CONFIG){ // Check if fallback mode is enabled, or we should just fail without support
641bf215546Sopenharmony_ci
642bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] WARNING: Requested rate control is not supported, trying fallback to unsetting optional features\n");
643bf215546Sopenharmony_ci
644bf215546Sopenharmony_ci         bool isRequestingVBVSizesSupported = ((capEncoderSupportData.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_VBV_SIZE_CONFIG_AVAILABLE) != 0);
645bf215546Sopenharmony_ci         bool isClientRequestingVBVSizes = ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES) != 0);
646bf215546Sopenharmony_ci
647bf215546Sopenharmony_ci         if(isClientRequestingVBVSizes && !isRequestingVBVSizesSupported) {
648bf215546Sopenharmony_ci            debug_printf("[d3d12_video_encoder] WARNING: Requested D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES with VBVCapacity (bits): %" PRIu64 " and InitialVBVFullness (bits) %" PRIu64 " is not supported, will continue encoding unsetting this feature as fallback.\n",
649bf215546Sopenharmony_ci                  pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.VBVCapacity,
650bf215546Sopenharmony_ci                  pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.InitialVBVFullness);
651bf215546Sopenharmony_ci
652bf215546Sopenharmony_ci            pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags &= ~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
653bf215546Sopenharmony_ci            pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.VBVCapacity = 0;
654bf215546Sopenharmony_ci            pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_CBR.InitialVBVFullness = 0;
655bf215546Sopenharmony_ci         }
656bf215546Sopenharmony_ci
657bf215546Sopenharmony_ci         bool isRequestingPeakFrameSizeSupported = ((capEncoderSupportData.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_MAX_FRAME_SIZE_AVAILABLE) != 0);
658bf215546Sopenharmony_ci         bool isClientRequestingPeakFrameSize = ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE) != 0);
659bf215546Sopenharmony_ci
660bf215546Sopenharmony_ci         if(isClientRequestingPeakFrameSize && !isRequestingPeakFrameSizeSupported) {
661bf215546Sopenharmony_ci            debug_printf("[d3d12_video_encoder] WARNING: Requested D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE with MaxFrameBitSize %" PRIu64 " but the feature is not supported, will continue encoding unsetting this feature as fallback.\n",
662bf215546Sopenharmony_ci               pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.MaxFrameBitSize);
663bf215546Sopenharmony_ci
664bf215546Sopenharmony_ci            pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags &= ~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
665bf215546Sopenharmony_ci            pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_VBR.MaxFrameBitSize = 0;
666bf215546Sopenharmony_ci         }
667bf215546Sopenharmony_ci
668bf215546Sopenharmony_ci         ///
669bf215546Sopenharmony_ci         /// Try fallback configuration
670bf215546Sopenharmony_ci         ///
671bf215546Sopenharmony_ci         configSupported = d3d12_video_encoder_query_d3d12_driver_caps(pD3D12Enc, /*inout*/ capEncoderSupportData)
672bf215546Sopenharmony_ci          && (((capEncoderSupportData.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_GENERAL_SUPPORT_OK) != 0)
673bf215546Sopenharmony_ci                           && (capEncoderSupportData.ValidationFlags == D3D12_VIDEO_ENCODER_VALIDATION_FLAG_NONE));
674bf215546Sopenharmony_ci
675bf215546Sopenharmony_ci      } else {
676bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] WARNING: Requested rate control is not supported. To continue with a fallback, must enable the OS environment variable D3D12_VIDEO_ENC_FALLBACK_RATE_CONTROL_CONFIG\n");
677bf215546Sopenharmony_ci      }
678bf215546Sopenharmony_ci   }
679bf215546Sopenharmony_ci
680bf215546Sopenharmony_ci   if(!configSupported) {
681bf215546Sopenharmony_ci      debug_printf("[d3d12_video_encoder] Cap negotiation failed, see more details below:\n");
682bf215546Sopenharmony_ci
683bf215546Sopenharmony_ci      if ((capEncoderSupportData.ValidationFlags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_CODEC_NOT_SUPPORTED) != 0) {
684bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] Requested codec is not supported\n");
685bf215546Sopenharmony_ci      }
686bf215546Sopenharmony_ci
687bf215546Sopenharmony_ci      if ((capEncoderSupportData.ValidationFlags &
688bf215546Sopenharmony_ci         D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RESOLUTION_NOT_SUPPORTED_IN_LIST) != 0) {
689bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] Requested resolution is not supported\n");
690bf215546Sopenharmony_ci      }
691bf215546Sopenharmony_ci
692bf215546Sopenharmony_ci      if ((capEncoderSupportData.ValidationFlags &
693bf215546Sopenharmony_ci         D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RATE_CONTROL_CONFIGURATION_NOT_SUPPORTED) != 0) {
694bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] Requested bitrate or rc config is not supported\n");
695bf215546Sopenharmony_ci      }
696bf215546Sopenharmony_ci
697bf215546Sopenharmony_ci      if ((capEncoderSupportData.ValidationFlags &
698bf215546Sopenharmony_ci         D3D12_VIDEO_ENCODER_VALIDATION_FLAG_CODEC_CONFIGURATION_NOT_SUPPORTED) != 0) {
699bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] Requested codec config is not supported\n");
700bf215546Sopenharmony_ci      }
701bf215546Sopenharmony_ci
702bf215546Sopenharmony_ci      if ((capEncoderSupportData.ValidationFlags &
703bf215546Sopenharmony_ci         D3D12_VIDEO_ENCODER_VALIDATION_FLAG_RATE_CONTROL_MODE_NOT_SUPPORTED) != 0) {
704bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] Requested rate control mode is not supported\n");
705bf215546Sopenharmony_ci      }
706bf215546Sopenharmony_ci
707bf215546Sopenharmony_ci      if ((capEncoderSupportData.ValidationFlags &
708bf215546Sopenharmony_ci         D3D12_VIDEO_ENCODER_VALIDATION_FLAG_INTRA_REFRESH_MODE_NOT_SUPPORTED) != 0) {
709bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] Requested intra refresh config is not supported\n");
710bf215546Sopenharmony_ci      }
711bf215546Sopenharmony_ci
712bf215546Sopenharmony_ci      if ((capEncoderSupportData.ValidationFlags &
713bf215546Sopenharmony_ci         D3D12_VIDEO_ENCODER_VALIDATION_FLAG_SUBREGION_LAYOUT_MODE_NOT_SUPPORTED) != 0) {
714bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] Requested subregion layout mode is not supported\n");
715bf215546Sopenharmony_ci      }
716bf215546Sopenharmony_ci
717bf215546Sopenharmony_ci      if ((capEncoderSupportData.ValidationFlags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_INPUT_FORMAT_NOT_SUPPORTED) !=
718bf215546Sopenharmony_ci         0) {
719bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] Requested input dxgi format is not supported\n");
720bf215546Sopenharmony_ci      }
721bf215546Sopenharmony_ci   }
722bf215546Sopenharmony_ci
723bf215546Sopenharmony_ci   return configSupported;
724bf215546Sopenharmony_ci}
725bf215546Sopenharmony_ci
726bf215546Sopenharmony_cibool d3d12_video_encoder_query_d3d12_driver_caps(struct d3d12_video_encoder *pD3D12Enc, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT &capEncoderSupportData) {
727bf215546Sopenharmony_ci   capEncoderSupportData.NodeIndex                                = pD3D12Enc->m_NodeIndex;
728bf215546Sopenharmony_ci   capEncoderSupportData.Codec                                    = d3d12_video_encoder_get_current_codec(pD3D12Enc);
729bf215546Sopenharmony_ci   capEncoderSupportData.InputFormat            = pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format;
730bf215546Sopenharmony_ci   capEncoderSupportData.RateControl            = d3d12_video_encoder_get_current_rate_control_settings(pD3D12Enc);
731bf215546Sopenharmony_ci   capEncoderSupportData.IntraRefresh           = pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh.Mode;
732bf215546Sopenharmony_ci   capEncoderSupportData.SubregionFrameEncoding = pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode;
733bf215546Sopenharmony_ci   capEncoderSupportData.ResolutionsListCount   = 1;
734bf215546Sopenharmony_ci   capEncoderSupportData.pResolutionList        = &pD3D12Enc->m_currentEncodeConfig.m_currentResolution;
735bf215546Sopenharmony_ci   capEncoderSupportData.CodecGopSequence       = d3d12_video_encoder_get_current_gop_desc(pD3D12Enc);
736bf215546Sopenharmony_ci   capEncoderSupportData.MaxReferenceFramesInDPB = d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc);
737bf215546Sopenharmony_ci   capEncoderSupportData.CodecConfiguration = d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc);
738bf215546Sopenharmony_ci
739bf215546Sopenharmony_ci   enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
740bf215546Sopenharmony_ci   switch (codec) {
741bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
742bf215546Sopenharmony_ci      {
743bf215546Sopenharmony_ci         capEncoderSupportData.SuggestedProfile.pH264Profile =
744bf215546Sopenharmony_ci            &pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_H264Profile;
745bf215546Sopenharmony_ci         capEncoderSupportData.SuggestedProfile.DataSize =
746bf215546Sopenharmony_ci            sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderSuggestedProfileDesc.m_H264Profile);
747bf215546Sopenharmony_ci         capEncoderSupportData.SuggestedLevel.pH264LevelSetting =
748bf215546Sopenharmony_ci            &pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_H264LevelSetting;
749bf215546Sopenharmony_ci         capEncoderSupportData.SuggestedLevel.DataSize =
750bf215546Sopenharmony_ci            sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_encoderLevelSuggestedDesc.m_H264LevelSetting);
751bf215546Sopenharmony_ci      } break;
752bf215546Sopenharmony_ci
753bf215546Sopenharmony_ci      default:
754bf215546Sopenharmony_ci      {
755bf215546Sopenharmony_ci         unreachable("Unsupported pipe_video_format");
756bf215546Sopenharmony_ci      } break;
757bf215546Sopenharmony_ci   }
758bf215546Sopenharmony_ci
759bf215546Sopenharmony_ci   // prepare inout storage for the resolution dependent result.
760bf215546Sopenharmony_ci   capEncoderSupportData.pResolutionDependentSupport =
761bf215546Sopenharmony_ci      &pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps;
762bf215546Sopenharmony_ci
763bf215546Sopenharmony_ci   HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_SUPPORT,
764bf215546Sopenharmony_ci                                                                         &capEncoderSupportData,
765bf215546Sopenharmony_ci                                                                         sizeof(capEncoderSupportData));
766bf215546Sopenharmony_ci   if (FAILED(hr)) {
767bf215546Sopenharmony_ci      debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
768bf215546Sopenharmony_ci      return false;
769bf215546Sopenharmony_ci   }
770bf215546Sopenharmony_ci   pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags    = capEncoderSupportData.SupportFlags;
771bf215546Sopenharmony_ci   pD3D12Enc->m_currentEncodeCapabilities.m_ValidationFlags = capEncoderSupportData.ValidationFlags;
772bf215546Sopenharmony_ci   return true;
773bf215546Sopenharmony_ci}
774bf215546Sopenharmony_ci
775bf215546Sopenharmony_cibool d3d12_video_encoder_check_subregion_mode_support(struct d3d12_video_encoder *pD3D12Enc,
776bf215546Sopenharmony_ci                                    D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedSlicesMode
777bf215546Sopenharmony_ci   )
778bf215546Sopenharmony_ci{
779bf215546Sopenharmony_ci   D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE capDataSubregionLayout = { };
780bf215546Sopenharmony_ci   capDataSubregionLayout.NodeIndex = pD3D12Enc->m_NodeIndex;
781bf215546Sopenharmony_ci   capDataSubregionLayout.Codec = d3d12_video_encoder_get_current_codec(pD3D12Enc);
782bf215546Sopenharmony_ci   capDataSubregionLayout.Profile = d3d12_video_encoder_get_current_profile_desc(pD3D12Enc);
783bf215546Sopenharmony_ci   capDataSubregionLayout.Level = d3d12_video_encoder_get_current_level_desc(pD3D12Enc);
784bf215546Sopenharmony_ci   capDataSubregionLayout.SubregionMode = requestedSlicesMode;
785bf215546Sopenharmony_ci   HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE, &capDataSubregionLayout, sizeof(capDataSubregionLayout));
786bf215546Sopenharmony_ci   if (FAILED(hr)) {
787bf215546Sopenharmony_ci      debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
788bf215546Sopenharmony_ci      return false;
789bf215546Sopenharmony_ci   }
790bf215546Sopenharmony_ci   return capDataSubregionLayout.IsSupported;
791bf215546Sopenharmony_ci}
792bf215546Sopenharmony_ci
793bf215546Sopenharmony_ciD3D12_VIDEO_ENCODER_PROFILE_DESC
794bf215546Sopenharmony_cid3d12_video_encoder_get_current_profile_desc(struct d3d12_video_encoder *pD3D12Enc)
795bf215546Sopenharmony_ci{
796bf215546Sopenharmony_ci   enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
797bf215546Sopenharmony_ci   switch (codec) {
798bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
799bf215546Sopenharmony_ci      {
800bf215546Sopenharmony_ci         D3D12_VIDEO_ENCODER_PROFILE_DESC curProfDesc = {};
801bf215546Sopenharmony_ci         curProfDesc.pH264Profile = &pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile;
802bf215546Sopenharmony_ci         curProfDesc.DataSize     = sizeof(pD3D12Enc->m_currentEncodeConfig.m_encoderProfileDesc.m_H264Profile);
803bf215546Sopenharmony_ci         return curProfDesc;
804bf215546Sopenharmony_ci      } break;
805bf215546Sopenharmony_ci
806bf215546Sopenharmony_ci      default:
807bf215546Sopenharmony_ci      {
808bf215546Sopenharmony_ci         unreachable("Unsupported pipe_video_format");
809bf215546Sopenharmony_ci      } break;
810bf215546Sopenharmony_ci   }
811bf215546Sopenharmony_ci}
812bf215546Sopenharmony_ci
813bf215546Sopenharmony_ciuint32_t
814bf215546Sopenharmony_cid3d12_video_encoder_get_current_max_dpb_capacity(struct d3d12_video_encoder *pD3D12Enc)
815bf215546Sopenharmony_ci{
816bf215546Sopenharmony_ci   return pD3D12Enc->base.max_references;
817bf215546Sopenharmony_ci}
818bf215546Sopenharmony_ci
819bf215546Sopenharmony_cibool
820bf215546Sopenharmony_cid3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encoder *pD3D12Enc,
821bf215546Sopenharmony_ci                                                        struct pipe_video_buffer *  srcTexture,
822bf215546Sopenharmony_ci                                                        struct pipe_picture_desc *  picture)
823bf215546Sopenharmony_ci{
824bf215546Sopenharmony_ci   enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
825bf215546Sopenharmony_ci   switch (codec) {
826bf215546Sopenharmony_ci      case PIPE_VIDEO_FORMAT_MPEG4_AVC:
827bf215546Sopenharmony_ci      {
828bf215546Sopenharmony_ci         return d3d12_video_encoder_update_current_encoder_config_state_h264(pD3D12Enc, srcTexture, picture);
829bf215546Sopenharmony_ci      } break;
830bf215546Sopenharmony_ci
831bf215546Sopenharmony_ci      default:
832bf215546Sopenharmony_ci      {
833bf215546Sopenharmony_ci         unreachable("Unsupported pipe_video_format");
834bf215546Sopenharmony_ci      } break;
835bf215546Sopenharmony_ci   }
836bf215546Sopenharmony_ci}
837bf215546Sopenharmony_ci
838bf215546Sopenharmony_cibool
839bf215546Sopenharmony_cid3d12_video_encoder_create_command_objects(struct d3d12_video_encoder *pD3D12Enc)
840bf215546Sopenharmony_ci{
841bf215546Sopenharmony_ci   assert(pD3D12Enc->m_spD3D12VideoDevice);
842bf215546Sopenharmony_ci
843bf215546Sopenharmony_ci   D3D12_COMMAND_QUEUE_DESC commandQueueDesc = { D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE };
844bf215546Sopenharmony_ci   HRESULT                  hr               = pD3D12Enc->m_pD3D12Screen->dev->CreateCommandQueue(
845bf215546Sopenharmony_ci      &commandQueueDesc,
846bf215546Sopenharmony_ci      IID_PPV_ARGS(pD3D12Enc->m_spEncodeCommandQueue.GetAddressOf()));
847bf215546Sopenharmony_ci   if (FAILED(hr)) {
848bf215546Sopenharmony_ci      debug_printf("[d3d12_video_encoder] d3d12_video_encoder_create_command_objects - Call to CreateCommandQueue "
849bf215546Sopenharmony_ci                      "failed with HR %x\n",
850bf215546Sopenharmony_ci                      hr);
851bf215546Sopenharmony_ci      return false;
852bf215546Sopenharmony_ci   }
853bf215546Sopenharmony_ci
854bf215546Sopenharmony_ci   hr = pD3D12Enc->m_pD3D12Screen->dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&pD3D12Enc->m_spFence));
855bf215546Sopenharmony_ci   if (FAILED(hr)) {
856bf215546Sopenharmony_ci      debug_printf(
857bf215546Sopenharmony_ci         "[d3d12_video_encoder] d3d12_video_encoder_create_command_objects - Call to CreateFence failed with HR %x\n",
858bf215546Sopenharmony_ci         hr);
859bf215546Sopenharmony_ci      return false;
860bf215546Sopenharmony_ci   }
861bf215546Sopenharmony_ci
862bf215546Sopenharmony_ci   hr = pD3D12Enc->m_pD3D12Screen->dev->CreateCommandAllocator(
863bf215546Sopenharmony_ci      D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE,
864bf215546Sopenharmony_ci      IID_PPV_ARGS(pD3D12Enc->m_spCommandAllocator.GetAddressOf()));
865bf215546Sopenharmony_ci   if (FAILED(hr)) {
866bf215546Sopenharmony_ci      debug_printf("[d3d12_video_encoder] d3d12_video_encoder_create_command_objects - Call to "
867bf215546Sopenharmony_ci                      "CreateCommandAllocator failed with HR %x\n",
868bf215546Sopenharmony_ci                      hr);
869bf215546Sopenharmony_ci      return false;
870bf215546Sopenharmony_ci   }
871bf215546Sopenharmony_ci
872bf215546Sopenharmony_ci   hr =
873bf215546Sopenharmony_ci      pD3D12Enc->m_pD3D12Screen->dev->CreateCommandList(0,
874bf215546Sopenharmony_ci                                                        D3D12_COMMAND_LIST_TYPE_VIDEO_ENCODE,
875bf215546Sopenharmony_ci                                                        pD3D12Enc->m_spCommandAllocator.Get(),
876bf215546Sopenharmony_ci                                                        nullptr,
877bf215546Sopenharmony_ci                                                        IID_PPV_ARGS(pD3D12Enc->m_spEncodeCommandList.GetAddressOf()));
878bf215546Sopenharmony_ci
879bf215546Sopenharmony_ci   if (FAILED(hr)) {
880bf215546Sopenharmony_ci      debug_printf("[d3d12_video_encoder] d3d12_video_encoder_create_command_objects - Call to CreateCommandList "
881bf215546Sopenharmony_ci                      "failed with HR %x\n",
882bf215546Sopenharmony_ci                      hr);
883bf215546Sopenharmony_ci      return false;
884bf215546Sopenharmony_ci   }
885bf215546Sopenharmony_ci
886bf215546Sopenharmony_ci   return true;
887bf215546Sopenharmony_ci}
888bf215546Sopenharmony_ci
889bf215546Sopenharmony_cistruct pipe_video_codec *
890bf215546Sopenharmony_cid3d12_video_encoder_create_encoder(struct pipe_context *context, const struct pipe_video_codec *codec)
891bf215546Sopenharmony_ci{
892bf215546Sopenharmony_ci   ///
893bf215546Sopenharmony_ci   /// Initialize d3d12_video_encoder
894bf215546Sopenharmony_ci   ///
895bf215546Sopenharmony_ci
896bf215546Sopenharmony_ci   // Not using new doesn't call ctor and the initializations in the class declaration are lost
897bf215546Sopenharmony_ci   struct d3d12_video_encoder *pD3D12Enc = new d3d12_video_encoder;
898bf215546Sopenharmony_ci
899bf215546Sopenharmony_ci   pD3D12Enc->base         = *codec;
900bf215546Sopenharmony_ci   pD3D12Enc->m_screen     = context->screen;
901bf215546Sopenharmony_ci   pD3D12Enc->base.context = context;
902bf215546Sopenharmony_ci   pD3D12Enc->base.width   = codec->width;
903bf215546Sopenharmony_ci   pD3D12Enc->base.height  = codec->height;
904bf215546Sopenharmony_ci   pD3D12Enc->base.max_references  = codec->max_references;
905bf215546Sopenharmony_ci   // Only fill methods that are supported by the d3d12 encoder, leaving null the rest (ie. encode_* / encode_macroblock)
906bf215546Sopenharmony_ci   pD3D12Enc->base.destroy          = d3d12_video_encoder_destroy;
907bf215546Sopenharmony_ci   pD3D12Enc->base.begin_frame      = d3d12_video_encoder_begin_frame;
908bf215546Sopenharmony_ci   pD3D12Enc->base.encode_bitstream = d3d12_video_encoder_encode_bitstream;
909bf215546Sopenharmony_ci   pD3D12Enc->base.end_frame        = d3d12_video_encoder_end_frame;
910bf215546Sopenharmony_ci   pD3D12Enc->base.flush            = d3d12_video_encoder_flush;
911bf215546Sopenharmony_ci   pD3D12Enc->base.get_feedback     = d3d12_video_encoder_get_feedback;
912bf215546Sopenharmony_ci
913bf215546Sopenharmony_ci   struct d3d12_context *pD3D12Ctx = (struct d3d12_context *) context;
914bf215546Sopenharmony_ci   pD3D12Enc->m_pD3D12Screen       = d3d12_screen(pD3D12Ctx->base.screen);
915bf215546Sopenharmony_ci
916bf215546Sopenharmony_ci   if (FAILED(pD3D12Enc->m_pD3D12Screen->dev->QueryInterface(
917bf215546Sopenharmony_ci          IID_PPV_ARGS(pD3D12Enc->m_spD3D12VideoDevice.GetAddressOf())))) {
918bf215546Sopenharmony_ci      debug_printf(
919bf215546Sopenharmony_ci         "[d3d12_video_encoder] d3d12_video_encoder_create_encoder - D3D12 Device has no Video encode support\n");
920bf215546Sopenharmony_ci      goto failed;
921bf215546Sopenharmony_ci   }
922bf215546Sopenharmony_ci
923bf215546Sopenharmony_ci   if (!d3d12_video_encoder_create_command_objects(pD3D12Enc)) {
924bf215546Sopenharmony_ci      debug_printf("[d3d12_video_encoder] d3d12_video_encoder_create_encoder - Failure on "
925bf215546Sopenharmony_ci                      "d3d12_video_encoder_create_command_objects\n");
926bf215546Sopenharmony_ci      goto failed;
927bf215546Sopenharmony_ci   }
928bf215546Sopenharmony_ci
929bf215546Sopenharmony_ci   return &pD3D12Enc->base;
930bf215546Sopenharmony_ci
931bf215546Sopenharmony_cifailed:
932bf215546Sopenharmony_ci   if (pD3D12Enc != nullptr) {
933bf215546Sopenharmony_ci      d3d12_video_encoder_destroy((struct pipe_video_codec *) pD3D12Enc);
934bf215546Sopenharmony_ci   }
935bf215546Sopenharmony_ci
936bf215546Sopenharmony_ci   return nullptr;
937bf215546Sopenharmony_ci}
938bf215546Sopenharmony_ci
939bf215546Sopenharmony_cibool
940bf215546Sopenharmony_cid3d12_video_encoder_prepare_output_buffers(struct d3d12_video_encoder *pD3D12Enc,
941bf215546Sopenharmony_ci                                           struct pipe_video_buffer *  srcTexture,
942bf215546Sopenharmony_ci                                           struct pipe_picture_desc *  picture)
943bf215546Sopenharmony_ci{
944bf215546Sopenharmony_ci   pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.NodeIndex = pD3D12Enc->m_NodeIndex;
945bf215546Sopenharmony_ci   pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.Codec =
946bf215546Sopenharmony_ci      pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc;
947bf215546Sopenharmony_ci   pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.Profile =
948bf215546Sopenharmony_ci      d3d12_video_encoder_get_current_profile_desc(pD3D12Enc);
949bf215546Sopenharmony_ci   pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.InputFormat =
950bf215546Sopenharmony_ci      pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format;
951bf215546Sopenharmony_ci   pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.PictureTargetResolution =
952bf215546Sopenharmony_ci      pD3D12Enc->m_currentEncodeConfig.m_currentResolution;
953bf215546Sopenharmony_ci
954bf215546Sopenharmony_ci   HRESULT hr = pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(
955bf215546Sopenharmony_ci      D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS,
956bf215546Sopenharmony_ci      &pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps,
957bf215546Sopenharmony_ci      sizeof(pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps));
958bf215546Sopenharmony_ci
959bf215546Sopenharmony_ci   if (FAILED(hr)) {
960bf215546Sopenharmony_ci      debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
961bf215546Sopenharmony_ci      return false;
962bf215546Sopenharmony_ci   }
963bf215546Sopenharmony_ci
964bf215546Sopenharmony_ci   if (!pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.IsSupported) {
965bf215546Sopenharmony_ci      debug_printf("[d3d12_video_encoder] D3D12_FEATURE_VIDEO_ENCODER_RESOURCE_REQUIREMENTS arguments are not supported.\n");
966bf215546Sopenharmony_ci      return false;
967bf215546Sopenharmony_ci   }
968bf215546Sopenharmony_ci
969bf215546Sopenharmony_ci   d3d12_video_encoder_calculate_metadata_resolved_buffer_size(
970bf215546Sopenharmony_ci      pD3D12Enc->m_currentEncodeCapabilities.m_MaxSlicesInOutput,
971bf215546Sopenharmony_ci      pD3D12Enc->m_currentEncodeCapabilities.m_resolvedLayoutMetadataBufferRequiredSize);
972bf215546Sopenharmony_ci
973bf215546Sopenharmony_ci   D3D12_HEAP_PROPERTIES Properties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
974bf215546Sopenharmony_ci   if ((pD3D12Enc->m_spResolvedMetadataBuffer == nullptr) ||
975bf215546Sopenharmony_ci       (GetDesc(pD3D12Enc->m_spResolvedMetadataBuffer.Get()).Width <
976bf215546Sopenharmony_ci        pD3D12Enc->m_currentEncodeCapabilities.m_resolvedLayoutMetadataBufferRequiredSize)) {
977bf215546Sopenharmony_ci      CD3DX12_RESOURCE_DESC resolvedMetadataBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(
978bf215546Sopenharmony_ci         pD3D12Enc->m_currentEncodeCapabilities.m_resolvedLayoutMetadataBufferRequiredSize);
979bf215546Sopenharmony_ci
980bf215546Sopenharmony_ci      HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CreateCommittedResource(
981bf215546Sopenharmony_ci         &Properties,
982bf215546Sopenharmony_ci         D3D12_HEAP_FLAG_NONE,
983bf215546Sopenharmony_ci         &resolvedMetadataBufferDesc,
984bf215546Sopenharmony_ci         D3D12_RESOURCE_STATE_COMMON,
985bf215546Sopenharmony_ci         nullptr,
986bf215546Sopenharmony_ci         IID_PPV_ARGS(pD3D12Enc->m_spResolvedMetadataBuffer.GetAddressOf()));
987bf215546Sopenharmony_ci
988bf215546Sopenharmony_ci      if (FAILED(hr)) {
989bf215546Sopenharmony_ci         debug_printf("CreateCommittedResource failed with HR %x\n", hr);
990bf215546Sopenharmony_ci         return false;
991bf215546Sopenharmony_ci      }
992bf215546Sopenharmony_ci   }
993bf215546Sopenharmony_ci
994bf215546Sopenharmony_ci   if ((pD3D12Enc->m_spMetadataOutputBuffer == nullptr) ||
995bf215546Sopenharmony_ci       (GetDesc(pD3D12Enc->m_spMetadataOutputBuffer.Get()).Width <
996bf215546Sopenharmony_ci        pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.MaxEncoderOutputMetadataBufferSize)) {
997bf215546Sopenharmony_ci      CD3DX12_RESOURCE_DESC metadataBufferDesc = CD3DX12_RESOURCE_DESC::Buffer(
998bf215546Sopenharmony_ci         pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.MaxEncoderOutputMetadataBufferSize);
999bf215546Sopenharmony_ci
1000bf215546Sopenharmony_ci      HRESULT hr = pD3D12Enc->m_pD3D12Screen->dev->CreateCommittedResource(
1001bf215546Sopenharmony_ci         &Properties,
1002bf215546Sopenharmony_ci         D3D12_HEAP_FLAG_NONE,
1003bf215546Sopenharmony_ci         &metadataBufferDesc,
1004bf215546Sopenharmony_ci         D3D12_RESOURCE_STATE_COMMON,
1005bf215546Sopenharmony_ci         nullptr,
1006bf215546Sopenharmony_ci         IID_PPV_ARGS(pD3D12Enc->m_spMetadataOutputBuffer.GetAddressOf()));
1007bf215546Sopenharmony_ci
1008bf215546Sopenharmony_ci      if (FAILED(hr)) {
1009bf215546Sopenharmony_ci         debug_printf("CreateCommittedResource failed with HR %x\n", hr);
1010bf215546Sopenharmony_ci         return false;
1011bf215546Sopenharmony_ci      }
1012bf215546Sopenharmony_ci   }
1013bf215546Sopenharmony_ci   return true;
1014bf215546Sopenharmony_ci}
1015bf215546Sopenharmony_ci
1016bf215546Sopenharmony_cibool
1017bf215546Sopenharmony_cid3d12_video_encoder_reconfigure_session(struct d3d12_video_encoder *pD3D12Enc,
1018bf215546Sopenharmony_ci                                        struct pipe_video_buffer *  srcTexture,
1019bf215546Sopenharmony_ci                                        struct pipe_picture_desc *  picture)
1020bf215546Sopenharmony_ci{
1021bf215546Sopenharmony_ci   assert(pD3D12Enc->m_spD3D12VideoDevice);
1022bf215546Sopenharmony_ci   if(!d3d12_video_encoder_update_current_encoder_config_state(pD3D12Enc, srcTexture, picture)) {
1023bf215546Sopenharmony_ci      debug_printf("d3d12_video_encoder_update_current_encoder_config_state failed!\n");
1024bf215546Sopenharmony_ci      return false;
1025bf215546Sopenharmony_ci   }
1026bf215546Sopenharmony_ci   if(!d3d12_video_encoder_reconfigure_encoder_objects(pD3D12Enc, srcTexture, picture)) {
1027bf215546Sopenharmony_ci      debug_printf("d3d12_video_encoder_reconfigure_encoder_objects failed!\n");
1028bf215546Sopenharmony_ci      return false;
1029bf215546Sopenharmony_ci   }
1030bf215546Sopenharmony_ci   d3d12_video_encoder_update_picparams_tracking(pD3D12Enc, srcTexture, picture);
1031bf215546Sopenharmony_ci   if(!d3d12_video_encoder_prepare_output_buffers(pD3D12Enc, srcTexture, picture)) {
1032bf215546Sopenharmony_ci      debug_printf("d3d12_video_encoder_prepare_output_buffers failed!\n");
1033bf215546Sopenharmony_ci      return false;
1034bf215546Sopenharmony_ci   }
1035bf215546Sopenharmony_ci   return true;
1036bf215546Sopenharmony_ci}
1037bf215546Sopenharmony_ci
1038bf215546Sopenharmony_ci/**
1039bf215546Sopenharmony_ci * start encoding of a new frame
1040bf215546Sopenharmony_ci */
1041bf215546Sopenharmony_civoid
1042bf215546Sopenharmony_cid3d12_video_encoder_begin_frame(struct pipe_video_codec * codec,
1043bf215546Sopenharmony_ci                                struct pipe_video_buffer *target,
1044bf215546Sopenharmony_ci                                struct pipe_picture_desc *picture)
1045bf215546Sopenharmony_ci{
1046bf215546Sopenharmony_ci   // Do nothing here. Initialize happens on encoder creation, re-config (if any) happens in
1047bf215546Sopenharmony_ci   // d3d12_video_encoder_encode_bitstream
1048bf215546Sopenharmony_ci   struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
1049bf215546Sopenharmony_ci   assert(pD3D12Enc);
1050bf215546Sopenharmony_ci   debug_printf("[d3d12_video_encoder] d3d12_video_encoder_begin_frame started for fenceValue: %d\n",
1051bf215546Sopenharmony_ci                 pD3D12Enc->m_fenceValue);
1052bf215546Sopenharmony_ci
1053bf215546Sopenharmony_ci   if (!d3d12_video_encoder_reconfigure_session(pD3D12Enc, target, picture)) {
1054bf215546Sopenharmony_ci      debug_printf("[d3d12_video_encoder] d3d12_video_encoder_begin_frame - Failure on "
1055bf215546Sopenharmony_ci                      "d3d12_video_encoder_reconfigure_session\n");
1056bf215546Sopenharmony_ci      goto fail;
1057bf215546Sopenharmony_ci   }
1058bf215546Sopenharmony_ci
1059bf215546Sopenharmony_ci   debug_printf("[d3d12_video_encoder] d3d12_video_encoder_begin_frame finalized for fenceValue: %d\n",
1060bf215546Sopenharmony_ci                 pD3D12Enc->m_fenceValue);
1061bf215546Sopenharmony_ci   return;
1062bf215546Sopenharmony_ci
1063bf215546Sopenharmony_cifail:
1064bf215546Sopenharmony_ci   debug_printf("[d3d12_video_encoder] d3d12_video_encoder_begin_frame failed for fenceValue: %d\n",
1065bf215546Sopenharmony_ci                pD3D12Enc->m_fenceValue);
1066bf215546Sopenharmony_ci   assert(false);
1067bf215546Sopenharmony_ci}
1068bf215546Sopenharmony_ci
1069bf215546Sopenharmony_civoid
1070bf215546Sopenharmony_cid3d12_video_encoder_calculate_metadata_resolved_buffer_size(uint32_t maxSliceNumber, size_t &bufferSize)
1071bf215546Sopenharmony_ci{
1072bf215546Sopenharmony_ci   bufferSize = sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA) +
1073bf215546Sopenharmony_ci                (maxSliceNumber * sizeof(D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA));
1074bf215546Sopenharmony_ci}
1075bf215546Sopenharmony_ci
1076bf215546Sopenharmony_ci// Returns the number of slices that the output will contain for fixed slicing modes
1077bf215546Sopenharmony_ci// and the maximum number of slices the output might contain for dynamic slicing modes (eg. max bytes per slice)
1078bf215546Sopenharmony_ciuint32_t
1079bf215546Sopenharmony_cid3d12_video_encoder_calculate_max_slices_count_in_output(
1080bf215546Sopenharmony_ci   D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE                          slicesMode,
1081bf215546Sopenharmony_ci   const D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES *slicesConfig,
1082bf215546Sopenharmony_ci   uint32_t                                                                 MaxSubregionsNumberFromCaps,
1083bf215546Sopenharmony_ci   D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC                              sequenceTargetResolution,
1084bf215546Sopenharmony_ci   uint32_t                                                                 SubregionBlockPixelsSize)
1085bf215546Sopenharmony_ci{
1086bf215546Sopenharmony_ci   uint32_t pic_width_in_subregion_units =
1087bf215546Sopenharmony_ci      static_cast<uint32_t>(std::ceil(sequenceTargetResolution.Width / static_cast<double>(SubregionBlockPixelsSize)));
1088bf215546Sopenharmony_ci   uint32_t pic_height_in_subregion_units =
1089bf215546Sopenharmony_ci      static_cast<uint32_t>(std::ceil(sequenceTargetResolution.Height / static_cast<double>(SubregionBlockPixelsSize)));
1090bf215546Sopenharmony_ci   uint32_t total_picture_subregion_units = pic_width_in_subregion_units * pic_height_in_subregion_units;
1091bf215546Sopenharmony_ci   uint32_t maxSlices                     = 0u;
1092bf215546Sopenharmony_ci   switch (slicesMode) {
1093bf215546Sopenharmony_ci      case D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME:
1094bf215546Sopenharmony_ci      {
1095bf215546Sopenharmony_ci         maxSlices = 1u;
1096bf215546Sopenharmony_ci      } break;
1097bf215546Sopenharmony_ci      case D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION:
1098bf215546Sopenharmony_ci      {
1099bf215546Sopenharmony_ci         maxSlices = MaxSubregionsNumberFromCaps;
1100bf215546Sopenharmony_ci      } break;
1101bf215546Sopenharmony_ci      case D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_SQUARE_UNITS_PER_SUBREGION_ROW_UNALIGNED:
1102bf215546Sopenharmony_ci      {
1103bf215546Sopenharmony_ci         maxSlices = static_cast<uint32_t>(
1104bf215546Sopenharmony_ci            std::ceil(total_picture_subregion_units / static_cast<double>(slicesConfig->NumberOfCodingUnitsPerSlice)));
1105bf215546Sopenharmony_ci      } break;
1106bf215546Sopenharmony_ci      case D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION:
1107bf215546Sopenharmony_ci      {
1108bf215546Sopenharmony_ci         maxSlices = static_cast<uint32_t>(
1109bf215546Sopenharmony_ci            std::ceil(pic_height_in_subregion_units / static_cast<double>(slicesConfig->NumberOfRowsPerSlice)));
1110bf215546Sopenharmony_ci      } break;
1111bf215546Sopenharmony_ci      case D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME:
1112bf215546Sopenharmony_ci      {
1113bf215546Sopenharmony_ci         maxSlices = slicesConfig->NumberOfSlicesPerFrame;
1114bf215546Sopenharmony_ci      } break;
1115bf215546Sopenharmony_ci      default:
1116bf215546Sopenharmony_ci      {
1117bf215546Sopenharmony_ci         unreachable("Unsupported D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE");
1118bf215546Sopenharmony_ci      } break;
1119bf215546Sopenharmony_ci   }
1120bf215546Sopenharmony_ci
1121bf215546Sopenharmony_ci   return maxSlices;
1122bf215546Sopenharmony_ci}
1123bf215546Sopenharmony_ci
1124bf215546Sopenharmony_ci/**
1125bf215546Sopenharmony_ci * encode a bitstream
1126bf215546Sopenharmony_ci */
1127bf215546Sopenharmony_civoid
1128bf215546Sopenharmony_cid3d12_video_encoder_encode_bitstream(struct pipe_video_codec * codec,
1129bf215546Sopenharmony_ci                                     struct pipe_video_buffer *source,
1130bf215546Sopenharmony_ci                                     struct pipe_resource *    destination,
1131bf215546Sopenharmony_ci                                     void **                   feedback)
1132bf215546Sopenharmony_ci{
1133bf215546Sopenharmony_ci   struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
1134bf215546Sopenharmony_ci   assert(pD3D12Enc);
1135bf215546Sopenharmony_ci   debug_printf("[d3d12_video_encoder] d3d12_video_encoder_encode_bitstream started for fenceValue: %d\n",
1136bf215546Sopenharmony_ci                 pD3D12Enc->m_fenceValue);
1137bf215546Sopenharmony_ci   assert(pD3D12Enc->m_spD3D12VideoDevice);
1138bf215546Sopenharmony_ci   assert(pD3D12Enc->m_spEncodeCommandQueue);
1139bf215546Sopenharmony_ci   assert(pD3D12Enc->m_pD3D12Screen);
1140bf215546Sopenharmony_ci
1141bf215546Sopenharmony_ci   struct d3d12_video_buffer *pInputVideoBuffer = (struct d3d12_video_buffer *) source;
1142bf215546Sopenharmony_ci   assert(pInputVideoBuffer);
1143bf215546Sopenharmony_ci   ID3D12Resource *pInputVideoD3D12Res        = d3d12_resource_resource(pInputVideoBuffer->texture);
1144bf215546Sopenharmony_ci   uint32_t        inputVideoD3D12Subresource = 0u;
1145bf215546Sopenharmony_ci
1146bf215546Sopenharmony_ci   struct d3d12_resource *pOutputBitstreamBuffer = (struct d3d12_resource *) destination;
1147bf215546Sopenharmony_ci   assert(pOutputBitstreamBuffer);
1148bf215546Sopenharmony_ci   ID3D12Resource *pOutputBufferD3D12Res = d3d12_resource_resource(pOutputBitstreamBuffer);
1149bf215546Sopenharmony_ci
1150bf215546Sopenharmony_ci   // Make them permanently resident for video use
1151bf215546Sopenharmony_ci   d3d12_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, pOutputBitstreamBuffer);
1152bf215546Sopenharmony_ci   d3d12_promote_to_permanent_residency(pD3D12Enc->m_pD3D12Screen, pInputVideoBuffer->texture);
1153bf215546Sopenharmony_ci
1154bf215546Sopenharmony_ci   ///
1155bf215546Sopenharmony_ci   /// Record Encode operation
1156bf215546Sopenharmony_ci   ///
1157bf215546Sopenharmony_ci
1158bf215546Sopenharmony_ci   ///
1159bf215546Sopenharmony_ci   /// pInputVideoD3D12Res and pOutputBufferD3D12Res are unwrapped from pipe_resource objects that are passed externally
1160bf215546Sopenharmony_ci   /// and could be tracked by pipe_context and have pending ops. Flush any work on them and transition to
1161bf215546Sopenharmony_ci   /// D3D12_RESOURCE_STATE_COMMON before issuing work in Video command queue below. After the video work is done in the
1162bf215546Sopenharmony_ci   /// GPU, transition back to D3D12_RESOURCE_STATE_COMMON
1163bf215546Sopenharmony_ci   ///
1164bf215546Sopenharmony_ci   /// Note that unlike the D3D12TranslationLayer codebase, the state tracker here doesn't (yet) have any kind of
1165bf215546Sopenharmony_ci   /// multi-queue support, so it wouldn't implicitly synchronize when trying to transition between a graphics op and a
1166bf215546Sopenharmony_ci   /// video op.
1167bf215546Sopenharmony_ci   ///
1168bf215546Sopenharmony_ci
1169bf215546Sopenharmony_ci   d3d12_transition_resource_state(
1170bf215546Sopenharmony_ci      d3d12_context(pD3D12Enc->base.context),
1171bf215546Sopenharmony_ci      pInputVideoBuffer->texture,   // d3d12_resource wrapper for pInputVideoD3D12Res
1172bf215546Sopenharmony_ci      D3D12_RESOURCE_STATE_COMMON,
1173bf215546Sopenharmony_ci      D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
1174bf215546Sopenharmony_ci   d3d12_transition_resource_state(d3d12_context(pD3D12Enc->base.context),
1175bf215546Sopenharmony_ci                                   pOutputBitstreamBuffer,   // d3d12_resource wrapped for pOutputBufferD3D12Res
1176bf215546Sopenharmony_ci                                   D3D12_RESOURCE_STATE_COMMON,
1177bf215546Sopenharmony_ci                                   D3D12_TRANSITION_FLAG_INVALIDATE_BINDINGS);
1178bf215546Sopenharmony_ci   d3d12_apply_resource_states(d3d12_context(pD3D12Enc->base.context), false);
1179bf215546Sopenharmony_ci
1180bf215546Sopenharmony_ci   d3d12_resource_wait_idle(d3d12_context(pD3D12Enc->base.context),
1181bf215546Sopenharmony_ci                            pInputVideoBuffer->texture,
1182bf215546Sopenharmony_ci                            false /*wantToWrite*/);
1183bf215546Sopenharmony_ci   d3d12_resource_wait_idle(d3d12_context(pD3D12Enc->base.context), pOutputBitstreamBuffer, true /*wantToWrite*/);
1184bf215546Sopenharmony_ci
1185bf215546Sopenharmony_ci   std::vector<D3D12_RESOURCE_BARRIER> rgCurrentFrameStateTransitions = {
1186bf215546Sopenharmony_ci      CD3DX12_RESOURCE_BARRIER::Transition(pInputVideoD3D12Res,
1187bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_COMMON,
1188bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ),
1189bf215546Sopenharmony_ci      CD3DX12_RESOURCE_BARRIER::Transition(pOutputBufferD3D12Res,
1190bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_COMMON,
1191bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE),
1192bf215546Sopenharmony_ci      CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_spMetadataOutputBuffer.Get(),
1193bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_COMMON,
1194bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE)
1195bf215546Sopenharmony_ci   };
1196bf215546Sopenharmony_ci
1197bf215546Sopenharmony_ci   pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(rgCurrentFrameStateTransitions.size(),
1198bf215546Sopenharmony_ci                                                     rgCurrentFrameStateTransitions.data());
1199bf215546Sopenharmony_ci
1200bf215546Sopenharmony_ci   D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE reconPicOutputTextureDesc =
1201bf215546Sopenharmony_ci      pD3D12Enc->m_upDPBManager->get_current_frame_recon_pic_output_allocation();
1202bf215546Sopenharmony_ci   D3D12_VIDEO_ENCODE_REFERENCE_FRAMES referenceFramesDescriptor =
1203bf215546Sopenharmony_ci      pD3D12Enc->m_upDPBManager->get_current_reference_frames();
1204bf215546Sopenharmony_ci   D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAGS picCtrlFlags = D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_NONE;
1205bf215546Sopenharmony_ci
1206bf215546Sopenharmony_ci   // Transition DPB reference pictures to read mode
1207bf215546Sopenharmony_ci   uint32_t                            maxReferences = d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc);
1208bf215546Sopenharmony_ci   std::vector<D3D12_RESOURCE_BARRIER> rgReferenceTransitions(maxReferences);
1209bf215546Sopenharmony_ci   if ((referenceFramesDescriptor.NumTexture2Ds > 0) ||
1210bf215546Sopenharmony_ci       (pD3D12Enc->m_upDPBManager->is_current_frame_used_as_reference())) {
1211bf215546Sopenharmony_ci      rgReferenceTransitions.clear();
1212bf215546Sopenharmony_ci      rgReferenceTransitions.reserve(maxReferences);
1213bf215546Sopenharmony_ci
1214bf215546Sopenharmony_ci      // Check if array of textures vs texture array
1215bf215546Sopenharmony_ci
1216bf215546Sopenharmony_ci      if (referenceFramesDescriptor.pSubresources == nullptr) {
1217bf215546Sopenharmony_ci
1218bf215546Sopenharmony_ci         // Array of resources mode for reference pictures
1219bf215546Sopenharmony_ci
1220bf215546Sopenharmony_ci         // Transition all subresources of each reference frame independent resource allocation
1221bf215546Sopenharmony_ci         for (uint32_t referenceIdx = 0; referenceIdx < referenceFramesDescriptor.NumTexture2Ds; referenceIdx++) {
1222bf215546Sopenharmony_ci            rgReferenceTransitions.push_back(
1223bf215546Sopenharmony_ci               CD3DX12_RESOURCE_BARRIER::Transition(referenceFramesDescriptor.ppTexture2Ds[referenceIdx],
1224bf215546Sopenharmony_ci                                                    D3D12_RESOURCE_STATE_COMMON,
1225bf215546Sopenharmony_ci                                                    D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ));
1226bf215546Sopenharmony_ci         }
1227bf215546Sopenharmony_ci
1228bf215546Sopenharmony_ci         // Transition all subresources the output recon pic independent resource allocation
1229bf215546Sopenharmony_ci         if (reconPicOutputTextureDesc.pReconstructedPicture != nullptr) {
1230bf215546Sopenharmony_ci            picCtrlFlags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_USED_AS_REFERENCE_PICTURE;
1231bf215546Sopenharmony_ci
1232bf215546Sopenharmony_ci            rgReferenceTransitions.push_back(
1233bf215546Sopenharmony_ci               CD3DX12_RESOURCE_BARRIER::Transition(reconPicOutputTextureDesc.pReconstructedPicture,
1234bf215546Sopenharmony_ci                                                    D3D12_RESOURCE_STATE_COMMON,
1235bf215546Sopenharmony_ci                                                    D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE));
1236bf215546Sopenharmony_ci         }
1237bf215546Sopenharmony_ci      } else if (referenceFramesDescriptor.NumTexture2Ds > 0) {
1238bf215546Sopenharmony_ci
1239bf215546Sopenharmony_ci         // texture array mode for reference pictures
1240bf215546Sopenharmony_ci
1241bf215546Sopenharmony_ci         // In Texture array mode, the dpb storage allocator uses the same texture array for all the input
1242bf215546Sopenharmony_ci         // reference pics in ppTexture2Ds and also for the pReconstructedPicture output allocations, just different
1243bf215546Sopenharmony_ci         // subresources.
1244bf215546Sopenharmony_ci
1245bf215546Sopenharmony_ci         CD3DX12_RESOURCE_DESC referencesTexArrayDesc(GetDesc(referenceFramesDescriptor.ppTexture2Ds[0]));
1246bf215546Sopenharmony_ci
1247bf215546Sopenharmony_ci         for (uint32_t referenceSubresource = 0; referenceSubresource < referencesTexArrayDesc.DepthOrArraySize;
1248bf215546Sopenharmony_ci              referenceSubresource++) {
1249bf215546Sopenharmony_ci
1250bf215546Sopenharmony_ci            // all reference frames inputs should be all the same texarray allocation
1251bf215546Sopenharmony_ci            assert(referenceFramesDescriptor.ppTexture2Ds[0] ==
1252bf215546Sopenharmony_ci                   referenceFramesDescriptor.ppTexture2Ds[referenceSubresource]);
1253bf215546Sopenharmony_ci
1254bf215546Sopenharmony_ci            // the reconpic output should be all the same texarray allocation
1255bf215546Sopenharmony_ci            assert(referenceFramesDescriptor.ppTexture2Ds[0] == reconPicOutputTextureDesc.pReconstructedPicture);
1256bf215546Sopenharmony_ci
1257bf215546Sopenharmony_ci            uint32_t MipLevel, PlaneSlice, ArraySlice;
1258bf215546Sopenharmony_ci            D3D12DecomposeSubresource(referenceSubresource,
1259bf215546Sopenharmony_ci                                      referencesTexArrayDesc.MipLevels,
1260bf215546Sopenharmony_ci                                      referencesTexArrayDesc.ArraySize(),
1261bf215546Sopenharmony_ci                                      MipLevel,
1262bf215546Sopenharmony_ci                                      ArraySlice,
1263bf215546Sopenharmony_ci                                      PlaneSlice);
1264bf215546Sopenharmony_ci
1265bf215546Sopenharmony_ci            for (PlaneSlice = 0; PlaneSlice < pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.PlaneCount;
1266bf215546Sopenharmony_ci                 PlaneSlice++) {
1267bf215546Sopenharmony_ci
1268bf215546Sopenharmony_ci               uint32_t planeOutputSubresource =
1269bf215546Sopenharmony_ci                  referencesTexArrayDesc.CalcSubresource(MipLevel, ArraySlice, PlaneSlice);
1270bf215546Sopenharmony_ci
1271bf215546Sopenharmony_ci               rgReferenceTransitions.push_back(CD3DX12_RESOURCE_BARRIER::Transition(
1272bf215546Sopenharmony_ci                  // Always same allocation in texarray mode
1273bf215546Sopenharmony_ci                  referenceFramesDescriptor.ppTexture2Ds[0],
1274bf215546Sopenharmony_ci                  D3D12_RESOURCE_STATE_COMMON,
1275bf215546Sopenharmony_ci                  // If this is the subresource for the reconpic output allocation, transition to ENCODE_WRITE
1276bf215546Sopenharmony_ci                  // Otherwise, it's a subresource for an input reference picture, transition to ENCODE_READ
1277bf215546Sopenharmony_ci                  (referenceSubresource == reconPicOutputTextureDesc.ReconstructedPictureSubresource) ?
1278bf215546Sopenharmony_ci                     D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE :
1279bf215546Sopenharmony_ci                     D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
1280bf215546Sopenharmony_ci                  planeOutputSubresource));
1281bf215546Sopenharmony_ci            }
1282bf215546Sopenharmony_ci         }
1283bf215546Sopenharmony_ci      }
1284bf215546Sopenharmony_ci
1285bf215546Sopenharmony_ci      if (rgReferenceTransitions.size() > 0) {
1286bf215546Sopenharmony_ci         pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(static_cast<uint32_t>(rgReferenceTransitions.size()),
1287bf215546Sopenharmony_ci                                                           rgReferenceTransitions.data());
1288bf215546Sopenharmony_ci      }
1289bf215546Sopenharmony_ci   }
1290bf215546Sopenharmony_ci
1291bf215546Sopenharmony_ci   // Update current frame pic params state after reconfiguring above.
1292bf215546Sopenharmony_ci   D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA currentPicParams =
1293bf215546Sopenharmony_ci      d3d12_video_encoder_get_current_picture_param_settings(pD3D12Enc);
1294bf215546Sopenharmony_ci   pD3D12Enc->m_upDPBManager->get_current_frame_picture_control_data(currentPicParams);
1295bf215546Sopenharmony_ci
1296bf215546Sopenharmony_ci   uint32_t prefixGeneratedHeadersByteSize = d3d12_video_encoder_build_codec_headers(pD3D12Enc);
1297bf215546Sopenharmony_ci
1298bf215546Sopenharmony_ci   // If driver needs offset alignment for bitstream resource, we will pad zeroes on the codec header to this end.
1299bf215546Sopenharmony_ci   if (
1300bf215546Sopenharmony_ci      (pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.CompressedBitstreamBufferAccessAlignment > 1)
1301bf215546Sopenharmony_ci      && ((prefixGeneratedHeadersByteSize % pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.CompressedBitstreamBufferAccessAlignment) != 0)
1302bf215546Sopenharmony_ci   ) {
1303bf215546Sopenharmony_ci      prefixGeneratedHeadersByteSize = ALIGN(prefixGeneratedHeadersByteSize, pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.CompressedBitstreamBufferAccessAlignment);
1304bf215546Sopenharmony_ci      pD3D12Enc->m_BitstreamHeadersBuffer.resize(prefixGeneratedHeadersByteSize, 0);
1305bf215546Sopenharmony_ci   }
1306bf215546Sopenharmony_ci
1307bf215546Sopenharmony_ci   const D3D12_VIDEO_ENCODER_ENCODEFRAME_INPUT_ARGUMENTS inputStreamArguments = {
1308bf215546Sopenharmony_ci      // D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_DESC
1309bf215546Sopenharmony_ci      { // D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS
1310bf215546Sopenharmony_ci        pD3D12Enc->m_currentEncodeConfig.m_seqFlags,
1311bf215546Sopenharmony_ci        // D3D12_VIDEO_ENCODER_INTRA_REFRESH
1312bf215546Sopenharmony_ci        pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh,
1313bf215546Sopenharmony_ci        d3d12_video_encoder_get_current_rate_control_settings(pD3D12Enc),
1314bf215546Sopenharmony_ci        // D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC
1315bf215546Sopenharmony_ci        pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
1316bf215546Sopenharmony_ci        pD3D12Enc->m_currentEncodeConfig.m_encoderSliceConfigMode,
1317bf215546Sopenharmony_ci        d3d12_video_encoder_get_current_slice_param_settings(pD3D12Enc),
1318bf215546Sopenharmony_ci        d3d12_video_encoder_get_current_gop_desc(pD3D12Enc) },
1319bf215546Sopenharmony_ci      // D3D12_VIDEO_ENCODER_PICTURE_CONTROL_DESC
1320bf215546Sopenharmony_ci      { // uint32_t IntraRefreshFrameIndex;
1321bf215546Sopenharmony_ci        pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex,
1322bf215546Sopenharmony_ci        // D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAGS Flags;
1323bf215546Sopenharmony_ci        picCtrlFlags,
1324bf215546Sopenharmony_ci        // D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA PictureControlCodecData;
1325bf215546Sopenharmony_ci        currentPicParams,
1326bf215546Sopenharmony_ci        // D3D12_VIDEO_ENCODE_REFERENCE_FRAMES ReferenceFrames;
1327bf215546Sopenharmony_ci        referenceFramesDescriptor },
1328bf215546Sopenharmony_ci      pInputVideoD3D12Res,
1329bf215546Sopenharmony_ci      inputVideoD3D12Subresource,
1330bf215546Sopenharmony_ci      prefixGeneratedHeadersByteSize   // hint for driver to know header size in final bitstream for rate control internal
1331bf215546Sopenharmony_ci      // budgeting. - User can also calculate headers fixed size beforehand (eg. no VUI,
1332bf215546Sopenharmony_ci      // etc) and build them with final values after EncodeFrame is executed
1333bf215546Sopenharmony_ci   };
1334bf215546Sopenharmony_ci
1335bf215546Sopenharmony_ci   const D3D12_VIDEO_ENCODER_ENCODEFRAME_OUTPUT_ARGUMENTS outputStreamArguments = {
1336bf215546Sopenharmony_ci      // D3D12_VIDEO_ENCODER_COMPRESSED_BITSTREAM
1337bf215546Sopenharmony_ci      {
1338bf215546Sopenharmony_ci         pOutputBufferD3D12Res,
1339bf215546Sopenharmony_ci         prefixGeneratedHeadersByteSize,   // Start writing after the reserved interval [0,
1340bf215546Sopenharmony_ci                                           // prefixGeneratedHeadersByteSize) for bitstream headers
1341bf215546Sopenharmony_ci      },
1342bf215546Sopenharmony_ci      // D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE
1343bf215546Sopenharmony_ci      reconPicOutputTextureDesc,
1344bf215546Sopenharmony_ci      // D3D12_VIDEO_ENCODER_ENCODE_OPERATION_METADATA_BUFFER
1345bf215546Sopenharmony_ci      { pD3D12Enc->m_spMetadataOutputBuffer.Get(), 0 }
1346bf215546Sopenharmony_ci   };
1347bf215546Sopenharmony_ci
1348bf215546Sopenharmony_ci   // Upload the CPU buffers with the bitstream headers to the compressed bitstream resource in the interval [0,
1349bf215546Sopenharmony_ci   // prefixGeneratedHeadersByteSize)
1350bf215546Sopenharmony_ci   assert(prefixGeneratedHeadersByteSize == pD3D12Enc->m_BitstreamHeadersBuffer.size());
1351bf215546Sopenharmony_ci
1352bf215546Sopenharmony_ci   pD3D12Enc->base.context->buffer_subdata(
1353bf215546Sopenharmony_ci      pD3D12Enc->base.context,   // context
1354bf215546Sopenharmony_ci      destination,               // dst buffer - "destination" is the pipe_resource object
1355bf215546Sopenharmony_ci                                 // wrapping pOutputBitstreamBuffer and eventually pOutputBufferD3D12Res
1356bf215546Sopenharmony_ci      PIPE_MAP_WRITE,            // usage PIPE_MAP_x
1357bf215546Sopenharmony_ci      0,                         // offset
1358bf215546Sopenharmony_ci      pD3D12Enc->m_BitstreamHeadersBuffer.size(),
1359bf215546Sopenharmony_ci      pD3D12Enc->m_BitstreamHeadersBuffer.data());
1360bf215546Sopenharmony_ci
1361bf215546Sopenharmony_ci   // Note: The buffer_subdata is queued in pD3D12Enc->base.context but doesn't execute immediately
1362bf215546Sopenharmony_ci   // Will flush and sync this batch in d3d12_video_encoder_flush with the rest of the Video Encode Queue GPU work
1363bf215546Sopenharmony_ci
1364bf215546Sopenharmony_ci   // Record EncodeFrame
1365bf215546Sopenharmony_ci   pD3D12Enc->m_spEncodeCommandList->EncodeFrame(pD3D12Enc->m_spVideoEncoder.Get(),
1366bf215546Sopenharmony_ci                                                 pD3D12Enc->m_spVideoEncoderHeap.Get(),
1367bf215546Sopenharmony_ci                                                 &inputStreamArguments,
1368bf215546Sopenharmony_ci                                                 &outputStreamArguments);
1369bf215546Sopenharmony_ci
1370bf215546Sopenharmony_ci   D3D12_RESOURCE_BARRIER rgResolveMetadataStateTransitions[] = {
1371bf215546Sopenharmony_ci      CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_spResolvedMetadataBuffer.Get(),
1372bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_COMMON,
1373bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE),
1374bf215546Sopenharmony_ci      CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_spMetadataOutputBuffer.Get(),
1375bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
1376bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ),
1377bf215546Sopenharmony_ci      CD3DX12_RESOURCE_BARRIER::Transition(pInputVideoD3D12Res,
1378bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
1379bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_COMMON),
1380bf215546Sopenharmony_ci      CD3DX12_RESOURCE_BARRIER::Transition(pOutputBufferD3D12Res,
1381bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
1382bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_COMMON)
1383bf215546Sopenharmony_ci   };
1384bf215546Sopenharmony_ci
1385bf215546Sopenharmony_ci   pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(_countof(rgResolveMetadataStateTransitions),
1386bf215546Sopenharmony_ci                                                     rgResolveMetadataStateTransitions);
1387bf215546Sopenharmony_ci
1388bf215546Sopenharmony_ci   const D3D12_VIDEO_ENCODER_RESOLVE_METADATA_INPUT_ARGUMENTS inputMetadataCmd = {
1389bf215546Sopenharmony_ci      pD3D12Enc->m_currentEncodeConfig.m_encoderCodecDesc,
1390bf215546Sopenharmony_ci      d3d12_video_encoder_get_current_profile_desc(pD3D12Enc),
1391bf215546Sopenharmony_ci      pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
1392bf215546Sopenharmony_ci      // D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC
1393bf215546Sopenharmony_ci      pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
1394bf215546Sopenharmony_ci      { pD3D12Enc->m_spMetadataOutputBuffer.Get(), 0 }
1395bf215546Sopenharmony_ci   };
1396bf215546Sopenharmony_ci
1397bf215546Sopenharmony_ci   const D3D12_VIDEO_ENCODER_RESOLVE_METADATA_OUTPUT_ARGUMENTS outputMetadataCmd = {
1398bf215546Sopenharmony_ci      /*If offset were to change, has to be aligned to pD3D12Enc->m_currentEncodeCapabilities.m_ResourceRequirementsCaps.EncoderMetadataBufferAccessAlignment*/
1399bf215546Sopenharmony_ci      { pD3D12Enc->m_spResolvedMetadataBuffer.Get(), 0 }
1400bf215546Sopenharmony_ci   };
1401bf215546Sopenharmony_ci   pD3D12Enc->m_spEncodeCommandList->ResolveEncoderOutputMetadata(&inputMetadataCmd, &outputMetadataCmd);
1402bf215546Sopenharmony_ci
1403bf215546Sopenharmony_ci   // Transition DPB reference pictures back to COMMON
1404bf215546Sopenharmony_ci   if ((referenceFramesDescriptor.NumTexture2Ds > 0) ||
1405bf215546Sopenharmony_ci       (pD3D12Enc->m_upDPBManager->is_current_frame_used_as_reference())) {
1406bf215546Sopenharmony_ci      for (auto &BarrierDesc : rgReferenceTransitions) {
1407bf215546Sopenharmony_ci         std::swap(BarrierDesc.Transition.StateBefore, BarrierDesc.Transition.StateAfter);
1408bf215546Sopenharmony_ci      }
1409bf215546Sopenharmony_ci
1410bf215546Sopenharmony_ci      if (rgReferenceTransitions.size() > 0) {
1411bf215546Sopenharmony_ci         pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(static_cast<uint32_t>(rgReferenceTransitions.size()),
1412bf215546Sopenharmony_ci                                                           rgReferenceTransitions.data());
1413bf215546Sopenharmony_ci      }
1414bf215546Sopenharmony_ci   }
1415bf215546Sopenharmony_ci
1416bf215546Sopenharmony_ci   D3D12_RESOURCE_BARRIER rgRevertResolveMetadataStateTransitions[] = {
1417bf215546Sopenharmony_ci      CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_spResolvedMetadataBuffer.Get(),
1418bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE,
1419bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_COMMON),
1420bf215546Sopenharmony_ci      CD3DX12_RESOURCE_BARRIER::Transition(pD3D12Enc->m_spMetadataOutputBuffer.Get(),
1421bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ,
1422bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_COMMON),
1423bf215546Sopenharmony_ci   };
1424bf215546Sopenharmony_ci
1425bf215546Sopenharmony_ci   pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(_countof(rgRevertResolveMetadataStateTransitions),
1426bf215546Sopenharmony_ci                                                     rgRevertResolveMetadataStateTransitions);
1427bf215546Sopenharmony_ci
1428bf215546Sopenharmony_ci   debug_printf("[d3d12_video_encoder] d3d12_video_encoder_encode_bitstream finalized for fenceValue: %d\n",
1429bf215546Sopenharmony_ci                 pD3D12Enc->m_fenceValue);
1430bf215546Sopenharmony_ci}
1431bf215546Sopenharmony_ci
1432bf215546Sopenharmony_civoid
1433bf215546Sopenharmony_cid3d12_video_encoder_get_feedback(struct pipe_video_codec *codec, void *feedback, unsigned *size)
1434bf215546Sopenharmony_ci{
1435bf215546Sopenharmony_ci   struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
1436bf215546Sopenharmony_ci   assert(pD3D12Enc);
1437bf215546Sopenharmony_ci
1438bf215546Sopenharmony_ci   if (pD3D12Enc->m_needsGPUFlush) {
1439bf215546Sopenharmony_ci      d3d12_video_encoder_flush(codec);
1440bf215546Sopenharmony_ci   }
1441bf215546Sopenharmony_ci
1442bf215546Sopenharmony_ci   D3D12_VIDEO_ENCODER_OUTPUT_METADATA                       encoderMetadata;
1443bf215546Sopenharmony_ci   std::vector<D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA> pSubregionsMetadata;
1444bf215546Sopenharmony_ci   d3d12_video_encoder_extract_encode_metadata(
1445bf215546Sopenharmony_ci      pD3D12Enc,
1446bf215546Sopenharmony_ci      pD3D12Enc->m_spResolvedMetadataBuffer.Get(),
1447bf215546Sopenharmony_ci      pD3D12Enc->m_currentEncodeCapabilities.m_resolvedLayoutMetadataBufferRequiredSize,
1448bf215546Sopenharmony_ci      encoderMetadata,
1449bf215546Sopenharmony_ci      pSubregionsMetadata);
1450bf215546Sopenharmony_ci
1451bf215546Sopenharmony_ci   // Read metadata from encoderMetadata
1452bf215546Sopenharmony_ci   if (encoderMetadata.EncodeErrorFlags != D3D12_VIDEO_ENCODER_ENCODE_ERROR_FLAG_NO_ERROR) {
1453bf215546Sopenharmony_ci      debug_printf("[d3d12_video_encoder] Encode GPU command failed - EncodeErrorFlags: %" PRIu64 "\n",
1454bf215546Sopenharmony_ci                      encoderMetadata.EncodeErrorFlags);
1455bf215546Sopenharmony_ci      *size = 0;
1456bf215546Sopenharmony_ci   }
1457bf215546Sopenharmony_ci
1458bf215546Sopenharmony_ci   assert(encoderMetadata.EncodedBitstreamWrittenBytesCount > 0u);
1459bf215546Sopenharmony_ci   *size = (pD3D12Enc->m_BitstreamHeadersBuffer.size() + encoderMetadata.EncodedBitstreamWrittenBytesCount);
1460bf215546Sopenharmony_ci}
1461bf215546Sopenharmony_ci
1462bf215546Sopenharmony_civoid
1463bf215546Sopenharmony_cid3d12_video_encoder_extract_encode_metadata(
1464bf215546Sopenharmony_ci   struct d3d12_video_encoder *                               pD3D12Enc,
1465bf215546Sopenharmony_ci   ID3D12Resource *                                           pResolvedMetadataBuffer,   // input
1466bf215546Sopenharmony_ci   size_t                                                     resourceMetadataSize,      // input
1467bf215546Sopenharmony_ci   D3D12_VIDEO_ENCODER_OUTPUT_METADATA &                      parsedMetadata,            // output
1468bf215546Sopenharmony_ci   std::vector<D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA> &pSubregionsMetadata        // output
1469bf215546Sopenharmony_ci)
1470bf215546Sopenharmony_ci{
1471bf215546Sopenharmony_ci   struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pD3D12Enc->m_pD3D12Screen;
1472bf215546Sopenharmony_ci   assert(pD3D12Screen);
1473bf215546Sopenharmony_ci   pipe_resource *pPipeResolvedMetadataBuffer =
1474bf215546Sopenharmony_ci      d3d12_resource_from_resource(&pD3D12Screen->base, pResolvedMetadataBuffer);
1475bf215546Sopenharmony_ci   assert(pPipeResolvedMetadataBuffer);
1476bf215546Sopenharmony_ci   assert(resourceMetadataSize < INT_MAX);
1477bf215546Sopenharmony_ci   struct pipe_box box = {
1478bf215546Sopenharmony_ci      0,                                        // x
1479bf215546Sopenharmony_ci      0,                                        // y
1480bf215546Sopenharmony_ci      0,                                        // z
1481bf215546Sopenharmony_ci      static_cast<int>(resourceMetadataSize),   // width
1482bf215546Sopenharmony_ci      1,                                        // height
1483bf215546Sopenharmony_ci      1                                         // depth
1484bf215546Sopenharmony_ci   };
1485bf215546Sopenharmony_ci   struct pipe_transfer *mapTransfer;
1486bf215546Sopenharmony_ci   unsigned mapUsage = PIPE_MAP_READ;
1487bf215546Sopenharmony_ci   void *                pMetadataBufferSrc = pD3D12Enc->base.context->buffer_map(pD3D12Enc->base.context,
1488bf215546Sopenharmony_ci                                                                  pPipeResolvedMetadataBuffer,
1489bf215546Sopenharmony_ci                                                                  0,
1490bf215546Sopenharmony_ci                                                                  mapUsage,
1491bf215546Sopenharmony_ci                                                                  &box,
1492bf215546Sopenharmony_ci                                                                  &mapTransfer);
1493bf215546Sopenharmony_ci
1494bf215546Sopenharmony_ci   assert(mapUsage & PIPE_MAP_READ);
1495bf215546Sopenharmony_ci   assert(pPipeResolvedMetadataBuffer->usage == PIPE_USAGE_DEFAULT);
1496bf215546Sopenharmony_ci   // Note: As we're calling buffer_map with PIPE_MAP_READ on a pPipeResolvedMetadataBuffer which has pipe_usage_default
1497bf215546Sopenharmony_ci   // buffer_map itself will do all the synchronization and waits so once the function returns control here
1498bf215546Sopenharmony_ci   // the contents of mapTransfer are ready to be accessed.
1499bf215546Sopenharmony_ci
1500bf215546Sopenharmony_ci   // Clear output
1501bf215546Sopenharmony_ci   memset(&parsedMetadata, 0, sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA));
1502bf215546Sopenharmony_ci
1503bf215546Sopenharmony_ci   // Calculate sizes
1504bf215546Sopenharmony_ci   size_t encoderMetadataSize = sizeof(D3D12_VIDEO_ENCODER_OUTPUT_METADATA);
1505bf215546Sopenharmony_ci
1506bf215546Sopenharmony_ci   // Copy buffer to the appropriate D3D12_VIDEO_ENCODER_OUTPUT_METADATA memory layout
1507bf215546Sopenharmony_ci   parsedMetadata = *reinterpret_cast<D3D12_VIDEO_ENCODER_OUTPUT_METADATA *>(pMetadataBufferSrc);
1508bf215546Sopenharmony_ci
1509bf215546Sopenharmony_ci   // As specified in D3D12 Encode spec, the array base for metadata for the slices
1510bf215546Sopenharmony_ci   // (D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA[]) is placed in memory immediately after the
1511bf215546Sopenharmony_ci   // D3D12_VIDEO_ENCODER_OUTPUT_METADATA structure
1512bf215546Sopenharmony_ci   D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA *pFrameSubregionMetadata =
1513bf215546Sopenharmony_ci      reinterpret_cast<D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA *>(reinterpret_cast<uint8_t *>(pMetadataBufferSrc) +
1514bf215546Sopenharmony_ci                                                                       encoderMetadataSize);
1515bf215546Sopenharmony_ci
1516bf215546Sopenharmony_ci   // Copy fields into D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA
1517bf215546Sopenharmony_ci   assert(parsedMetadata.WrittenSubregionsCount < SIZE_MAX);
1518bf215546Sopenharmony_ci   pSubregionsMetadata.resize(static_cast<size_t>(parsedMetadata.WrittenSubregionsCount));
1519bf215546Sopenharmony_ci   for (uint32_t sliceIdx = 0; sliceIdx < parsedMetadata.WrittenSubregionsCount; sliceIdx++) {
1520bf215546Sopenharmony_ci      pSubregionsMetadata[sliceIdx].bHeaderSize  = pFrameSubregionMetadata[sliceIdx].bHeaderSize;
1521bf215546Sopenharmony_ci      pSubregionsMetadata[sliceIdx].bSize        = pFrameSubregionMetadata[sliceIdx].bSize;
1522bf215546Sopenharmony_ci      pSubregionsMetadata[sliceIdx].bStartOffset = pFrameSubregionMetadata[sliceIdx].bStartOffset;
1523bf215546Sopenharmony_ci   }
1524bf215546Sopenharmony_ci
1525bf215546Sopenharmony_ci   // Unmap the buffer tmp storage
1526bf215546Sopenharmony_ci   pipe_buffer_unmap(pD3D12Enc->base.context, mapTransfer);
1527bf215546Sopenharmony_ci}
1528bf215546Sopenharmony_ci
1529bf215546Sopenharmony_ci/**
1530bf215546Sopenharmony_ci * end encoding of the current frame
1531bf215546Sopenharmony_ci */
1532bf215546Sopenharmony_civoid
1533bf215546Sopenharmony_cid3d12_video_encoder_end_frame(struct pipe_video_codec * codec,
1534bf215546Sopenharmony_ci                              struct pipe_video_buffer *target,
1535bf215546Sopenharmony_ci                              struct pipe_picture_desc *picture)
1536bf215546Sopenharmony_ci{
1537bf215546Sopenharmony_ci   struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec;
1538bf215546Sopenharmony_ci   assert(pD3D12Enc);
1539bf215546Sopenharmony_ci   debug_printf("[d3d12_video_encoder] d3d12_video_encoder_end_frame started for fenceValue: %d\n",
1540bf215546Sopenharmony_ci                 pD3D12Enc->m_fenceValue);
1541bf215546Sopenharmony_ci
1542bf215546Sopenharmony_ci   // Signal finish of current frame encoding to the picture management tracker
1543bf215546Sopenharmony_ci   pD3D12Enc->m_upDPBManager->end_frame();
1544bf215546Sopenharmony_ci
1545bf215546Sopenharmony_ci   debug_printf("[d3d12_video_encoder] d3d12_video_encoder_end_frame finalized for fenceValue: %d\n",
1546bf215546Sopenharmony_ci                 pD3D12Enc->m_fenceValue);
1547bf215546Sopenharmony_ci
1548bf215546Sopenharmony_ci   ///
1549bf215546Sopenharmony_ci   /// Flush work to the GPU and blocking wait until encode finishes
1550bf215546Sopenharmony_ci   ///
1551bf215546Sopenharmony_ci   pD3D12Enc->m_needsGPUFlush = true;
1552bf215546Sopenharmony_ci   d3d12_video_encoder_flush(codec);
1553bf215546Sopenharmony_ci}
1554