SkWuffsCodec: fix dependent frames
SkWuffsCodec tells wuffs to decode only the current frame's contribution, and then SkWuffsCodec blends it onto the prior frame (if any). If there is a prior frame, do not call SkSampler::Fill, and blend the new frame onto the old, rather than replacing it. In addition, set rowsDecoded to scaledHeight to work properly for scaled decodes. TBR=reed@google.com No change to public API Bug: skia:8235 Change-Id: I08e89f1083da3f9b98f93d8d2375ce78f0c378f8 Reviewed-on: https://skia-review.googlesource.com/c/171645 Commit-Queue: Leon Scroggins <scroggo@google.com> Reviewed-by: Nigel Tao <nigeltao@google.com>
This commit is contained in:
parent
f4958ce207
commit
9b0ba2c2cd
@ -785,6 +785,14 @@ protected:
|
||||
|
||||
virtual int onOutputScanline(int inputScanline) const;
|
||||
|
||||
/**
|
||||
* Return whether we can convert to dst.
|
||||
*
|
||||
* Will be called for the appropriate frame, prior to initializing the colorXform.
|
||||
*/
|
||||
virtual bool conversionSupported(const SkImageInfo& dst, bool srcIsOpaque,
|
||||
bool needsColorXform);
|
||||
|
||||
// Some classes never need a colorXform e.g.
|
||||
// - ICO uses its embedded codec's colorXform
|
||||
// - WBMP is just Black/White
|
||||
@ -831,14 +839,6 @@ private:
|
||||
|
||||
bool fStartedIncrementalDecode;
|
||||
|
||||
/**
|
||||
* Return whether we can convert to dst.
|
||||
*
|
||||
* Will be called for the appropriate frame, prior to initializing the colorXform.
|
||||
*/
|
||||
virtual bool conversionSupported(const SkImageInfo& dst, bool srcIsOpaque,
|
||||
bool needsColorXform);
|
||||
|
||||
bool initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha, bool srcIsOpaque);
|
||||
|
||||
/**
|
||||
|
@ -173,6 +173,7 @@ private:
|
||||
bool onGetFrameInfo(int, FrameInfo*) const override;
|
||||
int onGetRepetitionCount() override;
|
||||
SkSampler* getSampler(bool createIfNecessary) override;
|
||||
bool conversionSupported(const SkImageInfo& dst, bool, bool) override;
|
||||
|
||||
void readFrames();
|
||||
Result seekFrame(int frameIndex);
|
||||
@ -389,6 +390,26 @@ SkCodec::Result SkWuffsCodec::onStartIncrementalDecode(const SkImageInfo& d
|
||||
return SkCodec::kSuccess;
|
||||
}
|
||||
|
||||
static bool independent_frame(SkCodec* codec, int frameIndex) {
|
||||
if (frameIndex == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
SkCodec::FrameInfo frameInfo;
|
||||
SkAssertResult(codec->getFrameInfo(frameIndex, &frameInfo));
|
||||
return frameInfo.fRequiredFrame == SkCodec::kNoFrame;
|
||||
}
|
||||
|
||||
static void blend(uint32_t* dst, const uint32_t* src, int width) {
|
||||
while (width --> 0) {
|
||||
if (*src != 0) {
|
||||
*dst = *src;
|
||||
}
|
||||
src++;
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
|
||||
SkCodec::Result SkWuffsCodec::onIncrementalDecode(int* rowsDecoded) {
|
||||
if (!fIncrDecDst) {
|
||||
return SkCodec::kInternalError;
|
||||
@ -418,6 +439,7 @@ SkCodec::Result SkWuffsCodec::onIncrementalDecode(int* rowsDecoded) {
|
||||
return SkCodec::kErrorInInput;
|
||||
}
|
||||
|
||||
const bool independent = independent_frame(this, options().fFrameIndex);
|
||||
wuffs_base__rect_ie_u32 r = fFrameConfig.bounds();
|
||||
if (!fSwizzler) {
|
||||
SkIRect swizzleRect = SkIRect::MakeLTRB(r.min_incl_x, 0, r.max_excl_x, 1);
|
||||
@ -426,9 +448,12 @@ SkCodec::Result SkWuffsCodec::onIncrementalDecode(int* rowsDecoded) {
|
||||
fSwizzler->setSampleX(fSpySampler.sampleX());
|
||||
fSwizzler->setSampleY(fSpySampler.sampleY());
|
||||
|
||||
auto fillInfo = dstInfo().makeWH(
|
||||
fSwizzler->fillWidth(), get_scaled_dimension(dstInfo().height(), fSwizzler->sampleY()));
|
||||
SkSampler::Fill(fillInfo, fIncrDecDst, fIncrDecRowBytes, options().fZeroInitialized);
|
||||
if (independent) {
|
||||
auto fillInfo = dstInfo().makeWH(fSwizzler->fillWidth(),
|
||||
get_scaled_dimension(this->dstInfo().height(),
|
||||
fSwizzler->sampleY()));
|
||||
SkSampler::Fill(fillInfo, fIncrDecDst, fIncrDecRowBytes, options().fZeroInitialized);
|
||||
}
|
||||
}
|
||||
|
||||
wuffs_base__slice_u8 palette = fPixelBuffer.palette();
|
||||
@ -439,6 +464,10 @@ SkCodec::Result SkWuffsCodec::onIncrementalDecode(int* rowsDecoded) {
|
||||
fColorTable[i] = proc(p[3], p[2], p[1], p[0]);
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8_t[]> tmpBuffer;
|
||||
if (!independent) {
|
||||
tmpBuffer.reset(new uint8_t[dstInfo().minRowBytes()]);
|
||||
}
|
||||
wuffs_base__table_u8 pixels = fPixelBuffer.plane(0);
|
||||
const int sampleY = fSwizzler->sampleY();
|
||||
const int scaledHeight = get_scaled_dimension(dstInfo().height(), sampleY);
|
||||
@ -468,7 +497,16 @@ SkCodec::Result SkWuffsCodec::onIncrementalDecode(int* rowsDecoded) {
|
||||
// To get from the start (in the X-direction) of the image to the start
|
||||
// of the frame, we adjust s by (r.min_incl_x * src_bpp).
|
||||
uint8_t* s = pixels.ptr + (y * pixels.stride) + (r.min_incl_x * src_bpp);
|
||||
fSwizzler->swizzle(d, s);
|
||||
if (independent) {
|
||||
fSwizzler->swizzle(d, s);
|
||||
} else {
|
||||
SkASSERT(tmpBuffer.get());
|
||||
fSwizzler->swizzle(tmpBuffer.get(), s);
|
||||
d = SkTAddOffset<uint8_t>(d, fSwizzler->swizzleOffsetBytes());
|
||||
const auto* swizzled = SkTAddOffset<uint32_t>(tmpBuffer.get(),
|
||||
fSwizzler->swizzleOffsetBytes());
|
||||
blend(reinterpret_cast<uint32_t*>(d), swizzled, fSwizzler->swizzleWidth());
|
||||
}
|
||||
}
|
||||
|
||||
// The semantics of *rowsDecoded is: say you have a 10 pixel high image
|
||||
@ -484,8 +522,12 @@ SkCodec::Result SkWuffsCodec::onIncrementalDecode(int* rowsDecoded) {
|
||||
// interlaced), we just zero-initialize all 10 rows ahead of time and
|
||||
// return the height of the image, so the caller knows it doesn't need to
|
||||
// do anything.
|
||||
//
|
||||
// Similarly, if the output is scaled, we zero-initialized all
|
||||
// |scaledHeight| rows (the scaled image height), so we inform the caller
|
||||
// that it doesn't need to do anything.
|
||||
if (rowsDecoded) {
|
||||
*rowsDecoded = static_cast<int>(fPixelBuffer.pixcfg.height());
|
||||
*rowsDecoded = scaledHeight;
|
||||
}
|
||||
|
||||
if (result == SkCodec::kSuccess) {
|
||||
@ -543,6 +585,22 @@ SkSampler* SkWuffsCodec::getSampler(bool createIfNecessary) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SkWuffsCodec::conversionSupported(const SkImageInfo& dst, bool srcIsOpaque, bool needsColorXform) {
|
||||
if (!this->INHERITED::conversionSupported(dst, srcIsOpaque, needsColorXform)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (dst.colorType()) {
|
||||
case kRGBA_8888_SkColorType:
|
||||
case kBGRA_8888_SkColorType:
|
||||
return true;
|
||||
default:
|
||||
// FIXME: Add skcms to support F16
|
||||
// FIXME: Add support for 565 on the first frame
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void SkWuffsCodec::readFrames() {
|
||||
size_t n = fFrames.size();
|
||||
int i = n ? n - 1 : 0;
|
||||
|
Loading…
Reference in New Issue
Block a user