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_context.h"
25bf215546Sopenharmony_ci#include "d3d12_format.h"
26bf215546Sopenharmony_ci#include "d3d12_resource.h"
27bf215546Sopenharmony_ci#include "d3d12_screen.h"
28bf215546Sopenharmony_ci#include "d3d12_surface.h"
29bf215546Sopenharmony_ci#include "d3d12_video_dec.h"
30bf215546Sopenharmony_ci#include "d3d12_video_dec_h264.h"
31bf215546Sopenharmony_ci#include "d3d12_video_buffer.h"
32bf215546Sopenharmony_ci#include "d3d12_residency.h"
33bf215546Sopenharmony_ci
34bf215546Sopenharmony_ci#include "vl/vl_video_buffer.h"
35bf215546Sopenharmony_ci#include "util/format/u_format.h"
36bf215546Sopenharmony_ci#include "util/u_inlines.h"
37bf215546Sopenharmony_ci#include "util/u_memory.h"
38bf215546Sopenharmony_ci#include "util/u_video.h"
39bf215546Sopenharmony_ci#include "util/vl_vlc.h"
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_cistruct pipe_video_codec *
42bf215546Sopenharmony_cid3d12_video_create_decoder(struct pipe_context *context, const struct pipe_video_codec *codec)
43bf215546Sopenharmony_ci{
44bf215546Sopenharmony_ci   ///
45bf215546Sopenharmony_ci   /// Initialize d3d12_video_decoder
46bf215546Sopenharmony_ci   ///
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_ci   // Not using new doesn't call ctor and the initializations in the class declaration are lost
50bf215546Sopenharmony_ci   struct d3d12_video_decoder *pD3D12Dec = new d3d12_video_decoder;
51bf215546Sopenharmony_ci
52bf215546Sopenharmony_ci   pD3D12Dec->base = *codec;
53bf215546Sopenharmony_ci   pD3D12Dec->m_screen = context->screen;
54bf215546Sopenharmony_ci
55bf215546Sopenharmony_ci   pD3D12Dec->base.context = context;
56bf215546Sopenharmony_ci   pD3D12Dec->base.width = codec->width;
57bf215546Sopenharmony_ci   pD3D12Dec->base.height = codec->height;
58bf215546Sopenharmony_ci   // Only fill methods that are supported by the d3d12 decoder, leaving null the rest (ie. encode_* / decode_macroblock
59bf215546Sopenharmony_ci   // / get_feedback for encode)
60bf215546Sopenharmony_ci   pD3D12Dec->base.destroy = d3d12_video_decoder_destroy;
61bf215546Sopenharmony_ci   pD3D12Dec->base.begin_frame = d3d12_video_decoder_begin_frame;
62bf215546Sopenharmony_ci   pD3D12Dec->base.decode_bitstream = d3d12_video_decoder_decode_bitstream;
63bf215546Sopenharmony_ci   pD3D12Dec->base.end_frame = d3d12_video_decoder_end_frame;
64bf215546Sopenharmony_ci   pD3D12Dec->base.flush = d3d12_video_decoder_flush;
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci   pD3D12Dec->m_decodeFormat = d3d12_convert_pipe_video_profile_to_dxgi_format(codec->profile);
67bf215546Sopenharmony_ci   pD3D12Dec->m_d3d12DecProfileType = d3d12_video_decoder_convert_pipe_video_profile_to_profile_type(codec->profile);
68bf215546Sopenharmony_ci   pD3D12Dec->m_d3d12DecProfile = d3d12_video_decoder_convert_pipe_video_profile_to_d3d12_profile(codec->profile);
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_ci   ///
71bf215546Sopenharmony_ci   /// Try initializing D3D12 Video device and check for device caps
72bf215546Sopenharmony_ci   ///
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_ci   struct d3d12_context *pD3D12Ctx = (struct d3d12_context *) context;
75bf215546Sopenharmony_ci   pD3D12Dec->m_pD3D12Screen = d3d12_screen(pD3D12Ctx->base.screen);
76bf215546Sopenharmony_ci
77bf215546Sopenharmony_ci   ///
78bf215546Sopenharmony_ci   /// Create decode objects
79bf215546Sopenharmony_ci   ///
80bf215546Sopenharmony_ci   HRESULT hr = S_OK;
81bf215546Sopenharmony_ci   if (FAILED(pD3D12Dec->m_pD3D12Screen->dev->QueryInterface(
82bf215546Sopenharmony_ci          IID_PPV_ARGS(pD3D12Dec->m_spD3D12VideoDevice.GetAddressOf())))) {
83bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_create_decoder - D3D12 Device has no Video support\n");
84bf215546Sopenharmony_ci      goto failed;
85bf215546Sopenharmony_ci   }
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_ci   if (!d3d12_video_decoder_check_caps_and_create_decoder(pD3D12Dec->m_pD3D12Screen, pD3D12Dec)) {
88bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_create_decoder - Failure on "
89bf215546Sopenharmony_ci                      "d3d12_video_decoder_check_caps_and_create_decoder\n");
90bf215546Sopenharmony_ci      goto failed;
91bf215546Sopenharmony_ci   }
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci   if (!d3d12_video_decoder_create_command_objects(pD3D12Dec->m_pD3D12Screen, pD3D12Dec)) {
94bf215546Sopenharmony_ci      debug_printf(
95bf215546Sopenharmony_ci         "[d3d12_video_decoder] d3d12_video_create_decoder - Failure on d3d12_video_decoder_create_command_objects\n");
96bf215546Sopenharmony_ci      goto failed;
97bf215546Sopenharmony_ci   }
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_ci   if (!d3d12_video_decoder_create_video_state_buffers(pD3D12Dec->m_pD3D12Screen, pD3D12Dec)) {
100bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_create_decoder - Failure on "
101bf215546Sopenharmony_ci                      "d3d12_video_decoder_create_video_state_buffers\n");
102bf215546Sopenharmony_ci      goto failed;
103bf215546Sopenharmony_ci   }
104bf215546Sopenharmony_ci
105bf215546Sopenharmony_ci   pD3D12Dec->m_decodeFormatInfo = { pD3D12Dec->m_decodeFormat };
106bf215546Sopenharmony_ci   hr = pD3D12Dec->m_pD3D12Screen->dev->CheckFeatureSupport(D3D12_FEATURE_FORMAT_INFO,
107bf215546Sopenharmony_ci                                                                        &pD3D12Dec->m_decodeFormatInfo,
108bf215546Sopenharmony_ci                                                                        sizeof(pD3D12Dec->m_decodeFormatInfo));
109bf215546Sopenharmony_ci   if(FAILED(hr)) {
110bf215546Sopenharmony_ci      debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
111bf215546Sopenharmony_ci      goto failed;
112bf215546Sopenharmony_ci   }
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci   return &pD3D12Dec->base;
115bf215546Sopenharmony_ci
116bf215546Sopenharmony_cifailed:
117bf215546Sopenharmony_ci   if (pD3D12Dec != nullptr) {
118bf215546Sopenharmony_ci      d3d12_video_decoder_destroy((struct pipe_video_codec *) pD3D12Dec);
119bf215546Sopenharmony_ci   }
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci   return nullptr;
122bf215546Sopenharmony_ci}
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_ci/**
125bf215546Sopenharmony_ci * Destroys a d3d12_video_decoder
126bf215546Sopenharmony_ci * Call destroy_XX for applicable XX nested member types before deallocating
127bf215546Sopenharmony_ci * Destroy methods should check != nullptr on their input target argument as this method can be called as part of
128bf215546Sopenharmony_ci * cleanup from failure on the creation method
129bf215546Sopenharmony_ci */
130bf215546Sopenharmony_civoid
131bf215546Sopenharmony_cid3d12_video_decoder_destroy(struct pipe_video_codec *codec)
132bf215546Sopenharmony_ci{
133bf215546Sopenharmony_ci   if (codec == nullptr) {
134bf215546Sopenharmony_ci      return;
135bf215546Sopenharmony_ci   }
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci   d3d12_video_decoder_flush(codec);   // Flush pending work before destroying.
138bf215546Sopenharmony_ci
139bf215546Sopenharmony_ci   struct d3d12_video_decoder *pD3D12Dec = (struct d3d12_video_decoder *) codec;
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci   //
142bf215546Sopenharmony_ci   // Destroys a decoder
143bf215546Sopenharmony_ci   // Call destroy_XX for applicable XX nested member types before deallocating
144bf215546Sopenharmony_ci   // Destroy methods should check != nullptr on their input target argument as this method can be called as part of
145bf215546Sopenharmony_ci   // cleanup from failure on the creation method
146bf215546Sopenharmony_ci   //
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_ci   // No need for d3d12_destroy_video_objects
149bf215546Sopenharmony_ci   //    All the objects created here are smart pointer members of d3d12_video_decoder
150bf215546Sopenharmony_ci   // No need for d3d12_destroy_video_decoder_and_heap
151bf215546Sopenharmony_ci   //    All the objects created here are smart pointer members of d3d12_video_decoder
152bf215546Sopenharmony_ci   // No need for d3d12_destroy_video_dpbmanagers
153bf215546Sopenharmony_ci   //    All the objects created here are smart pointer members of d3d12_video_decoder
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci   // No need for m_pD3D12Screen as it is not managed by d3d12_video_decoder
156bf215546Sopenharmony_ci
157bf215546Sopenharmony_ci   // Call dtor to make ComPtr work
158bf215546Sopenharmony_ci   delete pD3D12Dec;
159bf215546Sopenharmony_ci}
160bf215546Sopenharmony_ci
161bf215546Sopenharmony_ci/**
162bf215546Sopenharmony_ci * start decoding of a new frame
163bf215546Sopenharmony_ci */
164bf215546Sopenharmony_civoid
165bf215546Sopenharmony_cid3d12_video_decoder_begin_frame(struct pipe_video_codec *codec,
166bf215546Sopenharmony_ci                                struct pipe_video_buffer *target,
167bf215546Sopenharmony_ci                                struct pipe_picture_desc *picture)
168bf215546Sopenharmony_ci{
169bf215546Sopenharmony_ci   // Do nothing here. Initialize happens on decoder creation, re-config (if any) happens in
170bf215546Sopenharmony_ci   // d3d12_video_decoder_decode_bitstream
171bf215546Sopenharmony_ci   struct d3d12_video_decoder *pD3D12Dec = (struct d3d12_video_decoder *) codec;
172bf215546Sopenharmony_ci   assert(pD3D12Dec);
173bf215546Sopenharmony_ci   debug_printf("[d3d12_video_decoder] d3d12_video_decoder_begin_frame finalized for fenceValue: %d\n",
174bf215546Sopenharmony_ci                 pD3D12Dec->m_fenceValue);
175bf215546Sopenharmony_ci}
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci/**
178bf215546Sopenharmony_ci * decode a bitstream
179bf215546Sopenharmony_ci */
180bf215546Sopenharmony_civoid
181bf215546Sopenharmony_cid3d12_video_decoder_decode_bitstream(struct pipe_video_codec *codec,
182bf215546Sopenharmony_ci                                     struct pipe_video_buffer *target,
183bf215546Sopenharmony_ci                                     struct pipe_picture_desc *picture,
184bf215546Sopenharmony_ci                                     unsigned num_buffers,
185bf215546Sopenharmony_ci                                     const void *const *buffers,
186bf215546Sopenharmony_ci                                     const unsigned *sizes)
187bf215546Sopenharmony_ci{
188bf215546Sopenharmony_ci   struct d3d12_video_decoder *pD3D12Dec = (struct d3d12_video_decoder *) codec;
189bf215546Sopenharmony_ci   assert(pD3D12Dec);
190bf215546Sopenharmony_ci   debug_printf("[d3d12_video_decoder] d3d12_video_decoder_decode_bitstream started for fenceValue: %d\n",
191bf215546Sopenharmony_ci                 pD3D12Dec->m_fenceValue);
192bf215546Sopenharmony_ci   assert(pD3D12Dec->m_spD3D12VideoDevice);
193bf215546Sopenharmony_ci   assert(pD3D12Dec->m_spDecodeCommandQueue);
194bf215546Sopenharmony_ci   assert(pD3D12Dec->m_pD3D12Screen);
195bf215546Sopenharmony_ci   struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) target;
196bf215546Sopenharmony_ci   assert(pD3D12VideoBuffer);
197bf215546Sopenharmony_ci
198bf215546Sopenharmony_ci   ///
199bf215546Sopenharmony_ci   /// Compressed bitstream buffers
200bf215546Sopenharmony_ci   ///
201bf215546Sopenharmony_ci
202bf215546Sopenharmony_ci   /// Mesa VA frontend Video buffer passing semantics for H264, HEVC, MPEG4, VC1 and PIPE_VIDEO_PROFILE_VC1_ADVANCED
203bf215546Sopenharmony_ci   /// are: If num_buffers == 1 -> buf[0] has the compressed bitstream WITH the starting code If num_buffers == 2 ->
204bf215546Sopenharmony_ci   /// buf[0] has the NALU starting code and buf[1] has the compressed bitstream WITHOUT any starting code. If
205bf215546Sopenharmony_ci   /// num_buffers = 3 -> It's JPEG, not supported in D3D12. num_buffers is at most 3.
206bf215546Sopenharmony_ci   /// Mesa VDPAU frontend passes the buffers as they get passed in VdpDecoderRender without fixing any start codes
207bf215546Sopenharmony_ci   /// except for PIPE_VIDEO_PROFILE_VC1_ADVANCED
208bf215546Sopenharmony_ci   // In https://http.download.nvidia.com/XFree86/vdpau/doxygen/html/index.html#video_mixer_usage it's mentioned that:
209bf215546Sopenharmony_ci   // It is recommended that applications pass solely the slice data to VDPAU; specifically that any header data
210bf215546Sopenharmony_ci   // structures be excluded from the portion of the bitstream passed to VDPAU. VDPAU implementations must operate
211bf215546Sopenharmony_ci   // correctly if non-slice data is included, at least for formats employing start codes to delimit slice data. For all
212bf215546Sopenharmony_ci   // codecs/profiles it's highly recommended (when the codec/profile has such codes...) that the start codes are passed
213bf215546Sopenharmony_ci   // to VDPAU, even when not included in the bitstream the VDPAU client is parsing. Let's assume we get all the start
214bf215546Sopenharmony_ci   // codes for VDPAU. The doc also says "VDPAU implementations must operate correctly if non-slice data is included, at
215bf215546Sopenharmony_ci   // least for formats employing start codes to delimit slice data" if we ever get an issue with VDPAU start codes we
216bf215546Sopenharmony_ci   // should consider adding the code that handles this in the VDPAU layer above the gallium driver like mesa VA does.
217bf215546Sopenharmony_ci
218bf215546Sopenharmony_ci   // To handle the multi-slice case end_frame already takes care of this by parsing the start codes from the
219bf215546Sopenharmony_ci   // combined bitstream of all decode_bitstream calls.
220bf215546Sopenharmony_ci
221bf215546Sopenharmony_ci   // VAAPI seems to send one decode_bitstream command per slice, but we should also support the VDPAU case where the
222bf215546Sopenharmony_ci   // buffers have multiple buffer array entry per slice {startCode (optional), slice1, slice2, ..., startCode
223bf215546Sopenharmony_ci   // (optional) , sliceN}
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci   if (num_buffers > 2)   // Assume this means multiple slices at once in a decode_bitstream call
226bf215546Sopenharmony_ci   {
227bf215546Sopenharmony_ci      // Based on VA frontend codebase, this never happens for video (no JPEG)
228bf215546Sopenharmony_ci      // Based on VDPAU frontends codebase, this only happens when sending more than one slice at once in decode bitstream
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci      // To handle the case where VDPAU send all the slices at once in a single decode_bitstream call, let's pretend it
231bf215546Sopenharmony_ci      // was a series of different calls
232bf215546Sopenharmony_ci
233bf215546Sopenharmony_ci      // group by start codes and buffers and perform calls for the number of slices
234bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_decoder_decode_bitstream multiple slices on same call detected "
235bf215546Sopenharmony_ci                     "for fenceValue: %d, breaking down the calls into one per slice\n",
236bf215546Sopenharmony_ci                     pD3D12Dec->m_fenceValue);
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_ci      size_t curBufferIdx = 0;
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci      // Vars to be used for the delegation calls to decode_bitstream
241bf215546Sopenharmony_ci      unsigned call_num_buffers = 0;
242bf215546Sopenharmony_ci      const void *const *call_buffers = nullptr;
243bf215546Sopenharmony_ci      const unsigned *call_sizes = nullptr;
244bf215546Sopenharmony_ci
245bf215546Sopenharmony_ci      while (curBufferIdx < num_buffers) {
246bf215546Sopenharmony_ci         // Store the current buffer as the base array pointer for the delegated call, later decide if it'll be a
247bf215546Sopenharmony_ci         // startcode+slicedata or just slicedata call
248bf215546Sopenharmony_ci         call_buffers = &buffers[curBufferIdx];
249bf215546Sopenharmony_ci         call_sizes = &sizes[curBufferIdx];
250bf215546Sopenharmony_ci
251bf215546Sopenharmony_ci         // Usually start codes are less or equal than 4 bytes
252bf215546Sopenharmony_ci         // If the current buffer is a start code buffer, send it along with the next buffer. Otherwise, just send the
253bf215546Sopenharmony_ci         // current buffer.
254bf215546Sopenharmony_ci         call_num_buffers = (sizes[curBufferIdx] <= 4) ? 2 : 1;
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_ci         // Delegate call with one or two buffers only
257bf215546Sopenharmony_ci         d3d12_video_decoder_decode_bitstream(codec, target, picture, call_num_buffers, call_buffers, call_sizes);
258bf215546Sopenharmony_ci
259bf215546Sopenharmony_ci         curBufferIdx += call_num_buffers;   // Consume from the loop the buffers sent in the last call
260bf215546Sopenharmony_ci      }
261bf215546Sopenharmony_ci   } else {
262bf215546Sopenharmony_ci      ///
263bf215546Sopenharmony_ci      /// Handle single slice buffer path, maybe with an extra start code buffer at buffers[0].
264bf215546Sopenharmony_ci      ///
265bf215546Sopenharmony_ci
266bf215546Sopenharmony_ci      // Both the start codes being present at buffers[0] and the rest in buffers [1] or full buffer at [0] cases can be
267bf215546Sopenharmony_ci      // handled by flattening all the buffers into a single one and passing that to HW.
268bf215546Sopenharmony_ci
269bf215546Sopenharmony_ci      size_t totalReceivedBuffersSize = 0u;   // Combined size of all sizes[]
270bf215546Sopenharmony_ci      for (size_t bufferIdx = 0; bufferIdx < num_buffers; bufferIdx++) {
271bf215546Sopenharmony_ci         totalReceivedBuffersSize += sizes[bufferIdx];
272bf215546Sopenharmony_ci      }
273bf215546Sopenharmony_ci
274bf215546Sopenharmony_ci      // Bytes of data pre-staged before this decode_frame call
275bf215546Sopenharmony_ci      size_t preStagedDataSize = pD3D12Dec->m_stagingDecodeBitstream.size();
276bf215546Sopenharmony_ci
277bf215546Sopenharmony_ci      // Extend the staging buffer size, as decode_frame can be called several times before end_frame
278bf215546Sopenharmony_ci      pD3D12Dec->m_stagingDecodeBitstream.resize(preStagedDataSize + totalReceivedBuffersSize);
279bf215546Sopenharmony_ci
280bf215546Sopenharmony_ci      // Point newSliceDataPositionDstBase to the end of the pre-staged data in m_stagingDecodeBitstream, where the new
281bf215546Sopenharmony_ci      // buffers will be appended
282bf215546Sopenharmony_ci      uint8_t *newSliceDataPositionDstBase = pD3D12Dec->m_stagingDecodeBitstream.data() + preStagedDataSize;
283bf215546Sopenharmony_ci
284bf215546Sopenharmony_ci      // Append new data at the end.
285bf215546Sopenharmony_ci      size_t dstOffset = 0u;
286bf215546Sopenharmony_ci      for (size_t bufferIdx = 0; bufferIdx < num_buffers; bufferIdx++) {
287bf215546Sopenharmony_ci         memcpy(newSliceDataPositionDstBase + dstOffset, buffers[bufferIdx], sizes[bufferIdx]);
288bf215546Sopenharmony_ci         dstOffset += sizes[bufferIdx];
289bf215546Sopenharmony_ci      }
290bf215546Sopenharmony_ci
291bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_decoder_decode_bitstream finalized for fenceValue: %d\n",
292bf215546Sopenharmony_ci                    pD3D12Dec->m_fenceValue);
293bf215546Sopenharmony_ci   }
294bf215546Sopenharmony_ci}
295bf215546Sopenharmony_ci
296bf215546Sopenharmony_civoid
297bf215546Sopenharmony_cid3d12_video_decoder_store_upper_layer_references(struct d3d12_video_decoder *pD3D12Dec,
298bf215546Sopenharmony_ci                                                 struct pipe_video_buffer *target,
299bf215546Sopenharmony_ci                                                 struct pipe_picture_desc *picture)
300bf215546Sopenharmony_ci{
301bf215546Sopenharmony_ci   switch (pD3D12Dec->m_d3d12DecProfileType) {
302bf215546Sopenharmony_ci      case d3d12_video_decode_profile_type_h264:
303bf215546Sopenharmony_ci      {
304bf215546Sopenharmony_ci         pipe_h264_picture_desc *pPicControlH264 = (pipe_h264_picture_desc *) picture;
305bf215546Sopenharmony_ci         pD3D12Dec->m_pCurrentDecodeTarget = target;
306bf215546Sopenharmony_ci         pD3D12Dec->m_pCurrentReferenceTargets = pPicControlH264->ref;
307bf215546Sopenharmony_ci      } break;
308bf215546Sopenharmony_ci
309bf215546Sopenharmony_ci      default:
310bf215546Sopenharmony_ci      {
311bf215546Sopenharmony_ci         unreachable("Unsupported d3d12_video_decode_profile_type");
312bf215546Sopenharmony_ci      } break;
313bf215546Sopenharmony_ci   }
314bf215546Sopenharmony_ci}
315bf215546Sopenharmony_ci
316bf215546Sopenharmony_ci/**
317bf215546Sopenharmony_ci * end decoding of the current frame
318bf215546Sopenharmony_ci */
319bf215546Sopenharmony_civoid
320bf215546Sopenharmony_cid3d12_video_decoder_end_frame(struct pipe_video_codec *codec,
321bf215546Sopenharmony_ci                              struct pipe_video_buffer *target,
322bf215546Sopenharmony_ci                              struct pipe_picture_desc *picture)
323bf215546Sopenharmony_ci{
324bf215546Sopenharmony_ci   struct d3d12_video_decoder *pD3D12Dec = (struct d3d12_video_decoder *) codec;
325bf215546Sopenharmony_ci   assert(pD3D12Dec);
326bf215546Sopenharmony_ci   struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pD3D12Dec->m_pD3D12Screen;
327bf215546Sopenharmony_ci   assert(pD3D12Screen);
328bf215546Sopenharmony_ci   debug_printf("[d3d12_video_decoder] d3d12_video_decoder_end_frame started for fenceValue: %d\n",
329bf215546Sopenharmony_ci                 pD3D12Dec->m_fenceValue);
330bf215546Sopenharmony_ci   assert(pD3D12Dec->m_spD3D12VideoDevice);
331bf215546Sopenharmony_ci   assert(pD3D12Dec->m_spDecodeCommandQueue);
332bf215546Sopenharmony_ci   struct d3d12_video_buffer *pD3D12VideoBuffer = (struct d3d12_video_buffer *) target;
333bf215546Sopenharmony_ci   assert(pD3D12VideoBuffer);
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci   ///
336bf215546Sopenharmony_ci   /// Store current decode output target texture and reference textures from upper layer
337bf215546Sopenharmony_ci   ///
338bf215546Sopenharmony_ci   d3d12_video_decoder_store_upper_layer_references(pD3D12Dec, target, picture);
339bf215546Sopenharmony_ci
340bf215546Sopenharmony_ci   ///
341bf215546Sopenharmony_ci   /// Codec header picture parameters buffers
342bf215546Sopenharmony_ci   ///
343bf215546Sopenharmony_ci
344bf215546Sopenharmony_ci   d3d12_video_decoder_store_converted_dxva_picparams_from_pipe_input(pD3D12Dec, picture, pD3D12VideoBuffer);
345bf215546Sopenharmony_ci   assert(pD3D12Dec->m_picParamsBuffer.size() > 0);
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci   ///
348bf215546Sopenharmony_ci   /// Prepare Slice control buffers before clearing staging buffer
349bf215546Sopenharmony_ci   ///
350bf215546Sopenharmony_ci   assert(pD3D12Dec->m_stagingDecodeBitstream.size() > 0);   // Make sure the staging wasn't cleared yet in end_frame
351bf215546Sopenharmony_ci   d3d12_video_decoder_prepare_dxva_slices_control(pD3D12Dec, picture);
352bf215546Sopenharmony_ci   assert(pD3D12Dec->m_SliceControlBuffer.size() > 0);
353bf215546Sopenharmony_ci
354bf215546Sopenharmony_ci   ///
355bf215546Sopenharmony_ci   /// Upload m_stagingDecodeBitstream to GPU memory now that end_frame is called and clear staging buffer
356bf215546Sopenharmony_ci   ///
357bf215546Sopenharmony_ci
358bf215546Sopenharmony_ci   uint64_t sliceDataStagingBufferSize = pD3D12Dec->m_stagingDecodeBitstream.size();
359bf215546Sopenharmony_ci   uint8_t *sliceDataStagingBufferPtr = pD3D12Dec->m_stagingDecodeBitstream.data();
360bf215546Sopenharmony_ci
361bf215546Sopenharmony_ci   // Reallocate if necessary to accomodate the current frame bitstream buffer in GPU memory
362bf215546Sopenharmony_ci   if (pD3D12Dec->m_curFrameCompressedBitstreamBufferAllocatedSize < sliceDataStagingBufferSize) {
363bf215546Sopenharmony_ci      if (!d3d12_video_decoder_create_staging_bitstream_buffer(pD3D12Screen, pD3D12Dec, sliceDataStagingBufferSize)) {
364bf215546Sopenharmony_ci         debug_printf("[d3d12_video_decoder] d3d12_video_decoder_end_frame - Failure on "
365bf215546Sopenharmony_ci                         "d3d12_video_decoder_create_staging_bitstream_buffer\n");
366bf215546Sopenharmony_ci         debug_printf("[d3d12_video_encoder] d3d12_video_decoder_end_frame failed for fenceValue: %d\n",
367bf215546Sopenharmony_ci                pD3D12Dec->m_fenceValue);
368bf215546Sopenharmony_ci         assert(false);
369bf215546Sopenharmony_ci         return;
370bf215546Sopenharmony_ci      }
371bf215546Sopenharmony_ci   }
372bf215546Sopenharmony_ci
373bf215546Sopenharmony_ci   // Upload frame bitstream CPU data to ID3D12Resource buffer
374bf215546Sopenharmony_ci   pD3D12Dec->m_curFrameCompressedBitstreamBufferPayloadSize =
375bf215546Sopenharmony_ci      sliceDataStagingBufferSize;   // This can be less than m_curFrameCompressedBitstreamBufferAllocatedSize.
376bf215546Sopenharmony_ci   assert(pD3D12Dec->m_curFrameCompressedBitstreamBufferPayloadSize <=
377bf215546Sopenharmony_ci          pD3D12Dec->m_curFrameCompressedBitstreamBufferAllocatedSize);
378bf215546Sopenharmony_ci
379bf215546Sopenharmony_ci   /* One-shot transfer operation with data supplied in a user
380bf215546Sopenharmony_ci    * pointer.
381bf215546Sopenharmony_ci    */
382bf215546Sopenharmony_ci   pipe_resource *pPipeCompressedBufferObj =
383bf215546Sopenharmony_ci      d3d12_resource_from_resource(&pD3D12Screen->base, pD3D12Dec->m_curFrameCompressedBitstreamBuffer.Get());
384bf215546Sopenharmony_ci   assert(pPipeCompressedBufferObj);
385bf215546Sopenharmony_ci   pD3D12Dec->base.context->buffer_subdata(pD3D12Dec->base.context,    // context
386bf215546Sopenharmony_ci                                           pPipeCompressedBufferObj,   // dst buffer
387bf215546Sopenharmony_ci                                           PIPE_MAP_WRITE,             // usage PIPE_MAP_x
388bf215546Sopenharmony_ci                                           0,                          // offset
389bf215546Sopenharmony_ci                                           sizeof(*sliceDataStagingBufferPtr) * sliceDataStagingBufferSize,   // size
390bf215546Sopenharmony_ci                                           sliceDataStagingBufferPtr                                          // data
391bf215546Sopenharmony_ci   );
392bf215546Sopenharmony_ci
393bf215546Sopenharmony_ci   // Flush buffer_subdata batch and wait on this CPU thread for GPU work completion
394bf215546Sopenharmony_ci   // before deleting the source CPU buffer below
395bf215546Sopenharmony_ci   struct pipe_fence_handle *pUploadGPUCompletionFence = NULL;
396bf215546Sopenharmony_ci   pD3D12Dec->base.context->flush(pD3D12Dec->base.context,
397bf215546Sopenharmony_ci                                  &pUploadGPUCompletionFence,
398bf215546Sopenharmony_ci                                  PIPE_FLUSH_ASYNC | PIPE_FLUSH_HINT_FINISH);
399bf215546Sopenharmony_ci   assert(pUploadGPUCompletionFence);
400bf215546Sopenharmony_ci   debug_printf("[d3d12_video_decoder] d3d12_video_decoder_end_frame - Waiting on GPU completion fence for "
401bf215546Sopenharmony_ci                  "buffer_subdata to upload compressed bitstream.\n");
402bf215546Sopenharmony_ci   pD3D12Screen->base.fence_finish(&pD3D12Screen->base, NULL, pUploadGPUCompletionFence, PIPE_TIMEOUT_INFINITE);
403bf215546Sopenharmony_ci   pD3D12Screen->base.fence_reference(&pD3D12Screen->base, &pUploadGPUCompletionFence, NULL);
404bf215546Sopenharmony_ci
405bf215546Sopenharmony_ci   // [After buffer_subdata GPU work is finished] Clear CPU staging buffer now that end_frame is called and was uploaded
406bf215546Sopenharmony_ci   // to GPU for DecodeFrame call.
407bf215546Sopenharmony_ci   pD3D12Dec->m_stagingDecodeBitstream.resize(0);
408bf215546Sopenharmony_ci
409bf215546Sopenharmony_ci   ///
410bf215546Sopenharmony_ci   /// Proceed to record the GPU Decode commands
411bf215546Sopenharmony_ci   ///
412bf215546Sopenharmony_ci
413bf215546Sopenharmony_ci   // Requested conversions by caller upper layer (none for now)
414bf215546Sopenharmony_ci   d3d12_video_decode_output_conversion_arguments requestedConversionArguments = {};
415bf215546Sopenharmony_ci
416bf215546Sopenharmony_ci   ///
417bf215546Sopenharmony_ci   /// Record DecodeFrame operation and resource state transitions.
418bf215546Sopenharmony_ci   ///
419bf215546Sopenharmony_ci
420bf215546Sopenharmony_ci   // Translate input D3D12 structure
421bf215546Sopenharmony_ci   D3D12_VIDEO_DECODE_INPUT_STREAM_ARGUMENTS d3d12InputArguments = {};
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci   d3d12InputArguments.CompressedBitstream.pBuffer = pD3D12Dec->m_curFrameCompressedBitstreamBuffer.Get();
424bf215546Sopenharmony_ci   d3d12InputArguments.CompressedBitstream.Offset = 0u;
425bf215546Sopenharmony_ci   constexpr uint64_t d3d12BitstreamOffsetAlignment =
426bf215546Sopenharmony_ci      128u;   // specified in
427bf215546Sopenharmony_ci              // https://docs.microsoft.com/en-us/windows/win32/api/d3d12video/ne-d3d12video-d3d12_video_decode_tier
428bf215546Sopenharmony_ci   assert((d3d12InputArguments.CompressedBitstream.Offset == 0) ||
429bf215546Sopenharmony_ci         ((d3d12InputArguments.CompressedBitstream.Offset % d3d12BitstreamOffsetAlignment) == 0));
430bf215546Sopenharmony_ci   d3d12InputArguments.CompressedBitstream.Size = pD3D12Dec->m_curFrameCompressedBitstreamBufferPayloadSize;
431bf215546Sopenharmony_ci
432bf215546Sopenharmony_ci   D3D12_RESOURCE_BARRIER resourceBarrierCommonToDecode[1] = {
433bf215546Sopenharmony_ci      CD3DX12_RESOURCE_BARRIER::Transition(d3d12InputArguments.CompressedBitstream.pBuffer,
434bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_COMMON,
435bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_VIDEO_DECODE_READ),
436bf215546Sopenharmony_ci   };
437bf215546Sopenharmony_ci   pD3D12Dec->m_spDecodeCommandList->ResourceBarrier(1u, resourceBarrierCommonToDecode);
438bf215546Sopenharmony_ci
439bf215546Sopenharmony_ci   // Schedule reverse (back to common) transitions before command list closes for current frame
440bf215546Sopenharmony_ci   pD3D12Dec->m_transitionsBeforeCloseCmdList.push_back(
441bf215546Sopenharmony_ci      CD3DX12_RESOURCE_BARRIER::Transition(d3d12InputArguments.CompressedBitstream.pBuffer,
442bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_VIDEO_DECODE_READ,
443bf215546Sopenharmony_ci                                           D3D12_RESOURCE_STATE_COMMON));
444bf215546Sopenharmony_ci
445bf215546Sopenharmony_ci   ///
446bf215546Sopenharmony_ci   /// Clear texture (no reference only flags in resource allocation) to use as decode output to send downstream for
447bf215546Sopenharmony_ci   /// display/consumption
448bf215546Sopenharmony_ci   ///
449bf215546Sopenharmony_ci   ID3D12Resource *pOutputD3D12Texture;
450bf215546Sopenharmony_ci   uint outputD3D12Subresource = 0;
451bf215546Sopenharmony_ci
452bf215546Sopenharmony_ci   ///
453bf215546Sopenharmony_ci   /// Ref Only texture (with reference only flags in resource allocation) to use as reconstructed picture decode output
454bf215546Sopenharmony_ci   /// and to store as future reference in DPB
455bf215546Sopenharmony_ci   ///
456bf215546Sopenharmony_ci   ID3D12Resource *pRefOnlyOutputD3D12Texture;
457bf215546Sopenharmony_ci   uint refOnlyOutputD3D12Subresource = 0;
458bf215546Sopenharmony_ci
459bf215546Sopenharmony_ci   if(!d3d12_video_decoder_prepare_for_decode_frame(pD3D12Dec,
460bf215546Sopenharmony_ci                                                target,
461bf215546Sopenharmony_ci                                                pD3D12VideoBuffer,
462bf215546Sopenharmony_ci                                                &pOutputD3D12Texture,             // output
463bf215546Sopenharmony_ci                                                &outputD3D12Subresource,          // output
464bf215546Sopenharmony_ci                                                &pRefOnlyOutputD3D12Texture,      // output
465bf215546Sopenharmony_ci                                                &refOnlyOutputD3D12Subresource,   // output
466bf215546Sopenharmony_ci                                                requestedConversionArguments)) {
467bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_decoder_end_frame - Failure on "
468bf215546Sopenharmony_ci                      "d3d12_video_decoder_prepare_for_decode_frame\n");
469bf215546Sopenharmony_ci      debug_printf("[d3d12_video_encoder] d3d12_video_decoder_end_frame failed for fenceValue: %d\n",
470bf215546Sopenharmony_ci                pD3D12Dec->m_fenceValue);
471bf215546Sopenharmony_ci      assert(false);
472bf215546Sopenharmony_ci      return;
473bf215546Sopenharmony_ci   }
474bf215546Sopenharmony_ci
475bf215546Sopenharmony_ci   ///
476bf215546Sopenharmony_ci   /// Set codec picture parameters CPU buffer
477bf215546Sopenharmony_ci   ///
478bf215546Sopenharmony_ci
479bf215546Sopenharmony_ci   d3d12InputArguments.NumFrameArguments =
480bf215546Sopenharmony_ci      1u;   // Only the codec data received from the above layer with picture params
481bf215546Sopenharmony_ci   d3d12InputArguments.FrameArguments[d3d12InputArguments.NumFrameArguments - 1] = {
482bf215546Sopenharmony_ci      D3D12_VIDEO_DECODE_ARGUMENT_TYPE_PICTURE_PARAMETERS,
483bf215546Sopenharmony_ci      static_cast<uint32_t>(pD3D12Dec->m_picParamsBuffer.size()),
484bf215546Sopenharmony_ci      pD3D12Dec->m_picParamsBuffer.data(),
485bf215546Sopenharmony_ci   };
486bf215546Sopenharmony_ci
487bf215546Sopenharmony_ci   if (pD3D12Dec->m_SliceControlBuffer.size() > 0) {
488bf215546Sopenharmony_ci      d3d12InputArguments.NumFrameArguments++;
489bf215546Sopenharmony_ci      d3d12InputArguments.FrameArguments[d3d12InputArguments.NumFrameArguments - 1] = {
490bf215546Sopenharmony_ci         D3D12_VIDEO_DECODE_ARGUMENT_TYPE_SLICE_CONTROL,
491bf215546Sopenharmony_ci         static_cast<uint32_t>(pD3D12Dec->m_SliceControlBuffer.size()),
492bf215546Sopenharmony_ci         pD3D12Dec->m_SliceControlBuffer.data(),
493bf215546Sopenharmony_ci      };
494bf215546Sopenharmony_ci   }
495bf215546Sopenharmony_ci
496bf215546Sopenharmony_ci   if (pD3D12Dec->m_InverseQuantMatrixBuffer.size() > 0) {
497bf215546Sopenharmony_ci      d3d12InputArguments.NumFrameArguments++;
498bf215546Sopenharmony_ci      d3d12InputArguments.FrameArguments[d3d12InputArguments.NumFrameArguments - 1] = {
499bf215546Sopenharmony_ci         D3D12_VIDEO_DECODE_ARGUMENT_TYPE_INVERSE_QUANTIZATION_MATRIX,
500bf215546Sopenharmony_ci         static_cast<uint32_t>(pD3D12Dec->m_InverseQuantMatrixBuffer.size()),
501bf215546Sopenharmony_ci         pD3D12Dec->m_InverseQuantMatrixBuffer.data(),
502bf215546Sopenharmony_ci      };
503bf215546Sopenharmony_ci   }
504bf215546Sopenharmony_ci
505bf215546Sopenharmony_ci   d3d12InputArguments.ReferenceFrames = pD3D12Dec->m_spDPBManager->get_current_reference_frames();
506bf215546Sopenharmony_ci   if (D3D12_DEBUG_VERBOSE & d3d12_debug) {
507bf215546Sopenharmony_ci      pD3D12Dec->m_spDPBManager->print_dpb();
508bf215546Sopenharmony_ci   }
509bf215546Sopenharmony_ci
510bf215546Sopenharmony_ci   d3d12InputArguments.pHeap = pD3D12Dec->m_spVideoDecoderHeap.Get();
511bf215546Sopenharmony_ci
512bf215546Sopenharmony_ci   // translate output D3D12 structure
513bf215546Sopenharmony_ci   D3D12_VIDEO_DECODE_OUTPUT_STREAM_ARGUMENTS1 d3d12OutputArguments = {};
514bf215546Sopenharmony_ci   d3d12OutputArguments.pOutputTexture2D = pOutputD3D12Texture;
515bf215546Sopenharmony_ci   d3d12OutputArguments.OutputSubresource = outputD3D12Subresource;
516bf215546Sopenharmony_ci
517bf215546Sopenharmony_ci   bool fReferenceOnly = (pD3D12Dec->m_ConfigDecoderSpecificFlags &
518bf215546Sopenharmony_ci                          d3d12_video_decode_config_specific_flag_reference_only_textures_required) != 0;
519bf215546Sopenharmony_ci   if (fReferenceOnly) {
520bf215546Sopenharmony_ci      d3d12OutputArguments.ConversionArguments.Enable = TRUE;
521bf215546Sopenharmony_ci
522bf215546Sopenharmony_ci      assert(pRefOnlyOutputD3D12Texture);
523bf215546Sopenharmony_ci      d3d12OutputArguments.ConversionArguments.pReferenceTexture2D = pRefOnlyOutputD3D12Texture;
524bf215546Sopenharmony_ci      d3d12OutputArguments.ConversionArguments.ReferenceSubresource = refOnlyOutputD3D12Subresource;
525bf215546Sopenharmony_ci
526bf215546Sopenharmony_ci      const D3D12_RESOURCE_DESC &descReference = GetDesc(d3d12OutputArguments.ConversionArguments.pReferenceTexture2D);
527bf215546Sopenharmony_ci      d3d12OutputArguments.ConversionArguments.DecodeColorSpace = d3d12_convert_from_legacy_color_space(
528bf215546Sopenharmony_ci         !util_format_is_yuv(d3d12_get_pipe_format(descReference.Format)),
529bf215546Sopenharmony_ci         util_format_get_blocksize(d3d12_get_pipe_format(descReference.Format)) * 8 /*bytes to bits conversion*/,
530bf215546Sopenharmony_ci         /* StudioRGB= */ false,
531bf215546Sopenharmony_ci         /* P709= */ true,
532bf215546Sopenharmony_ci         /* StudioYUV= */ true);
533bf215546Sopenharmony_ci
534bf215546Sopenharmony_ci      const D3D12_RESOURCE_DESC &descOutput = GetDesc(d3d12OutputArguments.pOutputTexture2D);
535bf215546Sopenharmony_ci      d3d12OutputArguments.ConversionArguments.OutputColorSpace = d3d12_convert_from_legacy_color_space(
536bf215546Sopenharmony_ci         !util_format_is_yuv(d3d12_get_pipe_format(descOutput.Format)),
537bf215546Sopenharmony_ci         util_format_get_blocksize(d3d12_get_pipe_format(descOutput.Format)) * 8 /*bytes to bits conversion*/,
538bf215546Sopenharmony_ci         /* StudioRGB= */ false,
539bf215546Sopenharmony_ci         /* P709= */ true,
540bf215546Sopenharmony_ci         /* StudioYUV= */ true);
541bf215546Sopenharmony_ci
542bf215546Sopenharmony_ci      const D3D12_VIDEO_DECODER_HEAP_DESC &HeapDesc = GetDesc(pD3D12Dec->m_spVideoDecoderHeap.Get());
543bf215546Sopenharmony_ci      d3d12OutputArguments.ConversionArguments.OutputWidth = HeapDesc.DecodeWidth;
544bf215546Sopenharmony_ci      d3d12OutputArguments.ConversionArguments.OutputHeight = HeapDesc.DecodeHeight;
545bf215546Sopenharmony_ci   } else {
546bf215546Sopenharmony_ci      d3d12OutputArguments.ConversionArguments.Enable = FALSE;
547bf215546Sopenharmony_ci   }
548bf215546Sopenharmony_ci
549bf215546Sopenharmony_ci   CD3DX12_RESOURCE_DESC outputDesc(GetDesc(d3d12OutputArguments.pOutputTexture2D));
550bf215546Sopenharmony_ci   uint32_t MipLevel, PlaneSlice, ArraySlice;
551bf215546Sopenharmony_ci   D3D12DecomposeSubresource(d3d12OutputArguments.OutputSubresource,
552bf215546Sopenharmony_ci                             outputDesc.MipLevels,
553bf215546Sopenharmony_ci                             outputDesc.ArraySize(),
554bf215546Sopenharmony_ci                             MipLevel,
555bf215546Sopenharmony_ci                             ArraySlice,
556bf215546Sopenharmony_ci                             PlaneSlice);
557bf215546Sopenharmony_ci
558bf215546Sopenharmony_ci   for (PlaneSlice = 0; PlaneSlice < pD3D12Dec->m_decodeFormatInfo.PlaneCount; PlaneSlice++) {
559bf215546Sopenharmony_ci      uint planeOutputSubresource = outputDesc.CalcSubresource(MipLevel, ArraySlice, PlaneSlice);
560bf215546Sopenharmony_ci
561bf215546Sopenharmony_ci      D3D12_RESOURCE_BARRIER resourceBarrierCommonToDecode[1] = {
562bf215546Sopenharmony_ci         CD3DX12_RESOURCE_BARRIER::Transition(d3d12OutputArguments.pOutputTexture2D,
563bf215546Sopenharmony_ci                                              D3D12_RESOURCE_STATE_COMMON,
564bf215546Sopenharmony_ci                                              D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE,
565bf215546Sopenharmony_ci                                              planeOutputSubresource),
566bf215546Sopenharmony_ci      };
567bf215546Sopenharmony_ci      pD3D12Dec->m_spDecodeCommandList->ResourceBarrier(1u, resourceBarrierCommonToDecode);
568bf215546Sopenharmony_ci   }
569bf215546Sopenharmony_ci
570bf215546Sopenharmony_ci   // Schedule reverse (back to common) transitions before command list closes for current frame
571bf215546Sopenharmony_ci   for (PlaneSlice = 0; PlaneSlice < pD3D12Dec->m_decodeFormatInfo.PlaneCount; PlaneSlice++) {
572bf215546Sopenharmony_ci      uint planeOutputSubresource = outputDesc.CalcSubresource(MipLevel, ArraySlice, PlaneSlice);
573bf215546Sopenharmony_ci      pD3D12Dec->m_transitionsBeforeCloseCmdList.push_back(
574bf215546Sopenharmony_ci         CD3DX12_RESOURCE_BARRIER::Transition(d3d12OutputArguments.pOutputTexture2D,
575bf215546Sopenharmony_ci                                              D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE,
576bf215546Sopenharmony_ci                                              D3D12_RESOURCE_STATE_COMMON,
577bf215546Sopenharmony_ci                                              planeOutputSubresource));
578bf215546Sopenharmony_ci   }
579bf215546Sopenharmony_ci
580bf215546Sopenharmony_ci   // Record DecodeFrame
581bf215546Sopenharmony_ci
582bf215546Sopenharmony_ci   pD3D12Dec->m_spDecodeCommandList->DecodeFrame1(pD3D12Dec->m_spVideoDecoder.Get(),
583bf215546Sopenharmony_ci                                                  &d3d12OutputArguments,
584bf215546Sopenharmony_ci                                                  &d3d12InputArguments);
585bf215546Sopenharmony_ci
586bf215546Sopenharmony_ci   debug_printf("[d3d12_video_decoder] d3d12_video_decoder_end_frame finalized for fenceValue: %d\n",
587bf215546Sopenharmony_ci                 pD3D12Dec->m_fenceValue);
588bf215546Sopenharmony_ci
589bf215546Sopenharmony_ci   ///
590bf215546Sopenharmony_ci   /// Flush work to the GPU and blocking wait until decode finishes
591bf215546Sopenharmony_ci   ///
592bf215546Sopenharmony_ci   pD3D12Dec->m_needsGPUFlush = true;
593bf215546Sopenharmony_ci   d3d12_video_decoder_flush(codec);
594bf215546Sopenharmony_ci
595bf215546Sopenharmony_ci   if (!pD3D12Dec->m_spDPBManager->is_pipe_buffer_underlying_output_decode_allocation()) {
596bf215546Sopenharmony_ci      ///
597bf215546Sopenharmony_ci      /// If !pD3D12Dec->m_spDPBManager->is_pipe_buffer_underlying_output_decode_allocation()
598bf215546Sopenharmony_ci      /// We cannot use the standalone video buffer allocation directly and we must use instead
599bf215546Sopenharmony_ci      /// either a ID3D12Resource with DECODE_REFERENCE only flag or a texture array within the same
600bf215546Sopenharmony_ci      /// allocation
601bf215546Sopenharmony_ci      /// Do GPU->GPU texture copy from decode output to pipe target decode texture sampler view planes
602bf215546Sopenharmony_ci      ///
603bf215546Sopenharmony_ci
604bf215546Sopenharmony_ci      // Get destination resource
605bf215546Sopenharmony_ci      struct pipe_sampler_view **pPipeDstViews = target->get_sampler_view_planes(target);
606bf215546Sopenharmony_ci
607bf215546Sopenharmony_ci      // Get source pipe_resource
608bf215546Sopenharmony_ci      pipe_resource *pPipeSrc =
609bf215546Sopenharmony_ci         d3d12_resource_from_resource(&pD3D12Screen->base, d3d12OutputArguments.pOutputTexture2D);
610bf215546Sopenharmony_ci      assert(pPipeSrc);
611bf215546Sopenharmony_ci
612bf215546Sopenharmony_ci      // Copy all format subresources/texture planes
613bf215546Sopenharmony_ci
614bf215546Sopenharmony_ci      for (PlaneSlice = 0; PlaneSlice < pD3D12Dec->m_decodeFormatInfo.PlaneCount; PlaneSlice++) {
615bf215546Sopenharmony_ci         assert(d3d12OutputArguments.OutputSubresource < INT16_MAX);
616bf215546Sopenharmony_ci         struct pipe_box box = { 0,
617bf215546Sopenharmony_ci                                 0,
618bf215546Sopenharmony_ci                                 // src array slice, taken as Z for TEXTURE_2D_ARRAY
619bf215546Sopenharmony_ci                                 static_cast<int16_t>(d3d12OutputArguments.OutputSubresource),
620bf215546Sopenharmony_ci                                 static_cast<int>(pPipeDstViews[PlaneSlice]->texture->width0),
621bf215546Sopenharmony_ci                                 static_cast<int16_t>(pPipeDstViews[PlaneSlice]->texture->height0),
622bf215546Sopenharmony_ci                                 1 };
623bf215546Sopenharmony_ci
624bf215546Sopenharmony_ci         pD3D12Dec->base.context->resource_copy_region(pD3D12Dec->base.context,
625bf215546Sopenharmony_ci                                                       pPipeDstViews[PlaneSlice]->texture,              // dst
626bf215546Sopenharmony_ci                                                       0,                                               // dst level
627bf215546Sopenharmony_ci                                                       0,                                               // dstX
628bf215546Sopenharmony_ci                                                       0,                                               // dstY
629bf215546Sopenharmony_ci                                                       0,                                               // dstZ
630bf215546Sopenharmony_ci                                                       (PlaneSlice == 0) ? pPipeSrc : pPipeSrc->next,   // src
631bf215546Sopenharmony_ci                                                       0,                                               // src level
632bf215546Sopenharmony_ci                                                       &box);
633bf215546Sopenharmony_ci      }
634bf215546Sopenharmony_ci      // Flush resource_copy_region batch and wait on this CPU thread for GPU work completion
635bf215546Sopenharmony_ci      struct pipe_fence_handle *completion_fence = NULL;
636bf215546Sopenharmony_ci      pD3D12Dec->base.context->flush(pD3D12Dec->base.context,
637bf215546Sopenharmony_ci                                     &completion_fence,
638bf215546Sopenharmony_ci                                     PIPE_FLUSH_ASYNC | PIPE_FLUSH_HINT_FINISH);
639bf215546Sopenharmony_ci      assert(completion_fence);
640bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_decoder_end_frame - Waiting on GPU completion fence for "
641bf215546Sopenharmony_ci                     "resource_copy_region on decoded frame.\n");
642bf215546Sopenharmony_ci      pD3D12Screen->base.fence_finish(&pD3D12Screen->base, NULL, completion_fence, PIPE_TIMEOUT_INFINITE);
643bf215546Sopenharmony_ci      pD3D12Screen->base.fence_reference(&pD3D12Screen->base, &completion_fence, NULL);
644bf215546Sopenharmony_ci   }
645bf215546Sopenharmony_ci}
646bf215546Sopenharmony_ci
647bf215546Sopenharmony_ci/**
648bf215546Sopenharmony_ci * flush any outstanding command buffers to the hardware
649bf215546Sopenharmony_ci * should be called before a video_buffer is acessed by the gallium frontend again
650bf215546Sopenharmony_ci */
651bf215546Sopenharmony_civoid
652bf215546Sopenharmony_cid3d12_video_decoder_flush(struct pipe_video_codec *codec)
653bf215546Sopenharmony_ci{
654bf215546Sopenharmony_ci   struct d3d12_video_decoder *pD3D12Dec = (struct d3d12_video_decoder *) codec;
655bf215546Sopenharmony_ci   assert(pD3D12Dec);
656bf215546Sopenharmony_ci   assert(pD3D12Dec->m_spD3D12VideoDevice);
657bf215546Sopenharmony_ci   assert(pD3D12Dec->m_spDecodeCommandQueue);
658bf215546Sopenharmony_ci   debug_printf("[d3d12_video_decoder] d3d12_video_decoder_flush started. Will flush video queue work and CPU wait on "
659bf215546Sopenharmony_ci                 "fenceValue: %d\n",
660bf215546Sopenharmony_ci                 pD3D12Dec->m_fenceValue);
661bf215546Sopenharmony_ci
662bf215546Sopenharmony_ci   if (!pD3D12Dec->m_needsGPUFlush) {
663bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_decoder_flush started. Nothing to flush, all up to date.\n");
664bf215546Sopenharmony_ci   } else {
665bf215546Sopenharmony_ci      HRESULT hr = pD3D12Dec->m_pD3D12Screen->dev->GetDeviceRemovedReason();
666bf215546Sopenharmony_ci      if (hr != S_OK) {
667bf215546Sopenharmony_ci         debug_printf("[d3d12_video_decoder] d3d12_video_decoder_flush"
668bf215546Sopenharmony_ci                         " - D3D12Device was removed BEFORE commandlist "
669bf215546Sopenharmony_ci                         "execution with HR %x.\n",
670bf215546Sopenharmony_ci                         hr);
671bf215546Sopenharmony_ci         goto flush_fail;
672bf215546Sopenharmony_ci      }
673bf215546Sopenharmony_ci
674bf215546Sopenharmony_ci      // Close and execute command list and wait for idle on CPU blocking
675bf215546Sopenharmony_ci      // this method before resetting list and allocator for next submission.
676bf215546Sopenharmony_ci
677bf215546Sopenharmony_ci      if (pD3D12Dec->m_transitionsBeforeCloseCmdList.size() > 0) {
678bf215546Sopenharmony_ci         pD3D12Dec->m_spDecodeCommandList->ResourceBarrier(pD3D12Dec->m_transitionsBeforeCloseCmdList.size(),
679bf215546Sopenharmony_ci                                                           pD3D12Dec->m_transitionsBeforeCloseCmdList.data());
680bf215546Sopenharmony_ci         pD3D12Dec->m_transitionsBeforeCloseCmdList.clear();
681bf215546Sopenharmony_ci      }
682bf215546Sopenharmony_ci
683bf215546Sopenharmony_ci      hr = pD3D12Dec->m_spDecodeCommandList->Close();
684bf215546Sopenharmony_ci      if (FAILED(hr)) {
685bf215546Sopenharmony_ci         debug_printf("[d3d12_video_decoder] d3d12_video_decoder_flush - Can't close command list with HR %x\n", hr);
686bf215546Sopenharmony_ci         goto flush_fail;
687bf215546Sopenharmony_ci      }
688bf215546Sopenharmony_ci
689bf215546Sopenharmony_ci      ID3D12CommandList *ppCommandLists[1] = { pD3D12Dec->m_spDecodeCommandList.Get() };
690bf215546Sopenharmony_ci      pD3D12Dec->m_spDecodeCommandQueue->ExecuteCommandLists(1, ppCommandLists);
691bf215546Sopenharmony_ci      pD3D12Dec->m_spDecodeCommandQueue->Signal(pD3D12Dec->m_spFence.Get(), pD3D12Dec->m_fenceValue);
692bf215546Sopenharmony_ci      pD3D12Dec->m_spFence->SetEventOnCompletion(pD3D12Dec->m_fenceValue, nullptr);
693bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_decoder_flush - ExecuteCommandLists finished on signal with "
694bf215546Sopenharmony_ci                    "fenceValue: %d\n",
695bf215546Sopenharmony_ci                    pD3D12Dec->m_fenceValue);
696bf215546Sopenharmony_ci
697bf215546Sopenharmony_ci      hr = pD3D12Dec->m_spCommandAllocator->Reset();
698bf215546Sopenharmony_ci      if (FAILED(hr)) {
699bf215546Sopenharmony_ci         debug_printf(
700bf215546Sopenharmony_ci            "[d3d12_video_decoder] d3d12_video_decoder_flush - resetting ID3D12CommandAllocator failed with HR %x\n",
701bf215546Sopenharmony_ci            hr);
702bf215546Sopenharmony_ci         goto flush_fail;
703bf215546Sopenharmony_ci      }
704bf215546Sopenharmony_ci
705bf215546Sopenharmony_ci      hr = pD3D12Dec->m_spDecodeCommandList->Reset(pD3D12Dec->m_spCommandAllocator.Get());
706bf215546Sopenharmony_ci      if (FAILED(hr)) {
707bf215546Sopenharmony_ci         debug_printf(
708bf215546Sopenharmony_ci            "[d3d12_video_decoder] d3d12_video_decoder_flush - resetting ID3D12GraphicsCommandList failed with HR %x\n",
709bf215546Sopenharmony_ci            hr);
710bf215546Sopenharmony_ci         goto flush_fail;
711bf215546Sopenharmony_ci      }
712bf215546Sopenharmony_ci
713bf215546Sopenharmony_ci      // Validate device was not removed
714bf215546Sopenharmony_ci      hr = pD3D12Dec->m_pD3D12Screen->dev->GetDeviceRemovedReason();
715bf215546Sopenharmony_ci      if (hr != S_OK) {
716bf215546Sopenharmony_ci         debug_printf("[d3d12_video_decoder] d3d12_video_decoder_flush"
717bf215546Sopenharmony_ci                         " - D3D12Device was removed AFTER commandlist "
718bf215546Sopenharmony_ci                         "execution with HR %x, but wasn't before.\n",
719bf215546Sopenharmony_ci                         hr);
720bf215546Sopenharmony_ci         goto flush_fail;
721bf215546Sopenharmony_ci      }
722bf215546Sopenharmony_ci
723bf215546Sopenharmony_ci      debug_printf(
724bf215546Sopenharmony_ci         "[d3d12_video_decoder] d3d12_video_decoder_flush - GPU signaled execution finalized for fenceValue: %d\n",
725bf215546Sopenharmony_ci         pD3D12Dec->m_fenceValue);
726bf215546Sopenharmony_ci
727bf215546Sopenharmony_ci      pD3D12Dec->m_fenceValue++;
728bf215546Sopenharmony_ci      pD3D12Dec->m_needsGPUFlush = false;
729bf215546Sopenharmony_ci   }
730bf215546Sopenharmony_ci   return;
731bf215546Sopenharmony_ci
732bf215546Sopenharmony_ciflush_fail:
733bf215546Sopenharmony_ci   debug_printf("[d3d12_video_decoder] d3d12_video_decoder_flush failed for fenceValue: %d\n", pD3D12Dec->m_fenceValue);
734bf215546Sopenharmony_ci   assert(false);
735bf215546Sopenharmony_ci}
736bf215546Sopenharmony_ci
737bf215546Sopenharmony_cibool
738bf215546Sopenharmony_cid3d12_video_decoder_create_command_objects(const struct d3d12_screen *pD3D12Screen,
739bf215546Sopenharmony_ci                                           struct d3d12_video_decoder *pD3D12Dec)
740bf215546Sopenharmony_ci{
741bf215546Sopenharmony_ci   assert(pD3D12Dec->m_spD3D12VideoDevice);
742bf215546Sopenharmony_ci
743bf215546Sopenharmony_ci   D3D12_COMMAND_QUEUE_DESC commandQueueDesc = { D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE };
744bf215546Sopenharmony_ci   HRESULT hr = pD3D12Screen->dev->CreateCommandQueue(&commandQueueDesc,
745bf215546Sopenharmony_ci                                                      IID_PPV_ARGS(pD3D12Dec->m_spDecodeCommandQueue.GetAddressOf()));
746bf215546Sopenharmony_ci   if (FAILED(hr)) {
747bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_decoder_create_command_objects - Call to CreateCommandQueue "
748bf215546Sopenharmony_ci                      "failed with HR %x\n",
749bf215546Sopenharmony_ci                      hr);
750bf215546Sopenharmony_ci      return false;
751bf215546Sopenharmony_ci   }
752bf215546Sopenharmony_ci
753bf215546Sopenharmony_ci   hr = pD3D12Screen->dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&pD3D12Dec->m_spFence));
754bf215546Sopenharmony_ci   if (FAILED(hr)) {
755bf215546Sopenharmony_ci      debug_printf(
756bf215546Sopenharmony_ci         "[d3d12_video_decoder] d3d12_video_decoder_create_command_objects - Call to CreateFence failed with HR %x\n",
757bf215546Sopenharmony_ci         hr);
758bf215546Sopenharmony_ci      return false;
759bf215546Sopenharmony_ci   }
760bf215546Sopenharmony_ci
761bf215546Sopenharmony_ci   hr = pD3D12Screen->dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE,
762bf215546Sopenharmony_ci                                                  IID_PPV_ARGS(pD3D12Dec->m_spCommandAllocator.GetAddressOf()));
763bf215546Sopenharmony_ci   if (FAILED(hr)) {
764bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_decoder_create_command_objects - Call to "
765bf215546Sopenharmony_ci                      "CreateCommandAllocator failed with HR %x\n",
766bf215546Sopenharmony_ci                      hr);
767bf215546Sopenharmony_ci      return false;
768bf215546Sopenharmony_ci   }
769bf215546Sopenharmony_ci
770bf215546Sopenharmony_ci   hr = pD3D12Screen->dev->CreateCommandList(0,
771bf215546Sopenharmony_ci                                             D3D12_COMMAND_LIST_TYPE_VIDEO_DECODE,
772bf215546Sopenharmony_ci                                             pD3D12Dec->m_spCommandAllocator.Get(),
773bf215546Sopenharmony_ci                                             nullptr,
774bf215546Sopenharmony_ci                                             IID_PPV_ARGS(pD3D12Dec->m_spDecodeCommandList.GetAddressOf()));
775bf215546Sopenharmony_ci
776bf215546Sopenharmony_ci   if (FAILED(hr)) {
777bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_decoder_create_command_objects - Call to CreateCommandList "
778bf215546Sopenharmony_ci                      "failed with HR %x\n",
779bf215546Sopenharmony_ci                      hr);
780bf215546Sopenharmony_ci      return false;
781bf215546Sopenharmony_ci   }
782bf215546Sopenharmony_ci
783bf215546Sopenharmony_ci   return true;
784bf215546Sopenharmony_ci}
785bf215546Sopenharmony_ci
786bf215546Sopenharmony_cibool
787bf215546Sopenharmony_cid3d12_video_decoder_check_caps_and_create_decoder(const struct d3d12_screen *pD3D12Screen,
788bf215546Sopenharmony_ci                                                  struct d3d12_video_decoder *pD3D12Dec)
789bf215546Sopenharmony_ci{
790bf215546Sopenharmony_ci   assert(pD3D12Dec->m_spD3D12VideoDevice);
791bf215546Sopenharmony_ci
792bf215546Sopenharmony_ci   pD3D12Dec->m_decoderDesc = {};
793bf215546Sopenharmony_ci
794bf215546Sopenharmony_ci   D3D12_VIDEO_DECODE_CONFIGURATION decodeConfiguration = { pD3D12Dec->m_d3d12DecProfile,
795bf215546Sopenharmony_ci                                                            D3D12_BITSTREAM_ENCRYPTION_TYPE_NONE,
796bf215546Sopenharmony_ci                                                            D3D12_VIDEO_FRAME_CODED_INTERLACE_TYPE_NONE };
797bf215546Sopenharmony_ci
798bf215546Sopenharmony_ci   D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT decodeSupport = {};
799bf215546Sopenharmony_ci   decodeSupport.NodeIndex = pD3D12Dec->m_NodeIndex;
800bf215546Sopenharmony_ci   decodeSupport.Configuration = decodeConfiguration;
801bf215546Sopenharmony_ci   decodeSupport.Width = pD3D12Dec->base.width;
802bf215546Sopenharmony_ci   decodeSupport.Height = pD3D12Dec->base.height;
803bf215546Sopenharmony_ci   decodeSupport.DecodeFormat = pD3D12Dec->m_decodeFormat;
804bf215546Sopenharmony_ci   // no info from above layer on framerate/bitrate
805bf215546Sopenharmony_ci   decodeSupport.FrameRate.Numerator = 0;
806bf215546Sopenharmony_ci   decodeSupport.FrameRate.Denominator = 0;
807bf215546Sopenharmony_ci   decodeSupport.BitRate = 0;
808bf215546Sopenharmony_ci
809bf215546Sopenharmony_ci   HRESULT hr = pD3D12Dec->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_DECODE_SUPPORT,
810bf215546Sopenharmony_ci                                                                     &decodeSupport,
811bf215546Sopenharmony_ci                                                                     sizeof(decodeSupport));
812bf215546Sopenharmony_ci   if (FAILED(hr)) {
813bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_decoder_check_caps_and_create_decoder - CheckFeatureSupport "
814bf215546Sopenharmony_ci                      "failed with HR %x\n",
815bf215546Sopenharmony_ci                      hr);
816bf215546Sopenharmony_ci      return false;
817bf215546Sopenharmony_ci   }
818bf215546Sopenharmony_ci
819bf215546Sopenharmony_ci   if (!(decodeSupport.SupportFlags & D3D12_VIDEO_DECODE_SUPPORT_FLAG_SUPPORTED)) {
820bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_decoder_check_caps_and_create_decoder - "
821bf215546Sopenharmony_ci                      "D3D12_VIDEO_DECODE_SUPPORT_FLAG_SUPPORTED was false when checking caps \n");
822bf215546Sopenharmony_ci      return false;
823bf215546Sopenharmony_ci   }
824bf215546Sopenharmony_ci
825bf215546Sopenharmony_ci   pD3D12Dec->m_configurationFlags = decodeSupport.ConfigurationFlags;
826bf215546Sopenharmony_ci   pD3D12Dec->m_tier = decodeSupport.DecodeTier;
827bf215546Sopenharmony_ci
828bf215546Sopenharmony_ci   if (d3d12_video_decoder_supports_aot_dpb(decodeSupport, pD3D12Dec->m_d3d12DecProfileType)) {
829bf215546Sopenharmony_ci      pD3D12Dec->m_ConfigDecoderSpecificFlags |= d3d12_video_decode_config_specific_flag_array_of_textures;
830bf215546Sopenharmony_ci   }
831bf215546Sopenharmony_ci
832bf215546Sopenharmony_ci   if (decodeSupport.ConfigurationFlags & D3D12_VIDEO_DECODE_CONFIGURATION_FLAG_HEIGHT_ALIGNMENT_MULTIPLE_32_REQUIRED) {
833bf215546Sopenharmony_ci      pD3D12Dec->m_ConfigDecoderSpecificFlags |= d3d12_video_decode_config_specific_flag_alignment_height;
834bf215546Sopenharmony_ci   }
835bf215546Sopenharmony_ci
836bf215546Sopenharmony_ci   if (decodeSupport.ConfigurationFlags & D3D12_VIDEO_DECODE_CONFIGURATION_FLAG_REFERENCE_ONLY_ALLOCATIONS_REQUIRED) {
837bf215546Sopenharmony_ci      pD3D12Dec->m_ConfigDecoderSpecificFlags |=
838bf215546Sopenharmony_ci         d3d12_video_decode_config_specific_flag_reference_only_textures_required;
839bf215546Sopenharmony_ci   }
840bf215546Sopenharmony_ci
841bf215546Sopenharmony_ci   pD3D12Dec->m_decoderDesc.NodeMask = pD3D12Dec->m_NodeMask;
842bf215546Sopenharmony_ci   pD3D12Dec->m_decoderDesc.Configuration = decodeConfiguration;
843bf215546Sopenharmony_ci
844bf215546Sopenharmony_ci   hr = pD3D12Dec->m_spD3D12VideoDevice->CreateVideoDecoder(&pD3D12Dec->m_decoderDesc,
845bf215546Sopenharmony_ci                                                            IID_PPV_ARGS(pD3D12Dec->m_spVideoDecoder.GetAddressOf()));
846bf215546Sopenharmony_ci   if (FAILED(hr)) {
847bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_decoder_check_caps_and_create_decoder - CreateVideoDecoder "
848bf215546Sopenharmony_ci                      "failed with HR %x\n",
849bf215546Sopenharmony_ci                      hr);
850bf215546Sopenharmony_ci      return false;
851bf215546Sopenharmony_ci   }
852bf215546Sopenharmony_ci
853bf215546Sopenharmony_ci   return true;
854bf215546Sopenharmony_ci}
855bf215546Sopenharmony_ci
856bf215546Sopenharmony_cibool
857bf215546Sopenharmony_cid3d12_video_decoder_create_video_state_buffers(const struct d3d12_screen *pD3D12Screen,
858bf215546Sopenharmony_ci                                               struct d3d12_video_decoder *pD3D12Dec)
859bf215546Sopenharmony_ci{
860bf215546Sopenharmony_ci   assert(pD3D12Dec->m_spD3D12VideoDevice);
861bf215546Sopenharmony_ci   if (!d3d12_video_decoder_create_staging_bitstream_buffer(pD3D12Screen,
862bf215546Sopenharmony_ci                                                            pD3D12Dec,
863bf215546Sopenharmony_ci                                                            pD3D12Dec->m_InitialCompBitstreamGPUBufferSize)) {
864bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_decoder_create_video_state_buffers - Failure on "
865bf215546Sopenharmony_ci                      "d3d12_video_decoder_create_staging_bitstream_buffer\n");
866bf215546Sopenharmony_ci      return false;
867bf215546Sopenharmony_ci   }
868bf215546Sopenharmony_ci
869bf215546Sopenharmony_ci   return true;
870bf215546Sopenharmony_ci}
871bf215546Sopenharmony_ci
872bf215546Sopenharmony_cibool
873bf215546Sopenharmony_cid3d12_video_decoder_create_staging_bitstream_buffer(const struct d3d12_screen *pD3D12Screen,
874bf215546Sopenharmony_ci                                                    struct d3d12_video_decoder *pD3D12Dec,
875bf215546Sopenharmony_ci                                                    uint64_t bufSize)
876bf215546Sopenharmony_ci{
877bf215546Sopenharmony_ci   assert(pD3D12Dec->m_spD3D12VideoDevice);
878bf215546Sopenharmony_ci
879bf215546Sopenharmony_ci   if (pD3D12Dec->m_curFrameCompressedBitstreamBuffer.Get() != nullptr) {
880bf215546Sopenharmony_ci      pD3D12Dec->m_curFrameCompressedBitstreamBuffer.Reset();
881bf215546Sopenharmony_ci   }
882bf215546Sopenharmony_ci
883bf215546Sopenharmony_ci   auto descHeap = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT, pD3D12Dec->m_NodeMask, pD3D12Dec->m_NodeMask);
884bf215546Sopenharmony_ci   auto descResource = CD3DX12_RESOURCE_DESC::Buffer(bufSize);
885bf215546Sopenharmony_ci   HRESULT hr = pD3D12Screen->dev->CreateCommittedResource(
886bf215546Sopenharmony_ci      &descHeap,
887bf215546Sopenharmony_ci      D3D12_HEAP_FLAG_NONE,
888bf215546Sopenharmony_ci      &descResource,
889bf215546Sopenharmony_ci      D3D12_RESOURCE_STATE_COMMON,
890bf215546Sopenharmony_ci      nullptr,
891bf215546Sopenharmony_ci      IID_PPV_ARGS(pD3D12Dec->m_curFrameCompressedBitstreamBuffer.GetAddressOf()));
892bf215546Sopenharmony_ci   if (FAILED(hr)) {
893bf215546Sopenharmony_ci      debug_printf("[d3d12_video_decoder] d3d12_video_decoder_create_staging_bitstream_buffer - "
894bf215546Sopenharmony_ci                      "CreateCommittedResource failed with HR %x\n",
895bf215546Sopenharmony_ci                      hr);
896bf215546Sopenharmony_ci      return false;
897bf215546Sopenharmony_ci   }
898bf215546Sopenharmony_ci
899bf215546Sopenharmony_ci   pD3D12Dec->m_curFrameCompressedBitstreamBufferAllocatedSize = bufSize;
900bf215546Sopenharmony_ci   return true;
901bf215546Sopenharmony_ci}
902bf215546Sopenharmony_ci
903bf215546Sopenharmony_cibool
904bf215546Sopenharmony_cid3d12_video_decoder_prepare_for_decode_frame(struct d3d12_video_decoder *pD3D12Dec,
905bf215546Sopenharmony_ci                                             struct pipe_video_buffer *pCurrentDecodeTarget,
906bf215546Sopenharmony_ci                                             struct d3d12_video_buffer *pD3D12VideoBuffer,
907bf215546Sopenharmony_ci                                             ID3D12Resource **ppOutTexture2D,
908bf215546Sopenharmony_ci                                             uint32_t *pOutSubresourceIndex,
909bf215546Sopenharmony_ci                                             ID3D12Resource **ppRefOnlyOutTexture2D,
910bf215546Sopenharmony_ci                                             uint32_t *pRefOnlyOutSubresourceIndex,
911bf215546Sopenharmony_ci                                             const d3d12_video_decode_output_conversion_arguments &conversionArgs)
912bf215546Sopenharmony_ci{
913bf215546Sopenharmony_ci   if(!d3d12_video_decoder_reconfigure_dpb(pD3D12Dec, pD3D12VideoBuffer, conversionArgs)) {
914bf215546Sopenharmony_ci      debug_printf("d3d12_video_decoder_reconfigure_dpb failed!\n");
915bf215546Sopenharmony_ci      return false;
916bf215546Sopenharmony_ci   }
917bf215546Sopenharmony_ci
918bf215546Sopenharmony_ci   // Refresh DPB active references for current frame, release memory for unused references.
919bf215546Sopenharmony_ci   d3d12_video_decoder_refresh_dpb_active_references(pD3D12Dec);
920bf215546Sopenharmony_ci
921bf215546Sopenharmony_ci   // Get the output texture for the current frame to be decoded
922bf215546Sopenharmony_ci   pD3D12Dec->m_spDPBManager->get_current_frame_decode_output_texture(pCurrentDecodeTarget,
923bf215546Sopenharmony_ci                                                                      ppOutTexture2D,
924bf215546Sopenharmony_ci                                                                      pOutSubresourceIndex);
925bf215546Sopenharmony_ci
926bf215546Sopenharmony_ci   auto vidBuffer = (struct d3d12_video_buffer *)(pCurrentDecodeTarget);
927bf215546Sopenharmony_ci   // If is_pipe_buffer_underlying_output_decode_allocation is enabled,
928bf215546Sopenharmony_ci   // we can just use the underlying allocation in pCurrentDecodeTarget
929bf215546Sopenharmony_ci   // and avoid an extra copy after decoding the frame.
930bf215546Sopenharmony_ci   // If this is the case, we need to handle the residency of this resource
931bf215546Sopenharmony_ci   // (if not we're actually creating the resources with CreateCommitedResource with
932bf215546Sopenharmony_ci   // residency by default)
933bf215546Sopenharmony_ci   if(pD3D12Dec->m_spDPBManager->is_pipe_buffer_underlying_output_decode_allocation()) {
934bf215546Sopenharmony_ci      assert(d3d12_resource_resource(vidBuffer->texture) == *ppOutTexture2D);
935bf215546Sopenharmony_ci      // Make it permanently resident for video use
936bf215546Sopenharmony_ci      d3d12_promote_to_permanent_residency(pD3D12Dec->m_pD3D12Screen, vidBuffer->texture);
937bf215546Sopenharmony_ci   }
938bf215546Sopenharmony_ci
939bf215546Sopenharmony_ci   // Get the reference only texture for the current frame to be decoded (if applicable)
940bf215546Sopenharmony_ci   bool fReferenceOnly = (pD3D12Dec->m_ConfigDecoderSpecificFlags &
941bf215546Sopenharmony_ci                          d3d12_video_decode_config_specific_flag_reference_only_textures_required) != 0;
942bf215546Sopenharmony_ci   if (fReferenceOnly) {
943bf215546Sopenharmony_ci      bool needsTransitionToDecodeWrite = false;
944bf215546Sopenharmony_ci      pD3D12Dec->m_spDPBManager->get_reference_only_output(pCurrentDecodeTarget,
945bf215546Sopenharmony_ci                                                           ppRefOnlyOutTexture2D,
946bf215546Sopenharmony_ci                                                           pRefOnlyOutSubresourceIndex,
947bf215546Sopenharmony_ci                                                           needsTransitionToDecodeWrite);
948bf215546Sopenharmony_ci      assert(needsTransitionToDecodeWrite);
949bf215546Sopenharmony_ci
950bf215546Sopenharmony_ci      CD3DX12_RESOURCE_DESC outputDesc(GetDesc(*ppRefOnlyOutTexture2D));
951bf215546Sopenharmony_ci      uint32_t MipLevel, PlaneSlice, ArraySlice;
952bf215546Sopenharmony_ci      D3D12DecomposeSubresource(*pRefOnlyOutSubresourceIndex,
953bf215546Sopenharmony_ci                                outputDesc.MipLevels,
954bf215546Sopenharmony_ci                                outputDesc.ArraySize(),
955bf215546Sopenharmony_ci                                MipLevel,
956bf215546Sopenharmony_ci                                ArraySlice,
957bf215546Sopenharmony_ci                                PlaneSlice);
958bf215546Sopenharmony_ci
959bf215546Sopenharmony_ci      for (PlaneSlice = 0; PlaneSlice < pD3D12Dec->m_decodeFormatInfo.PlaneCount; PlaneSlice++) {
960bf215546Sopenharmony_ci         uint planeOutputSubresource = outputDesc.CalcSubresource(MipLevel, ArraySlice, PlaneSlice);
961bf215546Sopenharmony_ci
962bf215546Sopenharmony_ci         D3D12_RESOURCE_BARRIER resourceBarrierCommonToDecode[1] = {
963bf215546Sopenharmony_ci            CD3DX12_RESOURCE_BARRIER::Transition(*ppRefOnlyOutTexture2D,
964bf215546Sopenharmony_ci                                                 D3D12_RESOURCE_STATE_COMMON,
965bf215546Sopenharmony_ci                                                 D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE,
966bf215546Sopenharmony_ci                                                 planeOutputSubresource),
967bf215546Sopenharmony_ci         };
968bf215546Sopenharmony_ci         pD3D12Dec->m_spDecodeCommandList->ResourceBarrier(1u, resourceBarrierCommonToDecode);
969bf215546Sopenharmony_ci      }
970bf215546Sopenharmony_ci
971bf215546Sopenharmony_ci      // Schedule reverse (back to common) transitions before command list closes for current frame
972bf215546Sopenharmony_ci      for (PlaneSlice = 0; PlaneSlice < pD3D12Dec->m_decodeFormatInfo.PlaneCount; PlaneSlice++) {
973bf215546Sopenharmony_ci         uint planeOutputSubresource = outputDesc.CalcSubresource(MipLevel, ArraySlice, PlaneSlice);
974bf215546Sopenharmony_ci         pD3D12Dec->m_transitionsBeforeCloseCmdList.push_back(
975bf215546Sopenharmony_ci            CD3DX12_RESOURCE_BARRIER::Transition(*ppRefOnlyOutTexture2D,
976bf215546Sopenharmony_ci                                                 D3D12_RESOURCE_STATE_VIDEO_DECODE_WRITE,
977bf215546Sopenharmony_ci                                                 D3D12_RESOURCE_STATE_COMMON,
978bf215546Sopenharmony_ci                                                 planeOutputSubresource));
979bf215546Sopenharmony_ci      }
980bf215546Sopenharmony_ci   }
981bf215546Sopenharmony_ci
982bf215546Sopenharmony_ci   // If decoded needs reference_only entries in the dpb, use the reference_only allocation for current frame
983bf215546Sopenharmony_ci   // otherwise, use the standard output resource
984bf215546Sopenharmony_ci   ID3D12Resource *pCurrentFrameDPBEntry = fReferenceOnly ? *ppRefOnlyOutTexture2D : *ppOutTexture2D;
985bf215546Sopenharmony_ci   uint32_t currentFrameDPBEntrySubresource = fReferenceOnly ? *pRefOnlyOutSubresourceIndex : *pOutSubresourceIndex;
986bf215546Sopenharmony_ci
987bf215546Sopenharmony_ci   switch (pD3D12Dec->m_d3d12DecProfileType) {
988bf215546Sopenharmony_ci      case d3d12_video_decode_profile_type_h264:
989bf215546Sopenharmony_ci      {
990bf215546Sopenharmony_ci         d3d12_video_decoder_prepare_current_frame_references_h264(pD3D12Dec,
991bf215546Sopenharmony_ci                                                                   pCurrentFrameDPBEntry,
992bf215546Sopenharmony_ci                                                                   currentFrameDPBEntrySubresource);
993bf215546Sopenharmony_ci      } break;
994bf215546Sopenharmony_ci
995bf215546Sopenharmony_ci      default:
996bf215546Sopenharmony_ci      {
997bf215546Sopenharmony_ci         unreachable("Unsupported d3d12_video_decode_profile_type");
998bf215546Sopenharmony_ci      } break;
999bf215546Sopenharmony_ci   }
1000bf215546Sopenharmony_ci
1001bf215546Sopenharmony_ci   return true;
1002bf215546Sopenharmony_ci}
1003bf215546Sopenharmony_ci
1004bf215546Sopenharmony_cibool
1005bf215546Sopenharmony_cid3d12_video_decoder_reconfigure_dpb(struct d3d12_video_decoder *pD3D12Dec,
1006bf215546Sopenharmony_ci                                    struct d3d12_video_buffer *pD3D12VideoBuffer,
1007bf215546Sopenharmony_ci                                    const d3d12_video_decode_output_conversion_arguments &conversionArguments)
1008bf215546Sopenharmony_ci{
1009bf215546Sopenharmony_ci   uint32_t width;
1010bf215546Sopenharmony_ci   uint32_t height;
1011bf215546Sopenharmony_ci   uint16_t maxDPB;
1012bf215546Sopenharmony_ci   bool isInterlaced;
1013bf215546Sopenharmony_ci   d3d12_video_decoder_get_frame_info(pD3D12Dec, &width, &height, &maxDPB, isInterlaced);
1014bf215546Sopenharmony_ci
1015bf215546Sopenharmony_ci   ID3D12Resource *pPipeD3D12DstResource = d3d12_resource_resource(pD3D12VideoBuffer->texture);
1016bf215546Sopenharmony_ci   D3D12_RESOURCE_DESC outputResourceDesc = GetDesc(pPipeD3D12DstResource);
1017bf215546Sopenharmony_ci
1018bf215546Sopenharmony_ci   pD3D12VideoBuffer->base.interlaced = isInterlaced;
1019bf215546Sopenharmony_ci   D3D12_VIDEO_FRAME_CODED_INTERLACE_TYPE interlaceTypeRequested =
1020bf215546Sopenharmony_ci      isInterlaced ? D3D12_VIDEO_FRAME_CODED_INTERLACE_TYPE_FIELD_BASED : D3D12_VIDEO_FRAME_CODED_INTERLACE_TYPE_NONE;
1021bf215546Sopenharmony_ci   if ((pD3D12Dec->m_decodeFormat != outputResourceDesc.Format) ||
1022bf215546Sopenharmony_ci       (pD3D12Dec->m_decoderDesc.Configuration.InterlaceType != interlaceTypeRequested)) {
1023bf215546Sopenharmony_ci      // Copy current pD3D12Dec->m_decoderDesc, modify decodeprofile and re-create decoder.
1024bf215546Sopenharmony_ci      D3D12_VIDEO_DECODER_DESC decoderDesc = pD3D12Dec->m_decoderDesc;
1025bf215546Sopenharmony_ci      decoderDesc.Configuration.InterlaceType = interlaceTypeRequested;
1026bf215546Sopenharmony_ci      decoderDesc.Configuration.DecodeProfile =
1027bf215546Sopenharmony_ci         d3d12_video_decoder_resolve_profile(pD3D12Dec->m_d3d12DecProfileType);
1028bf215546Sopenharmony_ci      pD3D12Dec->m_spVideoDecoder.Reset();
1029bf215546Sopenharmony_ci      HRESULT hr =
1030bf215546Sopenharmony_ci         pD3D12Dec->m_spD3D12VideoDevice->CreateVideoDecoder(&decoderDesc,
1031bf215546Sopenharmony_ci                                                             IID_PPV_ARGS(pD3D12Dec->m_spVideoDecoder.GetAddressOf()));
1032bf215546Sopenharmony_ci      if (FAILED(hr)) {
1033bf215546Sopenharmony_ci         debug_printf(
1034bf215546Sopenharmony_ci            "[d3d12_video_decoder] d3d12_video_decoder_reconfigure_dpb - CreateVideoDecoder failed with HR %x\n",
1035bf215546Sopenharmony_ci            hr);
1036bf215546Sopenharmony_ci         return false;
1037bf215546Sopenharmony_ci      }
1038bf215546Sopenharmony_ci      // Update state after CreateVideoDecoder succeeds only.
1039bf215546Sopenharmony_ci      pD3D12Dec->m_decoderDesc = decoderDesc;
1040bf215546Sopenharmony_ci   }
1041bf215546Sopenharmony_ci
1042bf215546Sopenharmony_ci   if (!pD3D12Dec->m_spDPBManager || !pD3D12Dec->m_spVideoDecoderHeap ||
1043bf215546Sopenharmony_ci       pD3D12Dec->m_decodeFormat != outputResourceDesc.Format || pD3D12Dec->m_decoderHeapDesc.DecodeWidth != width ||
1044bf215546Sopenharmony_ci       pD3D12Dec->m_decoderHeapDesc.DecodeHeight != height ||
1045bf215546Sopenharmony_ci       pD3D12Dec->m_decoderHeapDesc.MaxDecodePictureBufferCount < maxDPB) {
1046bf215546Sopenharmony_ci      // Detect the combination of AOT/ReferenceOnly to configure the DPB manager
1047bf215546Sopenharmony_ci      uint16_t referenceCount = (conversionArguments.Enable) ? (uint16_t) conversionArguments.ReferenceFrameCount +
1048bf215546Sopenharmony_ci                                                                  1 /*extra slot for current picture*/ :
1049bf215546Sopenharmony_ci                                                               maxDPB;
1050bf215546Sopenharmony_ci      d3d12_video_decode_dpb_descriptor dpbDesc = {};
1051bf215546Sopenharmony_ci      dpbDesc.Width = (conversionArguments.Enable) ? conversionArguments.ReferenceInfo.Width : width;
1052bf215546Sopenharmony_ci      dpbDesc.Height = (conversionArguments.Enable) ? conversionArguments.ReferenceInfo.Height : height;
1053bf215546Sopenharmony_ci      dpbDesc.Format =
1054bf215546Sopenharmony_ci         (conversionArguments.Enable) ? conversionArguments.ReferenceInfo.Format.Format : outputResourceDesc.Format;
1055bf215546Sopenharmony_ci      dpbDesc.fArrayOfTexture =
1056bf215546Sopenharmony_ci         ((pD3D12Dec->m_ConfigDecoderSpecificFlags & d3d12_video_decode_config_specific_flag_array_of_textures) != 0);
1057bf215546Sopenharmony_ci      dpbDesc.dpbSize = referenceCount;
1058bf215546Sopenharmony_ci      dpbDesc.m_NodeMask = pD3D12Dec->m_NodeMask;
1059bf215546Sopenharmony_ci      dpbDesc.fReferenceOnly = ((pD3D12Dec->m_ConfigDecoderSpecificFlags &
1060bf215546Sopenharmony_ci                                 d3d12_video_decode_config_specific_flag_reference_only_textures_required) != 0);
1061bf215546Sopenharmony_ci
1062bf215546Sopenharmony_ci      // Create DPB manager
1063bf215546Sopenharmony_ci      if (pD3D12Dec->m_spDPBManager == nullptr) {
1064bf215546Sopenharmony_ci         pD3D12Dec->m_spDPBManager.reset(new d3d12_video_decoder_references_manager(pD3D12Dec->m_pD3D12Screen,
1065bf215546Sopenharmony_ci                                                                                    pD3D12Dec->m_NodeMask,
1066bf215546Sopenharmony_ci                                                                                    pD3D12Dec->m_d3d12DecProfileType,
1067bf215546Sopenharmony_ci                                                                                    dpbDesc));
1068bf215546Sopenharmony_ci      }
1069bf215546Sopenharmony_ci
1070bf215546Sopenharmony_ci      //
1071bf215546Sopenharmony_ci      // (Re)-create decoder heap
1072bf215546Sopenharmony_ci      //
1073bf215546Sopenharmony_ci      D3D12_VIDEO_DECODER_HEAP_DESC decoderHeapDesc = {};
1074bf215546Sopenharmony_ci      decoderHeapDesc.NodeMask = pD3D12Dec->m_NodeMask;
1075bf215546Sopenharmony_ci      decoderHeapDesc.Configuration = pD3D12Dec->m_decoderDesc.Configuration;
1076bf215546Sopenharmony_ci      decoderHeapDesc.DecodeWidth = dpbDesc.Width;
1077bf215546Sopenharmony_ci      decoderHeapDesc.DecodeHeight = dpbDesc.Height;
1078bf215546Sopenharmony_ci      decoderHeapDesc.Format = dpbDesc.Format;
1079bf215546Sopenharmony_ci      decoderHeapDesc.MaxDecodePictureBufferCount = maxDPB;
1080bf215546Sopenharmony_ci      pD3D12Dec->m_spVideoDecoderHeap.Reset();
1081bf215546Sopenharmony_ci      HRESULT hr = pD3D12Dec->m_spD3D12VideoDevice->CreateVideoDecoderHeap(
1082bf215546Sopenharmony_ci         &decoderHeapDesc,
1083bf215546Sopenharmony_ci         IID_PPV_ARGS(pD3D12Dec->m_spVideoDecoderHeap.GetAddressOf()));
1084bf215546Sopenharmony_ci      if (FAILED(hr)) {
1085bf215546Sopenharmony_ci         debug_printf(
1086bf215546Sopenharmony_ci            "[d3d12_video_decoder] d3d12_video_decoder_reconfigure_dpb - CreateVideoDecoderHeap failed with HR %x\n",
1087bf215546Sopenharmony_ci            hr);
1088bf215546Sopenharmony_ci         return false;
1089bf215546Sopenharmony_ci      }
1090bf215546Sopenharmony_ci      // Update pD3D12Dec after CreateVideoDecoderHeap succeeds only.
1091bf215546Sopenharmony_ci      pD3D12Dec->m_decoderHeapDesc = decoderHeapDesc;
1092bf215546Sopenharmony_ci   }
1093bf215546Sopenharmony_ci
1094bf215546Sopenharmony_ci   pD3D12Dec->m_decodeFormat = outputResourceDesc.Format;
1095bf215546Sopenharmony_ci
1096bf215546Sopenharmony_ci   return true;
1097bf215546Sopenharmony_ci}
1098bf215546Sopenharmony_ci
1099bf215546Sopenharmony_civoid
1100bf215546Sopenharmony_cid3d12_video_decoder_refresh_dpb_active_references(struct d3d12_video_decoder *pD3D12Dec)
1101bf215546Sopenharmony_ci{
1102bf215546Sopenharmony_ci   switch (pD3D12Dec->m_d3d12DecProfileType) {
1103bf215546Sopenharmony_ci      case d3d12_video_decode_profile_type_h264:
1104bf215546Sopenharmony_ci      {
1105bf215546Sopenharmony_ci         d3d12_video_decoder_refresh_dpb_active_references_h264(pD3D12Dec);
1106bf215546Sopenharmony_ci      } break;
1107bf215546Sopenharmony_ci
1108bf215546Sopenharmony_ci      default:
1109bf215546Sopenharmony_ci      {
1110bf215546Sopenharmony_ci         unreachable("Unsupported d3d12_video_decode_profile_type");
1111bf215546Sopenharmony_ci      } break;
1112bf215546Sopenharmony_ci   }
1113bf215546Sopenharmony_ci}
1114bf215546Sopenharmony_ci
1115bf215546Sopenharmony_civoid
1116bf215546Sopenharmony_cid3d12_video_decoder_get_frame_info(
1117bf215546Sopenharmony_ci   struct d3d12_video_decoder *pD3D12Dec, uint32_t *pWidth, uint32_t *pHeight, uint16_t *pMaxDPB, bool &isInterlaced)
1118bf215546Sopenharmony_ci{
1119bf215546Sopenharmony_ci   *pWidth = 0;
1120bf215546Sopenharmony_ci   *pHeight = 0;
1121bf215546Sopenharmony_ci   *pMaxDPB = 0;
1122bf215546Sopenharmony_ci   isInterlaced = false;
1123bf215546Sopenharmony_ci
1124bf215546Sopenharmony_ci   switch (pD3D12Dec->m_d3d12DecProfileType) {
1125bf215546Sopenharmony_ci      case d3d12_video_decode_profile_type_h264:
1126bf215546Sopenharmony_ci      {
1127bf215546Sopenharmony_ci         d3d12_video_decoder_get_frame_info_h264(pD3D12Dec, pWidth, pHeight, pMaxDPB, isInterlaced);
1128bf215546Sopenharmony_ci      } break;
1129bf215546Sopenharmony_ci
1130bf215546Sopenharmony_ci      default:
1131bf215546Sopenharmony_ci      {
1132bf215546Sopenharmony_ci         unreachable("Unsupported d3d12_video_decode_profile_type");
1133bf215546Sopenharmony_ci      } break;
1134bf215546Sopenharmony_ci   }
1135bf215546Sopenharmony_ci
1136bf215546Sopenharmony_ci   if (pD3D12Dec->m_ConfigDecoderSpecificFlags & d3d12_video_decode_config_specific_flag_alignment_height) {
1137bf215546Sopenharmony_ci      const uint32_t AlignmentMask = 31;
1138bf215546Sopenharmony_ci      *pHeight = (*pHeight + AlignmentMask) & ~AlignmentMask;
1139bf215546Sopenharmony_ci   }
1140bf215546Sopenharmony_ci}
1141bf215546Sopenharmony_ci
1142bf215546Sopenharmony_ci///
1143bf215546Sopenharmony_ci/// Returns the number of bytes starting from [buf.data() + buffsetOffset] where the _targetCode_ is found
1144bf215546Sopenharmony_ci/// Returns -1 if start code not found
1145bf215546Sopenharmony_ci///
1146bf215546Sopenharmony_ciint
1147bf215546Sopenharmony_cid3d12_video_decoder_get_next_startcode_offset(std::vector<uint8_t> &buf,
1148bf215546Sopenharmony_ci                                              unsigned int bufferOffset,
1149bf215546Sopenharmony_ci                                              unsigned int targetCode,
1150bf215546Sopenharmony_ci                                              unsigned int targetCodeBitSize,
1151bf215546Sopenharmony_ci                                              unsigned int numBitsToSearchIntoBuffer)
1152bf215546Sopenharmony_ci{
1153bf215546Sopenharmony_ci   struct vl_vlc vlc = { 0 };
1154bf215546Sopenharmony_ci
1155bf215546Sopenharmony_ci   // Shorten the buffer to be [buffetOffset, endOfBuf)
1156bf215546Sopenharmony_ci   unsigned int bufSize = buf.size() - bufferOffset;
1157bf215546Sopenharmony_ci   uint8_t *bufPtr = buf.data();
1158bf215546Sopenharmony_ci   bufPtr += bufferOffset;
1159bf215546Sopenharmony_ci
1160bf215546Sopenharmony_ci   /* search the first numBitsToSearchIntoBuffer bytes for a startcode */
1161bf215546Sopenharmony_ci   vl_vlc_init(&vlc, 1, (const void *const *) &bufPtr, &bufSize);
1162bf215546Sopenharmony_ci   for (uint i = 0; i < numBitsToSearchIntoBuffer && vl_vlc_bits_left(&vlc) >= targetCodeBitSize; ++i) {
1163bf215546Sopenharmony_ci      if (vl_vlc_peekbits(&vlc, targetCodeBitSize) == targetCode)
1164bf215546Sopenharmony_ci         return i;
1165bf215546Sopenharmony_ci      vl_vlc_eatbits(&vlc, 8);   // Stride is 8 bits = 1 byte
1166bf215546Sopenharmony_ci      vl_vlc_fillbits(&vlc);
1167bf215546Sopenharmony_ci   }
1168bf215546Sopenharmony_ci
1169bf215546Sopenharmony_ci   return -1;
1170bf215546Sopenharmony_ci}
1171bf215546Sopenharmony_ci
1172bf215546Sopenharmony_civoid
1173bf215546Sopenharmony_cid3d12_video_decoder_store_converted_dxva_picparams_from_pipe_input(
1174bf215546Sopenharmony_ci   struct d3d12_video_decoder *codec,   // input argument, current decoder
1175bf215546Sopenharmony_ci   struct pipe_picture_desc
1176bf215546Sopenharmony_ci      *picture,   // input argument, base structure of pipe_XXX_picture_desc where XXX is the codec name
1177bf215546Sopenharmony_ci   struct d3d12_video_buffer *pD3D12VideoBuffer   // input argument, target video buffer
1178bf215546Sopenharmony_ci)
1179bf215546Sopenharmony_ci{
1180bf215546Sopenharmony_ci   assert(picture);
1181bf215546Sopenharmony_ci   assert(codec);
1182bf215546Sopenharmony_ci   struct d3d12_video_decoder *pD3D12Dec = (struct d3d12_video_decoder *) codec;
1183bf215546Sopenharmony_ci
1184bf215546Sopenharmony_ci   d3d12_video_decode_profile_type profileType =
1185bf215546Sopenharmony_ci      d3d12_video_decoder_convert_pipe_video_profile_to_profile_type(codec->base.profile);
1186bf215546Sopenharmony_ci   switch (profileType) {
1187bf215546Sopenharmony_ci      case d3d12_video_decode_profile_type_h264:
1188bf215546Sopenharmony_ci      {
1189bf215546Sopenharmony_ci         size_t dxvaPicParamsBufferSize = sizeof(DXVA_PicParams_H264);
1190bf215546Sopenharmony_ci         pipe_h264_picture_desc *pPicControlH264 = (pipe_h264_picture_desc *) picture;
1191bf215546Sopenharmony_ci         ID3D12Resource *pPipeD3D12DstResource = d3d12_resource_resource(pD3D12VideoBuffer->texture);
1192bf215546Sopenharmony_ci         D3D12_RESOURCE_DESC outputResourceDesc = GetDesc(pPipeD3D12DstResource);
1193bf215546Sopenharmony_ci         DXVA_PicParams_H264 dxvaPicParamsH264 =
1194bf215546Sopenharmony_ci            d3d12_video_decoder_dxva_picparams_from_pipe_picparams_h264(pD3D12Dec->m_fenceValue,
1195bf215546Sopenharmony_ci                                                                        codec->base.profile,
1196bf215546Sopenharmony_ci                                                                        outputResourceDesc.Width,
1197bf215546Sopenharmony_ci                                                                        outputResourceDesc.Height,
1198bf215546Sopenharmony_ci                                                                        pPicControlH264);
1199bf215546Sopenharmony_ci
1200bf215546Sopenharmony_ci         d3d12_video_decoder_store_dxva_picparams_in_picparams_buffer(codec,
1201bf215546Sopenharmony_ci                                                                      &dxvaPicParamsH264,
1202bf215546Sopenharmony_ci                                                                      dxvaPicParamsBufferSize);
1203bf215546Sopenharmony_ci
1204bf215546Sopenharmony_ci         size_t dxvaQMatrixBufferSize = sizeof(DXVA_Qmatrix_H264);
1205bf215546Sopenharmony_ci         DXVA_Qmatrix_H264 dxvaQmatrixH264 = {};
1206bf215546Sopenharmony_ci         d3d12_video_decoder_dxva_qmatrix_from_pipe_picparams_h264((pipe_h264_picture_desc *) picture,
1207bf215546Sopenharmony_ci                                                                   dxvaQmatrixH264);
1208bf215546Sopenharmony_ci         d3d12_video_decoder_store_dxva_qmatrix_in_qmatrix_buffer(codec, &dxvaQmatrixH264, dxvaQMatrixBufferSize);
1209bf215546Sopenharmony_ci      } break;
1210bf215546Sopenharmony_ci      default:
1211bf215546Sopenharmony_ci      {
1212bf215546Sopenharmony_ci         unreachable("Unsupported d3d12_video_decode_profile_type");
1213bf215546Sopenharmony_ci      } break;
1214bf215546Sopenharmony_ci   }
1215bf215546Sopenharmony_ci}
1216bf215546Sopenharmony_ci
1217bf215546Sopenharmony_civoid
1218bf215546Sopenharmony_cid3d12_video_decoder_prepare_dxva_slices_control(
1219bf215546Sopenharmony_ci   struct d3d12_video_decoder *pD3D12Dec,   // input argument, current decoder
1220bf215546Sopenharmony_ci   struct pipe_picture_desc *picture
1221bf215546Sopenharmony_ci)
1222bf215546Sopenharmony_ci{
1223bf215546Sopenharmony_ci   d3d12_video_decode_profile_type profileType =
1224bf215546Sopenharmony_ci      d3d12_video_decoder_convert_pipe_video_profile_to_profile_type(pD3D12Dec->base.profile);
1225bf215546Sopenharmony_ci   switch (profileType) {
1226bf215546Sopenharmony_ci      case d3d12_video_decode_profile_type_h264:
1227bf215546Sopenharmony_ci      {
1228bf215546Sopenharmony_ci
1229bf215546Sopenharmony_ci         std::vector<DXVA_Slice_H264_Short> pOutSliceControlBuffers;
1230bf215546Sopenharmony_ci         struct pipe_h264_picture_desc* picture_h264 = (struct pipe_h264_picture_desc*) picture;
1231bf215546Sopenharmony_ci         d3d12_video_decoder_prepare_dxva_slices_control_h264(pD3D12Dec, pOutSliceControlBuffers, picture_h264);
1232bf215546Sopenharmony_ci
1233bf215546Sopenharmony_ci         assert(sizeof(pOutSliceControlBuffers.data()[0]) == sizeof(DXVA_Slice_H264_Short));
1234bf215546Sopenharmony_ci         uint64_t DXVAStructSize = pOutSliceControlBuffers.size() * sizeof((pOutSliceControlBuffers.data()[0]));
1235bf215546Sopenharmony_ci         assert((DXVAStructSize % sizeof(DXVA_Slice_H264_Short)) == 0);
1236bf215546Sopenharmony_ci         d3d12_video_decoder_store_dxva_slicecontrol_in_slicecontrol_buffer(pD3D12Dec,
1237bf215546Sopenharmony_ci                                                                            pOutSliceControlBuffers.data(),
1238bf215546Sopenharmony_ci                                                                            DXVAStructSize);
1239bf215546Sopenharmony_ci         assert(pD3D12Dec->m_SliceControlBuffer.size() == DXVAStructSize);
1240bf215546Sopenharmony_ci      } break;
1241bf215546Sopenharmony_ci      default:
1242bf215546Sopenharmony_ci      {
1243bf215546Sopenharmony_ci         unreachable("Unsupported d3d12_video_decode_profile_type");
1244bf215546Sopenharmony_ci      } break;
1245bf215546Sopenharmony_ci   }
1246bf215546Sopenharmony_ci}
1247bf215546Sopenharmony_ci
1248bf215546Sopenharmony_civoid
1249bf215546Sopenharmony_cid3d12_video_decoder_store_dxva_slicecontrol_in_slicecontrol_buffer(struct d3d12_video_decoder *pD3D12Dec,
1250bf215546Sopenharmony_ci                                                                   void *pDXVAStruct,
1251bf215546Sopenharmony_ci                                                                   uint64_t DXVAStructSize)
1252bf215546Sopenharmony_ci{
1253bf215546Sopenharmony_ci   if (pD3D12Dec->m_SliceControlBuffer.capacity() < DXVAStructSize) {
1254bf215546Sopenharmony_ci      pD3D12Dec->m_SliceControlBuffer.reserve(DXVAStructSize);
1255bf215546Sopenharmony_ci   }
1256bf215546Sopenharmony_ci
1257bf215546Sopenharmony_ci   pD3D12Dec->m_SliceControlBuffer.resize(DXVAStructSize);
1258bf215546Sopenharmony_ci   memcpy(pD3D12Dec->m_SliceControlBuffer.data(), pDXVAStruct, DXVAStructSize);
1259bf215546Sopenharmony_ci}
1260bf215546Sopenharmony_ci
1261bf215546Sopenharmony_civoid
1262bf215546Sopenharmony_cid3d12_video_decoder_store_dxva_qmatrix_in_qmatrix_buffer(struct d3d12_video_decoder *pD3D12Dec,
1263bf215546Sopenharmony_ci                                                         void *pDXVAStruct,
1264bf215546Sopenharmony_ci                                                         uint64_t DXVAStructSize)
1265bf215546Sopenharmony_ci{
1266bf215546Sopenharmony_ci   if (pD3D12Dec->m_InverseQuantMatrixBuffer.capacity() < DXVAStructSize) {
1267bf215546Sopenharmony_ci      pD3D12Dec->m_InverseQuantMatrixBuffer.reserve(DXVAStructSize);
1268bf215546Sopenharmony_ci   }
1269bf215546Sopenharmony_ci
1270bf215546Sopenharmony_ci   pD3D12Dec->m_InverseQuantMatrixBuffer.resize(DXVAStructSize);
1271bf215546Sopenharmony_ci   memcpy(pD3D12Dec->m_InverseQuantMatrixBuffer.data(), pDXVAStruct, DXVAStructSize);
1272bf215546Sopenharmony_ci}
1273bf215546Sopenharmony_ci
1274bf215546Sopenharmony_civoid
1275bf215546Sopenharmony_cid3d12_video_decoder_store_dxva_picparams_in_picparams_buffer(struct d3d12_video_decoder *pD3D12Dec,
1276bf215546Sopenharmony_ci                                                             void *pDXVAStruct,
1277bf215546Sopenharmony_ci                                                             uint64_t DXVAStructSize)
1278bf215546Sopenharmony_ci{
1279bf215546Sopenharmony_ci   if (pD3D12Dec->m_picParamsBuffer.capacity() < DXVAStructSize) {
1280bf215546Sopenharmony_ci      pD3D12Dec->m_picParamsBuffer.reserve(DXVAStructSize);
1281bf215546Sopenharmony_ci   }
1282bf215546Sopenharmony_ci
1283bf215546Sopenharmony_ci   pD3D12Dec->m_picParamsBuffer.resize(DXVAStructSize);
1284bf215546Sopenharmony_ci   memcpy(pD3D12Dec->m_picParamsBuffer.data(), pDXVAStruct, DXVAStructSize);
1285bf215546Sopenharmony_ci}
1286bf215546Sopenharmony_ci
1287bf215546Sopenharmony_cibool
1288bf215546Sopenharmony_cid3d12_video_decoder_supports_aot_dpb(D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT decodeSupport,
1289bf215546Sopenharmony_ci                                     d3d12_video_decode_profile_type profileType)
1290bf215546Sopenharmony_ci{
1291bf215546Sopenharmony_ci   bool supportedProfile = false;
1292bf215546Sopenharmony_ci   switch (profileType) {
1293bf215546Sopenharmony_ci      case d3d12_video_decode_profile_type_h264:
1294bf215546Sopenharmony_ci         supportedProfile = true;
1295bf215546Sopenharmony_ci         break;
1296bf215546Sopenharmony_ci      default:
1297bf215546Sopenharmony_ci         supportedProfile = false;
1298bf215546Sopenharmony_ci         break;
1299bf215546Sopenharmony_ci   }
1300bf215546Sopenharmony_ci
1301bf215546Sopenharmony_ci   return (decodeSupport.DecodeTier >= D3D12_VIDEO_DECODE_TIER_2) && supportedProfile;
1302bf215546Sopenharmony_ci}
1303bf215546Sopenharmony_ci
1304bf215546Sopenharmony_cid3d12_video_decode_profile_type
1305bf215546Sopenharmony_cid3d12_video_decoder_convert_pipe_video_profile_to_profile_type(enum pipe_video_profile profile)
1306bf215546Sopenharmony_ci{
1307bf215546Sopenharmony_ci   switch (profile) {
1308bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
1309bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
1310bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
1311bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED:
1312bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
1313bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
1314bf215546Sopenharmony_ci         return d3d12_video_decode_profile_type_h264;
1315bf215546Sopenharmony_ci      default:
1316bf215546Sopenharmony_ci      {
1317bf215546Sopenharmony_ci         unreachable("Unsupported pipe video profile");
1318bf215546Sopenharmony_ci      } break;
1319bf215546Sopenharmony_ci   }
1320bf215546Sopenharmony_ci}
1321bf215546Sopenharmony_ci
1322bf215546Sopenharmony_ciGUID
1323bf215546Sopenharmony_cid3d12_video_decoder_convert_pipe_video_profile_to_d3d12_profile(enum pipe_video_profile profile)
1324bf215546Sopenharmony_ci{
1325bf215546Sopenharmony_ci   switch (profile) {
1326bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
1327bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
1328bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
1329bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED:
1330bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
1331bf215546Sopenharmony_ci      case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
1332bf215546Sopenharmony_ci         return D3D12_VIDEO_DECODE_PROFILE_H264;
1333bf215546Sopenharmony_ci      default:
1334bf215546Sopenharmony_ci         return {};
1335bf215546Sopenharmony_ci   }
1336bf215546Sopenharmony_ci}
1337bf215546Sopenharmony_ci
1338bf215546Sopenharmony_ciGUID
1339bf215546Sopenharmony_cid3d12_video_decoder_resolve_profile(d3d12_video_decode_profile_type profileType)
1340bf215546Sopenharmony_ci{
1341bf215546Sopenharmony_ci   switch (profileType) {
1342bf215546Sopenharmony_ci      case d3d12_video_decode_profile_type_h264:
1343bf215546Sopenharmony_ci         return D3D12_VIDEO_DECODE_PROFILE_H264;
1344bf215546Sopenharmony_ci         break;
1345bf215546Sopenharmony_ci      default:
1346bf215546Sopenharmony_ci      {
1347bf215546Sopenharmony_ci         unreachable("Unsupported d3d12_video_decode_profile_type");
1348bf215546Sopenharmony_ci      } break;
1349bf215546Sopenharmony_ci   }
1350bf215546Sopenharmony_ci}
1351