Module: Mesa Branch: main Commit: 948c03bf58b73f904fb9abe3814b0f830328168f URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=948c03bf58b73f904fb9abe3814b0f830328168f
Author: Sil Vilerino <[email protected]> Date: Fri Jul 15 08:04:49 2022 -0400 d3d12: Enable VPP rotation, flip, alpha blend, crop, scaling via pipe_video_codec::process_frame Reviewed-by: Jesse Natalie <[email protected]> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/17557> --- src/gallium/drivers/d3d12/d3d12_context.cpp | 3 + src/gallium/drivers/d3d12/d3d12_video_screen.cpp | 160 +++++++++++++++++++++++ 2 files changed, 163 insertions(+) diff --git a/src/gallium/drivers/d3d12/d3d12_context.cpp b/src/gallium/drivers/d3d12/d3d12_context.cpp index 84023c43cdd..1b84a68d23f 100644 --- a/src/gallium/drivers/d3d12/d3d12_context.cpp +++ b/src/gallium/drivers/d3d12/d3d12_context.cpp @@ -37,6 +37,7 @@ #ifdef HAVE_GALLIUM_D3D12_VIDEO #include "d3d12_video_dec.h" #include "d3d12_video_enc.h" +#include "d3d12_video_proc.h" #include "d3d12_video_buffer.h" #endif #include "util/u_atomic.h" @@ -2407,6 +2408,8 @@ d3d12_video_create_codec(struct pipe_context *context, return d3d12_video_encoder_create_encoder(context, templat); } else if (templat->entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM) { return d3d12_video_create_decoder(context, templat); + } else if (templat->entrypoint == PIPE_VIDEO_ENTRYPOINT_PROCESSING) { + return d3d12_video_processor_create(context, templat); } else { debug_printf("D3D12: Unsupported video codec entrypoint %d\n", templat->entrypoint); return nullptr; diff --git a/src/gallium/drivers/d3d12/d3d12_video_screen.cpp b/src/gallium/drivers/d3d12/d3d12_video_screen.cpp index cd1fa052e53..a5b8cd323b4 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_screen.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_screen.cpp @@ -542,6 +542,164 @@ d3d12_screen_get_video_param_decode(struct pipe_screen *pscreen, } } + +static bool +d3d12_has_video_process_support(struct pipe_screen *pscreen, D3D12_FEATURE_DATA_VIDEO_PROCESS_SUPPORT &supportCaps) +{ + ComPtr<ID3D12VideoDevice2> spD3D12VideoDevice; + struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen; + if (FAILED(pD3D12Screen->dev->QueryInterface(IID_PPV_ARGS(spD3D12VideoDevice.GetAddressOf())))) { + // No video encode support in underlying d3d12 device (needs ID3D12VideoDevice2) + return false; + } + + D3D12_FEATURE_DATA_VIDEO_FEATURE_AREA_SUPPORT VideoFeatureAreaSupport = {}; + if (FAILED(spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_FEATURE_AREA_SUPPORT, + &VideoFeatureAreaSupport, + sizeof(VideoFeatureAreaSupport)))) { + return false; + } + + struct ResolStruct { + uint Width; + uint Height; + }; + + ResolStruct resolutionsList[] = { + { 8192, 8192 }, // 8k + { 8192, 4320 }, // 8k - alternative + { 7680, 4800 }, // 8k - alternative + { 7680, 4320 }, // 8k - alternative + { 4096, 2304 }, // 2160p (4K) + { 4096, 2160 }, // 2160p (4K) - alternative + { 2560, 1440 }, // 1440p + { 1920, 1200 }, // 1200p + { 1920, 1080 }, // 1080p + { 1280, 720 }, // 720p + { 800, 600 }, + }; + + uint32_t idxResol = 0; + bool bSupportsAny = false; + while ((idxResol < ARRAY_SIZE(resolutionsList)) && !bSupportsAny) { + supportCaps.InputSample.Width = resolutionsList[idxResol].Width; + supportCaps.InputSample.Height = resolutionsList[idxResol].Height; + if (SUCCEEDED(spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_PROCESS_SUPPORT, &supportCaps, sizeof(supportCaps)))) { + bSupportsAny = ((supportCaps.SupportFlags & D3D12_VIDEO_PROCESS_SUPPORT_FLAG_SUPPORTED) != 0) ; + } + idxResol++; + } + + return VideoFeatureAreaSupport.VideoProcessSupport && bSupportsAny; +} + +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) +{ + switch (param) { + case PIPE_VIDEO_CAP_NPOT_TEXTURES: + return 1; + case PIPE_VIDEO_CAP_MAX_WIDTH: + case PIPE_VIDEO_CAP_MAX_HEIGHT: + case PIPE_VIDEO_CAP_SUPPORTED: + case PIPE_VIDEO_CAP_PREFERED_FORMAT: + case PIPE_VIDEO_CAP_SUPPORTS_INTERLACED: + case PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE: + case PIPE_VIDEO_CAP_VPP_MAX_INPUT_WIDTH: + case PIPE_VIDEO_CAP_VPP_MAX_INPUT_HEIGHT: + case PIPE_VIDEO_CAP_VPP_MIN_INPUT_WIDTH: + case PIPE_VIDEO_CAP_VPP_MIN_INPUT_HEIGHT: + case PIPE_VIDEO_CAP_VPP_MAX_OUTPUT_WIDTH: + case PIPE_VIDEO_CAP_VPP_MAX_OUTPUT_HEIGHT: + case PIPE_VIDEO_CAP_VPP_MIN_OUTPUT_WIDTH: + case PIPE_VIDEO_CAP_VPP_MIN_OUTPUT_HEIGHT: + case PIPE_VIDEO_CAP_VPP_ORIENTATION_MODES: + case PIPE_VIDEO_CAP_VPP_BLEND_MODES: + { + // Assume defaults for now, we don't have the input args passed by get_video_param to be accurate here. + const D3D12_VIDEO_FIELD_TYPE FieldType = D3D12_VIDEO_FIELD_TYPE_NONE; + const D3D12_VIDEO_FRAME_STEREO_FORMAT StereoFormat = D3D12_VIDEO_FRAME_STEREO_FORMAT_NONE; + const DXGI_RATIONAL FrameRate = { 30, 1 }; + const DXGI_FORMAT InputFormat = DXGI_FORMAT_NV12; + const DXGI_COLOR_SPACE_TYPE InputColorSpace = DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709; + const DXGI_FORMAT OutputFormat = DXGI_FORMAT_NV12; + const DXGI_COLOR_SPACE_TYPE OutputColorSpace = DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709; + const UINT Width = 1280; + const UINT Height = 720; + D3D12_FEATURE_DATA_VIDEO_PROCESS_SUPPORT supportCaps = + { + 0, // NodeIndex + { Width, Height, { InputFormat, InputColorSpace } }, + FieldType, + StereoFormat, + FrameRate, + { OutputFormat, OutputColorSpace }, + StereoFormat, + FrameRate, + }; + + if (d3d12_has_video_process_support(pscreen, supportCaps)) { + if (param == PIPE_VIDEO_CAP_SUPPORTED) { + return true; + } else if (param == PIPE_VIDEO_CAP_PREFERED_FORMAT) { + return PIPE_FORMAT_NV12; + } else if (param == PIPE_VIDEO_CAP_SUPPORTS_INTERLACED) { + return false; + } else if (param == PIPE_VIDEO_CAP_MAX_WIDTH) { + return supportCaps.InputSample.Width; + } else if (param == PIPE_VIDEO_CAP_MAX_HEIGHT) { + return supportCaps.InputSample.Height; + } else if (param == PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE) { + return true; + } else if (param == PIPE_VIDEO_CAP_VPP_MAX_INPUT_WIDTH) { + return supportCaps.ScaleSupport.OutputSizeRange.MaxWidth; + } else if (param == PIPE_VIDEO_CAP_VPP_MAX_INPUT_HEIGHT) { + return supportCaps.ScaleSupport.OutputSizeRange.MaxHeight; + } else if (param == PIPE_VIDEO_CAP_VPP_MIN_INPUT_WIDTH) { + return supportCaps.ScaleSupport.OutputSizeRange.MinWidth; + } else if (param == PIPE_VIDEO_CAP_VPP_MIN_INPUT_HEIGHT) { + return supportCaps.ScaleSupport.OutputSizeRange.MinHeight; + } else if (param == PIPE_VIDEO_CAP_VPP_MAX_OUTPUT_WIDTH) { + return supportCaps.ScaleSupport.OutputSizeRange.MaxWidth; + } else if (param == PIPE_VIDEO_CAP_VPP_MAX_OUTPUT_HEIGHT) { + return supportCaps.ScaleSupport.OutputSizeRange.MaxHeight; + } else if (param == PIPE_VIDEO_CAP_VPP_MIN_OUTPUT_WIDTH) { + return supportCaps.ScaleSupport.OutputSizeRange.MinWidth; + } else if (param == PIPE_VIDEO_CAP_VPP_MIN_OUTPUT_HEIGHT) { + return supportCaps.ScaleSupport.OutputSizeRange.MinHeight; + } else if (param == PIPE_VIDEO_CAP_VPP_BLEND_MODES) { + uint32_t blend_modes = PIPE_VIDEO_VPP_BLEND_MODE_NONE; + if (((supportCaps.FeatureSupport & D3D12_VIDEO_PROCESS_FEATURE_FLAG_ALPHA_BLENDING) != 0) + && ((supportCaps.FeatureSupport & D3D12_VIDEO_PROCESS_FEATURE_FLAG_ALPHA_FILL) != 0)) + { + blend_modes |= PIPE_VIDEO_VPP_BLEND_MODE_GLOBAL_ALPHA; + } + return blend_modes; + } else if (param == PIPE_VIDEO_CAP_VPP_ORIENTATION_MODES) { + uint32_t orientation_modes = PIPE_VIDEO_VPP_ORIENTATION_DEFAULT; + if((supportCaps.FeatureSupport & D3D12_VIDEO_PROCESS_FEATURE_FLAG_FLIP) != 0) { + orientation_modes |= PIPE_VIDEO_VPP_FLIP_HORIZONTAL; + orientation_modes |= PIPE_VIDEO_VPP_FLIP_VERTICAL; + } + + if((supportCaps.FeatureSupport & D3D12_VIDEO_PROCESS_FEATURE_FLAG_ROTATION) != 0) { + orientation_modes |= PIPE_VIDEO_VPP_ROTATION_90; + orientation_modes |= PIPE_VIDEO_VPP_ROTATION_180; + orientation_modes |= PIPE_VIDEO_VPP_ROTATION_270; + } + return orientation_modes; + } + } + return 0; + } break; + default: + return 0; + } +} + static int d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, enum pipe_video_profile profile, @@ -613,6 +771,8 @@ d3d12_screen_get_video_param(struct pipe_screen *pscreen, return d3d12_screen_get_video_param_decode(pscreen, profile, entrypoint, param); } else if (entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) { return d3d12_screen_get_video_param_encode(pscreen, profile, entrypoint, param); + } else if (entrypoint == PIPE_VIDEO_ENTRYPOINT_PROCESSING) { + return d3d12_screen_get_video_param_postproc(pscreen, profile, entrypoint, param); } return 0; }
