Revert "Fill intermediate device image with clamped backdrop content"
This reverts commit 25f5e1f838
.
Reason for revert: needs_subset is unused for no-gpu+release builds
Original change's description:
> Fill intermediate device image with clamped backdrop content
>
> Adds asShader() to SkSpecialImage that accepts a local matrix and a
> tilemode. It automatically handles the subsetting of the image data
> (either by making a new bitmap view, or using GrTexturEffect), as well
> as modifying the local matrix to account for the subset's offset within
> the image data.
>
> By adding asShader(), SkCanvas can fill a device using drawPaint() to
> apply the image's tilemode to the entire contents, ensuring that any
> device bounds clipping from snapping of backdrop filters doesn't leave
> the default transparent pixels around for later filtering.
>
> Additionally, making SkSpecialImage more like a shader will make it
> easier down the road to continue refactoring the image filter pipeline
> to be more backend agnostic and allow operations to be performed by
> filling devices with shaders, instead of relying on FPs directly.
>
> Lastly, once SkImage::makeShader() can support subsets on the raster
> backend, then SkSpecialImage may not be required at all in order to
> implement the image filtering pipeline...
>
> Bug: b/197774543, skia:12784
> Change-Id: I21dcb22b56b19ff58d246b3c0517bb8a265649bc
> Reviewed-on: https://skia-review.googlesource.com/c/skia/+/491445
> Reviewed-by: Brian Salomon <bsalomon@google.com>
> Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Bug: b/197774543, skia:12784
Change-Id: Ia9adedaab9378d2679353ab94c7a9589c0ff9e02
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/491978
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
parent
ce49ff6520
commit
35ac48c715
@ -924,15 +924,12 @@ void SkCanvas::internalDrawDeviceWithFilter(SkBaseDevice* src,
|
||||
intermediateDevice->setOrigin(SkM44(srcToIntermediate),
|
||||
requiredInput.left(), requiredInput.top());
|
||||
|
||||
// We use drawPaint to fill the entire device with the src input + clamp tiling, which
|
||||
// extends the backdrop's edge pixels to the parts of 'requiredInput' that map offscreen
|
||||
// Without this, the intermediateDevice would contain transparent pixels that may then
|
||||
// infect blurs and other filters with large kernels.
|
||||
SkPaint imageFill;
|
||||
imageFill.setShader(srcImage->asShader(SkTileMode::kClamp,
|
||||
SkSamplingOptions{SkFilterMode::kLinear},
|
||||
SkMatrix::Translate(srcSubset.topLeft())));
|
||||
intermediateDevice->drawPaint(imageFill);
|
||||
SkMatrix offsetLocalToDevice = intermediateDevice->localToDevice();
|
||||
offsetLocalToDevice.preTranslate(srcSubset.left(), srcSubset.top());
|
||||
// We draw with non-AA bilinear since we cover the destination but definitely don't have
|
||||
// a pixel-aligned transform.
|
||||
intermediateDevice->drawSpecial(srcImage.get(), offsetLocalToDevice,
|
||||
SkSamplingOptions{SkFilterMode::kLinear}, {});
|
||||
filterInput = intermediateDevice->snapSpecial();
|
||||
|
||||
// TODO: Like the non-intermediate case, we need to apply the image origin.
|
||||
|
@ -10,8 +10,6 @@
|
||||
#include "include/core/SkBitmap.h"
|
||||
#include "include/core/SkCanvas.h"
|
||||
#include "include/core/SkImage.h"
|
||||
#include "include/core/SkMatrix.h"
|
||||
#include "include/core/SkTileMode.h"
|
||||
#include "src/core/SkSpecialSurface.h"
|
||||
#include "src/core/SkSurfacePriv.h"
|
||||
#include "src/image/SkImage_Base.h"
|
||||
@ -24,7 +22,6 @@
|
||||
#include "src/gpu/GrRecordingContextPriv.h"
|
||||
#include "src/gpu/GrTextureProxy.h"
|
||||
#include "src/image/SkImage_Gpu.h"
|
||||
#include "src/shaders/SkImageShader.h"
|
||||
#endif
|
||||
|
||||
// Currently the raster imagefilters can only handle certain imageinfos. Call this to know if
|
||||
@ -67,10 +64,6 @@ public:
|
||||
// already been mapped from the content rect by the non-virtual asImage().
|
||||
virtual sk_sp<SkImage> onAsImage(const SkIRect* subset) const = 0;
|
||||
|
||||
virtual sk_sp<SkShader> onAsShader(SkTileMode,
|
||||
const SkSamplingOptions&,
|
||||
const SkMatrix&) const = 0;
|
||||
|
||||
virtual sk_sp<SkSurface> onMakeTightSurface(
|
||||
SkColorType colorType, const SkColorSpace* colorSpace,
|
||||
const SkISize& size, SkAlphaType at) const = 0;
|
||||
@ -145,21 +138,6 @@ sk_sp<SkImage> SkSpecialImage::asImage(const SkIRect* subset) const {
|
||||
}
|
||||
}
|
||||
|
||||
sk_sp<SkShader> SkSpecialImage::asShader(SkTileMode tileMode,
|
||||
const SkSamplingOptions& sampling,
|
||||
const SkMatrix& lm) const {
|
||||
return as_SIB(this)->onAsShader(tileMode, sampling, lm);
|
||||
}
|
||||
|
||||
sk_sp<SkShader> SkSpecialImage::asShader(const SkSamplingOptions& sampling) const {
|
||||
return this->asShader(sampling, SkMatrix::I());
|
||||
}
|
||||
|
||||
sk_sp<SkShader> SkSpecialImage::asShader(const SkSamplingOptions& sampling,
|
||||
const SkMatrix& lm) const {
|
||||
return this->asShader(SkTileMode::kClamp, sampling, lm);
|
||||
}
|
||||
|
||||
#if defined(SK_DEBUG) || SK_SUPPORT_GPU
|
||||
static bool rect_fits(const SkIRect& rect, int width, int height) {
|
||||
if (0 == width && 0 == height) {
|
||||
@ -274,19 +252,7 @@ public:
|
||||
return fBitmap.asImage();
|
||||
}
|
||||
|
||||
sk_sp<SkShader> onAsShader(SkTileMode tileMode,
|
||||
const SkSamplingOptions& sampling,
|
||||
const SkMatrix& lm) const override {
|
||||
// TODO(skbug.com/12784): SkImage::makeShader() doesn't support a subset yet, but SkBitmap
|
||||
// supports subset views so create the shader from the subset bitmap instead of fBitmap.
|
||||
SkBitmap subsetBM;
|
||||
if (!this->getROPixels(&subsetBM)) {
|
||||
return nullptr;
|
||||
}
|
||||
return subsetBM.asImage()->makeShader(tileMode, tileMode, sampling, lm);
|
||||
}
|
||||
|
||||
sk_sp<SkSurface> onMakeTightSurface(SkColorType colorType, const SkColorSpace* colorSpace,
|
||||
sk_sp<SkSurface> onMakeTightSurface(SkColorType colorType, const SkColorSpace* colorSpace,
|
||||
const SkISize& size, SkAlphaType at) const override {
|
||||
// Ignore the requested color type, the raster backend currently only supports N32
|
||||
colorType = kN32_SkColorType; // TODO: find ways to allow f16
|
||||
@ -472,23 +438,6 @@ public:
|
||||
return wrap_proxy_in_image(fContext, fView, this->colorType(), fAlphaType, fColorSpace);
|
||||
}
|
||||
|
||||
sk_sp<SkShader> onAsShader(SkTileMode tileMode,
|
||||
const SkSamplingOptions& sampling,
|
||||
const SkMatrix& lm) const override {
|
||||
// The special image's logical (0,0) is at its subset's topLeft() so we need to account for
|
||||
// that in the local matrix used when sampling.
|
||||
SkMatrix subsetOrigin = SkMatrix::Translate(-this->subset().topLeft());
|
||||
subsetOrigin.postConcat(lm);
|
||||
// However, we don't need to modify the subset itself since that is defined with respect to
|
||||
// the base image, and the local matrix is applied before any tiling/clamping.
|
||||
const SkRect subset = SkRect::Make(this->subset());
|
||||
|
||||
// asImage() w/o a subset makes no copy; create the SkImageShader directly to remember the
|
||||
// subset used to access the image.
|
||||
return SkImageShader::MakeSubset(
|
||||
this->asImage(), subset, tileMode, tileMode, sampling, &subsetOrigin);
|
||||
}
|
||||
|
||||
sk_sp<SkSurface> onMakeTightSurface(SkColorType colorType, const SkColorSpace* colorSpace,
|
||||
const SkISize& size, SkAlphaType at) const override {
|
||||
// TODO (michaelludwig): Why does this ignore colorType but onMakeSurface doesn't ignore it?
|
||||
|
@ -25,13 +25,10 @@ class SkBitmap;
|
||||
class SkCanvas;
|
||||
class SkImage;
|
||||
struct SkImageInfo;
|
||||
class SkMatrix;
|
||||
class SkPaint;
|
||||
class SkPixmap;
|
||||
class SkShader;
|
||||
class SkSpecialSurface;
|
||||
class SkSurface;
|
||||
enum class SkTileMode;
|
||||
|
||||
enum {
|
||||
kNeedNewImageUniqueID_SpecialImage = 0
|
||||
@ -129,20 +126,8 @@ public:
|
||||
* When the 'subset' parameter is specified the returned image will be tight even if that
|
||||
* entails a copy! The 'subset' is relative to this special image's content rect.
|
||||
*/
|
||||
// TODO: The only version that uses the subset is the tile image filter, and that doesn't need
|
||||
// to if it can be rewritten to use asShader() and SkTileModes. Similarly, the only use case of
|
||||
// asImage() w/o a subset is SkImage::makeFiltered() and that could/should return an SkShader so
|
||||
// that users don't need to worry about correctly applying the subset, etc.
|
||||
sk_sp<SkImage> asImage(const SkIRect* subset = nullptr) const;
|
||||
|
||||
/**
|
||||
* Create an SkShader that samples the contents of this special image, applying tile mode for
|
||||
* any sample that falls outside its internal subset.
|
||||
*/
|
||||
sk_sp<SkShader> asShader(SkTileMode, const SkSamplingOptions&, const SkMatrix&) const;
|
||||
sk_sp<SkShader> asShader(const SkSamplingOptions& sampling) const;
|
||||
sk_sp<SkShader> asShader(const SkSamplingOptions& sampling, const SkMatrix& lm) const;
|
||||
|
||||
/**
|
||||
* If the SpecialImage is backed by a gpu texture, return true.
|
||||
*/
|
||||
|
@ -176,9 +176,11 @@ sk_sp<SkSpecialImage> SkRuntimeImageFilter::onFilterImage(const Context& ctx,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkMatrix localM = inverse * SkMatrix::Translate(inputOffset);
|
||||
SkMatrix localM = inverse *
|
||||
SkMatrix::Translate(inputOffset) *
|
||||
SkMatrix::Translate(-input->subset().topLeft());
|
||||
sk_sp<SkShader> inputShader =
|
||||
input->asShader(SkSamplingOptions(SkFilterMode::kLinear), localM);
|
||||
input->asImage()->makeShader(SkSamplingOptions(SkFilterMode::kLinear), &localM);
|
||||
SkASSERT(inputShader);
|
||||
inputShaders.push_back(std::move(inputShader));
|
||||
}
|
||||
|
@ -67,12 +67,7 @@ static SkTileMode optimize(SkTileMode tm, int dimension) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool needs_subset(SkImage* img, const SkRect& subset) {
|
||||
return subset != SkRect::Make(img->dimensions());
|
||||
}
|
||||
|
||||
SkImageShader::SkImageShader(sk_sp<SkImage> img,
|
||||
const SkRect& subset,
|
||||
SkTileMode tmx, SkTileMode tmy,
|
||||
const SkSamplingOptions& sampling,
|
||||
const SkMatrix* localMatrix,
|
||||
@ -83,7 +78,6 @@ SkImageShader::SkImageShader(sk_sp<SkImage> img,
|
||||
, fSampling(sampling)
|
||||
, fTileModeX(optimize(tmx, fImage->width()))
|
||||
, fTileModeY(optimize(tmy, fImage->height()))
|
||||
, fSubset(subset)
|
||||
, fRaw(raw)
|
||||
, fClampAsIfUnpremul(clampAsIfUnpremul) {
|
||||
// These options should never appear together:
|
||||
@ -138,9 +132,6 @@ sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) {
|
||||
bool raw = buffer.isVersionLT(SkPicturePriv::Version::kRawImageShaders) ? false
|
||||
: buffer.readBool();
|
||||
|
||||
// TODO(skbug.com/12784): Subset is not serialized yet; it's only used by special images so it
|
||||
// will never be written to an SKP.
|
||||
|
||||
return raw ? SkImageShader::MakeRaw(std::move(img), tmx, tmy, sampling, &localMatrix)
|
||||
: SkImageShader::Make(std::move(img), tmx, tmy, sampling, &localMatrix);
|
||||
}
|
||||
@ -155,10 +146,6 @@ void SkImageShader::flatten(SkWriteBuffer& buffer) const {
|
||||
buffer.writeImage(fImage.get());
|
||||
SkASSERT(fClampAsIfUnpremul == false);
|
||||
|
||||
// TODO(skbug.com/12784): Subset is not serialized yet; it's only used by special images so it
|
||||
// will never be written to an SKP.
|
||||
SkASSERT(!needs_subset(fImage.get(), fSubset));
|
||||
|
||||
buffer.writeBool(fRaw);
|
||||
}
|
||||
|
||||
@ -202,7 +189,6 @@ static bool legacy_shader_can_handle(const SkMatrix& inv) {
|
||||
|
||||
SkShaderBase::Context* SkImageShader::onMakeContext(const ContextRec& rec,
|
||||
SkArenaAlloc* alloc) const {
|
||||
SkASSERT(!needs_subset(fImage.get(), fSubset)); // TODO(skbug.com/12784)
|
||||
if (fImage->alphaType() == kUnpremul_SkAlphaType) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -279,8 +265,19 @@ sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image,
|
||||
const SkSamplingOptions& options,
|
||||
const SkMatrix* localMatrix,
|
||||
bool clampAsIfUnpremul) {
|
||||
SkRect subset = image ? SkRect::Make(image->dimensions()) : SkRect::MakeEmpty();
|
||||
return MakeSubset(std::move(image), subset, tmx, tmy, options, localMatrix, clampAsIfUnpremul);
|
||||
auto is_unit = [](float x) {
|
||||
return x >= 0 && x <= 1;
|
||||
};
|
||||
if (options.useCubic) {
|
||||
if (!is_unit(options.cubic.B) || !is_unit(options.cubic.C)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (!image) {
|
||||
return sk_make_sp<SkEmptyShader>();
|
||||
}
|
||||
return sk_sp<SkShader>{new SkImageShader(
|
||||
image, tmx, tmy, options, localMatrix, /*raw=*/false, clampAsIfUnpremul)};
|
||||
}
|
||||
|
||||
sk_sp<SkShader> SkImageShader::MakeRaw(sk_sp<SkImage> image,
|
||||
@ -294,36 +291,7 @@ sk_sp<SkShader> SkImageShader::MakeRaw(sk_sp<SkImage> image,
|
||||
return sk_make_sp<SkEmptyShader>();
|
||||
}
|
||||
return sk_sp<SkShader>{new SkImageShader(
|
||||
image, SkRect::Make(image->dimensions()), tmx, tmy, options, localMatrix,
|
||||
/*raw=*/true, /*clampAsIfUnpremul=*/false)};
|
||||
}
|
||||
|
||||
sk_sp<SkShader> SkImageShader::MakeSubset(sk_sp<SkImage> image,
|
||||
const SkRect& subset,
|
||||
SkTileMode tmx, SkTileMode tmy,
|
||||
const SkSamplingOptions& options,
|
||||
const SkMatrix* localMatrix,
|
||||
bool clampAsIfUnpremul) {
|
||||
auto is_unit = [](float x) {
|
||||
return x >= 0 && x <= 1;
|
||||
};
|
||||
if (options.useCubic) {
|
||||
if (!is_unit(options.cubic.B) || !is_unit(options.cubic.C)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (!image || subset.isEmpty()) {
|
||||
return sk_make_sp<SkEmptyShader>();
|
||||
}
|
||||
|
||||
// Validate subset and check if we can drop it
|
||||
if (!SkRect::Make(image->bounds()).contains(subset)) {
|
||||
return nullptr;
|
||||
}
|
||||
// TODO(skbug.com/12784): GPU-only for now since it's only supported in onAsFragmentProcessor()
|
||||
SkASSERT(!needs_subset(image.get(), subset) || image->isTextureBacked());
|
||||
return sk_sp<SkShader>{new SkImageShader(
|
||||
image, subset, tmx, tmy, options, localMatrix, /*raw=*/false, clampAsIfUnpremul)};
|
||||
image, tmx, tmy, options, localMatrix, /*raw=*/true, /*clampAsIfUnpremul=*/false)};
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -342,12 +310,10 @@ std::unique_ptr<GrFragmentProcessor> SkImageShader::asFragmentProcessor(
|
||||
}
|
||||
|
||||
SkTileMode tileModes[2] = {fTileModeX, fTileModeY};
|
||||
const SkRect* subset = needs_subset(fImage.get(), fSubset) ? &fSubset : nullptr;
|
||||
auto fp = as_IB(fImage.get())->asFragmentProcessor(args.fContext,
|
||||
fSampling,
|
||||
tileModes,
|
||||
lmInverse,
|
||||
subset);
|
||||
lmInverse);
|
||||
if (!fp) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -441,7 +407,6 @@ static SkMatrix tweak_inv_matrix(SkFilterMode filter, SkMatrix matrix) {
|
||||
}
|
||||
|
||||
bool SkImageShader::doStages(const SkStageRec& rec, TransformShader* updater) const {
|
||||
SkASSERT(!needs_subset(fImage.get(), fSubset)); // TODO(skbug.com/12784)
|
||||
// We only support certain sampling options in stages so far
|
||||
auto sampling = fSampling;
|
||||
if (sampling.useCubic) {
|
||||
@ -740,7 +705,7 @@ skvm::Color SkImageShader::makeProgram(
|
||||
skvm::Builder* p, skvm::Coord device, skvm::Coord origLocal, skvm::Color paint,
|
||||
const SkMatrixProvider& matrices, const SkMatrix* localM, const SkColorInfo& dst,
|
||||
skvm::Uniforms* uniforms, const TransformShader* coordShader, SkArenaAlloc* alloc) const {
|
||||
SkASSERT(!needs_subset(fImage.get(), fSubset)); // TODO(skbug.com/12784)
|
||||
|
||||
SkMatrix baseInv;
|
||||
if (!this->computeTotalInverse(matrices.localToDevice(), localM, &baseInv)) {
|
||||
return {};
|
||||
|
@ -28,16 +28,6 @@ public:
|
||||
const SkSamplingOptions&,
|
||||
const SkMatrix* localMatrix);
|
||||
|
||||
// TODO(skbug.com/12784): Requires SkImage to be texture backed, and created SkShader can only
|
||||
// be used on GPU-backed surfaces.
|
||||
static sk_sp<SkShader> MakeSubset(sk_sp<SkImage>,
|
||||
const SkRect& subset,
|
||||
SkTileMode tmx,
|
||||
SkTileMode tmy,
|
||||
const SkSamplingOptions&,
|
||||
const SkMatrix* localMatrix,
|
||||
bool clampAsIfUnpremul = false);
|
||||
|
||||
bool isOpaque() const override;
|
||||
|
||||
#if SK_SUPPORT_GPU
|
||||
@ -50,7 +40,6 @@ private:
|
||||
SK_FLATTENABLE_HOOKS(SkImageShader)
|
||||
|
||||
SkImageShader(sk_sp<SkImage>,
|
||||
const SkRect& subset,
|
||||
SkTileMode tmx,
|
||||
SkTileMode tmy,
|
||||
const SkSamplingOptions&,
|
||||
@ -85,11 +74,6 @@ private:
|
||||
const SkSamplingOptions fSampling;
|
||||
const SkTileMode fTileModeX;
|
||||
const SkTileMode fTileModeY;
|
||||
|
||||
// TODO(skbug.com/12784): This is only supported for GPU images currently.
|
||||
// If subset == (0,0,w,h) of the image, then no subset is applied. Subset will not be empty.
|
||||
const SkRect fSubset;
|
||||
|
||||
const bool fRaw;
|
||||
const bool fClampAsIfUnpremul;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user