d3d12: Video Encode H264 to use direct DPB from frontend

Reviewed-by: Jesse Natalie <jenatali@microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/30908>
This commit is contained in:
Sil Vilerino
2024-08-28 16:42:20 -04:00
committed by Marge Bot
parent bb1bbe51df
commit da2cbfe3bf
6 changed files with 480 additions and 403 deletions

View File

@@ -339,6 +339,35 @@ d3d12_video_encoder_update_picparams_tracking(struct d3d12_video_encoder *pD3D12
pD3D12Enc->m_upDPBManager->begin_frame(currentPicParams, bUsedAsReference, picture);
}
bool
d3d12_video_encoder_uses_direct_dpb(enum pipe_video_format codec)
{
switch (codec) {
#if VIDEO_CODEC_H264ENC
case PIPE_VIDEO_FORMAT_MPEG4_AVC:
{
return true;
} break;
#endif
#if VIDEO_CODEC_H265ENC
case PIPE_VIDEO_FORMAT_HEVC:
{
return false;
} break;
#endif
#if VIDEO_CODEC_AV1ENC
case PIPE_VIDEO_FORMAT_AV1:
{
return false;
} break;
#endif
default:
{
unreachable("Unsupported pipe_video_format");
} break;
}
}
bool
d3d12_video_encoder_reconfigure_encoder_objects(struct d3d12_video_encoder *pD3D12Enc,
struct pipe_video_buffer * srcTexture,
@@ -388,35 +417,40 @@ d3d12_video_encoder_reconfigure_encoder_objects(struct d3d12_video_encoder *pD3D
debug_printf("[d3d12_video_encoder] Reconfiguration triggered -> Re-creating Reference Pictures Manager\n");
}
D3D12_RESOURCE_FLAGS resourceAllocFlags =
D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
bool fArrayOfTextures = ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RECONSTRUCTED_FRAMES_REQUIRE_TEXTURE_ARRAYS) == 0);
uint32_t texturePoolSize = d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc) +
1u; // adding an extra slot as we also need to count the current frame output recon
// allocation along max reference frame allocations
assert(texturePoolSize < UINT16_MAX);
pD3D12Enc->m_upDPBStorageManager.reset();
if (fArrayOfTextures) {
pD3D12Enc->m_upDPBStorageManager = std::make_unique<d3d12_array_of_textures_dpb_manager>(
static_cast<uint16_t>(texturePoolSize),
pD3D12Enc->m_pD3D12Screen->dev,
pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
(D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE),
true, // setNullSubresourcesOnAllZero - D3D12 Video Encode expects nullptr pSubresources if AoT,
pD3D12Enc->m_NodeMask,
/*use underlying pool, we can't reuse upper level allocations, need D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY*/
true);
} else {
pD3D12Enc->m_upDPBStorageManager = std::make_unique<d3d12_texture_array_dpb_manager>(
static_cast<uint16_t>(texturePoolSize),
pD3D12Enc->m_pD3D12Screen->dev,
pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
resourceAllocFlags,
pD3D12Enc->m_NodeMask);
enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
if (!d3d12_video_encoder_uses_direct_dpb(codec))
{
D3D12_RESOURCE_FLAGS resourceAllocFlags =
D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE;
bool fArrayOfTextures = ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RECONSTRUCTED_FRAMES_REQUIRE_TEXTURE_ARRAYS) == 0);
uint32_t texturePoolSize = d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc) +
1u; // adding an extra slot as we also need to count the current frame output recon
// allocation along max reference frame allocations
assert(texturePoolSize < UINT16_MAX);
pD3D12Enc->m_upDPBStorageManager.reset();
if (fArrayOfTextures) {
pD3D12Enc->m_upDPBStorageManager = std::make_unique<d3d12_array_of_textures_dpb_manager>(
static_cast<uint16_t>(texturePoolSize),
pD3D12Enc->m_pD3D12Screen->dev,
pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
resourceAllocFlags,
true, // setNullSubresourcesOnAllZero - D3D12 Video Encode expects nullptr pSubresources if AoT,
pD3D12Enc->m_NodeMask,
/*use underlying pool, we can't reuse upper level allocations, need D3D12_RESOURCE_FLAG_VIDEO_ENCODE_REFERENCE_ONLY*/
true);
} else {
pD3D12Enc->m_upDPBStorageManager = std::make_unique<d3d12_texture_array_dpb_manager>(
static_cast<uint16_t>(texturePoolSize),
pD3D12Enc->m_pD3D12Screen->dev,
pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format,
pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
resourceAllocFlags,
pD3D12Enc->m_NodeMask);
}
}
d3d12_video_encoder_create_reference_picture_manager(pD3D12Enc, picture);
}
@@ -564,19 +598,7 @@ d3d12_video_encoder_create_reference_picture_manager(struct d3d12_video_encoder
#if VIDEO_CODEC_H264ENC
case PIPE_VIDEO_FORMAT_MPEG4_AVC:
{
bool gopHasPFrames =
(pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures.PPicturePeriod > 0) &&
((pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures.GOPLength == 0) ||
(pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures.PPicturePeriod <
pD3D12Enc->m_currentEncodeConfig.m_encoderGOPConfigDesc.m_H264GroupOfPictures.GOPLength));
pD3D12Enc->m_upDPBManager = std::make_unique<d3d12_video_encoder_references_manager_h264>(
gopHasPFrames,
*pD3D12Enc->m_upDPBStorageManager,
// Max number of frames to be used as a reference, without counting the current recon picture
d3d12_video_encoder_get_current_max_dpb_capacity(pD3D12Enc)
);
pD3D12Enc->m_upDPBManager = std::make_unique<d3d12_video_encoder_references_manager_h264>();
struct pipe_h264_enc_picture_desc *pH264Pic = (struct pipe_h264_enc_picture_desc *) picture;
pD3D12Enc->m_upBitstreamBuilder = std::make_unique<d3d12_video_bitstream_builder_h264>(pH264Pic->insert_aud_nalu);
} break;

View File

@@ -539,6 +539,9 @@ d3d12_video_encoder_update_picparams_region_of_interest_qpmap(struct d3d12_video
int32_t min_delta_qp,
int32_t max_delta_qp,
std::vector<T>& pQPMap);
bool
d3d12_video_encoder_uses_direct_dpb(enum pipe_video_format codec);
///
/// d3d12_video_encoder functions ends
///

View File

@@ -358,25 +358,6 @@ d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video
}
picParams.pH264PicData->pic_parameter_set_id = pH264BitstreamBuilder->get_active_pps().pic_parameter_set_id;
picParams.pH264PicData->idr_pic_id = h264Pic->idr_pic_id;
picParams.pH264PicData->FrameType = d3d12_video_encoder_convert_frame_type_h264(h264Pic->picture_type);
picParams.pH264PicData->PictureOrderCountNumber = h264Pic->pic_order_cnt;
picParams.pH264PicData->FrameDecodingOrderNumber = h264Pic->frame_num;
picParams.pH264PicData->List0ReferenceFramesCount = 0;
picParams.pH264PicData->pList0ReferenceFrames = nullptr;
picParams.pH264PicData->List1ReferenceFramesCount = 0;
picParams.pH264PicData->pList1ReferenceFrames = nullptr;
if (picParams.pH264PicData->FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME) {
picParams.pH264PicData->List0ReferenceFramesCount = h264Pic->num_ref_idx_l0_active_minus1 + 1;
picParams.pH264PicData->pList0ReferenceFrames = h264Pic->ref_idx_l0_list;
} else if (picParams.pH264PicData->FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME) {
picParams.pH264PicData->List0ReferenceFramesCount = h264Pic->num_ref_idx_l0_active_minus1 + 1;
picParams.pH264PicData->pList0ReferenceFrames = h264Pic->ref_idx_l0_list;
picParams.pH264PicData->List1ReferenceFramesCount = h264Pic->num_ref_idx_l1_active_minus1 + 1;
picParams.pH264PicData->pList1ReferenceFrames = h264Pic->ref_idx_l1_list;
}
if ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0)
{
@@ -394,33 +375,6 @@ d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video
}
}
D3D12_VIDEO_ENCODER_FRAME_TYPE_H264
d3d12_video_encoder_convert_frame_type_h264(enum pipe_h2645_enc_picture_type picType)
{
switch (picType) {
case PIPE_H2645_ENC_PICTURE_TYPE_P:
{
return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME;
} break;
case PIPE_H2645_ENC_PICTURE_TYPE_B:
{
return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME;
} break;
case PIPE_H2645_ENC_PICTURE_TYPE_I:
{
return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_I_FRAME;
} break;
case PIPE_H2645_ENC_PICTURE_TYPE_IDR:
{
return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME;
} break;
default:
{
unreachable("Unsupported pipe_h2645_enc_picture_type");
} break;
}
}
///
/// Tries to configurate the encoder using the requested slice configuration
/// or falls back to single slice encoding.

View File

@@ -54,8 +54,6 @@ d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video
struct pipe_picture_desc * picture,
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &picParams,
bool &bUsedAsReference);
D3D12_VIDEO_ENCODER_FRAME_TYPE_H264
d3d12_video_encoder_convert_frame_type_h264(enum pipe_h2645_enc_picture_type picType);
uint32_t
d3d12_video_encoder_build_codec_headers_h264(struct d3d12_video_encoder *pD3D12Enc,
std::vector<uint64_t> &pWrittenCodecUnitsSizes);

View File

@@ -25,166 +25,24 @@
#include <algorithm>
#include <string>
#include "d3d12_screen.h"
#include "d3d12_video_buffer.h"
#include "d3d12_resource.h"
using namespace std;
d3d12_video_encoder_references_manager_h264::d3d12_video_encoder_references_manager_h264(
bool gopHasIorPFrames, d3d12_video_dpb_storage_manager_interface &rDpbStorageManager, uint32_t MaxDPBCapacity)
: m_MaxDPBCapacity(MaxDPBCapacity),
m_rDPBStorageManager(rDpbStorageManager),
m_CurrentFrameReferencesData({}),
m_gopHasInterFrames(gopHasIorPFrames)
{
assert((m_MaxDPBCapacity + 1 /*extra for cur frame output recon pic*/) ==
m_rDPBStorageManager.get_number_of_tracked_allocations());
debug_printf("[D3D12 Video Encoder Picture Manager H264] Completed construction of "
"d3d12_video_encoder_references_manager_h264 instance, settings are\n");
debug_printf("[D3D12 Video Encoder Picture Manager H264] m_MaxDPBCapacity: %d\n", m_MaxDPBCapacity);
}
void
d3d12_video_encoder_references_manager_h264::reset_gop_tracking_and_dpb()
{
// Reset m_CurrentFrameReferencesData tracking
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.clear();
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.reserve(m_MaxDPBCapacity);
m_CurrentFrameReferencesData.ReconstructedPicTexture = { nullptr, 0 };
// Reset DPB storage
ASSERTED uint32_t numPicsBeforeClearInDPB = m_rDPBStorageManager.get_number_of_pics_in_dpb();
ASSERTED uint32_t cFreedResources = m_rDPBStorageManager.clear_decode_picture_buffer();
assert(numPicsBeforeClearInDPB == cFreedResources);
// Initialize if needed the reconstructed picture allocation for the first IDR picture in the GOP
// This needs to be done after initializing the GOP tracking state above since it makes decisions based on the
// current picture type.
prepare_current_frame_recon_pic_allocation();
// After clearing the DPB, outstanding used allocations should be 1u only for the first allocation for the
// reconstructed picture of the initial IDR in the GOP
assert(m_rDPBStorageManager.get_number_of_in_use_allocations() == (m_gopHasInterFrames ? 1u : 0u));
assert(m_rDPBStorageManager.get_number_of_tracked_allocations() <=
(m_MaxDPBCapacity + 1)); // pool is not extended beyond maximum expected usage
}
// Calculates the picture control structure for the current frame
bool
d3d12_video_encoder_references_manager_h264::get_current_frame_picture_control_data(
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &codecAllocation)
{
// Update reference picture control structures (L0/L1 and DPB descriptors lists based on current frame and next frame
// in GOP) for next frame
debug_printf("[D3D12 Video Encoder Picture Manager H264] %d resources IN USE out of a total of %d ALLOCATED "
"resources at frame with POC: %d\n",
m_rDPBStorageManager.get_number_of_in_use_allocations(),
m_rDPBStorageManager.get_number_of_tracked_allocations(),
m_curFrameState.PictureOrderCountNumber);
// See casts below
assert(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size() < UINT32_MAX);
bool needsL0List = (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME) ||
(m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME);
bool needsL1List = (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME);
assert(codecAllocation.DataSize == sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264));
// See D3D12 Encode spec below
// pList0ReferenceFrames
// List of past frame reference frames to be used for this frame. Each integer value in this array indices into
// pReferenceFramesReconPictureDescriptors to reference pictures kept in the DPB.
// pList1ReferenceFrames
// List of future frame reference frames to be used for this frame. Each integer value in this array indices into
// pReferenceFramesReconPictureDescriptors to reference pictures kept in the DPB.
// Need to map from frame_num in the receiving ref_idx_l0_list/ref_idx_l1_list to the position with that
// FrameDecodingOrderNumber in the DPB descriptor
if (needsL0List && (m_curFrameState.List0ReferenceFramesCount > 0)) {
std::vector<uint32_t> tmpL0(m_curFrameState.List0ReferenceFramesCount, 0);
memcpy(tmpL0.data(),
m_curFrameState.pList0ReferenceFrames,
m_curFrameState.List0ReferenceFramesCount * sizeof(m_curFrameState.pList0ReferenceFrames[0]));
for (size_t l0Idx = 0; l0Idx < m_curFrameState.List0ReferenceFramesCount; l0Idx++) {
// tmpL0[l0Idx] has frame_num's (FrameDecodingOrderNumber)
// m_curFrameState.pList0ReferenceFrames[l0Idx] needs to have the index j of
// pReferenceFramesReconPictureDescriptors where
// pReferenceFramesReconPictureDescriptors[j].FrameDecodingOrderNumber == tmpL0[l0Idx]
auto value = tmpL0[l0Idx];
auto foundItemIt = std::find_if(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(),
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end(),
[&value](const D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_H264 &p) {
return p.FrameDecodingOrderNumber == value;
});
assert(foundItemIt != m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end());
if (foundItemIt == m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end())
{
return false;
}
m_curFrameState.pList0ReferenceFrames[l0Idx] =
std::distance(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(), foundItemIt);
}
}
if (needsL1List && (m_curFrameState.List1ReferenceFramesCount > 0)) {
std::vector<uint32_t> tmpL1(m_curFrameState.List1ReferenceFramesCount, 0);
memcpy(tmpL1.data(),
m_curFrameState.pList1ReferenceFrames,
m_curFrameState.List1ReferenceFramesCount * sizeof(m_curFrameState.pList1ReferenceFrames[0]));
for (size_t l1Idx = 0; l1Idx < m_curFrameState.List1ReferenceFramesCount; l1Idx++) {
// tmpL1[l1Idx] has frame_num's (FrameDecodingOrderNumber)
// m_curFrameState.pList1ReferenceFrames[l1Idx] needs to have the index j of
// pReferenceFramesReconPictureDescriptors where
// pReferenceFramesReconPictureDescriptors[j].FrameDecodingOrderNumber == tmpL1[l1Idx]
auto value = tmpL1[l1Idx];
auto foundItemIt = std::find_if(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(),
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end(),
[&value](const D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_H264 &p) {
return p.FrameDecodingOrderNumber == value;
});
assert(foundItemIt != m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end());
if (foundItemIt == m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.end())
{
return false;
}
m_curFrameState.pList1ReferenceFrames[l1Idx] =
std::distance(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(), foundItemIt);
}
}
m_curFrameState.List0ReferenceFramesCount = needsL0List ? m_curFrameState.List0ReferenceFramesCount : 0;
m_curFrameState.pList0ReferenceFrames = needsL0List ? m_curFrameState.pList0ReferenceFrames : nullptr,
m_curFrameState.List1ReferenceFramesCount = needsL1List ? m_curFrameState.List1ReferenceFramesCount : 0,
m_curFrameState.pList1ReferenceFrames = needsL1List ? m_curFrameState.pList1ReferenceFrames : nullptr,
m_curFrameState.ReferenceFramesReconPictureDescriptorsCount =
needsL0List ? static_cast<uint32_t>(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size()) :
0,
m_curFrameState.pReferenceFramesReconPictureDescriptors =
needsL0List ? m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.data() : nullptr,
if (codecAllocation.DataSize != sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264))
return false;
*codecAllocation.pH264PicData = m_curFrameState;
print_l0_l1_lists();
print_dpb();
return true;
}
// Returns the resource allocation for a reconstructed picture output for the current frame
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE
d3d12_video_encoder_references_manager_h264::get_current_frame_recon_pic_output_allocation()
{
return m_CurrentFrameReferencesData.ReconstructedPicTexture;
}
D3D12_VIDEO_ENCODE_REFERENCE_FRAMES
d3d12_video_encoder_references_manager_h264::get_current_reference_frames()
{
@@ -198,109 +56,59 @@ d3d12_video_encoder_references_manager_h264::get_current_reference_frames()
// and return references information for inter frames (eg.P/B) and I frame that doesn't flush DPB
if ((m_curFrameState.FrameType != D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME) &&
(m_curFrameState.FrameType != D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_I_FRAME) && m_gopHasInterFrames) {
auto curRef = m_rDPBStorageManager.get_current_reference_frames();
retVal.NumTexture2Ds = curRef.NumTexture2Ds;
retVal.ppTexture2Ds = curRef.ppTexture2Ds;
retVal.pSubresources = curRef.pSubresources;
(m_curFrameState.FrameType != D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_I_FRAME)) {
retVal.NumTexture2Ds = m_CurrentFrameReferencesData.ReferenceTextures.pResources.size();
retVal.ppTexture2Ds = m_CurrentFrameReferencesData.ReferenceTextures.pResources.data();
// D3D12 Encode expects null subresources for AoT
bool isAoT = (std::all_of(m_CurrentFrameReferencesData.ReferenceTextures.pSubresources.begin(),
m_CurrentFrameReferencesData.ReferenceTextures.pSubresources.end(),
[](UINT i) { return i == 0; }));
retVal.pSubresources = isAoT ? nullptr : m_CurrentFrameReferencesData.ReferenceTextures.pSubresources.data();
}
return retVal;
}
void
d3d12_video_encoder_references_manager_h264::prepare_current_frame_recon_pic_allocation()
static const char *
d3d12_video_encoder_friendly_frame_type_h264(D3D12_VIDEO_ENCODER_FRAME_TYPE_H264 picType)
{
m_CurrentFrameReferencesData.ReconstructedPicTexture = { nullptr, 0 };
// If all GOP are intra frames, no point in doing reference pic allocations
if (is_current_frame_used_as_reference() && m_gopHasInterFrames) {
auto reconPic = m_rDPBStorageManager.get_new_tracked_picture_allocation();
m_CurrentFrameReferencesData.ReconstructedPicTexture.pReconstructedPicture = reconPic.pReconstructedPicture;
m_CurrentFrameReferencesData.ReconstructedPicTexture.ReconstructedPictureSubresource =
reconPic.ReconstructedPictureSubresource;
switch (picType) {
case D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME:
{
return "H264_P_FRAME";
} break;
case D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME:
{
return "H264_B_FRAME";
} break;
case D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_I_FRAME:
{
return "H264_I_FRAME";
} break;
case D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME:
{
return "H264_IDR_FRAME";
} break;
default:
{
unreachable("Unsupported pipe_h2645_enc_picture_type");
} break;
}
}
void
d3d12_video_encoder_references_manager_h264::update_fifo_dpb_push_front_cur_recon_pic()
{
// Keep the order of the dpb storage and dpb descriptors in a circular buffer
// order such that the DPB array consists of a sequence of frames in DECREASING encoding order
// eg. last frame encoded at first, followed by one to last frames encoded, and at the end
// the most distant frame encoded (currentFrameEncodeOrderNumber - MaxDPBSize)
// If current pic was not used as reference, current reconstructed picture resource is empty,
// No need to to anything in that case.
// Otherwise extract the reconstructed picture result and add it to the DPB
// If GOP are all intra frames, do nothing also.
if (is_current_frame_used_as_reference() && m_gopHasInterFrames) {
debug_printf("[D3D12 Video Encoder Picture Manager H264] MaxDPBCapacity is %d - Number of pics in DPB is %d "
"when trying to put frame with POC %d at front of the DPB\n",
m_MaxDPBCapacity,
m_rDPBStorageManager.get_number_of_pics_in_dpb(),
m_curFrameState.PictureOrderCountNumber);
// Release least recently used in DPB if we filled the m_MaxDPBCapacity allowed
if (m_rDPBStorageManager.get_number_of_pics_in_dpb() == m_MaxDPBCapacity) {
bool untrackedRes = false;
m_rDPBStorageManager.remove_reference_frame(m_rDPBStorageManager.get_number_of_pics_in_dpb() - 1,
&untrackedRes); // Remove last entry
// Verify that resource was untracked since this class is using the pool completely for allocations
assert(untrackedRes);
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.pop_back(); // Remove last entry
}
// Add new dpb to front of DPB
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE recAlloc = get_current_frame_recon_pic_output_allocation();
d3d12_video_reconstructed_picture refFrameDesc = {};
refFrameDesc.pReconstructedPicture = recAlloc.pReconstructedPicture;
refFrameDesc.ReconstructedPictureSubresource = recAlloc.ReconstructedPictureSubresource;
refFrameDesc.pVideoHeap = nullptr; // D3D12 Video Encode does not need the D3D12VideoEncoderHeap struct for H264
// (used for no-key-frame resolution change in VC1, AV1, etc)
m_rDPBStorageManager.insert_reference_frame(refFrameDesc, 0);
// Prepare D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_H264 for added DPB member
D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_H264 newDPBDescriptor = {
// uint32_t ReconstructedPictureResourceIndex;
0, // the associated reconstructed picture is also being pushed_front in m_rDPBStorageManager
// BOOL IsLongTermReference;
false,
// uint32_t LongTermPictureIdx;
0,
// uint32_t PictureOrderCountNumber;
m_curFrameState.PictureOrderCountNumber,
// uint32_t FrameDecodingOrderNumber;
m_curFrameState.FrameDecodingOrderNumber,
// uint32_t TemporalLayerIndex;
0 // NO B-hierarchy in this impl of the picture manager
};
// Add DPB entry
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.insert(
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.begin(),
newDPBDescriptor);
// Update the indices for ReconstructedPictureResourceIndex in pReferenceFramesReconPictureDescriptors
// to be in identity mapping with m_rDPBStorageManager indices
// after pushing the elements to the right in the push_front operation
for (uint32_t dpbResIdx = 1;
dpbResIdx < m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size();
dpbResIdx++) {
auto &dpbDesc = m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[dpbResIdx];
dpbDesc.ReconstructedPictureResourceIndex = dpbResIdx;
}
}
// Number of allocations, disregarding if they are used or not, should not exceed this limit due to reuse policies on
// DPB items removal.
assert(m_rDPBStorageManager.get_number_of_tracked_allocations() <= (m_MaxDPBCapacity + 1));
}
void
d3d12_video_encoder_references_manager_h264::print_l0_l1_lists()
{
debug_printf(
"[D3D12 Video Encoder Picture Manager H264] L0 (%d entries) and L1 (%d entries) lists for frame with POC "
"%d (frame_num: %d) and frame_type %s are:\n",
m_curFrameState.List0ReferenceFramesCount,
m_curFrameState.List1ReferenceFramesCount,
m_curFrameState.PictureOrderCountNumber,
m_curFrameState.FrameDecodingOrderNumber,
d3d12_video_encoder_friendly_frame_type_h264(m_curFrameState.FrameType));
if ((D3D12_DEBUG_VERBOSE & d3d12_debug) &&
((m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME) ||
(m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME))) {
@@ -318,11 +126,33 @@ d3d12_video_encoder_references_manager_h264::print_l0_l1_lists()
list0ContentsString += "}\n";
}
debug_printf(
"[D3D12 Video Encoder Picture Manager H264] L0 list for frame with POC %d - frame_num (%d) is: \n %s \n",
m_curFrameState.PictureOrderCountNumber,
m_curFrameState.FrameDecodingOrderNumber,
list0ContentsString.c_str());
debug_printf("[D3D12 Video Encoder Picture Manager H264] L0 list (%d entries) for frame with POC %d - frame_num "
"(%d) is: \n %s \n",
m_curFrameState.List0ReferenceFramesCount,
m_curFrameState.PictureOrderCountNumber,
m_curFrameState.FrameDecodingOrderNumber,
list0ContentsString.c_str());
std::string modificationOrderList0ContentsString;
for (uint32_t idx = 0; idx < m_curFrameState.List0RefPicModificationsCount; idx++) {
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION value =
m_curFrameState.pList0RefPicModifications[idx];
modificationOrderList0ContentsString += "{ modification_of_pic_nums_idc: ";
modificationOrderList0ContentsString += std::to_string(value.modification_of_pic_nums_idc);
modificationOrderList0ContentsString += " - abs_diff_pic_num_minus1: ";
modificationOrderList0ContentsString += std::to_string(value.abs_diff_pic_num_minus1);
modificationOrderList0ContentsString += " - long_term_pic_num: ";
modificationOrderList0ContentsString += std::to_string(value.long_term_pic_num);
modificationOrderList0ContentsString += "}\n";
}
debug_printf("[D3D12 Video Encoder Picture Manager H264] L0 modification list (%d entries) for frame with POC %d "
"- frame_num "
"(%d) temporal_id (%d) is: \n %s \n",
m_curFrameState.List0RefPicModificationsCount,
m_curFrameState.PictureOrderCountNumber,
m_curFrameState.FrameDecodingOrderNumber,
m_curFrameState.TemporalLayerIndex,
modificationOrderList0ContentsString.c_str());
std::string list1ContentsString;
for (uint32_t idx = 0; idx < m_curFrameState.List1ReferenceFramesCount; idx++) {
@@ -338,11 +168,34 @@ d3d12_video_encoder_references_manager_h264::print_l0_l1_lists()
list1ContentsString += "}\n";
}
debug_printf(
"[D3D12 Video Encoder Picture Manager H264] L1 list for frame with POC %d - frame_num (%d) is: \n %s \n",
m_curFrameState.PictureOrderCountNumber,
m_curFrameState.FrameDecodingOrderNumber,
list1ContentsString.c_str());
debug_printf("[D3D12 Video Encoder Picture Manager H264] L1 list (%d entries) for frame with POC %d - frame_num "
"(%d) is: \n %s \n",
m_curFrameState.List1ReferenceFramesCount,
m_curFrameState.PictureOrderCountNumber,
m_curFrameState.FrameDecodingOrderNumber,
list1ContentsString.c_str());
std::string modificationOrderList1ContentsString;
for (uint32_t idx = 0; idx < m_curFrameState.List1RefPicModificationsCount; idx++) {
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION value =
m_curFrameState.pList1RefPicModifications[idx];
modificationOrderList1ContentsString += "{ modification_of_pic_nums_idc: ";
modificationOrderList1ContentsString += std::to_string(value.modification_of_pic_nums_idc);
modificationOrderList1ContentsString += " - abs_diff_pic_num_minus1: ";
modificationOrderList1ContentsString += std::to_string(value.abs_diff_pic_num_minus1);
modificationOrderList1ContentsString += " - long_term_pic_num: ";
modificationOrderList1ContentsString += std::to_string(value.long_term_pic_num);
modificationOrderList1ContentsString += "}\n";
}
debug_printf("[D3D12 Video Encoder Picture Manager H264] L1 modification list (%d entries) for frame with POC %d "
"- frame_num "
"(%d) temporal_id (%d) is: \n %s \n",
m_curFrameState.List1RefPicModificationsCount,
m_curFrameState.PictureOrderCountNumber,
m_curFrameState.FrameDecodingOrderNumber,
m_curFrameState.TemporalLayerIndex,
modificationOrderList1ContentsString.c_str());
}
}
@@ -355,10 +208,14 @@ d3d12_video_encoder_references_manager_h264::print_dpb()
dpbResIdx < m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size();
dpbResIdx++) {
auto &dpbDesc = m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[dpbResIdx];
auto dpbEntry = m_rDPBStorageManager.get_reference_frame(dpbDesc.ReconstructedPictureResourceIndex);
dpbContents += "{ DPBidx: ";
dpbContents += std::to_string(dpbResIdx);
if (dpbDesc.PictureOrderCountNumber == m_curFrameState.PictureOrderCountNumber) {
dpbContents += " - CURRENT FRAME RECON PIC ";
}
dpbContents += " - POC: ";
dpbContents += std::to_string(dpbDesc.PictureOrderCountNumber);
dpbContents += " - FrameDecodingOrderNumber: ";
@@ -368,69 +225,306 @@ d3d12_video_encoder_references_manager_h264::print_dpb()
dpbContents += " - DPBStorageResourcePtr: ";
char strBuf[256];
memset(&strBuf, '\0', 256);
sprintf(strBuf, "%p", dpbEntry.pReconstructedPicture);
sprintf(strBuf,
"%p",
m_CurrentFrameReferencesData.ReferenceTextures.pResources[dpbDesc.ReconstructedPictureResourceIndex]);
dpbContents += std::string(strBuf);
dpbContents += " - DPBStorageSubresource: ";
dpbContents += std::to_string(dpbEntry.ReconstructedPictureSubresource);
dpbContents += std::to_string(
m_CurrentFrameReferencesData.ReferenceTextures.pSubresources[dpbDesc.ReconstructedPictureResourceIndex]);
dpbContents += "}\n";
}
debug_printf("[D3D12 Video Encoder Picture Manager H264] DPB Current output reconstructed picture %p subresource %d\n",
m_CurrentFrameReferencesData.ReconstructedPicTexture.pReconstructedPicture,
m_CurrentFrameReferencesData.ReconstructedPicTexture.ReconstructedPictureSubresource);
debug_printf("[D3D12 Video Encoder Picture Manager H264] DPB has %d frames - DPB references for frame with POC "
"%d (frame_num: %d) are: \n %s \n",
m_rDPBStorageManager.get_number_of_pics_in_dpb(),
m_curFrameState.PictureOrderCountNumber,
m_curFrameState.FrameDecodingOrderNumber,
dpbContents.c_str());
"%d (frame_num: %d) are: \n %s \n",
static_cast<UINT>(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size()),
m_curFrameState.PictureOrderCountNumber,
m_curFrameState.FrameDecodingOrderNumber,
dpbContents.c_str());
}
}
// Advances state to next frame in GOP; subsequent calls to GetCurrentFrame* point to the advanced frame status
void
d3d12_video_encoder_references_manager_h264::end_frame()
static D3D12_VIDEO_ENCODER_FRAME_TYPE_H264
d3d12_video_encoder_convert_frame_type_h264(enum pipe_h2645_enc_picture_type picType)
{
debug_printf("[D3D12 Video Encoder Picture Manager H264] %d resources IN USE out of a total of %d ALLOCATED "
"resources at end_frame for frame with POC: %d\n",
m_rDPBStorageManager.get_number_of_in_use_allocations(),
m_rDPBStorageManager.get_number_of_tracked_allocations(),
m_curFrameState.PictureOrderCountNumber);
// Adds last used (if not null) get_current_frame_recon_pic_output_allocation to DPB for next EncodeFrame if
// necessary updates pReferenceFramesReconPictureDescriptors and updates the dpb storage
update_fifo_dpb_push_front_cur_recon_pic();
}
bool
d3d12_video_encoder_references_manager_h264::is_current_frame_used_as_reference()
{
return m_isCurrentFrameUsedAsReference;
switch (picType) {
case PIPE_H2645_ENC_PICTURE_TYPE_P:
{
return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME;
} break;
case PIPE_H2645_ENC_PICTURE_TYPE_B:
{
return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME;
} break;
case PIPE_H2645_ENC_PICTURE_TYPE_I:
{
return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_I_FRAME;
} break;
case PIPE_H2645_ENC_PICTURE_TYPE_IDR:
{
return D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME;
} break;
default:
{
unreachable("Unsupported pipe_h2645_enc_picture_type");
} break;
}
}
void
d3d12_video_encoder_references_manager_h264::begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData,
bool bUsedAsReference, struct pipe_picture_desc* picture)
bool bUsedAsReference,
struct pipe_picture_desc *picture)
{
m_curFrameState = *curFrameData.pH264PicData;
m_isCurrentFrameUsedAsReference = bUsedAsReference;
debug_printf("[Entrypoint: %d] - Marking frame_num %d (POC %d) as reference ? %d\n",
picture->entry_point,
curFrameData.pH264PicData->FrameDecodingOrderNumber,
curFrameData.pH264PicData->PictureOrderCountNumber,
bUsedAsReference);
// Advance the GOP tracking state
bool isDPBFlushNeeded = (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_IDR_FRAME);
if (isDPBFlushNeeded) {
reset_gop_tracking_and_dpb();
} else {
// Get new allocation from DPB storage for reconstructed picture
// This is only necessary for the frames that come after an IDR
// since in the initial state already has this initialized
// and re-initialized by reset_gop_tracking_and_dpb above
struct pipe_h264_enc_picture_desc *h264Pic = (struct pipe_h264_enc_picture_desc *) picture;
prepare_current_frame_recon_pic_allocation();
///
/// Copy DPB snapshot from pipe params
///
m_curFrameState.ReferenceFramesReconPictureDescriptorsCount =
static_cast<uint32_t>(m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size());
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.resize(h264Pic->dpb_size);
m_CurrentFrameReferencesData.ReferenceTextures.pResources.resize(h264Pic->dpb_size);
m_CurrentFrameReferencesData.ReferenceTextures.pSubresources.resize(h264Pic->dpb_size);
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.resize(h264Pic->dpb_size);
for (uint8_t i = 0; i < h264Pic->dpb_size; i++) {
//
// Set entry DPB members
//
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[i].FrameDecodingOrderNumber =
h264Pic->dpb[i].frame_idx;
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[i].IsLongTermReference =
h264Pic->dpb[i].is_ltr;
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[i].LongTermPictureIdx =
h264Pic->dpb[i].is_ltr ? h264Pic->dpb[i].frame_idx : 0u;
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[i].PictureOrderCountNumber =
h264Pic->dpb[i].pic_order_cnt;
// mirror indices between DPB entries and allocation arrays
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[i].ReconstructedPictureResourceIndex = i;
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors[i].TemporalLayerIndex =
0u; // h264Pic->dpb[i].temporal_id;
//
// Set texture allocations
//
struct d3d12_video_buffer *vidbuf = (struct d3d12_video_buffer *) h264Pic->dpb[i].buffer;
m_CurrentFrameReferencesData.ReferenceTextures.pResources[i] = d3d12_resource_resource(vidbuf->texture);
m_CurrentFrameReferencesData.ReferenceTextures.pSubresources[i] = vidbuf->idx_texarray_slots;
if (h264Pic->dpb[i].pic_order_cnt == h264Pic->pic_order_cnt) {
m_CurrentFrameReferencesData.ReconstructedPicTexture.pReconstructedPicture =
m_CurrentFrameReferencesData.ReferenceTextures.pResources[i];
m_CurrentFrameReferencesData.ReconstructedPicTexture.ReconstructedPictureSubresource =
m_CurrentFrameReferencesData.ReferenceTextures.pSubresources[i];
}
}
///
/// Set pic control info
///
m_curFrameState.idr_pic_id = h264Pic->idr_pic_id;
m_curFrameState.FrameType = d3d12_video_encoder_convert_frame_type_h264(h264Pic->picture_type);
m_curFrameState.PictureOrderCountNumber = h264Pic->pic_order_cnt;
m_curFrameState.FrameDecodingOrderNumber = h264Pic->frame_num;
m_curFrameState.TemporalLayerIndex = 0u; // h264Pic->temporal_id;
///
/// Set MMCO info
///
// If these static asserts do not pass anymore, change below ALL OCCURRENCES OF reinterpret_casts between
// pipe_h264_ref_pic_marking_entry and
// D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_MARKING_OPERATION
static_assert(sizeof(struct pipe_h264_ref_pic_marking_entry) ==
sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_MARKING_OPERATION));
static_assert(offsetof(struct pipe_h264_ref_pic_marking_entry, memory_management_control_operation) ==
offsetof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_MARKING_OPERATION,
memory_management_control_operation));
static_assert(offsetof(struct pipe_h264_ref_pic_marking_entry, difference_of_pic_nums_minus1) ==
offsetof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_MARKING_OPERATION,
difference_of_pic_nums_minus1));
static_assert(offsetof(struct pipe_h264_ref_pic_marking_entry, long_term_pic_num) ==
offsetof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_MARKING_OPERATION,
long_term_pic_num));
static_assert(offsetof(struct pipe_h264_ref_pic_marking_entry, long_term_frame_idx) ==
offsetof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_MARKING_OPERATION,
long_term_frame_idx));
static_assert(offsetof(struct pipe_h264_ref_pic_marking_entry, max_long_term_frame_idx_plus1) ==
offsetof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_MARKING_OPERATION,
max_long_term_frame_idx_plus1));
// Shallow Copy MMCO list
m_curFrameState.pRefPicMarkingOperationsCommands = nullptr;
m_curFrameState.RefPicMarkingOperationsCommandsCount = 0u;
// m_curFrameState.adaptive_ref_pic_marking_mode_flag = h264Pic->slice.adaptive_ref_pic_marking_mode_flag; // TODO:
// Uncomment setting adaptive_ref_pic_marking_mode_flag
if (m_curFrameState.adaptive_ref_pic_marking_mode_flag) {
m_curFrameState.RefPicMarkingOperationsCommandsCount = h264Pic->slice.num_ref_pic_marking_operations;
m_curFrameState.pRefPicMarkingOperationsCommands =
reinterpret_cast<D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_MARKING_OPERATION *>(
&h264Pic->slice.ref_pic_marking_operations[0]);
assert((m_curFrameState.RefPicMarkingOperationsCommandsCount == 0) ||
m_curFrameState.pRefPicMarkingOperationsCommands[m_curFrameState.RefPicMarkingOperationsCommandsCount - 1]
.memory_management_control_operation == 3);
}
///
/// Set ref pic modifications info
///
// d3d12 needs the array allocations passed in D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264
// to avoid copies, and taking advantage of the same memory layout with pipe, shallow copy them
// If these static asserts do not pass anymore, change below ALL OCCURRENCES OF reinterpret_casts between
// pipe_h264_ref_list_mod_entry and
// D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION
static_assert(
sizeof(struct pipe_h264_ref_list_mod_entry) ==
sizeof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION));
static_assert(
offsetof(struct pipe_h264_ref_list_mod_entry, modification_of_pic_nums_idc) ==
offsetof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION,
modification_of_pic_nums_idc));
static_assert(
offsetof(struct pipe_h264_ref_list_mod_entry, abs_diff_pic_num_minus1) ==
offsetof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION,
abs_diff_pic_num_minus1));
static_assert(
offsetof(struct pipe_h264_ref_list_mod_entry, long_term_pic_num) ==
offsetof(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION,
long_term_pic_num));
m_curFrameState.List0ReferenceFramesCount = 0;
m_curFrameState.pList0ReferenceFrames = nullptr;
m_curFrameState.List0RefPicModificationsCount = 0;
m_curFrameState.pList0RefPicModifications = nullptr;
m_curFrameState.List1ReferenceFramesCount = 0;
m_curFrameState.pList1ReferenceFrames = nullptr;
m_curFrameState.List1RefPicModificationsCount = 0;
m_curFrameState.pList1RefPicModifications = nullptr;
m_curFrameState.ReferenceFramesReconPictureDescriptorsCount = 0u;
m_curFrameState.pReferenceFramesReconPictureDescriptors = nullptr;
if ((m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_P_FRAME) ||
(m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME)) {
// Set DPB descriptors
m_curFrameState.ReferenceFramesReconPictureDescriptorsCount =
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.size();
m_curFrameState.pReferenceFramesReconPictureDescriptors =
m_CurrentFrameReferencesData.pReferenceFramesReconPictureDescriptors.data();
// Deep Copy L0 list
m_curFrameState.List0ReferenceFramesCount = h264Pic->num_ref_idx_l0_active_minus1 + 1;
m_CurrentFrameReferencesData.pList0ReferenceFrames.resize(m_curFrameState.List0ReferenceFramesCount);
for (unsigned i = 0; i < m_curFrameState.List0ReferenceFramesCount; i++)
m_CurrentFrameReferencesData.pList0ReferenceFrames[i] = h264Pic->ref_list0[i];
m_curFrameState.pList0ReferenceFrames = m_CurrentFrameReferencesData.pList0ReferenceFrames.data();
// Shallow Copy L0 ref modification list
m_curFrameState.List0RefPicModificationsCount = h264Pic->slice.num_ref_list0_mod_operations;
if (m_curFrameState.List0RefPicModificationsCount > 0) {
m_curFrameState.pList0RefPicModifications = reinterpret_cast<
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION *>(
&h264Pic->slice.ref_list0_mod_operations[0]);
// DX12 driver requires "End modification_of_pic_nums_idc syntax element loop" to be
// sent at the end of the list for coding the slice header when sending down reordering commands
assert((m_curFrameState.List0RefPicModificationsCount == 0) ||
m_curFrameState.pList0RefPicModifications[m_curFrameState.List0RefPicModificationsCount - 1]
.modification_of_pic_nums_idc == 3);
}
}
if (m_curFrameState.FrameType == D3D12_VIDEO_ENCODER_FRAME_TYPE_H264_B_FRAME) {
// Deep Copy L1 list
m_curFrameState.List1ReferenceFramesCount = h264Pic->num_ref_idx_l1_active_minus1 + 1;
m_CurrentFrameReferencesData.pList1ReferenceFrames.resize(m_curFrameState.List1ReferenceFramesCount);
for (unsigned i = 0; i < m_curFrameState.List1ReferenceFramesCount; i++)
m_CurrentFrameReferencesData.pList1ReferenceFrames[i] = h264Pic->ref_list1[i];
m_curFrameState.pList1ReferenceFrames = m_CurrentFrameReferencesData.pList1ReferenceFrames.data();
// Shallow Copy L1 ref modification list
m_curFrameState.List1RefPicModificationsCount = h264Pic->slice.num_ref_list1_mod_operations;
if (m_curFrameState.List1RefPicModificationsCount > 0) {
m_curFrameState.pList1RefPicModifications = reinterpret_cast<
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_LIST_MODIFICATION_OPERATION *>(
&h264Pic->slice.ref_list1_mod_operations[0]);
// DX12 driver requires "End modification_of_pic_nums_idc syntax element loop" to be
// sent at the end of the list for coding the slice header when sending down reordering commands
assert((m_curFrameState.List1RefPicModificationsCount == 0) ||
m_curFrameState.pList1RefPicModifications[m_curFrameState.List1RefPicModificationsCount - 1]
.modification_of_pic_nums_idc == 3);
}
}
print_dpb();
print_l0_l1_lists();
print_mmco_lists();
}
void
d3d12_video_encoder_references_manager_h264::print_mmco_lists()
{
debug_printf("[D3D12 Video Encoder Picture Manager H264] mmco list (%d entries) for frame with POC "
"%d (frame_num: %d) and frame_type %d are:\n",
m_curFrameState.RefPicMarkingOperationsCommandsCount,
m_curFrameState.PictureOrderCountNumber,
m_curFrameState.FrameDecodingOrderNumber,
m_curFrameState.FrameType);
for (uint32_t idx = 0; idx < m_curFrameState.RefPicMarkingOperationsCommandsCount; idx++) {
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264_REFERENCE_PICTURE_MARKING_OPERATION current_op =
m_curFrameState.pRefPicMarkingOperationsCommands[idx];
switch (current_op.memory_management_control_operation) {
case 0:
{
debug_printf("End memory_management_control_operation syntax element loop\n");
} break;
case 1:
{
debug_printf(
"Mark a short-term reference picture as \"unused for reference\" - difference_of_pic_nums_minus1: %d\n",
current_op.difference_of_pic_nums_minus1);
} break;
case 2:
{
debug_printf("Mark a long-term reference picture as \"unused for reference\"\n - long_term_pic_num: %d\n",
current_op.long_term_pic_num);
} break;
case 3:
{
debug_printf("Mark a short-term reference picture as \"used for long-term reference\" and assign a "
"long-term frame index to it - difference_of_pic_nums_minus1: %d - long_term_frame_idx: %d\n",
current_op.difference_of_pic_nums_minus1,
current_op.long_term_frame_idx);
} break;
case 4:
{
debug_printf("Specify the maximum long-term frame index and mark all long-term reference pictures having "
"long-term frame indices greater than the maximum value as \"unused for reference\" - "
"max_long_term_frame_idx_plus1: %d",
current_op.max_long_term_frame_idx_plus1);
} break;
case 5:
{
debug_printf("Mark all reference pictures as \"unused for reference\" and set the MaxLongTermFrameIdx "
"variable to \"no long-term frame indices\"");
} break;
case 6:
{
debug_printf("Mark the current picture as \"used for long-term reference\" and assign a long-term frame "
"index to it - long_term_frame_idx: %d",
current_op.long_term_frame_idx);
} break;
default:
{
unreachable("Unsupported memory_management_control_operation");
} break;
}
}
}

View File

@@ -21,54 +21,60 @@
* IN THE SOFTWARE.
*/
#ifndef D3D12_VIDEO_ENCODE_FIFO_REFERENCES_MANAGER_H264_H
#define D3D12_VIDEO_ENCODE_FIFO_REFERENCES_MANAGER_H264_H
#ifndef D3D12_VIDEO_ENCODE_REFERENCES_MANAGER_H264_H
#define D3D12_VIDEO_ENCODE_REFERENCES_MANAGER_H264_H
#include "d3d12_video_types.h"
#include "d3d12_video_encoder_references_manager.h"
#include "d3d12_video_dpb_storage_manager.h"
class d3d12_video_encoder_references_manager_h264 : public d3d12_video_encoder_references_manager_interface
{
public:
void end_frame();
void begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData, bool bUsedAsReference, struct pipe_picture_desc* picture);
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE get_current_frame_recon_pic_output_allocation();
void begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData,
bool bUsedAsReference,
struct pipe_picture_desc *picture);
bool get_current_frame_picture_control_data(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &codecAllocation);
bool is_current_frame_used_as_reference();
D3D12_VIDEO_ENCODE_REFERENCE_FRAMES get_current_reference_frames();
d3d12_video_encoder_references_manager_h264(bool gopHasInterCodedFrames,
d3d12_video_dpb_storage_manager_interface &rDpbStorageManager,
uint32_t MaxDPBCapacity);
bool is_current_frame_used_as_reference()
{
return m_isCurrentFrameUsedAsReference;
}
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE get_current_frame_recon_pic_output_allocation()
{
return m_CurrentFrameReferencesData.ReconstructedPicTexture;
}
void end_frame()
{ }
d3d12_video_encoder_references_manager_h264()
{ }
~d3d12_video_encoder_references_manager_h264()
{ }
private:
// Class helpers
void prepare_current_frame_recon_pic_allocation();
void reset_gop_tracking_and_dpb();
void update_fifo_dpb_push_front_cur_recon_pic();
void print_dpb();
void print_l0_l1_lists();
void print_mmco_lists();
// Class members
uint32_t m_MaxDPBCapacity = 0;
struct d3d12_video_dpb
{
std::vector<ID3D12Resource *> pResources;
std::vector<uint32_t> pSubresources;
};
struct current_frame_references_data
{
std::vector<D3D12_VIDEO_ENCODER_REFERENCE_PICTURE_DESCRIPTOR_H264> pReferenceFramesReconPictureDescriptors;
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE ReconstructedPicTexture;
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE ReconstructedPicTexture;
d3d12_video_dpb ReferenceTextures;
std::vector<UINT> pList0ReferenceFrames;
std::vector<UINT> pList1ReferenceFrames;
};
d3d12_video_dpb_storage_manager_interface &m_rDPBStorageManager;
current_frame_references_data m_CurrentFrameReferencesData;
bool m_gopHasInterFrames = false;
bool m_isCurrentFrameUsedAsReference = false;
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264 m_curFrameState = {};
};