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