// Copyright 2020 yuzu Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include #include #include "common/common_funcs.h" #include "common/common_types.h" namespace Tegra { class GPU; namespace Decoder { struct Vp9FrameDimensions { s16 width{}; s16 height{}; s16 luma_pitch{}; s16 chroma_pitch{}; }; static_assert(sizeof(Vp9FrameDimensions) == 0x8, "Vp9 Vp9FrameDimensions is an invalid size"); enum FrameFlags : u32 { IsKeyFrame = 1 << 0, LastFrameIsKeyFrame = 1 << 1, FrameSizeChanged = 1 << 2, ErrorResilientMode = 1 << 3, LastShowFrame = 1 << 4, IntraOnly = 1 << 5, }; enum class MvJointType { MvJointZero = 0, /* Zero vector */ MvJointHnzvz = 1, /* Vert zero, hor nonzero */ MvJointHzvnz = 2, /* Hor zero, vert nonzero */ MvJointHnzvnz = 3, /* Both components nonzero */ }; enum class MvClassType { MvClass0 = 0, /* (0, 2] integer pel */ MvClass1 = 1, /* (2, 4] integer pel */ MvClass2 = 2, /* (4, 8] integer pel */ MvClass3 = 3, /* (8, 16] integer pel */ MvClass4 = 4, /* (16, 32] integer pel */ MvClass5 = 5, /* (32, 64] integer pel */ MvClass6 = 6, /* (64, 128] integer pel */ MvClass7 = 7, /* (128, 256] integer pel */ MvClass8 = 8, /* (256, 512] integer pel */ MvClass9 = 9, /* (512, 1024] integer pel */ MvClass10 = 10, /* (1024,2048] integer pel */ }; enum class BlockSize { Block4x4 = 0, Block4x8 = 1, Block8x4 = 2, Block8x8 = 3, Block8x16 = 4, Block16x8 = 5, Block16x16 = 6, Block16x32 = 7, Block32x16 = 8, Block32x32 = 9, Block32x64 = 10, Block64x32 = 11, Block64x64 = 12, BlockSizes = 13, BlockInvalid = BlockSizes }; enum class PredictionMode { DcPred = 0, // Average of above and left pixels VPred = 1, // Vertical HPred = 2, // Horizontal D45Pred = 3, // Directional 45 deg = round(arctan(1 / 1) * 180 / pi) D135Pred = 4, // Directional 135 deg = 180 - 45 D117Pred = 5, // Directional 117 deg = 180 - 63 D153Pred = 6, // Directional 153 deg = 180 - 27 D207Pred = 7, // Directional 207 deg = 180 + 27 D63Pred = 8, // Directional 63 deg = round(arctan(2 / 1) * 180 / pi) TmPred = 9, // True-motion NearestMv = 10, NearMv = 11, ZeroMv = 12, NewMv = 13, MbModeCount = 14 }; enum class TxSize { Tx4x4 = 0, // 4x4 transform Tx8x8 = 1, // 8x8 transform Tx16x16 = 2, // 16x16 transform Tx32x32 = 3, // 32x32 transform TxSizes = 4 }; enum class TxMode { Only4X4 = 0, // Only 4x4 transform used Allow8X8 = 1, // Allow block transform size up to 8x8 Allow16X16 = 2, // Allow block transform size up to 16x16 Allow32X32 = 3, // Allow block transform size up to 32x32 TxModeSelect = 4, // Transform specified for each block TxModes = 5 }; enum class reference_mode { SingleReference = 0, CompoundReference = 1, ReferenceModeSelect = 2, ReferenceModes = 3 }; struct Segmentation { u8 enabled{}; u8 update_map{}; u8 temporal_update{}; u8 abs_delta{}; std::array feature_mask{}; std::array, 8> feature_data{}; }; static_assert(sizeof(Segmentation) == 0x64, "Segmentation is an invalid size"); struct LoopFilter { u8 mode_ref_delta_enabled{}; std::array ref_deltas{}; std::array mode_deltas{}; }; static_assert(sizeof(LoopFilter) == 0x7, "LoopFilter is an invalid size"); struct Vp9EntropyProbs { std::array y_mode_prob{}; std::array partition_prob{}; std::array coef_probs{}; std::array switchable_interp_prob{}; std::array inter_mode_prob{}; std::array intra_inter_prob{}; std::array comp_inter_prob{}; std::array single_ref_prob{}; std::array comp_ref_prob{}; std::array tx_32x32_prob{}; std::array tx_16x16_prob{}; std::array tx_8x8_prob{}; std::array skip_probs{}; std::array joints{}; std::array sign{}; std::array classes{}; std::array class_0{}; std::array prob_bits{}; std::array class_0_fr{}; std::array fr{}; std::array class_0_hp{}; std::array high_precision{}; }; static_assert(sizeof(Vp9EntropyProbs) == 0x9F4, "Vp9EntropyProbs is an invalid size"); struct Vp9PictureInfo { bool is_key_frame{}; bool intra_only{}; bool last_frame_was_key{}; bool frame_size_changed{}; bool error_resilient_mode{}; bool last_frame_shown{}; bool show_frame{}; std::array ref_frame_sign_bias{}; s32 base_q_index{}; s32 y_dc_delta_q{}; s32 uv_dc_delta_q{}; s32 uv_ac_delta_q{}; bool lossless{}; s32 transform_mode{}; bool allow_high_precision_mv{}; s32 interp_filter{}; s32 reference_mode{}; s8 comp_fixed_ref{}; std::array comp_var_ref{}; s32 log2_tile_cols{}; s32 log2_tile_rows{}; bool segment_enabled{}; bool segment_map_update{}; bool segment_map_temporal_update{}; s32 segment_abs_delta{}; std::array segment_feature_enable{}; std::array, 8> segment_feature_data{}; bool mode_ref_delta_enabled{}; bool use_prev_in_find_mv_refs{}; std::array ref_deltas{}; std::array mode_deltas{}; Vp9EntropyProbs entropy{}; Vp9FrameDimensions frame_size{}; u8 first_level{}; u8 sharpness_level{}; u32 bitstream_size{}; std::array frame_offsets{}; std::array refresh_frame{}; }; struct Vp9FrameContainer { Vp9PictureInfo info{}; std::vector bit_stream; }; struct PictureInfo { INSERT_PADDING_WORDS(12); u32 bitstream_size{}; INSERT_PADDING_WORDS(5); Vp9FrameDimensions last_frame_size{}; Vp9FrameDimensions golden_frame_size{}; Vp9FrameDimensions alt_frame_size{}; Vp9FrameDimensions current_frame_size{}; u32 vp9_flags{}; std::array ref_frame_sign_bias{}; u8 first_level{}; u8 sharpness_level{}; u8 base_q_index{}; u8 y_dc_delta_q{}; u8 uv_ac_delta_q{}; u8 uv_dc_delta_q{}; u8 lossless{}; u8 tx_mode{}; u8 allow_high_precision_mv{}; u8 interp_filter{}; u8 reference_mode{}; s8 comp_fixed_ref{}; std::array comp_var_ref{}; u8 log2_tile_cols{}; u8 log2_tile_rows{}; Segmentation segmentation{}; LoopFilter loop_filter{}; INSERT_PADDING_BYTES(5); u32 surface_params{}; INSERT_PADDING_WORDS(3); [[nodiscard]] Vp9PictureInfo Convert() const { return { .is_key_frame = (vp9_flags & FrameFlags::IsKeyFrame) != 0, .intra_only = (vp9_flags & FrameFlags::IntraOnly) != 0, .last_frame_was_key = (vp9_flags & FrameFlags::LastFrameIsKeyFrame) != 0, .frame_size_changed = (vp9_flags & FrameFlags::FrameSizeChanged) != 0, .error_resilient_mode = (vp9_flags & FrameFlags::ErrorResilientMode) != 0, .last_frame_shown = (vp9_flags & FrameFlags::LastShowFrame) != 0, .ref_frame_sign_bias = ref_frame_sign_bias, .base_q_index = base_q_index, .y_dc_delta_q = y_dc_delta_q, .uv_dc_delta_q = uv_dc_delta_q, .uv_ac_delta_q = uv_ac_delta_q, .lossless = lossless != 0, .transform_mode = tx_mode, .allow_high_precision_mv = allow_high_precision_mv != 0, .interp_filter = interp_filter, .reference_mode = reference_mode, .comp_fixed_ref = comp_fixed_ref, .comp_var_ref = comp_var_ref, .log2_tile_cols = log2_tile_cols, .log2_tile_rows = log2_tile_rows, .segment_enabled = segmentation.enabled != 0, .segment_map_update = segmentation.update_map != 0, .segment_map_temporal_update = segmentation.temporal_update != 0, .segment_abs_delta = segmentation.abs_delta, .segment_feature_enable = segmentation.feature_mask, .segment_feature_data = segmentation.feature_data, .mode_ref_delta_enabled = loop_filter.mode_ref_delta_enabled != 0, .use_prev_in_find_mv_refs = !(vp9_flags == (FrameFlags::ErrorResilientMode)) && !(vp9_flags == (FrameFlags::FrameSizeChanged)) && !(vp9_flags == (FrameFlags::IntraOnly)) && (vp9_flags == (FrameFlags::LastShowFrame)) && !(vp9_flags == (FrameFlags::LastFrameIsKeyFrame)), .ref_deltas = loop_filter.ref_deltas, .mode_deltas = loop_filter.mode_deltas, .frame_size = current_frame_size, .first_level = first_level, .sharpness_level = sharpness_level, .bitstream_size = bitstream_size, }; } }; static_assert(sizeof(PictureInfo) == 0x100, "PictureInfo is an invalid size"); struct EntropyProbs { INSERT_PADDING_BYTES(1024); std::array, 7> inter_mode_prob{}; std::array intra_inter_prob{}; INSERT_PADDING_BYTES(80); std::array, 2> tx_8x8_prob{}; std::array, 2> tx_16x16_prob{}; std::array, 2> tx_32x32_prob{}; std::array y_mode_prob_e8{}; std::array, 4> y_mode_prob_e0e7{}; INSERT_PADDING_BYTES(64); std::array, 16> partition_prob{}; INSERT_PADDING_BYTES(10); std::array, 4> switchable_interp_prob{}; std::array comp_inter_prob{}; std::array skip_probs{}; std::array joints{}; std::array sign{}; std::array, 2> class_0{}; std::array, 2> fr{}; std::array class_0_hp{}; std::array high_precision{}; std::array, 2> classes{}; std::array, 2>, 2> class_0_fr{}; std::array, 2> pred_bits{}; std::array, 5> single_ref_prob{}; std::array comp_ref_prob{}; INSERT_PADDING_BYTES(17); std::array, 6>, 6>, 2>, 2>, 4> coef_probs{}; void Convert(Vp9EntropyProbs& fc) { std::memcpy(fc.inter_mode_prob.data(), inter_mode_prob.data(), fc.inter_mode_prob.size()); std::memcpy(fc.intra_inter_prob.data(), intra_inter_prob.data(), fc.intra_inter_prob.size()); std::memcpy(fc.tx_8x8_prob.data(), tx_8x8_prob.data(), fc.tx_8x8_prob.size()); std::memcpy(fc.tx_16x16_prob.data(), tx_16x16_prob.data(), fc.tx_16x16_prob.size()); std::memcpy(fc.tx_32x32_prob.data(), tx_32x32_prob.data(), fc.tx_32x32_prob.size()); for (s32 i = 0; i < 4; i++) { for (s32 j = 0; j < 9; j++) { fc.y_mode_prob[j + 9 * i] = j < 8 ? y_mode_prob_e0e7[i][j] : y_mode_prob_e8[i]; } } std::memcpy(fc.partition_prob.data(), partition_prob.data(), fc.partition_prob.size()); std::memcpy(fc.switchable_interp_prob.data(), switchable_interp_prob.data(), fc.switchable_interp_prob.size()); std::memcpy(fc.comp_inter_prob.data(), comp_inter_prob.data(), fc.comp_inter_prob.size()); std::memcpy(fc.skip_probs.data(), skip_probs.data(), fc.skip_probs.size()); std::memcpy(fc.joints.data(), joints.data(), fc.joints.size()); std::memcpy(fc.sign.data(), sign.data(), fc.sign.size()); std::memcpy(fc.class_0.data(), class_0.data(), fc.class_0.size()); std::memcpy(fc.fr.data(), fr.data(), fc.fr.size()); std::memcpy(fc.class_0_hp.data(), class_0_hp.data(), fc.class_0_hp.size()); std::memcpy(fc.high_precision.data(), high_precision.data(), fc.high_precision.size()); std::memcpy(fc.classes.data(), classes.data(), fc.classes.size()); std::memcpy(fc.class_0_fr.data(), class_0_fr.data(), fc.class_0_fr.size()); std::memcpy(fc.prob_bits.data(), pred_bits.data(), fc.prob_bits.size()); std::memcpy(fc.single_ref_prob.data(), single_ref_prob.data(), fc.single_ref_prob.size()); std::memcpy(fc.comp_ref_prob.data(), comp_ref_prob.data(), fc.comp_ref_prob.size()); std::memcpy(fc.coef_probs.data(), coef_probs.data(), fc.coef_probs.size()); } }; static_assert(sizeof(EntropyProbs) == 0xEA0, "EntropyProbs is an invalid size"); enum class Ref { Last, Golden, AltRef }; struct RefPoolElement { s64 frame{}; Ref ref{}; bool refresh{}; }; struct FrameContexts { s64 from{}; bool adapted{}; Vp9EntropyProbs probs{}; }; }; // namespace Decoder }; // namespace Tegra