Separate MIP filtering from min/mag filtering.

Does not add kNearest as a mip map mode yet.

Bug: skia:10344

Change-Id: Ida80cbf19e2b1eed5209d0680837fb45e54b4261
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/303481
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Greg Daniel <egdaniel@google.com>
This commit is contained in:
Brian Salomon 2020-07-22 11:18:06 -04:00 committed by Skia Commit-Bot
parent 40ad5fd50a
commit e69b9efcb3
39 changed files with 776 additions and 498 deletions

View File

@ -254,10 +254,19 @@ void ClockwiseGM::onDraw(GrRecordingContext* ctx, GrRenderTargetContext* rtc, Sk
topLeftRTC->clear(SK_PMColor4fTRANSPARENT);
topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0));
topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100));
rtc->drawTexture(nullptr, topLeftRTC->readSurfaceView(), rtc->colorInfo().alphaType(),
GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver, SK_PMColor4fWHITE,
{0, 0, 100, 200}, {100, 0, 200, 200}, GrAA::kNo, GrQuadAAFlags::kNone,
SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(),
rtc->drawTexture(nullptr,
topLeftRTC->readSurfaceView(),
rtc->colorInfo().alphaType(),
GrSamplerState::Filter::kNearest,
GrSamplerState::MipmapMode::kNone,
SkBlendMode::kSrcOver,
SK_PMColor4fWHITE,
{0, 0, 100, 200},
{100, 0, 200, 200},
GrAA::kNo,
GrQuadAAFlags::kNone,
SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint,
SkMatrix::I(),
nullptr);
}
@ -269,10 +278,19 @@ void ClockwiseGM::onDraw(GrRecordingContext* ctx, GrRenderTargetContext* rtc, Sk
topLeftRTC->clear(SK_PMColor4fTRANSPARENT);
topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, false, 0));
topLeftRTC->priv().testingOnly_addDrawOp(ClockwiseTestOp::Make(ctx, true, 100));
rtc->drawTexture(nullptr, topLeftRTC->readSurfaceView(), rtc->colorInfo().alphaType(),
GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver, SK_PMColor4fWHITE,
{0, 0, 100, 200}, {200, 0, 300, 200}, GrAA::kNo, GrQuadAAFlags::kNone,
SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(),
rtc->drawTexture(nullptr,
topLeftRTC->readSurfaceView(),
rtc->colorInfo().alphaType(),
GrSamplerState::Filter::kNearest,
GrSamplerState::MipmapMode::kNone,
SkBlendMode::kSrcOver,
SK_PMColor4fWHITE,
{0, 0, 100, 200},
{200, 0, 300, 200},
GrAA::kNo,
GrQuadAAFlags::kNone,
SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint,
SkMatrix::I(),
nullptr);
}
}

View File

@ -366,11 +366,19 @@ DrawResult SampleLocationsGM::onDraw(GrRecordingContext* ctx, GrRenderTargetCont
SkMatrix::I(), SkRect::MakeWH(200, 200));
// Copy offscreen texture to canvas.
rtc->drawTexture(nullptr, offscreenRTC->readSurfaceView(),
rtc->drawTexture(nullptr,
offscreenRTC->readSurfaceView(),
offscreenRTC->colorInfo().alphaType(),
GrSamplerState::Filter::kNearest, SkBlendMode::kSrc, SK_PMColor4fWHITE,
{0,0,200,200}, {0,0,200,200}, GrAA::kNo, GrQuadAAFlags::kNone,
SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint, SkMatrix::I(),
GrSamplerState::Filter::kNearest,
GrSamplerState::MipmapMode::kNone,
SkBlendMode::kSrc,
SK_PMColor4fWHITE,
{0, 0, 200, 200},
{0, 0, 200, 200},
GrAA::kNo,
GrQuadAAFlags::kNone,
SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint,
SkMatrix::I(),
nullptr);
return skiagm::DrawResult::kOk;

View File

@ -33,28 +33,37 @@
#include <memory>
#include <utility>
using MipmapMode = GrSamplerState::MipmapMode;
using Filter = GrSamplerState::Filter;
using Wrap = GrSamplerState::WrapMode;
namespace skiagm {
/**
* This GM directly exercises GrTextureEffect::MakeTexelSubset.
*/
class TexelSubset : public GpuGM {
public:
TexelSubset(GrSamplerState::Filter filter, bool upscale) : fFilter(filter), fUpscale(upscale) {
TexelSubset(Filter filter, MipmapMode mm, bool upscale)
: fFilter(filter), fMipmapMode(mm), fUpscale(upscale) {
this->setBGColor(0xFFFFFFFF);
}
protected:
SkString onShortName() override {
SkString name("texel_subset");
switch (fMipmapMode) {
case MipmapMode::kNone:
break;
case MipmapMode::kLinear:
name.append("_linear_mipmap");
break;
}
switch (fFilter) {
case GrSamplerState::Filter::kNearest:
case Filter::kNearest:
name.append("_nearest");
break;
case GrSamplerState::Filter::kLinear:
name.append("_bilerp");
break;
case GrSamplerState::Filter::kMipMap:
name.append("_mip_map");
case Filter::kLinear:
name.append("_linear");
break;
}
name.append(fUpscale ? "_up" : "_down");
@ -77,11 +86,13 @@ protected:
DrawResult onDraw(GrRecordingContext* context, GrRenderTargetContext* renderTargetContext,
SkCanvas* canvas, SkString* errorMsg) override {
GrMipmapped mipMapped = fFilter == GrSamplerState::Filter::kMipMap &&
context->priv().caps()->mipmapSupport()
? GrMipmapped::kYes : GrMipmapped::kNo;
GrMipmapped mipmapped = (fMipmapMode != MipmapMode::kNone) ? GrMipmapped::kYes
: GrMipmapped::kNo;
if (mipmapped == GrMipmapped::kYes && !context->priv().caps()->mipmapSupport()) {
return DrawResult::kSkip;
}
GrBitmapTextureMaker maker(context, fBitmap, GrImageTexGenPolicy::kDraw);
auto view = maker.view(mipMapped);
auto view = maker.view(mipmapped);
if (!view) {
*errorMsg = "Failed to create proxy.";
return DrawResult::kFail;
@ -115,7 +126,7 @@ protected:
fBitmap.extractSubset(&subsetBmp, texelSubset);
subsetBmp.setImmutable();
GrBitmapTextureMaker subsetMaker(context, subsetBmp, GrImageTexGenPolicy::kDraw);
auto subsetView = subsetMaker.view(mipMapped);
auto subsetView = subsetMaker.view(mipmapped);
SkRect localRect = SkRect::Make(fBitmap.bounds()).makeOutset(kDrawPad, kDrawPad);
@ -126,13 +137,13 @@ protected:
for (int tm = 0; tm < textureMatrices.count(); ++tm) {
for (int my = 0; my < GrSamplerState::kWrapModeCount; ++my) {
SkScalar x = kDrawPad + kTestPad;
auto wmy = static_cast<GrSamplerState::WrapMode>(my);
auto wmy = static_cast<Wrap>(my);
for (int mx = 0; mx < GrSamplerState::kWrapModeCount; ++mx) {
auto wmx = static_cast<GrSamplerState::WrapMode>(mx);
auto wmx = static_cast<Wrap>(mx);
const auto& caps = *context->priv().caps();
GrSamplerState sampler(wmx, wmy, fFilter);
GrSamplerState sampler(wmx, wmy, fFilter, fMipmapMode);
drawRect = localRect.makeOffset(x, y);
@ -166,9 +177,11 @@ protected:
SkMatrix subsetTextureMatrix = SkMatrix::Concat(
SkMatrix::Translate(-texelSubset.topLeft()), textureMatrices[tm]);
auto fp2 = GrTextureEffect::Make(subsetView, fBitmap.alphaType(),
auto fp2 = GrTextureEffect::Make(subsetView,
fBitmap.alphaType(),
subsetTextureMatrix,
GrSamplerState(wmx, wmy, fFilter), caps);
sampler,
caps);
if (auto op = sk_gpu_test::test_ops::MakeRect(context, std::move(fp2), drawRect,
localRect)) {
renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
@ -202,17 +215,19 @@ private:
static constexpr SkScalar kDrawPad = 10.f;
static constexpr SkScalar kTestPad = 10.f;
SkBitmap fBitmap;
GrSamplerState::Filter fFilter;
Filter fFilter;
MipmapMode fMipmapMode;
bool fUpscale;
typedef GM INHERITED;
};
DEF_GM(return new TexelSubset(GrSamplerState::Filter::kNearest, false);)
DEF_GM(return new TexelSubset(GrSamplerState::Filter::kNearest, true);)
DEF_GM(return new TexelSubset(GrSamplerState::Filter::kLinear , false);)
DEF_GM(return new TexelSubset(GrSamplerState::Filter::kLinear , true);)
DEF_GM(return new TexelSubset(Filter::kNearest, MipmapMode::kNone , false);)
DEF_GM(return new TexelSubset(Filter::kNearest, MipmapMode::kNone , true);)
DEF_GM(return new TexelSubset(Filter::kLinear , MipmapMode::kNone , false);)
DEF_GM(return new TexelSubset(Filter::kLinear , MipmapMode::kNone , true);)
// It doesn't make sense to have upscaling MIP map.
DEF_GM(return new TexelSubset(GrSamplerState::Filter::kMipMap, false);)
DEF_GM(return new TexelSubset(Filter::kNearest, MipmapMode::kLinear, false);)
DEF_GM(return new TexelSubset(Filter::kLinear , MipmapMode::kLinear, false);)
}

View File

@ -45,8 +45,7 @@ bool GrFragmentProcessor::isEqual(const GrFragmentProcessor& that) const {
void GrFragmentProcessor::visitProxies(const GrOp::VisitProxyFunc& func) const {
this->visitTextureEffects([&func](const GrTextureEffect& te) {
bool mipped = (GrSamplerState::Filter::kMipMap == te.samplerState().filter());
func(te.view().proxy(), GrMipmapped(mipped));
func(te.view().proxy(), te.samplerState().mipmapped());
});
}

View File

@ -70,11 +70,10 @@ std::unique_ptr<GrFragmentProcessor> GrYUVAImageTextureMaker::createFragmentProc
}
// Check to see if the client has given us pre-mipped textures or we can generate them
// If not, fall back to linear filtering. Also fall back to linear filtering when a domain is
// requested.
if (samplerState.filter() == GrSamplerState::Filter::kMipMap &&
// If not disable mip mapping. Also disable when a subset is requested.
if (samplerState.mipmapped() == GrMipmapped::kYes &&
(subset || !fImage->setupMipmapsForPlanes(this->context()))) {
samplerState.setFilterMode(GrSamplerState::Filter::kLinear);
samplerState.setMipmapMode(GrSamplerState::MipmapMode::kNone);
}
const auto& caps = *fImage->context()->priv().caps();

View File

@ -158,7 +158,7 @@ void GrOpsRenderPass::bindTextures(const GrPrimitiveProcessor& primProc,
const GrTexture* tex = proxy->peekTexture();
SkASSERT(tex);
if (GrSamplerState::Filter::kMipMap == sampler.samplerState().filter() &&
if (sampler.samplerState().mipmapped() == GrMipmapped::kYes &&
(tex->width() != 1 || tex->height() != 1)) {
// There are some cases where we might be given a non-mipmapped texture with a mipmap
// filter. See skbug.com/7094.

View File

@ -43,7 +43,7 @@ void GrProgramInfo::checkMSAAAndMIPSAreResolved() const {
SkASSERT(tex);
// Ensure mipmaps were all resolved ahead of time by the DAG.
if (GrSamplerState::Filter::kMipMap == te.samplerState().filter() &&
if (te.samplerState().mipmapped() == GrMipmapped::kYes &&
(tex->width() != 1 || tex->height() != 1)) {
// There are some cases where we might be given a non-mipmapped texture with a
// mipmap filter. See skbug.com/7094.

View File

@ -798,6 +798,7 @@ void GrRenderTargetContext::drawTexturedQuad(const GrClip* clip,
SkAlphaType srcAlphaType,
sk_sp<GrColorSpaceXform> textureXform,
GrSamplerState::Filter filter,
GrSamplerState::MipmapMode mm,
const SkPMColor4f& color,
SkBlendMode blendMode,
GrAA aa,
@ -827,7 +828,7 @@ void GrRenderTargetContext::drawTexturedQuad(const GrClip* clip,
// quad is sufficiently inside the subset and the constraint could be dropped.
this->addDrawOp(finalClip,
GrTextureOp::Make(fContext, std::move(proxyView), srcAlphaType,
std::move(textureXform), filter, color, saturate,
std::move(textureXform), filter, mm, color, saturate,
blendMode, aaType, quad, subset));
}
}
@ -1007,10 +1008,15 @@ void GrRenderTargetContextPriv::stencilPath(const GrHardClip* clip,
fRenderTargetContext->addOp(std::move(op));
}
void GrRenderTargetContext::drawTextureSet(const GrClip* clip, TextureSetEntry set[],
int cnt, int proxyRunCnt,
GrSamplerState::Filter filter, SkBlendMode mode,
GrAA aa, SkCanvas::SrcRectConstraint constraint,
void GrRenderTargetContext::drawTextureSet(const GrClip* clip,
TextureSetEntry set[],
int cnt,
int proxyRunCnt,
GrSamplerState::Filter filter,
GrSamplerState::MipmapMode mm,
SkBlendMode mode,
GrAA aa,
SkCanvas::SrcRectConstraint constraint,
const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> texXform) {
ASSERT_SINGLE_OWNER
@ -1025,7 +1031,7 @@ void GrRenderTargetContext::drawTextureSet(const GrClip* clip, TextureSetEntry s
auto clampType = GrColorTypeClampType(this->colorInfo().colorType());
auto saturate = clampType == GrClampType::kManual ? GrTextureOp::Saturate::kYes
: GrTextureOp::Saturate::kNo;
GrTextureOp::AddTextureSetOps(this, clip, fContext, set, cnt, proxyRunCnt, filter, saturate,
GrTextureOp::AddTextureSetOps(this, clip, fContext, set, cnt, proxyRunCnt, filter, mm, saturate,
mode, aaType, constraint, viewMatrix, std::move(texXform));
}

View File

@ -270,17 +270,26 @@ public:
* specifies the rectangle to draw in local coords which will be transformed by 'viewMatrix' to
* device space.
*/
void drawTexture(const GrClip* clip, GrSurfaceProxyView view, SkAlphaType srcAlphaType,
GrSamplerState::Filter filter, SkBlendMode mode, const SkPMColor4f& color,
const SkRect& srcRect, const SkRect& dstRect, GrAA aa, GrQuadAAFlags edgeAA,
SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix,
void drawTexture(const GrClip* clip,
GrSurfaceProxyView view,
SkAlphaType srcAlphaType,
GrSamplerState::Filter filter,
GrSamplerState::MipmapMode mm,
SkBlendMode mode,
const SkPMColor4f& color,
const SkRect& srcRect,
const SkRect& dstRect,
GrAA aa,
GrQuadAAFlags edgeAA,
SkCanvas::SrcRectConstraint constraint,
const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> texXform) {
const SkRect* subset = constraint == SkCanvas::kStrict_SrcRectConstraint ?
&srcRect : nullptr;
DrawQuad quad{GrQuad::MakeFromRect(dstRect, viewMatrix), GrQuad(srcRect), edgeAA};
this->drawTexturedQuad(clip, std::move(view), srcAlphaType, std::move(texXform),
filter, color, mode, aa, &quad, subset);
this->drawTexturedQuad(clip, std::move(view), srcAlphaType, std::move(texXform), filter, mm,
color, mode, aa, &quad, subset);
}
/**
@ -289,16 +298,25 @@ public:
* 'subset' is null, it's equivalent to using the fast src rect constraint. If 'subset' is
* provided, the strict src rect constraint is applied using 'subset'.
*/
void drawTextureQuad(const GrClip* clip, GrSurfaceProxyView view, GrColorType srcColorType,
SkAlphaType srcAlphaType, GrSamplerState::Filter filter, SkBlendMode mode,
const SkPMColor4f& color, const SkPoint srcQuad[4],
const SkPoint dstQuad[4], GrAA aa, GrQuadAAFlags edgeAA,
const SkRect* subset, const SkMatrix& viewMatrix,
void drawTextureQuad(const GrClip* clip,
GrSurfaceProxyView view,
GrColorType srcColorType,
SkAlphaType srcAlphaType,
GrSamplerState::Filter filter,
GrSamplerState::MipmapMode mm,
SkBlendMode mode,
const SkPMColor4f& color,
const SkPoint srcQuad[4],
const SkPoint dstQuad[4],
GrAA aa,
GrQuadAAFlags edgeAA,
const SkRect* subset,
const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> texXform) {
DrawQuad quad{GrQuad::MakeFromSkQuad(dstQuad, viewMatrix),
GrQuad::MakeFromSkQuad(srcQuad, SkMatrix::I()), edgeAA};
this->drawTexturedQuad(clip, std::move(view), srcAlphaType, std::move(texXform),
filter, color, mode, aa, &quad, subset);
this->drawTexturedQuad(clip, std::move(view), srcAlphaType, std::move(texXform), filter, mm,
color, mode, aa, &quad, subset);
}
/** Used with drawTextureSet */
@ -323,9 +341,16 @@ public:
* can be inferred from the array within this function, but the information is already known
* by SkGpuDevice, so no need to incur another iteration over the array.
*/
void drawTextureSet(const GrClip*, TextureSetEntry[], int cnt, int proxyRunCnt,
GrSamplerState::Filter, SkBlendMode mode, GrAA aa,
SkCanvas::SrcRectConstraint, const SkMatrix& viewMatrix,
void drawTextureSet(const GrClip*,
TextureSetEntry[],
int cnt,
int proxyRunCnt,
GrSamplerState::Filter,
GrSamplerState::MipmapMode,
SkBlendMode mode,
GrAA aa,
SkCanvas::SrcRectConstraint,
const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> texXform);
/**
@ -645,6 +670,7 @@ private:
SkAlphaType alphaType,
sk_sp<GrColorSpaceXform> textureXform,
GrSamplerState::Filter filter,
GrSamplerState::MipmapMode,
const SkPMColor4f& color,
SkBlendMode blendMode,
GrAA aa,

View File

@ -16,48 +16,71 @@
*/
class GrSamplerState {
public:
enum class Filter : uint8_t { kNearest, kLinear, kMipMap, kLast = kMipMap };
enum class WrapMode : uint8_t { kClamp, kRepeat, kMirrorRepeat, kClampToBorder,
kLast = kClampToBorder };
enum class Filter : uint8_t { kNearest, kLinear, kLast = kLinear };
enum class MipmapMode : uint8_t { kNone, /*kNearest,*/ kLinear, kLast = kLinear };
enum class WrapMode : uint8_t {
kClamp,
kRepeat,
kMirrorRepeat,
kClampToBorder,
kLast = kClampToBorder
};
static constexpr int kFilterCount = static_cast<int>(Filter::kLast) + 1;
static constexpr int kWrapModeCount = static_cast<int>(WrapMode::kLast) + 1;
constexpr GrSamplerState() = default;
constexpr GrSamplerState(WrapMode wrapXAndY, Filter filter)
: fWrapModes{wrapXAndY, wrapXAndY}, fFilter(filter) {}
constexpr GrSamplerState(WrapMode wrapXAndY, Filter filter, MipmapMode mm = MipmapMode::kNone)
: fWrapModes{wrapXAndY, wrapXAndY}, fFilter(filter), fMipmapMode(mm) {}
constexpr GrSamplerState(WrapMode wrapX, WrapMode wrapY, Filter filter)
: fWrapModes{wrapX, wrapY}, fFilter(filter) {}
constexpr GrSamplerState(WrapMode wrapX,
WrapMode wrapY,
Filter filter,
MipmapMode mm = MipmapMode::kNone)
: fWrapModes{wrapX, wrapY}, fFilter(filter), fMipmapMode(mm) {}
constexpr GrSamplerState(const WrapMode wrapModes[2], Filter filter)
: fWrapModes{wrapModes[0], wrapModes[1]}, fFilter(filter) {}
constexpr GrSamplerState(const WrapMode wrapModes[2],
Filter filter,
MipmapMode mm = MipmapMode::kNone)
: fWrapModes{wrapModes[0], wrapModes[1]}, fFilter(filter), fMipmapMode(mm) {}
constexpr /*explicit*/ GrSamplerState(Filter filter) : fFilter(filter) {}
constexpr GrSamplerState(Filter filter, MipmapMode mm) : fFilter(filter), fMipmapMode(mm) {}
constexpr GrSamplerState(const GrSamplerState&) = default;
constexpr GrSamplerState& operator=(const GrSamplerState&) = default;
constexpr Filter filter() const { return fFilter; }
constexpr void setFilterMode(Filter filterMode) { fFilter = filterMode; }
constexpr void setWrapModeX(const WrapMode wrap) { fWrapModes[0] = wrap; }
constexpr void setWrapModeY(const WrapMode wrap) { fWrapModes[1] = wrap; }
constexpr WrapMode wrapModeX() const { return fWrapModes[0]; }
constexpr WrapMode wrapModeY() const { return fWrapModes[1]; }
constexpr bool isRepeated() const {
return (WrapMode::kClamp != fWrapModes[0] && WrapMode::kClampToBorder != fWrapModes[0]) ||
(WrapMode::kClamp != fWrapModes[1] && WrapMode::kClampToBorder != fWrapModes[1]);
return fWrapModes[0] == WrapMode::kRepeat || fWrapModes[0] == WrapMode::kMirrorRepeat ||
fWrapModes[1] == WrapMode::kRepeat || fWrapModes[1] == WrapMode::kMirrorRepeat;
}
constexpr Filter filter() const { return fFilter; }
constexpr MipmapMode mipmapMode() const { return fMipmapMode; }
constexpr GrMipmapped mipmapped() const {
return GrMipmapped(fMipmapMode != MipmapMode::kNone);
}
constexpr void setFilterMode(Filter filterMode) { fFilter = filterMode; }
constexpr void setMipmapMode(MipmapMode mm) { fMipmapMode = mm; }
constexpr void setWrapModeX(const WrapMode wrap) { fWrapModes[0] = wrap; }
constexpr void setWrapModeY(const WrapMode wrap) { fWrapModes[1] = wrap; }
constexpr bool operator==(GrSamplerState that) const {
return fWrapModes[0] == that.fWrapModes[0] && fWrapModes[1] == that.fWrapModes[1] &&
fFilter == that.fFilter;
fFilter == that.fFilter && fMipmapMode == that.fMipmapMode;
}
constexpr bool operator!=(const GrSamplerState& that) const { return !(*this == that); }
@ -68,19 +91,23 @@ public:
*/
constexpr uint8_t asIndex() const {
constexpr int kNumWraps = static_cast<int>(WrapMode::kLast) + 1;
constexpr int kNumFilters = static_cast<int>(Filter::kLast ) + 1;
int result = static_cast<int>(fWrapModes[0])*1
+ static_cast<int>(fWrapModes[1])*kNumWraps
+ static_cast<int>(fFilter) *kNumWraps*kNumWraps;
+ static_cast<int>(fFilter) *kNumWraps*kNumWraps
+ static_cast<int>(fMipmapMode) *kNumWraps*kNumWraps*kNumFilters;
SkASSERT(result <= kNumUniqueSamplers);
return static_cast<uint8_t>(result);
}
static constexpr int kNumUniqueSamplers = (static_cast<int>(WrapMode::kLast) + 1)
* (static_cast<int>(WrapMode::kLast) + 1)
* (static_cast<int>(Filter::kLast ) + 1);
static constexpr int kNumUniqueSamplers = (static_cast<int>(WrapMode::kLast ) + 1)
* (static_cast<int>(WrapMode::kLast ) + 1)
* (static_cast<int>(Filter::kLast ) + 1)
* (static_cast<int>(MipmapMode::kLast) + 1);
private:
WrapMode fWrapModes[2] = {WrapMode::kClamp, WrapMode::kClamp};
Filter fFilter = GrSamplerState::Filter::kNearest;
MipmapMode fMipmapMode = GrSamplerState::MipmapMode::kNone;
};
static_assert(GrSamplerState::kNumUniqueSamplers <=

View File

@ -575,12 +575,20 @@ void GrSurfaceContext::asyncRescaleAndReadPixels(const SkImageInfo& info,
callback(context, nullptr);
return;
}
tempRTC->drawTexture(nullptr, std::move(texProxyView), this->colorInfo().alphaType(),
GrSamplerState::Filter::kNearest, SkBlendMode::kSrc,
SK_PMColor4fWHITE, srcRectToDraw,
SkRect::MakeWH(srcRect.width(), srcRect.height()), GrAA::kNo,
GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
SkMatrix::I(), std::move(xform));
tempRTC->drawTexture(nullptr,
std::move(texProxyView),
this->colorInfo().alphaType(),
GrSamplerState::Filter::kNearest,
GrSamplerState::MipmapMode::kNone,
SkBlendMode::kSrc,
SK_PMColor4fWHITE,
srcRectToDraw,
SkRect::MakeWH(srcRect.width(), srcRect.height()),
GrAA::kNo,
GrQuadAAFlags::kNone,
SkCanvas::kFast_SrcRectConstraint,
SkMatrix::I(),
std::move(xform));
x = y = 0;
}
}
@ -799,11 +807,20 @@ void GrSurfaceContext::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorS
callback(context, nullptr);
return;
}
tempRTC->drawTexture(nullptr, std::move(srcView), this->colorInfo().alphaType(),
GrSamplerState::Filter::kNearest, SkBlendMode::kSrc,
SK_PMColor4fWHITE, srcRectToDraw, SkRect::Make(srcRect.size()),
GrAA::kNo, GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
SkMatrix::I(), std::move(xform));
tempRTC->drawTexture(nullptr,
std::move(srcView),
this->colorInfo().alphaType(),
GrSamplerState::Filter::kNearest,
GrSamplerState::MipmapMode::kNone,
SkBlendMode::kSrc,
SK_PMColor4fWHITE,
srcRectToDraw,
SkRect::Make(srcRect.size()),
GrAA::kNo,
GrQuadAAFlags::kNone,
SkCanvas::kFast_SrcRectConstraint,
SkMatrix::I(),
std::move(xform));
srcView = tempRTC->readSurfaceView();
SkASSERT(srcView.asTextureProxy());
x = y = 0;
@ -1058,11 +1075,20 @@ std::unique_ptr<GrRenderTargetContext> GrSurfaceContext::rescale(const GrImageIn
return nullptr;
}
// 1-to-1 draw can always be kFast.
linearRTC->drawTexture(nullptr, std::move(texView), srcAlphaType,
GrSamplerState::Filter::kNearest, SkBlendMode::kSrc,
SK_PMColor4fWHITE, SkRect::Make(srcRect),
SkRect::Make(srcRect.size()), GrAA::kNo, GrQuadAAFlags::kNone,
SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), std::move(xform));
linearRTC->drawTexture(nullptr,
std::move(texView),
srcAlphaType,
GrSamplerState::Filter::kNearest,
GrSamplerState::MipmapMode::kNone,
SkBlendMode::kSrc,
SK_PMColor4fWHITE,
SkRect::Make(srcRect),
SkRect::Make(srcRect.size()),
GrAA::kNo,
GrQuadAAFlags::kNone,
SkCanvas::kFast_SrcRectConstraint,
SkMatrix::I(),
std::move(xform));
texView = linearRTC->readSurfaceView();
SkASSERT(texView.asTextureProxy());
tempA = std::move(linearRTC);
@ -1135,9 +1161,20 @@ std::unique_ptr<GrRenderTargetContext> GrSurfaceContext::rescale(const GrImageIn
if (nextDims.width() <= srcRect.width() && nextDims.height() <= srcRect.height()) {
constraint = SkCanvas::SrcRectConstraint::kFast_SrcRectConstraint;
}
tempB->drawTexture(nullptr, std::move(texView), srcAlphaType, filter, SkBlendMode::kSrc,
SK_PMColor4fWHITE, SkRect::Make(srcRect), dstRect, GrAA::kNo,
GrQuadAAFlags::kNone, constraint, SkMatrix::I(), std::move(xform));
tempB->drawTexture(nullptr,
std::move(texView),
srcAlphaType,
filter,
GrSamplerState::MipmapMode::kNone,
SkBlendMode::kSrc,
SK_PMColor4fWHITE,
SkRect::Make(srcRect),
dstRect,
GrAA::kNo,
GrQuadAAFlags::kNone,
constraint,
SkMatrix::I(),
std::move(xform));
}
texView = tempB->readSurfaceView();
tempA = std::move(tempB);

View File

@ -81,7 +81,7 @@ std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor(
const SkRect* domain,
GrSamplerState samplerState) {
return this->createFragmentProcessorForView(
this->view(samplerState.filter()), textureMatrix, subset, domain, samplerState);
this->view(samplerState.mipmapped()), textureMatrix, subset, domain, samplerState);
}
std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createBicubicFragmentProcessor(

View File

@ -29,7 +29,7 @@ std::unique_ptr<GrFragmentProcessor> GrTextureMaker::createFragmentProcessor(
GrSamplerState sampler) {
GrSurfaceProxyView view;
return this->createFragmentProcessorForView(
this->view(sampler.filter()), textureMatrix, subset, domain, sampler);
this->view(sampler.mipmapped()), textureMatrix, subset, domain, sampler);
}
std::unique_ptr<GrFragmentProcessor> GrTextureMaker::createBicubicFragmentProcessor(

View File

@ -101,9 +101,3 @@ GrSurfaceProxyView GrTextureProducer::view(GrMipmapped mipMapped) {
!caps->isFormatCopyable(result.proxy()->backendFormat()));
return result;
}
GrSurfaceProxyView GrTextureProducer::view(GrSamplerState::Filter filter) {
auto mipMapped = filter == GrSamplerState::Filter::kMipMap ? GrMipmapped::kYes
: GrMipmapped::kNo;
return this->view(mipMapped);
}

View File

@ -88,9 +88,6 @@ public:
*/
GrSurfaceProxyView view(GrMipmapped);
/** Helper version of above that determines MIP mapping requirement from Filter. */
GrSurfaceProxyView view(GrSamplerState::Filter);
int width() const { return fImageInfo.width(); }
int height() const { return fImageInfo.height(); }
SkISize dimensions() const { return fImageInfo.dimensions(); }

View File

@ -147,11 +147,6 @@ size_t GrTextureProxy::onUninstantiatedGpuMemorySize(const GrCaps& caps) const {
this->proxyMipmapped(), !this->priv().isExact());
}
GrSamplerState::Filter GrTextureProxy::HighestFilterMode(GrTextureType textureType) {
return GrTextureTypeHasRestrictedSampling(textureType) ? GrSamplerState::Filter::kLinear
: GrSamplerState::Filter::kMipMap;
}
bool GrTextureProxy::ProxiesAreCompatibleAsDynamicState(const GrSurfaceProxy* first,
const GrSurfaceProxy* second) {
// In order to be compatible, the proxies should also have the same texture type. This is

View File

@ -58,9 +58,6 @@ public:
return GrTextureTypeHasRestrictedSampling(this->textureType());
}
// Returns the highest allowed filter mode for a given texture type
static GrSamplerState::Filter HighestFilterMode(const GrTextureType textureType);
// Returns true if the passed in proxies can be used as dynamic state together when flushing
// draws to the gpu. This accepts GrSurfaceProxy since the information needed is defined on
// that type, but this function exists in GrTextureProxy because it's only relevant when the

View File

@ -817,7 +817,6 @@ static GrSamplerState::Filter compute_lattice_filter_mode(const SkPaint& paint)
if (paint.getFilterQuality() == kNone_SkFilterQuality) {
return GrSamplerState::Filter::kNearest;
}
return GrSamplerState::Filter::kLinear;
}
@ -861,7 +860,7 @@ void SkGpuDevice::drawProducerLattice(GrTextureProducer* producer,
auto dstColorSpace = fRenderTargetContext->colorInfo().colorSpace();
const GrSamplerState::Filter filter = compute_lattice_filter_mode(*paint);
auto view = producer->view(filter);
auto view = producer->view(GrMipmapped::kNo);
if (!view) {
return;
}

View File

@ -336,10 +336,17 @@ static SkPMColor4f texture_color(SkColor4f paintColor, float entryAlpha, GrColor
}
// Assumes srcRect and dstRect have already been optimized to fit the proxy
static void draw_texture(GrRenderTargetContext* rtc, const GrClip* clip, const SkMatrix& ctm,
const SkPaint& paint, const SkRect& srcRect, const SkRect& dstRect,
const SkPoint dstClip[4], GrAA aa, GrQuadAAFlags aaFlags,
SkCanvas::SrcRectConstraint constraint, GrSurfaceProxyView view,
static void draw_texture(GrRenderTargetContext* rtc,
const GrClip* clip,
const SkMatrix& ctm,
const SkPaint& paint,
const SkRect& srcRect,
const SkRect& dstRect,
const SkPoint dstClip[4],
GrAA aa,
GrQuadAAFlags aaFlags,
SkCanvas::SrcRectConstraint constraint,
GrSurfaceProxyView view,
const GrColorInfo& srcColorInfo) {
const GrColorInfo& dstInfo(rtc->colorInfo());
auto textureXform =
@ -378,15 +385,36 @@ static void draw_texture(GrRenderTargetContext* rtc, const GrClip* clip, const S
SkPoint srcQuad[4];
GrMapRectPoints(dstRect, srcRect, dstClip, srcQuad, 4);
rtc->drawTextureQuad(clip, std::move(view), srcColorInfo.colorType(),
srcColorInfo.alphaType(), filter, paint.getBlendMode(), color, srcQuad,
dstClip, aa, aaFlags,
rtc->drawTextureQuad(clip,
std::move(view),
srcColorInfo.colorType(),
srcColorInfo.alphaType(),
filter,
GrSamplerState::MipmapMode::kNone,
paint.getBlendMode(),
color,
srcQuad,
dstClip,
aa,
aaFlags,
constraint == SkCanvas::kStrict_SrcRectConstraint ? &srcRect : nullptr,
ctm, std::move(textureXform));
ctm,
std::move(textureXform));
} else {
rtc->drawTexture(clip, std::move(view), srcColorInfo.alphaType(), filter,
paint.getBlendMode(), color, srcRect, dstRect, aa, aaFlags, constraint,
ctm, std::move(textureXform));
rtc->drawTexture(clip,
std::move(view),
srcColorInfo.alphaType(),
filter,
GrSamplerState::MipmapMode::kNone,
paint.getBlendMode(),
color,
srcRect,
dstRect,
aa,
aaFlags,
constraint,
ctm,
std::move(textureXform));
}
}
@ -404,11 +432,11 @@ static void draw_texture_producer(GrRecordingContext* context,
GrAA aa,
GrQuadAAFlags aaFlags,
SkCanvas::SrcRectConstraint constraint,
GrSamplerState::WrapMode wm,
GrSamplerState::Filter fm,
GrSamplerState sampler,
bool doBicubic) {
const SkMatrix& ctm(matrixProvider.localToDevice());
if (wm == GrSamplerState::WrapMode::kClamp && !producer->isPlanar() &&
if (sampler.wrapModeX() == GrSamplerState::WrapMode::kClamp &&
sampler.wrapModeY() == GrSamplerState::WrapMode::kClamp && !producer->isPlanar() &&
can_use_draw_texture(paint)) {
// We've done enough checks above to allow us to pass ClampNearest() and not check for
// scaling adjustments.
@ -446,8 +474,9 @@ static void draw_texture_producer(GrRecordingContext* context,
bool coordsAllInsideSrcRect = aaFlags == GrQuadAAFlags::kNone && !mf;
// Check for optimization to drop the src rect constraint when using linear filtering.
if (!doBicubic && fm == GrSamplerState::Filter::kLinear && restrictToSubset &&
coordsAllInsideSrcRect && !producer->isPlanar()) {
if (!doBicubic && sampler.filter() == GrSamplerState::Filter::kLinear && restrictToSubset &&
sampler.mipmapped() == GrMipmapped::kNo && coordsAllInsideSrcRect &&
!producer->isPlanar()) {
SkMatrix combinedMatrix;
combinedMatrix.setConcat(ctm, srcToDst);
if (can_ignore_linear_filtering_subset(*producer, src, combinedMatrix, rtc->numSamples())) {
@ -467,9 +496,10 @@ static void draw_texture_producer(GrRecordingContext* context,
const SkRect* domain = coordsAllInsideSrcRect ? &src : nullptr;
std::unique_ptr<GrFragmentProcessor> fp;
if (doBicubic) {
fp = producer->createBicubicFragmentProcessor(textureMatrix, subset, domain, wm, wm);
fp = producer->createBicubicFragmentProcessor(textureMatrix, subset, domain,
sampler.wrapModeX(), sampler.wrapModeY());
} else {
fp = producer->createFragmentProcessor(textureMatrix, subset, domain, {wm, fm});
fp = producer->createFragmentProcessor(textureMatrix, subset, domain, sampler);
}
if (fp) {
fp = GrXfermodeFragmentProcessor::Make(std::move(fp), nullptr, SkBlendMode::kModulate);
@ -534,8 +564,7 @@ void draw_tiled_bitmap(GrRecordingContext* context,
const SkPaint& paint,
GrAA aa,
SkCanvas::SrcRectConstraint constraint,
GrSamplerState::WrapMode wm,
GrSamplerState::Filter fm,
GrSamplerState sampler,
bool doBicubic) {
SkRect clippedSrcRect = SkRect::Make(clippedSrcIRect);
@ -562,7 +591,7 @@ void draw_tiled_bitmap(GrRecordingContext* context,
SkIntToScalar(iTileR.fTop));
SkRect rectToDraw = tileR;
srcToDst.mapRect(&rectToDraw);
if (fm != GrSamplerState::Filter::kNearest || doBicubic) {
if (sampler.filter() != GrSamplerState::Filter::kNearest || doBicubic) {
SkIRect iClampRect;
if (SkCanvas::kFast_SrcRectConstraint == constraint) {
@ -611,10 +640,9 @@ void draw_tiled_bitmap(GrRecordingContext* context,
tileR.offset(-offset.fX, -offset.fY);
SkMatrix offsetSrcToDst = srcToDst;
offsetSrcToDst.preTranslate(offset.fX, offset.fY);
draw_texture_producer(context, rtc, clip, matrixProvider, paint, &tileProducer,
tileR, rectToDraw, nullptr, offsetSrcToDst, aa, aaFlags,
constraint, wm, fm, doBicubic);
constraint, sampler, doBicubic);
}
}
}
@ -650,10 +678,9 @@ void SkGpuDevice::drawImageQuad(const SkImage* image, const SkRect* srcRect, con
preViewMatrix ? *preViewMatrix : SkMatrix::I());
const SkMatrix& ctm(matrixProvider.localToDevice());
bool doBicubic;
GrSamplerState::Filter fm = GrSkFilterQualityToGrFilterMode(
image->width(), image->height(), paint.getFilterQuality(), ctm, srcToDst,
fContext->priv().options().fSharpenMipmappedTextures, &doBicubic);
bool sharpenMM = fContext->priv().options().fSharpenMipmappedTextures;
auto [fm, mm, bicubic] = GrInterpretFilterQuality(image->dimensions(), paint.getFilterQuality(),
ctm, srcToDst, sharpenMM);
auto clip = this->clip();
@ -667,7 +694,7 @@ void SkGpuDevice::drawImageQuad(const SkImage* image, const SkRect* srcRect, con
GrYUVAImageTextureMaker maker(fContext.get(), image);
draw_texture_producer(fContext.get(), fRenderTargetContext.get(), clip, matrixProvider,
paint, &maker, src, dst, dstClip, srcToDst, aa, aaFlags, constraint,
wrapMode, fm, doBicubic);
{wrapMode, fm, mm}, bicubic);
return;
}
@ -691,7 +718,7 @@ void SkGpuDevice::drawImageQuad(const SkImage* image, const SkRect* srcRect, con
GrTextureAdjuster adjuster(fContext.get(), std::move(view), colorInfo, pinnedUniqueID);
draw_texture_producer(fContext.get(), fRenderTargetContext.get(), clip, matrixProvider,
paint, &adjuster, src, dst, dstClip, srcToDst, aa, aaFlags,
constraint, wrapMode, fm, doBicubic);
constraint, {wrapMode, fm, mm}, bicubic);
return;
}
@ -701,7 +728,7 @@ void SkGpuDevice::drawImageQuad(const SkImage* image, const SkRect* srcRect, con
SkASSERT(!image->isTextureBacked());
int tileFilterPad;
if (doBicubic) {
if (bicubic) {
tileFilterPad = GrBicubicEffect::kFilterTexelPad;
} else if (GrSamplerState::Filter::kNearest == fm) {
tileFilterPad = 0;
@ -724,7 +751,7 @@ void SkGpuDevice::drawImageQuad(const SkImage* image, const SkRect* srcRect, con
LogDrawScaleFactor(ctm, srcToDst, paint.getFilterQuality());
draw_tiled_bitmap(fContext.get(), fRenderTargetContext.get(), clip, bm, tileSize,
matrixProvider, srcToDst, src, clippedSubset, paint, aa,
constraint, wrapMode, fm, doBicubic);
constraint, {wrapMode, fm, mm}, bicubic);
return;
}
}
@ -740,7 +767,7 @@ void SkGpuDevice::drawImageQuad(const SkImage* image, const SkRect* srcRect, con
GrImageTextureMaker maker(fContext.get(), image, GrImageTexGenPolicy::kDraw);
draw_texture_producer(fContext.get(), fRenderTargetContext.get(), clip, matrixProvider,
paint, &maker, src, dst, dstClip, srcToDst, aa, aaFlags, constraint,
wrapMode, fm, doBicubic);
{wrapMode, fm, mm}, bicubic);
return;
}
@ -749,7 +776,7 @@ void SkGpuDevice::drawImageQuad(const SkImage* image, const SkRect* srcRect, con
GrBitmapTextureMaker maker(fContext.get(), bm, GrImageTexGenPolicy::kDraw);
draw_texture_producer(fContext.get(), fRenderTargetContext.get(), clip, matrixProvider,
paint, &maker, src, dst, dstClip, srcToDst, aa, aaFlags, constraint,
wrapMode, fm, doBicubic);
{wrapMode, fm, mm}, bicubic);
}
// Otherwise don't know how to draw it
@ -799,9 +826,17 @@ void SkGpuDevice::drawEdgeAAImageSet(const SkCanvas::ImageSetEntry set[], int co
auto textureXform = GrColorSpaceXform::Make(
set[base].fImage->colorSpace(), set[base].fImage->alphaType(),
fRenderTargetContext->colorInfo().colorSpace(), kPremul_SkAlphaType);
fRenderTargetContext->drawTextureSet(this->clip(), textures.get() + base, n, p,
filter, mode, GrAA::kYes, constraint,
this->localToDevice(), std::move(textureXform));
fRenderTargetContext->drawTextureSet(this->clip(),
textures.get() + base,
n,
p,
filter,
GrSamplerState::MipmapMode::kNone,
mode,
GrAA::kYes,
constraint,
this->localToDevice(),
std::move(textureXform));
}
base = nextBase;
n = 0;

View File

@ -23,6 +23,7 @@
#include "src/core/SkColorSpacePriv.h"
#include "src/core/SkImagePriv.h"
#include "src/core/SkMaskFilterBase.h"
#include "src/core/SkMatrixPriv.h"
#include "src/core/SkMessageBus.h"
#include "src/core/SkMipmap.h"
#include "src/core/SkPaintPriv.h"
@ -37,6 +38,7 @@
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrTextureProxy.h"
#include "src/gpu/GrXferProcessor.h"
#include "src/gpu/SkGr.h"
#include "src/gpu/effects/GrBicubicEffect.h"
#include "src/gpu/effects/GrPorterDuffXferProcessor.h"
#include "src/gpu/effects/GrXfermodeFragmentProcessor.h"
@ -432,21 +434,25 @@ bool SkPaintToGrPaintWithTexture(GrRecordingContext* context,
////////////////////////////////////////////////////////////////////////////////////////////////
GrSamplerState::Filter GrSkFilterQualityToGrFilterMode(int imageWidth, int imageHeight,
SkFilterQuality paintFilterQuality,
const SkMatrix& viewM,
const SkMatrix& localM,
bool sharpenMipmappedTextures,
bool* doBicubic) {
*doBicubic = false;
if (imageWidth <= 1 && imageHeight <= 1) {
return GrSamplerState::Filter::kNearest;
std::tuple<GrSamplerState::Filter,
GrSamplerState::MipmapMode,
bool /*bicubic*/>
GrInterpretFilterQuality(SkISize imageDims,
SkFilterQuality paintFilterQuality,
const SkMatrix& viewM,
const SkMatrix& localM,
bool sharpenMipmappedTextures) {
using Filter = GrSamplerState::Filter;
using MipmapMode = GrSamplerState::MipmapMode;
if (imageDims.area() <= 1) {
// TOOD: should know we're not in decal mode to do this transformation.
return {Filter::kNearest, MipmapMode::kNone, false};
}
switch (paintFilterQuality) {
case kNone_SkFilterQuality:
return GrSamplerState::Filter::kNearest;
return {Filter::kNearest, MipmapMode::kNone, false};
case kLow_SkFilterQuality:
return GrSamplerState::Filter::kLinear;
return {Filter::kLinear, MipmapMode::kNone, false};
case kMedium_SkFilterQuality: {
SkMatrix matrix;
matrix.setConcat(viewM, localM);
@ -460,18 +466,21 @@ GrSamplerState::Filter GrSkFilterQualityToGrFilterMode(int imageWidth, int image
// 2^0.5/2 = s
SkScalar mipScale = sharpenMipmappedTextures ? SK_ScalarRoot2Over2 : SK_Scalar1;
if (matrix.getMinScale() < mipScale) {
return GrSamplerState::Filter::kMipMap;
return {Filter::kLinear, MipmapMode::kLinear, false};
} else {
// Don't trigger MIP level generation unnecessarily.
return GrSamplerState::Filter::kLinear;
return {Filter::kLinear, MipmapMode::kNone, false};
}
}
case kHigh_SkFilterQuality: {
SkMatrix matrix;
matrix.setConcat(viewM, localM);
GrSamplerState::Filter textureFilterMode;
*doBicubic = GrBicubicEffect::ShouldUseBicubic(matrix, &textureFilterMode);
return textureFilterMode;
switch (SkMatrixPriv::AdjustHighQualityFilterLevel(matrix)) {
case kNone_SkFilterQuality: return {Filter::kNearest, MipmapMode::kNone , false};
case kLow_SkFilterQuality: return {Filter::kLinear , MipmapMode::kNone , false};
case kMedium_SkFilterQuality: return {Filter::kLinear , MipmapMode::kLinear, false};
case kHigh_SkFilterQuality: return {Filter::kNearest, MipmapMode::kNone , true };
}
SkUNREACHABLE;
}
}
SkUNREACHABLE;

View File

@ -141,12 +141,19 @@ bool SkPaintToGrPaintWithTexture(GrRecordingContext*,
////////////////////////////////////////////////////////////////////////////////
// Misc Sk to Gr type conversions
GrSamplerState::Filter GrSkFilterQualityToGrFilterMode(int imageWidth, int imageHeight,
SkFilterQuality paintFilterQuality,
const SkMatrix& viewM,
const SkMatrix& localM,
bool sharpenMipmappedTextures,
bool* doBicubic);
/**
* Determines how to interpret SkFilterQuality given draw params and canvas state. If the returned
* bool is true then bicubic filtering should be used (and the two other return values can be
* ignored).
*/
std::tuple<GrSamplerState::Filter,
GrSamplerState::MipmapMode,
bool /*bicubic*/>
GrInterpretFilterQuality(SkISize imageDims,
SkFilterQuality paintFilterQuality,
const SkMatrix& viewM,
const SkMatrix& localM,
bool sharpenMipmappedTextures);
//////////////////////////////////////////////////////////////////////////////

View File

@ -128,6 +128,24 @@ static D3D12_TEXTURE_ADDRESS_MODE wrap_mode_to_d3d_address_mode(GrSamplerState::
SK_ABORT("Unknown wrap mode.");
}
static D3D12_FILTER d3d_filter(GrSamplerState sampler) {
switch (sampler.mipmapMode()) {
case GrSamplerState::MipmapMode::kNone:
switch (sampler.filter()) {
case GrSamplerState::Filter::kNearest: return D3D12_FILTER_MIN_MAG_MIP_POINT;
case GrSamplerState::Filter::kLinear: return D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT;
}
SkUNREACHABLE;
case GrSamplerState::MipmapMode::kLinear:
switch (sampler.filter()) {
case GrSamplerState::Filter::kNearest: return D3D12_FILTER_MIN_MAG_POINT_MIP_LINEAR;
case GrSamplerState::Filter::kLinear: return D3D12_FILTER_MIN_MAG_MIP_LINEAR;
}
SkUNREACHABLE;
}
SkUNREACHABLE;
}
D3D12_CPU_DESCRIPTOR_HANDLE GrD3DResourceProvider::findOrCreateCompatibleSampler(
const GrSamplerState& params) {
uint32_t key = params.asIndex();
@ -136,17 +154,7 @@ D3D12_CPU_DESCRIPTOR_HANDLE GrD3DResourceProvider::findOrCreateCompatibleSampler
return *samplerPtr;
}
static D3D12_FILTER d3dFilterModes[] = {
D3D12_FILTER_MIN_MAG_MIP_POINT,
D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT,
D3D12_FILTER_MIN_MAG_MIP_LINEAR
};
static_assert((int)GrSamplerState::Filter::kNearest == 0);
static_assert((int)GrSamplerState::Filter::kLinear == 1);
static_assert((int)GrSamplerState::Filter::kMipMap == 2);
D3D12_FILTER filter = d3dFilterModes[static_cast<int>(params.filter())];
D3D12_FILTER filter = d3d_filter(params);
D3D12_TEXTURE_ADDRESS_MODE addressModeU = wrap_mode_to_d3d_address_mode(params.wrapModeX());
D3D12_TEXTURE_ADDRESS_MODE addressModeV = wrap_mode_to_d3d_address_mode(params.wrapModeY());

View File

@ -73,7 +73,6 @@ static wgpu::FilterMode to_dawn_filter_mode(GrSamplerState::Filter filter) {
case GrSamplerState::Filter::kNearest:
return wgpu::FilterMode::Nearest;
case GrSamplerState::Filter::kLinear:
case GrSamplerState::Filter::kMipMap:
return wgpu::FilterMode::Linear;
default:
SkASSERT(!"unsupported filter mode");

View File

@ -329,25 +329,3 @@ std::unique_ptr<GrFragmentProcessor> GrBicubicEffect::TestCreate(GrProcessorTest
}
}
#endif
//////////////////////////////////////////////////////////////////////////////
bool GrBicubicEffect::ShouldUseBicubic(const SkMatrix& matrix, GrSamplerState::Filter* filterMode) {
switch (SkMatrixPriv::AdjustHighQualityFilterLevel(matrix)) {
case kNone_SkFilterQuality:
*filterMode = GrSamplerState::Filter::kNearest;
break;
case kLow_SkFilterQuality:
*filterMode = GrSamplerState::Filter::kLinear;
break;
case kMedium_SkFilterQuality:
*filterMode = GrSamplerState::Filter::kMipMap;
break;
case kHigh_SkFilterQuality:
// When we use the bicubic filtering effect each sample is read from the texture using
// nearest neighbor sampling.
*filterMode = GrSamplerState::Filter::kNearest;
return true;
}
return false;
}

View File

@ -99,16 +99,6 @@ public:
Kernel,
Direction);
/**
* Determines whether the bicubic effect should be used based on the transformation from the
* local coords to the device. Returns true if the bicubic effect should be used. filterMode
* is set to appropriate filtering mode to use regardless of the return result (e.g. when this
* returns false it may indicate that the best fallback is to use kMipMap, kLinear, or
* kNearest).
*/
static bool ShouldUseBicubic(const SkMatrix& localCoordsToDevice,
GrSamplerState::Filter* filterMode);
private:
class Impl;

View File

@ -15,8 +15,9 @@
#include "src/sksl/SkSLCPP.h"
#include "src/sksl/SkSLUtil.h"
using Mode = GrSamplerState::WrapMode;
using Wrap = GrSamplerState::WrapMode;
using Filter = GrSamplerState::Filter;
using MipmapMode = GrSamplerState::MipmapMode;
struct GrTextureEffect::Sampling {
GrSamplerState fHWSampler;
@ -24,9 +25,9 @@ struct GrTextureEffect::Sampling {
SkRect fShaderSubset = {0, 0, 0, 0};
SkRect fShaderClamp = {0, 0, 0, 0};
float fBorder[4] = {0, 0, 0, 0};
Sampling(GrSamplerState::Filter filter) : fHWSampler(filter) {}
Sampling(Filter filter, MipmapMode mm) : fHWSampler(filter, mm) {}
Sampling(const GrSurfaceProxy& proxy,
GrSamplerState sampler,
GrSamplerState wrap,
const SkRect&,
const SkRect*,
const float border[4],
@ -59,28 +60,29 @@ GrTextureEffect::Sampling::Sampling(const GrSurfaceProxy& proxy,
ShaderMode fShaderMode;
Span fShaderSubset;
Span fShaderClamp;
Mode fHWMode;
Wrap fHWWrap;
};
auto type = proxy.asTextureProxy()->textureType();
auto filter = sampler.filter();
auto mm = sampler.mipmapMode();
auto resolve = [&](int size, Mode mode, Span subset, Span domain, float linearFilterInset) {
auto resolve = [&](int size, Wrap wrap, Span subset, Span domain, float linearFilterInset) {
Result1D r;
bool canDoModeInHW = true;
// TODO: Use HW border color when available.
if (mode == Mode::kClampToBorder &&
if (wrap == Wrap::kClampToBorder &&
(!caps.clampToBorderSupport() || border[0] || border[1] || border[2] || border[3])) {
canDoModeInHW = false;
} else if (mode != Mode::kClamp && !caps.npotTextureTileSupport() && !SkIsPow2(size)) {
} else if (wrap != Wrap::kClamp && !caps.npotTextureTileSupport() && !SkIsPow2(size)) {
canDoModeInHW = false;
} else if (type != GrTextureType::k2D &&
!(mode == Mode::kClamp || mode == Mode::kClampToBorder)) {
!(wrap == Wrap::kClamp || wrap == Wrap::kClampToBorder)) {
canDoModeInHW = false;
}
if (canDoModeInHW && size > 0 && subset.fA <= 0 && subset.fB >= size) {
r.fShaderMode = ShaderMode::kNone;
r.fHWMode = mode;
r.fHWWrap = wrap;
r.fShaderSubset = r.fShaderClamp = {0, 0};
return r;
}
@ -107,12 +109,12 @@ GrTextureEffect::Sampling::Sampling(const GrSurfaceProxy& proxy,
// So the wrap mode effectively doesn't matter. We use kClamp since it is always
// supported.
r.fShaderMode = ShaderMode::kNone;
r.fHWMode = Mode::kClamp;
r.fHWWrap = Wrap::kClamp;
r.fShaderSubset = r.fShaderClamp = {0, 0};
return r;
}
r.fShaderMode = GetShaderMode(mode, filter);
r.fHWMode = Mode::kClamp;
r.fShaderMode = GetShaderMode(wrap, filter, mm);
r.fHWWrap = Wrap::kClamp;
return r;
};
@ -128,7 +130,7 @@ GrTextureEffect::Sampling::Sampling(const GrSurfaceProxy& proxy,
: Span{SK_FloatNegativeInfinity, SK_FloatInfinity};
auto y = resolve(dim.height(), sampler.wrapModeY(), subsetY, domainY, linearFilterInset.fY);
fHWSampler = {x.fHWMode, y.fHWMode, filter};
fHWSampler = {x.fHWWrap, y.fHWWrap, filter, mm};
fShaderModes[0] = x.fShaderMode;
fShaderModes[1] = y.fShaderMode;
fShaderSubset = {x.fShaderSubset.fA, y.fShaderSubset.fA,
@ -139,8 +141,8 @@ GrTextureEffect::Sampling::Sampling(const GrSurfaceProxy& proxy,
}
bool GrTextureEffect::Sampling::hasBorderAlpha() const {
if (fHWSampler.wrapModeX() == GrSamplerState::WrapMode::kClampToBorder ||
fHWSampler.wrapModeY() == GrSamplerState::WrapMode::kClampToBorder) {
if (fHWSampler.wrapModeX() == Wrap::kClampToBorder ||
fHWSampler.wrapModeY() == Wrap::kClampToBorder) {
return true;
}
if (ShaderModeIsClampToBorder(fShaderModes[0]) || ShaderModeIsClampToBorder(fShaderModes[1])) {
@ -192,14 +194,15 @@ static void get_matrix(const SkMatrix& preMatrix, const GrSurfaceProxyView& view
std::unique_ptr<GrFragmentProcessor> GrTextureEffect::Make(GrSurfaceProxyView view,
SkAlphaType alphaType,
const SkMatrix& matrix,
Filter filter) {
Filter filter,
MipmapMode mm) {
SkMatrix final;
bool lazyProxyNormalization;
get_matrix(matrix, view, &final, &lazyProxyNormalization);
return GrMatrixEffect::Make(final, std::unique_ptr<GrFragmentProcessor>(
new GrTextureEffect(std::move(view),
alphaType,
Sampling(filter),
Sampling(filter, mm),
lazyProxyNormalization)));
}
@ -262,14 +265,14 @@ std::unique_ptr<GrFragmentProcessor> GrTextureEffect::MakeCustomLinearFilterInse
GrSurfaceProxyView view,
SkAlphaType alphaType,
const SkMatrix& matrix,
GrSamplerState::WrapMode wx,
GrSamplerState::WrapMode wy,
Wrap wx,
Wrap wy,
const SkRect& subset,
const SkRect* domain,
SkVector inset,
const GrCaps& caps,
const float border[4]) {
GrSamplerState sampler(wx, wy, GrSamplerState::Filter::kLinear);
GrSamplerState sampler(wx, wy, Filter::kLinear);
Sampling sampling(*view.proxy(), sampler, subset, domain, border, caps, inset);
SkMatrix final;
bool lazyProxyNormalization;
@ -279,32 +282,39 @@ std::unique_ptr<GrFragmentProcessor> GrTextureEffect::MakeCustomLinearFilterInse
std::move(view), alphaType, sampling, lazyProxyNormalization)));
}
GrTextureEffect::ShaderMode GrTextureEffect::GetShaderMode(GrSamplerState::WrapMode mode,
GrSamplerState::Filter filter) {
switch (mode) {
case GrSamplerState::WrapMode::kMirrorRepeat:
GrTextureEffect::ShaderMode GrTextureEffect::GetShaderMode(Wrap wrap,
Filter filter,
MipmapMode mm) {
switch (wrap) {
case Wrap::kMirrorRepeat:
return ShaderMode::kMirrorRepeat;
case GrSamplerState::WrapMode::kClamp:
case Wrap::kClamp:
return ShaderMode::kClamp;
case GrSamplerState::WrapMode::kRepeat:
switch (filter) {
case GrSamplerState::Filter::kNearest:
return ShaderMode::kRepeatNearest;
case GrSamplerState::Filter::kLinear:
return ShaderMode::kRepeatLinear;
case GrSamplerState::Filter::kMipMap:
return ShaderMode::kRepeatMipMap;
case Wrap::kRepeat:
switch (mm) {
case MipmapMode::kNone:
switch (filter) {
case Filter::kNearest: return ShaderMode::kRepeat_Nearest_None;
case Filter::kLinear: return ShaderMode::kRepeat_Linear_None;
}
SkUNREACHABLE;
case MipmapMode::kLinear:
switch (filter) {
case Filter::kNearest: return ShaderMode::kRepeat_Nearest_Mipmap;
case Filter::kLinear: return ShaderMode::kRepeat_Linear_Mipmap;
}
SkUNREACHABLE;
}
SkUNREACHABLE;
case GrSamplerState::WrapMode::kClampToBorder:
return filter == GrSamplerState::Filter::kNearest ? ShaderMode::kClampToBorderNearest
: ShaderMode::kClampToBorderFilter;
case Wrap::kClampToBorder:
return filter == Filter::kNearest ? ShaderMode::kClampToBorder_Nearest
: ShaderMode::kClampToBorder_Filter;
}
SkUNREACHABLE;
}
inline bool GrTextureEffect::ShaderModeIsClampToBorder(ShaderMode m) {
return m == ShaderMode::kClampToBorderNearest || m == ShaderMode::kClampToBorderFilter;
return m == ShaderMode::kClampToBorder_Nearest || m == ShaderMode::kClampToBorder_Filter;
}
void GrTextureEffect::Impl::emitCode(EmitArgs& args) {
@ -366,12 +376,13 @@ void GrTextureEffect::Impl::emitCode(EmitArgs& args) {
switch (m) {
case ShaderMode::kNone: return false;
case ShaderMode::kClamp: return false;
case ShaderMode::kRepeatNearest: return true;
case ShaderMode::kRepeatLinear: return true;
case ShaderMode::kRepeatMipMap: return true;
case ShaderMode::kRepeat_Nearest_None: return true;
case ShaderMode::kRepeat_Linear_None: return true;
case ShaderMode::kRepeat_Nearest_Mipmap: return true;
case ShaderMode::kRepeat_Linear_Mipmap: return true;
case ShaderMode::kMirrorRepeat: return true;
case ShaderMode::kClampToBorderNearest: return true;
case ShaderMode::kClampToBorderFilter: return true;
case ShaderMode::kClampToBorder_Nearest: return true;
case ShaderMode::kClampToBorder_Filter: return true;
}
SkUNREACHABLE;
};
@ -380,12 +391,13 @@ void GrTextureEffect::Impl::emitCode(EmitArgs& args) {
switch (m) {
case ShaderMode::kNone: return false;
case ShaderMode::kClamp: return true;
case ShaderMode::kRepeatNearest: return true;
case ShaderMode::kRepeatLinear: return true;
case ShaderMode::kRepeatMipMap: return true;
case ShaderMode::kRepeat_Nearest_None: return true;
case ShaderMode::kRepeat_Linear_None: return true;
case ShaderMode::kRepeat_Nearest_Mipmap: return true;
case ShaderMode::kRepeat_Linear_Mipmap: return true;
case ShaderMode::kMirrorRepeat: return true;
case ShaderMode::kClampToBorderNearest: return false;
case ShaderMode::kClampToBorderFilter: return true;
case ShaderMode::kClampToBorder_Nearest: return false;
case ShaderMode::kClampToBorder_Filter: return true;
}
SkUNREACHABLE;
};
@ -397,12 +409,13 @@ void GrTextureEffect::Impl::emitCode(EmitArgs& args) {
switch (m) {
case ShaderMode::kNone: return false;
case ShaderMode::kClamp: return false;
case ShaderMode::kRepeatNearest: return false;
case ShaderMode::kRepeatLinear: return true;
case ShaderMode::kRepeatMipMap: return true;
case ShaderMode::kRepeat_Nearest_None: return false;
case ShaderMode::kRepeat_Linear_None: return true;
case ShaderMode::kRepeat_Nearest_Mipmap: return true;
case ShaderMode::kRepeat_Linear_Mipmap: return true;
case ShaderMode::kMirrorRepeat: return false;
case ShaderMode::kClampToBorderNearest: return true;
case ShaderMode::kClampToBorderFilter: return true;
case ShaderMode::kClampToBorder_Nearest: return true;
case ShaderMode::kClampToBorder_Filter: return true;
}
SkUNREACHABLE;
};
@ -458,13 +471,13 @@ void GrTextureEffect::Impl::emitCode(EmitArgs& args) {
// These modes either don't use the subset rect or don't need to map the
// coords to be within the subset.
case ShaderMode::kNone:
case ShaderMode::kClampToBorderNearest:
case ShaderMode::kClampToBorderFilter:
case ShaderMode::kClampToBorder_Nearest:
case ShaderMode::kClampToBorder_Filter:
case ShaderMode::kClamp:
fb->codeAppendf("subsetCoord.%s = inCoord.%s;", coordSwizzle, coordSwizzle);
break;
case ShaderMode::kRepeatNearest:
case ShaderMode::kRepeatLinear:
case ShaderMode::kRepeat_Nearest_None:
case ShaderMode::kRepeat_Linear_None:
fb->codeAppendf(
"subsetCoord.%s = mod(inCoord.%s - %s.%s, %s.%s - %s.%s) + "
"%s.%s;",
@ -472,7 +485,8 @@ void GrTextureEffect::Impl::emitCode(EmitArgs& args) {
subsetStopSwizzle, subsetName, subsetStartSwizzle, subsetName,
subsetStartSwizzle);
break;
case ShaderMode::kRepeatMipMap:
case ShaderMode::kRepeat_Nearest_Mipmap:
case ShaderMode::kRepeat_Linear_Mipmap:
// The approach here is to generate two sets of texture coords that
// are both "moving" at the same speed (if not direction) as
// inCoords. We accomplish that by using two out of phase mirror
@ -533,17 +547,23 @@ void GrTextureEffect::Impl::emitCode(EmitArgs& args) {
}
};
// Insert vars for extra coords and blending weights for kRepeatMipMap.
// Insert vars for extra coords and blending weights for repeat + mip map.
const char* extraRepeatCoordX = nullptr;
const char* repeatCoordWeightX = nullptr;
const char* extraRepeatCoordY = nullptr;
const char* repeatCoordWeightY = nullptr;
if (m[0] == ShaderMode::kRepeatMipMap) {
bool mipmapRepeatX = m[0] == ShaderMode::kRepeat_Nearest_Mipmap ||
m[0] == ShaderMode::kRepeat_Linear_Mipmap;
bool mipmapRepeatY = m[1] == ShaderMode::kRepeat_Nearest_Mipmap ||
m[1] == ShaderMode::kRepeat_Linear_Mipmap;
if (mipmapRepeatX) {
fb->codeAppend("float extraRepeatCoordX; half repeatCoordWeightX;");
extraRepeatCoordX = "extraRepeatCoordX";
repeatCoordWeightX = "repeatCoordWeightX";
}
if (m[1] == ShaderMode::kRepeatMipMap) {
if (mipmapRepeatY) {
fb->codeAppend("float extraRepeatCoordY; half repeatCoordWeightY;");
extraRepeatCoordY = "extraRepeatCoordY";
repeatCoordWeightY = "repeatCoordWeightY";
@ -557,20 +577,20 @@ void GrTextureEffect::Impl::emitCode(EmitArgs& args) {
clampCoord(useClamp[0], "x", "x", "z");
clampCoord(useClamp[1], "y", "y", "w");
// Additional clamping for the extra coords for kRepeatMipMap.
if (m[0] == ShaderMode::kRepeatMipMap) {
// Additional clamping for the extra coords for kRepeat with mip maps.
if (mipmapRepeatX) {
fb->codeAppendf("extraRepeatCoordX = clamp(extraRepeatCoordX, %s.x, %s.z);", clampName,
clampName);
}
if (m[1] == ShaderMode::kRepeatMipMap) {
if (mipmapRepeatY) {
fb->codeAppendf("extraRepeatCoordY = clamp(extraRepeatCoordY, %s.y, %s.w);", clampName,
clampName);
}
// Do the 2 or 4 texture reads for kRepeatMipMap and then apply the weight(s)
// to blend between them. If neither direction is kRepeatMipMap do a single
// to blend between them. If neither direction is repeat or not using mip maps do a single
// read at clampedCoord.
if (m[0] == ShaderMode::kRepeatMipMap && m[1] == ShaderMode::kRepeatMipMap) {
if (mipmapRepeatX && mipmapRepeatY) {
fb->codeAppendf(
"half4 textureColor ="
" mix(mix(%s, %s, repeatCoordWeightX),"
@ -581,11 +601,11 @@ void GrTextureEffect::Impl::emitCode(EmitArgs& args) {
read("float2(clampedCoord.x, extraRepeatCoordY)").c_str(),
read("float2(extraRepeatCoordX, extraRepeatCoordY)").c_str());
} else if (m[0] == ShaderMode::kRepeatMipMap) {
} else if (mipmapRepeatX) {
fb->codeAppendf("half4 textureColor = mix(%s, %s, repeatCoordWeightX);",
read("clampedCoord").c_str(),
read("float2(extraRepeatCoordX, clampedCoord.y)").c_str());
} else if (m[1] == ShaderMode::kRepeatMipMap) {
} else if (mipmapRepeatY) {
fb->codeAppendf("half4 textureColor = mix(%s, %s, repeatCoordWeightY);",
read("clampedCoord").c_str(),
read("float2(clampedCoord.x, extraRepeatCoordY)").c_str());
@ -599,30 +619,33 @@ void GrTextureEffect::Impl::emitCode(EmitArgs& args) {
// Calculate the amount the coord moved for clamping. This will be used
// to implement shader-based filtering for kClampToBorder and kRepeat.
if (m[0] == ShaderMode::kRepeatLinear || m[0] == ShaderMode::kClampToBorderFilter) {
bool repeatLinearFilterX = m[0] == ShaderMode::kRepeat_Linear_None ||
m[0] == ShaderMode::kRepeat_Linear_Mipmap;
bool repeatLinearFilterY = m[1] == ShaderMode::kRepeat_Linear_None ||
m[1] == ShaderMode::kRepeat_Linear_Mipmap;
if (repeatLinearFilterX || m[0] == ShaderMode::kClampToBorder_Filter) {
fb->codeAppend("half errX = half(subsetCoord.x - clampedCoord.x);");
if (m[0] == ShaderMode::kRepeatLinear) {
if (repeatLinearFilterX) {
fb->codeAppendf("float repeatCoordX = errX > 0 ? %s.x : %s.z;",
clampName, clampName);
repeatLinearReadX = read("float2(repeatCoordX, clampedCoord.y)");
}
}
if (m[1] == ShaderMode::kRepeatLinear || m[1] == ShaderMode::kClampToBorderFilter) {
if (repeatLinearFilterY || m[1] == ShaderMode::kClampToBorder_Filter) {
fb->codeAppend("half errY = half(subsetCoord.y - clampedCoord.y);");
if (m[1] == ShaderMode::kRepeatLinear) {
if (repeatLinearFilterY) {
fb->codeAppendf("float repeatCoordY = errY > 0 ? %s.y : %s.w;",
clampName, clampName);
repeatLinearReadY = read("float2(clampedCoord.x, repeatCoordY)");
}
}
// Add logic for kRepeatLinear. Do 1 or 3 more texture reads depending
// Add logic for kRepeat + linear filter. Do 1 or 3 more texture reads depending
// on whether both modes are kRepeat and whether we're near a single subset edge
// or a corner. Then blend the multiple reads using the err values calculated
// above.
const char* ifStr = "if";
if (m[0] == ShaderMode::kRepeatLinear && m[1] == ShaderMode::kRepeatLinear) {
if (repeatLinearFilterX && repeatLinearFilterY) {
auto repeatLinearReadXY = read("float2(repeatCoordX, repeatCoordY)");
fb->codeAppendf(
"if (errX != 0 && errY != 0) {"
@ -635,14 +658,14 @@ void GrTextureEffect::Impl::emitCode(EmitArgs& args) {
repeatLinearReadXY.c_str());
ifStr = "else if";
}
if (m[0] == ShaderMode::kRepeatLinear) {
if (repeatLinearFilterX) {
fb->codeAppendf(
"%s (errX != 0) {"
" textureColor = mix(textureColor, %s, abs(errX));"
"}",
ifStr, repeatLinearReadX.c_str());
}
if (m[1] == ShaderMode::kRepeatLinear) {
if (repeatLinearFilterY) {
fb->codeAppendf(
"%s (errY != 0) {"
" textureColor = mix(textureColor, %s, abs(errY));"
@ -652,17 +675,17 @@ void GrTextureEffect::Impl::emitCode(EmitArgs& args) {
// Do soft edge shader filtering against border color for kClampToBorderFilter using
// the err values calculated above.
if (m[0] == ShaderMode::kClampToBorderFilter) {
if (m[0] == ShaderMode::kClampToBorder_Filter) {
fb->codeAppendf("textureColor = mix(textureColor, %s, min(abs(errX), 1));", borderName);
}
if (m[1] == ShaderMode::kClampToBorderFilter) {
if (m[1] == ShaderMode::kClampToBorder_Filter) {
fb->codeAppendf("textureColor = mix(textureColor, %s, min(abs(errY), 1));", borderName);
}
// Do hard-edge shader transition to border color for kClampToBorderNearest at the
// subset boundaries. Snap the input coordinates to nearest neighbor (with an
// epsilon) before comparing to the subset rect to avoid GPU interpolation errors
if (m[0] == ShaderMode::kClampToBorderNearest) {
if (m[0] == ShaderMode::kClampToBorder_Nearest) {
fb->codeAppendf(
"float snappedX = floor(inCoord.x + 0.001) + 0.5;"
"if (snappedX < %s.x || snappedX > %s.z) {"
@ -670,7 +693,7 @@ void GrTextureEffect::Impl::emitCode(EmitArgs& args) {
"}",
subsetName, subsetName, borderName);
}
if (m[1] == ShaderMode::kClampToBorderNearest) {
if (m[1] == ShaderMode::kClampToBorder_Nearest) {
fb->codeAppendf(
"float snappedY = floor(inCoord.y + 0.001) + 0.5;"
"if (snappedY < %s.y || snappedY > %s.w) {"
@ -796,26 +819,15 @@ GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrTextureEffect);
#if GR_TEST_UTILS
std::unique_ptr<GrFragmentProcessor> GrTextureEffect::TestCreate(GrProcessorTestData* testData) {
auto [view, ct, at] = testData->randomView();
Mode wrapModes[2];
Wrap wrapModes[2];
GrTest::TestWrapModes(testData->fRandom, wrapModes);
Filter filter;
Filter filter = testData->fRandom->nextBool() ? Filter::kLinear : Filter::kNearest;
MipmapMode mm = MipmapMode::kNone;
if (view.asTextureProxy()->mipmapped() == GrMipmapped::kYes) {
switch (testData->fRandom->nextULessThan(3)) {
case 0:
filter = Filter::kNearest;
break;
case 1:
filter = Filter::kLinear;
break;
default:
filter = Filter::kMipMap;
break;
}
} else {
filter = testData->fRandom->nextBool() ? Filter::kLinear : Filter::kNearest;
mm = testData->fRandom->nextBool() ? MipmapMode::kLinear : MipmapMode::kNone;
}
GrSamplerState params(wrapModes, filter);
GrSamplerState params(wrapModes, filter, mm);
const SkMatrix& matrix = GrTest::TestMatrix(testData->fRandom);
return GrTextureEffect::Make(std::move(view), at, matrix, params, *testData->caps());

View File

@ -23,7 +23,8 @@ public:
GrSurfaceProxyView,
SkAlphaType,
const SkMatrix& = SkMatrix::I(),
GrSamplerState::Filter = GrSamplerState::Filter::kNearest);
GrSamplerState::Filter = GrSamplerState::Filter::kNearest,
GrSamplerState::MipmapMode mipmapMode = GrSamplerState::MipmapMode::kNone);
/**
* Make from a full GrSamplerState. Caps are required to determine support for kClampToBorder.
@ -124,16 +125,19 @@ private:
* filter.
*/
enum class ShaderMode : uint16_t {
kNone, // Using HW mode
kClamp, // Shader based clamp, no filter specialization
kRepeatNearest, // Simple repeat for nearest sampling
kRepeatLinear, // Filter across the subset boundary for kRepeat mode
kRepeatMipMap, // Logic for LOD selection with kRepeat mode.
kMirrorRepeat, // Mirror repeat (doesn't depend on filter))
kClampToBorderNearest, // Logic for hard transition to border color when not filtering.
kClampToBorderFilter, // Logic for fading to border color when filtering.
kNone, // Using HW mode
kClamp, // Shader based clamp, no filter specialization
kRepeat_Nearest_None, // Simple repeat for nearest sampling, no mipmapping
kRepeat_Linear_None, // Filter the subset boundary for kRepeat mode, no mip mapping
kRepeat_Linear_Mipmap, // Logic for linear filtering and LOD selection with kRepeat mode.
kRepeat_Nearest_Mipmap, // Logic for nearest filtering and LOD selection with kRepeat mode.
kMirrorRepeat, // Mirror repeat (doesn't depend on filter))
kClampToBorder_Nearest, // Logic for hard transition to border color when not filtering.
kClampToBorder_Filter, // Logic for fading to border color when filtering.
};
static ShaderMode GetShaderMode(GrSamplerState::WrapMode, GrSamplerState::Filter);
static ShaderMode GetShaderMode(GrSamplerState::WrapMode,
GrSamplerState::Filter,
GrSamplerState::MipmapMode);
static bool ShaderModeIsClampToBorder(ShaderMode);
GrSurfaceProxyView fView;

View File

@ -116,7 +116,7 @@ std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(GrSurfaceProxyView v
}
}
if (subset) {
SkASSERT(samplerState.filter() != GrSamplerState::Filter::kMipMap);
SkASSERT(samplerState.mipmapped() == GrMipmapped::kNo);
if (makeLinearWithSnap) {
// The plane is subsampled and we have an overall subset on the image. We're
// emulating do_fancy_upsampling using linear filtering but snapping look ups to the
@ -137,7 +137,6 @@ std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(GrSurfaceProxyView v
*planeMatrix, samplerState, planeSubset,
planeDomain, caps, planeBorders[i]);
} else {
SkASSERT(samplerState.filter() != GrSamplerState::Filter::kMipMap);
planeFPs[i] = GrTextureEffect::MakeSubset(views[i], kUnknown_SkAlphaType,
*planeMatrix, samplerState, planeSubset,
caps, planeBorders[i]);

View File

@ -178,18 +178,23 @@ static GrGLenum filter_to_gl_mag_filter(GrSamplerState::Filter filter) {
switch (filter) {
case GrSamplerState::Filter::kNearest: return GR_GL_NEAREST;
case GrSamplerState::Filter::kLinear: return GR_GL_LINEAR;
case GrSamplerState::Filter::kMipMap: return GR_GL_LINEAR;
}
SK_ABORT("Unknown filter");
SkUNREACHABLE;
}
static GrGLenum filter_to_gl_min_filter(GrSamplerState::Filter filter) {
switch (filter) {
case GrSamplerState::Filter::kNearest: return GR_GL_NEAREST;
case GrSamplerState::Filter::kLinear: return GR_GL_LINEAR;
case GrSamplerState::Filter::kMipMap: return GR_GL_LINEAR_MIPMAP_LINEAR;
static GrGLenum filter_to_gl_min_filter(GrSamplerState::Filter filter,
GrSamplerState::MipmapMode mm) {
switch (mm) {
case GrSamplerState::MipmapMode::kNone:
return filter_to_gl_mag_filter(filter);
case GrSamplerState::MipmapMode::kLinear:
switch (filter) {
case GrSamplerState::Filter::kNearest: return GR_GL_NEAREST_MIPMAP_LINEAR;
case GrSamplerState::Filter::kLinear: return GR_GL_LINEAR_MIPMAP_LINEAR;
}
SkUNREACHABLE;
}
SK_ABORT("Unknown filter");
SkUNREACHABLE;
}
static inline GrGLenum wrap_mode_to_gl_wrap(GrSamplerState::WrapMode wrapMode,
@ -203,7 +208,7 @@ static inline GrGLenum wrap_mode_to_gl_wrap(GrSamplerState::WrapMode wrapMode,
SkASSERT(caps.clampToBorderSupport());
return GR_GL_CLAMP_TO_BORDER;
}
SK_ABORT("Unknown wrap mode");
SkUNREACHABLE;
}
///////////////////////////////////////////////////////////////////////////////
@ -240,10 +245,10 @@ public:
return;
}
fSamplers[index] = s;
auto minFilter = filter_to_gl_min_filter(state.filter());
auto magFilter = filter_to_gl_mag_filter(state.filter());
auto wrapX = wrap_mode_to_gl_wrap(state.wrapModeX(), fGpu->glCaps());
auto wrapY = wrap_mode_to_gl_wrap(state.wrapModeY(), fGpu->glCaps());
GrGLenum minFilter = filter_to_gl_min_filter(state.filter(), state.mipmapMode());
GrGLenum magFilter = filter_to_gl_mag_filter(state.filter());
GrGLenum wrapX = wrap_mode_to_gl_wrap(state.wrapModeX(), fGpu->glCaps());
GrGLenum wrapY = wrap_mode_to_gl_wrap(state.wrapModeY(), fGpu->glCaps());
GR_GL_CALL(fGpu->glInterface(),
SamplerParameteri(s, GR_GL_TEXTURE_MIN_FILTER, minFilter));
GR_GL_CALL(fGpu->glInterface(),
@ -2574,37 +2579,32 @@ void GrGLGpu::bindTexture(int unitIdx, GrSamplerState samplerState, const GrSwiz
fHWTextureUnitBindings[unitIdx].setBoundID(target, textureID);
}
if (samplerState.filter() == GrSamplerState::Filter::kMipMap) {
if (samplerState.mipmapped() == GrMipmapped::kYes) {
if (!this->caps()->mipmapSupport() ||
texture->texturePriv().mipmapped() == GrMipmapped::kNo) {
samplerState.setFilterMode(GrSamplerState::Filter::kLinear);
samplerState.setMipmapMode(GrSamplerState::MipmapMode::kNone);
} else {
SkASSERT(!texture->texturePriv().mipmapsAreDirty());
}
}
#ifdef SK_DEBUG
// We were supposed to ensure MipMaps were up-to-date before getting here.
if (samplerState.filter() == GrSamplerState::Filter::kMipMap) {
SkASSERT(!texture->texturePriv().mipmapsAreDirty());
}
#endif
auto timestamp = texture->parameters()->resetTimestamp();
bool setAll = timestamp < fResetTimestampForTextureParameters;
const GrGLTextureParameters::SamplerOverriddenState* samplerStateToRecord = nullptr;
GrGLTextureParameters::SamplerOverriddenState newSamplerState;
if (fSamplerObjectCache) {
fSamplerObjectCache->bindSampler(unitIdx, samplerState);
if (this->glCaps().mustSetTexParameterMinFilterToEnableMipmapping()) {
if (samplerState.filter() == GrSamplerState::Filter::kMipMap) {
if (samplerState.mipmapped() == GrMipmapped::kYes) {
GrGLenum minFilter = filter_to_gl_min_filter(samplerState.filter(),
samplerState.mipmapMode());
const GrGLTextureParameters::SamplerOverriddenState& oldSamplerState =
texture->parameters()->samplerOverriddenState();
if (setAll || oldSamplerState.fMinFilter != GR_GL_LINEAR_MIPMAP_LINEAR) {
if (setAll || oldSamplerState.fMinFilter != minFilter) {
this->setTextureUnit(unitIdx);
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MIN_FILTER,
GR_GL_LINEAR_MIPMAP_LINEAR));
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MIN_FILTER, minFilter));
newSamplerState = oldSamplerState;
newSamplerState.fMinFilter = GR_GL_LINEAR_MIPMAP_LINEAR;
newSamplerState.fMinFilter = minFilter;
samplerStateToRecord = &newSamplerState;
}
}
@ -2614,7 +2614,8 @@ void GrGLGpu::bindTexture(int unitIdx, GrSamplerState samplerState, const GrSwiz
texture->parameters()->samplerOverriddenState();
samplerStateToRecord = &newSamplerState;
newSamplerState.fMinFilter = filter_to_gl_min_filter(samplerState.filter());
newSamplerState.fMinFilter = filter_to_gl_min_filter(samplerState.filter(),
samplerState.mipmapMode());
newSamplerState.fMagFilter = filter_to_gl_mag_filter(samplerState.filter());
newSamplerState.fWrapS = wrap_mode_to_gl_wrap(samplerState.wrapModeX(), this->glCaps());

View File

@ -41,15 +41,21 @@ static inline MTLSamplerAddressMode wrap_mode_to_mtl_sampler_address(
}
GrMtlSampler* GrMtlSampler::Create(const GrMtlGpu* gpu, GrSamplerState samplerState) {
static MTLSamplerMinMagFilter mtlMinMagFilterModes[] = {
MTLSamplerMinMagFilterNearest,
MTLSamplerMinMagFilterLinear,
MTLSamplerMinMagFilterLinear
};
MTLSamplerMinMagFilter minMagFilter = [&] {
switch (samplerState.filter()) {
case GrSamplerState::Filter::kNearest: return MTLSamplerMinMagFilterNearest;
case GrSamplerState::Filter::kLinear: return MTLSamplerMinMagFilterLinear;
}
SkUNREACHABLE;
}();
static_assert((int)GrSamplerState::Filter::kNearest == 0);
static_assert((int)GrSamplerState::Filter::kLinear == 1);
static_assert((int)GrSamplerState::Filter::kMipMap == 2);
MTLSamplerMipFilter mipFilter = [&] {
switch (samplerState.mipmapMode()) {
case GrSamplerState::MipmapMode::kNone: return MTLSamplerMipFilterNotMipmapped;
case GrSamplerState::MipmapMode::kLinear: return MTLSamplerMipFilterLinear;
}
SkUNREACHABLE;
}();
auto samplerDesc = [[MTLSamplerDescriptor alloc] init];
samplerDesc.rAddressMode = MTLSamplerAddressModeClampToEdge;
@ -57,12 +63,11 @@ GrMtlSampler* GrMtlSampler::Create(const GrMtlGpu* gpu, GrSamplerState samplerSt
gpu->mtlCaps());
samplerDesc.tAddressMode = wrap_mode_to_mtl_sampler_address(samplerState.wrapModeY(),
gpu->mtlCaps());
samplerDesc.magFilter = mtlMinMagFilterModes[static_cast<int>(samplerState.filter())];
samplerDesc.minFilter = mtlMinMagFilterModes[static_cast<int>(samplerState.filter())];
samplerDesc.mipFilter = MTLSamplerMipFilterLinear;
samplerDesc.magFilter = minMagFilter;
samplerDesc.minFilter = minMagFilter;
samplerDesc.mipFilter = mipFilter;
samplerDesc.lodMinClamp = 0.0f;
bool useMipMaps = GrSamplerState::Filter::kMipMap == samplerState.filter();
samplerDesc.lodMaxClamp = !useMipMaps ? 0.0f : 10000.0f;
samplerDesc.lodMaxClamp = FLT_MAX; // default value according to docs.
samplerDesc.maxAnisotropy = 1.0f;
samplerDesc.normalizedCoordinates = true;
if (@available(macOS 10.11, iOS 9.0, *)) {

View File

@ -165,8 +165,7 @@ public:
const char* name() const override { return "NonAALatticeOp"; }
void visitProxies(const VisitProxyFunc& func) const override {
bool mipped = (GrSamplerState::Filter::kMipMap == fFilter);
func(fView.proxy(), GrMipmapped(mipped));
func(fView.proxy(), GrMipmapped::kNo);
if (fProgramInfo) {
fProgramInfo->visitFPProxies(func);
} else {

View File

@ -58,11 +58,13 @@ static SkSize axis_aligned_quad_size(const GrQuad& quad) {
return {dw, dh};
}
static bool filter_has_effect(const GrQuad& srcQuad, const GrQuad& dstQuad) {
static std::tuple<bool /* filter */,
bool /* mipmap */>
filter_and_mm_have_effect(const GrQuad& srcQuad, const GrQuad& dstQuad) {
// If not axis-aligned in src or dst, then always say it has an effect
if (srcQuad.quadType() != GrQuad::Type::kAxisAligned ||
dstQuad.quadType() != GrQuad::Type::kAxisAligned) {
return true;
return {true, true};
}
SkRect srcRect;
@ -72,24 +74,26 @@ static bool filter_has_effect(const GrQuad& srcQuad, const GrQuad& dstQuad) {
// top-left corners have the same fraction (so src and dst snap to the pixel grid
// identically).
SkASSERT(srcRect.isSorted());
return srcRect.width() != dstRect.width() || srcRect.height() != dstRect.height() ||
SkScalarFraction(srcRect.fLeft) != SkScalarFraction(dstRect.fLeft) ||
SkScalarFraction(srcRect.fTop) != SkScalarFraction(dstRect.fTop);
} else {
// Although the quads are axis-aligned, the local coordinate system is transformed such
// that fractionally-aligned sample centers will not align with the device coordinate system
// So disable filtering when edges are the same length and both srcQuad and dstQuad
// 0th vertex is integer aligned.
if (SkScalarIsInt(srcQuad.x(0)) && SkScalarIsInt(srcQuad.y(0)) &&
SkScalarIsInt(dstQuad.x(0)) && SkScalarIsInt(dstQuad.y(0))) {
// Extract edge lengths
SkSize srcSize = axis_aligned_quad_size(srcQuad);
SkSize dstSize = axis_aligned_quad_size(dstQuad);
return srcSize.fWidth != dstSize.fWidth || srcSize.fHeight != dstSize.fHeight;
} else {
return true;
}
bool filter = srcRect.width() != dstRect.width() || srcRect.height() != dstRect.height() ||
SkScalarFraction(srcRect.fLeft) != SkScalarFraction(dstRect.fLeft) ||
SkScalarFraction(srcRect.fTop) != SkScalarFraction(dstRect.fTop);
bool mm = srcRect.width() > dstRect.width() || srcRect.height() > dstRect.height();
return {filter, mm};
}
// Extract edge lengths
SkSize srcSize = axis_aligned_quad_size(srcQuad);
SkSize dstSize = axis_aligned_quad_size(dstQuad);
// Although the quads are axis-aligned, the local coordinate system is transformed such
// that fractionally-aligned sample centers will not align with the device coordinate system
// So disable filtering when edges are the same length and both srcQuad and dstQuad
// 0th vertex is integer aligned.
bool filter = srcSize != dstSize ||
!SkScalarIsInt(srcQuad.x(0)) ||
!SkScalarIsInt(srcQuad.y(0)) ||
!SkScalarIsInt(dstQuad.x(0)) ||
!SkScalarIsInt(dstQuad.y(0));
bool mm = srcSize.fWidth > dstSize.fWidth || srcSize.fHeight > dstSize.fHeight;
return {filter, mm};
}
// Describes function for normalizing src coords: [x * iw, y * ih + yOffset] can represent
@ -222,13 +226,14 @@ public:
GrSurfaceProxyView proxyView,
sk_sp<GrColorSpaceXform> textureXform,
GrSamplerState::Filter filter,
GrSamplerState::MipmapMode mm,
const SkPMColor4f& color,
GrTextureOp::Saturate saturate,
GrAAType aaType,
DrawQuad* quad,
const SkRect* subset) {
GrOpMemoryPool* pool = context->priv().opMemoryPool();
return pool->allocate<TextureOp>(std::move(proxyView), std::move(textureXform), filter,
return pool->allocate<TextureOp>(std::move(proxyView), std::move(textureXform), filter, mm,
color, saturate, aaType, quad, subset);
}
@ -237,6 +242,7 @@ public:
int cnt,
int proxyRunCnt,
GrSamplerState::Filter filter,
GrSamplerState::MipmapMode mm,
GrTextureOp::Saturate saturate,
GrAAType aaType,
SkCanvas::SrcRectConstraint constraint,
@ -249,7 +255,7 @@ public:
GrOpMemoryPool* pool = context->priv().opMemoryPool();
void* mem = pool->allocate(size);
return std::unique_ptr<GrDrawOp>(
new (mem) TextureOp(set, cnt, proxyRunCnt, filter, saturate, aaType, constraint,
new (mem) TextureOp(set, cnt, proxyRunCnt, filter, mm, saturate, aaType, constraint,
viewMatrix, std::move(textureColorSpaceXform)));
}
@ -262,7 +268,7 @@ public:
const char* name() const override { return "TextureOp"; }
void visitProxies(const VisitProxyFunc& func) const override {
bool mipped = (GrSamplerState::Filter::kMipMap == fMetadata.filter());
bool mipped = (fMetadata.mipmapMode() != GrSamplerState::MipmapMode::kNone);
for (unsigned p = 0; p < fMetadata.fProxyCount; ++p) {
func(fViewCountPairs[p].fProxy.get(), GrMipmapped(mipped));
}
@ -277,9 +283,10 @@ public:
str.appendf("# draws: %d\n", fQuads.count());
auto iter = fQuads.iterator();
for (unsigned p = 0; p < fMetadata.fProxyCount; ++p) {
str.appendf("Proxy ID: %d, Filter: %d\n",
str.appendf("Proxy ID: %d, Filter: %d, MM: %d\n",
fViewCountPairs[p].fProxy->uniqueID().asUInt(),
static_cast<int>(fMetadata.fFilter));
static_cast<int>(fMetadata.fFilter),
static_cast<int>(fMetadata.fMipmapMode));
int i = 0;
while(i < fViewCountPairs[p].fQuadCnt && iter.next()) {
const GrQuad* quad = iter.deviceQuad();
@ -368,12 +375,16 @@ private:
// performance (since texture ops are one of the most commonly used in an app).
struct Metadata {
// AAType must be filled after initialization; ColorType is determined in finalize()
Metadata(const GrSwizzle& swizzle, GrSamplerState::Filter filter,
GrQuadPerEdgeAA::Subset subset, GrTextureOp::Saturate saturate)
Metadata(const GrSwizzle& swizzle,
GrSamplerState::Filter filter,
GrSamplerState::MipmapMode mm,
GrQuadPerEdgeAA::Subset subset,
GrTextureOp::Saturate saturate)
: fSwizzle(swizzle)
, fProxyCount(1)
, fTotalQuadCount(1)
, fFilter(static_cast<uint16_t>(filter))
, fMipmapMode(static_cast<uint16_t>(mm))
, fAAType(static_cast<uint16_t>(GrAAType::kNone))
, fColorType(static_cast<uint16_t>(ColorType::kNone))
, fSubset(static_cast<uint16_t>(subset))
@ -386,15 +397,19 @@ private:
// These must be based on uint16_t to help MSVC's pack bitfields optimally
uint16_t fFilter : 2; // GrSamplerState::Filter
uint16_t fMipmapMode : 2; // GrSamplerState::MipmapMode
uint16_t fAAType : 2; // GrAAType
uint16_t fColorType : 2; // GrQuadPerEdgeAA::ColorType
uint16_t fSubset : 1; // bool
uint16_t fSaturate : 1; // bool
uint16_t fUnused : 8; // # of bits left before Metadata exceeds 8 bytes
uint16_t fUnused : 6; // # of bits left before Metadata exceeds 8 bytes
GrSamplerState::Filter filter() const {
return static_cast<GrSamplerState::Filter>(fFilter);
}
GrSamplerState::MipmapMode mipmapMode() const {
return static_cast<GrSamplerState::MipmapMode>(fMipmapMode);
}
GrAAType aaType() const { return static_cast<GrAAType>(fAAType); }
ColorType colorType() const { return static_cast<ColorType>(fColorType); }
Subset subset() const { return static_cast<Subset>(fSubset); }
@ -449,6 +464,7 @@ private:
TextureOp(GrSurfaceProxyView proxyView,
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
GrSamplerState::Filter filter,
GrSamplerState::MipmapMode mm,
const SkPMColor4f& color,
GrTextureOp::Saturate saturate,
GrAAType aaType,
@ -458,8 +474,7 @@ private:
, fQuads(1, true /* includes locals */)
, fTextureColorSpaceXform(std::move(textureColorSpaceXform))
, fDesc(nullptr)
, fMetadata(proxyView.swizzle(), filter, Subset(!!subsetRect), saturate) {
, fMetadata(proxyView.swizzle(), filter, mm, Subset(!!subsetRect), saturate) {
// Clean up disparities between the overall aa type and edge configuration and apply
// optimizations based on the rect and matrix when appropriate
GrQuadUtils::ResolveAAType(aaType, quad->fEdgeFlags, quad->fDevice,
@ -498,6 +513,7 @@ private:
int cnt,
int proxyRunCnt,
GrSamplerState::Filter filter,
GrSamplerState::MipmapMode mm,
GrTextureOp::Saturate saturate,
GrAAType aaType,
SkCanvas::SrcRectConstraint constraint,
@ -507,8 +523,11 @@ private:
, fQuads(cnt, true /* includes locals */)
, fTextureColorSpaceXform(std::move(textureColorSpaceXform))
, fDesc(nullptr)
, fMetadata(set[0].fProxyView.swizzle(), GrSamplerState::Filter::kNearest,
Subset::kNo, saturate) {
, fMetadata(set[0].fProxyView.swizzle(),
GrSamplerState::Filter::kNearest,
GrSamplerState::MipmapMode::kNone,
Subset::kNo,
saturate) {
// Update counts to reflect the batch op
fMetadata.fProxyCount = SkToUInt(proxyRunCnt);
fMetadata.fTotalQuadCount = SkToUInt(cnt);
@ -518,6 +537,7 @@ private:
GrAAType netAAType = GrAAType::kNone; // aa type maximally compatible with all dst rects
Subset netSubset = Subset::kNo;
GrSamplerState::Filter netFilter = GrSamplerState::Filter::kNearest;
GrSamplerState::MipmapMode netMM = GrSamplerState::MipmapMode::kNone;
const GrSurfaceProxy* curProxy = nullptr;
@ -525,6 +545,9 @@ private:
// increases when set[q]'s proxy changes.
int p = 0;
for (int q = 0; q < cnt; ++q) {
SkASSERT(mm == GrSamplerState::MipmapMode::kNone ||
(set[0].fProxyView.proxy()->asTextureProxy()->mipmapped() ==
GrMipmapped::kYes));
if (q == 0) {
// We do not placement new the first ViewCountPair since that one is allocated and
// initialized as part of the GrTextureOp creation.
@ -561,13 +584,19 @@ private:
quad.fLocal = GrQuad(set[q].fSrcRect);
}
if (netFilter != filter && filter_has_effect(quad.fLocal, quad.fDevice)) {
// The only way netFilter != filter is if linear filtering is requested and we
// haven't yet found a quad that requires linear filtering (so net is still
// nearest).
SkASSERT(netFilter == GrSamplerState::Filter::kNearest &&
filter == GrSamplerState::Filter::kLinear);
netFilter = GrSamplerState::Filter::kLinear;
if (netFilter != filter || netMM != mm) {
// The only way netFilter != filter is if linear is requested and we haven't yet
// found a quad that requires linear (so net is still nearest). Similar for mip
// mapping.
SkASSERT(netFilter <= filter);
SkASSERT(netMM <= mm);
auto [mustFilter, mustMM] = filter_and_mm_have_effect(quad.fLocal, quad.fDevice);
if (mustFilter && filter != GrSamplerState::Filter::kNearest) {
netFilter = GrSamplerState::Filter::kLinear;
}
if (mustMM && mm != GrSamplerState::MipmapMode::kNone) {
netMM = GrSamplerState::MipmapMode::kLinear;
}
}
// Update overall bounds of the op as the union of all quads
@ -970,6 +999,9 @@ private:
if (fMetadata.filter() != that->fMetadata.filter()) {
return CombineResult::kCannotCombine;
}
if (fMetadata.mipmapMode() != that->fMetadata.mipmapMode()) {
return CombineResult::kCannotCombine;
}
if (fMetadata.fSwizzle != that->fMetadata.fSwizzle) {
return CombineResult::kCannotCombine;
}
@ -1028,6 +1060,7 @@ std::unique_ptr<GrDrawOp> GrTextureOp::Make(GrRecordingContext* context,
SkAlphaType alphaType,
sk_sp<GrColorSpaceXform> textureXform,
GrSamplerState::Filter filter,
GrSamplerState::MipmapMode mm,
const SkPMColor4f& color,
Saturate saturate,
SkBlendMode blendMode,
@ -1040,13 +1073,18 @@ std::unique_ptr<GrDrawOp> GrTextureOp::Make(GrRecordingContext* context,
subset = nullptr;
}
if (filter != GrSamplerState::Filter::kNearest &&
!filter_has_effect(quad->fLocal, quad->fDevice)) {
filter = GrSamplerState::Filter::kNearest;
if (filter != GrSamplerState::Filter::kNearest || mm != GrSamplerState::MipmapMode::kNone) {
auto [mustFilter, mustMM] = filter_and_mm_have_effect(quad->fLocal, quad->fDevice);
if (!mustFilter) {
filter = GrSamplerState::Filter::kNearest;
}
if (!mustMM) {
mm = GrSamplerState::MipmapMode::kNone;
}
}
if (blendMode == SkBlendMode::kSrcOver) {
return TextureOp::Make(context, std::move(proxyView), std::move(textureXform), filter,
return TextureOp::Make(context, std::move(proxyView), std::move(textureXform), filter, mm,
color, saturate, aaType, std::move(quad), subset);
} else {
// Emulate complex blending using GrFillRectOp
@ -1086,6 +1124,7 @@ public:
GrRecordingContext* context,
int numEntries,
GrSamplerState::Filter filter,
GrSamplerState::MipmapMode mm,
GrTextureOp::Saturate saturate,
SkCanvas::SrcRectConstraint constraint,
const SkMatrix& viewMatrix,
@ -1094,20 +1133,27 @@ public:
, fClip(clip)
, fContext(context)
, fFilter(filter)
, fMipmapMode(mm)
, fSaturate(saturate)
, fConstraint(constraint)
, fViewMatrix(viewMatrix)
, fTextureColorSpaceXform(textureColorSpaceXform)
, fNumLeft(numEntries) {
}
, fNumLeft(numEntries) {}
void createOp(GrRenderTargetContext::TextureSetEntry set[],
int clumpSize,
GrAAType aaType) {
int clumpProxyCount = proxy_run_count(&set[fNumClumped], clumpSize);
std::unique_ptr<GrDrawOp> op = TextureOp::Make(fContext, &set[fNumClumped], clumpSize,
clumpProxyCount, fFilter, fSaturate, aaType,
fConstraint, fViewMatrix,
std::unique_ptr<GrDrawOp> op = TextureOp::Make(fContext,
&set[fNumClumped],
clumpSize,
clumpProxyCount,
fFilter,
fMipmapMode,
fSaturate,
aaType,
fConstraint,
fViewMatrix,
fTextureColorSpaceXform);
fRTC->addDrawOp(fClip, std::move(op));
@ -1123,6 +1169,7 @@ private:
const GrClip* fClip;
GrRecordingContext* fContext;
GrSamplerState::Filter fFilter;
GrSamplerState::MipmapMode fMipmapMode;
GrTextureOp::Saturate fSaturate;
SkCanvas::SrcRectConstraint fConstraint;
const SkMatrix& fViewMatrix;
@ -1140,6 +1187,7 @@ void GrTextureOp::AddTextureSetOps(GrRenderTargetContext* rtc,
int cnt,
int proxyRunCnt,
GrSamplerState::Filter filter,
GrSamplerState::MipmapMode mm,
Saturate saturate,
SkBlendMode blendMode,
GrAAType aaType,
@ -1181,8 +1229,7 @@ void GrTextureOp::AddTextureSetOps(GrRenderTargetContext* rtc,
? &set[i].fSrcRect : nullptr;
auto op = Make(context, set[i].fProxyView, set[i].fSrcAlphaType, textureColorSpaceXform,
filter, set[i].fColor, saturate, blendMode, aaType,
&quad, subset);
filter, mm, set[i].fColor, saturate, blendMode, aaType, &quad, subset);
rtc->addDrawOp(clip, std::move(op));
}
return;
@ -1192,13 +1239,13 @@ void GrTextureOp::AddTextureSetOps(GrRenderTargetContext* rtc,
// needed to clump things together.
if (cnt <= std::min(GrResourceProvider::MaxNumNonAAQuads(),
GrResourceProvider::MaxNumAAQuads())) {
auto op = TextureOp::Make(context, set, cnt, proxyRunCnt, filter, saturate, aaType,
auto op = TextureOp::Make(context, set, cnt, proxyRunCnt, filter, mm, saturate, aaType,
constraint, viewMatrix, std::move(textureColorSpaceXform));
rtc->addDrawOp(clip, std::move(op));
return;
}
BatchSizeLimiter state(rtc, clip, context, cnt, filter, saturate, constraint, viewMatrix,
BatchSizeLimiter state(rtc, clip, context, cnt, filter, mm, saturate, constraint, viewMatrix,
std::move(textureColorSpaceXform));
// kNone and kMSAA never get altered
@ -1292,11 +1339,13 @@ GR_DRAW_OP_TEST_DEFINE(TextureOp) {
SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random);
SkPMColor4f color = SkPMColor4f::FromBytes_RGBA(SkColorToPremulGrColor(random->nextU()));
GrSamplerState::Filter filter = (GrSamplerState::Filter)random->nextULessThan(
static_cast<uint32_t>(GrSamplerState::Filter::kMipMap) + 1);
while (mipMapped == GrMipmapped::kNo && filter == GrSamplerState::Filter::kMipMap) {
filter = (GrSamplerState::Filter)random->nextULessThan(
static_cast<uint32_t>(GrSamplerState::Filter::kMipMap) + 1);
static_cast<uint32_t>(GrSamplerState::Filter::kLast) + 1);
GrSamplerState::MipmapMode mm = GrSamplerState::MipmapMode::kNone;
if (mipMapped == GrMipmapped::kYes) {
mm = (GrSamplerState::MipmapMode)random->nextULessThan(
static_cast<uint32_t>(GrSamplerState::MipmapMode::kLast) + 1);
}
auto texXform = GrTest::TestColorXform(random);
GrAAType aaType = GrAAType::kNone;
if (random->nextBool()) {
@ -1317,8 +1366,8 @@ GR_DRAW_OP_TEST_DEFINE(TextureOp) {
DrawQuad quad = {GrQuad::MakeFromRect(rect, viewMatrix), GrQuad(srcRect), aaFlags};
return GrTextureOp::Make(context, std::move(proxyView), alphaType, std::move(texXform), filter,
color, saturate, SkBlendMode::kSrcOver, aaType,
&quad, useSubset ? &srcRect : nullptr);
mm, color, saturate, SkBlendMode::kSrcOver, aaType, &quad,
useSubset ? &srcRect : nullptr);
}
#endif

View File

@ -45,6 +45,7 @@ public:
SkAlphaType srcAlphaType,
sk_sp<GrColorSpaceXform>,
GrSamplerState::Filter,
GrSamplerState::MipmapMode,
const SkPMColor4f&,
Saturate,
SkBlendMode,
@ -62,6 +63,7 @@ public:
int cnt,
int proxyRunCnt,
GrSamplerState::Filter,
GrSamplerState::MipmapMode,
Saturate,
SkBlendMode,
GrAAType,

View File

@ -10,8 +10,7 @@
#include "src/gpu/vk/GrVkGpu.h"
#include "src/gpu/vk/GrVkSamplerYcbcrConversion.h"
static inline VkSamplerAddressMode wrap_mode_to_vk_sampler_address(
GrSamplerState::WrapMode wrapMode) {
static VkSamplerAddressMode wrap_mode_to_vk_sampler_address(GrSamplerState::WrapMode wrapMode) {
switch (wrapMode) {
case GrSamplerState::WrapMode::kClamp:
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
@ -22,7 +21,16 @@ static inline VkSamplerAddressMode wrap_mode_to_vk_sampler_address(
case GrSamplerState::WrapMode::kClampToBorder:
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
}
SK_ABORT("Unknown wrap mode.");
SkUNREACHABLE;
}
static VkSamplerMipmapMode mipmap_mode_to_vk_sampler_mipmap_mode(GrSamplerState::MipmapMode mm) {
switch (mm) {
// There is no disable mode. We use max level to disable mip mapping.
case GrSamplerState::MipmapMode::kNone: return VK_SAMPLER_MIPMAP_MODE_NEAREST;
case GrSamplerState::MipmapMode::kLinear: return VK_SAMPLER_MIPMAP_MODE_LINEAR;
}
SkUNREACHABLE;
}
GrVkSampler* GrVkSampler::Create(GrVkGpu* gpu, GrSamplerState samplerState,
@ -45,7 +53,7 @@ GrVkSampler* GrVkSampler::Create(GrVkGpu* gpu, GrSamplerState samplerState,
createInfo.flags = 0;
createInfo.magFilter = vkMagFilterModes[static_cast<int>(samplerState.filter())];
createInfo.minFilter = vkMinFilterModes[static_cast<int>(samplerState.filter())];
createInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
createInfo.mipmapMode = mipmap_mode_to_vk_sampler_mipmap_mode(samplerState.mipmapMode());
createInfo.addressModeU = wrap_mode_to_vk_sampler_address(samplerState.wrapModeX());
createInfo.addressModeV = wrap_mode_to_vk_sampler_address(samplerState.wrapModeY());
createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; // Shouldn't matter
@ -60,7 +68,7 @@ GrVkSampler* GrVkSampler::Create(GrVkGpu* gpu, GrSamplerState samplerState,
// level mip). If the filters weren't the same we could set min = 0 and max = 0.25 to force
// the minFilter on mip level 0.
createInfo.minLod = 0.0f;
bool useMipMaps = GrSamplerState::Filter::kMipMap == samplerState.filter();
bool useMipMaps = samplerState.mipmapped() == GrMipmapped::kYes;
createInfo.maxLod = !useMipMaps ? 0.0f : 10000.0f;
createInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
createInfo.unnormalizedCoordinates = VK_FALSE;

View File

@ -302,16 +302,17 @@ std::unique_ptr<GrFragmentProcessor> SkImageShader::asFragmentProcessor(
// below we check the matrix scale factors to determine how to interpret the filter
// quality setting. This completely ignores the complexity of the drawVertices case
// where explicit local coords are provided by the caller.
bool doBicubic;
GrSamplerState::Filter fm = GrSkFilterQualityToGrFilterMode(
fImage->width(), fImage->height(), this->resolveFiltering(args.fFilterQuality),
args.fMatrixProvider.localToDevice(), *lm,
args.fContext->priv().options().fSharpenMipmappedTextures, &doBicubic);
bool sharpen = args.fContext->priv().options().fSharpenMipmappedTextures;
auto [fm, mm, bicubic] = GrInterpretFilterQuality(fImage->dimensions(),
this->resolveFiltering(args.fFilterQuality),
args.fMatrixProvider.localToDevice(),
*lm,
sharpen);
std::unique_ptr<GrFragmentProcessor> fp;
if (doBicubic) {
if (bicubic) {
fp = producer->createBicubicFragmentProcessor(lmInverse, nullptr, nullptr, wmX, wmY);
} else {
fp = producer->createFragmentProcessor(lmInverse, nullptr, nullptr, {wmX, wmY, fm});
fp = producer->createFragmentProcessor(lmInverse, nullptr, nullptr, {wmX, wmY, fm, mm});
}
if (fp) {
fp = GrXfermodeFragmentProcessor::Make(std::move(fp), nullptr, SkBlendMode::kModulate);

View File

@ -110,14 +110,20 @@ static void bulk_texture_rect_create_test(skiatest::Reporter* reporter, GrDirect
set[i].fAAFlags = perQuadAA(i);
}
GrTextureOp::AddTextureSetOps(rtc.get(), nullptr, dContext, set, requestedTotNumQuads,
requestedTotNumQuads, // We alternate so proxyCnt == cnt
GrTextureOp::AddTextureSetOps(rtc.get(),
nullptr,
dContext,
set,
requestedTotNumQuads,
requestedTotNumQuads, // We alternate so proxyCnt == cnt
GrSamplerState::Filter::kNearest,
GrSamplerState::MipmapMode::kNone,
GrTextureOp::Saturate::kYes,
blendMode,
overallAA,
SkCanvas::kStrict_SrcRectConstraint,
SkMatrix::I(), nullptr);
SkMatrix::I(),
nullptr);
GrOpsTask* opsTask = rtc->testingOnly_PeekLastOpsTask();
int actualNumOps = opsTask->numOpChains();

View File

@ -349,19 +349,42 @@ DEF_GPUTEST_FOR_RENDERING_CONTEXTS(Gr1x1TextureMipMappedTest, reporter, ctxInfo)
// Create a new render target and draw 'mipmapView' into it using the provided 'filter'.
static std::unique_ptr<GrRenderTargetContext> draw_mipmap_into_new_render_target(
GrRecordingContext* context, GrProxyProvider* proxyProvider, GrColorType colorType,
SkAlphaType alphaType, GrSurfaceProxyView mipmapView, GrSamplerState::Filter filter) {
sk_sp<GrSurfaceProxy> renderTarget = proxyProvider->createProxy(
mipmapView.proxy()->backendFormat(), {1, 1}, GrRenderable::kYes, 1, GrMipmapped::kNo,
SkBackingFit::kApprox, SkBudgeted::kYes, GrProtected::kNo);
GrRecordingContext* context,
GrProxyProvider* proxyProvider,
GrColorType colorType,
SkAlphaType alphaType,
GrSurfaceProxyView mipmapView,
GrSamplerState::MipmapMode mm) {
sk_sp<GrSurfaceProxy> renderTarget =
proxyProvider->createProxy(mipmapView.proxy()->backendFormat(),
{1, 1},
GrRenderable::kYes,
1,
GrMipmapped::kNo,
SkBackingFit::kApprox,
SkBudgeted::kYes,
GrProtected::kNo);
auto rtc = GrRenderTargetContext::Make(
context, colorType, nullptr, std::move(renderTarget), kTopLeft_GrSurfaceOrigin,
nullptr);
auto rtc = GrRenderTargetContext::Make(context,
colorType,
nullptr,
std::move(renderTarget),
kTopLeft_GrSurfaceOrigin,
nullptr);
rtc->drawTexture(nullptr, std::move(mipmapView), alphaType, filter, SkBlendMode::kSrcOver,
{1,1,1,1}, SkRect::MakeWH(4, 4), SkRect::MakeWH(1,1), GrAA::kYes,
GrQuadAAFlags::kAll, SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(),
rtc->drawTexture(nullptr,
std::move(mipmapView),
alphaType,
GrSamplerState::Filter::kLinear,
mm,
SkBlendMode::kSrcOver,
{1, 1, 1, 1},
SkRect::MakeWH(4, 4),
SkRect::MakeWH(1, 1),
GrAA::kYes,
GrQuadAAFlags::kAll,
SkCanvas::kFast_SrcRectConstraint,
SkMatrix::I(),
nullptr);
return rtc;
}
@ -369,7 +392,7 @@ static std::unique_ptr<GrRenderTargetContext> draw_mipmap_into_new_render_target
// Test that two opsTasks using the same mipmaps both depend on the same GrTextureResolveRenderTask.
DEF_GPUTEST(GrManyDependentsMipMappedTest, reporter, /* options */) {
using Enable = GrContextOptions::Enable;
using Filter = GrSamplerState::Filter;
using MipmapMode = GrSamplerState::MipmapMode;
for (auto enableSortingAndReduction : {Enable::kYes, Enable::kNo}) {
GrMockOptions mockOptions;
@ -421,7 +444,7 @@ DEF_GPUTEST(GrManyDependentsMipMappedTest, reporter, /* options */) {
// Draw the dirty mipmap texture into a render target.
auto rtc1 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
alphaType, mipmapView, Filter::kMipMap);
alphaType, mipmapView, MipmapMode::kLinear);
auto rtc1Task = sk_ref_sp(rtc1->testingOnly_PeekLastOpsTask());
// Mipmaps should have gotten marked dirty during makeClosed, then marked clean again as
@ -436,7 +459,7 @@ DEF_GPUTEST(GrManyDependentsMipMappedTest, reporter, /* options */) {
// Draw the now-clean mipmap texture into a second target.
auto rtc2 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
alphaType, mipmapView, Filter::kMipMap);
alphaType, mipmapView, MipmapMode::kLinear);
auto rtc2Task = sk_ref_sp(rtc2->testingOnly_PeekLastOpsTask());
// Make sure the mipmap texture still has the same regen task.
@ -465,7 +488,7 @@ DEF_GPUTEST(GrManyDependentsMipMappedTest, reporter, /* options */) {
// Draw the dirty mipmap texture into a render target, but don't do mipmap filtering.
rtc1 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
alphaType, mipmapView, Filter::kLinear);
alphaType, mipmapView, MipmapMode::kNone);
// Mipmaps should have gotten marked dirty during makeClosed() when adding the dependency.
// Since the last draw did not use mips, they will not have been regenerated and should
@ -479,7 +502,7 @@ DEF_GPUTEST(GrManyDependentsMipMappedTest, reporter, /* options */) {
// Draw the stil-dirty mipmap texture into a second target with mipmap filtering.
rtc2 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
alphaType, std::move(mipmapView),
Filter::kMipMap);
MipmapMode::kLinear);
rtc2Task = sk_ref_sp(rtc2->testingOnly_PeekLastOpsTask());
// Make sure the mipmap texture now has a new last render task that regenerates the mips,

View File

@ -575,11 +575,20 @@ DEF_GPUTEST(TextureIdleProcTest, reporter, options) {
GrSwizzle readSwizzle = dContext->priv().caps()->getReadSwizzle(
backendFormat, GrColorType::kRGBA_8888);
GrSurfaceProxyView view(std::move(proxy), kTopLeft_GrSurfaceOrigin, readSwizzle);
rtc->drawTexture(nullptr, view, kPremul_SkAlphaType,
GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver,
SkPMColor4f(), SkRect::MakeWH(w, h), SkRect::MakeWH(w, h),
GrAA::kNo, GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint,
SkMatrix::I(), nullptr);
rtc->drawTexture(nullptr,
view,
kPremul_SkAlphaType,
GrSamplerState::Filter::kNearest,
GrSamplerState::MipmapMode::kNone,
SkBlendMode::kSrcOver,
SkPMColor4f(),
SkRect::MakeWH(w, h),
SkRect::MakeWH(w, h),
GrAA::kNo,
GrQuadAAFlags::kNone,
SkCanvas::kFast_SrcRectConstraint,
SkMatrix::I(),
nullptr);
// We still have the proxy, which should remain instantiated, thereby keeping the
// texture not purgeable.
REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
@ -589,11 +598,20 @@ DEF_GPUTEST(TextureIdleProcTest, reporter, options) {
REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
// This time we move the proxy into the draw.
rtc->drawTexture(nullptr, std::move(view), kPremul_SkAlphaType,
GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver,
SkPMColor4f(), SkRect::MakeWH(w, h), SkRect::MakeWH(w, h),
GrAA::kNo, GrQuadAAFlags::kNone,
SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
rtc->drawTexture(nullptr,
std::move(view),
kPremul_SkAlphaType,
GrSamplerState::Filter::kNearest,
GrSamplerState::MipmapMode::kNone,
SkBlendMode::kSrcOver,
SkPMColor4f(),
SkRect::MakeWH(w, h),
SkRect::MakeWH(w, h),
GrAA::kNo,
GrQuadAAFlags::kNone,
SkCanvas::kFast_SrcRectConstraint,
SkMatrix::I(),
nullptr);
REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
dContext->flushAndSubmit();
dContext->priv().getGpu()->testingOnly_flushGpuAndSync();
@ -640,12 +658,20 @@ DEF_GPUTEST(TextureIdleProcTest, reporter, options) {
proxy->backendFormat(), GrColorType::kRGBA_8888);
GrSurfaceProxyView view(std::move(proxy), kTopLeft_GrSurfaceOrigin,
swizzle);
rtc->drawTexture(
nullptr, std::move(view), kPremul_SkAlphaType,
GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver,
SkPMColor4f(), SkRect::MakeWH(w, h), SkRect::MakeWH(w, h),
GrAA::kNo, GrQuadAAFlags::kNone,
SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr);
rtc->drawTexture(nullptr,
std::move(view),
kPremul_SkAlphaType,
GrSamplerState::Filter::kNearest,
GrSamplerState::MipmapMode::kNone,
SkBlendMode::kSrcOver,
SkPMColor4f(),
SkRect::MakeWH(w, h),
SkRect::MakeWH(w, h),
GrAA::kNo,
GrQuadAAFlags::kNone,
SkCanvas::kFast_SrcRectConstraint,
SkMatrix::I(),
nullptr);
if (drawType == DrawType::kDrawAndFlush) {
dContext->flushAndSubmit();
}

View File

@ -28,17 +28,17 @@ static void test_basic_draw_as_src(skiatest::Reporter* reporter, GrRecordingCont
SkAlphaType alphaType, uint32_t expectedPixelValues[]) {
auto rtContext = GrRenderTargetContext::Make(
context, colorType, nullptr, SkBackingFit::kExact, rectView.proxy()->dimensions());
for (auto filter : {GrSamplerState::Filter::kNearest,
GrSamplerState::Filter::kLinear,
GrSamplerState::Filter::kMipMap}) {
rtContext->clear(SkPMColor4f::FromBytes_RGBA(0xDDCCBBAA));
auto fp = GrTextureEffect::Make(rectView, alphaType, SkMatrix::I(), filter);
GrPaint paint;
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
paint.setColorFragmentProcessor(std::move(fp));
rtContext->drawPaint(nullptr, std::move(paint), SkMatrix::I());
TestReadPixels(reporter, rtContext.get(), expectedPixelValues,
"RectangleTexture-basic-draw");
for (auto filter : {GrSamplerState::Filter::kNearest, GrSamplerState::Filter::kLinear}) {
for (auto mm : {GrSamplerState::MipmapMode::kNone, GrSamplerState::MipmapMode::kLinear}) {
rtContext->clear(SkPMColor4f::FromBytes_RGBA(0xDDCCBBAA));
auto fp = GrTextureEffect::Make(rectView, alphaType, SkMatrix::I(), filter, mm);
GrPaint paint;
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
paint.setColorFragmentProcessor(std::move(fp));
rtContext->drawPaint(nullptr, std::move(paint), SkMatrix::I());
TestReadPixels(reporter, rtContext.get(), expectedPixelValues,
"RectangleTexture-basic-draw");
}
}
}