• 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_screen.h"
25 #include "d3d12_video_screen.h"
26 #include "d3d12_format.h"
27 #include "util/u_video.h"
28 #include <directx/d3d12video.h>
29 
30 #include <wrl/client.h>
31 using Microsoft::WRL::ComPtr;
32 
33 #include "d3d12_video_types.h"
34 
35 static bool
d3d12_video_buffer_is_format_supported(struct pipe_screen * screen,enum pipe_format format,enum pipe_video_profile profile,enum pipe_video_entrypoint entrypoint)36 d3d12_video_buffer_is_format_supported(struct pipe_screen *screen,
37                                        enum pipe_format format,
38                                        enum pipe_video_profile profile,
39                                        enum pipe_video_entrypoint entrypoint)
40 {
41    return (format == PIPE_FORMAT_NV12);
42 }
43 
44 
45 struct d3d12_video_resolution_to_level_mapping_entry
46 {
47    D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC resolution;
48    uint32_t level;
49 };
50 
51 static d3d12_video_resolution_to_level_mapping_entry
get_max_level_resolution_video_decode_support(D3D12_VIDEO_DECODE_CONFIGURATION decoderConfig,DXGI_FORMAT format,struct pipe_screen * pscreen,bool & outSupportAny,D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT & outSupportedConfig)52 get_max_level_resolution_video_decode_support(D3D12_VIDEO_DECODE_CONFIGURATION decoderConfig,
53                                               DXGI_FORMAT format,
54                                               struct pipe_screen *pscreen,
55                                               bool &outSupportAny,
56                                               D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT &outSupportedConfig)
57 {
58    d3d12_video_resolution_to_level_mapping_entry supportedResult = {};
59    outSupportAny = false;
60    outSupportedConfig = {};
61 
62    ComPtr<ID3D12VideoDevice> spD3D12VideoDevice;
63    struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen;
64    if (FAILED(pD3D12Screen->dev->QueryInterface(IID_PPV_ARGS(spD3D12VideoDevice.GetAddressOf())))) {
65       // No video support in underlying d3d12 device (decode needs ID3D12VideoDevice)
66       return supportedResult;
67    }
68 
69    d3d12_video_resolution_to_level_mapping_entry resolutionsLevelList[] = {
70       { { 8192, 4320 }, 61 },   // 8k
71       { { 7680, 4800 }, 61 },   // 8k - alternative
72       { { 7680, 4320 }, 61 },   // 8k - alternative
73       { { 4096, 2304 }, 52 },   // 2160p (4K)
74       { { 4096, 2160 }, 52 },   // 2160p (4K) - alternative
75       { { 2560, 1440 }, 51 },   // 1440p
76       { { 1920, 1200 }, 5 },    // 1200p
77       { { 1920, 1080 }, 42 },   // 1080p
78       { { 1280, 720 }, 4 },     // 720p
79       { { 800, 600 }, 31 },
80    };
81 
82    D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT decodeSupport = {};
83    decodeSupport.Configuration = decoderConfig;
84    decodeSupport.DecodeFormat = format;
85 
86    uint32_t idxResol = 0;
87    while ((idxResol < ARRAY_SIZE(resolutionsLevelList)) && !outSupportAny) {
88 
89       decodeSupport.Width = resolutionsLevelList[idxResol].resolution.Width;
90       decodeSupport.Height = resolutionsLevelList[idxResol].resolution.Height;
91 
92       if (SUCCEEDED(spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_DECODE_SUPPORT,
93                                                             &decodeSupport,
94                                                             sizeof(decodeSupport)))) {
95 
96          if (((decodeSupport.SupportFlags & D3D12_VIDEO_DECODE_SUPPORT_FLAG_SUPPORTED) != 0) ||
97              decodeSupport.DecodeTier > D3D12_VIDEO_DECODE_TIER_NOT_SUPPORTED) {
98 
99             outSupportAny = true;
100             outSupportedConfig = decodeSupport;
101             supportedResult = resolutionsLevelList[idxResol];
102          }
103       }
104 
105       idxResol++;
106    }
107 
108    return supportedResult;
109 }
110 
111 static bool
d3d12_has_video_decode_support(struct pipe_screen * pscreen,enum pipe_video_profile profile)112 d3d12_has_video_decode_support(struct pipe_screen *pscreen, enum pipe_video_profile profile)
113 {
114    ComPtr<ID3D12VideoDevice> spD3D12VideoDevice;
115    struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen;
116    if (FAILED(pD3D12Screen->dev->QueryInterface(IID_PPV_ARGS(spD3D12VideoDevice.GetAddressOf())))) {
117       // No video support in underlying d3d12 device (needs ID3D12VideoDevice)
118       return 0;
119    }
120 
121    D3D12_FEATURE_DATA_VIDEO_FEATURE_AREA_SUPPORT VideoFeatureAreaSupport = {};
122    if (FAILED(spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_FEATURE_AREA_SUPPORT,
123                                                       &VideoFeatureAreaSupport,
124                                                       sizeof(VideoFeatureAreaSupport)))) {
125       return false;
126    }
127 
128    // Supported profiles below
129    bool supportsProfile = false;
130    switch (profile) {
131       case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
132       case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED:
133       case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
134       case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
135       case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
136       case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
137       {
138          supportsProfile = true;
139       } break;
140       default:
141          supportsProfile = false;
142    }
143 
144    return VideoFeatureAreaSupport.VideoDecodeSupport && supportsProfile;
145 }
146 
147 static bool
d3d12_video_encode_max_supported_level_for_profile(const D3D12_VIDEO_ENCODER_CODEC & argCodec,const D3D12_VIDEO_ENCODER_PROFILE_DESC & argTargetProfile,D3D12_VIDEO_ENCODER_LEVEL_SETTING & minLvl,D3D12_VIDEO_ENCODER_LEVEL_SETTING & maxLvl,ID3D12VideoDevice3 * pD3D12VideoDevice)148 d3d12_video_encode_max_supported_level_for_profile(const D3D12_VIDEO_ENCODER_CODEC &argCodec,
149                                                    const D3D12_VIDEO_ENCODER_PROFILE_DESC &argTargetProfile,
150                                                    D3D12_VIDEO_ENCODER_LEVEL_SETTING &minLvl,
151                                                    D3D12_VIDEO_ENCODER_LEVEL_SETTING &maxLvl,
152                                                    ID3D12VideoDevice3 *pD3D12VideoDevice)
153 {
154    D3D12_FEATURE_DATA_VIDEO_ENCODER_PROFILE_LEVEL capLevelData = {};
155    capLevelData.NodeIndex = 0;
156    capLevelData.Codec = argCodec;
157    capLevelData.Profile = argTargetProfile;
158    capLevelData.MinSupportedLevel = minLvl;
159    capLevelData.MaxSupportedLevel = maxLvl;
160 
161    if (FAILED(pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_PROFILE_LEVEL,
162                                                      &capLevelData,
163                                                      sizeof(capLevelData)))) {
164       return false;
165    }
166 
167    return capLevelData.IsSupported;
168 }
169 
170 static bool
d3d12_video_encode_max_supported_resolution(const D3D12_VIDEO_ENCODER_CODEC & argTargetCodec,D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC & maxResolution,ID3D12VideoDevice3 * pD3D12VideoDevice)171 d3d12_video_encode_max_supported_resolution(const D3D12_VIDEO_ENCODER_CODEC &argTargetCodec,
172                                             D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC &maxResolution,
173                                             ID3D12VideoDevice3 *pD3D12VideoDevice)
174 {
175    D3D12_FEATURE_DATA_VIDEO_ENCODER_OUTPUT_RESOLUTION_RATIOS_COUNT capResRatiosCountData = { 0, argTargetCodec, 0 };
176 
177    if (FAILED(pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_OUTPUT_RESOLUTION_RATIOS_COUNT,
178                                                      &capResRatiosCountData,
179                                                      sizeof(capResRatiosCountData)))) {
180       return false;
181    }
182 
183    D3D12_FEATURE_DATA_VIDEO_ENCODER_OUTPUT_RESOLUTION capOutputResolutionData = {};
184    capOutputResolutionData.NodeIndex = 0;
185    capOutputResolutionData.Codec = argTargetCodec;
186    capOutputResolutionData.ResolutionRatiosCount = capResRatiosCountData.ResolutionRatiosCount;
187 
188    std::vector<D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_RATIO_DESC> ratiosTmpOutput;
189    if (capResRatiosCountData.ResolutionRatiosCount > 0) {
190       ratiosTmpOutput.resize(capResRatiosCountData.ResolutionRatiosCount);
191       capOutputResolutionData.pResolutionRatios = ratiosTmpOutput.data();
192    } else {
193       capOutputResolutionData.pResolutionRatios = nullptr;
194    }
195 
196    if (FAILED(pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_OUTPUT_RESOLUTION,
197                                                      &capOutputResolutionData,
198                                                      sizeof(capOutputResolutionData))) ||
199        !capOutputResolutionData.IsSupported) {
200       return false;
201    }
202 
203    maxResolution = capOutputResolutionData.MaxResolutionSupported;
204 
205    return true;
206 }
207 
208 static uint32_t
d3d12_video_encode_supported_references_per_frame_structures(const D3D12_VIDEO_ENCODER_CODEC & codec,D3D12_VIDEO_ENCODER_PROFILE_H264 profile,D3D12_VIDEO_ENCODER_LEVELS_H264 level,ID3D12VideoDevice3 * pD3D12VideoDevice)209 d3d12_video_encode_supported_references_per_frame_structures(const D3D12_VIDEO_ENCODER_CODEC &codec,
210                                                              D3D12_VIDEO_ENCODER_PROFILE_H264 profile,
211                                                              D3D12_VIDEO_ENCODER_LEVELS_H264 level,
212                                                              ID3D12VideoDevice3 *pD3D12VideoDevice)
213 {
214    uint32_t supportedMaxRefFrames = 0u;
215 
216    D3D12_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT_H264 h264PictureControl = {};
217    D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT capPictureControlData = {};
218    capPictureControlData.NodeIndex = 0;
219    capPictureControlData.Codec = codec;
220    capPictureControlData.Profile.pH264Profile = &profile;
221    capPictureControlData.Profile.DataSize = sizeof(profile);
222    capPictureControlData.PictureSupport.pH264Support = &h264PictureControl;
223    capPictureControlData.PictureSupport.DataSize = sizeof(h264PictureControl);
224    HRESULT hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT,
225                                                            &capPictureControlData,
226                                                            sizeof(capPictureControlData));
227    if (FAILED(hr)) {
228       debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
229    }
230 
231    if (capPictureControlData.IsSupported) {
232       /* This attribute determines the maximum number of reference
233        * frames supported for encoding.
234        *
235        * Note: for H.264 encoding, the value represents the maximum number
236        * of reference frames for both the reference picture list 0 (bottom
237        * 16 bits) and the reference picture list 1 (top 16 bits).
238        */
239       uint32_t maxRefForL0 = std::min(capPictureControlData.PictureSupport.pH264Support->MaxL0ReferencesForP,
240                                       capPictureControlData.PictureSupport.pH264Support->MaxL0ReferencesForB);
241       uint32_t maxRefForL1 = capPictureControlData.PictureSupport.pH264Support->MaxL1ReferencesForB;
242       supportedMaxRefFrames = (maxRefForL0 & 0xffff) | ((maxRefForL1 & 0xffff) << 16);
243    }
244 
245    return supportedMaxRefFrames;
246 }
247 
248 static uint32_t
d3d12_video_encode_supported_slice_structures(const D3D12_VIDEO_ENCODER_CODEC & codec,D3D12_VIDEO_ENCODER_PROFILE_H264 profile,D3D12_VIDEO_ENCODER_LEVELS_H264 level,ID3D12VideoDevice3 * pD3D12VideoDevice)249 d3d12_video_encode_supported_slice_structures(const D3D12_VIDEO_ENCODER_CODEC &codec,
250                                               D3D12_VIDEO_ENCODER_PROFILE_H264 profile,
251                                               D3D12_VIDEO_ENCODER_LEVELS_H264 level,
252                                               ID3D12VideoDevice3 *pD3D12VideoDevice)
253 {
254    uint32_t supportedSliceStructuresBitMask = PIPE_VIDEO_CAP_SLICE_STRUCTURE_NONE;
255 
256    D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE capDataSubregionLayout = {};
257    capDataSubregionLayout.NodeIndex = 0;
258    capDataSubregionLayout.Codec = codec;
259    capDataSubregionLayout.Profile.pH264Profile = &profile;
260    capDataSubregionLayout.Profile.DataSize = sizeof(profile);
261    capDataSubregionLayout.Level.pH264LevelSetting = &level;
262    capDataSubregionLayout.Level.DataSize = sizeof(level);
263 
264    /**
265     * pipe_video_cap_slice_structure
266     *
267     * This attribute determines slice structures supported by the
268     * driver for encoding. This attribute is a hint to the user so
269     * that he can choose a suitable surface size and how to arrange
270     * the encoding process of multiple slices per frame.
271     *
272     * More specifically, for H.264 encoding, this attribute
273     * determines the range of accepted values to
274     * h264_slice_descriptor::macroblock_address and
275     * h264_slice_descriptor::num_macroblocks.
276     */
277    capDataSubregionLayout.SubregionMode =
278       D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
279    HRESULT hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE,
280                                                            &capDataSubregionLayout,
281                                                            sizeof(capDataSubregionLayout));
282    if (FAILED(hr)) {
283       debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
284    } else if (capDataSubregionLayout.IsSupported) {
285       /* This would be setting N subregions per frame in this D3D12 mode where N = (height/blocksize) / K */
286       supportedSliceStructuresBitMask |= PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_MULTI_ROWS;
287       /* Assuming height/blocksize >= max_supported_slices, which is reported
288        in PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME and should be checked by the client*/
289       /* This would be setting N subregions per frame in this D3D12 mode where N = (height/blocksize) */
290       supportedSliceStructuresBitMask |= PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_ROWS;
291       /* This is ok, would be setting K rows per subregions in this D3D12 mode (and rounding the last one) */
292       supportedSliceStructuresBitMask |= PIPE_VIDEO_CAP_SLICE_STRUCTURE_POWER_OF_TWO_ROWS;
293    }
294 
295    capDataSubregionLayout.SubregionMode =
296       D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION;
297    hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE,
298                                                            &capDataSubregionLayout,
299                                                            sizeof(capDataSubregionLayout));
300    if (FAILED(hr)) {
301       debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
302    } else if (capDataSubregionLayout.IsSupported) {
303       /* This would be setting K rows per subregions in this D3D12 mode */
304       supportedSliceStructuresBitMask |= PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_MULTI_ROWS;
305       /* Assuming height/blocksize >= max_supported_slices, which is reported
306        in PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME and should be checked by the client*/
307       /* This would be setting 1 row per subregion in this D3D12 mode */
308       supportedSliceStructuresBitMask |= PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_ROWS;
309       /* This is ok, would be setting K rows per subregions in this D3D12 mode (and rounding the last one) */
310       supportedSliceStructuresBitMask |= PIPE_VIDEO_CAP_SLICE_STRUCTURE_POWER_OF_TWO_ROWS;
311    }
312 
313    /* Needs more work in VA frontend to support VAEncMiscParameterMaxSliceSize
314          and the driver potentially reporting back status in VACodedBufferSegment */
315 
316    /*capDataSubregionLayout.SubregionMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION;
317    hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE,
318                                                            &capDataSubregionLayout,
319                                                            sizeof(capDataSubregionLayout));
320    if (FAILED(hr)) {
321       debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
322    } else if (capDataSubregionLayout.IsSupported) {
323       supportedSliceStructuresBitMask |= PIPE_VIDEO_CAP_SLICE_STRUCTURE_MAX_SLICE_SIZE;
324    }*/
325 
326    return supportedSliceStructuresBitMask;
327 }
328 
329 static bool
d3d12_video_encode_max_supported_slices(const D3D12_VIDEO_ENCODER_CODEC & argTargetCodec,D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC maxResolution,DXGI_FORMAT encodeFormat,uint32_t & outMaxSlices,ID3D12VideoDevice3 * pD3D12VideoDevice)330 d3d12_video_encode_max_supported_slices(const D3D12_VIDEO_ENCODER_CODEC &argTargetCodec,
331                                         D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC maxResolution,
332                                         DXGI_FORMAT encodeFormat,
333                                         uint32_t &outMaxSlices,
334                                         ID3D12VideoDevice3 *pD3D12VideoDevice)
335 {
336    D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT capEncoderSupportData = {};
337    capEncoderSupportData.NodeIndex = 0;
338    capEncoderSupportData.Codec = argTargetCodec;
339    capEncoderSupportData.InputFormat = encodeFormat;
340    capEncoderSupportData.RateControl = {};
341    capEncoderSupportData.RateControl.Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
342    capEncoderSupportData.RateControl.TargetFrameRate.Numerator = 60;
343    capEncoderSupportData.RateControl.TargetFrameRate.Denominator = 1;
344    D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP rcCqp = { 25, 25, 25 };
345    capEncoderSupportData.RateControl.ConfigParams.pConfiguration_CQP = &rcCqp;
346    capEncoderSupportData.RateControl.ConfigParams.DataSize = sizeof(rcCqp);
347    capEncoderSupportData.IntraRefresh = D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE;
348    capEncoderSupportData.ResolutionsListCount = 1;
349    capEncoderSupportData.pResolutionList = &maxResolution;
350    capEncoderSupportData.MaxReferenceFramesInDPB = 1;
351    capEncoderSupportData.SubregionFrameEncoding =
352       D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
353 
354    D3D12_VIDEO_ENCODER_PROFILE_H264 h264prof = {};
355    D3D12_VIDEO_ENCODER_LEVELS_H264 h264lvl = {};
356    D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_H264 h264Gop = { 1, 0, 0, 0, 0 };
357    D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 h264Config = {};
358    switch (argTargetCodec) {
359       case D3D12_VIDEO_ENCODER_CODEC_H264:
360       {
361          capEncoderSupportData.SuggestedProfile.pH264Profile = &h264prof;
362          capEncoderSupportData.SuggestedProfile.DataSize = sizeof(h264prof);
363          capEncoderSupportData.SuggestedLevel.pH264LevelSetting = &h264lvl;
364          capEncoderSupportData.SuggestedLevel.DataSize = sizeof(h264lvl);
365          capEncoderSupportData.CodecGopSequence.pH264GroupOfPictures = &h264Gop;
366          capEncoderSupportData.CodecGopSequence.DataSize = sizeof(h264Gop);
367          capEncoderSupportData.CodecConfiguration.DataSize = sizeof(h264Config);
368          capEncoderSupportData.CodecConfiguration.pH264Config = &h264Config;
369       } break;
370 
371       default:
372       {
373          unreachable("Unsupported D3D12_VIDEO_ENCODER_CODEC");
374       } break;
375    }
376 
377    // prepare inout storage for the resolution dependent result.
378    D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLUTION_SUPPORT_LIMITS resolutionDepCaps = {};
379    capEncoderSupportData.pResolutionDependentSupport = &resolutionDepCaps;
380 
381    HRESULT hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_SUPPORT,
382                                                            &capEncoderSupportData,
383                                                            sizeof(capEncoderSupportData));
384    if (FAILED(hr)) {
385       debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
386       return false;
387    } else {
388       bool configSupported =
389          (((capEncoderSupportData.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_GENERAL_SUPPORT_OK) != 0) &&
390             (capEncoderSupportData.ValidationFlags == D3D12_VIDEO_ENCODER_VALIDATION_FLAG_NONE));
391 
392       outMaxSlices = resolutionDepCaps.MaxSubregionsNumber;
393       return configSupported;
394    }
395 }
396 
397 static bool
d3d12_has_video_encode_support(struct pipe_screen * pscreen,enum pipe_video_profile profile,uint32_t & maxLvlSpec,D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC & maxRes,uint32_t & maxSlices,uint32_t & supportedSliceStructures,uint32_t & maxReferencesPerFrame)398 d3d12_has_video_encode_support(struct pipe_screen *pscreen,
399                                enum pipe_video_profile profile,
400                                uint32_t &maxLvlSpec,
401                                D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC &maxRes,
402                                uint32_t &maxSlices,
403                                uint32_t &supportedSliceStructures,
404                                uint32_t &maxReferencesPerFrame)
405 {
406    ComPtr<ID3D12VideoDevice3> spD3D12VideoDevice;
407    struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen;
408    if (FAILED(pD3D12Screen->dev->QueryInterface(IID_PPV_ARGS(spD3D12VideoDevice.GetAddressOf())))) {
409       // No video encode support in underlying d3d12 device (needs ID3D12VideoDevice3)
410       return 0;
411    }
412 
413    D3D12_FEATURE_DATA_VIDEO_FEATURE_AREA_SUPPORT VideoFeatureAreaSupport = {};
414    if (FAILED(spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_FEATURE_AREA_SUPPORT,
415                                                       &VideoFeatureAreaSupport,
416                                                       sizeof(VideoFeatureAreaSupport)))) {
417       return false;
418    }
419 
420    bool supportsProfile = false;
421    switch (profile) {
422       case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE:
423       case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE:
424       case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN:
425       case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH:
426       case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10:
427       {
428          supportsProfile = true;
429          D3D12_VIDEO_ENCODER_PROFILE_DESC profDesc = {};
430          D3D12_VIDEO_ENCODER_PROFILE_H264 profH264 =
431             d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_h264(profile);
432          profDesc.DataSize = sizeof(profH264);
433          profDesc.pH264Profile = &profH264;
434          D3D12_VIDEO_ENCODER_CODEC codecDesc = d3d12_video_encoder_convert_codec_to_d3d12_enc_codec(profile);
435          D3D12_VIDEO_ENCODER_LEVELS_H264 minLvlSettingH264 = static_cast<D3D12_VIDEO_ENCODER_LEVELS_H264>(0);
436          D3D12_VIDEO_ENCODER_LEVELS_H264 maxLvlSettingH264 = static_cast<D3D12_VIDEO_ENCODER_LEVELS_H264>(0);
437          D3D12_VIDEO_ENCODER_LEVEL_SETTING minLvl = {};
438          D3D12_VIDEO_ENCODER_LEVEL_SETTING maxLvl = {};
439          minLvl.pH264LevelSetting = &minLvlSettingH264;
440          minLvl.DataSize = sizeof(minLvlSettingH264);
441          maxLvl.pH264LevelSetting = &maxLvlSettingH264;
442          maxLvl.DataSize = sizeof(maxLvlSettingH264);
443          if (d3d12_video_encode_max_supported_level_for_profile(codecDesc,
444                                                                 profDesc,
445                                                                 minLvl,
446                                                                 maxLvl,
447                                                                 spD3D12VideoDevice.Get())) {
448             uint32_t constraintset3flag = false;
449             d3d12_video_encoder_convert_from_d3d12_level_h264(maxLvlSettingH264, maxLvlSpec, constraintset3flag);
450             supportsProfile = true;
451          }
452 
453          if (supportsProfile) {
454             DXGI_FORMAT encodeFormat = d3d12_convert_pipe_video_profile_to_dxgi_format(profile);
455             supportsProfile = supportsProfile &&
456                               d3d12_video_encode_max_supported_resolution(codecDesc, maxRes, spD3D12VideoDevice.Get());
457             supportsProfile = supportsProfile && d3d12_video_encode_max_supported_slices(codecDesc,
458                                                                                          maxRes,
459                                                                                          encodeFormat,
460                                                                                          maxSlices,
461                                                                                          spD3D12VideoDevice.Get());
462             supportedSliceStructures = d3d12_video_encode_supported_slice_structures(codecDesc,
463                                                                                      profH264,
464                                                                                      maxLvlSettingH264,
465                                                                                      spD3D12VideoDevice.Get());
466             maxReferencesPerFrame =
467                d3d12_video_encode_supported_references_per_frame_structures(codecDesc,
468                                                                             profH264,
469                                                                             maxLvlSettingH264,
470                                                                             spD3D12VideoDevice.Get());
471          }
472       } break;
473       default:
474          supportsProfile = false;
475    }
476 
477    return VideoFeatureAreaSupport.VideoEncodeSupport && supportsProfile;
478 }
479 
480 static int
d3d12_screen_get_video_param_decode(struct pipe_screen * pscreen,enum pipe_video_profile profile,enum pipe_video_entrypoint entrypoint,enum pipe_video_cap param)481 d3d12_screen_get_video_param_decode(struct pipe_screen *pscreen,
482                                     enum pipe_video_profile profile,
483                                     enum pipe_video_entrypoint entrypoint,
484                                     enum pipe_video_cap param)
485 {
486    switch (param) {
487       case PIPE_VIDEO_CAP_NPOT_TEXTURES:
488          return 1;
489       case PIPE_VIDEO_CAP_MAX_WIDTH:
490       case PIPE_VIDEO_CAP_MAX_HEIGHT:
491       case PIPE_VIDEO_CAP_MAX_LEVEL:
492       case PIPE_VIDEO_CAP_SUPPORTED:
493       {
494          if (d3d12_has_video_decode_support(pscreen, profile)) {
495             DXGI_FORMAT format = d3d12_convert_pipe_video_profile_to_dxgi_format(profile);
496             auto pipeFmt = d3d12_get_pipe_format(format);
497             bool formatSupported = pscreen->is_video_format_supported(pscreen, pipeFmt, profile, entrypoint);
498             if (formatSupported) {
499                GUID decodeGUID = d3d12_video_decoder_convert_pipe_video_profile_to_d3d12_profile(profile);
500                GUID emptyGUID = {};
501                if (decodeGUID != emptyGUID) {
502                   bool supportAny = false;
503                   D3D12_FEATURE_DATA_VIDEO_DECODE_SUPPORT outSupportedConfig = {};
504                   D3D12_VIDEO_DECODE_CONFIGURATION decoderConfig = { decodeGUID,
505                                                                      D3D12_BITSTREAM_ENCRYPTION_TYPE_NONE,
506                                                                      D3D12_VIDEO_FRAME_CODED_INTERLACE_TYPE_NONE };
507 
508                   d3d12_video_resolution_to_level_mapping_entry bestSupportedConfig =
509                      get_max_level_resolution_video_decode_support(decoderConfig,
510                                                                    format,
511                                                                    pscreen,
512                                                                    supportAny,
513                                                                    outSupportedConfig);
514                   if (supportAny) {
515                      if (param == PIPE_VIDEO_CAP_MAX_WIDTH) {
516                         return bestSupportedConfig.resolution.Width;
517                      } else if (param == PIPE_VIDEO_CAP_MAX_HEIGHT) {
518                         return bestSupportedConfig.resolution.Height;
519                      } else if (param == PIPE_VIDEO_CAP_MAX_LEVEL) {
520                         return bestSupportedConfig.level;
521                      } else if (param == PIPE_VIDEO_CAP_SUPPORTED) {
522                         return 1;
523                      }
524                   }
525                }
526             }
527          }
528          return 0;
529       } break;
530       case PIPE_VIDEO_CAP_PREFERED_FORMAT:
531          return PIPE_FORMAT_NV12;
532       case PIPE_VIDEO_CAP_PREFERS_INTERLACED:
533          return false;
534       case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:
535          return true;
536       case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:
537          return true;
538       case PIPE_VIDEO_SUPPORTS_CONTIGUOUS_PLANES_MAP:
539          return true;
540          break;
541       default:
542          debug_printf("[d3d12_screen_get_video_param] unknown video param: %d\n", param);
543          return 0;
544    }
545 }
546 
547 
548 static bool
d3d12_has_video_process_support(struct pipe_screen * pscreen,D3D12_FEATURE_DATA_VIDEO_PROCESS_SUPPORT & supportCaps)549 d3d12_has_video_process_support(struct pipe_screen *pscreen, D3D12_FEATURE_DATA_VIDEO_PROCESS_SUPPORT &supportCaps)
550 {
551    ComPtr<ID3D12VideoDevice2> spD3D12VideoDevice;
552    struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen;
553    if (FAILED(pD3D12Screen->dev->QueryInterface(IID_PPV_ARGS(spD3D12VideoDevice.GetAddressOf())))) {
554       // No video encode support in underlying d3d12 device (needs ID3D12VideoDevice2)
555       return false;
556    }
557 
558    D3D12_FEATURE_DATA_VIDEO_FEATURE_AREA_SUPPORT VideoFeatureAreaSupport = {};
559    if (FAILED(spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_FEATURE_AREA_SUPPORT,
560                                                       &VideoFeatureAreaSupport,
561                                                       sizeof(VideoFeatureAreaSupport)))) {
562       return false;
563    }
564 
565    struct ResolStruct {
566       uint Width;
567       uint Height;
568    };
569 
570    ResolStruct resolutionsList[] = {
571       { 8192, 8192 },   // 8k
572       { 8192, 4320 },   // 8k - alternative
573       { 7680, 4800 },   // 8k - alternative
574       { 7680, 4320 },   // 8k - alternative
575       { 4096, 2304 },   // 2160p (4K)
576       { 4096, 2160 },   // 2160p (4K) - alternative
577       { 2560, 1440 },   // 1440p
578       { 1920, 1200 },   // 1200p
579       { 1920, 1080 },   // 1080p
580       { 1280, 720 },    // 720p
581       { 800, 600 },
582    };
583 
584    uint32_t idxResol = 0;
585    bool bSupportsAny = false;
586    while ((idxResol < ARRAY_SIZE(resolutionsList)) && !bSupportsAny) {
587       supportCaps.InputSample.Width = resolutionsList[idxResol].Width;
588       supportCaps.InputSample.Height = resolutionsList[idxResol].Height;
589       if (SUCCEEDED(spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_PROCESS_SUPPORT, &supportCaps, sizeof(supportCaps)))) {
590          bSupportsAny = ((supportCaps.SupportFlags & D3D12_VIDEO_PROCESS_SUPPORT_FLAG_SUPPORTED) != 0) ;
591       }
592       idxResol++;
593    }
594 
595    return VideoFeatureAreaSupport.VideoProcessSupport && bSupportsAny;
596 }
597 
598 static int
d3d12_screen_get_video_param_postproc(struct pipe_screen * pscreen,enum pipe_video_profile profile,enum pipe_video_entrypoint entrypoint,enum pipe_video_cap param)599 d3d12_screen_get_video_param_postproc(struct pipe_screen *pscreen,
600                                     enum pipe_video_profile profile,
601                                     enum pipe_video_entrypoint entrypoint,
602                                     enum pipe_video_cap param)
603 {
604    switch (param) {
605       case PIPE_VIDEO_CAP_NPOT_TEXTURES:
606          return 1;
607       case PIPE_VIDEO_CAP_MAX_WIDTH:
608       case PIPE_VIDEO_CAP_MAX_HEIGHT:
609       case PIPE_VIDEO_CAP_SUPPORTED:
610       case PIPE_VIDEO_CAP_PREFERED_FORMAT:
611       case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:
612       case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:
613       case PIPE_VIDEO_SUPPORTS_CONTIGUOUS_PLANES_MAP:
614       case PIPE_VIDEO_CAP_VPP_MAX_INPUT_WIDTH:
615       case PIPE_VIDEO_CAP_VPP_MAX_INPUT_HEIGHT:
616       case PIPE_VIDEO_CAP_VPP_MIN_INPUT_WIDTH:
617       case PIPE_VIDEO_CAP_VPP_MIN_INPUT_HEIGHT:
618       case PIPE_VIDEO_CAP_VPP_MAX_OUTPUT_WIDTH:
619       case PIPE_VIDEO_CAP_VPP_MAX_OUTPUT_HEIGHT:
620       case PIPE_VIDEO_CAP_VPP_MIN_OUTPUT_WIDTH:
621       case PIPE_VIDEO_CAP_VPP_MIN_OUTPUT_HEIGHT:
622       case PIPE_VIDEO_CAP_VPP_ORIENTATION_MODES:
623       case PIPE_VIDEO_CAP_VPP_BLEND_MODES:
624       {
625          // Assume defaults for now, we don't have the input args passed by get_video_param to be accurate here.
626          const D3D12_VIDEO_FIELD_TYPE FieldType = D3D12_VIDEO_FIELD_TYPE_NONE;
627          const D3D12_VIDEO_FRAME_STEREO_FORMAT StereoFormat = D3D12_VIDEO_FRAME_STEREO_FORMAT_NONE;
628          const DXGI_RATIONAL FrameRate = { 30, 1 };
629          const DXGI_FORMAT InputFormat = DXGI_FORMAT_NV12;
630          const DXGI_COLOR_SPACE_TYPE InputColorSpace = DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709;
631          const DXGI_FORMAT OutputFormat = DXGI_FORMAT_NV12;
632          const DXGI_COLOR_SPACE_TYPE OutputColorSpace = DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709;
633          const UINT Width = 1280;
634          const UINT Height = 720;
635          D3D12_FEATURE_DATA_VIDEO_PROCESS_SUPPORT supportCaps =
636          {
637             0, // NodeIndex
638             { Width, Height, { InputFormat, InputColorSpace } },
639             FieldType,
640             StereoFormat,
641             FrameRate,
642             { OutputFormat, OutputColorSpace },
643             StereoFormat,
644             FrameRate,
645          };
646 
647          if (d3d12_has_video_process_support(pscreen, supportCaps)) {
648             if (param == PIPE_VIDEO_CAP_SUPPORTED) {
649                return true;
650             } else if (param == PIPE_VIDEO_CAP_PREFERED_FORMAT) {
651                return  PIPE_FORMAT_NV12;
652             } else if (param == PIPE_VIDEO_CAP_SUPPORTS_INTERLACED) {
653                return false;
654             } else if (param == PIPE_VIDEO_CAP_MAX_WIDTH) {
655                return supportCaps.InputSample.Width;
656             } else if (param == PIPE_VIDEO_CAP_MAX_HEIGHT) {
657                return supportCaps.InputSample.Height;
658             } else if (param == PIPE_VIDEO_SUPPORTS_CONTIGUOUS_PLANES_MAP) {
659                return true;
660             } else if (param == PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE) {
661                return true;
662             } else if (param == PIPE_VIDEO_CAP_VPP_MAX_INPUT_WIDTH) {
663                return supportCaps.ScaleSupport.OutputSizeRange.MaxWidth;
664             } else if (param == PIPE_VIDEO_CAP_VPP_MAX_INPUT_HEIGHT) {
665                return supportCaps.ScaleSupport.OutputSizeRange.MaxHeight;
666             } else if (param == PIPE_VIDEO_CAP_VPP_MIN_INPUT_WIDTH) {
667                return supportCaps.ScaleSupport.OutputSizeRange.MinWidth;
668             } else if (param == PIPE_VIDEO_CAP_VPP_MIN_INPUT_HEIGHT) {
669                return supportCaps.ScaleSupport.OutputSizeRange.MinHeight;
670             } else if (param == PIPE_VIDEO_CAP_VPP_MAX_OUTPUT_WIDTH) {
671                return supportCaps.ScaleSupport.OutputSizeRange.MaxWidth;
672             } else if (param == PIPE_VIDEO_CAP_VPP_MAX_OUTPUT_HEIGHT) {
673                return supportCaps.ScaleSupport.OutputSizeRange.MaxHeight;
674             } else if (param == PIPE_VIDEO_CAP_VPP_MIN_OUTPUT_WIDTH) {
675                return supportCaps.ScaleSupport.OutputSizeRange.MinWidth;
676             } else if (param == PIPE_VIDEO_CAP_VPP_MIN_OUTPUT_HEIGHT) {
677                return supportCaps.ScaleSupport.OutputSizeRange.MinHeight;
678             } else if (param == PIPE_VIDEO_CAP_VPP_BLEND_MODES) {
679                uint32_t blend_modes = PIPE_VIDEO_VPP_BLEND_MODE_NONE;
680                if (((supportCaps.FeatureSupport & D3D12_VIDEO_PROCESS_FEATURE_FLAG_ALPHA_BLENDING) != 0)
681                   && ((supportCaps.FeatureSupport & D3D12_VIDEO_PROCESS_FEATURE_FLAG_ALPHA_FILL) != 0))
682                   {
683                      blend_modes |= PIPE_VIDEO_VPP_BLEND_MODE_GLOBAL_ALPHA;
684                   }
685                   return blend_modes;
686             } else if (param == PIPE_VIDEO_CAP_VPP_ORIENTATION_MODES) {
687                 uint32_t orientation_modes = PIPE_VIDEO_VPP_ORIENTATION_DEFAULT;
688                 if((supportCaps.FeatureSupport & D3D12_VIDEO_PROCESS_FEATURE_FLAG_FLIP) != 0) {
689                   orientation_modes |= PIPE_VIDEO_VPP_FLIP_HORIZONTAL;
690                   orientation_modes |= PIPE_VIDEO_VPP_FLIP_VERTICAL;
691                 }
692 
693                 if((supportCaps.FeatureSupport & D3D12_VIDEO_PROCESS_FEATURE_FLAG_ROTATION) != 0) {
694                   orientation_modes |= PIPE_VIDEO_VPP_ROTATION_90;
695                   orientation_modes |= PIPE_VIDEO_VPP_ROTATION_180;
696                   orientation_modes |= PIPE_VIDEO_VPP_ROTATION_270;
697                 }
698                 return orientation_modes;
699             }
700          }
701          return 0;
702       } break;
703       default:
704          return 0;
705    }
706 }
707 
708 static int
d3d12_screen_get_video_param_encode(struct pipe_screen * pscreen,enum pipe_video_profile profile,enum pipe_video_entrypoint entrypoint,enum pipe_video_cap param)709 d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
710                                     enum pipe_video_profile profile,
711                                     enum pipe_video_entrypoint entrypoint,
712                                     enum pipe_video_cap param)
713 {
714    uint32_t maxLvlEncode = 0u;
715    D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC maxResEncode = {};
716    uint32_t maxSlices = 0u;
717    uint32_t supportedSliceStructures = 0u;
718    uint32_t maxReferencesPerFrame = 0u;
719    switch (param) {
720       case PIPE_VIDEO_CAP_NPOT_TEXTURES:
721          return 1;
722       case PIPE_VIDEO_CAP_MAX_WIDTH:
723       case PIPE_VIDEO_CAP_MAX_HEIGHT:
724       case PIPE_VIDEO_CAP_MAX_LEVEL:
725       case PIPE_VIDEO_CAP_SUPPORTED:
726       case PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME:
727       case PIPE_VIDEO_CAP_ENC_SLICES_STRUCTURE:
728       case PIPE_VIDEO_CAP_ENC_MAX_REFERENCES_PER_FRAME:
729       {
730          if (d3d12_has_video_encode_support(pscreen,
731                                             profile,
732                                             maxLvlEncode,
733                                             maxResEncode,
734                                             maxSlices,
735                                             supportedSliceStructures,
736                                             maxReferencesPerFrame)) {
737             if (param == PIPE_VIDEO_CAP_MAX_WIDTH) {
738                return maxResEncode.Width;
739             } else if (param == PIPE_VIDEO_CAP_MAX_HEIGHT) {
740                return maxResEncode.Height;
741             } else if (param == PIPE_VIDEO_CAP_MAX_LEVEL) {
742                return maxLvlEncode;
743             } else if (param == PIPE_VIDEO_CAP_SUPPORTED) {
744                return 1;
745             } else if (param == PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME) {
746                return maxSlices;
747             } else if (param == PIPE_VIDEO_CAP_ENC_SLICES_STRUCTURE) {
748                return supportedSliceStructures;
749             } else if (param == PIPE_VIDEO_CAP_ENC_MAX_REFERENCES_PER_FRAME) {
750                return maxReferencesPerFrame;
751             }
752          }
753          return 0;
754       } break;
755       case PIPE_VIDEO_CAP_PREFERED_FORMAT:
756          return PIPE_FORMAT_NV12;
757       case PIPE_VIDEO_CAP_PREFERS_INTERLACED:
758          return false;
759       case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED:
760          return false;
761       case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE:
762          return true;
763       case PIPE_VIDEO_SUPPORTS_CONTIGUOUS_PLANES_MAP:
764          return true;
765       default:
766          debug_printf("[d3d12_screen_get_video_param] unknown video param: %d\n", param);
767          return 0;
768    }
769 }
770 
771 static int
d3d12_screen_get_video_param(struct pipe_screen * pscreen,enum pipe_video_profile profile,enum pipe_video_entrypoint entrypoint,enum pipe_video_cap param)772 d3d12_screen_get_video_param(struct pipe_screen *pscreen,
773                              enum pipe_video_profile profile,
774                              enum pipe_video_entrypoint entrypoint,
775                              enum pipe_video_cap param)
776 {
777    if (entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM) {
778       return d3d12_screen_get_video_param_decode(pscreen, profile, entrypoint, param);
779    } else if (entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
780       return d3d12_screen_get_video_param_encode(pscreen, profile, entrypoint, param);
781    } else if (entrypoint == PIPE_VIDEO_ENTRYPOINT_PROCESSING) {
782       return d3d12_screen_get_video_param_postproc(pscreen, profile, entrypoint, param);
783    }
784    return 0;
785 }
786 
787 void
d3d12_screen_video_init(struct pipe_screen * pscreen)788 d3d12_screen_video_init(struct pipe_screen *pscreen)
789 {
790    pscreen->get_video_param = d3d12_screen_get_video_param;
791    pscreen->is_video_format_supported = d3d12_video_buffer_is_format_supported;
792 }
793