Move image sampling options into their own header

Experimenting with a single struct for everything, to simplify the
number of API changes/additions needed.

e.g. makeShader(...)

Idea is to use SkSampleOptions to augment drawBitmap calls, so we can
remove SkFilterQuality enum from SkPaint.

Change-Id: I9045ff483f58af29148d7dc21d30b294c4a718a1
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/332739
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Mike Reed <reed@google.com>
This commit is contained in:
Mike Reed 2020-11-06 09:50:47 -05:00 committed by Skia Commit-Bot
parent 7990e03d04
commit 15b95d6f6c
6 changed files with 110 additions and 110 deletions

View File

@ -13,6 +13,7 @@
#include "include/core/SkImageInfo.h"
#include "include/core/SkM44.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkSamplingOptions.h"
#include "include/core/SkScalar.h"
#include "include/core/SkShader.h"
#include "include/core/SkTileMode.h"
@ -41,22 +42,6 @@ class GrYUVABackendTextures;
struct SkYUVAIndex;
enum class SkSamplingMode {
kNearest, // single sample point (nearest neighbor)
kLinear, // interporate between 2x2 sample points (bilinear interpolation)
};
enum class SkMipmapMode {
kNone, // ignore mipmap levels, sample from the "base"
kNearest, // sample from the nearest level
kLinear, // interpolate between the two nearest levels
};
struct SkFilterOptions {
SkSamplingMode fSampling;
SkMipmapMode fMipmap;
};
class SkMipmapBuilder {
public:
SkMipmapBuilder(const SkImageInfo&);
@ -731,36 +716,10 @@ public:
/**
* Make a shader with the specified tiling and mipmap sampling.
*/
sk_sp<SkShader> makeShader(SkTileMode tmx, SkTileMode tmy, const SkFilterOptions&,
sk_sp<SkShader> makeShader(SkTileMode tmx, SkTileMode tmy, const SkSamplingOptions&,
const SkMatrix* localMatrix = nullptr) const;
/*
* Specify B and C (each between 0...1) to create a shader that applies the corresponding
* cubic reconstruction filter to the image.
*
* Example values:
* B = 1/3, C = 1/3 "Mitchell" filter
* B = 0, C = 1/2 "Catmull-Rom" filter
*
* See "Reconstruction Filters in Computer Graphics"
* Don P. Mitchell
* Arun N. Netravali
* 1988
* https://www.cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/mitchell/Mitchell.pdf
*
* Desmos worksheet https://www.desmos.com/calculator/aghdpicrvr
* Nice overview https://entropymine.com/imageworsener/bicubic/
*/
struct CubicResampler {
float B, C;
};
/**
* Make a shader with the specified tiling and CubicResampler parameters.
* Returns nullptr if the resampler values are outside of [0...1]
*/
sk_sp<SkShader> makeShader(SkTileMode tmx, SkTileMode tmy, CubicResampler,
const SkMatrix* localMatrix = nullptr) const;
using CubicResampler = SkCubicResampler;
/** Creates SkShader from SkImage. SkShader dimensions are taken from SkImage. SkShader uses
SkTileMode rules to fill drawn area outside SkImage. localMatrix permits

View File

@ -0,0 +1,74 @@
/*
* Copyright 2020 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef SkImageSampling_DEFINED
#define SkImageSampling_DEFINED
#include "include/core/SkTypes.h"
enum class SkSamplingMode {
kNearest, // single sample point (nearest neighbor)
kLinear, // interporate between 2x2 sample points (bilinear interpolation)
};
enum class SkMipmapMode {
kNone, // ignore mipmap levels, sample from the "base"
kNearest, // sample from the nearest level
kLinear, // interpolate between the two nearest levels
};
/*
* Specify B and C (each between 0...1) to create a shader that applies the corresponding
* cubic reconstruction filter to the image.
*
* Example values:
* B = 1/3, C = 1/3 "Mitchell" filter
* B = 0, C = 1/2 "Catmull-Rom" filter
*
* See "Reconstruction Filters in Computer Graphics"
* Don P. Mitchell
* Arun N. Netravali
* 1988
* https://www.cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/mitchell/Mitchell.pdf
*
* Desmos worksheet https://www.desmos.com/calculator/aghdpicrvr
* Nice overview https://entropymine.com/imageworsener/bicubic/
*/
struct SkCubicResampler {
float B, C;
};
struct SkFilterOptions {
SkSamplingMode fSampling;
SkMipmapMode fMipmap;
};
struct SkSamplingOptions {
bool fUseCubic;
SkCubicResampler fCubic; //!< use if fUseCubic is true
SkFilterOptions fFilter; //!< use if fUseCubic is false
SkSamplingOptions()
: fUseCubic(false)
, fCubic({0,0})
, fFilter({SkSamplingMode::kNearest, SkMipmapMode::kNone})
{}
SkSamplingOptions(const SkFilterOptions& filter)
: fUseCubic(false)
, fCubic({0,0}) // ignored
, fFilter(filter)
{}
SkSamplingOptions(const SkCubicResampler& cubic)
: fUseCubic(true)
, fCubic(cubic)
, fFilter({SkSamplingMode::kNearest, SkMipmapMode::kNone}) // ignored
{}
};
#endif

View File

@ -206,7 +206,7 @@ class CubicResamplerDemo : public Sample {
sk_sp<SkImage> fImage;
SkRect fBounds;
void draw(SkCanvas* canvas, SkImage::CubicResampler cubic) const {
void draw(SkCanvas* canvas, SkCubicResampler cubic) const {
SkRect r = fBounds;
SkPaint paint;
@ -219,7 +219,8 @@ class CubicResamplerDemo : public Sample {
lm.postTranslate(r.width() + 10, 0);
paint.setShader(fImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp,
{SkSamplingMode::kLinear, SkMipmapMode::kNone},
SkFilterOptions{ SkSamplingMode::kLinear,
SkMipmapMode::kNone },
&lm));
canvas->drawRect(r, paint);

View File

@ -141,7 +141,7 @@ sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy,
}
sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy,
const SkFilterOptions& options,
const SkSamplingOptions& options,
const SkMatrix* localMatrix) const {
return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy,
options, localMatrix);
@ -153,12 +153,6 @@ sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy,
SkImageShader::FilterEnum(filtering));
}
sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy, CubicResampler cubic,
const SkMatrix* localMatrix) const {
return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy, cubic,
localMatrix);
}
sk_sp<SkData> SkImage::encodeToData(SkEncodedImageFormat type, int quality) const {
// Context TODO: Elevate GrDirectContext requirement to public API.
auto dContext = as_IB(this)->directContext();

View File

@ -79,29 +79,17 @@ SkImageShader::SkImageShader(sk_sp<SkImage> img,
SkImageShader::SkImageShader(sk_sp<SkImage> img,
SkTileMode tmx, SkTileMode tmy,
const SkFilterOptions& options,
const SkSamplingOptions& options,
const SkMatrix* localMatrix)
: INHERITED(localMatrix)
, fImage(std::move(img))
, fTileModeX(optimize(tmx, fImage->width()))
, fTileModeY(optimize(tmy, fImage->height()))
, fFilterEnum(FilterEnum::kUseFilterOptions)
, fFilterEnum(options.fUseCubic ? FilterEnum::kUseCubicResampler
: FilterEnum::kUseFilterOptions)
, fClampAsIfUnpremul(false)
, fFilterOptions(options)
{}
SkImageShader::SkImageShader(sk_sp<SkImage> img,
SkTileMode tmx, SkTileMode tmy,
SkImage::CubicResampler cubic,
const SkMatrix* localMatrix)
: INHERITED(localMatrix)
, fImage(std::move(img))
, fTileModeX(optimize(tmx, fImage->width()))
, fTileModeY(optimize(tmy, fImage->height()))
, fFilterEnum(FilterEnum::kUseCubicResampler)
, fClampAsIfUnpremul(false)
, fFilterOptions({}) // ignored
, fCubic(cubic)
, fFilterOptions(options.fFilter)
, fCubic(options.fCubic)
{}
// fClampAsIfUnpremul is always false when constructed through public APIs,
@ -116,23 +104,25 @@ sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) {
fe = buffer.read32LE<FilterEnum>(kLast);
}
SkFilterOptions fo{ SkSamplingMode::kNearest, SkMipmapMode::kNone };
SkImage::CubicResampler cubic{};
SkSamplingOptions op;
if (buffer.isVersionLT(SkPicturePriv::kCubicResamplerImageShader_Version)) {
if (!buffer.isVersionLT(SkPicturePriv::kFilterOptionsInImageShader_Version)) {
fo.fSampling = buffer.read32LE<SkSamplingMode>(SkSamplingMode::kLinear);
fo.fMipmap = buffer.read32LE<SkMipmapMode>(SkMipmapMode::kLinear);
op.fUseCubic = false;
op.fFilter.fSampling = buffer.read32LE<SkSamplingMode>(SkSamplingMode::kLinear);
op.fFilter.fMipmap = buffer.read32LE<SkMipmapMode>(SkMipmapMode::kLinear);
}
} else {
switch (fe) {
case kUseFilterOptions:
fo.fSampling = buffer.read32LE<SkSamplingMode>(SkSamplingMode::kLinear);
fo.fMipmap = buffer.read32LE<SkMipmapMode>(SkMipmapMode::kLinear);
op.fUseCubic = false;
op.fFilter.fSampling = buffer.read32LE<SkSamplingMode>(SkSamplingMode::kLinear);
op.fFilter.fMipmap = buffer.read32LE<SkMipmapMode>(SkMipmapMode::kLinear);
break;
case kUseCubicResampler:
cubic.B = buffer.readScalar();
cubic.C = buffer.readScalar();
op.fUseCubic = true;
op.fCubic.B = buffer.readScalar();
op.fCubic.C = buffer.readScalar();
break;
default:
break;
@ -148,9 +138,8 @@ sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) {
switch (fe) {
case kUseFilterOptions:
return SkImageShader::Make(std::move(img), tmx, tmy, fo, &localMatrix);
case kUseCubicResampler:
return SkImageShader::Make(std::move(img), tmx, tmy, cubic, &localMatrix);
return SkImageShader::Make(std::move(img), tmx, tmy, op, &localMatrix);
default:
break;
}
@ -297,8 +286,16 @@ sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image,
sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image,
SkTileMode tmx, SkTileMode tmy,
const SkFilterOptions& options,
const SkSamplingOptions& options,
const SkMatrix* localMatrix) {
auto is_unit = [](float x) {
return x >= 0 && x <= 1;
};
if (options.fUseCubic) {
if (!is_unit(options.fCubic.B) || !is_unit(options.fCubic.C)) {
return nullptr;
}
}
if (!image) {
return sk_make_sp<SkEmptyShader>();
}
@ -307,20 +304,6 @@ sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image,
};
}
sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image, SkTileMode tmx, SkTileMode tmy,
SkImage::CubicResampler cubic, const SkMatrix* localMatrix) {
if (!(cubic.B >= 0 && cubic.B <= 1 &&
cubic.C >= 0 && cubic.C <= 1)) {
return nullptr;
}
if (!image) {
return sk_make_sp<SkEmptyShader>();
}
return sk_sp<SkShader>{
new SkImageShader(image, tmx, tmy, cubic, localMatrix)
};
}
///////////////////////////////////////////////////////////////////////////////////////////////////
#if SK_SUPPORT_GPU
@ -393,7 +376,7 @@ std::unique_ptr<GrFragmentProcessor> SkImageShader::asFragmentProcessor(
GrSamplerState::Filter fm;
GrSamplerState::MipmapMode mm;
bool bicubic;
SkImage::CubicResampler kernel = GrBicubicEffect::gMitchell;
SkCubicResampler kernel = GrBicubicEffect::gMitchell;
switch (fFilterEnum) {
case FilterEnum::kUseFilterOptions:

View File

@ -42,13 +42,7 @@ public:
static sk_sp<SkShader> Make(sk_sp<SkImage>,
SkTileMode tmx,
SkTileMode tmy,
const SkFilterOptions&,
const SkMatrix* localMatrix);
static sk_sp<SkShader> Make(sk_sp<SkImage>,
SkTileMode tmx,
SkTileMode tmy,
SkImage::CubicResampler,
const SkSamplingOptions&,
const SkMatrix* localMatrix);
bool isOpaque() const override;
@ -71,12 +65,7 @@ private:
SkImageShader(sk_sp<SkImage>,
SkTileMode tmx,
SkTileMode tmy,
const SkFilterOptions&,
const SkMatrix* localMatrix);
SkImageShader(sk_sp<SkImage>,
SkTileMode tmx,
SkTileMode tmy,
SkImage::CubicResampler,
const SkSamplingOptions&,
const SkMatrix* localMatrix);
void flatten(SkWriteBuffer&) const override;
@ -114,7 +103,7 @@ private:
// only use this if fFilterEnum == kUseFilterOptions
SkFilterOptions fFilterOptions;
// only use this if fFilterEnum == kUseCubicResampler or kHigh
SkImage::CubicResampler fCubic = {1/3.0f, 1/3.0f}; // Default to Mitchell-Netravali.
SkCubicResampler fCubic = {1/3.0f, 1/3.0f}; // Default to Mitchell-Netravali.
friend class SkShaderBase;
using INHERITED = SkShaderBase;