diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp index f1fdb5893e6..76564c6d714 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp @@ -385,6 +385,68 @@ d3d12_video_encoder_update_move_rects(struct d3d12_video_encoder *pD3D12Enc, #endif } +#if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE +static void d3d12_video_encoder_is_gpu_qmap_input_feature_enabled(struct d3d12_video_encoder* pD3D12Enc, BOOL& isEnabled, D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE &outMapSourceEnabled) +{ + isEnabled = FALSE; + + // + // Prefer GPU QP Map over CPU QP Delta Map if both are enabled + // + + if (pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.AppRequested) + { + isEnabled = TRUE; + outMapSourceEnabled = D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_CPU_BUFFER; + assert(!pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.GPUInput.AppRequested); // When enabling CPU QP Map, GPU QP Delta must be disabled + } + + if (pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.GPUInput.AppRequested) + { + isEnabled = TRUE; + outMapSourceEnabled = D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_GPU_TEXTURE; + assert(!pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.AppRequested); // When enabling GPU QP Map, CPU QP Delta must be disabled + } +} +#endif // D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE + +void +d3d12_video_encoder_update_qpmap_input(struct d3d12_video_encoder *pD3D12Enc, + struct pipe_resource* qpmap, + struct pipe_enc_roi roi, + uint32_t temporal_id) +{ +#if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE + // + // Clear QPDelta context for this frame + // + memset(&pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc, 0, sizeof(pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc)); + pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[temporal_id].m_Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE; + + // + // Check if CPU/GPU QP Maps are enabled and store it in the context + // + if (qpmap) + { + pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.GPUInput.AppRequested = true; + pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.GPUInput.InputMap = d3d12_resource(qpmap); + pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[temporal_id].m_Flags |= + D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP; + } + + if (roi.num > 0) + { + pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.AppRequested = true; + // pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.* QP matrices are copied over in + // d3d12_video_encoder_xxx.cpp by calling d3d12_video_encoder_update_picparams_region_of_interest_qpmap method + // from the different ROI structures/ranges passed by the application + pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[temporal_id].m_Flags |= + D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP; + } + +#endif +} + void d3d12_video_encoder_update_dirty_rects(struct d3d12_video_encoder *pD3D12Enc, const struct pipe_enc_dirty_info& rects) @@ -1553,6 +1615,9 @@ bool d3d12_video_encoder_query_d3d12_driver_caps(struct d3d12_video_encoder *pD3 pD3D12Enc->m_currentEncodeConfig.m_DirtyRectsDesc.RectsInfo.MapValuesType : pD3D12Enc->m_currentEncodeConfig.m_DirtyRectsDesc.MapInfo.MapValuesType; } + + d3d12_video_encoder_is_gpu_qmap_input_feature_enabled(pD3D12Enc, /*output param*/ capEncoderSupportData1.QPMap.Enabled, /*output param*/ capEncoderSupportData1.QPMap.MapSource); + #endif enum pipe_video_format codec = u_reduce_video_profile(pD3D12Enc->base.profile); @@ -1711,6 +1776,45 @@ bool d3d12_video_encoder_query_d3d12_driver_caps(struct d3d12_video_encoder *pD3 } } + if ((capEncoderSupportData1.QPMap.MapSource == D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_GPU_TEXTURE) && + (capEncoderSupportData1.QPMap.Enabled)) + { + // Query specifics of staging resource for QPMap regions + pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.GPUInput.capInputLayoutQPMap = + { + // UINT NodeIndex; + 0u, + // D3D12_VIDEO_ENCODER_INPUT_MAP_SESSION_INFO SessionInfo; + { + capEncoderSupportData1.Codec, + d3d12_video_encoder_get_current_profile_desc(pD3D12Enc), + d3d12_video_encoder_get_current_level_desc(pD3D12Enc), + pD3D12Enc->m_currentEncodeConfig.m_encodeFormatInfo.Format, + // D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC + pD3D12Enc->m_currentEncodeConfig.m_currentResolution, + d3d12_video_encoder_get_current_codec_config_desc(pD3D12Enc), + capEncoderSupportData1.SubregionFrameEncoding, + capEncoderSupportData1.SubregionFrameEncodingData + }, + // D3D12_VIDEO_ENCODER_INPUT_MAP_TYPE MapType; + D3D12_VIDEO_ENCODER_INPUT_MAP_TYPE_QUANTIZATION_MATRIX, + // BOOL IsSupported; + FALSE, + // UINT64 MaxResolvedBufferAllocationSize; + 0u, + }; + + hr = pD3D12Enc->m_spD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_RESOLVE_INPUT_PARAM_LAYOUT, + &pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.GPUInput.capInputLayoutQPMap, + sizeof(pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.GPUInput.capInputLayoutQPMap)); + + if (FAILED(hr)) { + debug_printf("CheckFeatureSupport D3D12_FEATURE_VIDEO_ENCODER_RESOLVE_INPUT_PARAM_LAYOUT failed with HR %x\n", hr); + return false; + } + } + + return true; } @@ -1834,6 +1938,9 @@ d3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encod d3d12_video_encoder_update_move_rects(pD3D12Enc, ((struct pipe_h264_enc_picture_desc *)picture)->move_rects); d3d12_video_encoder_update_dirty_rects(pD3D12Enc, ((struct pipe_h264_enc_picture_desc *)picture)->dirty_info); + 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); // ...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; @@ -1848,6 +1955,9 @@ d3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encod d3d12_video_encoder_update_move_rects(pD3D12Enc, ((struct pipe_h265_enc_picture_desc *)picture)->move_rects); d3d12_video_encoder_update_dirty_rects(pD3D12Enc, ((struct pipe_h265_enc_picture_desc *)picture)->dirty_info); + 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); // ...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; @@ -1855,6 +1965,10 @@ d3d12_video_encoder_update_current_encoder_config_state(struct d3d12_video_encod #if VIDEO_CODEC_AV1ENC case PIPE_VIDEO_FORMAT_AV1: { + d3d12_video_encoder_update_qpmap_input(pD3D12Enc, ((struct pipe_av1_enc_picture_desc *)picture)->input_gpu_qpmap, + ((struct pipe_av1_enc_picture_desc *)picture)->roi, + ((struct pipe_av1_enc_picture_desc *)picture)->temporal_id); + // ...encoder_config_state_av1 calls encoder support cap, set any state before this call bCodecUpdatesSuccess = d3d12_video_encoder_update_current_encoder_config_state_av1(pD3D12Enc, srcTextureDesc, picture); } break; #endif @@ -2150,6 +2264,31 @@ d3d12_video_encoder_prepare_input_buffers(struct d3d12_video_encoder *pD3D12Enc) } } + BOOL QPMapEnabled = FALSE; + D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE QPMapSource = D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_CPU_BUFFER; + d3d12_video_encoder_is_gpu_qmap_input_feature_enabled(pD3D12Enc, /*output param*/ QPMapEnabled, /*output param*/ QPMapSource); + if (QPMapEnabled && (QPMapSource == D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_GPU_TEXTURE)) + { + bool bNeedsCreation = (pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_spQPMapResolvedOpaqueMap == NULL) || + (GetDesc(pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_spQPMapResolvedOpaqueMap.Get()).Width < + pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.GPUInput.capInputLayoutQPMap.MaxResolvedBufferAllocationSize); + if (bNeedsCreation) + { + pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_spQPMapResolvedOpaqueMap.Reset(); + CD3DX12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Buffer(pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.GPUInput.capInputLayoutQPMap.MaxResolvedBufferAllocationSize); + hr = pD3D12Enc->m_pD3D12Screen->dev->CreateCommittedResource(&Properties, + D3D12_HEAP_FLAG_NONE, + &desc, + D3D12_RESOURCE_STATE_COMMON, + nullptr, + IID_PPV_ARGS(&pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_spQPMapResolvedOpaqueMap)); + if (FAILED(hr)) + { + debug_printf("CreateCommittedResource for m_spQPMapResolvedOpaqueMap failed with HR %x\n", hr); + } + } + } + return SUCCEEDED(hr); } @@ -2951,6 +3090,47 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec, } } + D3D12_VIDEO_ENCODER_QUANTIZATION_OPAQUE_MAP QuantizationTextureMap = {}; + BOOL QPMapEnabled = false; + D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE QPMapSource = D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_CPU_BUFFER; + d3d12_video_encoder_is_gpu_qmap_input_feature_enabled(pD3D12Enc, /*output param*/ QPMapEnabled, /*output param*/ QPMapSource); + if (QPMapEnabled && (QPMapSource == D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_GPU_TEXTURE)) + { + picCtrlFlags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_FLAG_ENABLE_QUANTIZATION_MATRIX_INPUT; + QuantizationTextureMap.pOpaqueQuantizationMap = pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].m_spQPMapResolvedOpaqueMap.Get(); + + pResolveInputDataBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(QuantizationTextureMap.pOpaqueQuantizationMap, + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_WRITE)); + + pResolveInputDataBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(d3d12_resource_resource(pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.GPUInput.InputMap), + D3D12_RESOURCE_STATE_COMMON, + D3D12_RESOURCE_STATE_VIDEO_ENCODE_READ)); + + // see below std::warp for reversal to common after ResolveInputParamLayout is done + pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(static_cast(pResolveInputDataBarriers.size()), + pResolveInputDataBarriers.data()); + D3D12_VIDEO_ENCODER_INPUT_MAP_DATA ResolveInputData = {}; + ResolveInputData.MapType = D3D12_VIDEO_ENCODER_INPUT_MAP_TYPE_QUANTIZATION_MATRIX; + ResolveInputData.Quantization.pQuantizationMap = d3d12_resource_resource(pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.GPUInput.InputMap); + D3D12_VIDEO_ENCODER_RESOLVE_INPUT_PARAM_LAYOUT_INPUT_ARGUMENTS resolveInputParamLayoutInput = + { + pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.GPUInput.capInputLayoutQPMap.SessionInfo, + ResolveInputData, + }; + D3D12_VIDEO_ENCODER_RESOLVE_INPUT_PARAM_LAYOUT_OUTPUT_ARGUMENTS resolveInputParamLayoutOutput = + { + QuantizationTextureMap.pOpaqueQuantizationMap, + }; + + pD3D12Enc->m_spEncodeCommandList->ResolveInputParamLayout(&resolveInputParamLayoutInput, &resolveInputParamLayoutOutput); + for (auto &BarrierDesc : pResolveInputDataBarriers) { + std::swap(BarrierDesc.Transition.StateBefore, BarrierDesc.Transition.StateAfter); + } + pD3D12Enc->m_spEncodeCommandList->ResourceBarrier(static_cast(pResolveInputDataBarriers.size()), + pResolveInputDataBarriers.data()); + } + D3D12_VIDEO_ENCODER_FRAME_MOTION_VECTORS motionRegions = { }; motionRegions.MapSource = D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_CPU_BUFFER; motionRegions.pCPUBuffer = &pD3D12Enc->m_currentEncodeConfig.m_MoveRectsDesc; @@ -3026,7 +3206,7 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec, // D3D12_VIDEO_ENCODER_DIRTY_REGIONS DirtyRects; dirtyRegions, // D3D12_VIDEO_ENCODER_QUANTIZATION_OPAQUE_MAP QuantizationTextureMap; - {}, + QuantizationTextureMap, #endif }, pInputVideoD3D12Res, diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.h b/src/gallium/drivers/d3d12/d3d12_video_enc.h index 17b7c3e7a11..520564e3f68 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.h +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.h @@ -232,10 +232,6 @@ struct D3D12EncodeRateControlState D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR1 m_Configuration_VBR1; D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR1 m_Configuration_QVBR1; } m_Config; - - // AV1 uses 16 bit integers, H26x uses 8 bit integers - std::vector m_pRateControlQPMap8Bit; - std::vector m_pRateControlQPMap16Bit; }; struct D3D12EncodeConfiguration @@ -339,6 +335,20 @@ struct D3D12EncodeConfiguration } MapInfo; }; } m_DirtyRectsDesc = {}; + struct + { + struct { + bool AppRequested; + struct d3d12_resource* InputMap; + D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLVE_INPUT_PARAM_LAYOUT capInputLayoutQPMap; + } GPUInput; + struct { + bool AppRequested; + // AV1 uses 16 bit integers, H26x uses 8 bit integers + std::vector m_pRateControlQPMap8Bit; + std::vector m_pRateControlQPMap16Bit; + } CPUInput; + } m_QuantizationMatrixDesc = {}; std::vector m_DirtyRectsArray; D3D12_VIDEO_ENCODER_MOVEREGION_INFO m_MoveRectsDesc = {}; std::vector m_MoveRectsArray; @@ -522,6 +532,7 @@ struct d3d12_video_encoder enum pipe_video_feedback_encode_result_flags encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_OK; ComPtr m_spDirtyRectsResolvedOpaqueMap; // output of ID3D12VideoEncodeCommandList::ResolveInputParamLayout + ComPtr m_spQPMapResolvedOpaqueMap; // output of ID3D12VideoEncodeCommandList::ResolveInputParamLayout }; std::vector m_inflightResourcesPool; @@ -662,6 +673,12 @@ d3d12_video_encoder_update_output_stats_resources(struct d3d12_video_encoder *pD bool d3d12_video_encoder_prepare_input_buffers(struct d3d12_video_encoder *pD3D12Enc); + +void +d3d12_video_encoder_update_qpmap_input(struct d3d12_video_encoder *pD3D12Enc, + struct pipe_resource* qpmap, + struct pipe_enc_roi roi, + uint32_t temporal_id); /// /// d3d12_video_encoder functions ends /// diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc_av1.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc_av1.cpp index 2a18cf18294..0e3f39659be 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc_av1.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc_av1.cpp @@ -39,14 +39,13 @@ d3d12_video_encoder_update_current_rate_control_av1(struct d3d12_video_encoder * struct D3D12EncodeRateControlState m_prevRCState = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->temporal_id]; pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex = picture->temporal_id; + bool wasDeltaQPRequested = (pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->temporal_id].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0; pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->temporal_id] = {}; + if (wasDeltaQPRequested) + pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->temporal_id].m_Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP; + pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->temporal_id].m_FrameRate.Numerator = picture->rc[picture->temporal_id].frame_rate_num; pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->temporal_id].m_FrameRate.Denominator = picture->rc[picture->temporal_id].frame_rate_den; - pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->temporal_id].m_Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE; - - if (picture->roi.num > 0) - pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->temporal_id].m_Flags |= - D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP; switch (picture->rc[picture->temporal_id].rate_ctrl_method) { case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP: @@ -1631,7 +1630,8 @@ d3d12_video_encoder_update_current_frame_pic_params_info_av1(struct d3d12_video_ // pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot] // .m_CodecSpecificData.AV1HeadersInfo.temporal_delim_rendered = pAV1Pic->temporal_delim_rendered; - if ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pAV1Pic->temporal_id].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0) +#if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE + if (pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.AppRequested) { // Use 16 bit qpmap array for AV1 picparams (-255, 255 range and int16_t pRateControlQPMap type) const int32_t av1_min_delta_qp = -255; @@ -1641,10 +1641,11 @@ d3d12_video_encoder_update_current_frame_pic_params_info_av1(struct d3d12_video_ &pAV1Pic->roi, av1_min_delta_qp, av1_max_delta_qp, - pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pAV1Pic->temporal_id].m_pRateControlQPMap16Bit); - picParams.pAV1PicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pAV1Pic->temporal_id].m_pRateControlQPMap16Bit.data(); - picParams.pAV1PicData->QPMapValuesCount = static_cast(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[pAV1Pic->temporal_id].m_pRateControlQPMap16Bit.size()); + pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.m_pRateControlQPMap16Bit); + picParams.pAV1PicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.m_pRateControlQPMap16Bit.data(); + picParams.pAV1PicData->QPMapValuesCount = static_cast(pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.m_pRateControlQPMap16Bit.size()); } +#endif // D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE } void diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc_h264.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc_h264.cpp index 9f6e5281637..6b13c090278 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc_h264.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc_h264.cpp @@ -43,16 +43,14 @@ d3d12_video_encoder_update_current_rate_control_h264(struct d3d12_video_encoder struct D3D12EncodeRateControlState m_prevRCState = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic_ctrl.temporal_id]; pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex = h264Pic->pic_ctrl.temporal_id; + bool wasDeltaQPRequested = (pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0; pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id] = {}; + if (wasDeltaQPRequested) + pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP; pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_FrameRate.Numerator = picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].frame_rate_num; pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_FrameRate.Denominator = picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].frame_rate_den; - pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE; - - if (picture->roi.num > 0) - pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags |= - D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP; switch (picture->rate_ctrl[h264Pic->pic_ctrl.temporal_id].rate_ctrl_method) { case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP: @@ -379,7 +377,8 @@ d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video if (h264Pic->picture_type == PIPE_H2645_ENC_PICTURE_TYPE_B) picParams.pH264PicData->List1ReferenceFramesCount = h264Pic->num_ref_idx_l1_active_minus1 + 1; - if ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0) +#if D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE + if (pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.AppRequested) { // Use 8 bit qpmap array for H264 picparams (-51, 51 range and int8_t pRateControlQPMap type) const int32_t h264_min_delta_qp = -51; @@ -389,10 +388,11 @@ d3d12_video_encoder_update_current_frame_pic_params_info_h264(struct d3d12_video &h264Pic->roi, h264_min_delta_qp, h264_max_delta_qp, - pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_pRateControlQPMap8Bit); - picParams.pH264PicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_pRateControlQPMap8Bit.data(); - picParams.pH264PicData->QPMapValuesCount = static_cast(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[h264Pic->pic_ctrl.temporal_id].m_pRateControlQPMap8Bit.size()); + pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.m_pRateControlQPMap8Bit); + picParams.pH264PicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.m_pRateControlQPMap8Bit.data(); + picParams.pH264PicData->QPMapValuesCount = static_cast(pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.m_pRateControlQPMap8Bit.size()); } +#endif // D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE pD3D12Enc->m_upDPBManager->begin_frame(picParams, bUsedAsReference, picture); pD3D12Enc->m_upDPBManager->get_current_frame_picture_control_data(picParams); diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc_hevc.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc_hevc.cpp index 8dac6ce55fa..393d0ab2cc1 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc_hevc.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc_hevc.cpp @@ -41,16 +41,15 @@ d3d12_video_encoder_update_current_rate_control_hevc(struct d3d12_video_encoder struct D3D12EncodeRateControlState m_prevRCState = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id]; pD3D12Enc->m_currentEncodeConfig.m_activeRateControlIndex = picture->pic.temporal_id; + bool wasDeltaQPRequested = (pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0; pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id] = {}; + if (wasDeltaQPRequested) + pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |= D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP; + pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_FrameRate.Numerator = picture->rc[picture->pic.temporal_id].frame_rate_num; pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_FrameRate.Denominator = picture->rc[picture->pic.temporal_id].frame_rate_den; - pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags = D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_NONE; - - if (picture->roi.num > 0) - pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[picture->pic.temporal_id].m_Flags |= - D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP; switch (picture->rc[picture->pic.temporal_id].rate_ctrl_method) { case PIPE_H2645_ENC_RATE_CONTROL_METHOD_VARIABLE_SKIP: @@ -545,7 +544,7 @@ d3d12_video_encoder_update_current_frame_pic_params_info_hevc(struct d3d12_video & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_ALLOW_REQUEST_INTRA_CONSTRAINED_SLICES) != 0) picParams.pHEVCPicData->Flags |= D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC_FLAG_REQUEST_INTRA_CONSTRAINED_SLICES; - if ((pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[hevcPic->pic.temporal_id].m_Flags & D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_DELTA_QP) != 0) + if (pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.AppRequested) { // Use 8 bit qpmap array for HEVC picparams (-51, 51 range and int8_t pRateControlQPMap type) const int32_t hevc_min_delta_qp = -51; @@ -555,9 +554,9 @@ d3d12_video_encoder_update_current_frame_pic_params_info_hevc(struct d3d12_video &hevcPic->roi, hevc_min_delta_qp, hevc_max_delta_qp, - pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[hevcPic->pic.temporal_id].m_pRateControlQPMap8Bit); - picParams.pHEVCPicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[hevcPic->pic.temporal_id].m_pRateControlQPMap8Bit.data(); - picParams.pHEVCPicData->QPMapValuesCount = static_cast(pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc[hevcPic->pic.temporal_id].m_pRateControlQPMap8Bit.size()); + pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.m_pRateControlQPMap8Bit); + picParams.pHEVCPicData->pRateControlQPMap = pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.m_pRateControlQPMap8Bit.data(); + picParams.pHEVCPicData->QPMapValuesCount = static_cast(pD3D12Enc->m_currentEncodeConfig.m_QuantizationMatrixDesc.CPUInput.m_pRateControlQPMap8Bit.size()); } pD3D12Enc->m_upDPBManager->begin_frame(picParams, bUsedAsReference, picture); diff --git a/src/gallium/drivers/d3d12/d3d12_video_screen.cpp b/src/gallium/drivers/d3d12/d3d12_video_screen.cpp index 4eb05f411c4..d770d173cc2 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_screen.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_screen.cpp @@ -1062,6 +1062,41 @@ get_sliced_encode_support(D3D12_VIDEO_ENCODER_SUPPORT_FLAGS capEncoderSupportFla return sliced_encode_support; } +static +union pipe_enc_cap_qpmap +get_qpmap_gpuinput_support(D3D12_VIDEO_ENCODER_INPUT_MAP_SESSION_INFO sessionInfo, + ID3D12VideoDevice3* pD3D12VideoDevice) +{ + D3D12_FEATURE_DATA_VIDEO_ENCODER_QPMAP_INPUT capQPInput = + { + // UINT NodeIndex; + 0u, + // D3D12_VIDEO_ENCODER_INPUT_MAP_SESSION_INFO SessionInfo; + sessionInfo, + // D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE MapSource; + D3D12_VIDEO_ENCODER_INPUT_MAP_SOURCE_GPU_TEXTURE, + // BOOL IsSupported; + FALSE, + // UINT MapSourcePreferenceRanking; + 0u, + // UINT BlockSize; + 0u, + }; + + union pipe_enc_cap_qpmap qpmap_gpu_support = {}; + if (SUCCEEDED(pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_QPMAP_INPUT, &capQPInput, sizeof(capQPInput)))) + { + qpmap_gpu_support.bits.supported = capQPInput.IsSupported ? 1u : 0u; + if (qpmap_gpu_support.bits.supported) + { + qpmap_gpu_support.bits.pipe_pixel_format = PIPE_FORMAT_R8_UINT; // As per DX12 spec + qpmap_gpu_support.bits.log2_values_block_size = static_cast(std::log2(capQPInput.BlockSize)); + } + } + + return qpmap_gpu_support; +} + #endif // D3D12_VIDEO_USE_NEW_ENCODECMDLIST4_INTERFACE static bool @@ -1090,7 +1125,8 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen, union pipe_enc_cap_gpu_stats_map &gpu_stats_satd, union pipe_enc_cap_gpu_stats_map &gpu_stats_rcbits, union pipe_enc_cap_sliced_notifications &sliced_encode_support, - union pipe_enc_cap_dirty_info &dirty_rects_support_gpu) + union pipe_enc_cap_dirty_info &dirty_rects_support_gpu, + union pipe_enc_cap_qpmap &qpmap_support) { ComPtr spD3D12VideoDevice; struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen; @@ -1224,6 +1260,7 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen, move_rects_support = get_move_rects_support(sessionInfo, spD3D12VideoDevice.Get()); 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); + qpmap_support = get_qpmap_gpuinput_support(sessionInfo, spD3D12VideoDevice.Get()); #endif } } break; @@ -2119,6 +2156,7 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, union pipe_enc_cap_gpu_stats_map gpu_stats_satd = {}; union pipe_enc_cap_gpu_stats_map gpu_stats_rcbits = {}; union pipe_enc_cap_sliced_notifications sliced_encode_support = {}; + union pipe_enc_cap_qpmap gpu_qpmap_input = {}; memset(&codec_specific_support, 0, sizeof(codec_specific_support)); switch (param) { case PIPE_VIDEO_CAP_REQUIRES_FLUSH_ON_END_FRAME: @@ -2188,6 +2226,7 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, case PIPE_VIDEO_CAP_ENC_GPU_STATS_RATE_CONTROL_BITS_MAP: case PIPE_VIDEO_CAP_ENC_SLICED_NOTIFICATIONS: case PIPE_VIDEO_CAP_ENC_DIRTY_MAPS: + case PIPE_VIDEO_CAP_ENC_QP_MAPS: { if (d3d12_has_video_encode_support(pscreen, profile, @@ -2214,7 +2253,8 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, gpu_stats_satd, gpu_stats_rcbits, sliced_encode_support, - dirty_rects_support_gpu)) { + dirty_rects_support_gpu, + gpu_qpmap_input)) { DXGI_FORMAT format = d3d12_convert_pipe_video_profile_to_dxgi_format(profile); auto pipeFmt = d3d12_get_pipe_format(format); @@ -2313,6 +2353,8 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen, return sliced_encode_support.value; } else if (param == PIPE_VIDEO_CAP_ENC_DIRTY_MAPS) { return dirty_rects_support_gpu.value; + } else if (param == PIPE_VIDEO_CAP_ENC_QP_MAPS) { + return gpu_qpmap_input.value; } } } else if (param == PIPE_VIDEO_CAP_ENC_QUALITY_LEVEL) { @@ -2388,6 +2430,7 @@ d3d12_video_encode_requires_texture_array_dpb(struct d3d12_screen* pScreen, enum union pipe_enc_cap_gpu_stats_map gpu_stats_satd = {}; union pipe_enc_cap_gpu_stats_map gpu_stats_rcbits = {}; union pipe_enc_cap_sliced_notifications sliced_encode_support = {}; + union pipe_enc_cap_qpmap gpu_qpmap_input = {}; if (d3d12_has_video_encode_support(&pScreen->base, profile, maxLvlEncode, @@ -2413,7 +2456,8 @@ d3d12_video_encode_requires_texture_array_dpb(struct d3d12_screen* pScreen, enum gpu_stats_satd, gpu_stats_rcbits, sliced_encode_support, - dirty_rects_support_gpu)) + dirty_rects_support_gpu, + gpu_qpmap_input)) { return bVideoEncodeRequiresTextureArray; }