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:
parent
7990e03d04
commit
15b95d6f6c
@ -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
|
||||
|
74
include/core/SkSamplingOptions.h
Normal file
74
include/core/SkSamplingOptions.h
Normal 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
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user