// 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 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 }; 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) == 0x7B4, "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 inter_mode_prob{}; std::array intra_inter_prob{}; INSERT_PADDING_BYTES(80); std::array tx_8x8_prob{}; std::array tx_16x16_prob{}; std::array tx_32x32_prob{}; std::array y_mode_prob_e8{}; std::array, 4> y_mode_prob_e0e7{}; INSERT_PADDING_BYTES(64); std::array partition_prob{}; INSERT_PADDING_BYTES(10); std::array switchable_interp_prob{}; std::array comp_inter_prob{}; std::array skip_probs{}; INSERT_PADDING_BYTES(1); std::array joints{}; std::array sign{}; std::array class_0{}; std::array fr{}; std::array class_0_hp{}; std::array high_precision{}; std::array classes{}; std::array class_0_fr{}; std::array pred_bits{}; std::array single_ref_prob{}; std::array comp_ref_prob{}; INSERT_PADDING_BYTES(17); std::array coef_probs{}; void Convert(Vp9EntropyProbs& fc) { fc.inter_mode_prob = inter_mode_prob; fc.intra_inter_prob = intra_inter_prob; fc.tx_8x8_prob = tx_8x8_prob; fc.tx_16x16_prob = tx_16x16_prob; fc.tx_32x32_prob = tx_32x32_prob; for (std::size_t i = 0; i < 4; i++) { for (std::size_t 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]; } } fc.partition_prob = partition_prob; fc.switchable_interp_prob = switchable_interp_prob; fc.comp_inter_prob = comp_inter_prob; fc.skip_probs = skip_probs; fc.joints = joints; fc.sign = sign; fc.class_0 = class_0; fc.fr = fr; fc.class_0_hp = class_0_hp; fc.high_precision = high_precision; fc.classes = classes; fc.class_0_fr = class_0_fr; fc.prob_bits = pred_bits; fc.single_ref_prob = single_ref_prob; fc.comp_ref_prob = comp_ref_prob; // Skip the 4th element as it goes unused for (std::size_t i = 0; i < coef_probs.size(); i += 4) { const std::size_t j = i - i / 4; fc.coef_probs[j] = coef_probs[i]; fc.coef_probs[j + 1] = coef_probs[i + 1]; fc.coef_probs[j + 2] = coef_probs[i + 2]; } } }; 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