From 2bb9f691e8ee7823ff195d9f85b11ddfb71bb123 Mon Sep 17 00:00:00 2001 From: "Pohsiang (John) Hsu" Date: Tue, 10 Jun 2025 15:22:01 -0700 Subject: [PATCH] mediafoundation: fix slice capability check, and fix the slice mb mode, remove slice mode 2 Reviewed-by: Sil Vilerino Part-of: --- .../frontends/mediafoundation/codecapi.cpp | 71 ++++++++----------- .../frontends/mediafoundation/encode_h264.cpp | 19 ++++- .../frontends/mediafoundation/encode_hevc.cpp | 11 ++- .../mediafoundation/encoder_capabilities.cpp | 8 ++- .../mediafoundation/encoder_capabilities.h | 5 +- .../frontends/mediafoundation/enum_mask.h | 64 ----------------- .../test/hmft_codecapi_test.cpp | 10 +++ 7 files changed, 72 insertions(+), 116 deletions(-) delete mode 100644 src/gallium/frontends/mediafoundation/enum_mask.h diff --git a/src/gallium/frontends/mediafoundation/codecapi.cpp b/src/gallium/frontends/mediafoundation/codecapi.cpp index 69a56d63dd9..2c4346fb841 100644 --- a/src/gallium/frontends/mediafoundation/codecapi.cpp +++ b/src/gallium/frontends/mediafoundation/codecapi.cpp @@ -383,53 +383,40 @@ CDX12EncHMFT::GetParameterRange( const GUID *Api, VARIANT *ValueMin, VARIANT *Va } else if( *Api == CODECAPI_AVEncSliceControlMode ) { - static_assert( PIPE_VIDEO_SLICE_MODE_BLOCKS == 0 ); - static_assert( PIPE_VIDEO_SLICE_MODE_MAX_SLICE_SIZE == 1 ); - static_assert( PIPE_VIDEO_SLICE_MODE_AUTO == 2 ); + bool bSliceModeMB = m_EncoderCapabilities.m_bHWSupportSliceModeMB; + bool bSliceModeMBRow = m_EncoderCapabilities.m_bHWSupportSliceModeMBRow; - // If PIPE_VIDEO_SLICE_MODE_BLOCKS is not supported, return error. - if( m_EncoderCapabilities.m_HWSupportedSliceModes.HasAll( PIPE_VIDEO_SLICE_MODE_BLOCKS, - PIPE_VIDEO_SLICE_MODE_MAX_SLICE_SIZE, - PIPE_VIDEO_SLICE_MODE_AUTO ) ) + if( !( bSliceModeMB || bSliceModeMBRow ) ) { - ValueMin->vt = VT_UI4; - ValueMin->ulVal = 0; - - ValueMax->vt = VT_UI4; - ValueMax->ulVal = 2; - - SteppingDelta->vt = VT_UI4; - SteppingDelta->ulVal = 1; - } - else if( m_EncoderCapabilities.m_HWSupportedSliceModes.HasAll( PIPE_VIDEO_SLICE_MODE_BLOCKS, - PIPE_VIDEO_SLICE_MODE_MAX_SLICE_SIZE ) ) - { - ValueMin->vt = VT_UI4; - ValueMin->ulVal = 0; - - ValueMax->vt = VT_UI4; - ValueMax->ulVal = 1; - - SteppingDelta->vt = VT_UI4; - SteppingDelta->ulVal = 1; - } - else if( m_EncoderCapabilities.m_HWSupportedSliceModes.HasAll( PIPE_VIDEO_SLICE_MODE_BLOCKS ) ) - { - ValueMin->vt = VT_UI4; - ValueMin->ulVal = 0; - - ValueMax->vt = VT_UI4; - ValueMax->ulVal = 0; - - SteppingDelta->vt = VT_UI4; - SteppingDelta->ulVal = 0; - } - else - { - // Nothing is supported. return E_NOTIMPL; } + ULONG min = 0; + ULONG max = 2; + ULONG delta = 2; + + if( bSliceModeMB && !bSliceModeMBRow ) + { + min = 0; + max = 0; + delta = 1; + } + else if( !bSliceModeMB && bSliceModeMBRow ) + { + min = 2; + max = 2; + delta = 1; + } + + ValueMin->vt = VT_UI4; + ValueMin->ulVal = min; + + ValueMax->vt = VT_UI4; + ValueMax->ulVal = max; + + SteppingDelta->vt = VT_UI4; + SteppingDelta->ulVal = delta; + return S_OK; } else if( *Api == CODECAPI_AVEncSliceControlSize ) diff --git a/src/gallium/frontends/mediafoundation/encode_h264.cpp b/src/gallium/frontends/mediafoundation/encode_h264.cpp index a2f3765d3f2..bd607630e2b 100644 --- a/src/gallium/frontends/mediafoundation/encode_h264.cpp +++ b/src/gallium/frontends/mediafoundation/encode_h264.cpp @@ -436,17 +436,24 @@ CDX12EncHMFT::PrepareForEncodeHelper( LPDX12EncodeContext pDX12EncodeContext, bo { pPicInfo->slice_mode = PIPE_VIDEO_SLICE_MODE_BLOCKS; uint32_t blocks_per_slice = m_uiSliceControlSize; - pPicInfo->num_slice_descriptors = ( height_in_blocks * width_in_blocks ) / blocks_per_slice; + pPicInfo->num_slice_descriptors = static_cast( + std::ceil( ( height_in_blocks * width_in_blocks ) / static_cast( blocks_per_slice ) ) ); uint32_t slice_starting_mb = 0; CHECKBOOL_GOTO( pPicInfo->num_slice_descriptors <= m_EncoderCapabilities.m_uiMaxHWSupportedMaxSlices, MF_E_UNEXPECTED, done ); - for( uint32_t i = 0; i < pPicInfo->num_slice_descriptors; i++ ) + CHECKBOOL_GOTO( pPicInfo->num_slice_descriptors >= 1, MF_E_UNEXPECTED, done ); + + uint32_t total_blocks = height_in_blocks * width_in_blocks; + uint32_t i = 0; + for( i = 0; i < pPicInfo->num_slice_descriptors - 1; i++ ) { pPicInfo->slices_descriptors[i].macroblock_address = slice_starting_mb; pPicInfo->slices_descriptors[i].num_macroblocks = blocks_per_slice; slice_starting_mb += blocks_per_slice; } + pPicInfo->slices_descriptors[i].macroblock_address = slice_starting_mb; + pPicInfo->slices_descriptors[i].num_macroblocks = total_blocks - slice_starting_mb; } else if( SLICE_CONTROL_MODE_BITS == m_uiSliceControlMode ) { @@ -463,12 +470,18 @@ CDX12EncHMFT::PrepareForEncodeHelper( LPDX12EncodeContext pDX12EncodeContext, bo CHECKBOOL_GOTO( pPicInfo->num_slice_descriptors <= m_EncoderCapabilities.m_uiMaxHWSupportedMaxSlices, MF_E_UNEXPECTED, done ); - for( uint32_t i = 0; i < pPicInfo->num_slice_descriptors; i++ ) + CHECKBOOL_GOTO( pPicInfo->num_slice_descriptors >= 1, MF_E_UNEXPECTED, done ); + + uint32_t total_blocks = height_in_blocks * width_in_blocks; + uint32_t i = 0; + for( i = 0; i < pPicInfo->num_slice_descriptors - 1; i++ ) { pPicInfo->slices_descriptors[i].macroblock_address = slice_starting_mb; pPicInfo->slices_descriptors[i].num_macroblocks = blocks_per_slice; slice_starting_mb += blocks_per_slice; } + pPicInfo->slices_descriptors[i].macroblock_address = slice_starting_mb; + pPicInfo->slices_descriptors[i].num_macroblocks = total_blocks - slice_starting_mb; } } } diff --git a/src/gallium/frontends/mediafoundation/encode_hevc.cpp b/src/gallium/frontends/mediafoundation/encode_hevc.cpp index 05a0ad685d4..850891a3e5e 100644 --- a/src/gallium/frontends/mediafoundation/encode_hevc.cpp +++ b/src/gallium/frontends/mediafoundation/encode_hevc.cpp @@ -434,17 +434,24 @@ CDX12EncHMFT::PrepareForEncodeHelper( LPDX12EncodeContext pDX12EncodeContext, bo { pPicInfo->slice_mode = PIPE_VIDEO_SLICE_MODE_BLOCKS; uint32_t blocks_per_slice = m_uiSliceControlSize; - pPicInfo->num_slice_descriptors = ( height_in_blocks * width_in_blocks ) / blocks_per_slice; + pPicInfo->num_slice_descriptors = static_cast( + std::ceil( ( height_in_blocks * width_in_blocks ) / static_cast( blocks_per_slice ) ) ); uint32_t slice_starting_mb = 0; CHECKBOOL_GOTO( pPicInfo->num_slice_descriptors <= m_EncoderCapabilities.m_uiMaxHWSupportedMaxSlices, MF_E_UNEXPECTED, done ); - for( uint32_t i = 0; i < pPicInfo->num_slice_descriptors; i++ ) + CHECKBOOL_GOTO( pPicInfo->num_slice_descriptors >= 1, MF_E_UNEXPECTED, done ); + + uint32_t total_blocks = height_in_blocks * width_in_blocks; + uint32_t i = 0; + for( i = 0; i < pPicInfo->num_slice_descriptors; i++ ) { pPicInfo->slices_descriptors[i].slice_segment_address = slice_starting_mb; pPicInfo->slices_descriptors[i].num_ctu_in_slice = blocks_per_slice; slice_starting_mb += blocks_per_slice; } + pPicInfo->slices_descriptors[i].slice_segment_address = slice_starting_mb; + pPicInfo->slices_descriptors[i].num_ctu_in_slice = total_blocks - slice_starting_mb; } else if( SLICE_CONTROL_MODE_BITS == m_uiSliceControlMode ) { diff --git a/src/gallium/frontends/mediafoundation/encoder_capabilities.cpp b/src/gallium/frontends/mediafoundation/encoder_capabilities.cpp index c452d6d9288..fd868f170a0 100644 --- a/src/gallium/frontends/mediafoundation/encoder_capabilities.cpp +++ b/src/gallium/frontends/mediafoundation/encoder_capabilities.cpp @@ -141,10 +141,12 @@ encoder_capabilities::initialize( pipe_screen *pScreen, pipe_video_profile video m_HWSupportMotionGPUMaps.value = pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_MOTION_VECTOR_MAPS ); - // TODO: We should get the supported slice mode from pipe, but currently, it doesn't support. - // Currently, dx12MFT only support mode_blocks, so we initialize it like this. - m_HWSupportedSliceModes = EnumMask { PIPE_VIDEO_SLICE_MODE_BLOCKS }; + uint32_t supportedSliceStructures = + pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_SLICES_STRUCTURE ); + m_bHWSupportSliceModeMB = ( ( supportedSliceStructures & PIPE_VIDEO_CAP_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS ) != 0 ); + m_bHWSupportSliceModeBits = ( ( supportedSliceStructures & PIPE_VIDEO_CAP_SLICE_STRUCTURE_MAX_SLICE_SIZE ) != 0 ); + m_bHWSupportSliceModeMBRow = ( ( supportedSliceStructures & PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_MULTI_ROWS ) != 0 ); m_TwoPassSupport.value = pScreen->get_video_param( pScreen, videoProfile, PIPE_VIDEO_ENTRYPOINT_ENCODE, PIPE_VIDEO_CAP_ENC_TWO_PASS ); diff --git a/src/gallium/frontends/mediafoundation/encoder_capabilities.h b/src/gallium/frontends/mediafoundation/encoder_capabilities.h index a2e8bf89e4b..871049cb99c 100644 --- a/src/gallium/frontends/mediafoundation/encoder_capabilities.h +++ b/src/gallium/frontends/mediafoundation/encoder_capabilities.h @@ -26,7 +26,6 @@ #include #include -#include "enum_mask.h" #include "pipe_headers.h" class encoder_capabilities @@ -126,7 +125,9 @@ class encoder_capabilities union pipe_enc_cap_motion_vector_map m_HWSupportMotionGPUMaps = {}; // Supported slice mode - EnumMask m_HWSupportedSliceModes {}; + bool m_bHWSupportSliceModeMB = false; + bool m_bHWSupportSliceModeBits = false; + bool m_bHWSupportSliceModeMBRow = false; // Two pass encode union pipe_enc_cap_two_pass m_TwoPassSupport = {}; diff --git a/src/gallium/frontends/mediafoundation/enum_mask.h b/src/gallium/frontends/mediafoundation/enum_mask.h deleted file mode 100644 index ffdf8bfdabb..00000000000 --- a/src/gallium/frontends/mediafoundation/enum_mask.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright © Microsoft Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -#pragma once - -#include -#include - -template -concept EnumType = std::is_enum_v; - -template -class EnumMask -{ - using UnderlyingType = std::underlying_type_t; - - public: - explicit constexpr EnumMask( std::initializer_list values ) - { - for( auto v : values ) - { - m_mask |= MakeValue( v ); - } - } - - constexpr bool HasAll( Enum v ) - { - return m_mask & MakeValue( v ); - } - - template - constexpr bool HasAll( Enum v, Enums... values ) - { - return HasAll( v ) && HasAll( values... ); - } - - private: - constexpr UnderlyingType MakeValue( Enum v ) - { - return 1 << (UnderlyingType) v; - } - - UnderlyingType m_mask {}; -}; \ No newline at end of file diff --git a/src/gallium/frontends/mediafoundation/test/hmft_codecapi_test.cpp b/src/gallium/frontends/mediafoundation/test/hmft_codecapi_test.cpp index 87d468888d0..8075d459b42 100644 --- a/src/gallium/frontends/mediafoundation/test/hmft_codecapi_test.cpp +++ b/src/gallium/frontends/mediafoundation/test/hmft_codecapi_test.cpp @@ -60,6 +60,16 @@ TEST( MediaFoundationEntrypoint, VerifyBasicCodecAPI ) ULONG ulValuesCount; CHECKHR_GOTO( spCodecAPI->GetParameterValues( &CODECAPI_AVEncVideoLTRBufferControl, &pValues, &ulValuesCount ), done ); } + { + VARIANT vMin; + VARIANT vMax; + VARIANT vDelta; + CHECKHR_GOTO( spCodecAPI->GetParameterRange( &CODECAPI_AVEncSliceControlMode, &vMin, &vMax, &vDelta ), done ); + ASSERT_TRUE( vMin.vt == VT_UI4 && vMax.vt == VT_UI4 && vDelta.vt == VT_UI4 ); + ASSERT_TRUE( vMin.ulVal <= 2u && vMax.ulVal <= 2u ); + ASSERT_TRUE( vMin.ulVal <= vMax.ulVal ); + ASSERT_TRUE( vDelta.ulVal >= 1u && vDelta.ulVal <= 2u ); + } done: ASSERT_HRESULT_SUCCEEDED( hr );