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