d3d12: Implement full/lower two pass video encode
Reviewed-by: Pohsiang (John) Hsu <pohhsu@microsoft.com> Reviewed-by: Jesse Natalie <jenatali@microsoft.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/35263>
This commit is contained in:
@@ -484,6 +484,179 @@ d3d12_video_encoder_update_qpmap_input(struct d3d12_video_encoder *pD3D12Enc,
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Called on encoder creation with the encoder creation parameters
|
||||
*/
|
||||
void d3d12_video_encoder_initialize_two_pass(struct d3d12_video_encoder *pD3D12Enc,
|
||||
const struct pipe_enc_two_pass_encoder_config& two_pass)
|
||||
{
|
||||
#if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE
|
||||
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc = {};
|
||||
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.two_pass_support.value =
|
||||
pD3D12Enc->m_screen->get_video_param(pD3D12Enc->m_screen,
|
||||
pD3D12Enc->base.profile,
|
||||
pD3D12Enc->base.entrypoint,
|
||||
PIPE_VIDEO_CAP_ENC_TWO_PASS);
|
||||
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.AppRequested = two_pass.enable;
|
||||
if (two_pass.pow2_downscale_factor > 0)
|
||||
{
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.Pow2DownscaleFactor = two_pass.pow2_downscale_factor;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.bUseExternalDPBScaling = two_pass.skip_1st_dpb_texture;
|
||||
}
|
||||
|
||||
#endif // D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE
|
||||
}
|
||||
|
||||
#if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE
|
||||
static
|
||||
struct pipe_enc_two_pass_frame_config
|
||||
d3d12_video_encoder_get_two_pass_config_from_picparams(struct pipe_picture_desc* picture,
|
||||
enum pipe_video_format codec)
|
||||
{
|
||||
struct pipe_enc_two_pass_frame_config twopass_frame_config = {};
|
||||
switch (codec) {
|
||||
#if VIDEO_CODEC_H264ENC
|
||||
case PIPE_VIDEO_FORMAT_MPEG4_AVC:
|
||||
{
|
||||
twopass_frame_config = ((struct pipe_h264_enc_picture_desc *)picture)->twopass_frame_config;
|
||||
} break;
|
||||
#endif
|
||||
#if VIDEO_CODEC_H265ENC
|
||||
case PIPE_VIDEO_FORMAT_HEVC:
|
||||
{
|
||||
twopass_frame_config = ((struct pipe_h265_enc_picture_desc *)picture)->twopass_frame_config;
|
||||
} break;
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
unreachable("Unsupported pipe_video_format");
|
||||
} break;
|
||||
}
|
||||
return twopass_frame_config;
|
||||
}
|
||||
#endif // D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE
|
||||
|
||||
/*
|
||||
* Caller once per frame to update the frame specific two pass settings
|
||||
* such as the skip_1st_pass_on_frame flag.
|
||||
*
|
||||
* This is called after the encoder has been created and the
|
||||
* encoder settings have been initialized in d3d12_video_encoder_initialize_two_pass
|
||||
* with the encoder creation two pass parameters.
|
||||
*/
|
||||
void
|
||||
d3d12_video_encoder_update_two_pass_frame_settings(struct d3d12_video_encoder *pD3D12Enc,
|
||||
enum pipe_video_format codec,
|
||||
struct pipe_picture_desc* picture)
|
||||
{
|
||||
#if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE
|
||||
if (pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.AppRequested)
|
||||
{
|
||||
struct pipe_enc_two_pass_frame_config two_pass_frame_cfg = d3d12_video_encoder_get_two_pass_config_from_picparams(picture, codec);
|
||||
|
||||
// Assume two pass enabled for all frames unless supports_dynamic_1st_pass_skip is not supported and skip requested
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.bSkipTwoPassInCurrentFrame = false;
|
||||
if (pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.two_pass_support.bits.supports_dynamic_1st_pass_skip)
|
||||
{
|
||||
// Honor the app's request to skip the 1st pass if supports_dynamic_1st_pass_skip supported
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.bSkipTwoPassInCurrentFrame = two_pass_frame_cfg.skip_1st_pass != 0;
|
||||
}
|
||||
|
||||
//
|
||||
// For when two pass is enabled for this frame AND Pow2DownscaleFactor > 0
|
||||
// also convert input downscaled texture and input recon pics (in/out)
|
||||
//
|
||||
if ((!pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.bSkipTwoPassInCurrentFrame) &&
|
||||
(pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.Pow2DownscaleFactor > 0))
|
||||
{
|
||||
|
||||
//
|
||||
// Convert the input downscaled texture from the pic params
|
||||
//
|
||||
struct d3d12_video_buffer *pDownscaledInputBuffer12 = (struct d3d12_video_buffer *) two_pass_frame_cfg.downscaled_source;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.pDownscaledInputTexture = pDownscaledInputBuffer12 ? d3d12_resource_resource(pDownscaledInputBuffer12->texture) : NULL;
|
||||
|
||||
//
|
||||
// Convert the DPB input and output params from the picparams DPB array
|
||||
//
|
||||
switch (codec) {
|
||||
#if VIDEO_CODEC_H264ENC
|
||||
case PIPE_VIDEO_FORMAT_MPEG4_AVC:
|
||||
{
|
||||
struct pipe_h264_enc_picture_desc *h264Pic = (struct pipe_h264_enc_picture_desc *) picture;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pResources.resize(h264Pic->dpb_size);
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pSubresources.resize(h264Pic->dpb_size);
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.FrameAnalysisReconstructedPictureOutput = { NULL, 0u };
|
||||
for (uint8_t i = 0; i < h264Pic->dpb_size; i++) {
|
||||
struct d3d12_video_buffer *vidbuf = (struct d3d12_video_buffer *) h264Pic->dpb[i].downscaled_buffer;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pResources[i] = d3d12_resource_resource(vidbuf->texture);
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pSubresources[i] = vidbuf->idx_texarray_slots;
|
||||
if (!pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.bUseExternalDPBScaling && // Pass NULL to the output recon pic 1st pass if bUseExternalDPBScaling set
|
||||
(h264Pic->dpb[i].pic_order_cnt == h264Pic->pic_order_cnt))
|
||||
{
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.FrameAnalysisReconstructedPictureOutput.pReconstructedPicture =
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pResources[i];
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.FrameAnalysisReconstructedPictureOutput.ReconstructedPictureSubresource =
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pSubresources[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we found the recon pio in the loop above
|
||||
// only fill the references for frame types as DX12 expects
|
||||
if ((h264Pic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_I) ||
|
||||
(h264Pic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR))
|
||||
{
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pResources.clear();
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pSubresources.clear();
|
||||
}
|
||||
|
||||
} break;
|
||||
#endif
|
||||
#if VIDEO_CODEC_H265ENC
|
||||
case PIPE_VIDEO_FORMAT_HEVC:
|
||||
{
|
||||
struct pipe_h265_enc_picture_desc *h265Pic = (struct pipe_h265_enc_picture_desc *) picture;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pResources.resize(h265Pic->dpb_size);
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pSubresources.resize(h265Pic->dpb_size);
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.FrameAnalysisReconstructedPictureOutput = { NULL, 0u };
|
||||
for (uint8_t i = 0; i < h265Pic->dpb_size; i++) {
|
||||
struct d3d12_video_buffer *vidbuf = (struct d3d12_video_buffer *) h265Pic->dpb[i].downscaled_buffer;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pResources[i] = d3d12_resource_resource(vidbuf->texture);
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pSubresources[i] = vidbuf->idx_texarray_slots;
|
||||
|
||||
if (!pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.bUseExternalDPBScaling && // Pass NULL to the output recon pic 1st pass if bUseExternalDPBScaling set
|
||||
(h265Pic->dpb[i].pic_order_cnt == h265Pic->pic_order_cnt))
|
||||
{
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.FrameAnalysisReconstructedPictureOutput.pReconstructedPicture =
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pResources[i];
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.FrameAnalysisReconstructedPictureOutput.ReconstructedPictureSubresource =
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pSubresources[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Now that we found the recon pio in the loop above
|
||||
// only fill the references for frame types as DX12 expects
|
||||
if (h265Pic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_IDR)
|
||||
{
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pResources.clear();
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pSubresources.clear();
|
||||
}
|
||||
|
||||
} break;
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
unreachable("Unsupported pipe_video_format");
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_update_dirty_rects(struct d3d12_video_encoder *pD3D12Enc,
|
||||
const struct pipe_enc_dirty_info& rects)
|
||||
@@ -805,6 +978,11 @@ d3d12_video_encoder_reconfigure_encoder_objects(struct d3d12_video_encoder *pD3D
|
||||
heapFlags |= D3D12_VIDEO_ENCODER_HEAP_FLAG_ALLOW_SUBREGION_NOTIFICATION_SINGLE_BUFFER;
|
||||
}
|
||||
|
||||
if (pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.AppRequested)
|
||||
{
|
||||
heapFlags |= D3D12_VIDEO_ENCODER_HEAP_FLAG_ALLOW_RATE_CONTROL_FRAME_ANALYSIS;
|
||||
}
|
||||
|
||||
D3D12_VIDEO_ENCODER_HEAP_DESC1 heapDesc1 = {
|
||||
pD3D12Enc->m_NodeMask,
|
||||
heapFlags,
|
||||
@@ -816,7 +994,9 @@ d3d12_video_encoder_reconfigure_encoder_objects(struct d3d12_video_encoder *pD3D
|
||||
// resolution list
|
||||
&pD3D12Enc->m_currentEncodeConfig.m_currentResolution,
|
||||
// UINT Pow2DownscaleFactor
|
||||
0,
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.AppRequested ?
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.Pow2DownscaleFactor
|
||||
: 0,
|
||||
};
|
||||
|
||||
// Create encoder heap
|
||||
@@ -1703,6 +1883,11 @@ bool d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(stru
|
||||
0) {
|
||||
debug_printf("[d3d12_video_encoder] Requested input dirty regions is not supported\n");
|
||||
}
|
||||
|
||||
if ((capEncoderSupportData1.ValidationFlags & D3D12_VIDEO_ENCODER_VALIDATION_FLAG_FRAME_ANALYSIS_NOT_SUPPORTED ) !=
|
||||
0) {
|
||||
debug_printf("[d3d12_video_encoder] Requested two pass encode is not supported\n");
|
||||
}
|
||||
#else
|
||||
|
||||
#endif
|
||||
@@ -1756,6 +1941,12 @@ bool d3d12_video_encoder_query_d3d12_driver_caps(struct d3d12_video_encoder *pD3
|
||||
capEncoderSupportData1.MotionSearch.BidirectionalRefFrameEnabled = TRUE;
|
||||
}
|
||||
|
||||
capEncoderSupportData1.FrameAnalysis.Enabled = pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.AppRequested;
|
||||
if (capEncoderSupportData1.FrameAnalysis.Enabled)
|
||||
{
|
||||
capEncoderSupportData1.FrameAnalysis.Pow2DownscaleFactor = pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.Pow2DownscaleFactor;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile);
|
||||
@@ -2118,6 +2309,7 @@ d3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encod
|
||||
d3d12_video_encoder_update_qpmap_input(pD3D12Enc, ((struct pipe_h264_enc_picture_desc *)picture)->input_gpu_qpmap,
|
||||
((struct pipe_h264_enc_picture_desc *)picture)->roi,
|
||||
((struct pipe_h264_enc_picture_desc *)picture)->pic_ctrl.temporal_id);
|
||||
d3d12_video_encoder_update_two_pass_frame_settings(pD3D12Enc, codec, picture);
|
||||
// ...encoder_config_state_h264 calls encoder support cap, set any state before this call
|
||||
bCodecUpdatesSuccess = d3d12_video_encoder_update_current_encoder_config_state_h264(pD3D12Enc, srcTextureDesc, picture);
|
||||
} break;
|
||||
@@ -2135,6 +2327,7 @@ d3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encod
|
||||
d3d12_video_encoder_update_qpmap_input(pD3D12Enc, ((struct pipe_h265_enc_picture_desc *)picture)->input_gpu_qpmap,
|
||||
((struct pipe_h265_enc_picture_desc *)picture)->roi,
|
||||
((struct pipe_h265_enc_picture_desc *)picture)->pic.temporal_id);
|
||||
d3d12_video_encoder_update_two_pass_frame_settings(pD3D12Enc, codec, picture);
|
||||
// ...encoder_config_state_hevc calls encoder support cap, set any state before this call
|
||||
bCodecUpdatesSuccess = d3d12_video_encoder_update_current_encoder_config_state_hevc(pD3D12Enc, srcTextureDesc, picture);
|
||||
} break;
|
||||
@@ -2294,6 +2487,7 @@ d3d12_video_encoder_create_encoder(struct pipe_context *context, const struct pi
|
||||
pD3D12Enc->supports_sliced_fences.value = context->screen->get_video_param(context->screen, codec->profile,
|
||||
codec->entrypoint,
|
||||
PIPE_VIDEO_CAP_ENC_SLICED_NOTIFICATIONS);
|
||||
d3d12_video_encoder_initialize_two_pass(pD3D12Enc, codec->two_pass);
|
||||
|
||||
return &pD3D12Enc->base;
|
||||
|
||||
@@ -3447,6 +3641,93 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec,
|
||||
d12_gpu_stats_rc_bitallocation_map = d3d12_resource_resource(pD3D12Enc->m_currentEncodeConfig.m_GPURCBitAllocationStatsResource);
|
||||
}
|
||||
|
||||
D3D12_VIDEO_ENCODER_FRAME_ANALYSIS FrameAnalysis = {};
|
||||
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE FrameAnalysisReconstructedPicture = {};
|
||||
std::vector<D3D12_RESOURCE_BARRIER> pTwoPassExtraBarriers;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Flags &=
|
||||
~D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_FRAME_ANALYSIS;
|
||||
|
||||
if ((pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.AppRequested) &&
|
||||
(!pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.bSkipTwoPassInCurrentFrame))
|
||||
{
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex].m_Flags |=
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_FRAME_ANALYSIS;
|
||||
|
||||
//
|
||||
// When Pow2DownscaleFactor is zero, is full resolution two pass, which leaves FrameAnalysis empty/zero filled.
|
||||
// For lower 1st pass resolution, we fill FrameAnalysis appropiately
|
||||
//
|
||||
|
||||
if (pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.Pow2DownscaleFactor > 0)
|
||||
{
|
||||
//
|
||||
// Schedule barrier transitions (reverse ones are scheduled later by doing swap to pTwoPassExtraBarriers)
|
||||
//
|
||||
|
||||
if (pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.pDownscaledInputTexture)
|
||||
{
|
||||
pTwoPassExtraBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.pDownscaledInputTexture,
|
||||
D3D12_RESOURCE_STATE_COMMON,
|
||||
D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ));
|
||||
}
|
||||
|
||||
if (pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pResources.size() > 0)
|
||||
{
|
||||
if ((pD3D12Enc->m_currentEncodeCapabilities.m_SupportFlags &
|
||||
D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RECONSTRUCTED_FRAMES_REQUIRE_TEXTURE_ARRAYS) != 0)
|
||||
{
|
||||
pTwoPassExtraBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pResources[0],
|
||||
D3D12_RESOURCE_STATE_COMMON,
|
||||
D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned i = 0; i < pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pResources.size(); i++)
|
||||
pTwoPassExtraBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pResources[i],
|
||||
D3D12_RESOURCE_STATE_COMMON,
|
||||
D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ));
|
||||
}
|
||||
}
|
||||
|
||||
if (pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.FrameAnalysisReconstructedPictureOutput.pReconstructedPicture) // can be NULL if external dpb scaling
|
||||
{
|
||||
pTwoPassExtraBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.FrameAnalysisReconstructedPictureOutput.pReconstructedPicture,
|
||||
D3D12_RESOURCE_STATE_COMMON,
|
||||
D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE));
|
||||
}
|
||||
|
||||
//
|
||||
// Set EncodeFrame params
|
||||
//
|
||||
|
||||
FrameAnalysisReconstructedPicture = pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.FrameAnalysisReconstructedPictureOutput;
|
||||
|
||||
FrameAnalysis =
|
||||
{
|
||||
// ID3D12Resource *pDownscaledFrame;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.pDownscaledInputTexture,
|
||||
// UINT64 Subresource;
|
||||
0u,
|
||||
// D3D12_VIDEO_ENCODE_REFERENCE_FRAMES DownscaledReferences;
|
||||
{
|
||||
// UINT NumTexture2Ds;
|
||||
static_cast<UINT>(pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pResources.size()),
|
||||
// _Field_size_full_(NumTexture2Ds) ID3D12Resource **ppTexture2Ds;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pResources.data(),
|
||||
// _Field_size_full_(NumTexture2Ds) UINT *pSubresources;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_TwoPassEncodeDesc.DownscaledReferences.pSubresources.data(),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
spEncodeCommandList4->ResourceBarrier(static_cast<uint32_t>(pTwoPassExtraBarriers.size()),
|
||||
pTwoPassExtraBarriers.data());
|
||||
}
|
||||
|
||||
const D3D12_VIDEO_ENCODER_ENCODEFRAME_INPUT_ARGUMENTS1 inputStreamArguments = {
|
||||
// D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_DESC
|
||||
{ // D3D12_VIDEO_ENCODER_SEQUENCE_CONTROL_FLAGS
|
||||
@@ -3475,7 +3756,7 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec,
|
||||
// D3D12_VIDEO_ENCODER_QUANTIZATION_OPAQUE_MAP QuantizationTextureMap;
|
||||
QuantizationTextureMap,
|
||||
// D3D12_VIDEO_ENCODER_FRAME_ANALYSIS FrameAnalysis;
|
||||
{ },
|
||||
FrameAnalysis,
|
||||
},
|
||||
pInputVideoD3D12Res,
|
||||
inputVideoD3D12Subresource,
|
||||
@@ -3659,7 +3940,7 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec,
|
||||
// D3D12_VIDEO_ENCODER_ENCODE_OPERATION_METADATA_BUFFER
|
||||
{ pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_spMetadataOutputBuffer.Get(), 0 },
|
||||
// D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE FrameAnalysisReconstructedPicture;
|
||||
{},
|
||||
FrameAnalysisReconstructedPicture,
|
||||
};
|
||||
|
||||
debug_printf("DX12 EncodeFrame submission fenceValue %" PRIu64 " current_metadata_slot %" PRIu64 " - POC %d picture_type %s LayoutMode %d SlicesCount %d IRMode %d IRIndex %d\n",
|
||||
@@ -3803,6 +4084,12 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec,
|
||||
}
|
||||
spEncodeCommandList4->ResourceBarrier(static_cast<uint32_t>(pSlicedEncodingExtraBarriers.size()),
|
||||
pSlicedEncodingExtraBarriers.data());
|
||||
|
||||
for (auto &BarrierDesc : pTwoPassExtraBarriers) {
|
||||
std::swap(BarrierDesc.Transition.StateBefore, BarrierDesc.Transition.StateAfter);
|
||||
}
|
||||
spEncodeCommandList4->ResourceBarrier(static_cast<uint32_t>(pTwoPassExtraBarriers.size()),
|
||||
pTwoPassExtraBarriers.data());
|
||||
}
|
||||
else
|
||||
#endif // D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE
|
||||
|
||||
@@ -378,6 +378,50 @@ struct D3D12EncodeConfiguration
|
||||
struct d3d12_resource *m_GPUQPStatsResource = NULL;
|
||||
struct d3d12_resource *m_GPUSATDStatsResource = NULL;
|
||||
struct d3d12_resource *m_GPURCBitAllocationStatsResource = NULL;
|
||||
struct
|
||||
{
|
||||
//
|
||||
// Cached caps on encoder creation members
|
||||
//
|
||||
union pipe_enc_cap_two_pass two_pass_support;
|
||||
|
||||
//
|
||||
// Encoder scope members
|
||||
//
|
||||
|
||||
// Indicates if two pass enabled
|
||||
bool AppRequested;
|
||||
|
||||
// Indicates, if enabled, the downscale factor for two pass
|
||||
UINT Pow2DownscaleFactor;
|
||||
|
||||
// If enabled, disable 1st pass recon pic output
|
||||
// as app will generate that by downscaling the
|
||||
// 2nd pass dpn recon externally
|
||||
bool bUseExternalDPBScaling;
|
||||
|
||||
//
|
||||
// Per frame scope members
|
||||
//
|
||||
|
||||
// If AppRequested is set, this
|
||||
// indicates when a specific frame two pass
|
||||
// will be disabled and its updated per frame
|
||||
// from the pipe pic params
|
||||
//
|
||||
// Note: IHV drivers may not support two pass
|
||||
// on all frame types, so the ones not supported
|
||||
// will naturally be always "skipped" anyways
|
||||
bool bSkipTwoPassInCurrentFrame;
|
||||
ID3D12Resource* pDownscaledInputTexture;
|
||||
struct
|
||||
{
|
||||
std::vector<ID3D12Resource *> pResources;
|
||||
std::vector<uint32_t> pSubresources;
|
||||
} DownscaledReferences;
|
||||
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE FrameAnalysisReconstructedPictureOutput;
|
||||
|
||||
} m_TwoPassEncodeDesc = {};
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -703,6 +747,13 @@ d3d12_video_encoder_update_qpmap_input(struct d3d12_video_encoder *pD3D12Enc,
|
||||
struct pipe_resource* qpmap,
|
||||
struct pipe_enc_roi roi,
|
||||
uint32_t temporal_id);
|
||||
void
|
||||
d3d12_video_encoder_initialize_two_pass(struct d3d12_video_encoder *pD3D12Enc,
|
||||
const struct pipe_enc_two_pass_encoder_config& two_pass);
|
||||
void
|
||||
d3d12_video_encoder_update_two_pass_frame_settings(struct d3d12_video_encoder *pD3D12Enc,
|
||||
enum pipe_video_format codec,
|
||||
struct pipe_picture_desc* picture);
|
||||
///
|
||||
/// d3d12_video_encoder functions ends
|
||||
///
|
||||
|
||||
@@ -907,8 +907,235 @@ static d3d12_video_encode_get_hevc_codec_support ( const D3D12_VIDEO_ENCODER_COD
|
||||
}
|
||||
#endif // VIDEO_CODEC_H265ENC
|
||||
|
||||
static bool
|
||||
d3d12_has_video_process_support(struct pipe_screen *pscreen,
|
||||
D3D12_FEATURE_DATA_VIDEO_PROCESS_SUPPORT &supportCaps,
|
||||
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC& outMinSupportedInput,
|
||||
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC& outMaxSupportedInput)
|
||||
{
|
||||
ComPtr<ID3D12VideoDevice> spD3D12VideoDevice;
|
||||
struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen;
|
||||
if (FAILED(pD3D12Screen->dev->QueryInterface(IID_PPV_ARGS(spD3D12VideoDevice.GetAddressOf())))) {
|
||||
// No video process support in underlying d3d12 device (needs ID3D12VideoDevice)
|
||||
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;
|
||||
}
|
||||
|
||||
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC 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 },
|
||||
{ 352, 480 },
|
||||
{ 352, 240 },
|
||||
{ 176, 144 },
|
||||
{ 128, 128 },
|
||||
{ 96, 96 },
|
||||
{ 64, 64 },
|
||||
{ 32, 32 },
|
||||
{ 16, 16 },
|
||||
{ 8, 8 },
|
||||
{ 4, 4 },
|
||||
{ 2, 2 },
|
||||
{ 1, 1 },
|
||||
};
|
||||
|
||||
outMinSupportedInput = {};
|
||||
outMaxSupportedInput = {};
|
||||
uint32_t idxResol = 0;
|
||||
bool bSupportsAny = false;
|
||||
while (idxResol < ARRAY_SIZE(resolutionsList)) {
|
||||
supportCaps.InputSample.Width = resolutionsList[idxResol].Width;
|
||||
supportCaps.InputSample.Height = resolutionsList[idxResol].Height;
|
||||
if (SUCCEEDED(spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_PROCESS_SUPPORT, &supportCaps, sizeof(supportCaps)))) {
|
||||
if ((supportCaps.SupportFlags & D3D12_VIDEO_PROCESS_SUPPORT_FLAG_SUPPORTED) != 0)
|
||||
{
|
||||
// Save the first (maximum)
|
||||
if(!bSupportsAny) {
|
||||
outMaxSupportedInput = resolutionsList[idxResol];
|
||||
bSupportsAny = true;
|
||||
}
|
||||
|
||||
// Keep saving the other supported values to get the minimum
|
||||
outMinSupportedInput = resolutionsList[idxResol];
|
||||
}
|
||||
}
|
||||
idxResol++;
|
||||
}
|
||||
|
||||
return VideoFeatureAreaSupport.VideoProcessSupport && bSupportsAny;
|
||||
}
|
||||
|
||||
#if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE
|
||||
|
||||
static
|
||||
union pipe_enc_cap_two_pass
|
||||
query_two_pass_support(struct pipe_screen *pscreen,
|
||||
D3D12_VIDEO_ENCODER_INPUT_MAP_SESSION_INFO sessionInfo,
|
||||
ID3D12VideoDevice3* pD3D12VideoDevice,
|
||||
bool bDriverSupportsReadableDPBReconPic)
|
||||
{
|
||||
union pipe_enc_cap_two_pass two_pass_support = {};
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_RATE_CONTROL_FRAME_ANALYSIS twoPassCapData =
|
||||
{
|
||||
// UINT NodeIndex;
|
||||
0u,
|
||||
//D3D12_VIDEO_ENCODER_CODEC Codec;
|
||||
sessionInfo.Codec,
|
||||
//D3D12_VIDEO_ENCODER_PROFILE_DESC Profile;
|
||||
sessionInfo.Profile,
|
||||
//D3D12_VIDEO_ENCODER_LEVEL_SETTING Level;
|
||||
sessionInfo.Level,
|
||||
//DXGI_FORMAT InputFormat;
|
||||
sessionInfo.InputFormat,
|
||||
//D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC InputResolution;
|
||||
sessionInfo.InputResolution,
|
||||
//D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION CodecConfiguration;
|
||||
sessionInfo.CodecConfiguration,
|
||||
//D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE SubregionFrameEncoding;
|
||||
sessionInfo.SubregionFrameEncoding,
|
||||
//D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA SubregionFrameEncodingData;
|
||||
sessionInfo.SubregionFrameEncodingData,
|
||||
//D3D12_VIDEO_ENCODER_QPMAP_CONFIGURATION QPMap;
|
||||
{
|
||||
//BOOL Enabled;
|
||||
FALSE,
|
||||
//D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE MapSource;
|
||||
D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_CPU_BUFFER,
|
||||
},
|
||||
//D3D12_VIDEO_ENCODER_DIRTY_REGIONS_CONFIGURATION DirtyRegions;
|
||||
{
|
||||
//BOOL Enabled;
|
||||
FALSE,
|
||||
//D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE MapSource;
|
||||
D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_CPU_BUFFER,
|
||||
//D3D12_VIDEO_ENCODER_DIRTY_REGIONS_MAP_VALUES_MODE MapValuesType;
|
||||
D3D12_VIDEO_ENCODER_DIRTY_REGIONS_MAP_VALUES_MODE_DIRTY,
|
||||
},
|
||||
//D3D12_VIDEO_ENCODER_MOTION_SEARCH_CONFIGURATION MotionSearch;
|
||||
{
|
||||
//BOOL Enabled;
|
||||
FALSE,
|
||||
//D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE MapSource;
|
||||
D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_CPU_BUFFER,
|
||||
//D3D12_VIDEO_ENCODER_FRAME_MOTION_SEARCH_MODE MotionSearchMode;
|
||||
D3D12_VIDEO_ENCODER_FRAME_MOTION_SEARCH_MODE_FULL_SEARCH,
|
||||
//BOOL BidirectionalRefFrameEnabled;
|
||||
FALSE,
|
||||
},
|
||||
//UINT Pow2DownscaleFactor;
|
||||
0u,
|
||||
//D3D12_VIDEO_ENCODER_RATE_CONTROL_FRAME_ANALYSIS_SUPPORT_FLAGS SupportFlags;
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FRAME_ANALYSIS_SUPPORT_FLAG_NONE,
|
||||
};
|
||||
|
||||
//
|
||||
// Find out if the driver supports D3D12_VIDEO_SCALE_SUPPORT_FLAG_DPB_ENCODER_RESOURCES
|
||||
//
|
||||
|
||||
D3D12_FEATURE_DATA_VIDEO_PROCESS_SUPPORT vpblitCapsData =
|
||||
{
|
||||
0, // NodeIndex
|
||||
{
|
||||
sessionInfo.InputResolution.Width,
|
||||
sessionInfo.InputResolution.Height,
|
||||
{
|
||||
sessionInfo.InputFormat,
|
||||
DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709
|
||||
}
|
||||
},
|
||||
D3D12_VIDEO_FIELD_TYPE_NONE,
|
||||
D3D12_VIDEO_FRAME_STEREO_FORMAT_NONE,
|
||||
{
|
||||
30,
|
||||
1
|
||||
},
|
||||
{
|
||||
sessionInfo.InputFormat,
|
||||
DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709
|
||||
},
|
||||
D3D12_VIDEO_FRAME_STEREO_FORMAT_NONE,
|
||||
{
|
||||
30,
|
||||
1
|
||||
},
|
||||
};
|
||||
|
||||
bool bDriverSupportsOpaqueDPBReconScaling = false;
|
||||
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC minSupportedInput = {};
|
||||
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC maxSupportedInput = {};
|
||||
if (d3d12_has_video_process_support(pscreen, vpblitCapsData, minSupportedInput, maxSupportedInput) &&
|
||||
(sessionInfo.InputResolution.Width <= maxSupportedInput.Width) &&
|
||||
(sessionInfo.InputResolution.Height <= maxSupportedInput.Height))
|
||||
{
|
||||
bDriverSupportsOpaqueDPBReconScaling = (vpblitCapsData.ScaleSupport.Flags & D3D12_VIDEO_SCALE_SUPPORT_FLAG_DPB_ENCODER_RESOURCES) != 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Find the min/max supported Pow2DownscaleFactor values.
|
||||
//
|
||||
|
||||
constexpr unsigned c_MaxPow2DownscaleToTry = 3u;
|
||||
// set a value bigger than c_MaxPow2DownscaleToTry and find the min in the loop below using std::min
|
||||
two_pass_support.bits.min_pow2_downscale_factor = c_MaxPow2DownscaleToTry + 1u;
|
||||
|
||||
for (unsigned CurPow2DownscaleFactor = 0; CurPow2DownscaleFactor <= c_MaxPow2DownscaleToTry; CurPow2DownscaleFactor++)
|
||||
{
|
||||
//
|
||||
// Query the cap with CurPow2DownscaleFactor
|
||||
//
|
||||
|
||||
twoPassCapData.Pow2DownscaleFactor = CurPow2DownscaleFactor;
|
||||
|
||||
if ((SUCCEEDED(pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_RATE_CONTROL_FRAME_ANALYSIS, &twoPassCapData, sizeof(twoPassCapData)))) &&
|
||||
(twoPassCapData.SupportFlags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FRAME_ANALYSIS_SUPPORT_FLAG_SUPPORTED))
|
||||
{
|
||||
two_pass_support.bits.supports_two_pass = 1u;
|
||||
two_pass_support.bits.min_pow2_downscale_factor = std::min(two_pass_support.bits.min_pow2_downscale_factor, twoPassCapData.Pow2DownscaleFactor);
|
||||
two_pass_support.bits.max_pow2_downscale_factor = std::max(two_pass_support.bits.min_pow2_downscale_factor, twoPassCapData.Pow2DownscaleFactor);
|
||||
two_pass_support.bits.supports_dynamic_1st_pass_skip = (twoPassCapData.SupportFlags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FRAME_ANALYSIS_SUPPORT_FLAG_DYNAMIC_1ST_PASS_SKIP) ? 1u : 0u;
|
||||
|
||||
if (twoPassCapData.SupportFlags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FRAME_ANALYSIS_SUPPORT_FLAG_EXTERNAL_DPB_DOWNSCALING)
|
||||
{
|
||||
//
|
||||
// For external DPB recon downscaling, one of these must be true:
|
||||
// 1. The DPB pictures are non-opaque layout (e.g without the reference only resource flag)
|
||||
// 2. The DPB pictures are opaque layout, but the driver also supports
|
||||
// D3D12_VIDEO_SCALE_SUPPORT_FLAG_DPB_ENCODER_RESOURCES (in the VPblit caps)
|
||||
//
|
||||
if (bDriverSupportsReadableDPBReconPic)
|
||||
{
|
||||
two_pass_support.bits.supports_1pass_recon_writing_skip = 1u;
|
||||
}
|
||||
else
|
||||
{
|
||||
two_pass_support.bits.supports_1pass_recon_writing_skip = bDriverSupportsOpaqueDPBReconScaling ? 1u : 0u;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!two_pass_support.bits.supports_two_pass)
|
||||
{
|
||||
two_pass_support = {}; // Clean min_pow2_downscale_factor
|
||||
}
|
||||
|
||||
return two_pass_support;
|
||||
}
|
||||
|
||||
static
|
||||
union pipe_enc_cap_dirty_info
|
||||
query_dirty_rects_support(D3D12_VIDEO_ENCODER_INPUT_MAP_SESSION_INFO sessionInfo,
|
||||
@@ -1251,7 +1478,8 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
|
||||
union pipe_enc_cap_sliced_notifications &sliced_encode_support,
|
||||
union pipe_enc_cap_dirty_info &dirty_rects_support_gpu,
|
||||
union pipe_enc_cap_qpmap &qpmap_support,
|
||||
union pipe_enc_cap_motion_vector_map &gpu_motion_input_support)
|
||||
union pipe_enc_cap_motion_vector_map &gpu_motion_input_support,
|
||||
union pipe_enc_cap_two_pass &two_pass_support)
|
||||
{
|
||||
ComPtr<ID3D12VideoDevice3> spD3D12VideoDevice;
|
||||
struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen;
|
||||
@@ -1389,6 +1617,9 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
|
||||
sliced_encode_support = get_sliced_encode_support(capEncoderSupportData1.SupportFlags);
|
||||
qpmap_support = get_qpmap_gpuinput_support(sessionInfo, spD3D12VideoDevice.Get());
|
||||
gpu_motion_input_support = get_motion_gpuinput_support(sessionInfo, spD3D12VideoDevice.Get());
|
||||
two_pass_support = query_two_pass_support(pscreen, sessionInfo, spD3D12VideoDevice.Get(),
|
||||
((capEncoderSupportData1.SupportFlags &
|
||||
D3D12_VIDEO_ENCODER_SUPPORT_FLAG_READABLE_RECONSTRUCTED_PICTURE_LAYOUT_AVAILABLE) != 0));
|
||||
#endif
|
||||
}
|
||||
} break;
|
||||
@@ -1715,6 +1946,9 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
|
||||
get_gpu_output_stats_support(sessionInfo, capEncoderSupportData1.SupportFlags, spD3D12VideoDevice.Get(), gpu_stats_qp, gpu_stats_satd, gpu_stats_rcbits);
|
||||
sliced_encode_support = get_sliced_encode_support(capEncoderSupportData1.SupportFlags);
|
||||
gpu_motion_input_support = get_motion_gpuinput_support(sessionInfo, spD3D12VideoDevice.Get());
|
||||
two_pass_support = query_two_pass_support(pscreen, sessionInfo, spD3D12VideoDevice.Get(),
|
||||
((capEncoderSupportData1.SupportFlags &
|
||||
D3D12_VIDEO_ENCODER_SUPPORT_FLAG_READABLE_RECONSTRUCTED_PICTURE_LAYOUT_AVAILABLE) != 0));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -2080,79 +2314,6 @@ 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,
|
||||
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC& outMinSupportedInput,
|
||||
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC& outMaxSupportedInput)
|
||||
{
|
||||
ComPtr<ID3D12VideoDevice> spD3D12VideoDevice;
|
||||
struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen;
|
||||
if (FAILED(pD3D12Screen->dev->QueryInterface(IID_PPV_ARGS(spD3D12VideoDevice.GetAddressOf())))) {
|
||||
// No video process support in underlying d3d12 device (needs ID3D12VideoDevice)
|
||||
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;
|
||||
}
|
||||
|
||||
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC 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 },
|
||||
{ 352, 480 },
|
||||
{ 352, 240 },
|
||||
{ 176, 144 },
|
||||
{ 128, 128 },
|
||||
{ 96, 96 },
|
||||
{ 64, 64 },
|
||||
{ 32, 32 },
|
||||
{ 16, 16 },
|
||||
{ 8, 8 },
|
||||
{ 4, 4 },
|
||||
{ 2, 2 },
|
||||
{ 1, 1 },
|
||||
};
|
||||
|
||||
outMinSupportedInput = {};
|
||||
outMaxSupportedInput = {};
|
||||
uint32_t idxResol = 0;
|
||||
bool bSupportsAny = false;
|
||||
while (idxResol < ARRAY_SIZE(resolutionsList)) {
|
||||
supportCaps.InputSample.Width = resolutionsList[idxResol].Width;
|
||||
supportCaps.InputSample.Height = resolutionsList[idxResol].Height;
|
||||
if (SUCCEEDED(spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_PROCESS_SUPPORT, &supportCaps, sizeof(supportCaps)))) {
|
||||
if ((supportCaps.SupportFlags & D3D12_VIDEO_PROCESS_SUPPORT_FLAG_SUPPORTED) != 0)
|
||||
{
|
||||
// Save the first (maximum)
|
||||
if(!bSupportsAny) {
|
||||
outMaxSupportedInput = resolutionsList[idxResol];
|
||||
bSupportsAny = true;
|
||||
}
|
||||
|
||||
// Keep saving the other supported values to get the minimum
|
||||
outMinSupportedInput = resolutionsList[idxResol];
|
||||
}
|
||||
}
|
||||
idxResol++;
|
||||
}
|
||||
|
||||
return VideoFeatureAreaSupport.VideoProcessSupport && bSupportsAny;
|
||||
}
|
||||
|
||||
static int
|
||||
d3d12_screen_get_video_param_postproc(struct pipe_screen *pscreen,
|
||||
enum pipe_video_profile profile,
|
||||
@@ -2305,6 +2466,7 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
|
||||
union pipe_enc_cap_sliced_notifications sliced_encode_support = {};
|
||||
union pipe_enc_cap_qpmap gpu_qpmap_input = {};
|
||||
union pipe_enc_cap_motion_vector_map gpu_motion_input = {};
|
||||
union pipe_enc_cap_two_pass two_pass_support = {};
|
||||
memset(&codec_specific_support, 0, sizeof(codec_specific_support));
|
||||
switch (param) {
|
||||
case PIPE_VIDEO_CAP_REQUIRES_FLUSH_ON_END_FRAME:
|
||||
@@ -2376,6 +2538,7 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
|
||||
case PIPE_VIDEO_CAP_ENC_DIRTY_MAPS:
|
||||
case PIPE_VIDEO_CAP_ENC_QP_MAPS:
|
||||
case PIPE_VIDEO_CAP_ENC_MOTION_VECTOR_MAPS:
|
||||
case PIPE_VIDEO_CAP_ENC_TWO_PASS:
|
||||
{
|
||||
if (d3d12_has_video_encode_support(pscreen,
|
||||
profile,
|
||||
@@ -2404,7 +2567,8 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
|
||||
sliced_encode_support,
|
||||
dirty_rects_support_gpu,
|
||||
gpu_qpmap_input,
|
||||
gpu_motion_input)) {
|
||||
gpu_motion_input,
|
||||
two_pass_support)) {
|
||||
|
||||
DXGI_FORMAT format = d3d12_convert_pipe_video_profile_to_dxgi_format(profile);
|
||||
auto pipeFmt = d3d12_get_pipe_format(format);
|
||||
@@ -2507,6 +2671,8 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
|
||||
return gpu_qpmap_input.value;
|
||||
} else if (param == PIPE_VIDEO_CAP_ENC_MOTION_VECTOR_MAPS) {
|
||||
return gpu_motion_input.value;
|
||||
} else if (param == PIPE_VIDEO_CAP_ENC_TWO_PASS ) {
|
||||
return two_pass_support.value;
|
||||
}
|
||||
}
|
||||
} else if (param == PIPE_VIDEO_CAP_ENC_QUALITY_LEVEL) {
|
||||
@@ -2584,6 +2750,7 @@ d3d12_video_encode_requires_texture_array_dpb(struct d3d12_screen* pScreen, enum
|
||||
union pipe_enc_cap_sliced_notifications sliced_encode_support = {};
|
||||
union pipe_enc_cap_qpmap gpu_qpmap_input = {};
|
||||
union pipe_enc_cap_motion_vector_map gpu_motion_input = {};
|
||||
union pipe_enc_cap_two_pass two_pass_support = {};
|
||||
if (d3d12_has_video_encode_support(&pScreen->base,
|
||||
profile,
|
||||
maxLvlEncode,
|
||||
@@ -2611,7 +2778,8 @@ d3d12_video_encode_requires_texture_array_dpb(struct d3d12_screen* pScreen, enum
|
||||
sliced_encode_support,
|
||||
dirty_rects_support_gpu,
|
||||
gpu_qpmap_input,
|
||||
gpu_motion_input))
|
||||
gpu_motion_input,
|
||||
two_pass_support))
|
||||
{
|
||||
return bVideoEncodeRequiresTextureArray;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user