Add anisotropic option to SkSamplingOptions.
Implement on GPU. Bug: skia:13036 Change-Id: I35d760596c4f8faaec27fccf284b70802fcf3f9b Reviewed-on: https://skia-review.googlesource.com/c/skia/+/524757 Commit-Queue: Brian Salomon <bsalomon@google.com> Reviewed-by: Brian Osman <brianosman@google.com> Reviewed-by: Michael Ludwig <michaelludwig@google.com>
This commit is contained in:
parent
0ec88022ff
commit
9be2d572d4
@ -2,6 +2,12 @@ Skia Graphics Release Notes
|
|||||||
|
|
||||||
This file includes a list of high level updates for each milestone release.
|
This file includes a list of high level updates for each milestone release.
|
||||||
|
|
||||||
|
Milestone 103
|
||||||
|
-------------
|
||||||
|
* SkSamplingOptions now includes anisotropic filtering. Implemented on GPU only.
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
Milestone 102
|
Milestone 102
|
||||||
-------------
|
-------------
|
||||||
* Add glGetFloatv and glSamplerParameterf to GrGLInterface.
|
* Add glGetFloatv and glSamplerParameterf to GrGLInterface.
|
||||||
|
@ -21,13 +21,39 @@ namespace skiagm {
|
|||||||
// This GM exercises anisotropic image scaling.
|
// This GM exercises anisotropic image scaling.
|
||||||
class AnisotropicGM : public GM {
|
class AnisotropicGM : public GM {
|
||||||
public:
|
public:
|
||||||
AnisotropicGM() : fSampling(SkFilterMode::kLinear, SkMipmapMode::kLinear) {
|
enum class Mode { kLinear, kMip, kAniso };
|
||||||
|
|
||||||
|
AnisotropicGM(Mode mode) : fMode(mode) {
|
||||||
|
switch (fMode) {
|
||||||
|
case Mode::kLinear:
|
||||||
|
fSampling = SkSamplingOptions(SkFilterMode::kLinear);
|
||||||
|
break;
|
||||||
|
case Mode::kMip:
|
||||||
|
fSampling = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
|
||||||
|
break;
|
||||||
|
case Mode::kAniso:
|
||||||
|
fSampling = SkSamplingOptions::Aniso(16);
|
||||||
|
break;
|
||||||
|
}
|
||||||
this->setBGColor(0xFFCCCCCC);
|
this->setBGColor(0xFFCCCCCC);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
SkString onShortName() override {
|
||||||
SkString onShortName() override { return SkString("anisotropic_image_scale_mip"); }
|
SkString name("anisotropic_image_scale_");
|
||||||
|
switch (fMode) {
|
||||||
|
case Mode::kLinear:
|
||||||
|
name += "linear";
|
||||||
|
break;
|
||||||
|
case Mode::kMip:
|
||||||
|
name += "mip";
|
||||||
|
break;
|
||||||
|
case Mode::kAniso:
|
||||||
|
name += "aniso";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
SkISize onISize() override {
|
SkISize onISize() override {
|
||||||
return SkISize::Make(2*kImageSize + 3*kSpacer,
|
return SkISize::Make(2*kImageSize + 3*kSpacer,
|
||||||
@ -112,11 +138,112 @@ private:
|
|||||||
|
|
||||||
sk_sp<SkImage> fImage;
|
sk_sp<SkImage> fImage;
|
||||||
SkSamplingOptions fSampling;
|
SkSamplingOptions fSampling;
|
||||||
|
Mode fMode;
|
||||||
|
|
||||||
using INHERITED = GM;
|
using INHERITED = GM;
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
DEF_GM(return new AnisotropicGM;)
|
DEF_GM(return new AnisotropicGM(AnisotropicGM::Mode::kLinear);)
|
||||||
|
DEF_GM(return new AnisotropicGM(AnisotropicGM::Mode::kMip);)
|
||||||
|
DEF_GM(return new AnisotropicGM(AnisotropicGM::Mode::kAniso);)
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class AnisoMipsGM : public GM {
|
||||||
|
public:
|
||||||
|
AnisoMipsGM() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SkString onShortName() override { return SkString("anisomips"); }
|
||||||
|
|
||||||
|
SkISize onISize() override { return SkISize::Make(520, 260); }
|
||||||
|
|
||||||
|
sk_sp<SkImage> updateImage(SkSurface* surf, SkColor color) {
|
||||||
|
surf->getCanvas()->clear(color);
|
||||||
|
SkPaint paint;
|
||||||
|
paint.setColor(~color | 0xFF000000);
|
||||||
|
surf->getCanvas()->drawRect(SkRect::MakeLTRB(surf->width() *2/5.f,
|
||||||
|
surf->height()*2/5.f,
|
||||||
|
surf->width() *3/5.f,
|
||||||
|
surf->height()*3/5.f),
|
||||||
|
paint);
|
||||||
|
return surf->makeImageSnapshot()->withDefaultMipmaps();
|
||||||
|
}
|
||||||
|
|
||||||
|
void onDraw(SkCanvas* canvas) override {
|
||||||
|
auto ct = canvas->imageInfo().colorType() == kUnknown_SkColorType
|
||||||
|
? kRGBA_8888_SkColorType
|
||||||
|
: canvas->imageInfo().colorType();
|
||||||
|
auto ii = SkImageInfo::Make(kImageSize,
|
||||||
|
kImageSize,
|
||||||
|
ct,
|
||||||
|
kPremul_SkAlphaType,
|
||||||
|
canvas->imageInfo().refColorSpace());
|
||||||
|
// In GPU mode we want a surface that is created with mipmaps to ensure that we exercise the
|
||||||
|
// case where the SkSurface and SkImage share a texture. If the surface texture isn't
|
||||||
|
// created with MIPs then asking for a mipmapped image will cause a copy to a mipped
|
||||||
|
// texture.
|
||||||
|
sk_sp<SkSurface> surface;
|
||||||
|
if (auto rc = canvas->recordingContext()) {
|
||||||
|
surface = SkSurface::MakeRenderTarget(rc,
|
||||||
|
SkBudgeted::kYes,
|
||||||
|
ii,
|
||||||
|
1,
|
||||||
|
kTopLeft_GrSurfaceOrigin,
|
||||||
|
/*surfaceProps=*/nullptr,
|
||||||
|
/*shouldCreateWithMips=*/true);
|
||||||
|
} else {
|
||||||
|
surface = canvas->makeSurface(ii);
|
||||||
|
if (!surface) { // could be a recording canvas.
|
||||||
|
surface = SkSurface::MakeRaster(ii);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr float kScales[] = {1.f, 0.5f, 0.25f, 0.125f};
|
||||||
|
SkColor kColors[] = {0xFFF0F0F0, SK_ColorBLUE, SK_ColorGREEN, SK_ColorRED};
|
||||||
|
static const SkSamplingOptions kSampling = SkSamplingOptions::Aniso(16);
|
||||||
|
|
||||||
|
for (bool shader : {false, true}) {
|
||||||
|
int c = 0;
|
||||||
|
canvas->save();
|
||||||
|
for (float sy : kScales) {
|
||||||
|
canvas->save();
|
||||||
|
for (float sx : kScales) {
|
||||||
|
canvas->save();
|
||||||
|
canvas->scale(sx, sy);
|
||||||
|
auto image = this->updateImage(surface.get(), kColors[c]);
|
||||||
|
if (shader) {
|
||||||
|
SkPaint paint;
|
||||||
|
paint.setShader(image->makeShader(kSampling));
|
||||||
|
canvas->drawRect(SkRect::Make(image->dimensions()), paint);
|
||||||
|
} else {
|
||||||
|
canvas->drawImage(image, 0, 0, kSampling);
|
||||||
|
}
|
||||||
|
canvas->restore();
|
||||||
|
canvas->translate(ii.width() * sx + kPad, 0);
|
||||||
|
c = (c + 1) % SK_ARRAY_COUNT(kColors);
|
||||||
|
}
|
||||||
|
canvas->restore();
|
||||||
|
canvas->translate(0, ii.width() * sy + kPad);
|
||||||
|
}
|
||||||
|
canvas->restore();
|
||||||
|
for (float sx : kScales) {
|
||||||
|
canvas->translate(ii.width() * sx + kPad, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
inline static constexpr int kImageSize = 128;
|
||||||
|
inline static constexpr int kPad = 5;
|
||||||
|
|
||||||
|
using INHERITED = GM;
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
DEF_GM(return new AnisoMipsGM();)
|
||||||
|
|
||||||
} // namespace skiagm
|
} // namespace skiagm
|
||||||
|
@ -158,10 +158,12 @@ protected:
|
|||||||
canvas->translate(0, SkIntToScalar(kCellSize));
|
canvas->translate(0, SkIntToScalar(kCellSize));
|
||||||
this->drawRow(canvas, SkSamplingOptions(SkCubicResampler::Mitchell()));
|
this->drawRow(canvas, SkSamplingOptions(SkCubicResampler::Mitchell()));
|
||||||
canvas->translate(0, SkIntToScalar(kCellSize));
|
canvas->translate(0, SkIntToScalar(kCellSize));
|
||||||
|
this->drawRow(canvas, SkSamplingOptions::Aniso(16));
|
||||||
|
canvas->translate(0, SkIntToScalar(kCellSize));
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
inline static constexpr int kCellSize = 50;
|
inline static constexpr int kCellSize = 50;
|
||||||
inline static constexpr int kNumRows = 4;
|
inline static constexpr int kNumRows = 5;
|
||||||
inline static constexpr int kNumCols = 6;
|
inline static constexpr int kNumCols = 6;
|
||||||
|
|
||||||
bool fDoAA;
|
bool fDoAA;
|
||||||
|
@ -66,7 +66,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
SkISize onISize() override {
|
SkISize onISize() override {
|
||||||
return SkISize::Make(520, 100);
|
return SkISize::Make(630, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onDraw(SkCanvas* canvas) override {
|
void onDraw(SkCanvas* canvas) override {
|
||||||
@ -77,20 +77,15 @@ protected:
|
|||||||
SkSamplingOptions(SkFilterMode::kLinear),
|
SkSamplingOptions(SkFilterMode::kLinear),
|
||||||
SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear),
|
SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear),
|
||||||
SkSamplingOptions(SkCubicResampler::Mitchell()),
|
SkSamplingOptions(SkCubicResampler::Mitchell()),
|
||||||
|
SkSamplingOptions::Aniso(16),
|
||||||
};
|
};
|
||||||
const SkRect srcRect = SkRect::MakeWH(96, 96);
|
const SkRect srcRect = SkRect::MakeWH(96, 96);
|
||||||
const SkSize deviceSize = SkSize::Make(16, 16);
|
const SkSize deviceSize = SkSize::Make(16, 16);
|
||||||
|
|
||||||
this->draw(canvas, srcRect, deviceSize, samplings[0], nullptr);
|
for (const auto& sampling : samplings) {
|
||||||
|
this->draw(canvas, srcRect, deviceSize, sampling, nullptr);
|
||||||
canvas->translate(srcRect.width() + SkIntToScalar(10), 0);
|
canvas->translate(srcRect.width() + SkIntToScalar(10), 0);
|
||||||
this->draw(canvas, srcRect, deviceSize, samplings[1], nullptr);
|
}
|
||||||
|
|
||||||
canvas->translate(srcRect.width() + SkIntToScalar(10), 0);
|
|
||||||
this->draw(canvas, srcRect, deviceSize, samplings[2], nullptr);
|
|
||||||
|
|
||||||
canvas->translate(srcRect.width() + SkIntToScalar(10), 0);
|
|
||||||
this->draw(canvas, srcRect, deviceSize, samplings[3], nullptr);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(16, 16));
|
sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(16, 16));
|
||||||
@ -109,7 +104,6 @@ protected:
|
|||||||
sk_sp<SkImageFilter> source(
|
sk_sp<SkImageFilter> source(
|
||||||
SkImageFilters::Image(std::move(image), inRect, outRect,
|
SkImageFilters::Image(std::move(image), inRect, outRect,
|
||||||
SkSamplingOptions({1/3.0f, 1/3.0f})));
|
SkSamplingOptions({1/3.0f, 1/3.0f})));
|
||||||
canvas->translate(srcRect.width() + SkIntToScalar(10), 0);
|
|
||||||
this->draw(canvas, srcRect, deviceSize, samplings[3], std::move(source));
|
this->draw(canvas, srcRect, deviceSize, samplings[3], std::move(source));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@ const SkSamplingOptions gSamplings[] = {
|
|||||||
SkSamplingOptions(SkFilterMode::kLinear),
|
SkSamplingOptions(SkFilterMode::kLinear),
|
||||||
SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear),
|
SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear),
|
||||||
SkSamplingOptions(SkCubicResampler::Mitchell()),
|
SkSamplingOptions(SkCubicResampler::Mitchell()),
|
||||||
|
SkSamplingOptions::Aniso(16),
|
||||||
};
|
};
|
||||||
|
|
||||||
static void makebm(SkBitmap* bm, SkColorType ct, int w, int h) {
|
static void makebm(SkBitmap* bm, SkColorType ct, int w, int h) {
|
||||||
@ -81,7 +82,7 @@ protected:
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkISize onISize() override { return SkISize::Make(880, 760); }
|
SkISize onISize() override { return SkISize::Make(880, 880); }
|
||||||
|
|
||||||
void onOnceBeforeDraw() override {
|
void onOnceBeforeDraw() override {
|
||||||
int size = fPowerOfTwoSize ? kPOTSize : kNPOTSize;
|
int size = fPowerOfTwoSize ? kPOTSize : kNPOTSize;
|
||||||
@ -102,7 +103,7 @@ protected:
|
|||||||
|
|
||||||
const char* gColorTypeNames[] = { "8888" , "565", "4444" };
|
const char* gColorTypeNames[] = { "8888" , "565", "4444" };
|
||||||
|
|
||||||
const char* gFilterNames[] = { "None", "Low", "Medium", "High" };
|
const char* gFilterNames[] = { "Nearest", "Linear", "Trilinear", "Mitchell", "Aniso" };
|
||||||
|
|
||||||
constexpr SkTileMode gModes[] = {
|
constexpr SkTileMode gModes[] = {
|
||||||
SkTileMode::kClamp, SkTileMode::kRepeat, SkTileMode::kMirror };
|
SkTileMode::kClamp, SkTileMode::kRepeat, SkTileMode::kMirror };
|
||||||
|
@ -1444,8 +1444,8 @@ public:
|
|||||||
/** \enum SkCanvas::SrcRectConstraint
|
/** \enum SkCanvas::SrcRectConstraint
|
||||||
SrcRectConstraint controls the behavior at the edge of source SkRect,
|
SrcRectConstraint controls the behavior at the edge of source SkRect,
|
||||||
provided to drawImageRect() when there is any filtering. If kStrict is set,
|
provided to drawImageRect() when there is any filtering. If kStrict is set,
|
||||||
then extra code is used to ensure it nevers samples outside of the src-rect.
|
then extra code is used to ensure it never samples outside of the src-rect.
|
||||||
kStrict_SrcRectConstraint disables the use of mipmaps.
|
kStrict_SrcRectConstraint disables the use of mipmaps and anisotropic filtering.
|
||||||
*/
|
*/
|
||||||
enum SrcRectConstraint {
|
enum SrcRectConstraint {
|
||||||
kStrict_SrcRectConstraint, //!< sample only inside bounds; slower
|
kStrict_SrcRectConstraint, //!< sample only inside bounds; slower
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
#define SkImageSampling_DEFINED
|
#define SkImageSampling_DEFINED
|
||||||
|
|
||||||
#include "include/core/SkTypes.h"
|
#include "include/core/SkTypes.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
enum class SkFilterMode {
|
enum class SkFilterMode {
|
||||||
@ -52,6 +54,7 @@ struct SkCubicResampler {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct SK_API SkSamplingOptions {
|
struct SK_API SkSamplingOptions {
|
||||||
|
const int maxAniso = 0;
|
||||||
const bool useCubic = false;
|
const bool useCubic = false;
|
||||||
const SkCubicResampler cubic = {0, 0};
|
const SkCubicResampler cubic = {0, 0};
|
||||||
const SkFilterMode filter = SkFilterMode::kNearest;
|
const SkFilterMode filter = SkFilterMode::kNearest;
|
||||||
@ -66,27 +69,35 @@ struct SK_API SkSamplingOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SkSamplingOptions(SkFilterMode fm, SkMipmapMode mm)
|
SkSamplingOptions(SkFilterMode fm, SkMipmapMode mm)
|
||||||
: useCubic(false)
|
: filter(fm)
|
||||||
, filter(fm)
|
|
||||||
, mipmap(mm) {}
|
, mipmap(mm) {}
|
||||||
|
|
||||||
explicit SkSamplingOptions(SkFilterMode fm)
|
explicit SkSamplingOptions(SkFilterMode fm)
|
||||||
: useCubic(false)
|
: filter(fm)
|
||||||
, filter(fm)
|
|
||||||
, mipmap(SkMipmapMode::kNone) {}
|
, mipmap(SkMipmapMode::kNone) {}
|
||||||
|
|
||||||
explicit SkSamplingOptions(const SkCubicResampler& c)
|
explicit SkSamplingOptions(const SkCubicResampler& c)
|
||||||
: useCubic(true)
|
: useCubic(true)
|
||||||
, cubic(c) {}
|
, cubic(c) {}
|
||||||
|
|
||||||
|
static SkSamplingOptions Aniso(int maxAniso) {
|
||||||
|
return SkSamplingOptions{std::max(maxAniso, 1)};
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const SkSamplingOptions& other) const {
|
bool operator==(const SkSamplingOptions& other) const {
|
||||||
return useCubic == other.useCubic
|
return maxAniso == other.maxAniso
|
||||||
|
&& useCubic == other.useCubic
|
||||||
&& cubic.B == other.cubic.B
|
&& cubic.B == other.cubic.B
|
||||||
&& cubic.C == other.cubic.C
|
&& cubic.C == other.cubic.C
|
||||||
&& filter == other.filter
|
&& filter == other.filter
|
||||||
&& mipmap == other.mipmap;
|
&& mipmap == other.mipmap;
|
||||||
}
|
}
|
||||||
bool operator!=(const SkSamplingOptions& other) const { return !(*this == other); }
|
bool operator!=(const SkSamplingOptions& other) const { return !(*this == other); }
|
||||||
|
|
||||||
|
bool isAniso() const { return maxAniso != 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SkSamplingOptions(int maxAniso) : maxAniso(maxAniso) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -184,6 +184,7 @@ bool SkBitmapProcState::init(const SkMatrix& inv, SkAlpha paintAlpha,
|
|||||||
const SkSamplingOptions& sampling) {
|
const SkSamplingOptions& sampling) {
|
||||||
SkASSERT(!inv.hasPerspective());
|
SkASSERT(!inv.hasPerspective());
|
||||||
SkASSERT(SkOpts::S32_alpha_D32_filter_DXDY || inv.isScaleTranslate());
|
SkASSERT(SkOpts::S32_alpha_D32_filter_DXDY || inv.isScaleTranslate());
|
||||||
|
SkASSERT(!sampling.isAniso());
|
||||||
SkASSERT(!sampling.useCubic);
|
SkASSERT(!sampling.useCubic);
|
||||||
SkASSERT(sampling.mipmap != SkMipmapMode::kLinear);
|
SkASSERT(sampling.mipmap != SkMipmapMode::kLinear);
|
||||||
|
|
||||||
|
@ -2262,9 +2262,13 @@ void SkCanvas::onDrawImage2(const SkImage* image, SkScalar x, SkScalar y,
|
|||||||
static SkSamplingOptions clean_sampling_for_constraint(
|
static SkSamplingOptions clean_sampling_for_constraint(
|
||||||
const SkSamplingOptions& sampling,
|
const SkSamplingOptions& sampling,
|
||||||
SkCanvas::SrcRectConstraint constraint) {
|
SkCanvas::SrcRectConstraint constraint) {
|
||||||
if (constraint == SkCanvas::kStrict_SrcRectConstraint &&
|
if (constraint == SkCanvas::kStrict_SrcRectConstraint) {
|
||||||
sampling.mipmap != SkMipmapMode::kNone) {
|
if (sampling.mipmap != SkMipmapMode::kNone) {
|
||||||
return SkSamplingOptions(sampling.filter);
|
return SkSamplingOptions(sampling.filter);
|
||||||
|
}
|
||||||
|
if (sampling.isAniso()) {
|
||||||
|
return SkSamplingOptions(SkFilterMode::kLinear);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return sampling;
|
return sampling;
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,8 @@ public:
|
|||||||
// V88: Add blender to ComposeShader and BlendImageFilter
|
// V88: Add blender to ComposeShader and BlendImageFilter
|
||||||
// V89: Deprecated SkClipOps are no longer supported
|
// V89: Deprecated SkClipOps are no longer supported
|
||||||
// V90: Private API for backdrop scale factor in SaveLayerRec
|
// V90: Private API for backdrop scale factor in SaveLayerRec
|
||||||
|
// V91: Added raw image shaders
|
||||||
|
// V92: Added anisotropic filtering to SkSamplingOptions
|
||||||
|
|
||||||
enum Version {
|
enum Version {
|
||||||
kPictureShaderFilterParam_Version = 82,
|
kPictureShaderFilterParam_Version = 82,
|
||||||
@ -112,10 +114,11 @@ public:
|
|||||||
kNoExpandingClipOps = 89,
|
kNoExpandingClipOps = 89,
|
||||||
kBackdropScaleFactor = 90,
|
kBackdropScaleFactor = 90,
|
||||||
kRawImageShaders = 91,
|
kRawImageShaders = 91,
|
||||||
|
kAnisotropicFilter = 92,
|
||||||
|
|
||||||
// Only SKPs within the min/current picture version range (inclusive) can be read.
|
// Only SKPs within the min/current picture version range (inclusive) can be read.
|
||||||
kMin_Version = kPictureShaderFilterParam_Version,
|
kMin_Version = kPictureShaderFilterParam_Version,
|
||||||
kCurrent_Version = kRawImageShaders
|
kCurrent_Version = kAnisotropicFilter
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -523,7 +523,7 @@ void SkPictureRecord::onDrawPath(const SkPath& path, const SkPaint& paint) {
|
|||||||
void SkPictureRecord::onDrawImage2(const SkImage* image, SkScalar x, SkScalar y,
|
void SkPictureRecord::onDrawImage2(const SkImage* image, SkScalar x, SkScalar y,
|
||||||
const SkSamplingOptions& sampling, const SkPaint* paint) {
|
const SkSamplingOptions& sampling, const SkPaint* paint) {
|
||||||
// op + paint_index + image_index + x + y
|
// op + paint_index + image_index + x + y
|
||||||
size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar) + SkSamplingPriv::kFlatSize;
|
size_t size = 3 * kUInt32Size + 2 * sizeof(SkScalar) + SkSamplingPriv::FlatSize(sampling);
|
||||||
size_t initialOffset = this->addDraw(DRAW_IMAGE2, &size);
|
size_t initialOffset = this->addDraw(DRAW_IMAGE2, &size);
|
||||||
this->addPaintPtr(paint);
|
this->addPaintPtr(paint);
|
||||||
this->addImage(image);
|
this->addImage(image);
|
||||||
@ -537,7 +537,8 @@ void SkPictureRecord::onDrawImageRect2(const SkImage* image, const SkRect& src,
|
|||||||
const SkSamplingOptions& sampling, const SkPaint* paint,
|
const SkSamplingOptions& sampling, const SkPaint* paint,
|
||||||
SrcRectConstraint constraint) {
|
SrcRectConstraint constraint) {
|
||||||
// id + paint_index + image_index + constraint
|
// id + paint_index + image_index + constraint
|
||||||
size_t size = 3 * kUInt32Size + 2 * sizeof(dst) + SkSamplingPriv::kFlatSize + kUInt32Size;
|
size_t size = 3 * kUInt32Size + 2 * sizeof(dst) + SkSamplingPriv::FlatSize(sampling) +
|
||||||
|
kUInt32Size;
|
||||||
|
|
||||||
size_t initialOffset = this->addDraw(DRAW_IMAGE_RECT2, &size);
|
size_t initialOffset = this->addDraw(DRAW_IMAGE_RECT2, &size);
|
||||||
this->addPaintPtr(paint);
|
this->addPaintPtr(paint);
|
||||||
@ -684,7 +685,7 @@ void SkPictureRecord::onDrawAtlas2(const SkImage* atlas, const SkRSXform xform[]
|
|||||||
const SkPaint* paint) {
|
const SkPaint* paint) {
|
||||||
// [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull
|
// [op + paint-index + atlas-index + flags + count] + [xform] + [tex] + [*colors + mode] + cull
|
||||||
size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect);
|
size_t size = 5 * kUInt32Size + count * sizeof(SkRSXform) + count * sizeof(SkRect);
|
||||||
size += SkSamplingPriv::kFlatSize;
|
size += SkSamplingPriv::FlatSize(sampling);
|
||||||
uint32_t flags = 0;
|
uint32_t flags = 0;
|
||||||
if (colors) {
|
if (colors) {
|
||||||
flags |= DRAW_ATLAS_HAS_COLORS;
|
flags |= DRAW_ATLAS_HAS_COLORS;
|
||||||
@ -780,7 +781,7 @@ void SkPictureRecord::onDrawEdgeAAImageSet2(const SkCanvas::ImageSetEntry set[],
|
|||||||
size_t size = 6 * kUInt32Size + sizeof(SkPoint) * totalDstClipCount +
|
size_t size = 6 * kUInt32Size + sizeof(SkPoint) * totalDstClipCount +
|
||||||
kMatrixSize * totalMatrixCount +
|
kMatrixSize * totalMatrixCount +
|
||||||
(4 * kUInt32Size + 2 * sizeof(SkRect) + sizeof(SkScalar)) * count +
|
(4 * kUInt32Size + 2 * sizeof(SkRect) + sizeof(SkScalar)) * count +
|
||||||
SkSamplingPriv::kFlatSize;
|
SkSamplingPriv::FlatSize(sampling);
|
||||||
size_t initialOffset = this->addDraw(DRAW_EDGEAA_IMAGE_SET2, &size);
|
size_t initialOffset = this->addDraw(DRAW_EDGEAA_IMAGE_SET2, &size);
|
||||||
this->addInt(count);
|
this->addInt(count);
|
||||||
this->addPaintPtr(paint);
|
this->addPaintPtr(paint);
|
||||||
|
@ -210,6 +210,12 @@ SkRect SkReadBuffer::readRect() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SkSamplingOptions SkReadBuffer::readSampling() {
|
SkSamplingOptions SkReadBuffer::readSampling() {
|
||||||
|
if (!this->isVersionLT(SkPicturePriv::kAnisotropicFilter)) {
|
||||||
|
int maxAniso = this->readInt();
|
||||||
|
if (maxAniso != 0) {
|
||||||
|
return SkSamplingOptions::Aniso(maxAniso);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (this->readBool()) {
|
if (this->readBool()) {
|
||||||
float B = this->readScalar();
|
float B = this->readScalar();
|
||||||
float C = this->readScalar();
|
float C = this->readScalar();
|
||||||
|
@ -32,17 +32,31 @@ enum SkMediumAs {
|
|||||||
|
|
||||||
class SkSamplingPriv {
|
class SkSamplingPriv {
|
||||||
public:
|
public:
|
||||||
enum {
|
static size_t FlatSize(const SkSamplingOptions& options) {
|
||||||
kFlatSize = 3 * sizeof(uint32_t) // bool32 + [2 floats | 2 ints]
|
size_t size = sizeof(uint32_t); // maxAniso
|
||||||
};
|
if (!options.isAniso()) {
|
||||||
|
size += 3 * sizeof(uint32_t); // bool32 + [2 floats | 2 ints]
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns true if the sampling can be ignored when the CTM is identity.
|
// Returns true if the sampling can be ignored when the CTM is identity.
|
||||||
static bool NoChangeWithIdentityMatrix(const SkSamplingOptions& sampling) {
|
static bool NoChangeWithIdentityMatrix(const SkSamplingOptions& sampling) {
|
||||||
// If B == 0, the cubic resampler should have no effect for identity matrices
|
// If B == 0, the cubic resampler should have no effect for identity matrices
|
||||||
// https://entropymine.com/imageworsener/bicubic/
|
// https://entropymine.com/imageworsener/bicubic/
|
||||||
|
// We assume aniso has no effect with an identity transform.
|
||||||
return !sampling.useCubic || sampling.cubic.B == 0;
|
return !sampling.useCubic || sampling.cubic.B == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Makes a fallback SkSamplingOptions for cases where anisotropic filtering is not allowed.
|
||||||
|
// anisotropic filtering can access mip levels if present, but we don't add mipmaps to non-
|
||||||
|
// mipmapped images when the user requests anisotropic. So we shouldn't fall back to a
|
||||||
|
// sampling that would trigger mip map creation.
|
||||||
|
static SkSamplingOptions AnisoFallback(bool imageIsMipped) {
|
||||||
|
auto mm = imageIsMipped ? SkMipmapMode::kLinear : SkMipmapMode::kNone;
|
||||||
|
return SkSamplingOptions(SkFilterMode::kLinear, mm);
|
||||||
|
}
|
||||||
|
|
||||||
static SkSamplingOptions FromFQ(SkLegacyFQ, SkMediumAs = kNearest_SkMediumAs);
|
static SkSamplingOptions FromFQ(SkLegacyFQ, SkMediumAs = kNearest_SkMediumAs);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,13 +18,16 @@ void SkWriter32::writeMatrix(const SkMatrix& matrix) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SkWriter32::writeSampling(const SkSamplingOptions& sampling) {
|
void SkWriter32::writeSampling(const SkSamplingOptions& sampling) {
|
||||||
this->writeBool(sampling.useCubic);
|
this->write32(sampling.maxAniso);
|
||||||
if (sampling.useCubic) {
|
if (!sampling.isAniso()) {
|
||||||
this->writeScalar(sampling.cubic.B);
|
this->writeBool(sampling.useCubic);
|
||||||
this->writeScalar(sampling.cubic.C);
|
if (sampling.useCubic) {
|
||||||
} else {
|
this->writeScalar(sampling.cubic.B);
|
||||||
this->write32((unsigned)sampling.filter);
|
this->writeScalar(sampling.cubic.C);
|
||||||
this->write32((unsigned)sampling.mipmap);
|
} else {
|
||||||
|
this->write32((unsigned)sampling.filter);
|
||||||
|
this->write32((unsigned)sampling.mipmap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,15 +58,46 @@ GrTextureEffect::Sampling::Sampling(const GrSurfaceProxy& proxy,
|
|||||||
bool contains(Span r) const { return fA <= r.fA && fB >= r.fB; }
|
bool contains(Span r) const { return fA <= r.fA && fB >= r.fB; }
|
||||||
};
|
};
|
||||||
struct Result1D {
|
struct Result1D {
|
||||||
ShaderMode fShaderMode;
|
ShaderMode fShaderMode = ShaderMode::kNone;
|
||||||
Span fShaderSubset;
|
Span fShaderSubset = {};
|
||||||
Span fShaderClamp;
|
Span fShaderClamp = {};
|
||||||
Wrap fHWWrap;
|
Wrap fHWWrap = Wrap::kClamp;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto type = proxy.asTextureProxy()->textureType();
|
auto type = proxy.asTextureProxy()->textureType();
|
||||||
auto filter = sampler.filter();
|
auto filter = sampler.filter();
|
||||||
auto mm = sampler.mipmapMode();
|
auto mm = sampler.mipmapMode();
|
||||||
|
|
||||||
|
// TODO: Use HW border color when available.
|
||||||
|
// TODO: Move this back into resolve below when aniso is supported with shader-based subsetting.
|
||||||
|
bool needShaderBorder = false;
|
||||||
|
if ((sampler.wrapModeX() == Wrap::kClampToBorder ||
|
||||||
|
sampler.wrapModeY() == Wrap::kClampToBorder) &&
|
||||||
|
(!caps.clampToBorderSupport() || border[0] || border[1] || border[2] || border[3])) {
|
||||||
|
needShaderBorder = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Right now if we use shader based subsetting for any reason we just completely drop
|
||||||
|
// aniso. Longer term allow shader subsetting, reusing the special repeat mode LOD selection
|
||||||
|
// logic for mip maps, and simply don't attempt to restrict ansiso's computed samples to the
|
||||||
|
// subset. That is use "subsetting" but not "clamping"/insetting in terms of the shader gen
|
||||||
|
// logic.
|
||||||
|
bool aniso = sampler.isAniso();
|
||||||
|
SkASSERT(!aniso || caps.anisoSupport());
|
||||||
|
if (aniso) {
|
||||||
|
bool anisoSubset = !proxy.backingStoreBoundsRect().contains(subset) &&
|
||||||
|
(!domain || !subset.contains(*domain));
|
||||||
|
if (needShaderBorder || anisoSubset) {
|
||||||
|
MipmapMode newMM = proxy.asTextureProxy()->mipmapped() == GrMipmapped::kYes
|
||||||
|
? MipmapMode::kLinear
|
||||||
|
: MipmapMode::kNone;
|
||||||
|
sampler = GrSamplerState(sampler.wrapModeX(),
|
||||||
|
sampler.wrapModeY(),
|
||||||
|
SkFilterMode::kLinear,
|
||||||
|
newMM);
|
||||||
|
aniso = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto resolve = [&](int size, Wrap wrap, Span subset, Span domain, float linearFilterInset) {
|
auto resolve = [&](int size, Wrap wrap, Span subset, Span domain, float linearFilterInset) {
|
||||||
Result1D r;
|
Result1D r;
|
||||||
@ -119,19 +150,29 @@ GrTextureEffect::Sampling::Sampling(const GrSurfaceProxy& proxy,
|
|||||||
return r;
|
return r;
|
||||||
};
|
};
|
||||||
|
|
||||||
SkISize dim = proxy.isFullyLazy() ? SkISize{-1, -1} : proxy.backingStoreDimensions();
|
Result1D x, y;
|
||||||
|
if (!aniso) {
|
||||||
|
SkISize dim = proxy.isFullyLazy() ? SkISize{-1, -1} : proxy.backingStoreDimensions();
|
||||||
|
|
||||||
Span subsetX{subset.fLeft, subset.fRight};
|
Span subsetX{subset.fLeft, subset.fRight};
|
||||||
auto domainX = domain ? Span{domain->fLeft, domain->fRight}
|
auto domainX = domain ? Span{domain->fLeft, domain->fRight}
|
||||||
: Span{SK_FloatNegativeInfinity, SK_FloatInfinity};
|
: Span{SK_FloatNegativeInfinity, SK_FloatInfinity};
|
||||||
auto x = resolve(dim.width(), sampler.wrapModeX(), subsetX, domainX, linearFilterInset.fX);
|
x = resolve(dim.width(), sampler.wrapModeX(), subsetX, domainX, linearFilterInset.fX);
|
||||||
|
|
||||||
Span subsetY{subset.fTop, subset.fBottom};
|
Span subsetY{subset.fTop, subset.fBottom};
|
||||||
auto domainY = domain ? Span{domain->fTop, domain->fBottom}
|
auto domainY = domain ? Span{domain->fTop, domain->fBottom}
|
||||||
: Span{SK_FloatNegativeInfinity, SK_FloatInfinity};
|
: Span{SK_FloatNegativeInfinity, SK_FloatInfinity};
|
||||||
auto y = resolve(dim.height(), sampler.wrapModeY(), subsetY, domainY, linearFilterInset.fY);
|
y = resolve(dim.height(), sampler.wrapModeY(), subsetY, domainY, linearFilterInset.fY);
|
||||||
|
} else {
|
||||||
|
x.fHWWrap = sampler.wrapModeX();
|
||||||
|
y.fHWWrap = sampler.wrapModeY();
|
||||||
|
}
|
||||||
|
|
||||||
fHWSampler = {x.fHWWrap, y.fHWWrap, filter, mm};
|
fHWSampler = aniso ? GrSamplerState::Aniso(x.fHWWrap,
|
||||||
|
y.fHWWrap,
|
||||||
|
sampler.maxAniso(),
|
||||||
|
proxy.asTextureProxy()->mipmapped())
|
||||||
|
: GrSamplerState{x.fHWWrap, y.fHWWrap, filter, mm};
|
||||||
fShaderModes[0] = x.fShaderMode;
|
fShaderModes[0] = x.fShaderMode;
|
||||||
fShaderModes[1] = y.fShaderMode;
|
fShaderModes[1] = y.fShaderMode;
|
||||||
fShaderSubset = {x.fShaderSubset.fA, y.fShaderSubset.fA,
|
fShaderSubset = {x.fShaderSubset.fA, y.fShaderSubset.fA,
|
||||||
|
@ -63,6 +63,7 @@ generated_cc_atom(
|
|||||||
"//src/core:SkDraw_hdr",
|
"//src/core:SkDraw_hdr",
|
||||||
"//src/core:SkImagePriv_hdr",
|
"//src/core:SkImagePriv_hdr",
|
||||||
"//src/core:SkMaskFilterBase_hdr",
|
"//src/core:SkMaskFilterBase_hdr",
|
||||||
|
"//src/core:SkSamplingPriv_hdr",
|
||||||
"//src/core:SkSpecialImage_hdr",
|
"//src/core:SkSpecialImage_hdr",
|
||||||
"//src/gpu/ganesh:GrBlurUtils_hdr",
|
"//src/gpu/ganesh:GrBlurUtils_hdr",
|
||||||
"//src/gpu/ganesh:GrCaps_hdr",
|
"//src/gpu/ganesh:GrCaps_hdr",
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "src/core/SkDraw.h"
|
#include "src/core/SkDraw.h"
|
||||||
#include "src/core/SkImagePriv.h"
|
#include "src/core/SkImagePriv.h"
|
||||||
#include "src/core/SkMaskFilterBase.h"
|
#include "src/core/SkMaskFilterBase.h"
|
||||||
|
#include "src/core/SkSamplingPriv.h"
|
||||||
#include "src/core/SkSpecialImage.h"
|
#include "src/core/SkSpecialImage.h"
|
||||||
#include "src/gpu/ganesh/GrBlurUtils.h"
|
#include "src/gpu/ganesh/GrBlurUtils.h"
|
||||||
#include "src/gpu/ganesh/GrCaps.h"
|
#include "src/gpu/ganesh/GrCaps.h"
|
||||||
@ -323,10 +324,10 @@ ImageDrawMode optimize_sample_area(const SkISize& image, const SkRect* origSrcRe
|
|||||||
* Checks whether the paint is compatible with using SurfaceDrawContext::drawTexture. It is more
|
* Checks whether the paint is compatible with using SurfaceDrawContext::drawTexture. It is more
|
||||||
* efficient than the SkImage general case.
|
* efficient than the SkImage general case.
|
||||||
*/
|
*/
|
||||||
bool can_use_draw_texture(const SkPaint& paint, bool useCubicResampler, SkMipmapMode mm) {
|
bool can_use_draw_texture(const SkPaint& paint, const SkSamplingOptions& sampling) {
|
||||||
return (!paint.getColorFilter() && !paint.getShader() && !paint.getMaskFilter() &&
|
return (!paint.getColorFilter() && !paint.getShader() && !paint.getMaskFilter() &&
|
||||||
!paint.getImageFilter() && !paint.getBlender() && !useCubicResampler &&
|
!paint.getImageFilter() && !paint.getBlender() && !sampling.isAniso() &&
|
||||||
mm == SkMipmapMode::kNone);
|
!sampling.useCubic && sampling.mipmap == SkMipmapMode::kNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
SkPMColor4f texture_color(SkColor4f paintColor, float entryAlpha, GrColorType srcColorType,
|
SkPMColor4f texture_color(SkColor4f paintColor, float entryAlpha, GrColorType srcColorType,
|
||||||
@ -426,9 +427,7 @@ void draw_image(GrRecordingContext* rContext,
|
|||||||
SkSamplingOptions sampling,
|
SkSamplingOptions sampling,
|
||||||
SkTileMode tm = SkTileMode::kClamp) {
|
SkTileMode tm = SkTileMode::kClamp) {
|
||||||
const SkMatrix& ctm(matrixProvider.localToDevice());
|
const SkMatrix& ctm(matrixProvider.localToDevice());
|
||||||
if (tm == SkTileMode::kClamp &&
|
if (tm == SkTileMode::kClamp && !image.isYUVA() && can_use_draw_texture(paint, sampling)) {
|
||||||
!image.isYUVA() &&
|
|
||||||
can_use_draw_texture(paint, sampling.useCubic, sampling.mipmap)) {
|
|
||||||
// We've done enough checks above to allow us to pass ClampNearest() and not check for
|
// We've done enough checks above to allow us to pass ClampNearest() and not check for
|
||||||
// scaling adjustments.
|
// scaling adjustments.
|
||||||
auto [view, ct] = image.asView(rContext, GrMipmapped::kNo);
|
auto [view, ct] = image.asView(rContext, GrMipmapped::kNo);
|
||||||
@ -476,7 +475,8 @@ void draw_image(GrRecordingContext* rContext,
|
|||||||
|
|
||||||
// Check for optimization to drop the src rect constraint when using linear filtering.
|
// Check for optimization to drop the src rect constraint when using linear filtering.
|
||||||
// TODO: Just rely on image to handle this.
|
// TODO: Just rely on image to handle this.
|
||||||
if (!sampling.useCubic &&
|
if (sampling.isAniso() &&
|
||||||
|
!sampling.useCubic &&
|
||||||
sampling.filter == SkFilterMode::kLinear &&
|
sampling.filter == SkFilterMode::kLinear &&
|
||||||
restrictToSubset &&
|
restrictToSubset &&
|
||||||
sampling.mipmap == SkMipmapMode::kNone &&
|
sampling.mipmap == SkMipmapMode::kNone &&
|
||||||
@ -579,6 +579,9 @@ void draw_tiled_bitmap(GrRecordingContext* rContext,
|
|||||||
SkCanvas::SrcRectConstraint constraint,
|
SkCanvas::SrcRectConstraint constraint,
|
||||||
SkSamplingOptions sampling,
|
SkSamplingOptions sampling,
|
||||||
SkTileMode tileMode) {
|
SkTileMode tileMode) {
|
||||||
|
if (sampling.isAniso()) {
|
||||||
|
sampling = SkSamplingPriv::AnisoFallback(/*imageIsMipped=*/false);
|
||||||
|
}
|
||||||
SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
|
SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
|
||||||
|
|
||||||
int nx = bitmap.width() / tileSize;
|
int nx = bitmap.width() / tileSize;
|
||||||
@ -670,7 +673,7 @@ void draw_tiled_bitmap(GrRecordingContext* rContext,
|
|||||||
|
|
||||||
SkFilterMode downgrade_to_filter(const SkSamplingOptions& sampling) {
|
SkFilterMode downgrade_to_filter(const SkSamplingOptions& sampling) {
|
||||||
SkFilterMode filter = sampling.filter;
|
SkFilterMode filter = sampling.filter;
|
||||||
if (sampling.useCubic || sampling.mipmap != SkMipmapMode::kNone) {
|
if (sampling.isAniso() || sampling.useCubic || sampling.mipmap != SkMipmapMode::kNone) {
|
||||||
// if we were "fancier" than just bilerp, only do bilerp
|
// if we were "fancier" than just bilerp, only do bilerp
|
||||||
filter = SkFilterMode::kLinear;
|
filter = SkFilterMode::kLinear;
|
||||||
}
|
}
|
||||||
@ -779,10 +782,11 @@ void Device::drawImageQuad(const SkImage* image,
|
|||||||
int tileFilterPad;
|
int tileFilterPad;
|
||||||
if (sampling.useCubic) {
|
if (sampling.useCubic) {
|
||||||
tileFilterPad = GrBicubicEffect::kFilterTexelPad;
|
tileFilterPad = GrBicubicEffect::kFilterTexelPad;
|
||||||
} else if (sampling.filter == SkFilterMode::kNearest) {
|
} else if (sampling.filter == SkFilterMode::kLinear || sampling.isAniso()) {
|
||||||
tileFilterPad = 0;
|
// Aniso will fallback to linear filtering in the tiling case.
|
||||||
} else {
|
|
||||||
tileFilterPad = 1;
|
tileFilterPad = 1;
|
||||||
|
} else {
|
||||||
|
tileFilterPad = 0;
|
||||||
}
|
}
|
||||||
int maxTileSize = fContext->priv().caps()->maxTextureSize() - 2*tileFilterPad;
|
int maxTileSize = fContext->priv().caps()->maxTextureSize() - 2*tileFilterPad;
|
||||||
int tileSize;
|
int tileSize;
|
||||||
@ -842,7 +846,7 @@ void Device::drawEdgeAAImageSet(const SkCanvas::ImageSetEntry set[], int count,
|
|||||||
const SkSamplingOptions& sampling, const SkPaint& paint,
|
const SkSamplingOptions& sampling, const SkPaint& paint,
|
||||||
SkCanvas::SrcRectConstraint constraint) {
|
SkCanvas::SrcRectConstraint constraint) {
|
||||||
SkASSERT(count > 0);
|
SkASSERT(count > 0);
|
||||||
if (!can_use_draw_texture(paint, sampling.useCubic, sampling.mipmap)) {
|
if (!can_use_draw_texture(paint, sampling)) {
|
||||||
// Send every entry through drawImageQuad() to handle the more complicated paint
|
// Send every entry through drawImageQuad() to handle the more complicated paint
|
||||||
int dstClipIndex = 0;
|
int dstClipIndex = 0;
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
|
@ -119,6 +119,7 @@ generated_cc_atom(
|
|||||||
"//include/gpu:GrYUVABackendTextures_hdr",
|
"//include/gpu:GrYUVABackendTextures_hdr",
|
||||||
"//src/core:SkAutoPixmapStorage_hdr",
|
"//src/core:SkAutoPixmapStorage_hdr",
|
||||||
"//src/core:SkMipmap_hdr",
|
"//src/core:SkMipmap_hdr",
|
||||||
|
"//src/core:SkSamplingPriv_hdr",
|
||||||
"//src/core:SkScopeExit_hdr",
|
"//src/core:SkScopeExit_hdr",
|
||||||
"//src/gpu/ganesh:GrClip_hdr",
|
"//src/gpu/ganesh:GrClip_hdr",
|
||||||
"//src/gpu/ganesh:GrDirectContextPriv_hdr",
|
"//src/gpu/ganesh:GrDirectContextPriv_hdr",
|
||||||
|
@ -389,10 +389,20 @@ std::unique_ptr<GrFragmentProcessor> SkImage_Base::MakeFragmentProcessorFromView
|
|||||||
GrBicubicEffect::Direction::kXY,
|
GrBicubicEffect::Direction::kXY,
|
||||||
*rContext->priv().caps());
|
*rContext->priv().caps());
|
||||||
}
|
}
|
||||||
if (view.proxy()->asTextureProxy()->mipmapped() == GrMipmapped::kNo) {
|
if (sampling.isAniso()) {
|
||||||
|
if (!rContext->priv().caps()->anisoSupport()) {
|
||||||
|
// Fallback to linear
|
||||||
|
sampling = SkSamplingPriv::AnisoFallback(view.mipmapped() == GrMipmapped::kYes);
|
||||||
|
}
|
||||||
|
} else if (view.mipmapped() == GrMipmapped::kNo) {
|
||||||
sampling = SkSamplingOptions(sampling.filter);
|
sampling = SkSamplingOptions(sampling.filter);
|
||||||
}
|
}
|
||||||
GrSamplerState sampler(wmx, wmy, sampling.filter, sampling.mipmap);
|
GrSamplerState sampler;
|
||||||
|
if (sampling.isAniso()) {
|
||||||
|
sampler = GrSamplerState::Aniso(wmx, wmy, sampling.maxAniso, view.mipmapped());
|
||||||
|
} else {
|
||||||
|
sampler = GrSamplerState(wmx, wmy, sampling.filter, sampling.mipmap);
|
||||||
|
}
|
||||||
if (subset) {
|
if (subset) {
|
||||||
if (domain) {
|
if (domain) {
|
||||||
return GrTextureEffect::MakeSubset(std::move(view),
|
return GrTextureEffect::MakeSubset(std::move(view),
|
||||||
|
@ -5,9 +5,7 @@
|
|||||||
* found in the LICENSE file.
|
* found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cstddef>
|
#include "src/image/SkImage_GpuYUVA.h"
|
||||||
#include <cstring>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include "include/core/SkBitmap.h"
|
#include "include/core/SkBitmap.h"
|
||||||
#include "include/core/SkYUVAPixmaps.h"
|
#include "include/core/SkYUVAPixmaps.h"
|
||||||
@ -16,6 +14,7 @@
|
|||||||
#include "include/gpu/GrYUVABackendTextures.h"
|
#include "include/gpu/GrYUVABackendTextures.h"
|
||||||
#include "src/core/SkAutoPixmapStorage.h"
|
#include "src/core/SkAutoPixmapStorage.h"
|
||||||
#include "src/core/SkMipmap.h"
|
#include "src/core/SkMipmap.h"
|
||||||
|
#include "src/core/SkSamplingPriv.h"
|
||||||
#include "src/core/SkScopeExit.h"
|
#include "src/core/SkScopeExit.h"
|
||||||
#include "src/gpu/ganesh/GrClip.h"
|
#include "src/gpu/ganesh/GrClip.h"
|
||||||
#include "src/gpu/ganesh/GrDirectContextPriv.h"
|
#include "src/gpu/ganesh/GrDirectContextPriv.h"
|
||||||
@ -28,7 +27,6 @@
|
|||||||
#include "src/gpu/ganesh/effects/GrBicubicEffect.h"
|
#include "src/gpu/ganesh/effects/GrBicubicEffect.h"
|
||||||
#include "src/gpu/ganesh/effects/GrYUVtoRGBEffect.h"
|
#include "src/gpu/ganesh/effects/GrYUVtoRGBEffect.h"
|
||||||
#include "src/image/SkImage_Gpu.h"
|
#include "src/image/SkImage_Gpu.h"
|
||||||
#include "src/image/SkImage_GpuYUVA.h"
|
|
||||||
|
|
||||||
static constexpr auto kAssumedColorType = kRGBA_8888_SkColorType;
|
static constexpr auto kAssumedColorType = kRGBA_8888_SkColorType;
|
||||||
|
|
||||||
@ -191,6 +189,11 @@ std::unique_ptr<GrFragmentProcessor> SkImage_GpuYUVA::onAsFragmentProcessor(
|
|||||||
if (!fContext->priv().matches(context)) {
|
if (!fContext->priv().matches(context)) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
// At least for now we do not attempt aniso filtering on YUVA images.
|
||||||
|
if (sampling.isAniso()) {
|
||||||
|
sampling = SkSamplingPriv::AnisoFallback(fYUVAProxies.mipmapped() == GrMipmapped::kYes);
|
||||||
|
}
|
||||||
|
|
||||||
auto wmx = SkTileModeToWrapMode(tileModes[0]);
|
auto wmx = SkTileModeToWrapMode(tileModes[0]);
|
||||||
auto wmy = SkTileModeToWrapMode(tileModes[1]);
|
auto wmy = SkTileModeToWrapMode(tileModes[1]);
|
||||||
GrSamplerState sampler(wmx, wmy, sampling.filter, sampling.mipmap);
|
GrSamplerState sampler(wmx, wmy, sampling.filter, sampling.mipmap);
|
||||||
|
@ -444,7 +444,7 @@ std::tuple<GrSurfaceProxyView, GrColorType> SkImage_Raster::onAsView(
|
|||||||
if (fPinnedView) {
|
if (fPinnedView) {
|
||||||
// We ignore the mipmap request here. If the pinned view isn't mipmapped then we will
|
// We ignore the mipmap request here. If the pinned view isn't mipmapped then we will
|
||||||
// fallback to bilinear. The pin API is used by Android Framework which does not expose
|
// fallback to bilinear. The pin API is used by Android Framework which does not expose
|
||||||
// mipmapping .Moreover, we're moving towards requiring that images be made with mip levels
|
// mipmapping . Moreover, we're moving towards requiring that images be made with mip levels
|
||||||
// if mipmapping is desired (skbug.com/10411)
|
// if mipmapping is desired (skbug.com/10411)
|
||||||
mipmapped = GrMipmapped::kNo;
|
mipmapped = GrMipmapped::kNo;
|
||||||
if (policy != GrImageTexGenPolicy::kDraw) {
|
if (policy != GrImageTexGenPolicy::kDraw) {
|
||||||
|
@ -220,6 +220,11 @@ SkShaderBase::Context* SkImageShader::onMakeContext(const ContextRec& rec,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SkSamplingOptions sampling = fSampling;
|
||||||
|
if (sampling.isAniso()) {
|
||||||
|
sampling = SkSamplingPriv::AnisoFallback(fImage->hasMipmaps());
|
||||||
|
}
|
||||||
|
|
||||||
auto supported = [](const SkSamplingOptions& sampling) {
|
auto supported = [](const SkSamplingOptions& sampling) {
|
||||||
const std::tuple<SkFilterMode,SkMipmapMode> supported[] = {
|
const std::tuple<SkFilterMode,SkMipmapMode> supported[] = {
|
||||||
{SkFilterMode::kNearest, SkMipmapMode::kNone}, // legacy None
|
{SkFilterMode::kNearest, SkMipmapMode::kNone}, // legacy None
|
||||||
@ -233,7 +238,7 @@ SkShaderBase::Context* SkImageShader::onMakeContext(const ContextRec& rec,
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
if (fSampling.useCubic || !supported(fSampling)) {
|
if (sampling.useCubic || !supported(sampling)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,7 +267,7 @@ SkShaderBase::Context* SkImageShader::onMakeContext(const ContextRec& rec,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY, fSampling,
|
return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY, sampling,
|
||||||
as_IB(fImage.get()), rec, alloc);
|
as_IB(fImage.get()), rec, alloc);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -471,6 +476,9 @@ bool SkImageShader::doStages(const SkStageRec& rec, TransformShader* updater) co
|
|||||||
SkASSERT(!needs_subset(fImage.get(), fSubset)); // TODO(skbug.com/12784)
|
SkASSERT(!needs_subset(fImage.get(), fSubset)); // TODO(skbug.com/12784)
|
||||||
// We only support certain sampling options in stages so far
|
// We only support certain sampling options in stages so far
|
||||||
auto sampling = fSampling;
|
auto sampling = fSampling;
|
||||||
|
if (sampling.isAniso()) {
|
||||||
|
sampling = SkSamplingPriv::AnisoFallback(fImage->hasMipmaps());
|
||||||
|
}
|
||||||
if (sampling.mipmap == SkMipmapMode::kLinear) {
|
if (sampling.mipmap == SkMipmapMode::kLinear) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -777,10 +785,14 @@ skvm::Color SkImageShader::makeProgram(
|
|||||||
baseInv.normalizePerspective();
|
baseInv.normalizePerspective();
|
||||||
|
|
||||||
auto sampling = fSampling;
|
auto sampling = fSampling;
|
||||||
|
if (sampling.isAniso()) {
|
||||||
|
sampling = SkSamplingPriv::AnisoFallback(fImage->hasMipmaps());
|
||||||
|
}
|
||||||
auto* access = SkMipmapAccessor::Make(alloc, fImage.get(), baseInv, sampling.mipmap);
|
auto* access = SkMipmapAccessor::Make(alloc, fImage.get(), baseInv, sampling.mipmap);
|
||||||
if (!access) {
|
if (!access) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto [upper, upperInv] = access->level();
|
auto [upper, upperInv] = access->level();
|
||||||
// If we are using a coordShader, then we can't make guesses about the state of the matrix.
|
// If we are using a coordShader, then we can't make guesses about the state of the matrix.
|
||||||
if (!sampling.useCubic && !coordShader) {
|
if (!sampling.useCubic && !coordShader) {
|
||||||
|
@ -211,6 +211,7 @@ generated_cc_atom(
|
|||||||
":JsonWriteBuffer_hdr",
|
":JsonWriteBuffer_hdr",
|
||||||
"//include/core:SkFlattenable_hdr",
|
"//include/core:SkFlattenable_hdr",
|
||||||
"//include/core:SkPoint_hdr",
|
"//include/core:SkPoint_hdr",
|
||||||
|
"//include/core:SkSamplingOptions_hdr",
|
||||||
"//include/core:SkString_hdr",
|
"//include/core:SkString_hdr",
|
||||||
"//src/utils:SkJSONWriter_hdr",
|
"//src/utils:SkJSONWriter_hdr",
|
||||||
],
|
],
|
||||||
|
@ -572,6 +572,7 @@ void DrawCommand::MakeJsonRegion(SkJSONWriter& writer, const SkRegion& region) {
|
|||||||
|
|
||||||
void DrawCommand::MakeJsonSampling(SkJSONWriter& writer, const SkSamplingOptions& sampling) {
|
void DrawCommand::MakeJsonSampling(SkJSONWriter& writer, const SkSamplingOptions& sampling) {
|
||||||
writer.beginObject();
|
writer.beginObject();
|
||||||
|
writer.appendS32("maxAniso", sampling.maxAniso);
|
||||||
writer.appendBool("useCubic", sampling.useCubic);
|
writer.appendBool("useCubic", sampling.useCubic);
|
||||||
writer.appendS32("filter", (int)sampling.filter);
|
writer.appendS32("filter", (int)sampling.filter);
|
||||||
writer.appendS32("mipmap", (int)sampling.mipmap);
|
writer.appendS32("mipmap", (int)sampling.mipmap);
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "include/core/SkFlattenable.h"
|
#include "include/core/SkFlattenable.h"
|
||||||
#include "include/core/SkPoint.h"
|
#include "include/core/SkPoint.h"
|
||||||
|
#include "include/core/SkSamplingOptions.h"
|
||||||
#include "include/core/SkString.h"
|
#include "include/core/SkString.h"
|
||||||
#include "src/utils/SkJSONWriter.h"
|
#include "src/utils/SkJSONWriter.h"
|
||||||
#include "tools/debugger/DrawCommand.h"
|
#include "tools/debugger/DrawCommand.h"
|
||||||
|
Loading…
Reference in New Issue
Block a user