Reset SkWuffsCodec frame-count decoder less often
Previously, every call to SkWuffsCodec::onGetFrameCountInternal would
reset the decoder, as it might have been suspended in a co-routine.
Resetting also meant re-winding the input stream back to the first byte
of source data, to re-parse the image configuration (not just a
per-frame configuration), since e.g. the overall image bounds can affect
(clip) a frame's bounds.
Now that there are two separate decoders (one for pixel data and one
just for the frame-count), the only co-routine that the frame-count
decoder could be suspended in is the call to decode the next frame
configuration. There is no longer a need to (conditionally) reset the
frame-count decoder; we can just resume that co-routine (provided that
the fIOBuffer is positioned where it left off).
After this commit, the Wuffs decoder should use a little less CPU and
I/O when having getFrameCount called multiple times, interleaved with
incrementally decoding an animation.
Bug: skia:8235
Change-Id: I871ead40ed0acd6d101cf12784ee5da45e7de5aa
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/254356
Reviewed-by: Leon Scroggins <scroggo@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
diff --git a/src/codec/SkWuffsCodec.cpp b/src/codec/SkWuffsCodec.cpp
index 45a01d8..a196e60 100644
--- a/src/codec/SkWuffsCodec.cpp
+++ b/src/codec/SkWuffsCodec.cpp
@@ -261,6 +261,7 @@
size_t fIncrDecRowBytes;
bool fFirstCallToIncrementalDecode;
+ uint64_t fFrameCountReaderIOPosition;
uint64_t fNumFullyReceivedFrames;
std::vector<SkWuffsFrame> fFrames;
bool fFramesComplete;
@@ -363,6 +364,7 @@
fIncrDecReaderIOPosition(0),
fIncrDecRowBytes(0),
fFirstCallToIncrementalDecode(false),
+ fFrameCountReaderIOPosition(0),
fNumFullyReceivedFrames(0),
fFramesComplete(false),
fDecoderIsSuspended{
@@ -593,16 +595,15 @@
}
int SkWuffsCodec::onGetFrameCount() {
- if (!fFramesComplete) {
+ if (!fFramesComplete && seek_buffer(&fIOBuffer, fStream.get(), fFrameCountReaderIOPosition)) {
this->onGetFrameCountInternal();
+ fFrameCountReaderIOPosition =
+ fDecoders[WhichDecoder::kFrameCount] ? fIOBuffer.reader_io_position() : 0;
}
return fFrames.size();
}
void SkWuffsCodec::onGetFrameCountInternal() {
- if (!seek_buffer(&fIOBuffer, fStream.get(), 0)) {
- return;
- }
if (!fDecoders[WhichDecoder::kFrameCount]) {
void* decoder_raw = sk_malloc_canfail(sizeof__wuffs_gif__decoder());
if (!decoder_raw) {
@@ -610,20 +611,13 @@
}
std::unique_ptr<wuffs_gif__decoder, decltype(&sk_free)> decoder(
reinterpret_cast<wuffs_gif__decoder*>(decoder_raw), &sk_free);
+ reset_and_decode_image_config(decoder.get(), nullptr, &fIOBuffer, fStream.get());
fDecoders[WhichDecoder::kFrameCount] = std::move(decoder);
}
- reset_and_decode_image_config(fDecoders[WhichDecoder::kFrameCount].get(), nullptr, &fIOBuffer,
- fStream.get());
-
- size_t n = fFrames.size();
- int i = n ? n - 1 : 0;
- if (this->seekFrame(WhichDecoder::kFrameCount, i) != SkCodec::kSuccess) {
- return;
- }
// Iterate through the frames, converting from Wuffs'
// wuffs_base__frame_config type to Skia's SkWuffsFrame type.
- for (; i < INT_MAX; i++) {
+ while (true) {
const char* status = this->decodeFrameConfig(WhichDecoder::kFrameCount);
if (status == nullptr) {
// No-op.
@@ -633,7 +627,11 @@
return;
}
- if (static_cast<size_t>(i) < fFrames.size()) {
+ uint64_t i = fDecoders[WhichDecoder::kFrameCount]->num_decoded_frame_configs();
+ if (i > INT_MAX) {
+ break;
+ }
+ if ((i == 0) || (static_cast<size_t>(i - 1) != fFrames.size())) {
continue;
}
fFrames.emplace_back(&fFrameConfigs[WhichDecoder::kFrameCount]);