diff options
| author | 2020-10-29 21:33:27 -0700 | |
|---|---|---|
| committer | 2020-10-29 21:33:27 -0700 | |
| commit | 131a75b65d088686f7b50392f0ee47a34c4a0512 (patch) | |
| tree | cec8eb2a2267f8c9148380c3a931ae5508878a9c | |
| parent | Merge pull request #4831 from lioncash/fmt (diff) | |
| parent | common/stream: Be explicit with copy and move operators (diff) | |
| download | yuzu-131a75b65d088686f7b50392f0ee47a34c4a0512.tar.gz yuzu-131a75b65d088686f7b50392f0ee47a34c4a0512.tar.xz yuzu-131a75b65d088686f7b50392f0ee47a34c4a0512.zip | |
Merge pull request #4867 from lioncash/vp9
VP9: Minor interface changes and safety improvements
| -rw-r--r-- | src/common/stream.h | 12 | ||||
| -rw-r--r-- | src/video_core/command_classes/codecs/vp9.cpp | 102 | ||||
| -rw-r--r-- | src/video_core/command_classes/codecs/vp9.h | 48 |
3 files changed, 91 insertions, 71 deletions
diff --git a/src/common/stream.h b/src/common/stream.h index 2585c16af..0e40692de 100644 --- a/src/common/stream.h +++ b/src/common/stream.h | |||
| @@ -21,6 +21,12 @@ public: | |||
| 21 | explicit Stream(); | 21 | explicit Stream(); |
| 22 | ~Stream(); | 22 | ~Stream(); |
| 23 | 23 | ||
| 24 | Stream(const Stream&) = delete; | ||
| 25 | Stream& operator=(const Stream&) = delete; | ||
| 26 | |||
| 27 | Stream(Stream&&) = default; | ||
| 28 | Stream& operator=(Stream&&) = default; | ||
| 29 | |||
| 24 | /// Reposition bitstream "cursor" to the specified offset from origin | 30 | /// Reposition bitstream "cursor" to the specified offset from origin |
| 25 | void Seek(s32 offset, SeekOrigin origin); | 31 | void Seek(s32 offset, SeekOrigin origin); |
| 26 | 32 | ||
| @@ -30,15 +36,15 @@ public: | |||
| 30 | /// Writes byte at current position | 36 | /// Writes byte at current position |
| 31 | void WriteByte(u8 byte); | 37 | void WriteByte(u8 byte); |
| 32 | 38 | ||
| 33 | std::size_t GetPosition() const { | 39 | [[nodiscard]] std::size_t GetPosition() const { |
| 34 | return position; | 40 | return position; |
| 35 | } | 41 | } |
| 36 | 42 | ||
| 37 | std::vector<u8>& GetBuffer() { | 43 | [[nodiscard]] std::vector<u8>& GetBuffer() { |
| 38 | return buffer; | 44 | return buffer; |
| 39 | } | 45 | } |
| 40 | 46 | ||
| 41 | const std::vector<u8>& GetBuffer() const { | 47 | [[nodiscard]] const std::vector<u8>& GetBuffer() const { |
| 42 | return buffer; | 48 | return buffer; |
| 43 | } | 49 | } |
| 44 | 50 | ||
diff --git a/src/video_core/command_classes/codecs/vp9.cpp b/src/video_core/command_classes/codecs/vp9.cpp index b3e98aa9f..42520f856 100644 --- a/src/video_core/command_classes/codecs/vp9.cpp +++ b/src/video_core/command_classes/codecs/vp9.cpp | |||
| @@ -197,6 +197,60 @@ constexpr std::array<s32, 254> map_lut{ | |||
| 197 | 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 18, 242, 243, 244, 245, 246, 247, | 197 | 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 18, 242, 243, 244, 245, 246, 247, |
| 198 | 248, 249, 250, 251, 252, 253, 19, | 198 | 248, 249, 250, 251, 252, 253, 19, |
| 199 | }; | 199 | }; |
| 200 | |||
| 201 | // 6.2.14 Tile size calculation | ||
| 202 | |||
| 203 | [[nodiscard]] s32 CalcMinLog2TileCols(s32 frame_width) { | ||
| 204 | const s32 sb64_cols = (frame_width + 63) / 64; | ||
| 205 | s32 min_log2 = 0; | ||
| 206 | |||
| 207 | while ((64 << min_log2) < sb64_cols) { | ||
| 208 | min_log2++; | ||
| 209 | } | ||
| 210 | |||
| 211 | return min_log2; | ||
| 212 | } | ||
| 213 | |||
| 214 | [[nodiscard]] s32 CalcMaxLog2TileCols(s32 frame_width) { | ||
| 215 | const s32 sb64_cols = (frame_width + 63) / 64; | ||
| 216 | s32 max_log2 = 1; | ||
| 217 | |||
| 218 | while ((sb64_cols >> max_log2) >= 4) { | ||
| 219 | max_log2++; | ||
| 220 | } | ||
| 221 | |||
| 222 | return max_log2 - 1; | ||
| 223 | } | ||
| 224 | |||
| 225 | // Recenters probability. Based on section 6.3.6 of VP9 Specification | ||
| 226 | [[nodiscard]] s32 RecenterNonNeg(s32 new_prob, s32 old_prob) { | ||
| 227 | if (new_prob > old_prob * 2) { | ||
| 228 | return new_prob; | ||
| 229 | } | ||
| 230 | |||
| 231 | if (new_prob >= old_prob) { | ||
| 232 | return (new_prob - old_prob) * 2; | ||
| 233 | } | ||
| 234 | |||
| 235 | return (old_prob - new_prob) * 2 - 1; | ||
| 236 | } | ||
| 237 | |||
| 238 | // Adjusts old_prob depending on new_prob. Based on section 6.3.5 of VP9 Specification | ||
| 239 | [[nodiscard]] s32 RemapProbability(s32 new_prob, s32 old_prob) { | ||
| 240 | new_prob--; | ||
| 241 | old_prob--; | ||
| 242 | |||
| 243 | std::size_t index{}; | ||
| 244 | |||
| 245 | if (old_prob * 2 <= 0xff) { | ||
| 246 | index = static_cast<std::size_t>(std::max(0, RecenterNonNeg(new_prob, old_prob) - 1)); | ||
| 247 | } else { | ||
| 248 | index = static_cast<std::size_t>( | ||
| 249 | std::max(0, RecenterNonNeg(0xff - 1 - new_prob, 0xff - 1 - old_prob) - 1)); | ||
| 250 | } | ||
| 251 | |||
| 252 | return map_lut[index]; | ||
| 253 | } | ||
| 200 | } // Anonymous namespace | 254 | } // Anonymous namespace |
| 201 | 255 | ||
| 202 | VP9::VP9(GPU& gpu) : gpu(gpu) {} | 256 | VP9::VP9(GPU& gpu) : gpu(gpu) {} |
| @@ -236,32 +290,6 @@ void VP9::WriteProbabilityDelta(VpxRangeEncoder& writer, u8 new_prob, u8 old_pro | |||
| 236 | EncodeTermSubExp(writer, delta); | 290 | EncodeTermSubExp(writer, delta); |
| 237 | } | 291 | } |
| 238 | 292 | ||
| 239 | s32 VP9::RemapProbability(s32 new_prob, s32 old_prob) { | ||
| 240 | new_prob--; | ||
| 241 | old_prob--; | ||
| 242 | |||
| 243 | std::size_t index{}; | ||
| 244 | |||
| 245 | if (old_prob * 2 <= 0xff) { | ||
| 246 | index = static_cast<std::size_t>(std::max(0, RecenterNonNeg(new_prob, old_prob) - 1)); | ||
| 247 | } else { | ||
| 248 | index = static_cast<std::size_t>( | ||
| 249 | std::max(0, RecenterNonNeg(0xff - 1 - new_prob, 0xff - 1 - old_prob) - 1)); | ||
| 250 | } | ||
| 251 | |||
| 252 | return map_lut[index]; | ||
| 253 | } | ||
| 254 | |||
| 255 | s32 VP9::RecenterNonNeg(s32 new_prob, s32 old_prob) { | ||
| 256 | if (new_prob > old_prob * 2) { | ||
| 257 | return new_prob; | ||
| 258 | } else if (new_prob >= old_prob) { | ||
| 259 | return (new_prob - old_prob) * 2; | ||
| 260 | } else { | ||
| 261 | return (old_prob - new_prob) * 2 - 1; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | void VP9::EncodeTermSubExp(VpxRangeEncoder& writer, s32 value) { | 293 | void VP9::EncodeTermSubExp(VpxRangeEncoder& writer, s32 value) { |
| 266 | if (WriteLessThan(writer, value, 16)) { | 294 | if (WriteLessThan(writer, value, 16)) { |
| 267 | writer.Write(value, 4); | 295 | writer.Write(value, 4); |
| @@ -361,28 +389,6 @@ void VP9::WriteMvProbabilityUpdate(VpxRangeEncoder& writer, u8 new_prob, u8 old_ | |||
| 361 | } | 389 | } |
| 362 | } | 390 | } |
| 363 | 391 | ||
| 364 | s32 VP9::CalcMinLog2TileCols(s32 frame_width) { | ||
| 365 | const s32 sb64_cols = (frame_width + 63) / 64; | ||
| 366 | s32 min_log2 = 0; | ||
| 367 | |||
| 368 | while ((64 << min_log2) < sb64_cols) { | ||
| 369 | min_log2++; | ||
| 370 | } | ||
| 371 | |||
| 372 | return min_log2; | ||
| 373 | } | ||
| 374 | |||
| 375 | s32 VP9::CalcMaxLog2TileCols(s32 frameWidth) { | ||
| 376 | const s32 sb64_cols = (frameWidth + 63) / 64; | ||
| 377 | s32 max_log2 = 1; | ||
| 378 | |||
| 379 | while ((sb64_cols >> max_log2) >= 4) { | ||
| 380 | max_log2++; | ||
| 381 | } | ||
| 382 | |||
| 383 | return max_log2 - 1; | ||
| 384 | } | ||
| 385 | |||
| 386 | Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state) { | 392 | Vp9PictureInfo VP9::GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state) { |
| 387 | PictureInfo picture_info{}; | 393 | PictureInfo picture_info{}; |
| 388 | gpu.MemoryManager().ReadBlock(state.picture_info_offset, &picture_info, sizeof(PictureInfo)); | 394 | gpu.MemoryManager().ReadBlock(state.picture_info_offset, &picture_info, sizeof(PictureInfo)); |
diff --git a/src/video_core/command_classes/codecs/vp9.h b/src/video_core/command_classes/codecs/vp9.h index dc52ddbde..05c9682fa 100644 --- a/src/video_core/command_classes/codecs/vp9.h +++ b/src/video_core/command_classes/codecs/vp9.h | |||
| @@ -25,6 +25,12 @@ public: | |||
| 25 | VpxRangeEncoder(); | 25 | VpxRangeEncoder(); |
| 26 | ~VpxRangeEncoder(); | 26 | ~VpxRangeEncoder(); |
| 27 | 27 | ||
| 28 | VpxRangeEncoder(const VpxRangeEncoder&) = delete; | ||
| 29 | VpxRangeEncoder& operator=(const VpxRangeEncoder&) = delete; | ||
| 30 | |||
| 31 | VpxRangeEncoder(VpxRangeEncoder&&) = default; | ||
| 32 | VpxRangeEncoder& operator=(VpxRangeEncoder&&) = default; | ||
| 33 | |||
| 28 | /// Writes the rightmost value_size bits from value into the stream | 34 | /// Writes the rightmost value_size bits from value into the stream |
| 29 | void Write(s32 value, s32 value_size); | 35 | void Write(s32 value, s32 value_size); |
| 30 | 36 | ||
| @@ -37,11 +43,11 @@ public: | |||
| 37 | /// Signal the end of the bitstream | 43 | /// Signal the end of the bitstream |
| 38 | void End(); | 44 | void End(); |
| 39 | 45 | ||
| 40 | std::vector<u8>& GetBuffer() { | 46 | [[nodiscard]] std::vector<u8>& GetBuffer() { |
| 41 | return base_stream.GetBuffer(); | 47 | return base_stream.GetBuffer(); |
| 42 | } | 48 | } |
| 43 | 49 | ||
| 44 | const std::vector<u8>& GetBuffer() const { | 50 | [[nodiscard]] const std::vector<u8>& GetBuffer() const { |
| 45 | return base_stream.GetBuffer(); | 51 | return base_stream.GetBuffer(); |
| 46 | } | 52 | } |
| 47 | 53 | ||
| @@ -59,6 +65,12 @@ public: | |||
| 59 | VpxBitStreamWriter(); | 65 | VpxBitStreamWriter(); |
| 60 | ~VpxBitStreamWriter(); | 66 | ~VpxBitStreamWriter(); |
| 61 | 67 | ||
| 68 | VpxBitStreamWriter(const VpxBitStreamWriter&) = delete; | ||
| 69 | VpxBitStreamWriter& operator=(const VpxBitStreamWriter&) = delete; | ||
| 70 | |||
| 71 | VpxBitStreamWriter(VpxBitStreamWriter&&) = default; | ||
| 72 | VpxBitStreamWriter& operator=(VpxBitStreamWriter&&) = default; | ||
| 73 | |||
| 62 | /// Write an unsigned integer value | 74 | /// Write an unsigned integer value |
| 63 | void WriteU(u32 value, u32 value_size); | 75 | void WriteU(u32 value, u32 value_size); |
| 64 | 76 | ||
| @@ -75,10 +87,10 @@ public: | |||
| 75 | void Flush(); | 87 | void Flush(); |
| 76 | 88 | ||
| 77 | /// Returns byte_array | 89 | /// Returns byte_array |
| 78 | std::vector<u8>& GetByteArray(); | 90 | [[nodiscard]] std::vector<u8>& GetByteArray(); |
| 79 | 91 | ||
| 80 | /// Returns const byte_array | 92 | /// Returns const byte_array |
| 81 | const std::vector<u8>& GetByteArray() const; | 93 | [[nodiscard]] const std::vector<u8>& GetByteArray() const; |
| 82 | 94 | ||
| 83 | private: | 95 | private: |
| 84 | /// Write bit_count bits from value into buffer | 96 | /// Write bit_count bits from value into buffer |
| @@ -99,12 +111,18 @@ public: | |||
| 99 | explicit VP9(GPU& gpu); | 111 | explicit VP9(GPU& gpu); |
| 100 | ~VP9(); | 112 | ~VP9(); |
| 101 | 113 | ||
| 114 | VP9(const VP9&) = delete; | ||
| 115 | VP9& operator=(const VP9&) = delete; | ||
| 116 | |||
| 117 | VP9(VP9&&) = default; | ||
| 118 | VP9& operator=(VP9&&) = delete; | ||
| 119 | |||
| 102 | /// Composes the VP9 frame from the GPU state information. Based on the official VP9 spec | 120 | /// Composes the VP9 frame from the GPU state information. Based on the official VP9 spec |
| 103 | /// documentation | 121 | /// documentation |
| 104 | std::vector<u8>& ComposeFrameHeader(NvdecCommon::NvdecRegisters& state); | 122 | std::vector<u8>& ComposeFrameHeader(NvdecCommon::NvdecRegisters& state); |
| 105 | 123 | ||
| 106 | /// Returns true if the most recent frame was a hidden frame. | 124 | /// Returns true if the most recent frame was a hidden frame. |
| 107 | bool WasFrameHidden() const { | 125 | [[nodiscard]] bool WasFrameHidden() const { |
| 108 | return hidden; | 126 | return hidden; |
| 109 | } | 127 | } |
| 110 | 128 | ||
| @@ -121,12 +139,6 @@ private: | |||
| 121 | /// Generates compressed header probability deltas in the bitstream writer | 139 | /// Generates compressed header probability deltas in the bitstream writer |
| 122 | void WriteProbabilityDelta(VpxRangeEncoder& writer, u8 new_prob, u8 old_prob); | 140 | void WriteProbabilityDelta(VpxRangeEncoder& writer, u8 new_prob, u8 old_prob); |
| 123 | 141 | ||
| 124 | /// Adjusts old_prob depending on new_prob. Based on section 6.3.5 of VP9 Specification | ||
| 125 | s32 RemapProbability(s32 new_prob, s32 old_prob); | ||
| 126 | |||
| 127 | /// Recenters probability. Based on section 6.3.6 of VP9 Specification | ||
| 128 | s32 RecenterNonNeg(s32 new_prob, s32 old_prob); | ||
| 129 | |||
| 130 | /// Inverse of 6.3.4 Decode term subexp | 142 | /// Inverse of 6.3.4 Decode term subexp |
| 131 | void EncodeTermSubExp(VpxRangeEncoder& writer, s32 value); | 143 | void EncodeTermSubExp(VpxRangeEncoder& writer, s32 value); |
| 132 | 144 | ||
| @@ -146,22 +158,18 @@ private: | |||
| 146 | /// Write motion vector probability updates. 6.3.17 in the spec | 158 | /// Write motion vector probability updates. 6.3.17 in the spec |
| 147 | void WriteMvProbabilityUpdate(VpxRangeEncoder& writer, u8 new_prob, u8 old_prob); | 159 | void WriteMvProbabilityUpdate(VpxRangeEncoder& writer, u8 new_prob, u8 old_prob); |
| 148 | 160 | ||
| 149 | /// 6.2.14 Tile size calculation | ||
| 150 | s32 CalcMinLog2TileCols(s32 frame_width); | ||
| 151 | s32 CalcMaxLog2TileCols(s32 frame_width); | ||
| 152 | |||
| 153 | /// Returns VP9 information from NVDEC provided offset and size | 161 | /// Returns VP9 information from NVDEC provided offset and size |
| 154 | Vp9PictureInfo GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state); | 162 | [[nodiscard]] Vp9PictureInfo GetVp9PictureInfo(const NvdecCommon::NvdecRegisters& state); |
| 155 | 163 | ||
| 156 | /// Read and convert NVDEC provided entropy probs to Vp9EntropyProbs struct | 164 | /// Read and convert NVDEC provided entropy probs to Vp9EntropyProbs struct |
| 157 | void InsertEntropy(u64 offset, Vp9EntropyProbs& dst); | 165 | void InsertEntropy(u64 offset, Vp9EntropyProbs& dst); |
| 158 | 166 | ||
| 159 | /// Returns frame to be decoded after buffering | 167 | /// Returns frame to be decoded after buffering |
| 160 | Vp9FrameContainer GetCurrentFrame(const NvdecCommon::NvdecRegisters& state); | 168 | [[nodiscard]] Vp9FrameContainer GetCurrentFrame(const NvdecCommon::NvdecRegisters& state); |
| 161 | 169 | ||
| 162 | /// Use NVDEC providied information to compose the headers for the current frame | 170 | /// Use NVDEC providied information to compose the headers for the current frame |
| 163 | std::vector<u8> ComposeCompressedHeader(); | 171 | [[nodiscard]] std::vector<u8> ComposeCompressedHeader(); |
| 164 | VpxBitStreamWriter ComposeUncompressedHeader(); | 172 | [[nodiscard]] VpxBitStreamWriter ComposeUncompressedHeader(); |
| 165 | 173 | ||
| 166 | GPU& gpu; | 174 | GPU& gpu; |
| 167 | std::vector<u8> frame; | 175 | std::vector<u8> frame; |
| @@ -169,7 +177,7 @@ private: | |||
| 169 | std::array<s8, 4> loop_filter_ref_deltas{}; | 177 | std::array<s8, 4> loop_filter_ref_deltas{}; |
| 170 | std::array<s8, 2> loop_filter_mode_deltas{}; | 178 | std::array<s8, 2> loop_filter_mode_deltas{}; |
| 171 | 179 | ||
| 172 | bool hidden; | 180 | bool hidden = false; |
| 173 | s64 current_frame_number = -2; // since we buffer 2 frames | 181 | s64 current_frame_number = -2; // since we buffer 2 frames |
| 174 | s32 grace_period = 6; // frame offsets need to stabilize | 182 | s32 grace_period = 6; // frame offsets need to stabilize |
| 175 | std::array<FrameContexts, 4> frame_ctxs{}; | 183 | std::array<FrameContexts, 4> frame_ctxs{}; |