d3d12: AV1 Encode
Reviewed-by: Jesse Natalie <jenatali@microsoft.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/23811>
This commit is contained in:
parent
314871d57b
commit
64da736286
15 changed files with 6023 additions and 304 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -29,6 +29,10 @@
|
|||
#include "d3d12_video_dpb_storage_manager.h"
|
||||
#include "d3d12_video_encoder_bitstream_builder_h264.h"
|
||||
#include "d3d12_video_encoder_bitstream_builder_hevc.h"
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
#include "d3d12_video_encoder_bitstream_builder_av1.h"
|
||||
#endif
|
||||
#include <list>
|
||||
|
||||
///
|
||||
/// Pipe video interface starts
|
||||
|
|
@ -126,18 +130,33 @@ struct D3D12EncodeCapabilities
|
|||
{
|
||||
D3D12_VIDEO_ENCODER_PROFILE_H264 m_H264Profile;
|
||||
D3D12_VIDEO_ENCODER_PROFILE_HEVC m_HEVCProfile;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
D3D12_VIDEO_ENCODER_AV1_PROFILE m_AV1Profile;
|
||||
#endif
|
||||
} m_encoderSuggestedProfileDesc = {};
|
||||
|
||||
union
|
||||
{
|
||||
D3D12_VIDEO_ENCODER_LEVELS_H264 m_H264LevelSetting;
|
||||
D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC m_HEVCLevelSetting;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS m_AV1LevelSetting;
|
||||
#endif
|
||||
} m_encoderLevelSuggestedDesc = {};
|
||||
|
||||
union
|
||||
struct
|
||||
{
|
||||
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264 m_H264CodecCaps;
|
||||
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC m_HEVCCodecCaps;
|
||||
union{
|
||||
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264 m_H264CodecCaps;
|
||||
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC m_HEVCCodecCaps;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT m_AV1CodecCaps;
|
||||
#endif
|
||||
};
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_SUPPORT m_AV1TileCaps;
|
||||
D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAGS RequiredNotRequestedFeatureFlags;
|
||||
#endif
|
||||
} m_encoderCodecSpecificConfigCaps = {};
|
||||
|
||||
// The maximum number of slices that the output of the current frame to be encoded will contain
|
||||
|
|
@ -147,6 +166,23 @@ struct D3D12EncodeCapabilities
|
|||
|
||||
};
|
||||
|
||||
struct D3D12EncodeRateControlState
|
||||
{
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE m_Mode = {};
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAGS m_Flags = {};
|
||||
DXGI_RATIONAL m_FrameRate = {};
|
||||
union
|
||||
{
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP m_Configuration_CQP;
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR m_Configuration_CBR;
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR m_Configuration_VBR;
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR m_Configuration_QVBR;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR1 m_Configuration_QVBR1;
|
||||
#endif
|
||||
} m_Config;
|
||||
};
|
||||
|
||||
struct D3D12EncodeConfiguration
|
||||
{
|
||||
d3d12_video_encoder_config_dirty_flags m_ConfigDirtyFlags = d3d12_video_encoder_config_dirty_flag_none;
|
||||
|
|
@ -166,52 +202,62 @@ struct D3D12EncodeConfiguration
|
|||
{
|
||||
D3D12_VIDEO_ENCODER_PROFILE_H264 m_H264Profile;
|
||||
D3D12_VIDEO_ENCODER_PROFILE_HEVC m_HEVCProfile;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
D3D12_VIDEO_ENCODER_AV1_PROFILE m_AV1Profile;
|
||||
#endif
|
||||
} m_encoderProfileDesc = {};
|
||||
|
||||
union
|
||||
{
|
||||
D3D12_VIDEO_ENCODER_LEVELS_H264 m_H264LevelSetting;
|
||||
D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC m_HEVCLevelSetting;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS m_AV1LevelSetting;
|
||||
#endif
|
||||
} m_encoderLevelDesc = {};
|
||||
|
||||
struct
|
||||
{
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE m_Mode = {};
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAGS m_Flags = {};
|
||||
DXGI_RATIONAL m_FrameRate = {};
|
||||
union
|
||||
{
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP m_Configuration_CQP;
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_CBR m_Configuration_CBR;
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_VBR m_Configuration_VBR;
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_QVBR m_Configuration_QVBR;
|
||||
} m_Config;
|
||||
} m_encoderRateControlDesc = {};
|
||||
struct D3D12EncodeRateControlState m_encoderRateControlDesc = {};
|
||||
|
||||
union
|
||||
{
|
||||
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_H264 m_H264Config;
|
||||
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC m_HEVCConfig;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION m_AV1Config;
|
||||
#endif
|
||||
} m_encoderCodecSpecificConfigDesc = {};
|
||||
|
||||
|
||||
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE m_encoderSliceConfigMode = {};
|
||||
union
|
||||
union
|
||||
{
|
||||
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES m_SlicesPartition_H264;
|
||||
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES m_SlicesPartition_HEVC;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
struct {
|
||||
D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES TilesPartition;
|
||||
uint8_t TilesGroupsCount;
|
||||
av1_tile_group_t TilesGroups[128];
|
||||
} m_TilesConfig_AV1;
|
||||
#endif
|
||||
} m_encoderSliceConfigDesc = {};
|
||||
|
||||
union
|
||||
{
|
||||
D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_H264 m_H264GroupOfPictures;
|
||||
D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_HEVC m_HEVCGroupOfPictures;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
D3D12_VIDEO_ENCODER_AV1_SEQUENCE_STRUCTURE m_AV1SequenceStructure;
|
||||
#endif
|
||||
} m_encoderGOPConfigDesc = {};
|
||||
|
||||
union
|
||||
{
|
||||
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_H264 m_H264PicData;
|
||||
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA_HEVC m_HEVCPicData;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_CODEC_DATA m_AV1PicData;
|
||||
#endif
|
||||
} m_encoderPicParamsDesc = {};
|
||||
|
||||
D3D12_VIDEO_ENCODER_MOTION_ESTIMATION_PRECISION_MODE m_encoderMotionPrecisionLimit =
|
||||
|
|
@ -220,6 +266,78 @@ struct D3D12EncodeConfiguration
|
|||
D3D12_VIDEO_ENCODER_INTRA_REFRESH m_IntraRefresh = { D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE, 0 };
|
||||
uint32_t m_IntraRefreshCurrentFrameIndex = 0;
|
||||
|
||||
struct D3D12AV1CodecSpecificState
|
||||
{
|
||||
std::list<UINT/*PictureIndex*/> pendingShowableFrames;
|
||||
} m_encoderCodecSpecificStateDescAV1;
|
||||
|
||||
};
|
||||
|
||||
struct EncodedBitstreamResolvedMetadata
|
||||
{
|
||||
ComPtr<ID3D12Resource> spBuffer;
|
||||
uint64_t bufferSize = 0;
|
||||
|
||||
ComPtr<ID3D12Resource> m_spMetadataOutputBuffer;
|
||||
/*
|
||||
* We need to store a snapshot of the encoder state
|
||||
* below as when get_feedback processes this other
|
||||
* async queued frames might have changed it
|
||||
*/
|
||||
|
||||
/*
|
||||
* byte size of pre encode uploaded bitstream headers
|
||||
* We need it in metadata as will be read in get_feedback
|
||||
* to calculate the final size while other async encode
|
||||
* operations (with potentially different headers) are being
|
||||
* encoded in the GPU
|
||||
*/
|
||||
uint64_t preEncodeGeneratedHeadersByteSize = 0;
|
||||
|
||||
/*
|
||||
* Indicates if the encoded frame needs header generation after GPU execution
|
||||
* If false, preEncodeGeneratedHeadersByteSize indicates the size of the generated
|
||||
* headers (if any)
|
||||
*
|
||||
* If true, indicates the headers must be generated at get_feedback time.
|
||||
*/
|
||||
bool postEncodeHeadersNeeded = false;
|
||||
|
||||
/* Indicates if the current metadata has been read by get_feedback */
|
||||
bool bRead = true;
|
||||
|
||||
/* associated encoded frame state snapshot*/
|
||||
struct D3D12EncodeCapabilities m_associatedEncodeCapabilities = {};
|
||||
struct D3D12EncodeConfiguration m_associatedEncodeConfig = {};
|
||||
|
||||
/*
|
||||
* Associated frame compressed bitstream buffer
|
||||
* If needed get_feedback will have to generate
|
||||
* headers and re-pack the compressed bitstream
|
||||
*/
|
||||
pipe_resource* comp_bit_destination;
|
||||
|
||||
/*
|
||||
* Staging bitstream for when headers must be
|
||||
* packed in get_feedback, it contains the encoded
|
||||
* stream from EncodeFrame.
|
||||
*/
|
||||
ComPtr<ID3D12Resource> spStagingBitstream;
|
||||
|
||||
/* codec specific associated configuration flags */
|
||||
union {
|
||||
struct {
|
||||
bool enable_frame_obu;
|
||||
bool obu_has_size_field;
|
||||
bool temporal_delim_rendered;
|
||||
} AV1HeadersInfo;
|
||||
} m_CodecSpecificData;
|
||||
|
||||
/*
|
||||
* Scratch CPU buffer memory to generate any extra headers
|
||||
* in between the GPU spStagingBitstream contents
|
||||
*/
|
||||
std::vector<uint8_t> m_StagingBitstreamConstruction;
|
||||
};
|
||||
|
||||
struct d3d12_video_encoder
|
||||
|
|
@ -250,14 +368,6 @@ struct d3d12_video_encoder
|
|||
std::shared_ptr<d3d12_video_dpb_storage_manager_interface> m_upDPBStorageManager;
|
||||
std::unique_ptr<d3d12_video_bitstream_builder_interface> m_upBitstreamBuilder;
|
||||
|
||||
struct EncodedBitstreamResolvedMetadata
|
||||
{
|
||||
ComPtr<ID3D12Resource> spBuffer;
|
||||
uint64_t bufferSize = 0;
|
||||
uint64_t codecHeadersSize = 0;
|
||||
ComPtr<ID3D12Resource> m_spMetadataOutputBuffer;
|
||||
};
|
||||
|
||||
std::vector<uint8_t> m_BitstreamHeadersBuffer;
|
||||
std::vector<uint8_t> m_StagingHeadersBuffer;
|
||||
std::vector<EncodedBitstreamResolvedMetadata> m_spEncodedFrameMetadata;
|
||||
|
|
@ -318,7 +428,7 @@ d3d12_video_encoder_update_picparams_tracking(struct d3d12_video_encoder *pD3D12
|
|||
struct pipe_video_buffer * srcTexture,
|
||||
struct pipe_picture_desc * picture);
|
||||
void
|
||||
d3d12_video_encoder_calculate_metadata_resolved_buffer_size(uint32_t maxSliceNumber, uint64_t &bufferSize);
|
||||
d3d12_video_encoder_calculate_metadata_resolved_buffer_size(enum pipe_video_format codec, uint32_t maxSliceNumber, uint64_t &bufferSize);
|
||||
uint32_t
|
||||
d3d12_video_encoder_calculate_max_slices_count_in_output(
|
||||
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE slicesMode,
|
||||
|
|
@ -330,8 +440,10 @@ bool
|
|||
d3d12_video_encoder_prepare_output_buffers(struct d3d12_video_encoder *pD3D12Enc,
|
||||
struct pipe_video_buffer * srcTexture,
|
||||
struct pipe_picture_desc * picture);
|
||||
uint32_t
|
||||
d3d12_video_encoder_build_codec_headers(struct d3d12_video_encoder *pD3D12Enc);
|
||||
void
|
||||
d3d12_video_encoder_build_pre_encode_codec_headers(struct d3d12_video_encoder *pD3D12Enc,
|
||||
bool &postEncodeHeadersNeeded,
|
||||
uint64_t &preEncodeGeneratedHeadersByteSize);
|
||||
void
|
||||
d3d12_video_encoder_extract_encode_metadata(
|
||||
struct d3d12_video_encoder * pD3D12Dec,
|
||||
|
|
@ -343,10 +455,26 @@ d3d12_video_encoder_extract_encode_metadata(
|
|||
D3D12_VIDEO_ENCODER_CODEC
|
||||
d3d12_video_encoder_get_current_codec(struct d3d12_video_encoder *pD3D12Enc);
|
||||
|
||||
bool d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(struct d3d12_video_encoder *pD3D12Enc, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT &capEncoderSupportData);
|
||||
bool d3d12_video_encoder_query_d3d12_driver_caps(struct d3d12_video_encoder *pD3D12Enc, D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT &capEncoderSupportData);
|
||||
bool d3d12_video_encoder_check_subregion_mode_support(struct d3d12_video_encoder *pD3D12Enc, D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedSlicesMode);
|
||||
uint64_t d3d12_video_encoder_pool_current_index(struct d3d12_video_encoder *pD3D12Enc);
|
||||
bool
|
||||
d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(struct d3d12_video_encoder *pD3D12Enc,
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 &capEncoderSupportData);
|
||||
bool
|
||||
d3d12_video_encoder_query_d3d12_driver_caps(struct d3d12_video_encoder *pD3D12Enc,
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 &capEncoderSupportData);
|
||||
bool
|
||||
d3d12_video_encoder_check_subregion_mode_support(struct d3d12_video_encoder *pD3D12Enc,
|
||||
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedSlicesMode);
|
||||
uint64_t
|
||||
d3d12_video_encoder_pool_current_index(struct d3d12_video_encoder *pD3D12Enc);
|
||||
|
||||
unsigned
|
||||
d3d12_video_encoder_build_post_encode_codec_bitstream(struct d3d12_video_encoder * pD3D12Enc,
|
||||
uint64_t associated_fence_value,
|
||||
EncodedBitstreamResolvedMetadata& associatedMetadata);
|
||||
|
||||
void
|
||||
d3d12_video_encoder_store_current_picture_references(d3d12_video_encoder *pD3D12Enc,
|
||||
uint64_t current_metadata_slot);
|
||||
|
||||
///
|
||||
/// d3d12_video_encoder functions ends
|
||||
|
|
|
|||
2695
src/gallium/drivers/d3d12/d3d12_video_enc_av1.cpp
Normal file
2695
src/gallium/drivers/d3d12/d3d12_video_enc_av1.cpp
Normal file
File diff suppressed because it is too large
Load diff
77
src/gallium/drivers/d3d12/d3d12_video_enc_av1.h
Normal file
77
src/gallium/drivers/d3d12/d3d12_video_enc_av1.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
|
||||
/*
|
||||
* Copyright © Microsoft Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef D3D12_VIDEO_ENC_AV1_H
|
||||
#define D3D12_VIDEO_ENC_AV1_H
|
||||
#include "d3d12_video_types.h"
|
||||
|
||||
const uint32_t UNUSED_VIRTUAL_DPB_SLOT_PHYSICAL_INDEX = 0xFF; // As per D3D12 spec
|
||||
|
||||
size_t
|
||||
d3d12_video_encoder_calculate_metadata_resolved_buffer_size_av1(uint32_t maxSliceNumber);
|
||||
|
||||
bool
|
||||
d3d12_video_encoder_update_current_encoder_config_state_av1(struct d3d12_video_encoder *pD3D12Enc,
|
||||
struct pipe_video_buffer *srcTexture,
|
||||
struct pipe_picture_desc *picture);
|
||||
|
||||
void
|
||||
d3d12_video_encoder_update_current_frame_pic_params_info_av1(struct d3d12_video_encoder *pD3D12Enc,
|
||||
struct pipe_video_buffer *srcTexture,
|
||||
struct pipe_picture_desc *picture,
|
||||
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &picParams,
|
||||
bool &bUsedAsReference);
|
||||
|
||||
unsigned
|
||||
d3d12_video_encoder_build_post_encode_codec_bitstream_av1(struct d3d12_video_encoder *pD3D12Enc,
|
||||
uint64_t associated_fence_value,
|
||||
EncodedBitstreamResolvedMetadata &associatedMetadata);
|
||||
|
||||
D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE
|
||||
d3d12_video_encoder_looprestorationsize_uint_to_d3d12_av1(uint32_t pixel_size);
|
||||
|
||||
unsigned
|
||||
d3d12_video_encoder_looprestorationsize_d3d12_to_uint_av1(D3D12_VIDEO_ENCODER_AV1_RESTORATION_TILESIZE d3d12_type);
|
||||
|
||||
void
|
||||
upload_tile_group_obu(struct d3d12_video_encoder *pD3D12Enc,
|
||||
size_t tile_group_obu_size,
|
||||
size_t decode_tile_elements_size,
|
||||
std::vector<uint8_t> &staging_bitstream_buffer,
|
||||
size_t staging_bitstream_buffer_offset,
|
||||
pipe_resource *src_driver_bitstream,
|
||||
pipe_resource *comp_bit_destination,
|
||||
size_t comp_bit_destination_offset,
|
||||
const D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA *pFrameSubregionMetadata,
|
||||
size_t TileSizeBytes, // Pass already +1'd from TileSizeBytesMinus1
|
||||
const D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES &TilesPartition,
|
||||
const av1_tile_group_t &tileGroup,
|
||||
size_t &written_bytes_to_staging_bitstream_buffer);
|
||||
|
||||
|
||||
void
|
||||
d3d12_video_encoder_store_current_picture_references_av1(d3d12_video_encoder *pD3D12Enc,
|
||||
uint64_t current_metadata_slot);
|
||||
|
||||
#endif
|
||||
|
|
@ -101,14 +101,74 @@ d3d12_video_encoder_update_current_rate_control_h264(struct d3d12_video_encoder
|
|||
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_QUALITY_VARIABLE:
|
||||
{
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate =
|
||||
picture->rate_ctrl[0].target_bitrate;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.PeakBitRate =
|
||||
picture->rate_ctrl[0].peak_bitrate;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.ConstantQualityTarget =
|
||||
picture->rate_ctrl[0].vbr_quality_factor;
|
||||
#else
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.TargetAvgBitRate =
|
||||
picture->rate_ctrl[0].target_bitrate;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.PeakBitRate =
|
||||
picture->rate_ctrl[0].peak_bitrate;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.ConstantQualityTarget =
|
||||
picture->rate_ctrl[0].vbr_quality_factor;
|
||||
#endif
|
||||
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
|
||||
debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE environment variable is set, "
|
||||
", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n", pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate);
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENDED_QVBR1_SUPPORT;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.VBVCapacity =
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.InitialVBVFullness =
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate;
|
||||
} else if (picture->rate_ctrl[0].app_requested_hrd_buffer) {
|
||||
debug_printf("[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 HRD required by app,"
|
||||
" setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n", picture->rate_ctrl[0].vbv_buffer_size, picture->rate_ctrl[0].vbv_buf_initial_size);
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENDED_QVBR1_SUPPORT;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.VBVCapacity =
|
||||
picture->rate_ctrl[0].vbv_buffer_size;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.InitialVBVFullness =
|
||||
picture->rate_ctrl[0].vbv_buf_initial_size;
|
||||
}
|
||||
#endif
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
if (picture->rate_ctrl[0].max_au_size > 0) {
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.MaxFrameBitSize =
|
||||
picture->rate_ctrl[0].max_au_size;
|
||||
|
||||
debug_printf(
|
||||
"[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 "
|
||||
"Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.MaxFrameBitSize);
|
||||
}
|
||||
|
||||
if (picture->rate_ctrl[0].app_requested_qp_range) {
|
||||
debug_printf(
|
||||
"[d3d12_video_encoder_h264] d3d12_video_encoder_update_current_rate_control_h264 "
|
||||
"Upper layer requested explicit MinQP: %d MaxQP: %d\n",
|
||||
picture->rate_ctrl[0].min_qp, picture->rate_ctrl[0].max_qp);
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.MinQP =
|
||||
picture->rate_ctrl[0].min_qp;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.MaxQP =
|
||||
picture->rate_ctrl[0].max_qp;
|
||||
}
|
||||
#else
|
||||
if (picture->rate_ctrl[0].max_au_size > 0) {
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.MaxFrameBitSize =
|
||||
|
|
@ -132,7 +192,7 @@ d3d12_video_encoder_update_current_rate_control_h264(struct d3d12_video_encoder
|
|||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.MaxQP =
|
||||
picture->rate_ctrl[0].max_qp;
|
||||
}
|
||||
|
||||
#endif
|
||||
} break;
|
||||
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP:
|
||||
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT:
|
||||
|
|
@ -807,13 +867,13 @@ d3d12_video_encoder_update_current_encoder_config_state_h264(struct d3d12_video_
|
|||
|
||||
// Will call for d3d12 driver support based on the initial requested features, then
|
||||
// try to fallback if any of them is not supported and return the negotiated d3d12 settings
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT capEncoderSupportData = {};
|
||||
if (!d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(pD3D12Enc, capEncoderSupportData)) {
|
||||
debug_printf("[d3d12_video_encoder_h264] After negotiating caps, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT "
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 capEncoderSupportData1 = {};
|
||||
if (!d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(pD3D12Enc, capEncoderSupportData1)) {
|
||||
debug_printf("[d3d12_video_encoder_h264] After negotiating caps, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1 "
|
||||
"arguments are not supported - "
|
||||
"ValidationFlags: 0x%x - SupportFlags: 0x%x\n",
|
||||
capEncoderSupportData.ValidationFlags,
|
||||
capEncoderSupportData.SupportFlags);
|
||||
capEncoderSupportData1.ValidationFlags,
|
||||
capEncoderSupportData1.SupportFlags);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -894,6 +954,12 @@ d3d12_video_encoder_convert_codec_to_d3d12_enc_codec(enum pipe_video_profile pro
|
|||
{
|
||||
return D3D12_VIDEO_ENCODER_CODEC_HEVC;
|
||||
} break;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
case PIPE_VIDEO_FORMAT_AV1:
|
||||
{
|
||||
return D3D12_VIDEO_ENCODER_CODEC_AV1;
|
||||
} break;
|
||||
#endif
|
||||
case PIPE_VIDEO_FORMAT_MPEG12:
|
||||
case PIPE_VIDEO_FORMAT_MPEG4:
|
||||
case PIPE_VIDEO_FORMAT_VC1:
|
||||
|
|
|
|||
|
|
@ -101,13 +101,72 @@ d3d12_video_encoder_update_current_rate_control_hevc(struct d3d12_video_encoder
|
|||
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_QUALITY_VARIABLE:
|
||||
{
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_QVBR;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate =
|
||||
picture->rc.target_bitrate;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.PeakBitRate =
|
||||
picture->rc.peak_bitrate;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.ConstantQualityTarget =
|
||||
picture->rc.vbr_quality_factor;
|
||||
#else
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.TargetAvgBitRate =
|
||||
picture->rc.target_bitrate;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.PeakBitRate =
|
||||
picture->rc.peak_bitrate;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.ConstantQualityTarget =
|
||||
picture->rc.vbr_quality_factor;
|
||||
#endif
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
if (D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE) {
|
||||
debug_printf("[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc D3D12_VIDEO_ENC_CBR_FORCE_VBV_EQUAL_BITRATE environment variable is set, "
|
||||
", forcing VBV Size = VBV Initial Capacity = Target Bitrate = %" PRIu64 " (bits)\n", pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate);
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENDED_QVBR1_SUPPORT;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.VBVCapacity =
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.InitialVBVFullness =
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.TargetAvgBitRate;
|
||||
} else if (picture->rc.app_requested_hrd_buffer) {
|
||||
debug_printf("[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc HRD required by app,"
|
||||
" setting VBV Size = %d (bits) - VBV Initial Capacity %d (bits)\n", picture->rc.vbv_buffer_size, picture->rc.vbv_buf_initial_size);
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_VBV_SIZES;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_EXTENDED_QVBR1_SUPPORT;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.VBVCapacity =
|
||||
picture->rc.vbv_buffer_size;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.InitialVBVFullness =
|
||||
picture->rc.vbv_buf_initial_size;
|
||||
}
|
||||
#endif
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
if (picture->rc.max_au_size > 0) {
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.MaxFrameBitSize =
|
||||
picture->rc.max_au_size;
|
||||
|
||||
debug_printf(
|
||||
"[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc "
|
||||
"Upper layer requested explicit MaxFrameBitSize: %" PRIu64 "\n",
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.MaxFrameBitSize);
|
||||
}
|
||||
|
||||
if (picture->rc.app_requested_qp_range) {
|
||||
debug_printf(
|
||||
"[d3d12_video_encoder_hevc] d3d12_video_encoder_update_current_rate_control_hevc "
|
||||
"Upper layer requested explicit MinQP: %d MaxQP: %d\n",
|
||||
picture->rc.min_qp, picture->rc.max_qp);
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_QP_RANGE;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.MinQP =
|
||||
picture->rc.min_qp;
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR1.MaxQP =
|
||||
picture->rc.max_qp;
|
||||
}
|
||||
#else
|
||||
if (picture->rc.max_au_size > 0) {
|
||||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Flags |=
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_FLAG_ENABLE_MAX_FRAME_SIZE;
|
||||
|
|
@ -132,7 +191,7 @@ d3d12_video_encoder_update_current_rate_control_hevc(struct d3d12_video_encoder
|
|||
pD3D12Enc->m_currentEncodeConfig.m_encoderRateControlDesc.m_Config.m_Configuration_QVBR.MaxQP =
|
||||
picture->rc.max_qp;
|
||||
}
|
||||
|
||||
#endif
|
||||
} break;
|
||||
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT_SKIP:
|
||||
case PIPE_H2645_ENC_RATE_CONTROL_METHOD_CONSTANT:
|
||||
|
|
@ -723,13 +782,13 @@ d3d12_video_encoder_update_current_encoder_config_state_hevc(struct d3d12_video_
|
|||
|
||||
// Will call for d3d12 driver support based on the initial requested features, then
|
||||
// try to fallback if any of them is not supported and return the negotiated d3d12 settings
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT capEncoderSupportData = {};
|
||||
if (!d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(pD3D12Enc, capEncoderSupportData)) {
|
||||
debug_printf("[d3d12_video_encoder_hevc] After negotiating caps, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT "
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 capEncoderSupportData1 = {};
|
||||
if (!d3d12_video_encoder_negotiate_requested_features_and_d3d12_driver_caps(pD3D12Enc, capEncoderSupportData1)) {
|
||||
debug_printf("[d3d12_video_encoder_hevc] After negotiating caps, D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1 "
|
||||
"arguments are not supported - "
|
||||
"ValidationFlags: 0x%x - SupportFlags: 0x%x\n",
|
||||
capEncoderSupportData.ValidationFlags,
|
||||
capEncoderSupportData.SupportFlags);
|
||||
capEncoderSupportData1.ValidationFlags,
|
||||
capEncoderSupportData1.SupportFlags);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,22 +26,22 @@
|
|||
|
||||
d3d12_video_encoder_bitstream::d3d12_video_encoder_bitstream()
|
||||
{
|
||||
m_pBitsBuffer = nullptr;
|
||||
m_uiBitsBufferSize = 0;
|
||||
m_uiOffset = 0;
|
||||
m_iBitsToGo = 32;
|
||||
m_uintEncBuffer = 0;
|
||||
m_bExternalBuffer = false;
|
||||
m_bBufferOverflow = false;
|
||||
m_pBitsBuffer = nullptr;
|
||||
m_uiBitsBufferSize = 0;
|
||||
m_uiOffset = 0;
|
||||
m_iBitsToGo = 32;
|
||||
m_uintEncBuffer = 0;
|
||||
m_bExternalBuffer = false;
|
||||
m_bBufferOverflow = false;
|
||||
m_bPreventStartCode = false;
|
||||
m_bAllowReallocate = false;
|
||||
m_bAllowReallocate = false;
|
||||
}
|
||||
|
||||
d3d12_video_encoder_bitstream::~d3d12_video_encoder_bitstream()
|
||||
{
|
||||
if (!m_bExternalBuffer) {
|
||||
if (m_pBitsBuffer) {
|
||||
delete[](m_pBitsBuffer);
|
||||
delete[] (m_pBitsBuffer);
|
||||
(m_pBitsBuffer) = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -91,13 +91,13 @@ d3d12_video_encoder_bitstream::exp_Golomb_se(int32_t iVal)
|
|||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_bitstream::setup_bitstream(uint32_t uiInitBufferSize, uint8_t *pBuffer)
|
||||
d3d12_video_encoder_bitstream::setup_bitstream(uint32_t uiInitBufferSize, uint8_t *pBuffer, size_t initial_byte_offset)
|
||||
{
|
||||
m_pBitsBuffer = pBuffer;
|
||||
m_pBitsBuffer = pBuffer;
|
||||
m_uiBitsBufferSize = uiInitBufferSize;
|
||||
m_uiOffset = 0;
|
||||
memset(m_pBitsBuffer, 0, m_uiBitsBufferSize);
|
||||
m_bExternalBuffer = true;
|
||||
m_uiOffset = initial_byte_offset;
|
||||
memset(m_pBitsBuffer + initial_byte_offset, 0, m_uiBitsBufferSize - initial_byte_offset);
|
||||
m_bExternalBuffer = true;
|
||||
m_bAllowReallocate = false;
|
||||
}
|
||||
|
||||
|
|
@ -113,7 +113,7 @@ d3d12_video_encoder_bitstream::create_bitstream(uint32_t uiInitBufferSize)
|
|||
}
|
||||
|
||||
m_uiBitsBufferSize = uiInitBufferSize;
|
||||
m_uiOffset = 0;
|
||||
m_uiOffset = 0;
|
||||
memset(m_pBitsBuffer, 0, m_uiBitsBufferSize);
|
||||
m_bExternalBuffer = false;
|
||||
|
||||
|
|
@ -124,7 +124,7 @@ bool
|
|||
d3d12_video_encoder_bitstream::reallocate_buffer()
|
||||
{
|
||||
uint32_t uiBufferSize = m_uiBitsBufferSize * 3 / 2;
|
||||
uint8_t *pNewBuffer = (uint8_t *) new uint8_t[uiBufferSize];
|
||||
uint8_t *pNewBuffer = (uint8_t *) new uint8_t[uiBufferSize];
|
||||
|
||||
if (nullptr == pNewBuffer) {
|
||||
return false;
|
||||
|
|
@ -132,10 +132,10 @@ d3d12_video_encoder_bitstream::reallocate_buffer()
|
|||
|
||||
memcpy(pNewBuffer, m_pBitsBuffer, m_uiOffset * sizeof(uint8_t));
|
||||
if (m_pBitsBuffer) {
|
||||
delete[](m_pBitsBuffer);
|
||||
delete[] (m_pBitsBuffer);
|
||||
(m_pBitsBuffer) = NULL;
|
||||
}
|
||||
m_pBitsBuffer = pNewBuffer;
|
||||
m_pBitsBuffer = pNewBuffer;
|
||||
m_uiBitsBufferSize = uiBufferSize;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -168,17 +168,17 @@ void
|
|||
d3d12_video_encoder_bitstream::get_current_buffer_position_and_size(uint8_t **ppCurrBufPos, int32_t *pdwLeftBufSize)
|
||||
{
|
||||
assert(32 == m_iBitsToGo && m_uiOffset < m_uiBitsBufferSize);
|
||||
*ppCurrBufPos = m_pBitsBuffer + m_uiOffset;
|
||||
*ppCurrBufPos = m_pBitsBuffer + m_uiOffset;
|
||||
*pdwLeftBufSize = m_uiBitsBufferSize - m_uiOffset;
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_bitstream::attach(uint8_t *pBitsBuffer, uint32_t uiBufferSize)
|
||||
{
|
||||
m_pBitsBuffer = pBitsBuffer;
|
||||
m_pBitsBuffer = pBitsBuffer;
|
||||
m_uiBitsBufferSize = uiBufferSize;
|
||||
m_bExternalBuffer = true;
|
||||
m_bBufferOverflow = false;
|
||||
m_bExternalBuffer = true;
|
||||
m_bBufferOverflow = false;
|
||||
m_bAllowReallocate = false;
|
||||
|
||||
clear();
|
||||
|
|
@ -187,7 +187,7 @@ d3d12_video_encoder_bitstream::attach(uint8_t *pBitsBuffer, uint32_t uiBufferSiz
|
|||
void
|
||||
d3d12_video_encoder_bitstream::write_byte_start_code_prevention(uint8_t u8Val)
|
||||
{
|
||||
int32_t iOffset = m_uiOffset;
|
||||
int32_t iOffset = m_uiOffset;
|
||||
uint8_t *pBuffer = m_pBitsBuffer + iOffset;
|
||||
|
||||
if (m_bPreventStartCode && iOffset > 1) {
|
||||
|
|
@ -208,6 +208,7 @@ d3d12_video_encoder_bitstream::write_byte_start_code_prevention(uint8_t u8Val)
|
|||
void
|
||||
d3d12_video_encoder_bitstream::put_bits(int32_t uiBitsCount, uint32_t iBitsVal)
|
||||
{
|
||||
assert(uiBitsCount > 0);
|
||||
assert(uiBitsCount <= 32);
|
||||
|
||||
if (uiBitsCount < m_iBitsToGo) {
|
||||
|
|
@ -224,7 +225,7 @@ d3d12_video_encoder_bitstream::put_bits(int32_t uiBitsCount, uint32_t iBitsVal)
|
|||
WRITE_BYTE(*temp);
|
||||
|
||||
m_uintEncBuffer = 0;
|
||||
m_iBitsToGo = 32 - iLeftOverBits;
|
||||
m_iBitsToGo = 32 - iLeftOverBits;
|
||||
|
||||
if (iLeftOverBits > 0) {
|
||||
m_uintEncBuffer = (iBitsVal << (32 - iLeftOverBits));
|
||||
|
|
@ -238,19 +239,19 @@ d3d12_video_encoder_bitstream::flush()
|
|||
ASSERTED bool isAligned = is_byte_aligned(); // causes side-effects in object state, don't put inside assert()
|
||||
assert(isAligned);
|
||||
|
||||
uint32_t temp = (uint32_t)(32 - m_iBitsToGo);
|
||||
uint32_t temp = (uint32_t) (32 - m_iBitsToGo);
|
||||
|
||||
if (!verify_buffer(temp >> 3)) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (temp > 0) {
|
||||
WRITE_BYTE((uint8_t)(m_uintEncBuffer >> 24));
|
||||
WRITE_BYTE((uint8_t) (m_uintEncBuffer >> 24));
|
||||
m_uintEncBuffer <<= 8;
|
||||
temp -= 8;
|
||||
}
|
||||
|
||||
m_iBitsToGo = 32;
|
||||
m_iBitsToGo = 32;
|
||||
m_uintEncBuffer = 0;
|
||||
}
|
||||
|
||||
|
|
@ -264,8 +265,8 @@ d3d12_video_encoder_bitstream::append_byte_stream(d3d12_video_encoder_bitstream
|
|||
assert(isThisAligned);
|
||||
assert(m_iBitsToGo == 32);
|
||||
|
||||
uint8_t *pDst = m_pBitsBuffer + m_uiOffset;
|
||||
uint8_t *pSrc = pStream->get_bitstream_buffer();
|
||||
uint8_t *pDst = m_pBitsBuffer + m_uiOffset;
|
||||
uint8_t *pSrc = pStream->get_bitstream_buffer();
|
||||
uint32_t uiLen = (uint32_t) pStream->get_byte_count();
|
||||
|
||||
if (!verify_buffer(uiLen)) {
|
||||
|
|
@ -275,3 +276,84 @@ d3d12_video_encoder_bitstream::append_byte_stream(d3d12_video_encoder_bitstream
|
|||
memcpy(pDst, pSrc, uiLen);
|
||||
m_uiOffset += uiLen;
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_bitstream::put_aligning_bits()
|
||||
{
|
||||
int32_t iLeft = get_num_bits_for_byte_align();
|
||||
if (iLeft)
|
||||
put_bits(iLeft, 0); // trailing_zero_bit
|
||||
|
||||
ASSERTED bool isAligned = is_byte_aligned(); // causes side-effects in object state, don't put inside assert()
|
||||
assert(isAligned);
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_bitstream::put_trailing_bits()
|
||||
{
|
||||
// trailing_one_bit shall be equal to 1.
|
||||
// When the syntax element trailing_one_bit is read, it is a requirement that nbBits is greater than zero.
|
||||
put_bits(1, 1); // trailing_one_bit
|
||||
int32_t nbBits = get_num_bits_for_byte_align();
|
||||
while (nbBits > 0) {
|
||||
put_bits(1, 0); // trailing_zero_bit
|
||||
nbBits--;
|
||||
}
|
||||
ASSERTED bool isAligned = is_byte_aligned(); // causes side-effects in object state, don't put inside assert()
|
||||
assert(isAligned);
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_bitstream::put_su_bits(uint16_t uiBitsCount, int32_t iBitsVal)
|
||||
{
|
||||
put_bits(uiBitsCount, calculate_su_bits(uiBitsCount, iBitsVal));
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_bitstream::put_ns_bits(uint16_t uiBitsCount, uint32_t iBitsVal)
|
||||
{
|
||||
if (uiBitsCount > 1) {
|
||||
uint32_t width = 0;
|
||||
uint32_t tmp = uiBitsCount;
|
||||
while (tmp) {
|
||||
tmp = (tmp >> 1);
|
||||
width++;
|
||||
}
|
||||
uint32_t m = (1 << width) - uiBitsCount;
|
||||
if (iBitsVal < m)
|
||||
put_bits(width - 1, iBitsVal);
|
||||
else
|
||||
put_bits(width, iBitsVal + m);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t
|
||||
d3d12_video_encoder_bitstream::calculate_su_bits(uint16_t uiBitsCount, int32_t iBitsVal)
|
||||
{
|
||||
int16_t mask_sign = 1 << (uiBitsCount - 1);
|
||||
if (iBitsVal & mask_sign)
|
||||
iBitsVal = iBitsVal - 2 * mask_sign;
|
||||
return iBitsVal;
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_bitstream::put_le_bytes(size_t uiBytesCount, uint32_t iBitsVal)
|
||||
{
|
||||
assert(uiBytesCount <= sizeof(iBitsVal));
|
||||
for (size_t i = 0; i < uiBytesCount; i++) {
|
||||
put_bits(8, static_cast<uint8_t>(iBitsVal & 0xFF));
|
||||
iBitsVal >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_bitstream::put_leb128_bytes(uint64_t iBitsVal)
|
||||
{
|
||||
do {
|
||||
uint8_t cur_byte = (iBitsVal & 0x7F);
|
||||
iBitsVal >>= 7;
|
||||
if (iBitsVal != 0)
|
||||
cur_byte |= 0x80;
|
||||
put_bits(8, cur_byte);
|
||||
} while (iBitsVal != 0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,17 +36,24 @@ class d3d12_video_encoder_bitstream
|
|||
void get_current_buffer_position_and_size(uint8_t **ppCurrBufPos, int32_t *pdwLeftBufSize);
|
||||
void inc_current_offset(int32_t dwOffset);
|
||||
bool create_bitstream(uint32_t uiInitBufferSize);
|
||||
void setup_bitstream(uint32_t uiInitBufferSize, uint8_t *pBuffer);
|
||||
void setup_bitstream(uint32_t uiInitBufferSize, uint8_t *pBuffer, size_t initial_byte_offset);
|
||||
void attach(uint8_t *pBitsBuffer, uint32_t uiBufferSize);
|
||||
void put_bits(int32_t uiBitsCount, uint32_t iBitsVal);
|
||||
void flush();
|
||||
void exp_Golomb_ue(uint32_t uiVal);
|
||||
void exp_Golomb_se(int32_t iVal);
|
||||
void put_aligning_bits();
|
||||
void put_trailing_bits();
|
||||
void put_su_bits(uint16_t uiBitsCount, int32_t iBitsVal);
|
||||
void put_ns_bits(uint16_t uiBitsCount, uint32_t iBitsVal);
|
||||
uint16_t calculate_su_bits(uint16_t uiBitsCount, int32_t iBitsVal);
|
||||
void put_le_bytes(size_t uiBytesCount, uint32_t iBitsVal);
|
||||
void put_leb128_bytes(uint64_t iBitsVal);
|
||||
|
||||
inline void clear()
|
||||
{
|
||||
m_iBitsToGo = 32;
|
||||
m_uiOffset = 0;
|
||||
m_iBitsToGo = 32;
|
||||
m_uiOffset = 0;
|
||||
m_uintEncBuffer = 0;
|
||||
};
|
||||
|
||||
|
|
@ -90,8 +97,8 @@ class d3d12_video_encoder_bitstream
|
|||
bool m_bAllowReallocate;
|
||||
|
||||
private:
|
||||
void write_byte_start_code_prevention(uint8_t u8Val);
|
||||
bool reallocate_buffer();
|
||||
void write_byte_start_code_prevention(uint8_t u8Val);
|
||||
bool reallocate_buffer();
|
||||
int32_t get_exp_golomb0_code_len(uint32_t uiVal);
|
||||
|
||||
const uint8_t m_iLog_2_N[256] = {
|
||||
|
|
@ -109,9 +116,9 @@ class d3d12_video_encoder_bitstream
|
|||
uint32_t m_uiBitsBufferSize;
|
||||
uint32_t m_uiOffset;
|
||||
|
||||
bool m_bExternalBuffer;
|
||||
bool m_bExternalBuffer;
|
||||
uint32_t m_uintEncBuffer;
|
||||
int32_t m_iBitsToGo;
|
||||
int32_t m_iBitsToGo;
|
||||
|
||||
bool m_bPreventStartCode;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,923 @@
|
|||
/*
|
||||
* Copyright © Microsoft Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "d3d12_video_encoder_bitstream_builder_av1.h"
|
||||
|
||||
void
|
||||
d3d12_video_bitstream_builder_av1::write_obu_header(d3d12_video_encoder_bitstream *pBit,
|
||||
av1_obutype_t obu_type,
|
||||
uint32_t obu_extension_flag,
|
||||
uint32_t temporal_id,
|
||||
uint32_t spatial_id)
|
||||
{
|
||||
pBit->put_bits(1, 0); // obu_forbidden_bit
|
||||
pBit->put_bits(4, obu_type); // type
|
||||
pBit->put_bits(1, obu_extension_flag);
|
||||
pBit->put_bits(1, 1); // obu_has_size_field
|
||||
pBit->put_bits(1, 0); // reserved
|
||||
if (obu_extension_flag) {
|
||||
// obu_extension_header()
|
||||
pBit->put_bits(3, temporal_id);
|
||||
pBit->put_bits(2, spatial_id);
|
||||
pBit->put_bits(3, 0); // extension_header_reserved_3bits
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_bitstream_builder_av1::pack_obu_header_size(d3d12_video_encoder_bitstream *pBit, uint64_t val)
|
||||
{
|
||||
pBit->put_leb128_bytes(val);
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_bitstream_builder_av1::write_seq_data(d3d12_video_encoder_bitstream *pBit, const av1_seq_header_t *pSeqHdr)
|
||||
{
|
||||
pBit->put_bits(3, pSeqHdr->seq_profile);
|
||||
pBit->put_bits(1, 0); // still_picture default 0
|
||||
pBit->put_bits(1, 0); // reduced_still_picture_header
|
||||
pBit->put_bits(1, 0); // timing_info_present_flag
|
||||
pBit->put_bits(1, 0); // initial_display_delay_present_flag
|
||||
|
||||
pBit->put_bits(5, pSeqHdr->operating_points_cnt_minus_1);
|
||||
for (uint8_t i = 0; i <= pSeqHdr->operating_points_cnt_minus_1; i++) {
|
||||
pBit->put_bits(8, pSeqHdr->operating_point_idc[i] >> 4);
|
||||
pBit->put_bits(4, pSeqHdr->operating_point_idc[i] & 0x9f);
|
||||
pBit->put_bits(5, pSeqHdr->seq_level_idx[i]);
|
||||
if (pSeqHdr->seq_level_idx[i] > 7)
|
||||
pBit->put_bits(1, pSeqHdr->seq_tier[i]);
|
||||
}
|
||||
|
||||
pBit->put_bits(4, d3d12_video_bitstream_builder_av1::frame_width_bits_minus_1); // frame_width_bits_minus_1
|
||||
pBit->put_bits(4, d3d12_video_bitstream_builder_av1::frame_height_bits_minus_1); // frame_height_bits_minus_1
|
||||
pBit->put_bits(d3d12_video_bitstream_builder_av1::frame_width_bits_minus_1 + 1,
|
||||
pSeqHdr->max_frame_width - 1); // max_frame_width_minus_1
|
||||
pBit->put_bits(d3d12_video_bitstream_builder_av1::frame_height_bits_minus_1 + 1,
|
||||
pSeqHdr->max_frame_height - 1); // max_frame_height_minus_1
|
||||
pBit->put_bits(1, 0); // frame_id_numbers_present_flag
|
||||
pBit->put_bits(1, pSeqHdr->use_128x128_superblock); // use_128x128_superblock
|
||||
pBit->put_bits(1, pSeqHdr->enable_filter_intra); // enable_filter_intra
|
||||
pBit->put_bits(1, pSeqHdr->enable_intra_edge_filter); // enable_intra_edge_filter
|
||||
pBit->put_bits(1, pSeqHdr->enable_interintra_compound); // enable_interintra_compound
|
||||
pBit->put_bits(1, pSeqHdr->enable_masked_compound); // enable_masked_compound
|
||||
pBit->put_bits(1, pSeqHdr->enable_warped_motion); // enable_warped_motion
|
||||
pBit->put_bits(1, pSeqHdr->enable_dual_filter); // enable_dual_filter
|
||||
pBit->put_bits(1, pSeqHdr->enable_order_hint); // enable_order_hint
|
||||
|
||||
if (pSeqHdr->enable_order_hint) {
|
||||
pBit->put_bits(1, pSeqHdr->enable_jnt_comp); // enable_jnt_comp
|
||||
pBit->put_bits(1, pSeqHdr->enable_ref_frame_mvs); // enable_ref_frame_mvs
|
||||
}
|
||||
|
||||
pBit->put_bits(1, pSeqHdr->seq_choose_screen_content_tools); // seq_choose_screen_content_tools
|
||||
if (!pSeqHdr->seq_choose_screen_content_tools)
|
||||
pBit->put_bits(1, pSeqHdr->seq_force_screen_content_tools); // seq_force_screen_content_tools
|
||||
|
||||
if (pSeqHdr->seq_force_screen_content_tools) {
|
||||
pBit->put_bits(1, pSeqHdr->seq_choose_integer_mv); // seq_choose_integer_mv
|
||||
if (!pSeqHdr->seq_choose_integer_mv)
|
||||
pBit->put_bits(1, pSeqHdr->seq_force_integer_mv); // seq_force_integer_mv
|
||||
}
|
||||
|
||||
if (pSeqHdr->enable_order_hint)
|
||||
pBit->put_bits(3, pSeqHdr->order_hint_bits_minus1);
|
||||
|
||||
pBit->put_bits(1, pSeqHdr->enable_superres); // enable_superres
|
||||
pBit->put_bits(1, pSeqHdr->enable_cdef); // enable_cdef
|
||||
pBit->put_bits(1, pSeqHdr->enable_restoration); // enable_restoration
|
||||
|
||||
// color_config ()
|
||||
pBit->put_bits(1,
|
||||
pSeqHdr->color_config.bit_depth == DXGI_FORMAT_P010 ? 1 : 0); // Assume DXGI_FORMAT_NV12 otherwise
|
||||
if (pSeqHdr->seq_profile != 1)
|
||||
pBit->put_bits(1, 0); // mono_chrome not supported
|
||||
|
||||
pBit->put_bits(1, pSeqHdr->color_config.color_description_present_flag);
|
||||
|
||||
if (pSeqHdr->color_config.color_description_present_flag) {
|
||||
pBit->put_bits(8, pSeqHdr->color_config.color_primaries);
|
||||
pBit->put_bits(8, pSeqHdr->color_config.transfer_characteristics);
|
||||
pBit->put_bits(8, pSeqHdr->color_config.matrix_coefficients);
|
||||
}
|
||||
|
||||
pBit->put_bits(1, pSeqHdr->color_config.color_range); // color_range
|
||||
|
||||
if (pSeqHdr->seq_profile == 0)
|
||||
pBit->put_bits(2, pSeqHdr->color_config.chroma_sample_position); // chroma_sample_position
|
||||
|
||||
pBit->put_bits(1, pSeqHdr->color_config.separate_uv_delta_q); // separate_uv_delta_q
|
||||
|
||||
pBit->put_bits(1, 0); // film_grain_params_present
|
||||
|
||||
pBit->put_trailing_bits();
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_bitstream_builder_av1::write_temporal_delimiter_obu(std::vector<uint8_t> &headerBitstream,
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t &writtenBytes)
|
||||
{
|
||||
auto startByteOffset = std::distance(headerBitstream.begin(), placingPositionStart);
|
||||
if (headerBitstream.size() < (startByteOffset + c_DefaultBitstreamBufSize))
|
||||
headerBitstream.resize(startByteOffset + c_DefaultBitstreamBufSize);
|
||||
|
||||
d3d12_video_encoder_bitstream bitstream_full_obu;
|
||||
bitstream_full_obu.setup_bitstream(headerBitstream.size(), headerBitstream.data(), startByteOffset);
|
||||
|
||||
{
|
||||
// temporal_delimiter_obu() has empty payload as per AV1 codec spec
|
||||
|
||||
// Write the header
|
||||
constexpr uint32_t obu_extension_flag = 0;
|
||||
constexpr uint32_t temporal_id = 0;
|
||||
constexpr uint32_t spatial_id = 0;
|
||||
write_obu_header(&bitstream_full_obu, OBU_TEMPORAL_DELIMITER, obu_extension_flag, temporal_id, spatial_id);
|
||||
|
||||
// Write the data size
|
||||
const size_t obu_size_in_bytes = 0;
|
||||
debug_printf("obu_size: %" PRIu64 " (temporal_delimiter_obu() has empty payload as per AV1 codec spec)\n",
|
||||
obu_size_in_bytes);
|
||||
pack_obu_header_size(&bitstream_full_obu, obu_size_in_bytes);
|
||||
}
|
||||
|
||||
bitstream_full_obu.flush();
|
||||
|
||||
// Shrink headerBitstream to fit
|
||||
writtenBytes = bitstream_full_obu.get_byte_count() - startByteOffset;
|
||||
headerBitstream.resize(writtenBytes + startByteOffset);
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_bitstream_builder_av1::write_sequence_header(const av1_seq_header_t *pSeqHdr,
|
||||
std::vector<uint8_t> &headerBitstream,
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t &writtenBytes)
|
||||
{
|
||||
auto startByteOffset = std::distance(headerBitstream.begin(), placingPositionStart);
|
||||
if (headerBitstream.size() < (startByteOffset + c_DefaultBitstreamBufSize))
|
||||
headerBitstream.resize(startByteOffset + c_DefaultBitstreamBufSize);
|
||||
|
||||
d3d12_video_encoder_bitstream bitstream_full_obu;
|
||||
bitstream_full_obu.setup_bitstream(headerBitstream.size(), headerBitstream.data(), startByteOffset);
|
||||
|
||||
// to handle variable length we first write the content
|
||||
// and later the obu header and concatenate both bitstreams
|
||||
d3d12_video_encoder_bitstream bitstream_seq;
|
||||
bitstream_seq.create_bitstream(c_DefaultBitstreamBufSize);
|
||||
|
||||
{
|
||||
// Write the data
|
||||
write_seq_data(&bitstream_seq, pSeqHdr);
|
||||
bitstream_seq.flush();
|
||||
debug_printf("sequence_header_obu() bytes: %" PRId32 "\n", bitstream_seq.get_byte_count());
|
||||
|
||||
// Write the header
|
||||
constexpr uint32_t obu_extension_flag = 0;
|
||||
constexpr uint32_t temporal_id = 0;
|
||||
constexpr uint32_t spatial_id = 0;
|
||||
write_obu_header(&bitstream_full_obu, OBU_SEQUENCE_HEADER, obu_extension_flag, temporal_id, spatial_id);
|
||||
|
||||
// Write the data size
|
||||
const size_t obu_size_in_bytes = static_cast<size_t>(bitstream_seq.get_byte_count());
|
||||
debug_printf("obu_size: %" PRIu64 "\n", obu_size_in_bytes);
|
||||
pack_obu_header_size(&bitstream_full_obu, obu_size_in_bytes);
|
||||
|
||||
bitstream_full_obu.flush();
|
||||
|
||||
// bitstream_full_obu has external buffer allocation and
|
||||
// append_bitstream deep copies bitstream_seq, so it's okay
|
||||
// for RAII of bitstream_seq to be deallocated out of scope
|
||||
bitstream_full_obu.append_byte_stream(&bitstream_seq);
|
||||
}
|
||||
|
||||
bitstream_full_obu.flush();
|
||||
|
||||
// Shrink headerBitstream to fit
|
||||
writtenBytes = bitstream_full_obu.get_byte_count() - startByteOffset;
|
||||
headerBitstream.resize(writtenBytes + startByteOffset);
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_bitstream_builder_av1::write_frame_size_with_refs(d3d12_video_encoder_bitstream *pBit,
|
||||
const av1_seq_header_t *pSeqHdr,
|
||||
const av1_pic_header_t *pPicHdr)
|
||||
{
|
||||
bool found_ref = false; // Send explicitly as default
|
||||
for (int i = 0; i < 7 /*REFS_PER_FRAME*/; i++) {
|
||||
pBit->put_bits(1, found_ref); // found_ref
|
||||
}
|
||||
|
||||
if (found_ref) {
|
||||
// frame_size()
|
||||
write_frame_size(pBit, pSeqHdr, pPicHdr);
|
||||
// render_size()
|
||||
write_render_size(pBit, pPicHdr);
|
||||
} else {
|
||||
// superres_params()
|
||||
write_superres_params(pBit, pSeqHdr, pPicHdr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_bitstream_builder_av1::write_frame_size(d3d12_video_encoder_bitstream *pBit,
|
||||
const av1_seq_header_t *pSeqHdr,
|
||||
const av1_pic_header_t *pPicHdr)
|
||||
{
|
||||
if (pPicHdr->frame_size_override_flag) {
|
||||
pBit->put_bits(d3d12_video_bitstream_builder_av1::frame_width_bits_minus_1 + 1,
|
||||
pPicHdr->FrameWidth - 1); // frame_width_minus_1
|
||||
pBit->put_bits(d3d12_video_bitstream_builder_av1::frame_height_bits_minus_1 + 1,
|
||||
pPicHdr->FrameHeight - 1); // frame_height_minus_1
|
||||
}
|
||||
// superres_params()
|
||||
write_superres_params(pBit, pSeqHdr, pPicHdr);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
d3d12_video_bitstream_builder_av1::write_superres_params(d3d12_video_encoder_bitstream *pBit,
|
||||
const av1_seq_header_t *pSeqHdr,
|
||||
const av1_pic_header_t *pPicHdr)
|
||||
{
|
||||
if (pSeqHdr->enable_superres)
|
||||
pBit->put_bits(1, pPicHdr->use_superres); // use_superres
|
||||
|
||||
constexpr unsigned SUPERRES_DENOM_BITS = 3; // As per AV1 codec spec
|
||||
if (pPicHdr->use_superres) {
|
||||
constexpr uint32_t SUPERRES_DENOM_MIN = 9; // As per AV1 codec spec
|
||||
assert(pPicHdr->SuperresDenom >= SUPERRES_DENOM_MIN);
|
||||
uint32_t coded_denom = pPicHdr->SuperresDenom - SUPERRES_DENOM_MIN;
|
||||
pBit->put_bits(SUPERRES_DENOM_BITS, coded_denom);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_bitstream_builder_av1::write_render_size(d3d12_video_encoder_bitstream *pBit,
|
||||
const av1_pic_header_t *pPicHdr)
|
||||
{
|
||||
uint8_t render_and_frame_size_different =
|
||||
((pPicHdr->RenderWidth != pPicHdr->FrameWidth) || (pPicHdr->RenderHeight != pPicHdr->FrameHeight)) ? 1 : 0;
|
||||
|
||||
pBit->put_bits(1, render_and_frame_size_different); // render_and_frame_size_different
|
||||
|
||||
if (render_and_frame_size_different == 1) {
|
||||
pBit->put_bits(16, pPicHdr->RenderWidth - 1); // render_width_minus_1
|
||||
pBit->put_bits(16, pPicHdr->RenderHeight - 1); // render_height_minus_1
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_bitstream_builder_av1::write_delta_q_value(d3d12_video_encoder_bitstream *pBit, int32_t delta_q_val)
|
||||
{
|
||||
if (delta_q_val) {
|
||||
pBit->put_bits(1, 1);
|
||||
pBit->put_su_bits(7, delta_q_val);
|
||||
} else {
|
||||
pBit->put_bits(1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
inline int
|
||||
get_relative_dist(int a, int b, int OrderHintBits, uint8_t enable_order_hint)
|
||||
{
|
||||
if (!enable_order_hint)
|
||||
return 0;
|
||||
int diff = a - b;
|
||||
int m = 1 << (OrderHintBits - 1);
|
||||
diff = (diff & (m - 1)) - (diff & m);
|
||||
return diff;
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_bitstream_builder_av1::write_pic_data(d3d12_video_encoder_bitstream *pBit,
|
||||
const av1_seq_header_t *pSeqHdr,
|
||||
const av1_pic_header_t *pPicHdr)
|
||||
{
|
||||
// uncompressed_header()
|
||||
|
||||
pBit->put_bits(1, pPicHdr->show_existing_frame);
|
||||
|
||||
if (pPicHdr->show_existing_frame) {
|
||||
pBit->put_bits(3, pPicHdr->frame_to_show_map_idx); // frame_to_show_map_idx f(3)
|
||||
|
||||
// decoder_model_info_present_flag Default 0
|
||||
// if ( decoder_model_info_present_flag && !equal_picture_interval ) {
|
||||
// temporal_point_info( )
|
||||
// }
|
||||
|
||||
// frame_id_numbers_present_flag default 0
|
||||
// if ( frame_id_numbers_present_flag ) {
|
||||
// display_frame_id f(idLen)
|
||||
// }
|
||||
} else {
|
||||
|
||||
const uint8_t FrameIsIntra = (pPicHdr->frame_type == D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTRA_ONLY_FRAME ||
|
||||
pPicHdr->frame_type == D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME);
|
||||
pBit->put_bits(2, pPicHdr->frame_type); // frame_type
|
||||
|
||||
pBit->put_bits(1, pPicHdr->show_frame); // show_frame
|
||||
if (!pPicHdr->show_frame)
|
||||
pBit->put_bits(1, pPicHdr->showable_frame); // showable_frame
|
||||
|
||||
|
||||
if (pPicHdr->frame_type == D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_SWITCH_FRAME ||
|
||||
(pPicHdr->frame_type == D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME && pPicHdr->show_frame)) {
|
||||
assert(pPicHdr->error_resilient_mode == 1);
|
||||
} else {
|
||||
pBit->put_bits(1, pPicHdr->error_resilient_mode); // error_resilient_mode
|
||||
}
|
||||
|
||||
pBit->put_bits(1, pPicHdr->disable_cdf_update); // disable_cdf_update
|
||||
if (pSeqHdr->seq_force_screen_content_tools == /*SELECT_SCREEN_CONTENT_TOOLS */ 2)
|
||||
pBit->put_bits(1, pPicHdr->allow_screen_content_tools); // allow_screen_content_tools
|
||||
|
||||
if (pPicHdr->allow_screen_content_tools && (pSeqHdr->seq_force_integer_mv == /*SELECT_INTEGER_MV */ 2))
|
||||
pBit->put_bits(1, pPicHdr->force_integer_mv); // force_integer_mv
|
||||
|
||||
// reduced_still_picture_header default 0 and frame_type != SWITCH
|
||||
if (pPicHdr->frame_type != D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_SWITCH_FRAME) {
|
||||
// Expicitly coded if NOT SWITCH FRAME
|
||||
pBit->put_bits(1, pPicHdr->frame_size_override_flag); // frame_size_override_flag
|
||||
} else {
|
||||
assert(pPicHdr->frame_size_override_flag ==
|
||||
1); // As per AV1 spec for SWITCH FRAME it's not coded but defaulted to 1 instead
|
||||
}
|
||||
|
||||
pBit->put_bits(pSeqHdr->order_hint_bits_minus1 + 1, pPicHdr->order_hint); // order_hint
|
||||
|
||||
if (!(FrameIsIntra || pPicHdr->error_resilient_mode))
|
||||
pBit->put_bits(3, pPicHdr->primary_ref_frame); // primary_ref_frame
|
||||
|
||||
// decoder_model_info_present_flag Default 0
|
||||
|
||||
if (!(pPicHdr->frame_type == D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_SWITCH_FRAME ||
|
||||
(pPicHdr->frame_type == D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME && pPicHdr->show_frame)))
|
||||
pBit->put_bits(8 /* NUM_REF_FRAMES from AV1 spec */, pPicHdr->refresh_frame_flags);
|
||||
|
||||
constexpr uint32_t allFrames = (1 << 8 /* NUM_REF_FRAMES from AV1 spec */) - 1;
|
||||
if (!FrameIsIntra || pPicHdr->refresh_frame_flags != allFrames) {
|
||||
|
||||
if (pPicHdr->error_resilient_mode && pSeqHdr->enable_order_hint) {
|
||||
for (uint8_t i = 0; i < 8 /* NUM_REF_FRAMES from AV1 spec */; i++) {
|
||||
pBit->put_bits(pSeqHdr->order_hint_bits_minus1 + 1,
|
||||
pPicHdr->ref_order_hint[i]); // ref_order_hint[i] f(OrderHintBits)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (FrameIsIntra) {
|
||||
// frame_size()
|
||||
write_frame_size(pBit, pSeqHdr, pPicHdr);
|
||||
// render_size()
|
||||
write_render_size(pBit, pPicHdr);
|
||||
|
||||
if (pPicHdr->allow_screen_content_tools && pPicHdr->UpscaledWidth == pPicHdr->FrameWidth)
|
||||
pBit->put_bits(1, pPicHdr->allow_intrabc);
|
||||
} else {
|
||||
if (pSeqHdr->enable_order_hint)
|
||||
pBit->put_bits(1, 0); // frame_refs_short_signaling default 0
|
||||
|
||||
for (uint8_t ref = 0; ref < ARRAY_SIZE(pPicHdr->ref_frame_idx); ref++)
|
||||
pBit->put_bits(3 /* log2 of NUM_REF_FRAMES from AV1 spec */, pPicHdr->ref_frame_idx[ref]);
|
||||
|
||||
// frame_id_numbers_present_flag default 0
|
||||
|
||||
if (pPicHdr->frame_size_override_flag && !pPicHdr->error_resilient_mode) {
|
||||
// frame_size_with_refs()
|
||||
write_frame_size_with_refs(pBit, pSeqHdr, pPicHdr);
|
||||
} else {
|
||||
// frame_size()
|
||||
write_frame_size(pBit, pSeqHdr, pPicHdr);
|
||||
// render_size()
|
||||
write_render_size(pBit, pPicHdr);
|
||||
}
|
||||
|
||||
if (!pPicHdr->force_integer_mv)
|
||||
pBit->put_bits(1, pPicHdr->allow_high_precision_mv); // allow_high_precision_mv
|
||||
|
||||
// read_interpolation_filter()
|
||||
{
|
||||
const uint8_t is_filter_switchable =
|
||||
(pPicHdr->interpolation_filter == D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_SWITCHABLE ? 1 : 0);
|
||||
pBit->put_bits(1, is_filter_switchable); // is_filter_switchable
|
||||
if (!is_filter_switchable) {
|
||||
pBit->put_bits(2, pPicHdr->interpolation_filter); // interpolation_filter
|
||||
}
|
||||
}
|
||||
|
||||
pBit->put_bits(1, pPicHdr->is_motion_mode_switchable); // is_motion_mode_switchable
|
||||
|
||||
if (!(pPicHdr->error_resilient_mode || !pPicHdr->use_ref_frame_mvs))
|
||||
pBit->put_bits(1, 1); // use_ref_frame_mvs
|
||||
}
|
||||
|
||||
if (!pPicHdr->disable_cdf_update /* || reduced_still_picture_header default 0 */)
|
||||
pBit->put_bits(1, pPicHdr->disable_frame_end_update_cdf); // disable_frame_end_update_cdf
|
||||
|
||||
// tile_info()
|
||||
{
|
||||
unsigned maxTileWidthSb = pPicHdr->tile_info.tile_support_caps.MaxTileWidth;
|
||||
unsigned maxTileAreaSb = pPicHdr->tile_info.tile_support_caps.MaxTileArea;
|
||||
|
||||
unsigned minLog2TileCols = log2(pPicHdr->tile_info.tile_support_caps.MinTileCols);
|
||||
unsigned maxLog2TileCols = log2(pPicHdr->tile_info.tile_support_caps.MaxTileCols);
|
||||
unsigned log2TileCols = log2(pPicHdr->tile_info.tile_partition.ColCount);
|
||||
|
||||
unsigned minLog2TileRows = log2(pPicHdr->tile_info.tile_support_caps.MinTileRows);
|
||||
unsigned maxLog2TileRows = log2(pPicHdr->tile_info.tile_support_caps.MaxTileRows);
|
||||
unsigned log2TileRows = log2(pPicHdr->tile_info.tile_partition.RowCount);
|
||||
|
||||
pBit->put_bits(1, pPicHdr->tile_info.uniform_tile_spacing_flag); // uniform_tile_spacing_flag
|
||||
|
||||
if (pPicHdr->tile_info.uniform_tile_spacing_flag) {
|
||||
for (unsigned i = minLog2TileCols; i < log2TileCols; i++)
|
||||
pBit->put_bits(1, 1); // one increment_tile_cols_log2
|
||||
if (log2TileCols < maxLog2TileCols)
|
||||
pBit->put_bits(1, 0); // zero increment_tile_cols_log2
|
||||
for (unsigned i = minLog2TileRows; i < log2TileRows; i++)
|
||||
pBit->put_bits(1, 1); // increment_tile_rows_log2
|
||||
if (log2TileRows < maxLog2TileRows)
|
||||
pBit->put_bits(1, 0); // increment_tile_rows_log2
|
||||
} else {
|
||||
unsigned sizeSb = 0;
|
||||
unsigned widestTileSb = 0;
|
||||
unsigned widthSb = pPicHdr->frame_width_sb;
|
||||
for (unsigned i = 0; i < pPicHdr->tile_info.tile_partition.ColCount; i++) {
|
||||
sizeSb = pPicHdr->tile_info.tile_partition.ColWidths[i];
|
||||
unsigned maxWidth = std::min(widthSb, maxTileWidthSb);
|
||||
pBit->put_ns_bits(maxWidth, sizeSb - 1); // width_in_sbs_minus_1
|
||||
widestTileSb = std::max(sizeSb, widestTileSb);
|
||||
widthSb -= sizeSb;
|
||||
}
|
||||
|
||||
unsigned maxTileHeightSb = std::max(maxTileAreaSb / widestTileSb, 1u);
|
||||
unsigned heightSb = pPicHdr->frame_height_sb;
|
||||
for (unsigned i = 0; i < pPicHdr->tile_info.tile_partition.RowCount; i++) {
|
||||
sizeSb = pPicHdr->tile_info.tile_partition.RowHeights[i];
|
||||
unsigned maxHeight = std::min(heightSb, maxTileHeightSb);
|
||||
pBit->put_ns_bits(maxHeight, sizeSb - 1); // height_in_sbs_minus_1
|
||||
heightSb -= sizeSb;
|
||||
}
|
||||
}
|
||||
|
||||
if (log2TileCols > 0 || log2TileRows > 0) {
|
||||
pBit->put_bits(log2TileRows + log2TileCols,
|
||||
pPicHdr->tile_info.tile_partition.ContextUpdateTileId); // f(TileRowsLog2 + TileColsLog2)
|
||||
pBit->put_bits(2, pPicHdr->tile_info.tile_support_caps.TileSizeBytesMinus1); // tile_size_bytes_minus_1
|
||||
// f(2)
|
||||
}
|
||||
}
|
||||
|
||||
// quantization_params()
|
||||
{
|
||||
pBit->put_bits(8, pPicHdr->quantization_params.BaseQIndex); // base_q_idx
|
||||
write_delta_q_value(pBit, pPicHdr->quantization_params.YDCDeltaQ);
|
||||
|
||||
bool diff_uv_delta = false;
|
||||
if (pPicHdr->quantization_params.UDCDeltaQ != pPicHdr->quantization_params.VDCDeltaQ ||
|
||||
pPicHdr->quantization_params.UACDeltaQ != pPicHdr->quantization_params.VACDeltaQ)
|
||||
diff_uv_delta = true;
|
||||
|
||||
if (diff_uv_delta)
|
||||
assert(pSeqHdr->color_config.separate_uv_delta_q == 1);
|
||||
|
||||
if (pSeqHdr->color_config.separate_uv_delta_q)
|
||||
pBit->put_bits(1, diff_uv_delta);
|
||||
|
||||
write_delta_q_value(pBit, pPicHdr->quantization_params.UDCDeltaQ);
|
||||
write_delta_q_value(pBit, pPicHdr->quantization_params.UACDeltaQ);
|
||||
|
||||
if (diff_uv_delta) {
|
||||
write_delta_q_value(pBit, pPicHdr->quantization_params.VDCDeltaQ);
|
||||
write_delta_q_value(pBit, pPicHdr->quantization_params.VACDeltaQ);
|
||||
}
|
||||
|
||||
pBit->put_bits(1, pPicHdr->quantization_params.UsingQMatrix); // using_qmatrix
|
||||
if (pPicHdr->quantization_params.UsingQMatrix) {
|
||||
pBit->put_bits(4, pPicHdr->quantization_params.QMY); // qm_y
|
||||
pBit->put_bits(4, pPicHdr->quantization_params.QMU); // qm_u
|
||||
if (pSeqHdr->color_config.separate_uv_delta_q)
|
||||
pBit->put_bits(4, pPicHdr->quantization_params.QMV); // qm_v
|
||||
}
|
||||
}
|
||||
|
||||
// segmentation_params()
|
||||
{
|
||||
pBit->put_bits(1, pPicHdr->segmentation_enabled); // segmentation_enabled
|
||||
if (pPicHdr->segmentation_enabled) {
|
||||
if (pPicHdr->primary_ref_frame != 7 /*PRIMARY_REF_NONE*/) {
|
||||
pBit->put_bits(1, pPicHdr->segmentation_config.UpdateMap); // segmentation_update_map f(1)
|
||||
if (pPicHdr->segmentation_config.UpdateMap == 1)
|
||||
pBit->put_bits(1, pPicHdr->segmentation_config.TemporalUpdate); // segmentation_temporal_update f(1)
|
||||
pBit->put_bits(1, pPicHdr->segmentation_config.UpdateData); // segmentation_update_data f(1)
|
||||
}
|
||||
|
||||
if (pPicHdr->segmentation_config.UpdateData == 1) {
|
||||
const int av1_segmentation_feature_bits[8 /*SEG_LVL_MAX*/] = { 8, 6, 6, 6, 6, 3, 0, 0 };
|
||||
const int av1_segmentation_feature_signed[8 /*SEG_LVL_MAX*/] = { 1, 1, 1, 1, 1, 0, 0, 0 };
|
||||
|
||||
for (int i = 0; i < 8 /*MAX_SEGMENTS*/; i++) {
|
||||
for (int j = 0; j < 8 /*SEG_LVL_MAX*/; j++) {
|
||||
bool feature_enabled =
|
||||
((static_cast<UINT>(1 << j) & static_cast<UINT>(pPicHdr->segmentation_config.SegmentsData[i].EnabledFeatures)) != 0);
|
||||
pBit->put_bits(1, feature_enabled ? 1 : 0); // feature_enabled f(1)
|
||||
|
||||
if (feature_enabled) {
|
||||
int bitsToRead = av1_segmentation_feature_bits[j];
|
||||
if (av1_segmentation_feature_signed[j] == 1) {
|
||||
pBit->put_su_bits(
|
||||
1 + bitsToRead,
|
||||
pPicHdr->segmentation_config.SegmentsData[i].FeatureValue[j]); // su(1+bitsToRead)
|
||||
} else {
|
||||
pBit->put_bits(
|
||||
bitsToRead,
|
||||
pPicHdr->segmentation_config.SegmentsData[i].FeatureValue[j]); // f(bitsToRead)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delta_q_params()
|
||||
// combined with delta_lf_params()
|
||||
{
|
||||
if (pPicHdr->quantization_params.BaseQIndex)
|
||||
pBit->put_bits(1, pPicHdr->delta_q_params.DeltaQPresent); // delta_q_present
|
||||
if (pPicHdr->delta_q_params.DeltaQPresent) {
|
||||
pBit->put_bits(2, pPicHdr->delta_q_params.DeltaQRes); // delta_q_res
|
||||
|
||||
// delta_lf_params()
|
||||
if (!pPicHdr->allow_intrabc) {
|
||||
pBit->put_bits(1, pPicHdr->delta_lf_params.DeltaLFPresent); // delta_lf_present
|
||||
if (pPicHdr->delta_lf_params.DeltaLFPresent) {
|
||||
pBit->put_bits(2, pPicHdr->delta_lf_params.DeltaLFRes); // delta_lf_res
|
||||
pBit->put_bits(1, pPicHdr->delta_lf_params.DeltaLFMulti); // delta_lf_multi
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool CodedLossless = false; // CodedLossless default 0
|
||||
constexpr bool AllLossless = false; // AllLossless default 0
|
||||
// loop_filter_params()
|
||||
{
|
||||
if (!(CodedLossless || pPicHdr->allow_intrabc)) {
|
||||
pBit->put_bits(6, pPicHdr->loop_filter_params.LoopFilterLevel[0]); // loop_filter_level[0]
|
||||
pBit->put_bits(6, pPicHdr->loop_filter_params.LoopFilterLevel[1]); // loop_filter_level[1]
|
||||
|
||||
if (pPicHdr->loop_filter_params.LoopFilterLevel[0] || pPicHdr->loop_filter_params.LoopFilterLevel[1]) {
|
||||
pBit->put_bits(6, pPicHdr->loop_filter_params.LoopFilterLevelU); // loop_filter_level[2]
|
||||
pBit->put_bits(6, pPicHdr->loop_filter_params.LoopFilterLevelV); // loop_filter_level[3]
|
||||
}
|
||||
|
||||
pBit->put_bits(3, pPicHdr->loop_filter_params.LoopFilterSharpnessLevel); // loop_filter_sharpness
|
||||
pBit->put_bits(1, pPicHdr->loop_filter_params.LoopFilterDeltaEnabled); // loop_filter_delta_enabled
|
||||
|
||||
if (pPicHdr->loop_filter_params.LoopFilterDeltaEnabled) {
|
||||
bool loop_filter_delta_update =
|
||||
(pPicHdr->loop_filter_params.UpdateRefDelta || pPicHdr->loop_filter_params.UpdateModeDelta);
|
||||
pBit->put_bits(1, loop_filter_delta_update); // loop_filter_delta_update
|
||||
if (loop_filter_delta_update) {
|
||||
constexpr uint8_t TOTAL_REFS_PER_FRAME = 8; // From AV1 spec
|
||||
static_assert(ARRAY_SIZE(pPicHdr->loop_filter_params.RefDeltas) == TOTAL_REFS_PER_FRAME);
|
||||
for (uint8_t i = 0; i < TOTAL_REFS_PER_FRAME; i++) {
|
||||
pBit->put_bits(1, pPicHdr->loop_filter_params.UpdateRefDelta); // loop_filter_delta_update
|
||||
if (pPicHdr->loop_filter_params.UpdateRefDelta) {
|
||||
pBit->put_su_bits(7, pPicHdr->loop_filter_params.RefDeltas[i]); // loop_filter_ref_deltas[i]
|
||||
}
|
||||
}
|
||||
|
||||
static_assert(ARRAY_SIZE(pPicHdr->loop_filter_params.ModeDeltas) == 2); // From AV1 spec
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
pBit->put_bits(1, pPicHdr->loop_filter_params.UpdateModeDelta); // update_mode_delta
|
||||
if (pPicHdr->loop_filter_params.UpdateModeDelta) {
|
||||
pBit->put_su_bits(7, pPicHdr->loop_filter_params.ModeDeltas[i]); // loop_filter_mode_deltas[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// cdef_params()
|
||||
{
|
||||
if (!(!pSeqHdr->enable_cdef || CodedLossless || pPicHdr->allow_intrabc)) {
|
||||
uint16_t num_planes = 3; // mono_chrome not supported
|
||||
pBit->put_bits(2, pPicHdr->cdef_params.CdefDampingMinus3); // cdef_damping_minus_3
|
||||
pBit->put_bits(2, pPicHdr->cdef_params.CdefBits); // cdef_bits
|
||||
for (uint16_t i = 0; i < (1 << pPicHdr->cdef_params.CdefBits); ++i) {
|
||||
pBit->put_bits(4, pPicHdr->cdef_params.CdefYPriStrength[i]); // cdef_y_pri_strength[i]
|
||||
pBit->put_bits(2, pPicHdr->cdef_params.CdefYSecStrength[i]); // cdef_y_sec_strength[i]
|
||||
if (num_planes > 1) {
|
||||
pBit->put_bits(4, pPicHdr->cdef_params.CdefUVPriStrength[i]); // cdef_uv_pri_strength[i]
|
||||
pBit->put_bits(2, pPicHdr->cdef_params.CdefUVSecStrength[i]); // cdef_uv_sec_strength[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// lr_params()
|
||||
{
|
||||
if (!(AllLossless || pPicHdr->allow_intrabc || !pSeqHdr->enable_restoration)) {
|
||||
bool uses_lr = false;
|
||||
bool uses_chroma_lr = false;
|
||||
for (int i = 0; i < 3 /*MaxNumPlanes*/; i++) {
|
||||
pBit->put_bits(2, pPicHdr->lr_params.lr_type[i]);
|
||||
if (pPicHdr->lr_params.lr_type[i] != D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE_DISABLED) {
|
||||
uses_lr = true;
|
||||
if (i > 0)
|
||||
uses_chroma_lr = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (uses_lr) {
|
||||
pBit->put_bits(1, pPicHdr->lr_params.lr_unit_shift);
|
||||
|
||||
if (!pSeqHdr->use_128x128_superblock && pPicHdr->lr_params.lr_unit_shift) {
|
||||
pBit->put_bits(1, pPicHdr->lr_params.lr_unit_extra_shift);
|
||||
}
|
||||
|
||||
if (pSeqHdr->color_config.subsampling_x && pSeqHdr->color_config.subsampling_y && uses_chroma_lr) {
|
||||
pBit->put_bits(1, pPicHdr->lr_params.lr_uv_shift);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read_tx_mode()
|
||||
{
|
||||
const uint8_t tx_mode_select = (pPicHdr->TxMode == D3D12_VIDEO_ENCODER_AV1_TX_MODE_SELECT) ? 1 : 0;
|
||||
if (!CodedLossless)
|
||||
pBit->put_bits(1, tx_mode_select); // tx_mode_select
|
||||
}
|
||||
|
||||
// frame_reference_mode()
|
||||
{
|
||||
if (!FrameIsIntra)
|
||||
pBit->put_bits(1, pPicHdr->reference_select); // reference_select
|
||||
}
|
||||
|
||||
// skip_mode_params()
|
||||
{
|
||||
uint8_t skipModeAllowed = 0;
|
||||
if (!(FrameIsIntra || !pPicHdr->reference_select || !pSeqHdr->enable_order_hint)) {
|
||||
int forwardIdx = -1;
|
||||
int backwardIdx = -1;
|
||||
int forwardHint = 0;
|
||||
int backwardHint = 0;
|
||||
for (int i = 0; i < 7 /*REFS_PER_FRAME*/; i++) {
|
||||
uint32_t refHint = pPicHdr->ref_order_hint[pPicHdr->ref_frame_idx[i]];
|
||||
if (get_relative_dist(refHint,
|
||||
pPicHdr->order_hint,
|
||||
pSeqHdr->order_hint_bits_minus1 + 1,
|
||||
pSeqHdr->enable_order_hint) < 0) {
|
||||
if (forwardIdx < 0 || get_relative_dist(refHint,
|
||||
forwardHint,
|
||||
pSeqHdr->order_hint_bits_minus1 + 1,
|
||||
pSeqHdr->enable_order_hint) > 0) {
|
||||
forwardIdx = i;
|
||||
forwardHint = refHint;
|
||||
}
|
||||
} else if (get_relative_dist(refHint,
|
||||
pPicHdr->order_hint,
|
||||
pSeqHdr->order_hint_bits_minus1 + 1,
|
||||
pSeqHdr->enable_order_hint) > 0) {
|
||||
if (backwardIdx < 0 || get_relative_dist(refHint,
|
||||
backwardHint,
|
||||
pSeqHdr->order_hint_bits_minus1 + 1,
|
||||
pSeqHdr->enable_order_hint) < 0) {
|
||||
backwardIdx = i;
|
||||
backwardHint = refHint;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (forwardIdx < 0) {
|
||||
skipModeAllowed = 0;
|
||||
} else if (backwardIdx >= 0) {
|
||||
skipModeAllowed = 1;
|
||||
} else {
|
||||
int secondForwardIdx = -1;
|
||||
int secondForwardHint = 0;
|
||||
for (int i = 0; i < 7 /*REFS_PER_FRAME*/; i++) {
|
||||
uint32_t refHint = pPicHdr->ref_order_hint[pPicHdr->ref_frame_idx[i]];
|
||||
if (get_relative_dist(refHint,
|
||||
forwardHint,
|
||||
pSeqHdr->order_hint_bits_minus1 + 1,
|
||||
pSeqHdr->enable_order_hint) < 0) {
|
||||
if (secondForwardIdx < 0 || get_relative_dist(refHint,
|
||||
secondForwardHint,
|
||||
pSeqHdr->order_hint_bits_minus1 + 1,
|
||||
pSeqHdr->enable_order_hint) > 0) {
|
||||
secondForwardIdx = i;
|
||||
secondForwardHint = refHint;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (secondForwardIdx < 0) {
|
||||
skipModeAllowed = 0;
|
||||
} else {
|
||||
skipModeAllowed = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (skipModeAllowed)
|
||||
pBit->put_bits(1, pPicHdr->skip_mode_present); // skip_mode_present
|
||||
|
||||
if (!(FrameIsIntra || pPicHdr->error_resilient_mode || !pSeqHdr->enable_warped_motion)) {
|
||||
pBit->put_bits(1, pPicHdr->allow_warped_motion); // allow_warped_motion
|
||||
}
|
||||
}
|
||||
|
||||
pBit->put_bits(1, pPicHdr->reduced_tx_set); // reduced_tx_set
|
||||
|
||||
// global_motion_params()
|
||||
{
|
||||
if (!FrameIsIntra) {
|
||||
for (uint8_t i = 0; i < 7; i++) {
|
||||
pBit->put_bits(1, 0); // is_global[7]
|
||||
// Unimplemented: Enable global_motion_params with ref_global_motion_info
|
||||
assert(pPicHdr->ref_global_motion_info[i].TransformationType ==
|
||||
D3D12_VIDEO_ENCODER_AV1_REFERENCE_WARPED_MOTION_TRANSFORMATION_IDENTITY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// film_grain_params()
|
||||
// constexpr uint8_t film_grain_params_present = 0; // film_grain_params_present default 0
|
||||
// {
|
||||
// if (!(!film_grain_params_present || (!pPicHdr->show_frame && !pPicHdr->showable_frame))
|
||||
// ... this will be unreachable as film_grain_params_present is zero.
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_bitstream_builder_av1::write_frame_header(const av1_seq_header_t *pSeqHdr,
|
||||
const av1_pic_header_t *pPicHdr,
|
||||
av1_obutype_t frame_pack_type,
|
||||
size_t extra_obu_size_bytes,
|
||||
std::vector<uint8_t> &headerBitstream,
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t &writtenBytes)
|
||||
{
|
||||
assert((frame_pack_type == OBU_FRAME) || (frame_pack_type == OBU_FRAME_HEADER));
|
||||
auto startByteOffset = std::distance(headerBitstream.begin(), placingPositionStart);
|
||||
if (headerBitstream.size() < (startByteOffset + c_DefaultBitstreamBufSize))
|
||||
headerBitstream.resize(startByteOffset + c_DefaultBitstreamBufSize);
|
||||
|
||||
d3d12_video_encoder_bitstream bitstream_full_obu;
|
||||
bitstream_full_obu.setup_bitstream(headerBitstream.size(), headerBitstream.data(), startByteOffset);
|
||||
|
||||
// to handle variable length we first write the content
|
||||
// and later the obu header and concatenate both bitstreams
|
||||
d3d12_video_encoder_bitstream bitstream_pic;
|
||||
bitstream_pic.create_bitstream(c_DefaultBitstreamBufSize);
|
||||
|
||||
{
|
||||
// Write frame_header_obu()
|
||||
write_pic_data(&bitstream_pic, pSeqHdr, pPicHdr);
|
||||
|
||||
debug_printf("frame_header_obu() bytes (without OBU_FRAME nor OBU_FRAME_HEADER alignment padding): %" PRId32 "\n",
|
||||
bitstream_pic.get_byte_count()); // May be bit unaligned at this point (see padding below)
|
||||
debug_printf("extra_obu_size_bytes (ie. tile_group_obu_size if writing OBU_FRAME ): %" PRIu64 "\n",
|
||||
extra_obu_size_bytes);
|
||||
|
||||
// Write the obu_header
|
||||
constexpr uint32_t obu_extension_flag = 0;
|
||||
constexpr uint32_t temporal_id = 0;
|
||||
constexpr uint32_t spatial_id = 0;
|
||||
write_obu_header(&bitstream_full_obu, frame_pack_type, obu_extension_flag, temporal_id, spatial_id);
|
||||
|
||||
if (frame_pack_type == OBU_FRAME) {
|
||||
// Required byte_alignment() in frame_obu() after frame_header_obu()
|
||||
bitstream_pic.put_aligning_bits();
|
||||
debug_printf("Adding byte_alignment() after frame_header_obu() for OBU_FRAME\n");
|
||||
} else if (frame_pack_type == OBU_FRAME_HEADER) {
|
||||
// whole open_bitstream_unit() for OBU_FRAME_HEADER
|
||||
// required in open_bitstream_unit () for OBU_FRAME_HEADER
|
||||
bitstream_pic.put_trailing_bits();
|
||||
debug_printf("Adding trailing_bits() after frame_header_obu() for OBU_FRAME\n");
|
||||
assert(extra_obu_size_bytes == 0);
|
||||
}
|
||||
|
||||
bitstream_pic.flush();
|
||||
|
||||
// Write the obu_size element
|
||||
const size_t obu_size_in_bytes = bitstream_pic.get_byte_count() + extra_obu_size_bytes;
|
||||
debug_printf("obu_size: %" PRIu64 "\n", obu_size_in_bytes);
|
||||
pack_obu_header_size(&bitstream_full_obu, obu_size_in_bytes);
|
||||
|
||||
bitstream_full_obu.flush();
|
||||
|
||||
// bitstream_full_obu has external buffer allocation and
|
||||
// append_bitstream deep copies bitstream_pic, so it's okay
|
||||
// for RAII of bitstream_pic to be deallocated out of scope
|
||||
bitstream_full_obu.append_byte_stream(&bitstream_pic);
|
||||
}
|
||||
|
||||
bitstream_full_obu.flush();
|
||||
|
||||
// Shrink headerBitstream to fit
|
||||
writtenBytes = bitstream_full_obu.get_byte_count() - startByteOffset;
|
||||
headerBitstream.resize(writtenBytes + startByteOffset);
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_bitstream_builder_av1::calculate_tile_group_obu_size(
|
||||
const D3D12_VIDEO_ENCODER_OUTPUT_METADATA *pParsedMetadata,
|
||||
const D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA *pFrameSubregionMetadata,
|
||||
size_t TileSizeBytes, // Pass already +1'd from TileSizeBytesMinus1
|
||||
const D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES &TilesPartition,
|
||||
const av1_tile_group_t &tileGroup,
|
||||
size_t &tile_group_obu_size,
|
||||
size_t &decode_tile_elements_size)
|
||||
{
|
||||
size_t tile_group_obu_size_bits = 0;
|
||||
|
||||
uint8_t NumTiles = TilesPartition.ColCount * TilesPartition.RowCount;
|
||||
if (NumTiles > 1)
|
||||
tile_group_obu_size_bits++; // tile_start_and_end_present_flag f(1)
|
||||
|
||||
bool tile_start_and_end_present_flag = !(tileGroup.tg_start == 0 && (tileGroup.tg_end == (NumTiles - 1)));
|
||||
if (!(NumTiles == 1 || !tile_start_and_end_present_flag)) {
|
||||
uint8_t tileBits = log2(TilesPartition.ColCount) + log2(TilesPartition.RowCount);
|
||||
tile_group_obu_size_bits += tileBits; // tg_start f(tileBits)
|
||||
tile_group_obu_size_bits += tileBits; // tg_end f(tileBits)
|
||||
}
|
||||
|
||||
while (tile_group_obu_size_bits & 7) // byte_alignment()
|
||||
tile_group_obu_size_bits++;
|
||||
|
||||
decode_tile_elements_size = 0;
|
||||
for (UINT64 TileIdx = tileGroup.tg_start; TileIdx <= tileGroup.tg_end; TileIdx++) {
|
||||
// tile_size_minus_1 not coded for last tile
|
||||
if ((TileIdx != tileGroup.tg_end))
|
||||
tile_group_obu_size_bits += (TileSizeBytes * 8); // tile_size_minus_1 le(TileSizeBytes)
|
||||
|
||||
size_t tile_effective_bytes_size =
|
||||
static_cast<size_t>(pFrameSubregionMetadata[TileIdx].bSize - pFrameSubregionMetadata[TileIdx].bStartOffset);
|
||||
decode_tile_elements_size += tile_effective_bytes_size;
|
||||
tile_group_obu_size_bits += (tile_effective_bytes_size * 8);
|
||||
}
|
||||
|
||||
assert((tile_group_obu_size_bits % 8) == 0);
|
||||
tile_group_obu_size = (tile_group_obu_size_bits / 8);
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_bitstream_builder_av1::write_obu_tile_group_header(size_t tile_group_obu_size,
|
||||
std::vector<uint8_t> &headerBitstream,
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t &writtenBytes)
|
||||
{
|
||||
auto startByteOffset = std::distance(headerBitstream.begin(), placingPositionStart);
|
||||
if (headerBitstream.size() < (startByteOffset + c_DefaultBitstreamBufSize))
|
||||
headerBitstream.resize(startByteOffset + c_DefaultBitstreamBufSize);
|
||||
|
||||
d3d12_video_encoder_bitstream bitstream_full_obu;
|
||||
bitstream_full_obu.setup_bitstream(headerBitstream.size(), headerBitstream.data(), startByteOffset);
|
||||
|
||||
// Write the obu_header
|
||||
constexpr uint32_t obu_extension_flag = 0;
|
||||
constexpr uint32_t temporal_id = 0;
|
||||
constexpr uint32_t spatial_id = 0;
|
||||
write_obu_header(&bitstream_full_obu, OBU_TILE_GROUP, obu_extension_flag, temporal_id, spatial_id);
|
||||
|
||||
// tile_group_obu() will be copied by get_feedback from EncodeFrame output
|
||||
// we have to calculate its size anyways using the metadata for the obu_header.
|
||||
// so we just add below the argument tile_group_obu_size informing about the
|
||||
// tile_group_obu() byte size
|
||||
// For OBU_TILE_GROUP there is no padding/alignment requirement so they can be concatenated directly by get_feedback
|
||||
|
||||
// Write the obu_size element
|
||||
pack_obu_header_size(&bitstream_full_obu, tile_group_obu_size);
|
||||
debug_printf("obu_size: %" PRIu64 "\n", tile_group_obu_size);
|
||||
|
||||
bitstream_full_obu.flush();
|
||||
|
||||
// Shrink headerBitstream to fit
|
||||
writtenBytes = bitstream_full_obu.get_byte_count() - startByteOffset;
|
||||
headerBitstream.resize(writtenBytes + startByteOffset);
|
||||
}
|
||||
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* Copyright © Microsoft Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef D3D12_VIDEO_ENC_BITSTREAM_BUILDER_AV1_H
|
||||
#define D3D12_VIDEO_ENC_BITSTREAM_BUILDER_AV1_H
|
||||
|
||||
#include "d3d12_video_encoder_bitstream_builder.h"
|
||||
#include "d3d12_video_encoder_bitstream.h"
|
||||
|
||||
typedef struct av1_tile_group_t
|
||||
{
|
||||
uint8_t tg_start;
|
||||
uint8_t tg_end;
|
||||
} av1_tile_group_t;
|
||||
|
||||
typedef enum av1_obutype_t
|
||||
{
|
||||
OBU_SEQUENCE_HEADER = 1,
|
||||
OBU_TEMPORAL_DELIMITER = 2,
|
||||
OBU_FRAME_HEADER = 3,
|
||||
OBU_TILE_GROUP = 4,
|
||||
OBU_METADATA = 5,
|
||||
OBU_FRAME = 6,
|
||||
OBU_REDUNDANT_FRAME_HEADER = 7,
|
||||
OBU_PADDING = 15,
|
||||
} av1_obutype_t;
|
||||
|
||||
typedef struct av1_pic_tile_info_t
|
||||
{
|
||||
uint32_t uniform_tile_spacing_flag;
|
||||
D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES tile_partition;
|
||||
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE tile_mode;
|
||||
D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_SUPPORT tile_support_caps;
|
||||
} av1_pic_tile_info_t;
|
||||
|
||||
typedef struct av1_pic_lr_params_t
|
||||
{
|
||||
D3D12_VIDEO_ENCODER_AV1_RESTORATION_TYPE lr_type[3];
|
||||
uint32_t lr_unit_shift;
|
||||
uint32_t lr_uv_shift;
|
||||
uint32_t lr_unit_extra_shift;
|
||||
} av1_pic_lr_params_t;
|
||||
|
||||
typedef struct av1_seq_color_config_t
|
||||
{
|
||||
DXGI_FORMAT bit_depth;
|
||||
// uint32_t mono_chrome; // coded in bitstream by default as 0
|
||||
uint32_t color_primaries;
|
||||
uint32_t transfer_characteristics;
|
||||
uint32_t matrix_coefficients;
|
||||
uint32_t color_description_present_flag;
|
||||
uint32_t color_range;
|
||||
uint32_t chroma_sample_position;
|
||||
uint32_t subsampling_x;
|
||||
uint32_t subsampling_y;
|
||||
uint32_t separate_uv_delta_q;
|
||||
} av1_seq_color_config_t;
|
||||
|
||||
typedef struct av1_pic_header_t
|
||||
{
|
||||
uint32_t show_existing_frame;
|
||||
uint32_t frame_to_show_map_idx;
|
||||
// uint32_t display_frame_id; // frame_id_numbers_present_flag coded in bitstream by default as 0
|
||||
D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE frame_type;
|
||||
uint32_t show_frame;
|
||||
uint32_t showable_frame;
|
||||
uint32_t error_resilient_mode;
|
||||
uint32_t disable_cdf_update;
|
||||
uint32_t allow_screen_content_tools;
|
||||
uint32_t force_integer_mv;
|
||||
uint32_t frame_size_override_flag;
|
||||
uint32_t order_hint;
|
||||
uint32_t ref_order_hint[8];
|
||||
uint32_t primary_ref_frame;
|
||||
uint8_t refresh_frame_flags;
|
||||
uint32_t FrameWidth;
|
||||
uint32_t FrameHeight;
|
||||
uint32_t frame_width_sb;
|
||||
uint32_t frame_height_sb;
|
||||
uint32_t use_superres;
|
||||
uint32_t SuperresDenom;
|
||||
uint32_t UpscaledWidth;
|
||||
uint32_t RenderWidth;
|
||||
uint32_t RenderHeight;
|
||||
uint32_t allow_intrabc;
|
||||
int32_t ref_frame_idx[7];
|
||||
D3D12_VIDEO_ENCODER_AV1_REFERENCE_PICTURE_WARPED_MOTION_INFO ref_global_motion_info[7];
|
||||
uint32_t allow_high_precision_mv;
|
||||
D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS interpolation_filter;
|
||||
uint32_t is_motion_mode_switchable;
|
||||
uint32_t use_ref_frame_mvs;
|
||||
uint32_t disable_frame_end_update_cdf;
|
||||
av1_pic_tile_info_t tile_info;
|
||||
D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_CONFIG quantization_params;
|
||||
D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_DELTA_CONFIG delta_lf_params;
|
||||
D3D12_VIDEO_ENCODER_CODEC_AV1_QUANTIZATION_DELTA_CONFIG delta_q_params;
|
||||
// uint32_t CodedLossless; // coded in bitstream by default as 0
|
||||
uint32_t AllLossless; // coded in bitstream by default as 0
|
||||
D3D12_VIDEO_ENCODER_CODEC_AV1_LOOP_FILTER_CONFIG loop_filter_params;
|
||||
D3D12_VIDEO_ENCODER_AV1_CDEF_CONFIG cdef_params;
|
||||
av1_pic_lr_params_t lr_params;
|
||||
D3D12_VIDEO_ENCODER_AV1_TX_MODE TxMode;
|
||||
uint32_t reference_select;
|
||||
uint32_t skip_mode_present;
|
||||
uint32_t allow_warped_motion;
|
||||
uint32_t reduced_tx_set;
|
||||
uint32_t segmentation_enabled;
|
||||
D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_CONFIG segmentation_config;
|
||||
// uint32_t frame_refs_short_signaling; // coded in bitstream by default as 0
|
||||
} av1_pic_header_t;
|
||||
|
||||
typedef struct av1_seq_header_t
|
||||
{
|
||||
uint32_t seq_profile;
|
||||
// uint32_t still_picture; // coded in bitstream by default as 0
|
||||
// uint32_t reduced_still_picture_header; // coded in bitstream by default as 0
|
||||
// uint32_t timing_info_present_flag; // coded in bitstream by default as 0
|
||||
// uint32_t decoder_model_info_present_flag; // coded in bitstream by default as 0
|
||||
uint32_t operating_points_cnt_minus_1;
|
||||
uint32_t operating_point_idc[32];
|
||||
uint32_t seq_level_idx[32];
|
||||
uint32_t seq_tier[32];
|
||||
uint32_t decoder_model_present_for_this_op[32];
|
||||
// uint32_t initial_display_delay_present_flag; // coded in bitstream by default as 0
|
||||
// uint32_t initial_display_delay_minus_1[32];
|
||||
// uint32_t initial_display_delay_present_for_this_op[32]
|
||||
uint32_t max_frame_width;
|
||||
uint32_t max_frame_height;
|
||||
// uint32_t frame_id_numbers_present_flag; // coded in bitstream by default as 0
|
||||
uint32_t use_128x128_superblock;
|
||||
uint32_t enable_filter_intra;
|
||||
uint32_t enable_intra_edge_filter;
|
||||
uint32_t enable_interintra_compound;
|
||||
uint32_t enable_masked_compound;
|
||||
uint32_t enable_warped_motion;
|
||||
uint32_t enable_dual_filter;
|
||||
uint32_t enable_order_hint;
|
||||
uint32_t enable_jnt_comp;
|
||||
uint32_t enable_ref_frame_mvs;
|
||||
uint32_t seq_choose_screen_content_tools;
|
||||
uint32_t seq_force_screen_content_tools;
|
||||
uint32_t seq_choose_integer_mv;
|
||||
uint32_t seq_force_integer_mv;
|
||||
uint32_t order_hint_bits_minus1;
|
||||
uint32_t enable_superres;
|
||||
uint32_t enable_cdef;
|
||||
uint32_t enable_restoration;
|
||||
av1_seq_color_config_t color_config;
|
||||
// uint32_t film_grain_params_present; // coded in bitstream by default as 0
|
||||
} av1_seq_header_t;
|
||||
|
||||
class d3d12_video_bitstream_builder_av1 : public d3d12_video_bitstream_builder_interface
|
||||
{
|
||||
public:
|
||||
d3d12_video_bitstream_builder_av1()
|
||||
{ }
|
||||
~d3d12_video_bitstream_builder_av1()
|
||||
{ }
|
||||
|
||||
void write_temporal_delimiter_obu(std::vector<uint8_t> &headerBitstream,
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t &writtenBytes);
|
||||
|
||||
void write_sequence_header(const av1_seq_header_t *pSeqHdr,
|
||||
std::vector<uint8_t> &headerBitstream,
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t &writtenBytes);
|
||||
|
||||
|
||||
void write_frame_header(const av1_seq_header_t *pSeqHdr,
|
||||
const av1_pic_header_t *pPicHdr,
|
||||
av1_obutype_t frame_pack_type,
|
||||
size_t extra_obu_size_bytes,
|
||||
std::vector<uint8_t> &headerBitstream,
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t &writtenBytes);
|
||||
|
||||
void calculate_tile_group_obu_size(
|
||||
const D3D12_VIDEO_ENCODER_OUTPUT_METADATA *pParsedMetadata,
|
||||
const D3D12_VIDEO_ENCODER_FRAME_SUBREGION_METADATA *pFrameSubregionMetadata,
|
||||
size_t TileSizeBytes, // Pass already +1'd from TileSizeBytesMinus1
|
||||
const D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES &TilesPartition,
|
||||
const av1_tile_group_t &tileGroup,
|
||||
size_t &tile_group_obu_total_size,
|
||||
size_t &decode_tile_elements_size);
|
||||
|
||||
void write_obu_tile_group_header(size_t tile_group_obu_size,
|
||||
std::vector<uint8_t> &headerBitstream,
|
||||
std::vector<uint8_t>::iterator placingPositionStart,
|
||||
size_t &writtenBytes);
|
||||
|
||||
private:
|
||||
// static void write_delta_q_value(d3d12_video_encoder_bitstream& bitstream,
|
||||
// int32_t delta_q_val);
|
||||
const size_t c_DefaultBitstreamBufSize = 1024;
|
||||
|
||||
void write_obu_header(d3d12_video_encoder_bitstream *pBit,
|
||||
av1_obutype_t obu_type,
|
||||
uint32_t obu_extension_flag,
|
||||
uint32_t temporal_id,
|
||||
uint32_t spatial_id);
|
||||
|
||||
void pack_obu_header_size(d3d12_video_encoder_bitstream *pBit, uint64_t val);
|
||||
|
||||
void write_seq_data(d3d12_video_encoder_bitstream *pBit, const av1_seq_header_t *pSeqHdr);
|
||||
|
||||
void write_pic_data(d3d12_video_encoder_bitstream *pBit,
|
||||
const av1_seq_header_t *pSeqHdr,
|
||||
const av1_pic_header_t *pPicHdr);
|
||||
|
||||
void write_delta_q_value(d3d12_video_encoder_bitstream *pBit, int32_t delta_q_val);
|
||||
|
||||
void write_frame_size(d3d12_video_encoder_bitstream *pBit,
|
||||
const av1_seq_header_t *pSeqHdr,
|
||||
const av1_pic_header_t *pPicHdr);
|
||||
|
||||
void write_frame_size_with_refs(d3d12_video_encoder_bitstream *pBit,
|
||||
const av1_seq_header_t *pSeqHdr,
|
||||
const av1_pic_header_t *pPicHdr);
|
||||
|
||||
void write_render_size(d3d12_video_encoder_bitstream *pBit, const av1_pic_header_t *pPicHdr);
|
||||
|
||||
void write_superres_params(d3d12_video_encoder_bitstream *pBit,
|
||||
const av1_seq_header_t *pSeqHdr,
|
||||
const av1_pic_header_t *pPicHdr);
|
||||
|
||||
// Constants
|
||||
static const uint32_t frame_width_bits_minus_1 = 15;
|
||||
static const uint32_t frame_height_bits_minus_1 = 15;
|
||||
};
|
||||
|
||||
#endif // D3D12_VIDEO_ENC_BITSTREAM_BUILDER_AV1_H
|
||||
|
|
@ -0,0 +1,431 @@
|
|||
/*
|
||||
* Copyright © Microsoft Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "d3d12_video_enc.h"
|
||||
#include "d3d12_video_enc_av1.h"
|
||||
#include "d3d12_video_encoder_references_manager_av1.h"
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include "d3d12_screen.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
d3d12_video_encoder_references_manager_av1::d3d12_video_encoder_references_manager_av1(
|
||||
bool gopHasInterFrames, d3d12_video_dpb_storage_manager_interface &rDpbStorageManager)
|
||||
: m_CurrentFrameReferencesData({}),
|
||||
m_PhysicalAllocationsStorage(rDpbStorageManager),
|
||||
m_gopHasInterFrames(gopHasInterFrames),
|
||||
m_isCurrentFrameUsedAsReference(false),
|
||||
m_CurrentFramePicParams({})
|
||||
{
|
||||
assert((NUM_REF_FRAMES + 1 /*extra for cur frame output recon pic*/) ==
|
||||
m_PhysicalAllocationsStorage.get_number_of_tracked_allocations());
|
||||
|
||||
debug_printf("[D3D12 Video Encoder Picture Manager AV1] Completed construction of "
|
||||
"d3d12_video_encoder_references_manager_AV1 instance.\n");
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_references_manager_av1::clear_dpb()
|
||||
{
|
||||
// Reset m_CurrentFrameReferencesData tracking
|
||||
m_CurrentFrameReferencesData.pVirtualDPBEntries.clear();
|
||||
m_CurrentFrameReferencesData.pVirtualDPBEntries.resize(NUM_REF_FRAMES);
|
||||
m_CurrentFrameReferencesData.ReconstructedPicTexture = { nullptr, 0 };
|
||||
|
||||
// Initialize DPB slots as unused
|
||||
for (size_t i = 0; i < NUM_REF_FRAMES; i++)
|
||||
m_CurrentFrameReferencesData.pVirtualDPBEntries[i].ReconstructedPictureResourceIndex =
|
||||
UNUSED_VIRTUAL_DPB_SLOT_PHYSICAL_INDEX;
|
||||
|
||||
// Reset physical DPB underlying storage
|
||||
ASSERTED uint32_t numPicsBeforeClearInDPB = m_PhysicalAllocationsStorage.get_number_of_pics_in_dpb();
|
||||
ASSERTED uint32_t cFreedResources = m_PhysicalAllocationsStorage.clear_decode_picture_buffer();
|
||||
assert(numPicsBeforeClearInDPB == cFreedResources);
|
||||
}
|
||||
|
||||
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE
|
||||
d3d12_video_encoder_references_manager_av1::get_current_frame_recon_pic_output_allocation()
|
||||
{
|
||||
return m_CurrentFrameReferencesData.ReconstructedPicTexture;
|
||||
}
|
||||
|
||||
bool
|
||||
d3d12_video_encoder_references_manager_av1::is_current_frame_used_as_reference()
|
||||
{
|
||||
return m_isCurrentFrameUsedAsReference;
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_references_manager_av1::begin_frame(D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA curFrameData,
|
||||
bool bUsedAsReference,
|
||||
struct pipe_picture_desc *picture)
|
||||
{
|
||||
m_CurrentFramePicParams = *curFrameData.pAV1PicData;
|
||||
m_isCurrentFrameUsedAsReference = bUsedAsReference;
|
||||
|
||||
if (m_CurrentFramePicParams.FrameType == D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME)
|
||||
clear_dpb();
|
||||
|
||||
// Prepare current frame recon pic allocation
|
||||
m_CurrentFrameReferencesData.ReconstructedPicTexture = { nullptr, 0 };
|
||||
if (is_current_frame_used_as_reference() && m_gopHasInterFrames) {
|
||||
auto reconPic = m_PhysicalAllocationsStorage.get_new_tracked_picture_allocation();
|
||||
m_CurrentFrameReferencesData.ReconstructedPicTexture.pReconstructedPicture = reconPic.pReconstructedPicture;
|
||||
m_CurrentFrameReferencesData.ReconstructedPicTexture.ReconstructedPictureSubresource =
|
||||
reconPic.ReconstructedPictureSubresource;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
assert(m_PhysicalAllocationsStorage.get_number_of_tracked_allocations() <=
|
||||
(NUM_REF_FRAMES + 1)); // pool is not extended beyond maximum expected usage
|
||||
|
||||
if (m_CurrentFramePicParams.FrameType == D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME) {
|
||||
// After clearing the DPB, outstanding used allocations should be 1u only for the first allocation for the
|
||||
// reconstructed picture of the initial KEY_FRAME
|
||||
assert(m_PhysicalAllocationsStorage.get_number_of_in_use_allocations() ==
|
||||
((is_current_frame_used_as_reference() && m_gopHasInterFrames) ? 1u : 0u));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_references_manager_av1::end_frame()
|
||||
{
|
||||
refresh_dpb_slots_with_current_frame_reconpic();
|
||||
}
|
||||
|
||||
D3D12_VIDEO_ENCODE_REFERENCE_FRAMES
|
||||
d3d12_video_encoder_references_manager_av1::get_current_reference_frames()
|
||||
{
|
||||
D3D12_VIDEO_ENCODE_REFERENCE_FRAMES retVal = { 0,
|
||||
// ppTexture2Ds
|
||||
nullptr,
|
||||
// pSubresources
|
||||
nullptr };
|
||||
|
||||
if ((m_CurrentFramePicParams.FrameType != D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME) && m_gopHasInterFrames) {
|
||||
auto curRef = m_PhysicalAllocationsStorage.get_current_reference_frames();
|
||||
retVal.NumTexture2Ds = curRef.NumTexture2Ds;
|
||||
retVal.ppTexture2Ds = curRef.ppTexture2Ds;
|
||||
retVal.pSubresources = curRef.pSubresources;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_references_manager_av1::print_ref_frame_idx()
|
||||
{
|
||||
std::string refListContentsString;
|
||||
for (uint32_t idx = 0; idx < REFS_PER_FRAME; idx++) {
|
||||
uint32_t reference = 0;
|
||||
reference = m_CurrentFramePicParams.ReferenceIndices[idx];
|
||||
refListContentsString += "{ ref_frame_idx[" + std::to_string(idx) + "] - ";
|
||||
refListContentsString += " DPBidx: ";
|
||||
refListContentsString += std::to_string(reference);
|
||||
if (m_CurrentFrameReferencesData.pVirtualDPBEntries[reference].ReconstructedPictureResourceIndex !=
|
||||
UNUSED_VIRTUAL_DPB_SLOT_PHYSICAL_INDEX) {
|
||||
refListContentsString += " - OrderHint: ";
|
||||
refListContentsString += std::to_string(m_CurrentFrameReferencesData.pVirtualDPBEntries[reference].OrderHint);
|
||||
refListContentsString += " - PictureIndex: ";
|
||||
refListContentsString +=
|
||||
std::to_string(m_CurrentFrameReferencesData.pVirtualDPBEntries[reference].PictureIndex);
|
||||
} else {
|
||||
refListContentsString += " - Unused Virtual DPB slot ";
|
||||
}
|
||||
|
||||
refListContentsString += " }\n";
|
||||
}
|
||||
|
||||
debug_printf("[D3D12 Video Encoder Picture Manager AV1] ref_frame_idx[REFS_PER_FRAME] for frame with OrderHint %d "
|
||||
"(PictureIndex %d) is: \n%s \n",
|
||||
m_CurrentFramePicParams.OrderHint,
|
||||
m_CurrentFramePicParams.PictureIndex,
|
||||
refListContentsString.c_str());
|
||||
debug_printf("[D3D12 Video Encoder Picture Manager AV1] Requested PrimaryRefFrame: %d\n",
|
||||
m_CurrentFramePicParams.PrimaryRefFrame);
|
||||
debug_printf("[D3D12 Video Encoder Picture Manager AV1] Requested RefreshFrameFlags: %d\n",
|
||||
m_CurrentFramePicParams.RefreshFrameFlags);
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_references_manager_av1::print_virtual_dpb_entries()
|
||||
{
|
||||
std::string dpbContents;
|
||||
for (uint32_t dpbResIdx = 0; dpbResIdx < m_CurrentFrameReferencesData.pVirtualDPBEntries.size(); dpbResIdx++) {
|
||||
auto &dpbDesc = m_CurrentFrameReferencesData.pVirtualDPBEntries[dpbResIdx];
|
||||
|
||||
if (dpbDesc.ReconstructedPictureResourceIndex != UNUSED_VIRTUAL_DPB_SLOT_PHYSICAL_INDEX) {
|
||||
d3d12_video_reconstructed_picture dpbEntry =
|
||||
m_PhysicalAllocationsStorage.get_reference_frame(dpbDesc.ReconstructedPictureResourceIndex);
|
||||
dpbContents += "{ DPBidx: ";
|
||||
dpbContents += std::to_string(dpbResIdx);
|
||||
dpbContents += " - OrderHint: ";
|
||||
dpbContents += std::to_string(dpbDesc.OrderHint);
|
||||
dpbContents += " - PictureIndex: ";
|
||||
dpbContents += std::to_string(dpbDesc.PictureIndex);
|
||||
dpbContents += " - DPBStorageIdx: ";
|
||||
dpbContents += std::to_string(dpbDesc.ReconstructedPictureResourceIndex);
|
||||
dpbContents += " - DPBStorageResourcePtr: ";
|
||||
char strBuf[256];
|
||||
memset(&strBuf, '\0', 256);
|
||||
sprintf(strBuf, "%p", dpbEntry.pReconstructedPicture);
|
||||
dpbContents += std::string(strBuf);
|
||||
dpbContents += " - DPBStorageSubresource: ";
|
||||
dpbContents += std::to_string(dpbEntry.ReconstructedPictureSubresource);
|
||||
dpbContents += " - RefCount (from any ref_frame_idx[0..6]): ";
|
||||
dpbContents += std::to_string(get_dpb_virtual_slot_refcount_from_ref_frame_idx(dpbResIdx));
|
||||
dpbContents += " }\n";
|
||||
} else {
|
||||
dpbContents += "{ DPBidx: ";
|
||||
dpbContents += std::to_string(dpbResIdx);
|
||||
dpbContents += " < Unused Virtual DPB slot > }\n";
|
||||
}
|
||||
}
|
||||
|
||||
debug_printf(
|
||||
"[D3D12 Video Encoder Picture Manager AV1] DPB Current output reconstructed picture %p subresource %d\n",
|
||||
m_CurrentFrameReferencesData.ReconstructedPicTexture.pReconstructedPicture,
|
||||
m_CurrentFrameReferencesData.ReconstructedPicTexture.ReconstructedPictureSubresource);
|
||||
|
||||
debug_printf("[D3D12 Video Encoder Picture Manager AV1] NumTexture2Ds is %d frames - "
|
||||
"Number of DPB virtual entries is %" PRIu64 " entries for frame with OrderHint "
|
||||
"%d (PictureIndex %d) are: \n%s \n",
|
||||
m_PhysicalAllocationsStorage.get_number_of_pics_in_dpb(),
|
||||
m_CurrentFrameReferencesData.pVirtualDPBEntries.size(),
|
||||
m_CurrentFramePicParams.OrderHint,
|
||||
m_CurrentFramePicParams.PictureIndex,
|
||||
dpbContents.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_references_manager_av1::print_physical_resource_references()
|
||||
{
|
||||
debug_printf("[D3D12 Video Encoder Picture Manager AV1] %d physical resources IN USE out of a total of %d physical "
|
||||
"resources ALLOCATED "
|
||||
"resources at end_frame for frame with OrderHint %d (PictureIndex %d)\n",
|
||||
m_PhysicalAllocationsStorage.get_number_of_in_use_allocations(),
|
||||
m_PhysicalAllocationsStorage.get_number_of_tracked_allocations(),
|
||||
m_CurrentFramePicParams.OrderHint,
|
||||
m_CurrentFramePicParams.PictureIndex);
|
||||
|
||||
D3D12_VIDEO_ENCODE_REFERENCE_FRAMES curRefs = get_current_reference_frames();
|
||||
std::string descContents;
|
||||
for (uint32_t index = 0; index < curRefs.NumTexture2Ds; index++) {
|
||||
assert(curRefs.ppTexture2Ds[index]); // These must be contiguous when sending down to D3D12 API
|
||||
descContents += "{ REFERENCE_FRAMES Index: ";
|
||||
descContents += std::to_string(index);
|
||||
descContents += " - ppTextures ptr: ";
|
||||
char strBuf[256];
|
||||
memset(&strBuf, '\0', 256);
|
||||
sprintf(strBuf, "%p", curRefs.ppTexture2Ds[index]);
|
||||
descContents += std::string(strBuf);
|
||||
descContents += " - ppSubresources index: ";
|
||||
if (curRefs.pSubresources != nullptr)
|
||||
descContents += std::to_string(curRefs.pSubresources[index]);
|
||||
else
|
||||
descContents += "(nil)";
|
||||
descContents += " - RefCount (from any virtual dpb slot [0..REFS_PER_FRAME]): ";
|
||||
descContents += std::to_string(get_dpb_physical_slot_refcount_from_virtual_dpb(index));
|
||||
descContents += " }\n";
|
||||
}
|
||||
|
||||
debug_printf("[D3D12 Video Encoder Picture Manager AV1] D3D12_VIDEO_ENCODE_REFERENCE_FRAMES has %d physical "
|
||||
"resources in ppTexture2Ds for OrderHint "
|
||||
"%d (PictureIndex %d) are: \n%s \n",
|
||||
curRefs.NumTexture2Ds,
|
||||
m_CurrentFramePicParams.OrderHint,
|
||||
m_CurrentFramePicParams.PictureIndex,
|
||||
descContents.c_str());
|
||||
}
|
||||
|
||||
//
|
||||
// Returns the number of Reference<XXX> (ie. LAST, LAST2, ..., ALTREF, etc)
|
||||
// pointing to dpbSlotIndex
|
||||
//
|
||||
uint32_t
|
||||
d3d12_video_encoder_references_manager_av1::get_dpb_virtual_slot_refcount_from_ref_frame_idx(uint32_t dpbSlotIndex)
|
||||
{
|
||||
uint32_t refCount = 0;
|
||||
for (uint8_t i = 0; i < ARRAY_SIZE(m_CurrentFramePicParams.ReferenceIndices); i++) {
|
||||
if (m_CurrentFramePicParams.ReferenceIndices[i] == dpbSlotIndex) {
|
||||
refCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return refCount;
|
||||
}
|
||||
|
||||
//
|
||||
// Returns the number of entries in the virtual DPB descriptors
|
||||
// that point to physicalSlotIndex
|
||||
//
|
||||
uint32_t
|
||||
d3d12_video_encoder_references_manager_av1::get_dpb_physical_slot_refcount_from_virtual_dpb(uint32_t physicalSlotIndex)
|
||||
{
|
||||
uint32_t refCount = 0;
|
||||
for (unsigned dpbSlotIndex = 0; dpbSlotIndex < m_CurrentFrameReferencesData.pVirtualDPBEntries.size();
|
||||
dpbSlotIndex++) {
|
||||
if (m_CurrentFrameReferencesData.pVirtualDPBEntries[dpbSlotIndex].ReconstructedPictureResourceIndex ==
|
||||
physicalSlotIndex)
|
||||
refCount++;
|
||||
}
|
||||
return refCount;
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_references_manager_av1::get_current_frame_picture_control_data(
|
||||
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_CODEC_DATA &codecAllocation)
|
||||
{
|
||||
assert(m_CurrentFrameReferencesData.pVirtualDPBEntries.size() == NUM_REF_FRAMES);
|
||||
assert(codecAllocation.DataSize == sizeof(D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_CODEC_DATA));
|
||||
|
||||
// Some apps don't clean this up for INTRA/KEY frames
|
||||
if ((m_CurrentFramePicParams.FrameType != D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_INTER_FRAME)
|
||||
&& (m_CurrentFramePicParams.FrameType != D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_SWITCH_FRAME))
|
||||
{
|
||||
for (uint8_t i = 0; i < ARRAY_SIZE(m_CurrentFramePicParams.ReferenceIndices); i++) {
|
||||
m_CurrentFramePicParams.ReferenceIndices[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < NUM_REF_FRAMES; i++)
|
||||
m_CurrentFramePicParams.ReferenceFramesReconPictureDescriptors[i] =
|
||||
m_CurrentFrameReferencesData.pVirtualDPBEntries[i];
|
||||
|
||||
#ifdef DEBUG // Otherwise may iterate over structures and do no-op debug_printf
|
||||
print_ref_frame_idx();
|
||||
print_virtual_dpb_entries();
|
||||
print_physical_resource_references();
|
||||
#endif
|
||||
|
||||
*codecAllocation.pAV1PicData = m_CurrentFramePicParams;
|
||||
}
|
||||
|
||||
void
|
||||
d3d12_video_encoder_references_manager_av1::refresh_dpb_slots_with_current_frame_reconpic()
|
||||
{
|
||||
UINT refresh_frame_flags = m_CurrentFramePicParams.RefreshFrameFlags;
|
||||
debug_printf("[D3D12 Video Encoder Picture Manager AV1] refresh_frame_flags 0x%x for frame with OrderHint %d "
|
||||
"(PictureIndex %d)\n",
|
||||
refresh_frame_flags,
|
||||
m_CurrentFramePicParams.OrderHint,
|
||||
m_CurrentFramePicParams.PictureIndex);
|
||||
|
||||
//
|
||||
// Put current frame in all slots of DPB indicated by refresh_frame_flags
|
||||
//
|
||||
if (is_current_frame_used_as_reference() && m_gopHasInterFrames && (refresh_frame_flags != 0)) {
|
||||
|
||||
//
|
||||
// First do a eviction pass and update virtual DPB physical indices in case the physical array shifted with an
|
||||
// eviction (erasing an ppTexture2Ds entry)
|
||||
//
|
||||
|
||||
for (unsigned dpbSlotIdx = 0; dpbSlotIdx < NUM_REF_FRAMES; dpbSlotIdx++) {
|
||||
if (((refresh_frame_flags >> dpbSlotIdx) & 0x1) != 0) {
|
||||
|
||||
//
|
||||
// Check if the slot this reconpic will take in the virtual DPB will leave an unreferenced
|
||||
// physical allocation, that may need to be evicted (if no other virtual dpb slot references it)
|
||||
//
|
||||
|
||||
if (m_CurrentFrameReferencesData.pVirtualDPBEntries[dpbSlotIdx].ReconstructedPictureResourceIndex !=
|
||||
UNUSED_VIRTUAL_DPB_SLOT_PHYSICAL_INDEX) {
|
||||
|
||||
// If this is a virtual dpb valid entry, there has to be a valid underlying physical allocation
|
||||
assert(m_CurrentFrameReferencesData.pVirtualDPBEntries[dpbSlotIdx].ReconstructedPictureResourceIndex <
|
||||
m_PhysicalAllocationsStorage.get_number_of_pics_in_dpb());
|
||||
|
||||
// Get the number of entries in the virtual DPB descriptors that point to
|
||||
// ReconstructedPictureResourceIndex of the current virtual dpb slot (counting the current dpbSlotIdx we
|
||||
// didn't clear yet)
|
||||
uint32_t numRefs = get_dpb_physical_slot_refcount_from_virtual_dpb(
|
||||
m_CurrentFrameReferencesData.pVirtualDPBEntries[dpbSlotIdx].ReconstructedPictureResourceIndex);
|
||||
if (numRefs == 1) {
|
||||
// When refreshing this dpbSlotIdx, we will leave an unreferenced physical allocation
|
||||
// so we can just remove it (and release the ID3D12Resource allocation back to the unused pool)
|
||||
|
||||
bool wasTracked = false;
|
||||
m_PhysicalAllocationsStorage.remove_reference_frame(
|
||||
m_CurrentFrameReferencesData.pVirtualDPBEntries[dpbSlotIdx].ReconstructedPictureResourceIndex,
|
||||
&wasTracked);
|
||||
assert(wasTracked);
|
||||
|
||||
// Indices in the virtual dpb higher or equal than
|
||||
// m_CurrentFrameReferencesData.pVirtualDPBEntries[dpbSlotIdx].ReconstructedPictureResourceIndex
|
||||
// must be shifted back one place as we erased the entry in the physical allocations array (ppTexture2Ds)
|
||||
for (auto &dpbVirtualEntry : m_CurrentFrameReferencesData.pVirtualDPBEntries) {
|
||||
if (
|
||||
// Check for slot being used
|
||||
(dpbVirtualEntry.ReconstructedPictureResourceIndex != UNUSED_VIRTUAL_DPB_SLOT_PHYSICAL_INDEX) &&
|
||||
// Check for slot to be affected by removing the entry in ppTexture2Ds above
|
||||
(dpbVirtualEntry.ReconstructedPictureResourceIndex >
|
||||
m_CurrentFrameReferencesData.pVirtualDPBEntries[dpbSlotIdx].ReconstructedPictureResourceIndex)) {
|
||||
|
||||
// Decrease the index to compensate for the removed ppTexture2Ds entry
|
||||
dpbVirtualEntry.ReconstructedPictureResourceIndex--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear this virtual dpb entry (so next iterations will decrease refcount)
|
||||
m_CurrentFrameReferencesData.pVirtualDPBEntries[dpbSlotIdx].ReconstructedPictureResourceIndex =
|
||||
UNUSED_VIRTUAL_DPB_SLOT_PHYSICAL_INDEX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Find a new free physical index for the current recon pic; always put new physical entry at the end to avoid
|
||||
// having to shift existing indices in virtual DPB
|
||||
//
|
||||
UINT allocationSlotIdx = m_PhysicalAllocationsStorage.get_number_of_pics_in_dpb();
|
||||
assert(static_cast<uint32_t>(allocationSlotIdx) < NUM_REF_FRAMES);
|
||||
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;
|
||||
m_PhysicalAllocationsStorage.insert_reference_frame(refFrameDesc, allocationSlotIdx);
|
||||
|
||||
//
|
||||
// Update virtual DPB entries with the current frame recon picture
|
||||
//
|
||||
for (unsigned dpbSlotIdx = 0; dpbSlotIdx < NUM_REF_FRAMES; dpbSlotIdx++) {
|
||||
if (((refresh_frame_flags >> dpbSlotIdx) & 0x1) != 0) {
|
||||
m_CurrentFrameReferencesData.pVirtualDPBEntries[dpbSlotIdx] = { allocationSlotIdx,
|
||||
0, // NO temporal scalability support
|
||||
0, // NO spatial scalability support
|
||||
m_CurrentFramePicParams.FrameType,
|
||||
{}, // No global_motion support
|
||||
m_CurrentFramePicParams.OrderHint,
|
||||
m_CurrentFramePicParams.PictureIndex };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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_PhysicalAllocationsStorage.get_number_of_tracked_allocations() <= (NUM_REF_FRAMES + 1));
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright © Microsoft Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the next
|
||||
* paragraph) shall be included in all copies or substantial portions of the
|
||||
* Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef D3D12_VIDEO_ENCODE_FIFO_REFERENCES_MANAGER_AV1_H
|
||||
#define D3D12_VIDEO_ENCODE_FIFO_REFERENCES_MANAGER_AV1_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_av1 : 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 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_av1(bool gopHasInterCodedFrames,
|
||||
d3d12_video_dpb_storage_manager_interface &rDpbStorageManager);
|
||||
|
||||
~d3d12_video_encoder_references_manager_av1()
|
||||
{ }
|
||||
|
||||
private:
|
||||
// Class helpers
|
||||
|
||||
void clear_dpb();
|
||||
void refresh_dpb_slots_with_current_frame_reconpic();
|
||||
|
||||
uint32_t get_dpb_virtual_slot_refcount_from_ref_frame_idx(uint32_t dpbSlotIndex);
|
||||
uint32_t get_dpb_physical_slot_refcount_from_virtual_dpb(uint32_t ReconstructedPictureResourceIndex);
|
||||
|
||||
void print_virtual_dpb_entries();
|
||||
void print_physical_resource_references();
|
||||
void print_ref_frame_idx();
|
||||
|
||||
// Class members
|
||||
|
||||
struct current_frame_references_data
|
||||
{
|
||||
std::vector<D3D12_VIDEO_ENCODER_AV1_REFERENCE_PICTURE_DESCRIPTOR> pVirtualDPBEntries;
|
||||
D3D12_VIDEO_ENCODER_RECONSTRUCTED_PICTURE ReconstructedPicTexture;
|
||||
} m_CurrentFrameReferencesData = {};
|
||||
d3d12_video_dpb_storage_manager_interface &m_PhysicalAllocationsStorage;
|
||||
bool m_gopHasInterFrames = false;
|
||||
bool m_isCurrentFrameUsedAsReference = false;
|
||||
D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_CODEC_DATA m_CurrentFramePicParams = {};
|
||||
|
||||
// Constants
|
||||
const uint32_t NUM_REF_FRAMES = 8;
|
||||
const uint32_t REFS_PER_FRAME = 7;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -42,10 +42,14 @@ struct d3d12_encode_codec_support {
|
|||
union pipe_h265_enc_cap_block_sizes hevc_block_sizes;
|
||||
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC d3d12_caps;
|
||||
} hevc_support;
|
||||
// Can add more codecs for each codec specific caps here, for example:
|
||||
// struct {
|
||||
// D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_H264;
|
||||
// } h264_support;
|
||||
struct {
|
||||
union pipe_av1_enc_cap_features features;
|
||||
union pipe_av1_enc_cap_features_ext1 features_ext1;
|
||||
union pipe_av1_enc_cap_features_ext2 features_ext2;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT d3d12_caps;
|
||||
#endif
|
||||
} av1_support;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -290,16 +294,88 @@ d3d12_video_encode_supported_references_per_frame_structures(const D3D12_VIDEO_E
|
|||
supportedMaxRefFrames = (maxRefForL0 & 0xffff) | ((maxRefForL1 & 0xffff) << 16);
|
||||
}
|
||||
}
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
else if(codec == D3D12_VIDEO_ENCODER_CODEC_AV1){
|
||||
D3D12_VIDEO_ENCODER_CODEC_AV1_PICTURE_CONTROL_SUPPORT av1PictureControl = {};
|
||||
capPictureControlData.Profile = profile;
|
||||
capPictureControlData.PictureSupport.pAV1Support = &av1PictureControl;
|
||||
capPictureControlData.PictureSupport.DataSize = sizeof(av1PictureControl);
|
||||
HRESULT hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_PICTURE_CONTROL_SUPPORT,
|
||||
&capPictureControlData,
|
||||
sizeof(capPictureControlData));
|
||||
if (FAILED(hr)) {
|
||||
debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
|
||||
}
|
||||
|
||||
if (capPictureControlData.IsSupported) {
|
||||
/* This attribute determines the maximum number of reference
|
||||
* frames supported for encoding.
|
||||
*/
|
||||
supportedMaxRefFrames = capPictureControlData.PictureSupport.pAV1Support->MaxUniqueReferencesPerFrame;
|
||||
supportedMaxRefFrames = (supportedMaxRefFrames & 0xffff) | ((supportedMaxRefFrames & 0xffff) << 16);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return supportedMaxRefFrames;
|
||||
}
|
||||
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
static void
|
||||
d3d12_video_encode_supported_tile_structures(const D3D12_VIDEO_ENCODER_CODEC &codec,
|
||||
const D3D12_VIDEO_ENCODER_PROFILE_DESC &profile,
|
||||
const D3D12_VIDEO_ENCODER_LEVEL_SETTING &level,
|
||||
ID3D12VideoDevice3 *pD3D12VideoDevice,
|
||||
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC maxRes,
|
||||
uint32_t& supportedSliceStructures, // out
|
||||
uint32_t& tile_size_bytes_minus1 // out
|
||||
)
|
||||
{
|
||||
// Assume no support and then add as queries succeed
|
||||
supportedSliceStructures = PIPE_VIDEO_CAP_SLICE_STRUCTURE_NONE;
|
||||
|
||||
// Only codecs supporting tiles should use this method. For slices related info, use d3d12_video_encode_supported_slice_structures
|
||||
assert (codec == D3D12_VIDEO_ENCODER_CODEC_AV1);
|
||||
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG capDataTilesSupport = { };
|
||||
capDataTilesSupport.NodeIndex = 0;
|
||||
capDataTilesSupport.Codec = codec;
|
||||
capDataTilesSupport.Profile = profile;
|
||||
capDataTilesSupport.Level = level;
|
||||
capDataTilesSupport.FrameResolution = maxRes; // Query for worst case resolution
|
||||
D3D12_VIDEO_ENCODER_AV1_FRAME_SUBREGION_LAYOUT_CONFIG_SUPPORT av1TileSupport = { };
|
||||
capDataTilesSupport.CodecSupport.DataSize = sizeof(av1TileSupport);
|
||||
capDataTilesSupport.CodecSupport.pAV1Support = &av1TileSupport;
|
||||
av1TileSupport.Use128SuperBlocks = false; // return units in 64x64 default size
|
||||
|
||||
capDataTilesSupport.SubregionMode =
|
||||
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_GRID_PARTITION;
|
||||
HRESULT hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG,
|
||||
&capDataTilesSupport,
|
||||
sizeof(capDataTilesSupport));
|
||||
if(SUCCEEDED(hr) && capDataTilesSupport.IsSupported)
|
||||
supportedSliceStructures |= (PIPE_VIDEO_CAP_SLICE_STRUCTURE_POWER_OF_TWO_ROWS | PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_ROWS | PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_MULTI_ROWS);
|
||||
|
||||
capDataTilesSupport.SubregionMode =
|
||||
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_CONFIGURABLE_GRID_PARTITION;
|
||||
hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_CONFIG,
|
||||
&capDataTilesSupport,
|
||||
sizeof(capDataTilesSupport));
|
||||
if(SUCCEEDED(hr) && capDataTilesSupport.IsSupported)
|
||||
supportedSliceStructures |= (PIPE_VIDEO_CAP_SLICE_STRUCTURE_ARBITRARY_MACROBLOCKS | PIPE_VIDEO_CAP_SLICE_STRUCTURE_ARBITRARY_ROWS);
|
||||
|
||||
tile_size_bytes_minus1 = av1TileSupport.TileSizeBytesMinus1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static uint32_t
|
||||
d3d12_video_encode_supported_slice_structures(const D3D12_VIDEO_ENCODER_CODEC &codec,
|
||||
D3D12_VIDEO_ENCODER_PROFILE_DESC profile,
|
||||
D3D12_VIDEO_ENCODER_LEVEL_SETTING level,
|
||||
ID3D12VideoDevice3 *pD3D12VideoDevice)
|
||||
{
|
||||
// Only codecs supporting slices should use this method. For tile related info, use d3d12_video_encode_supported_tile_structures
|
||||
assert ((codec == D3D12_VIDEO_ENCODER_CODEC_H264) || (codec == D3D12_VIDEO_ENCODER_CODEC_HEVC));
|
||||
|
||||
uint32_t supportedSliceStructuresBitMask = PIPE_VIDEO_CAP_SLICE_STRUCTURE_NONE;
|
||||
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE capDataSubregionLayout = {};
|
||||
|
|
@ -328,15 +404,15 @@ d3d12_video_encode_supported_slice_structures(const D3D12_VIDEO_ENCODER_CODEC &c
|
|||
capDataSubregionLayout.SubregionMode =
|
||||
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
|
||||
HRESULT hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE,
|
||||
&capDataSubregionLayout,
|
||||
sizeof(capDataSubregionLayout));
|
||||
&capDataSubregionLayout,
|
||||
sizeof(capDataSubregionLayout));
|
||||
if (FAILED(hr)) {
|
||||
debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
|
||||
} else if (capDataSubregionLayout.IsSupported) {
|
||||
/* This would be setting N subregions per frame in this D3D12 mode where N = (height/blocksize) / K */
|
||||
supportedSliceStructuresBitMask |= PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_MULTI_ROWS;
|
||||
/* Assuming height/blocksize >= max_supported_slices, which is reported
|
||||
in PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME and should be checked by the client*/
|
||||
in PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME and should be checked by the client*/
|
||||
/* This would be setting N subregions per frame in this D3D12 mode where N = (height/blocksize) */
|
||||
supportedSliceStructuresBitMask |= PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_ROWS;
|
||||
/* This is ok, would be setting K rows per subregions in this D3D12 mode (and rounding the last one) */
|
||||
|
|
@ -346,15 +422,15 @@ d3d12_video_encode_supported_slice_structures(const D3D12_VIDEO_ENCODER_CODEC &c
|
|||
capDataSubregionLayout.SubregionMode =
|
||||
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_ROWS_PER_SUBREGION;
|
||||
hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE,
|
||||
&capDataSubregionLayout,
|
||||
sizeof(capDataSubregionLayout));
|
||||
&capDataSubregionLayout,
|
||||
sizeof(capDataSubregionLayout));
|
||||
if (FAILED(hr)) {
|
||||
debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
|
||||
} else if (capDataSubregionLayout.IsSupported) {
|
||||
/* This would be setting K rows per subregions in this D3D12 mode */
|
||||
supportedSliceStructuresBitMask |= PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_MULTI_ROWS;
|
||||
/* Assuming height/blocksize >= max_supported_slices, which is reported
|
||||
in PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME and should be checked by the client*/
|
||||
in PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME and should be checked by the client*/
|
||||
/* This would be setting 1 row per subregion in this D3D12 mode */
|
||||
supportedSliceStructuresBitMask |= PIPE_VIDEO_CAP_SLICE_STRUCTURE_EQUAL_ROWS;
|
||||
/* This is ok, would be setting K rows per subregions in this D3D12 mode (and rounding the last one) */
|
||||
|
|
@ -366,43 +442,49 @@ d3d12_video_encode_supported_slice_structures(const D3D12_VIDEO_ENCODER_CODEC &c
|
|||
|
||||
/*capDataSubregionLayout.SubregionMode = D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_BYTES_PER_SUBREGION;
|
||||
hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE,
|
||||
&capDataSubregionLayout,
|
||||
sizeof(capDataSubregionLayout));
|
||||
&capDataSubregionLayout,
|
||||
sizeof(capDataSubregionLayout));
|
||||
if (FAILED(hr)) {
|
||||
debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
|
||||
} else if (capDataSubregionLayout.IsSupported) {
|
||||
supportedSliceStructuresBitMask |= PIPE_VIDEO_CAP_SLICE_STRUCTURE_MAX_SLICE_SIZE;
|
||||
}*/
|
||||
}*/
|
||||
|
||||
return supportedSliceStructuresBitMask;
|
||||
}
|
||||
|
||||
static bool
|
||||
d3d12_video_encode_max_supported_slices(const D3D12_VIDEO_ENCODER_CODEC &argTargetCodec,
|
||||
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC maxResolution,
|
||||
DXGI_FORMAT encodeFormat,
|
||||
uint32_t &outMaxSlices,
|
||||
ID3D12VideoDevice3 *pD3D12VideoDevice,
|
||||
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT codecSupport)
|
||||
d3d12_video_encode_support_caps(const D3D12_VIDEO_ENCODER_CODEC &argTargetCodec,
|
||||
D3D12_VIDEO_ENCODER_PICTURE_RESOLUTION_DESC maxResolution,
|
||||
DXGI_FORMAT encodeFormat,
|
||||
ID3D12VideoDevice3 *pD3D12VideoDevice,
|
||||
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT codecSupport,
|
||||
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE requestedSliceMode,
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 &capEncoderSupportData1,
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLUTION_SUPPORT_LIMITS &resolutionDepCaps)
|
||||
{
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT capEncoderSupportData = {};
|
||||
capEncoderSupportData.NodeIndex = 0;
|
||||
capEncoderSupportData.Codec = argTargetCodec;
|
||||
capEncoderSupportData.InputFormat = encodeFormat;
|
||||
capEncoderSupportData.RateControl = {};
|
||||
capEncoderSupportData.RateControl.Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
|
||||
capEncoderSupportData.RateControl.TargetFrameRate.Numerator = 60;
|
||||
capEncoderSupportData.RateControl.TargetFrameRate.Denominator = 1;
|
||||
capEncoderSupportData1 = {};
|
||||
capEncoderSupportData1.NodeIndex = 0;
|
||||
capEncoderSupportData1.Codec = argTargetCodec;
|
||||
capEncoderSupportData1.InputFormat = encodeFormat;
|
||||
capEncoderSupportData1.RateControl = {};
|
||||
capEncoderSupportData1.RateControl.Mode = D3D12_VIDEO_ENCODER_RATE_CONTROL_MODE_CQP;
|
||||
capEncoderSupportData1.RateControl.TargetFrameRate.Numerator = 60;
|
||||
capEncoderSupportData1.RateControl.TargetFrameRate.Denominator = 1;
|
||||
D3D12_VIDEO_ENCODER_RATE_CONTROL_CQP rcCqp = { 25, 25, 25 };
|
||||
capEncoderSupportData.RateControl.ConfigParams.pConfiguration_CQP = &rcCqp;
|
||||
capEncoderSupportData.RateControl.ConfigParams.DataSize = sizeof(rcCqp);
|
||||
capEncoderSupportData.IntraRefresh = D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE;
|
||||
capEncoderSupportData.ResolutionsListCount = 1;
|
||||
capEncoderSupportData.pResolutionList = &maxResolution;
|
||||
capEncoderSupportData.MaxReferenceFramesInDPB = 1;
|
||||
capEncoderSupportData.SubregionFrameEncoding =
|
||||
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME;
|
||||
|
||||
capEncoderSupportData1.RateControl.ConfigParams.pConfiguration_CQP = &rcCqp;
|
||||
capEncoderSupportData1.RateControl.ConfigParams.DataSize = sizeof(rcCqp);
|
||||
capEncoderSupportData1.IntraRefresh = D3D12_VIDEO_ENCODER_INTRA_REFRESH_MODE_NONE;
|
||||
capEncoderSupportData1.ResolutionsListCount = 1;
|
||||
capEncoderSupportData1.pResolutionList = &maxResolution;
|
||||
capEncoderSupportData1.MaxReferenceFramesInDPB = 1;
|
||||
D3D12_VIDEO_ENCODER_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_SLICES sliceData = { };
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
// Assume single tile for feature query support / entrypoint enumeration purposes
|
||||
D3D12_VIDEO_ENCODER_AV1_PICTURE_CONTROL_SUBREGIONS_LAYOUT_DATA_TILES tileData = { };
|
||||
tileData.ColCount = 1;
|
||||
tileData.RowCount = 1;
|
||||
#endif
|
||||
/*
|
||||
All codec structures must be declared outside the switch statement to be
|
||||
present in memory (stack scope) when calling CheckFeatureSupport below
|
||||
|
|
@ -415,18 +497,29 @@ d3d12_video_encode_max_supported_slices(const D3D12_VIDEO_ENCODER_CODEC &argTarg
|
|||
D3D12_VIDEO_ENCODER_LEVEL_TIER_CONSTRAINTS_HEVC hevcLvl = { };
|
||||
D3D12_VIDEO_ENCODER_SEQUENCE_GOP_STRUCTURE_HEVC hevcGop = { 1, 0, 0 };
|
||||
D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC hevcConfig = {};
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
D3D12_VIDEO_ENCODER_AV1_PROFILE av1prof = { };
|
||||
D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS av1Lvl = { };
|
||||
D3D12_VIDEO_ENCODER_AV1_SEQUENCE_STRUCTURE av1Gop = { 1, 0 };
|
||||
D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION av1Config = {};
|
||||
#endif
|
||||
switch (argTargetCodec) {
|
||||
case D3D12_VIDEO_ENCODER_CODEC_H264:
|
||||
{
|
||||
// assert(codecSupport.pH264Support); // Fill this in caller if ever used
|
||||
capEncoderSupportData.SuggestedProfile.pH264Profile = &h264prof;
|
||||
capEncoderSupportData.SuggestedProfile.DataSize = sizeof(h264prof);
|
||||
capEncoderSupportData.SuggestedLevel.pH264LevelSetting = &h264lvl;
|
||||
capEncoderSupportData.SuggestedLevel.DataSize = sizeof(h264lvl);
|
||||
capEncoderSupportData.CodecGopSequence.pH264GroupOfPictures = &h264Gop;
|
||||
capEncoderSupportData.CodecGopSequence.DataSize = sizeof(h264Gop);
|
||||
capEncoderSupportData.CodecConfiguration.DataSize = sizeof(h264Config);
|
||||
capEncoderSupportData.CodecConfiguration.pH264Config = &h264Config;
|
||||
capEncoderSupportData1.SuggestedProfile.pH264Profile = &h264prof;
|
||||
capEncoderSupportData1.SuggestedProfile.DataSize = sizeof(h264prof);
|
||||
capEncoderSupportData1.SuggestedLevel.pH264LevelSetting = &h264lvl;
|
||||
capEncoderSupportData1.SuggestedLevel.DataSize = sizeof(h264lvl);
|
||||
capEncoderSupportData1.CodecGopSequence.pH264GroupOfPictures = &h264Gop;
|
||||
capEncoderSupportData1.CodecGopSequence.DataSize = sizeof(h264Gop);
|
||||
capEncoderSupportData1.CodecConfiguration.DataSize = sizeof(h264Config);
|
||||
capEncoderSupportData1.CodecConfiguration.pH264Config = &h264Config;
|
||||
capEncoderSupportData1.SubregionFrameEncoding = requestedSliceMode;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
capEncoderSupportData1.SubregionFrameEncodingData.DataSize = sizeof(sliceData);
|
||||
capEncoderSupportData1.SubregionFrameEncodingData.pSlicesPartition_H264 = &sliceData;
|
||||
#endif
|
||||
} break;
|
||||
|
||||
case D3D12_VIDEO_ENCODER_CODEC_HEVC:
|
||||
|
|
@ -446,16 +539,56 @@ d3d12_video_encode_max_supported_slices(const D3D12_VIDEO_ENCODER_CODEC &argTarg
|
|||
if ((codecSupport.pHEVCSupport->SupportFlags & D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT_HEVC_FLAG_ASYMETRIC_MOTION_PARTITION_REQUIRED) != 0)
|
||||
hevcConfig.ConfigurationFlags |= D3D12_VIDEO_ENCODER_CODEC_CONFIGURATION_HEVC_FLAG_USE_ASYMETRIC_MOTION_PARTITION;
|
||||
|
||||
capEncoderSupportData.SuggestedProfile.pHEVCProfile = &hevcprof;
|
||||
capEncoderSupportData.SuggestedProfile.DataSize = sizeof(hevcprof);
|
||||
capEncoderSupportData.SuggestedLevel.pHEVCLevelSetting = &hevcLvl;
|
||||
capEncoderSupportData.SuggestedLevel.DataSize = sizeof(hevcLvl);
|
||||
capEncoderSupportData.CodecGopSequence.pHEVCGroupOfPictures = &hevcGop;
|
||||
capEncoderSupportData.CodecGopSequence.DataSize = sizeof(hevcGop);
|
||||
capEncoderSupportData.CodecConfiguration.DataSize = sizeof(hevcConfig);
|
||||
capEncoderSupportData.CodecConfiguration.pHEVCConfig = &hevcConfig;
|
||||
capEncoderSupportData1.SuggestedProfile.pHEVCProfile = &hevcprof;
|
||||
capEncoderSupportData1.SuggestedProfile.DataSize = sizeof(hevcprof);
|
||||
capEncoderSupportData1.SuggestedLevel.pHEVCLevelSetting = &hevcLvl;
|
||||
capEncoderSupportData1.SuggestedLevel.DataSize = sizeof(hevcLvl);
|
||||
capEncoderSupportData1.CodecGopSequence.pHEVCGroupOfPictures = &hevcGop;
|
||||
capEncoderSupportData1.CodecGopSequence.DataSize = sizeof(hevcGop);
|
||||
capEncoderSupportData1.CodecConfiguration.DataSize = sizeof(hevcConfig);
|
||||
capEncoderSupportData1.CodecConfiguration.pHEVCConfig = &hevcConfig;
|
||||
capEncoderSupportData1.SubregionFrameEncoding = requestedSliceMode;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
capEncoderSupportData1.SubregionFrameEncodingData.DataSize = sizeof(sliceData);
|
||||
capEncoderSupportData1.SubregionFrameEncodingData.pSlicesPartition_HEVC = &sliceData;
|
||||
#endif
|
||||
} break;
|
||||
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
case D3D12_VIDEO_ENCODER_CODEC_AV1:
|
||||
{
|
||||
capEncoderSupportData1.SuggestedProfile.pAV1Profile = &av1prof;
|
||||
capEncoderSupportData1.SuggestedProfile.DataSize = sizeof(av1prof);
|
||||
capEncoderSupportData1.SuggestedLevel.pAV1LevelSetting = &av1Lvl;
|
||||
capEncoderSupportData1.SuggestedLevel.DataSize = sizeof(av1Lvl);
|
||||
capEncoderSupportData1.CodecGopSequence.pAV1SequenceStructure = &av1Gop;
|
||||
capEncoderSupportData1.CodecGopSequence.DataSize = sizeof(av1Gop);
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT capCodecConfigData = { };
|
||||
capCodecConfigData.NodeIndex = 0;
|
||||
capCodecConfigData.Codec = D3D12_VIDEO_ENCODER_CODEC_AV1;
|
||||
capCodecConfigData.Profile.pAV1Profile = &av1prof;
|
||||
capCodecConfigData.Profile.DataSize = sizeof(av1prof);
|
||||
D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT av1CodecSupport = { };
|
||||
capCodecConfigData.CodecSupportLimits.pAV1Support = &av1CodecSupport;
|
||||
capCodecConfigData.CodecSupportLimits.DataSize = sizeof(av1CodecSupport);
|
||||
HRESULT hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, &capCodecConfigData, sizeof(capCodecConfigData));
|
||||
if (FAILED(hr)) {
|
||||
debug_printf("CheckFeatureSupport D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT failed with HR %x\n", hr);
|
||||
return false;
|
||||
} else if (!capCodecConfigData.IsSupported) {
|
||||
debug_printf("CheckFeatureSupport D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT IsSupported is false\n");
|
||||
return false;
|
||||
}
|
||||
av1Config.OrderHintBitsMinus1 = 7;
|
||||
av1Config.FeatureFlags = av1CodecSupport.RequiredFeatureFlags;
|
||||
capEncoderSupportData1.CodecConfiguration.DataSize = sizeof(av1Config);
|
||||
capEncoderSupportData1.CodecConfiguration.pAV1Config = &av1Config;
|
||||
capEncoderSupportData1.SubregionFrameEncoding = requestedSliceMode;
|
||||
capEncoderSupportData1.SubregionFrameEncodingData.DataSize = sizeof(tileData);
|
||||
capEncoderSupportData1.SubregionFrameEncodingData.pTilesPartition_AV1 = &tileData;
|
||||
|
||||
} break;
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
unreachable("Unsupported D3D12_VIDEO_ENCODER_CODEC");
|
||||
|
|
@ -463,25 +596,57 @@ d3d12_video_encode_max_supported_slices(const D3D12_VIDEO_ENCODER_CODEC &argTarg
|
|||
}
|
||||
|
||||
// prepare inout storage for the resolution dependent result.
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLUTION_SUPPORT_LIMITS resolutionDepCaps = {};
|
||||
capEncoderSupportData.pResolutionDependentSupport = &resolutionDepCaps;
|
||||
resolutionDepCaps = {};
|
||||
capEncoderSupportData1.pResolutionDependentSupport = &resolutionDepCaps;
|
||||
|
||||
HRESULT hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_SUPPORT,
|
||||
&capEncoderSupportData,
|
||||
sizeof(capEncoderSupportData));
|
||||
HRESULT hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1,
|
||||
&capEncoderSupportData1,
|
||||
sizeof(capEncoderSupportData1));
|
||||
if (FAILED(hr)) {
|
||||
debug_printf("CheckFeatureSupport failed with HR %x\n", hr);
|
||||
return false;
|
||||
} else {
|
||||
bool configSupported =
|
||||
(((capEncoderSupportData.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_GENERAL_SUPPORT_OK) != 0) &&
|
||||
(capEncoderSupportData.ValidationFlags == D3D12_VIDEO_ENCODER_VALIDATION_FLAG_NONE));
|
||||
debug_printf("CheckFeatureSupport D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1 failed with HR %x\n", hr);
|
||||
debug_printf("Falling back to check previous query version D3D12_FEATURE_VIDEO_ENCODER_SUPPORT...\n");
|
||||
|
||||
outMaxSlices = resolutionDepCaps.MaxSubregionsNumber;
|
||||
return configSupported;
|
||||
// D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 extends D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT
|
||||
// in a binary compatible way, so just cast it and try with the older query D3D12_FEATURE_VIDEO_ENCODER_SUPPORT
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT * casted_down_cap_data = reinterpret_cast<D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT*>(&capEncoderSupportData1);
|
||||
hr = pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_SUPPORT,
|
||||
casted_down_cap_data,
|
||||
sizeof(D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT));
|
||||
if (FAILED(hr)) {
|
||||
debug_printf("CheckFeatureSupport D3D12_FEATURE_VIDEO_ENCODER_SUPPORT failed with HR %x\n", hr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool configSupported =
|
||||
(((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_GENERAL_SUPPORT_OK) != 0) &&
|
||||
(capEncoderSupportData1.ValidationFlags == D3D12_VIDEO_ENCODER_VALIDATION_FLAG_NONE));
|
||||
|
||||
return configSupported;
|
||||
}
|
||||
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
bool
|
||||
static d3d12_video_encode_get_av1_codec_support ( const D3D12_VIDEO_ENCODER_CODEC &argCodec,
|
||||
const D3D12_VIDEO_ENCODER_PROFILE_DESC &argTargetProfile,
|
||||
ID3D12VideoDevice3 *pD3D12VideoDevice,
|
||||
D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT &av1Support)
|
||||
{
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT capCodecConfigData = { };
|
||||
capCodecConfigData.NodeIndex = 0;
|
||||
capCodecConfigData.Codec = D3D12_VIDEO_ENCODER_CODEC_AV1;
|
||||
capCodecConfigData.Profile = argTargetProfile;
|
||||
capCodecConfigData.CodecSupportLimits.pAV1Support = &av1Support;
|
||||
capCodecConfigData.CodecSupportLimits.DataSize = sizeof(D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT);
|
||||
if(SUCCEEDED(pD3D12VideoDevice->CheckFeatureSupport(D3D12_FEATURE_VIDEO_ENCODER_CODEC_CONFIGURATION_SUPPORT, &capCodecConfigData, sizeof(capCodecConfigData)))
|
||||
&& capCodecConfigData.IsSupported) {
|
||||
return true;
|
||||
}
|
||||
|
||||
memset(&av1Support, 0, sizeof(D3D12_VIDEO_ENCODER_AV1_CODEC_CONFIGURATION_SUPPORT));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
static d3d12_video_encode_get_hevc_codec_support ( const D3D12_VIDEO_ENCODER_CODEC &argCodec,
|
||||
|
|
@ -567,7 +732,8 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
|
|||
uint32_t &maxSlices,
|
||||
uint32_t &supportedSliceStructures,
|
||||
uint32_t &maxReferencesPerFrame,
|
||||
struct d3d12_encode_codec_support& codecSupport)
|
||||
struct d3d12_encode_codec_support& codecSupport,
|
||||
uint32_t &isRCMaxFrameSizeSupported)
|
||||
{
|
||||
ComPtr<ID3D12VideoDevice3> spD3D12VideoDevice;
|
||||
struct d3d12_screen *pD3D12Screen = (struct d3d12_screen *) pscreen;
|
||||
|
|
@ -628,15 +794,24 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
|
|||
profile,
|
||||
level,
|
||||
spD3D12VideoDevice.Get());
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 capEncoderSupportData1;
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLUTION_SUPPORT_LIMITS resolutionDepCaps;
|
||||
supportsProfile = supportsProfile && d3d12_video_encode_support_caps(codecDesc,
|
||||
maxRes,
|
||||
encodeFormat,
|
||||
spD3D12VideoDevice.Get(),
|
||||
d3d12_codec_support,
|
||||
(supportedSliceStructures == PIPE_VIDEO_CAP_SLICE_STRUCTURE_NONE) ?
|
||||
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME
|
||||
: D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME,
|
||||
capEncoderSupportData1,
|
||||
resolutionDepCaps);
|
||||
if (supportedSliceStructures == PIPE_VIDEO_CAP_SLICE_STRUCTURE_NONE)
|
||||
maxSlices = 0;
|
||||
else
|
||||
supportsProfile = supportsProfile && d3d12_video_encode_max_supported_slices(codecDesc,
|
||||
maxRes,
|
||||
encodeFormat,
|
||||
maxSlices,
|
||||
spD3D12VideoDevice.Get(),
|
||||
d3d12_codec_support);
|
||||
maxSlices = resolutionDepCaps.MaxSubregionsNumber;
|
||||
|
||||
isRCMaxFrameSizeSupported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_MAX_FRAME_SIZE_AVAILABLE) != 0) ? 1 : 0;
|
||||
maxReferencesPerFrame =
|
||||
d3d12_video_encode_supported_references_per_frame_structures(codecDesc,
|
||||
profile,
|
||||
|
|
@ -782,18 +957,275 @@ d3d12_has_video_encode_support(struct pipe_screen *pscreen,
|
|||
supportsProfile = supportsProfile &&
|
||||
d3d12_video_encode_supported_resolution_range(codecDesc, minRes, maxRes, spD3D12VideoDevice.Get());
|
||||
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 capEncoderSupportData1;
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLUTION_SUPPORT_LIMITS resolutionDepCaps;
|
||||
supportsProfile = supportsProfile && d3d12_video_encode_support_caps(codecDesc,
|
||||
maxRes,
|
||||
encodeFormat,
|
||||
spD3D12VideoDevice.Get(),
|
||||
d3d12_codec_support,
|
||||
(supportedSliceStructures == PIPE_VIDEO_CAP_SLICE_STRUCTURE_NONE) ?
|
||||
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME
|
||||
: D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_PARTITIONING_SUBREGIONS_PER_FRAME,
|
||||
capEncoderSupportData1,
|
||||
resolutionDepCaps);
|
||||
if (supportedSliceStructures == PIPE_VIDEO_CAP_SLICE_STRUCTURE_NONE)
|
||||
maxSlices = 0;
|
||||
else
|
||||
supportsProfile = supportsProfile && d3d12_video_encode_max_supported_slices(codecDesc,
|
||||
maxRes,
|
||||
encodeFormat,
|
||||
maxSlices,
|
||||
spD3D12VideoDevice.Get(),
|
||||
d3d12_codec_support);
|
||||
maxSlices = resolutionDepCaps.MaxSubregionsNumber;
|
||||
isRCMaxFrameSizeSupported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_MAX_FRAME_SIZE_AVAILABLE) != 0) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
case PIPE_VIDEO_PROFILE_AV1_MAIN:
|
||||
{
|
||||
D3D12_VIDEO_ENCODER_PROFILE_DESC profDesc = {};
|
||||
D3D12_VIDEO_ENCODER_AV1_PROFILE profAV1 =
|
||||
d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_av1(profile);
|
||||
profDesc.DataSize = sizeof(profAV1);
|
||||
profDesc.pAV1Profile = &profAV1;
|
||||
D3D12_VIDEO_ENCODER_CODEC codecDesc = d3d12_video_encoder_convert_codec_to_d3d12_enc_codec(profile);
|
||||
D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS minLvlSettingAV1 = { };
|
||||
D3D12_VIDEO_ENCODER_AV1_LEVEL_TIER_CONSTRAINTS maxLvlSettingAV1 = { };
|
||||
D3D12_VIDEO_ENCODER_LEVEL_SETTING minLvl = {};
|
||||
D3D12_VIDEO_ENCODER_LEVEL_SETTING maxLvl = {};
|
||||
minLvl.pAV1LevelSetting = &minLvlSettingAV1;
|
||||
minLvl.DataSize = sizeof(minLvlSettingAV1);
|
||||
maxLvl.pAV1LevelSetting = &maxLvlSettingAV1;
|
||||
maxLvl.DataSize = sizeof(maxLvlSettingAV1);
|
||||
if (d3d12_video_encode_max_supported_level_for_profile(codecDesc,
|
||||
profDesc,
|
||||
minLvl,
|
||||
maxLvl,
|
||||
spD3D12VideoDevice.Get())) {
|
||||
d3d12_video_encoder_convert_d3d12_to_spec_level_av1(maxLvlSettingAV1.Level, maxLvlSpec);
|
||||
|
||||
D3D12_VIDEO_ENCODER_PROFILE_DESC d3d12_profile;
|
||||
d3d12_profile.pAV1Profile = &profAV1;
|
||||
d3d12_profile.DataSize = sizeof(profAV1);
|
||||
|
||||
maxReferencesPerFrame =
|
||||
d3d12_video_encode_supported_references_per_frame_structures(codecDesc,
|
||||
d3d12_profile,
|
||||
spD3D12VideoDevice.Get());
|
||||
|
||||
supportsProfile = d3d12_video_encode_get_av1_codec_support(codecDesc,
|
||||
profDesc,
|
||||
spD3D12VideoDevice.Get(),
|
||||
codecSupport.av1_support.d3d12_caps);
|
||||
if (supportsProfile) {
|
||||
d3d12_codec_support.DataSize = sizeof(codecSupport.av1_support.d3d12_caps);
|
||||
d3d12_codec_support.pAV1Support = &codecSupport.av1_support.d3d12_caps;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK) != 0)
|
||||
codecSupport.av1_support.features.bits.support_128x128_superblock = PIPE_ENC_FEATURE_SUPPORTED;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.RequiredFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_128x128_SUPERBLOCK) != 0)
|
||||
codecSupport.av1_support.features.bits.support_128x128_superblock = (PIPE_ENC_FEATURE_SUPPORTED | PIPE_ENC_FEATURE_REQUIRED);
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FILTER_INTRA) != 0)
|
||||
codecSupport.av1_support.features.bits.support_filter_intra = PIPE_ENC_FEATURE_SUPPORTED;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.RequiredFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FILTER_INTRA) != 0)
|
||||
codecSupport.av1_support.features.bits.support_filter_intra = (PIPE_ENC_FEATURE_SUPPORTED | PIPE_ENC_FEATURE_REQUIRED);
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_EDGE_FILTER) != 0)
|
||||
codecSupport.av1_support.features.bits.support_intra_edge_filter = PIPE_ENC_FEATURE_SUPPORTED;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.RequiredFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_EDGE_FILTER) != 0)
|
||||
codecSupport.av1_support.features.bits.support_intra_edge_filter = (PIPE_ENC_FEATURE_SUPPORTED | PIPE_ENC_FEATURE_REQUIRED);
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTERINTRA_COMPOUND) != 0)
|
||||
codecSupport.av1_support.features.bits.support_interintra_compound = PIPE_ENC_FEATURE_SUPPORTED;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.RequiredFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTERINTRA_COMPOUND) != 0)
|
||||
codecSupport.av1_support.features.bits.support_interintra_compound = (PIPE_ENC_FEATURE_SUPPORTED | PIPE_ENC_FEATURE_REQUIRED);
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MASKED_COMPOUND) != 0)
|
||||
codecSupport.av1_support.features.bits.support_masked_compound = PIPE_ENC_FEATURE_SUPPORTED;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.RequiredFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_MASKED_COMPOUND) != 0)
|
||||
codecSupport.av1_support.features.bits.support_masked_compound = (PIPE_ENC_FEATURE_SUPPORTED | PIPE_ENC_FEATURE_REQUIRED);
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION) != 0)
|
||||
codecSupport.av1_support.features.bits.support_warped_motion = PIPE_ENC_FEATURE_SUPPORTED;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.RequiredFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_WARPED_MOTION) != 0)
|
||||
codecSupport.av1_support.features.bits.support_warped_motion = (PIPE_ENC_FEATURE_SUPPORTED | PIPE_ENC_FEATURE_REQUIRED);
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING) != 0)
|
||||
codecSupport.av1_support.features.bits.support_palette_mode = PIPE_ENC_FEATURE_SUPPORTED;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.RequiredFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_PALETTE_ENCODING) != 0)
|
||||
codecSupport.av1_support.features.bits.support_palette_mode = (PIPE_ENC_FEATURE_SUPPORTED | PIPE_ENC_FEATURE_REQUIRED);
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DUAL_FILTER) != 0)
|
||||
codecSupport.av1_support.features.bits.support_dual_filter = PIPE_ENC_FEATURE_SUPPORTED;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.RequiredFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_DUAL_FILTER) != 0)
|
||||
codecSupport.av1_support.features.bits.support_dual_filter = (PIPE_ENC_FEATURE_SUPPORTED | PIPE_ENC_FEATURE_REQUIRED);
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_JNT_COMP) != 0)
|
||||
codecSupport.av1_support.features.bits.support_jnt_comp = PIPE_ENC_FEATURE_SUPPORTED;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.RequiredFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_JNT_COMP) != 0)
|
||||
codecSupport.av1_support.features.bits.support_jnt_comp = (PIPE_ENC_FEATURE_SUPPORTED | PIPE_ENC_FEATURE_REQUIRED);
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS) != 0)
|
||||
codecSupport.av1_support.features.bits.support_ref_frame_mvs = PIPE_ENC_FEATURE_SUPPORTED;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.RequiredFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_FRAME_REFERENCE_MOTION_VECTORS) != 0)
|
||||
codecSupport.av1_support.features.bits.support_ref_frame_mvs = (PIPE_ENC_FEATURE_SUPPORTED | PIPE_ENC_FEATURE_REQUIRED);
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SUPER_RESOLUTION) != 0)
|
||||
codecSupport.av1_support.features.bits.support_superres = PIPE_ENC_FEATURE_SUPPORTED;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.RequiredFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_SUPER_RESOLUTION) != 0)
|
||||
codecSupport.av1_support.features.bits.support_superres = (PIPE_ENC_FEATURE_SUPPORTED | PIPE_ENC_FEATURE_REQUIRED);
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER) != 0)
|
||||
codecSupport.av1_support.features.bits.support_restoration = PIPE_ENC_FEATURE_SUPPORTED;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.RequiredFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_LOOP_RESTORATION_FILTER) != 0)
|
||||
codecSupport.av1_support.features.bits.support_restoration = (PIPE_ENC_FEATURE_SUPPORTED | PIPE_ENC_FEATURE_REQUIRED);
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY) != 0)
|
||||
codecSupport.av1_support.features.bits.support_allow_intrabc = PIPE_ENC_FEATURE_SUPPORTED;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.RequiredFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_INTRA_BLOCK_COPY) != 0)
|
||||
codecSupport.av1_support.features.bits.support_allow_intrabc = (PIPE_ENC_FEATURE_SUPPORTED | PIPE_ENC_FEATURE_REQUIRED);
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CDEF_FILTERING) != 0)
|
||||
codecSupport.av1_support.features.bits.support_cdef_channel_strength = PIPE_ENC_FEATURE_SUPPORTED;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.RequiredFeatureFlags & D3D12_VIDEO_ENCODER_AV1_FEATURE_FLAG_CDEF_FILTERING) != 0)
|
||||
codecSupport.av1_support.features.bits.support_cdef_channel_strength = (PIPE_ENC_FEATURE_SUPPORTED | PIPE_ENC_FEATURE_REQUIRED);
|
||||
|
||||
// pipe_av1_enc_cap_features_ext1
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedInterpolationFilters & D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_EIGHTTAP) != 0)
|
||||
codecSupport.av1_support.features_ext1.bits.interpolation_filter |= PIPE_VIDEO_CAP_ENC_AV1_INTERPOLATION_FILTER_EIGHT_TAP;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedInterpolationFilters & D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_EIGHTTAP_SMOOTH) != 0)
|
||||
codecSupport.av1_support.features_ext1.bits.interpolation_filter |= PIPE_VIDEO_CAP_ENC_AV1_INTERPOLATION_FILTER_EIGHT_TAP_SMOOTH;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedInterpolationFilters & D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_EIGHTTAP_SHARP) != 0)
|
||||
codecSupport.av1_support.features_ext1.bits.interpolation_filter |= PIPE_VIDEO_CAP_ENC_AV1_INTERPOLATION_FILTER_EIGHT_TAP_SHARP;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedInterpolationFilters & D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_BILINEAR) != 0)
|
||||
codecSupport.av1_support.features_ext1.bits.interpolation_filter |= PIPE_VIDEO_CAP_ENC_AV1_INTERPOLATION_FILTER_BILINEAR;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedInterpolationFilters & D3D12_VIDEO_ENCODER_AV1_INTERPOLATION_FILTERS_FLAG_SWITCHABLE) != 0)
|
||||
codecSupport.av1_support.features_ext1.bits.interpolation_filter |= PIPE_VIDEO_CAP_ENC_AV1_INTERPOLATION_FILTER_SWITCHABLE;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedSegmentationModes & D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_DISABLED) != 0)
|
||||
codecSupport.av1_support.features_ext1.bits.segment_feature_support = 0;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedSegmentationModes & D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_Q) != 0)
|
||||
codecSupport.av1_support.features_ext1.bits.segment_feature_support |= 0x1;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedSegmentationModes & D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_LF_Y_V) != 0)
|
||||
codecSupport.av1_support.features_ext1.bits.segment_feature_support |= 0x2;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedSegmentationModes & D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_LF_Y_H) != 0)
|
||||
codecSupport.av1_support.features_ext1.bits.segment_feature_support |= 0x4;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedSegmentationModes & D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_LF_U) != 0)
|
||||
codecSupport.av1_support.features_ext1.bits.segment_feature_support |= 0x8;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedSegmentationModes & D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_LF_V) != 0)
|
||||
codecSupport.av1_support.features_ext1.bits.segment_feature_support |= 0x10;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedSegmentationModes & D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_REF_FRAME) != 0)
|
||||
codecSupport.av1_support.features_ext1.bits.segment_feature_support |= 0x20;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedSegmentationModes & D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_SKIP) != 0)
|
||||
codecSupport.av1_support.features_ext1.bits.segment_feature_support |= 0x40;
|
||||
|
||||
if ((codecSupport.av1_support.d3d12_caps.SupportedSegmentationModes & D3D12_VIDEO_ENCODER_AV1_SEGMENTATION_MODE_FLAG_ALT_GLOBALMV) != 0)
|
||||
codecSupport.av1_support.features_ext1.bits.segment_feature_support |= 0x80;
|
||||
|
||||
// pipe_av1_enc_cap_features_ext2
|
||||
codecSupport.av1_support.features_ext2.bits.obu_size_bytes_minus1 = 4 - 1; // Default 4 bytes (reported minus 1)
|
||||
|
||||
// tx_mode_support query cap
|
||||
// Disregarding the VA mask definition for tx_mode_support, some apps use it as directly the value to be used
|
||||
// in VAEncPictureParameterBufferAV1.mode_control_flags.bits.tx_mode
|
||||
// So only return one based on preference order / driver support
|
||||
{
|
||||
// Check the mode is supported for all frame types, then report by preference priority
|
||||
|
||||
bool tx_mode_select_supported = true;
|
||||
for(uint8_t i = D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME; i <= D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_SWITCH_FRAME; i++)
|
||||
tx_mode_select_supported &= ((codecSupport.av1_support.d3d12_caps.SupportedTxModes[i] & D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAG_SELECT) != 0);
|
||||
|
||||
if (tx_mode_select_supported) {
|
||||
// Workaround for apps consuming the tx_mode_support cap directly as the tx_mode param to be used
|
||||
codecSupport.av1_support.features_ext2.bits.tx_mode_support = std::log2(static_cast<uint32_t>(PIPE_VIDEO_CAP_ENC_AV1_TX_MODE_SELECT));
|
||||
} else {
|
||||
bool tx_mode_largest_supported = true;
|
||||
for(uint8_t i = D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME; i <= D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_SWITCH_FRAME; i++)
|
||||
tx_mode_largest_supported &= ((codecSupport.av1_support.d3d12_caps.SupportedTxModes[i] & D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAG_LARGEST) != 0);
|
||||
|
||||
if (tx_mode_largest_supported) {
|
||||
// Workaround for apps consuming the tx_mode_support cap directly as the tx_mode param to be used.
|
||||
codecSupport.av1_support.features_ext2.bits.tx_mode_support = std::log2(static_cast<uint32_t>(PIPE_VIDEO_CAP_ENC_AV1_TX_MODE_LARGEST));
|
||||
} else {
|
||||
bool tx_mode_only_4x4_supported = true;
|
||||
for(uint8_t i = D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_KEY_FRAME; i <= D3D12_VIDEO_ENCODER_AV1_FRAME_TYPE_SWITCH_FRAME; i++)
|
||||
tx_mode_only_4x4_supported &= ((codecSupport.av1_support.d3d12_caps.SupportedTxModes[i] & D3D12_VIDEO_ENCODER_AV1_TX_MODE_FLAG_ONLY4x4) != 0);
|
||||
|
||||
if (tx_mode_only_4x4_supported) {
|
||||
// Workaround for apps consuming the tx_mode_support cap directly as the tx_mode param to be used.
|
||||
codecSupport.av1_support.features_ext2.bits.tx_mode_support = std::log2(static_cast<uint32_t>(PIPE_VIDEO_CAP_ENC_AV1_TX_MODE_ONLY_4X4));
|
||||
} else {
|
||||
assert(false); // As per d3d12 spec, driver must support at least one default mode for all frame types
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
supportsProfile = supportsProfile &&
|
||||
d3d12_video_encode_supported_resolution_range(codecDesc, minRes, maxRes, spD3D12VideoDevice.Get());
|
||||
|
||||
uint32_t tile_size_bytes_minus1 = 0;
|
||||
d3d12_video_encode_supported_tile_structures(codecDesc,
|
||||
profDesc,
|
||||
maxLvl,
|
||||
spD3D12VideoDevice.Get(),
|
||||
maxRes,
|
||||
supportedSliceStructures, // out
|
||||
tile_size_bytes_minus1 // out
|
||||
);
|
||||
// Cannot pass pipe 2 bit-field as reference, use aux variable instead.
|
||||
codecSupport.av1_support.features_ext2.bits.tile_size_bytes_minus1 = tile_size_bytes_minus1;
|
||||
|
||||
DXGI_FORMAT encodeFormat = d3d12_convert_pipe_video_profile_to_dxgi_format(profile);
|
||||
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 capEncoderSupportData1;
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_RESOLUTION_SUPPORT_LIMITS resolutionDepCaps;
|
||||
supportsProfile = supportsProfile && d3d12_video_encode_support_caps(codecDesc,
|
||||
maxRes,
|
||||
encodeFormat,
|
||||
spD3D12VideoDevice.Get(),
|
||||
d3d12_codec_support,
|
||||
(supportedSliceStructures == PIPE_VIDEO_CAP_SLICE_STRUCTURE_NONE) ?
|
||||
D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_FULL_FRAME
|
||||
: D3D12_VIDEO_ENCODER_FRAME_SUBREGION_LAYOUT_MODE_UNIFORM_GRID_PARTITION,
|
||||
capEncoderSupportData1,
|
||||
resolutionDepCaps);
|
||||
if (supportedSliceStructures == PIPE_VIDEO_CAP_SLICE_STRUCTURE_NONE)
|
||||
maxSlices = 0;
|
||||
else
|
||||
maxSlices = resolutionDepCaps.MaxSubregionsNumber;
|
||||
|
||||
codecSupport.av1_support.features_ext2.bits.max_tile_num_minus1 = maxSlices - 1;
|
||||
|
||||
isRCMaxFrameSizeSupported = ((capEncoderSupportData1.SupportFlags & D3D12_VIDEO_ENCODER_SUPPORT_FLAG_RATE_CONTROL_MAX_FRAME_SIZE_AVAILABLE) != 0) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
#endif
|
||||
default:
|
||||
supportsProfile = false;
|
||||
}
|
||||
|
|
@ -1087,6 +1519,7 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
|
|||
uint32_t maxSlices = 0u;
|
||||
uint32_t supportedSliceStructures = 0u;
|
||||
uint32_t maxReferencesPerFrame = 0u;
|
||||
uint32_t isRCMaxFrameSizeSupported = 0u;
|
||||
struct d3d12_encode_codec_support codec_specific_support;
|
||||
memset(&codec_specific_support, 0, sizeof(codec_specific_support));
|
||||
switch (param) {
|
||||
|
|
@ -1108,6 +1541,11 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
|
|||
case PIPE_VIDEO_CAP_ENC_HEVC_FEATURE_FLAGS:
|
||||
case PIPE_VIDEO_CAP_ENC_HEVC_BLOCK_SIZES:
|
||||
case PIPE_VIDEO_CAP_ENC_HEVC_PREDICTION_DIRECTION:
|
||||
case PIPE_VIDEO_CAP_ENC_AV1_FEATURE:
|
||||
case PIPE_VIDEO_CAP_ENC_AV1_FEATURE_EXT1:
|
||||
case PIPE_VIDEO_CAP_ENC_AV1_FEATURE_EXT2:
|
||||
case PIPE_VIDEO_CAP_ENC_SUPPORTS_TILE:
|
||||
case PIPE_VIDEO_CAP_ENC_SUPPORTS_MAX_FRAME_SIZE:
|
||||
{
|
||||
if (d3d12_has_video_encode_support(pscreen,
|
||||
profile,
|
||||
|
|
@ -1117,7 +1555,8 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
|
|||
maxSlices,
|
||||
supportedSliceStructures,
|
||||
maxReferencesPerFrame,
|
||||
codec_specific_support)) {
|
||||
codec_specific_support,
|
||||
isRCMaxFrameSizeSupported)) {
|
||||
|
||||
DXGI_FORMAT format = d3d12_convert_pipe_video_profile_to_dxgi_format(profile);
|
||||
auto pipeFmt = d3d12_get_pipe_format(format);
|
||||
|
|
@ -1141,6 +1580,8 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
|
|||
return supportedSliceStructures;
|
||||
} else if (param == PIPE_VIDEO_CAP_ENC_MAX_REFERENCES_PER_FRAME) {
|
||||
return maxReferencesPerFrame;
|
||||
} else if (param == PIPE_VIDEO_CAP_ENC_SUPPORTS_MAX_FRAME_SIZE) {
|
||||
return isRCMaxFrameSizeSupported;
|
||||
} else if (param == PIPE_VIDEO_CAP_ENC_HEVC_FEATURE_FLAGS) {
|
||||
/* get_video_param sets hevc_features.bits.config_supported = 1
|
||||
to distinguish between supported cap with all bits off and unsupported by driver
|
||||
|
|
@ -1154,8 +1595,21 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
|
|||
*/
|
||||
return codec_specific_support.hevc_support.hevc_block_sizes.value;
|
||||
} else if (param == PIPE_VIDEO_CAP_ENC_HEVC_PREDICTION_DIRECTION) {
|
||||
return codec_specific_support.hevc_support.prediction_direction;
|
||||
if (PIPE_VIDEO_FORMAT_HEVC == u_reduce_video_profile(profile))
|
||||
return codec_specific_support.hevc_support.prediction_direction;
|
||||
return 0;
|
||||
}
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
else if (param == PIPE_VIDEO_CAP_ENC_AV1_FEATURE) {
|
||||
return codec_specific_support.av1_support.features.value;
|
||||
} else if (param == PIPE_VIDEO_CAP_ENC_AV1_FEATURE_EXT1) {
|
||||
return codec_specific_support.av1_support.features_ext1.value;
|
||||
} else if (param == PIPE_VIDEO_CAP_ENC_AV1_FEATURE_EXT2) {
|
||||
return codec_specific_support.av1_support.features_ext2.value;
|
||||
} else if(param == PIPE_VIDEO_CAP_ENC_SUPPORTS_TILE) {
|
||||
return (profile == PIPE_VIDEO_PROFILE_AV1_MAIN) && (maxSlices != 0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -1170,8 +1624,6 @@ d3d12_screen_get_video_param_encode(struct pipe_screen *pscreen,
|
|||
return true;
|
||||
case PIPE_VIDEO_CAP_SUPPORTS_CONTIGUOUS_PLANES_MAP:
|
||||
return true;
|
||||
case PIPE_VIDEO_CAP_ENC_SUPPORTS_MAX_FRAME_SIZE:
|
||||
return true;
|
||||
case PIPE_VIDEO_CAP_ENC_QUALITY_LEVEL:
|
||||
/* VAEncMiscParameterBufferQualityLevel */
|
||||
return 1;
|
||||
|
|
@ -1228,6 +1680,9 @@ is_d3d12_video_encode_format_supported(struct pipe_screen *screen,
|
|||
{
|
||||
D3D12_VIDEO_ENCODER_PROFILE_H264 profH264 = {};
|
||||
D3D12_VIDEO_ENCODER_PROFILE_HEVC profHEVC = {};
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
D3D12_VIDEO_ENCODER_AV1_PROFILE profAV1 = {};
|
||||
#endif
|
||||
D3D12_FEATURE_DATA_VIDEO_ENCODER_INPUT_FORMAT capDataFmt = {};
|
||||
capDataFmt.NodeIndex = 0;
|
||||
capDataFmt.Codec = d3d12_video_encoder_convert_codec_to_d3d12_enc_codec(profile);
|
||||
|
|
@ -1245,6 +1700,14 @@ is_d3d12_video_encode_format_supported(struct pipe_screen *screen,
|
|||
capDataFmt.Profile.DataSize = sizeof(profHEVC);
|
||||
capDataFmt.Profile.pHEVCProfile = &profHEVC;
|
||||
} break;
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
case PIPE_VIDEO_FORMAT_AV1:
|
||||
{
|
||||
profAV1 = d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_av1(profile);
|
||||
capDataFmt.Profile.DataSize = sizeof(profAV1);
|
||||
capDataFmt.Profile.pAV1Profile = &profAV1;
|
||||
} break;
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
unreachable("Unsupported pipe_video_format");
|
||||
|
|
|
|||
|
|
@ -37,6 +37,12 @@
|
|||
#include <directx/d3d12video.h>
|
||||
#include <dxguids/dxguids.h>
|
||||
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
#else // leave this way so #if D3D12_PREVIEW_SDK_VERSION >= 711 is easily searchable later
|
||||
using D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT1 = D3D12_FEATURE_DATA_VIDEO_ENCODER_SUPPORT;
|
||||
constexpr D3D12_FEATURE_VIDEO D3D12_FEATURE_VIDEO_ENCODER_SUPPORT1 = D3D12_FEATURE_VIDEO_ENCODER_SUPPORT;
|
||||
#endif
|
||||
|
||||
#include <wrl/client.h>
|
||||
using Microsoft::WRL::ComPtr;
|
||||
|
||||
|
|
@ -81,6 +87,18 @@ const uint64_t D3D12_VIDEO_ENC_METADATA_BUFFERS_COUNT = debug_get_num_option("D3
|
|||
|
||||
constexpr unsigned int D3D12_VIDEO_H264_MB_IN_PIXELS = 16;
|
||||
|
||||
constexpr size_t D3D12_DEFAULT_COMPBIT_STAGING_SIZE = (1024 /*1K*/ * 1024/*1MB*/) * 8/*8 MB*/; // 8MB
|
||||
|
||||
/* If enabled, the D3D12 AV1 encoder will use always ...CONFIGURABLE_GRID_PARTITION mode */
|
||||
/* If disabled, the D3D12 AV1 encoder will try to use ...UNIFORM_GRID_PARTITION first and then fallback to ...CONFIGURABLE_GRID_PARTITION if not possible */
|
||||
const bool D3D12_VIDEO_FORCE_TILE_MODE = debug_get_bool_option("D3D12_VIDEO_FORCE_TILE_MODE", false);
|
||||
|
||||
/**
|
||||
* If enabled, the D3D12 AV1 encoder will insert a OBU_FRAME_HEADER with show_existing_frame = 1 after the current frame to show a previous
|
||||
* show_frame = 0 encoded frame as reference and used by the current frame
|
||||
*/
|
||||
const bool D3D12_VIDEO_AV1_INSERT_SHOW_EXISTING_FRAME_HEADER = debug_get_bool_option("D3D12_VIDEO_AV1_INSERT_SHOW_EXISTING_FRAME_HEADER", false);
|
||||
|
||||
enum d3d12_video_decode_config_specific_flags
|
||||
{
|
||||
d3d12_video_decode_config_specific_flag_none = 0,
|
||||
|
|
@ -128,10 +146,25 @@ d3d12_video_encoder_convert_from_d3d12_level_h264(D3D12_VIDEO_ENCODER_LEVELS_H26
|
|||
void
|
||||
d3d12_video_encoder_convert_from_d3d12_level_hevc(D3D12_VIDEO_ENCODER_LEVELS_HEVC level12,
|
||||
uint32_t & specLevel);
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
void
|
||||
d3d12_video_encoder_convert_d3d12_to_spec_level_av1(D3D12_VIDEO_ENCODER_AV1_LEVELS level12,
|
||||
uint32_t & specLevel);
|
||||
void
|
||||
d3d12_video_encoder_convert_spec_to_d3d12_level_av1(uint32_t specLevel,
|
||||
D3D12_VIDEO_ENCODER_AV1_LEVELS& level12);
|
||||
void
|
||||
d3d12_video_encoder_convert_spec_to_d3d12_tier_av1(uint32_t specTier,
|
||||
D3D12_VIDEO_ENCODER_AV1_TIER & tier12);
|
||||
#endif
|
||||
D3D12_VIDEO_ENCODER_PROFILE_H264
|
||||
d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_h264(enum pipe_video_profile profile);
|
||||
D3D12_VIDEO_ENCODER_PROFILE_HEVC
|
||||
d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_hevc(enum pipe_video_profile profile);
|
||||
#if D3D12_PREVIEW_SDK_VERSION >= 711
|
||||
D3D12_VIDEO_ENCODER_AV1_PROFILE
|
||||
d3d12_video_encoder_convert_profile_to_d3d12_enc_profile_av1(enum pipe_video_profile profile);
|
||||
#endif
|
||||
D3D12_VIDEO_ENCODER_CODEC
|
||||
d3d12_video_encoder_convert_codec_to_d3d12_enc_codec(enum pipe_video_profile profile);
|
||||
GUID
|
||||
|
|
|
|||
|
|
@ -70,6 +70,16 @@ if with_gallium_d3d12_video
|
|||
'd3d12_video_dec_av1.cpp',
|
||||
'd3d12_video_dec_vp9.cpp',
|
||||
]
|
||||
|
||||
# // TODO: Remove this and #ifdef checks for AV1 encode when header version is release 6xx
|
||||
if dep_dxheaders.version().version_compare('>= 1.711.3')
|
||||
files_libd3d12 += [
|
||||
'd3d12_video_enc_av1.cpp',
|
||||
'd3d12_video_encoder_references_manager_av1.cpp',
|
||||
'd3d12_video_encoder_bitstream_builder_av1.cpp',
|
||||
]
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
is_xbox = target_machine.system().startswith('Gaming.Xbox')
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue