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