mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-23 22:00:13 +01:00
d3d12: Implement Intra Refresh for H264, HEVC, AV1
Reviewed-by: Jesse Natalie <jenatali@microsoft.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26223>
This commit is contained in:
parent
a560706648
commit
c81967fa89
6 changed files with 171 additions and 2 deletions
|
|
@ -353,6 +353,8 @@ d3d12_video_encoder_reconfigure_encoder_objects(struct d3d12_video_encoder *pD3D
|
|||
((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags & d3d12_video_encoder_config_dirty_flag_gop) != 0);
|
||||
bool motionPrecisionLimitChanged = ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags &
|
||||
d3d12_video_encoder_config_dirty_flag_motion_precision_limit) != 0);
|
||||
bool irChanged = ((pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags &
|
||||
d3d12_video_encoder_config_dirty_flag_intra_refresh) != 0);
|
||||
|
||||
// Events that that trigger a re-creation of the reference picture manager
|
||||
// Stores codec agnostic textures so only input format, resolution and gop (num dpb references) affects this
|
||||
|
|
@ -528,6 +530,10 @@ d3d12_video_encoder_reconfigure_encoder_objects(struct d3d12_video_encoder *pD3D
|
|||
(pD3D12Enc->m_fenceValue > 1) && (!reCreatedEncoder || !reCreatedEncoderHeap)) {
|
||||
pD3D12Enc->m_currentEncodeConfig.m_seqFlags |= D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_GOP_SEQUENCE_CHANGE;
|
||||
}
|
||||
|
||||
if(irChanged)
|
||||
pD3D12Enc->m_currentEncodeConfig.m_seqFlags |= D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAG_REQUEST_INTRA_REFRESH;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1221,6 +1227,16 @@ bool d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(stru
|
|||
&& (capEncoderSupportData1.ValidationFlags == D3D12_VIDEO_ENCODER_VALIDATION_FLAG_NONE));
|
||||
}
|
||||
|
||||
if (pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh.IntraRefreshDuration >
|
||||
pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxIntraRefreshFrameDuration)
|
||||
{
|
||||
debug_printf("[d3d12_video_encoder] Desired duration of intrarefresh %d is not supported (higher than max "
|
||||
"reported IR duration %d in query caps) for current resolution.\n",
|
||||
pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh.IntraRefreshDuration,
|
||||
pD3D12Enc->m_currentEncodeCapabilities.m_currentResolutionSupportCaps.MaxIntraRefreshFrameDuration);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!configSupported) {
|
||||
debug_printf("[d3d12_video_encoder] Cap negotiation failed, see more details below:\n");
|
||||
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ enum d3d12_video_encoder_config_dirty_flags
|
|||
d3d12_video_encoder_config_dirty_flag_gop = 0x100,
|
||||
d3d12_video_encoder_config_dirty_flag_motion_precision_limit = 0x200,
|
||||
d3d12_video_encoder_config_dirty_flag_sequence_info = 0x400,
|
||||
d3d12_video_encoder_config_dirty_flag_intra_refresh = 0x800,
|
||||
};
|
||||
DEFINE_ENUM_FLAG_OPERATORS(d3d12_video_encoder_config_dirty_flags);
|
||||
|
||||
|
|
|
|||
|
|
@ -983,6 +983,48 @@ d3d12_video_encoder_convert_av1_codec_configuration(struct d3d12_video_encoder *
|
|||
return config;
|
||||
}
|
||||
|
||||
static bool
|
||||
d3d12_video_encoder_update_intra_refresh_av1(struct d3d12_video_encoder *pD3D12Enc,
|
||||
struct pipe_video_buffer * srcTexture,
|
||||
struct pipe_av1_enc_picture_desc * picture)
|
||||
{
|
||||
if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_NONE)
|
||||
{
|
||||
// D3D12 only supports row intra-refresh
|
||||
if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_UNIT_ROWS)
|
||||
{
|
||||
debug_printf("[d3d12_video_encoder_update_intra_refresh_av1] Unsupported INTRA_REFRESH_MODE %d\n", picture->intra_refresh.mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t sbSize = ((pD3D12Enc->m_currentEncodeConfig.m_encoderCodecSpecificConfigDesc.m_AV1Config.FeatureFlags &
|
||||
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK) != 0) ? 128u : 64u;
|
||||
uint32_t total_frame_blocks = static_cast<uint32_t>(std::ceil(srcTexture->height / sbSize)) *
|
||||
static_cast<uint32_t>(std::ceil(srcTexture->width / sbSize));
|
||||
D3D12_VIDEO_ENCODER_INTRA_REFRESH targetIntraRefresh = {
|
||||
D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_ROW_BASED,
|
||||
total_frame_blocks / picture->intra_refresh.region_size,
|
||||
};
|
||||
double ir_wave_progress = (picture->intra_refresh.offset == 0) ? 0 :
|
||||
picture->intra_refresh.offset / (double) total_frame_blocks;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex =
|
||||
static_cast<uint32_t>(std::ceil(ir_wave_progress * targetIntraRefresh.IntraRefreshDuration));
|
||||
|
||||
// Set intra refresh state
|
||||
pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = targetIntraRefresh;
|
||||
// Need to send the sequence flag during all the IR duration
|
||||
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_intra_refresh;
|
||||
} else {
|
||||
pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex = 0;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = {
|
||||
D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
|
||||
0,
|
||||
};
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
d3d12_video_encoder_update_current_encoder_config_state_av1(struct d3d12_video_encoder *pD3D12Enc,
|
||||
struct pipe_video_buffer *srcTexture,
|
||||
|
|
@ -1103,6 +1145,12 @@ d3d12_video_encoder_update_current_encoder_config_state_av1(struct d3d12_video_e
|
|||
return false;
|
||||
}
|
||||
|
||||
// Set intra-refresh config
|
||||
if(!d3d12_video_encoder_update_intra_refresh_av1(pD3D12Enc, srcTexture, av1Pic)) {
|
||||
debug_printf("d3d12_video_encoder_update_intra_refresh_av1 failed!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// m_currentEncodeConfig.m_encoderPicParamsDesc pic params are set in d3d12_video_encoder_reconfigure_encoder_objects
|
||||
// after re-allocating objects if needed
|
||||
|
||||
|
|
|
|||
|
|
@ -805,6 +805,46 @@ d3d12_video_encoder_convert_h264_codec_configuration(struct d3d12_video_encoder
|
|||
return config;
|
||||
}
|
||||
|
||||
static bool
|
||||
d3d12_video_encoder_update_intra_refresh_h264(struct d3d12_video_encoder *pD3D12Enc,
|
||||
struct pipe_video_buffer * srcTexture,
|
||||
struct pipe_h264_enc_picture_desc * picture)
|
||||
{
|
||||
if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_NONE)
|
||||
{
|
||||
// D3D12 only supports row intra-refresh
|
||||
if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_UNIT_ROWS)
|
||||
{
|
||||
debug_printf("[d3d12_video_encoder_update_intra_refresh_h264] Unsupported INTRA_REFRESH_MODE %d\n", picture->intra_refresh.mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t total_frame_blocks = static_cast<uint32_t>(std::ceil(srcTexture->height / D3D12_VIDEO_H264_MB_IN_PIXELS)) *
|
||||
static_cast<uint32_t>(std::ceil(srcTexture->width / D3D12_VIDEO_H264_MB_IN_PIXELS));
|
||||
D3D12_VIDEO_ENCODER_INTRA_REFRESH targetIntraRefresh = {
|
||||
D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_ROW_BASED,
|
||||
total_frame_blocks / picture->intra_refresh.region_size,
|
||||
};
|
||||
double ir_wave_progress = (picture->intra_refresh.offset == 0) ? 0 :
|
||||
picture->intra_refresh.offset / (double) total_frame_blocks;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex =
|
||||
static_cast<uint32_t>(std::ceil(ir_wave_progress * targetIntraRefresh.IntraRefreshDuration));
|
||||
|
||||
// Set intra refresh state
|
||||
pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = targetIntraRefresh;
|
||||
// Need to send the sequence flag during all the IR duration
|
||||
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_intra_refresh;
|
||||
} else {
|
||||
pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex = 0;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = {
|
||||
D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
|
||||
0,
|
||||
};
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
d3d12_video_encoder_update_current_encoder_config_state_h264(struct d3d12_video_encoder *pD3D12Enc,
|
||||
struct pipe_video_buffer *srcTexture,
|
||||
|
|
@ -847,6 +887,12 @@ d3d12_video_encoder_update_current_encoder_config_state_h264(struct d3d12_video_
|
|||
return false;
|
||||
}
|
||||
|
||||
// Set intra-refresh config
|
||||
if(!d3d12_video_encoder_update_intra_refresh_h264(pD3D12Enc, srcTexture, h264Pic)) {
|
||||
debug_printf("d3d12_video_encoder_update_intra_refresh_h264 failed!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set resolution
|
||||
if ((pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Width != srcTexture->width) ||
|
||||
(pD3D12Enc->m_currentEncodeConfig.m_currentResolution.Height != srcTexture->height)) {
|
||||
|
|
|
|||
|
|
@ -734,6 +734,48 @@ d3d12_video_encoder_convert_hevc_codec_configuration(struct d3d12_video_encoder
|
|||
return config;
|
||||
}
|
||||
|
||||
static bool
|
||||
d3d12_video_encoder_update_intra_refresh_hevc(struct d3d12_video_encoder *pD3D12Enc,
|
||||
struct pipe_video_buffer * srcTexture,
|
||||
struct pipe_h265_enc_picture_desc * picture)
|
||||
{
|
||||
if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_NONE)
|
||||
{
|
||||
// D3D12 only supports row intra-refresh
|
||||
if (picture->intra_refresh.mode != INTRA_REFRESH_MODE_UNIT_ROWS)
|
||||
{
|
||||
debug_printf("[d3d12_video_encoder_update_intra_refresh_hevc] Unsupported INTRA_REFRESH_MODE %d\n", picture->intra_refresh.mode);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t ctbSize = d3d12_video_encoder_convert_12cusize_to_pixel_size_hevc(
|
||||
pD3D12Enc->m_currentEncodeCapabilities.m_encoderCodecSpecificConfigCaps.m_HEVCCodecCaps.MaxLumaCodingUnitSize);
|
||||
uint32_t total_frame_blocks = static_cast<uint32_t>(std::ceil(srcTexture->height / ctbSize)) *
|
||||
static_cast<uint32_t>(std::ceil(srcTexture->width / ctbSize));
|
||||
D3D12_VIDEO_ENCODER_INTRA_REFRESH targetIntraRefresh = {
|
||||
D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_ROW_BASED,
|
||||
total_frame_blocks / picture->intra_refresh.region_size,
|
||||
};
|
||||
double ir_wave_progress = (picture->intra_refresh.offset == 0) ? 0 :
|
||||
picture->intra_refresh.offset / (double) total_frame_blocks;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex =
|
||||
static_cast<uint32_t>(std::ceil(ir_wave_progress * targetIntraRefresh.IntraRefreshDuration));
|
||||
|
||||
// Set intra refresh state
|
||||
pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = targetIntraRefresh;
|
||||
// Need to send the sequence flag during all the IR duration
|
||||
pD3D12Enc->m_currentEncodeConfig.m_ConfigDirtyFlags |= d3d12_video_encoder_config_dirty_flag_intra_refresh;
|
||||
} else {
|
||||
pD3D12Enc->m_currentEncodeConfig.m_IntraRefreshCurrentFrameIndex = 0;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_IntraRefresh = {
|
||||
D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE,
|
||||
0,
|
||||
};
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
d3d12_video_encoder_update_current_encoder_config_state_hevc(struct d3d12_video_encoder *pD3D12Enc,
|
||||
struct pipe_video_buffer *srcTexture,
|
||||
|
|
@ -868,6 +910,12 @@ d3d12_video_encoder_update_current_encoder_config_state_hevc(struct d3d12_video_
|
|||
return false;
|
||||
}
|
||||
|
||||
// Set intra-refresh config
|
||||
if(!d3d12_video_encoder_update_intra_refresh_hevc(pD3D12Enc, srcTexture, hevcPic)) {
|
||||
debug_printf("d3d12_video_encoder_update_intra_refresh_hevc failed!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// m_currentEncodeConfig.m_encoderPicParamsDesc pic params are set in d3d12_video_encoder_reconfigure_encoder_objects
|
||||
// after re-allocating objects if needed
|
||||
|
||||
|
|
|
|||
|
|
@ -803,7 +803,8 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
|
|||
uint32_t &isRCMaxFrameSizeSupported,
|
||||
uint32_t &maxQualityLevels,
|
||||
uint32_t &max_tile_rows,
|
||||
uint32_t &max_tile_cols)
|
||||
uint32_t &max_tile_cols,
|
||||
uint32_t &maxIRDuration)
|
||||
{
|
||||
ComPtr<ID3D12VideoDevice3> spD3D12VideoDevice;
|
||||
struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen;
|
||||
|
|
@ -887,6 +888,7 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
|
|||
else
|
||||
maxSlices = resolutionDepCaps.MaxSubregionsNumber;
|
||||
|
||||
maxIRDuration = resolutionDepCaps.MaxIntraRefreshFrameDuration;
|
||||
isRCMaxFrameSizeSupported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_MAX_FRAME_SIZE_AVAILABLE) != 0) ? 1 : 0;
|
||||
maxReferencesPerFrame =
|
||||
d3d12_video_encode_supported_references_per_frame_structures(codecDesc,
|
||||
|
|
@ -1059,6 +1061,8 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
|
|||
maxSlices = 0;
|
||||
else
|
||||
maxSlices = resolutionDepCaps.MaxSubregionsNumber;
|
||||
|
||||
maxIRDuration = resolutionDepCaps.MaxIntraRefreshFrameDuration;
|
||||
isRCMaxFrameSizeSupported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_MAX_FRAME_SIZE_AVAILABLE) != 0) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -1316,6 +1320,7 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
|
|||
else
|
||||
maxSlices = resolutionDepCaps.MaxSubregionsNumber;
|
||||
|
||||
maxIRDuration = resolutionDepCaps.MaxIntraRefreshFrameDuration;
|
||||
codecSupport.av1_support.features_ext2.bits.max_tile_num_minus1 = maxSlices - 1;
|
||||
|
||||
isRCMaxFrameSizeSupported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_MAX_FRAME_SIZE_AVAILABLE) != 0) ? 1 : 0;
|
||||
|
|
@ -1621,6 +1626,7 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
|
|||
uint32_t maxQualityLevels = 0u;
|
||||
uint32_t max_tile_rows = 0u;
|
||||
uint32_t max_tile_cols = 0u;
|
||||
uint32_t maxIRDuration = 0u;
|
||||
struct d3d12_encode_codec_support codec_specific_support;
|
||||
memset(&codec_specific_support, 0, sizeof(codec_specific_support));
|
||||
switch (param) {
|
||||
|
|
@ -1650,6 +1656,7 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
|
|||
case PIPE_VIDEO_CAP_ENC_QUALITY_LEVEL:
|
||||
case PIPE_VIDEO_CAP_ENC_MAX_TILE_ROWS:
|
||||
case PIPE_VIDEO_CAP_ENC_MAX_TILE_COLS:
|
||||
case PIPE_VIDEO_CAP_ENC_INTRA_REFRESH_MAX_DURATION:
|
||||
{
|
||||
if (d3d12_has_video_encode_support(pscreen,
|
||||
profile,
|
||||
|
|
@ -1663,7 +1670,8 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
|
|||
isRCMaxFrameSizeSupported,
|
||||
maxQualityLevels,
|
||||
max_tile_rows,
|
||||
max_tile_cols)) {
|
||||
max_tile_cols,
|
||||
maxIRDuration)) {
|
||||
|
||||
DXGI_FORMAT format = d3d12_convert_pipe_video_profile_to_dxgi_format(profile);
|
||||
auto pipeFmt = d3d12_get_pipe_format(format);
|
||||
|
|
@ -1691,6 +1699,8 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
|
|||
return max_tile_cols;
|
||||
} else if (param == PIPE_VIDEO_CAP_ENC_MAX_REFERENCES_PER_FRAME) {
|
||||
return maxReferencesPerFrame;
|
||||
} else if (param == PIPE_VIDEO_CAP_ENC_INTRA_REFRESH_MAX_DURATION) {
|
||||
return maxIRDuration;
|
||||
} else if (param == PIPE_VIDEO_CAP_ENC_SUPPORTS_MAX_FRAME_SIZE) {
|
||||
return isRCMaxFrameSizeSupported;
|
||||
} else if (param == PIPE_VIDEO_CAP_ENC_HEVC_FEATURE_FLAGS) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue