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

View File

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

View File

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

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 // 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 // If not disable mip mapping. Also disable when a subset is requested.
// requested. if (samplerState.mipmapped() == GrMipmapped::kYes &&
if (samplerState.filter() == GrSamplerState::Filter::kMipMap &&
(subset || !fImage->setupMipmapsForPlanes(this->context()))) { (subset || !fImage->setupMipmapsForPlanes(this->context()))) {
samplerState.setFilterMode(GrSamplerState::Filter::kLinear); samplerState.setMipmapMode(GrSamplerState::MipmapMode::kNone);
} }
const auto& caps = *fImage->context()->priv().caps(); const auto& caps = *fImage->context()->priv().caps();

View File

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

View File

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

View File

@ -798,6 +798,7 @@ void GrRenderTargetContext::drawTexturedQuad(const GrClip* clip,
SkAlphaType srcAlphaType, SkAlphaType srcAlphaType,
sk_sp<GrColorSpaceXform> textureXform, sk_sp<GrColorSpaceXform> textureXform,
GrSamplerState::Filter filter, GrSamplerState::Filter filter,
GrSamplerState::MipmapMode mm,
const SkPMColor4f& color, const SkPMColor4f& color,
SkBlendMode blendMode, SkBlendMode blendMode,
GrAA aa, GrAA aa,
@ -827,7 +828,7 @@ void GrRenderTargetContext::drawTexturedQuad(const GrClip* clip,
// quad is sufficiently inside the subset and the constraint could be dropped. // quad is sufficiently inside the subset and the constraint could be dropped.
this->addDrawOp(finalClip, this->addDrawOp(finalClip,
GrTextureOp::Make(fContext, std::move(proxyView), srcAlphaType, GrTextureOp::Make(fContext, std::move(proxyView), srcAlphaType,
std::move(textureXform), filter, color, saturate, std::move(textureXform), filter, mm, color, saturate,
blendMode, aaType, quad, subset)); blendMode, aaType, quad, subset));
} }
} }
@ -1007,10 +1008,15 @@ void GrRenderTargetContextPriv::stencilPath(const GrHardClip* clip,
fRenderTargetContext->addOp(std::move(op)); fRenderTargetContext->addOp(std::move(op));
} }
void GrRenderTargetContext::drawTextureSet(const GrClip* clip, TextureSetEntry set[], void GrRenderTargetContext::drawTextureSet(const GrClip* clip,
int cnt, int proxyRunCnt, TextureSetEntry set[],
GrSamplerState::Filter filter, SkBlendMode mode, int cnt,
GrAA aa, SkCanvas::SrcRectConstraint constraint, int proxyRunCnt,
GrSamplerState::Filter filter,
GrSamplerState::MipmapMode mm,
SkBlendMode mode,
GrAA aa,
SkCanvas::SrcRectConstraint constraint,
const SkMatrix& viewMatrix, const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> texXform) { sk_sp<GrColorSpaceXform> texXform) {
ASSERT_SINGLE_OWNER ASSERT_SINGLE_OWNER
@ -1025,7 +1031,7 @@ void GrRenderTargetContext::drawTextureSet(const GrClip* clip, TextureSetEntry s
auto clampType = GrColorTypeClampType(this->colorInfo().colorType()); auto clampType = GrColorTypeClampType(this->colorInfo().colorType());
auto saturate = clampType == GrClampType::kManual ? GrTextureOp::Saturate::kYes auto saturate = clampType == GrClampType::kManual ? GrTextureOp::Saturate::kYes
: GrTextureOp::Saturate::kNo; : 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)); 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 * specifies the rectangle to draw in local coords which will be transformed by 'viewMatrix' to
* device space. * device space.
*/ */
void drawTexture(const GrClip* clip, GrSurfaceProxyView view, SkAlphaType srcAlphaType, void drawTexture(const GrClip* clip,
GrSamplerState::Filter filter, SkBlendMode mode, const SkPMColor4f& color, GrSurfaceProxyView view,
const SkRect& srcRect, const SkRect& dstRect, GrAA aa, GrQuadAAFlags edgeAA, SkAlphaType srcAlphaType,
SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix, 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) { sk_sp<GrColorSpaceXform> texXform) {
const SkRect* subset = constraint == SkCanvas::kStrict_SrcRectConstraint ? const SkRect* subset = constraint == SkCanvas::kStrict_SrcRectConstraint ?
&srcRect : nullptr; &srcRect : nullptr;
DrawQuad quad{GrQuad::MakeFromRect(dstRect, viewMatrix), GrQuad(srcRect), edgeAA}; DrawQuad quad{GrQuad::MakeFromRect(dstRect, viewMatrix), GrQuad(srcRect), edgeAA};
this->drawTexturedQuad(clip, std::move(view), srcAlphaType, std::move(texXform), this->drawTexturedQuad(clip, std::move(view), srcAlphaType, std::move(texXform), filter, mm,
filter, color, mode, aa, &quad, subset); 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 * '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'. * provided, the strict src rect constraint is applied using 'subset'.
*/ */
void drawTextureQuad(const GrClip* clip, GrSurfaceProxyView view, GrColorType srcColorType, void drawTextureQuad(const GrClip* clip,
SkAlphaType srcAlphaType, GrSamplerState::Filter filter, SkBlendMode mode, GrSurfaceProxyView view,
const SkPMColor4f& color, const SkPoint srcQuad[4], GrColorType srcColorType,
const SkPoint dstQuad[4], GrAA aa, GrQuadAAFlags edgeAA, SkAlphaType srcAlphaType,
const SkRect* subset, const SkMatrix& viewMatrix, 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) { sk_sp<GrColorSpaceXform> texXform) {
DrawQuad quad{GrQuad::MakeFromSkQuad(dstQuad, viewMatrix), DrawQuad quad{GrQuad::MakeFromSkQuad(dstQuad, viewMatrix),
GrQuad::MakeFromSkQuad(srcQuad, SkMatrix::I()), edgeAA}; GrQuad::MakeFromSkQuad(srcQuad, SkMatrix::I()), edgeAA};
this->drawTexturedQuad(clip, std::move(view), srcAlphaType, std::move(texXform), this->drawTexturedQuad(clip, std::move(view), srcAlphaType, std::move(texXform), filter, mm,
filter, color, mode, aa, &quad, subset); color, mode, aa, &quad, subset);
} }
/** Used with drawTextureSet */ /** Used with drawTextureSet */
@ -323,9 +341,16 @@ public:
* can be inferred from the array within this function, but the information is already known * 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. * by SkGpuDevice, so no need to incur another iteration over the array.
*/ */
void drawTextureSet(const GrClip*, TextureSetEntry[], int cnt, int proxyRunCnt, void drawTextureSet(const GrClip*,
GrSamplerState::Filter, SkBlendMode mode, GrAA aa, TextureSetEntry[],
SkCanvas::SrcRectConstraint, const SkMatrix& viewMatrix, int cnt,
int proxyRunCnt,
GrSamplerState::Filter,
GrSamplerState::MipmapMode,
SkBlendMode mode,
GrAA aa,
SkCanvas::SrcRectConstraint,
const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> texXform); sk_sp<GrColorSpaceXform> texXform);
/** /**
@ -645,6 +670,7 @@ private:
SkAlphaType alphaType, SkAlphaType alphaType,
sk_sp<GrColorSpaceXform> textureXform, sk_sp<GrColorSpaceXform> textureXform,
GrSamplerState::Filter filter, GrSamplerState::Filter filter,
GrSamplerState::MipmapMode,
const SkPMColor4f& color, const SkPMColor4f& color,
SkBlendMode blendMode, SkBlendMode blendMode,
GrAA aa, GrAA aa,

View File

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

View File

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

View File

@ -81,7 +81,7 @@ std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createFragmentProcessor(
const SkRect* domain, const SkRect* domain,
GrSamplerState samplerState) { GrSamplerState samplerState) {
return this->createFragmentProcessorForView( 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( std::unique_ptr<GrFragmentProcessor> GrTextureAdjuster::createBicubicFragmentProcessor(

View File

@ -29,7 +29,7 @@ std::unique_ptr<GrFragmentProcessor> GrTextureMaker::createFragmentProcessor(
GrSamplerState sampler) { GrSamplerState sampler) {
GrSurfaceProxyView view; GrSurfaceProxyView view;
return this->createFragmentProcessorForView( 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( std::unique_ptr<GrFragmentProcessor> GrTextureMaker::createBicubicFragmentProcessor(

View File

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

View File

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

View File

@ -141,12 +141,19 @@ bool SkPaintToGrPaintWithTexture(GrRecordingContext*,
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Misc Sk to Gr type conversions // Misc Sk to Gr type conversions
GrSamplerState::Filter GrSkFilterQualityToGrFilterMode(int imageWidth, int imageHeight, /**
SkFilterQuality paintFilterQuality, * Determines how to interpret SkFilterQuality given draw params and canvas state. If the returned
const SkMatrix& viewM, * bool is true then bicubic filtering should be used (and the two other return values can be
const SkMatrix& localM, * ignored).
bool sharpenMipmappedTextures, */
bool* doBicubic); 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."); 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( D3D12_CPU_DESCRIPTOR_HANDLE GrD3DResourceProvider::findOrCreateCompatibleSampler(
const GrSamplerState& params) { const GrSamplerState& params) {
uint32_t key = params.asIndex(); uint32_t key = params.asIndex();
@ -136,17 +154,7 @@ D3D12_CPU_DESCRIPTOR_HANDLE GrD3DResourceProvider::findOrCreateCompatibleSampler
return *samplerPtr; return *samplerPtr;
} }
static D3D12_FILTER d3dFilterModes[] = { D3D12_FILTER filter = d3d_filter(params);
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_TEXTURE_ADDRESS_MODE addressModeU = wrap_mode_to_d3d_address_mode(params.wrapModeX()); 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()); 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: case GrSamplerState::Filter::kNearest:
return wgpu::FilterMode::Nearest; return wgpu::FilterMode::Nearest;
case GrSamplerState::Filter::kLinear: case GrSamplerState::Filter::kLinear:
case GrSamplerState::Filter::kMipMap:
return wgpu::FilterMode::Linear; return wgpu::FilterMode::Linear;
default: default:
SkASSERT(!"unsupported filter mode"); SkASSERT(!"unsupported filter mode");

View File

@ -329,25 +329,3 @@ std::unique_ptr<GrFragmentProcessor> GrBicubicEffect::TestCreate(GrProcessorTest
} }
} }
#endif #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, Kernel,
Direction); 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: private:
class Impl; class Impl;

View File

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

View File

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

View File

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

View File

@ -178,18 +178,23 @@ static GrGLenum filter_to_gl_mag_filter(GrSamplerState::Filter filter) {
switch (filter) { switch (filter) {
case GrSamplerState::Filter::kNearest: return GR_GL_NEAREST; case GrSamplerState::Filter::kNearest: return GR_GL_NEAREST;
case GrSamplerState::Filter::kLinear: return GR_GL_LINEAR; 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) { static GrGLenum filter_to_gl_min_filter(GrSamplerState::Filter filter,
switch (filter) { GrSamplerState::MipmapMode mm) {
case GrSamplerState::Filter::kNearest: return GR_GL_NEAREST; switch (mm) {
case GrSamplerState::Filter::kLinear: return GR_GL_LINEAR; case GrSamplerState::MipmapMode::kNone:
case GrSamplerState::Filter::kMipMap: return GR_GL_LINEAR_MIPMAP_LINEAR; 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, 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()); SkASSERT(caps.clampToBorderSupport());
return GR_GL_CLAMP_TO_BORDER; return GR_GL_CLAMP_TO_BORDER;
} }
SK_ABORT("Unknown wrap mode"); SkUNREACHABLE;
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -240,10 +245,10 @@ public:
return; return;
} }
fSamplers[index] = s; fSamplers[index] = s;
auto minFilter = filter_to_gl_min_filter(state.filter()); GrGLenum minFilter = filter_to_gl_min_filter(state.filter(), state.mipmapMode());
auto magFilter = filter_to_gl_mag_filter(state.filter()); GrGLenum magFilter = filter_to_gl_mag_filter(state.filter());
auto wrapX = wrap_mode_to_gl_wrap(state.wrapModeX(), fGpu->glCaps()); GrGLenum wrapX = wrap_mode_to_gl_wrap(state.wrapModeX(), fGpu->glCaps());
auto wrapY = wrap_mode_to_gl_wrap(state.wrapModeY(), fGpu->glCaps()); GrGLenum wrapY = wrap_mode_to_gl_wrap(state.wrapModeY(), fGpu->glCaps());
GR_GL_CALL(fGpu->glInterface(), GR_GL_CALL(fGpu->glInterface(),
SamplerParameteri(s, GR_GL_TEXTURE_MIN_FILTER, minFilter)); SamplerParameteri(s, GR_GL_TEXTURE_MIN_FILTER, minFilter));
GR_GL_CALL(fGpu->glInterface(), GR_GL_CALL(fGpu->glInterface(),
@ -2574,37 +2579,32 @@ void GrGLGpu::bindTexture(int unitIdx, GrSamplerState samplerState, const GrSwiz
fHWTextureUnitBindings[unitIdx].setBoundID(target, textureID); fHWTextureUnitBindings[unitIdx].setBoundID(target, textureID);
} }
if (samplerState.filter() == GrSamplerState::Filter::kMipMap) { if (samplerState.mipmapped() == GrMipmapped::kYes) {
if (!this->caps()->mipmapSupport() || if (!this->caps()->mipmapSupport() ||
texture->texturePriv().mipmapped() == GrMipmapped::kNo) { 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(); auto timestamp = texture->parameters()->resetTimestamp();
bool setAll = timestamp < fResetTimestampForTextureParameters; bool setAll = timestamp < fResetTimestampForTextureParameters;
const GrGLTextureParameters::SamplerOverriddenState* samplerStateToRecord = nullptr; const GrGLTextureParameters::SamplerOverriddenState* samplerStateToRecord = nullptr;
GrGLTextureParameters::SamplerOverriddenState newSamplerState; GrGLTextureParameters::SamplerOverriddenState newSamplerState;
if (fSamplerObjectCache) { if (fSamplerObjectCache) {
fSamplerObjectCache->bindSampler(unitIdx, samplerState); fSamplerObjectCache->bindSampler(unitIdx, samplerState);
if (this->glCaps().mustSetTexParameterMinFilterToEnableMipmapping()) { 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 = const GrGLTextureParameters::SamplerOverriddenState& oldSamplerState =
texture->parameters()->samplerOverriddenState(); texture->parameters()->samplerOverriddenState();
if (setAll || oldSamplerState.fMinFilter != GR_GL_LINEAR_MIPMAP_LINEAR) { if (setAll || oldSamplerState.fMinFilter != minFilter) {
this->setTextureUnit(unitIdx); this->setTextureUnit(unitIdx);
GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MIN_FILTER, GL_CALL(TexParameteri(target, GR_GL_TEXTURE_MIN_FILTER, minFilter));
GR_GL_LINEAR_MIPMAP_LINEAR));
newSamplerState = oldSamplerState; newSamplerState = oldSamplerState;
newSamplerState.fMinFilter = GR_GL_LINEAR_MIPMAP_LINEAR; newSamplerState.fMinFilter = minFilter;
samplerStateToRecord = &newSamplerState; samplerStateToRecord = &newSamplerState;
} }
} }
@ -2614,7 +2614,8 @@ void GrGLGpu::bindTexture(int unitIdx, GrSamplerState samplerState, const GrSwiz
texture->parameters()->samplerOverriddenState(); texture->parameters()->samplerOverriddenState();
samplerStateToRecord = &newSamplerState; 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.fMagFilter = filter_to_gl_mag_filter(samplerState.filter());
newSamplerState.fWrapS = wrap_mode_to_gl_wrap(samplerState.wrapModeX(), this->glCaps()); 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) { GrMtlSampler* GrMtlSampler::Create(const GrMtlGpu* gpu, GrSamplerState samplerState) {
static MTLSamplerMinMagFilter mtlMinMagFilterModes[] = { MTLSamplerMinMagFilter minMagFilter = [&] {
MTLSamplerMinMagFilterNearest, switch (samplerState.filter()) {
MTLSamplerMinMagFilterLinear, case GrSamplerState::Filter::kNearest: return MTLSamplerMinMagFilterNearest;
MTLSamplerMinMagFilterLinear case GrSamplerState::Filter::kLinear: return MTLSamplerMinMagFilterLinear;
}; }
SkUNREACHABLE;
}();
static_assert((int)GrSamplerState::Filter::kNearest == 0); MTLSamplerMipFilter mipFilter = [&] {
static_assert((int)GrSamplerState::Filter::kLinear == 1); switch (samplerState.mipmapMode()) {
static_assert((int)GrSamplerState::Filter::kMipMap == 2); case GrSamplerState::MipmapMode::kNone: return MTLSamplerMipFilterNotMipmapped;
case GrSamplerState::MipmapMode::kLinear: return MTLSamplerMipFilterLinear;
}
SkUNREACHABLE;
}();
auto samplerDesc = [[MTLSamplerDescriptor alloc] init]; auto samplerDesc = [[MTLSamplerDescriptor alloc] init];
samplerDesc.rAddressMode = MTLSamplerAddressModeClampToEdge; samplerDesc.rAddressMode = MTLSamplerAddressModeClampToEdge;
@ -57,12 +63,11 @@ GrMtlSampler* GrMtlSampler::Create(const GrMtlGpu* gpu, GrSamplerState samplerSt
gpu->mtlCaps()); gpu->mtlCaps());
samplerDesc.tAddressMode = wrap_mode_to_mtl_sampler_address(samplerState.wrapModeY(), samplerDesc.tAddressMode = wrap_mode_to_mtl_sampler_address(samplerState.wrapModeY(),
gpu->mtlCaps()); gpu->mtlCaps());
samplerDesc.magFilter = mtlMinMagFilterModes[static_cast<int>(samplerState.filter())]; samplerDesc.magFilter = minMagFilter;
samplerDesc.minFilter = mtlMinMagFilterModes[static_cast<int>(samplerState.filter())]; samplerDesc.minFilter = minMagFilter;
samplerDesc.mipFilter = MTLSamplerMipFilterLinear; samplerDesc.mipFilter = mipFilter;
samplerDesc.lodMinClamp = 0.0f; samplerDesc.lodMinClamp = 0.0f;
bool useMipMaps = GrSamplerState::Filter::kMipMap == samplerState.filter(); samplerDesc.lodMaxClamp = FLT_MAX; // default value according to docs.
samplerDesc.lodMaxClamp = !useMipMaps ? 0.0f : 10000.0f;
samplerDesc.maxAnisotropy = 1.0f; samplerDesc.maxAnisotropy = 1.0f;
samplerDesc.normalizedCoordinates = true; samplerDesc.normalizedCoordinates = true;
if (@available(macOS 10.11, iOS 9.0, *)) { if (@available(macOS 10.11, iOS 9.0, *)) {

View File

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

View File

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

View File

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

View File

@ -10,8 +10,7 @@
#include "src/gpu/vk/GrVkGpu.h" #include "src/gpu/vk/GrVkGpu.h"
#include "src/gpu/vk/GrVkSamplerYcbcrConversion.h" #include "src/gpu/vk/GrVkSamplerYcbcrConversion.h"
static inline VkSamplerAddressMode wrap_mode_to_vk_sampler_address( static VkSamplerAddressMode wrap_mode_to_vk_sampler_address(GrSamplerState::WrapMode wrapMode) {
GrSamplerState::WrapMode wrapMode) {
switch (wrapMode) { switch (wrapMode) {
case GrSamplerState::WrapMode::kClamp: case GrSamplerState::WrapMode::kClamp:
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; 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: case GrSamplerState::WrapMode::kClampToBorder:
return VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; 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, GrVkSampler* GrVkSampler::Create(GrVkGpu* gpu, GrSamplerState samplerState,
@ -45,7 +53,7 @@ GrVkSampler* GrVkSampler::Create(GrVkGpu* gpu, GrSamplerState samplerState,
createInfo.flags = 0; createInfo.flags = 0;
createInfo.magFilter = vkMagFilterModes[static_cast<int>(samplerState.filter())]; createInfo.magFilter = vkMagFilterModes[static_cast<int>(samplerState.filter())];
createInfo.minFilter = vkMinFilterModes[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.addressModeU = wrap_mode_to_vk_sampler_address(samplerState.wrapModeX());
createInfo.addressModeV = wrap_mode_to_vk_sampler_address(samplerState.wrapModeY()); createInfo.addressModeV = wrap_mode_to_vk_sampler_address(samplerState.wrapModeY());
createInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; // Shouldn't matter 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 // 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. // the minFilter on mip level 0.
createInfo.minLod = 0.0f; 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.maxLod = !useMipMaps ? 0.0f : 10000.0f;
createInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; createInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK;
createInfo.unnormalizedCoordinates = VK_FALSE; 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 // 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 // quality setting. This completely ignores the complexity of the drawVertices case
// where explicit local coords are provided by the caller. // where explicit local coords are provided by the caller.
bool doBicubic; bool sharpen = args.fContext->priv().options().fSharpenMipmappedTextures;
GrSamplerState::Filter fm = GrSkFilterQualityToGrFilterMode( auto [fm, mm, bicubic] = GrInterpretFilterQuality(fImage->dimensions(),
fImage->width(), fImage->height(), this->resolveFiltering(args.fFilterQuality), this->resolveFiltering(args.fFilterQuality),
args.fMatrixProvider.localToDevice(), *lm, args.fMatrixProvider.localToDevice(),
args.fContext->priv().options().fSharpenMipmappedTextures, &doBicubic); *lm,
sharpen);
std::unique_ptr<GrFragmentProcessor> fp; std::unique_ptr<GrFragmentProcessor> fp;
if (doBicubic) { if (bicubic) {
fp = producer->createBicubicFragmentProcessor(lmInverse, nullptr, nullptr, wmX, wmY); fp = producer->createBicubicFragmentProcessor(lmInverse, nullptr, nullptr, wmX, wmY);
} else { } else {
fp = producer->createFragmentProcessor(lmInverse, nullptr, nullptr, {wmX, wmY, fm}); fp = producer->createFragmentProcessor(lmInverse, nullptr, nullptr, {wmX, wmY, fm, mm});
} }
if (fp) { if (fp) {
fp = GrXfermodeFragmentProcessor::Make(std::move(fp), nullptr, SkBlendMode::kModulate); 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); set[i].fAAFlags = perQuadAA(i);
} }
GrTextureOp::AddTextureSetOps(rtc.get(), nullptr, dContext, set, requestedTotNumQuads, GrTextureOp::AddTextureSetOps(rtc.get(),
requestedTotNumQuads, // We alternate so proxyCnt == cnt nullptr,
dContext,
set,
requestedTotNumQuads,
requestedTotNumQuads, // We alternate so proxyCnt == cnt
GrSamplerState::Filter::kNearest, GrSamplerState::Filter::kNearest,
GrSamplerState::MipmapMode::kNone,
GrTextureOp::Saturate::kYes, GrTextureOp::Saturate::kYes,
blendMode, blendMode,
overallAA, overallAA,
SkCanvas::kStrict_SrcRectConstraint, SkCanvas::kStrict_SrcRectConstraint,
SkMatrix::I(), nullptr); SkMatrix::I(),
nullptr);
GrOpsTask* opsTask = rtc->testingOnly_PeekLastOpsTask(); GrOpsTask* opsTask = rtc->testingOnly_PeekLastOpsTask();
int actualNumOps = opsTask->numOpChains(); 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'. // 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( static std::unique_ptr<GrRenderTargetContext> draw_mipmap_into_new_render_target(
GrRecordingContext* context, GrProxyProvider* proxyProvider, GrColorType colorType, GrRecordingContext* context,
SkAlphaType alphaType, GrSurfaceProxyView mipmapView, GrSamplerState::Filter filter) { GrProxyProvider* proxyProvider,
sk_sp<GrSurfaceProxy> renderTarget = proxyProvider->createProxy( GrColorType colorType,
mipmapView.proxy()->backendFormat(), {1, 1}, GrRenderable::kYes, 1, GrMipmapped::kNo, SkAlphaType alphaType,
SkBackingFit::kApprox, SkBudgeted::kYes, GrProtected::kNo); 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( auto rtc = GrRenderTargetContext::Make(context,
context, colorType, nullptr, std::move(renderTarget), kTopLeft_GrSurfaceOrigin, colorType,
nullptr); nullptr,
std::move(renderTarget),
kTopLeft_GrSurfaceOrigin,
nullptr);
rtc->drawTexture(nullptr, std::move(mipmapView), alphaType, filter, SkBlendMode::kSrcOver, rtc->drawTexture(nullptr,
{1,1,1,1}, SkRect::MakeWH(4, 4), SkRect::MakeWH(1,1), GrAA::kYes, std::move(mipmapView),
GrQuadAAFlags::kAll, SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), 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); nullptr);
return rtc; 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. // Test that two opsTasks using the same mipmaps both depend on the same GrTextureResolveRenderTask.
DEF_GPUTEST(GrManyDependentsMipMappedTest, reporter, /* options */) { DEF_GPUTEST(GrManyDependentsMipMappedTest, reporter, /* options */) {
using Enable = GrContextOptions::Enable; using Enable = GrContextOptions::Enable;
using Filter = GrSamplerState::Filter; using MipmapMode = GrSamplerState::MipmapMode;
for (auto enableSortingAndReduction : {Enable::kYes, Enable::kNo}) { for (auto enableSortingAndReduction : {Enable::kYes, Enable::kNo}) {
GrMockOptions mockOptions; GrMockOptions mockOptions;
@ -421,7 +444,7 @@ DEF_GPUTEST(GrManyDependentsMipMappedTest, reporter, /* options */) {
// Draw the dirty mipmap texture into a render target. // Draw the dirty mipmap texture into a render target.
auto rtc1 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType, 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()); auto rtc1Task = sk_ref_sp(rtc1->testingOnly_PeekLastOpsTask());
// Mipmaps should have gotten marked dirty during makeClosed, then marked clean again as // 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. // Draw the now-clean mipmap texture into a second target.
auto rtc2 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType, 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()); auto rtc2Task = sk_ref_sp(rtc2->testingOnly_PeekLastOpsTask());
// Make sure the mipmap texture still has the same regen task. // 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. // 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, 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. // 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 // 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. // Draw the stil-dirty mipmap texture into a second target with mipmap filtering.
rtc2 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType, rtc2 = draw_mipmap_into_new_render_target(context.get(), proxyProvider, colorType,
alphaType, std::move(mipmapView), alphaType, std::move(mipmapView),
Filter::kMipMap); MipmapMode::kLinear);
rtc2Task = sk_ref_sp(rtc2->testingOnly_PeekLastOpsTask()); rtc2Task = sk_ref_sp(rtc2->testingOnly_PeekLastOpsTask());
// Make sure the mipmap texture now has a new last render task that regenerates the mips, // 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( GrSwizzle readSwizzle = dContext->priv().caps()->getReadSwizzle(
backendFormat, GrColorType::kRGBA_8888); backendFormat, GrColorType::kRGBA_8888);
GrSurfaceProxyView view(std::move(proxy), kTopLeft_GrSurfaceOrigin, readSwizzle); GrSurfaceProxyView view(std::move(proxy), kTopLeft_GrSurfaceOrigin, readSwizzle);
rtc->drawTexture(nullptr, view, kPremul_SkAlphaType, rtc->drawTexture(nullptr,
GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver, view,
SkPMColor4f(), SkRect::MakeWH(w, h), SkRect::MakeWH(w, h), kPremul_SkAlphaType,
GrAA::kNo, GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint, GrSamplerState::Filter::kNearest,
SkMatrix::I(), nullptr); 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 // We still have the proxy, which should remain instantiated, thereby keeping the
// texture not purgeable. // texture not purgeable.
REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end()); 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()); REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
// This time we move the proxy into the draw. // This time we move the proxy into the draw.
rtc->drawTexture(nullptr, std::move(view), kPremul_SkAlphaType, rtc->drawTexture(nullptr,
GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver, std::move(view),
SkPMColor4f(), SkRect::MakeWH(w, h), SkRect::MakeWH(w, h), kPremul_SkAlphaType,
GrAA::kNo, GrQuadAAFlags::kNone, GrSamplerState::Filter::kNearest,
SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr); 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()); REPORTER_ASSERT(reporter, idleIDs.find(2) == idleIDs.end());
dContext->flushAndSubmit(); dContext->flushAndSubmit();
dContext->priv().getGpu()->testingOnly_flushGpuAndSync(); dContext->priv().getGpu()->testingOnly_flushGpuAndSync();
@ -640,12 +658,20 @@ DEF_GPUTEST(TextureIdleProcTest, reporter, options) {
proxy->backendFormat(), GrColorType::kRGBA_8888); proxy->backendFormat(), GrColorType::kRGBA_8888);
GrSurfaceProxyView view(std::move(proxy), kTopLeft_GrSurfaceOrigin, GrSurfaceProxyView view(std::move(proxy), kTopLeft_GrSurfaceOrigin,
swizzle); swizzle);
rtc->drawTexture( rtc->drawTexture(nullptr,
nullptr, std::move(view), kPremul_SkAlphaType, std::move(view),
GrSamplerState::Filter::kNearest, SkBlendMode::kSrcOver, kPremul_SkAlphaType,
SkPMColor4f(), SkRect::MakeWH(w, h), SkRect::MakeWH(w, h), GrSamplerState::Filter::kNearest,
GrAA::kNo, GrQuadAAFlags::kNone, GrSamplerState::MipmapMode::kNone,
SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), nullptr); 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) { if (drawType == DrawType::kDrawAndFlush) {
dContext->flushAndSubmit(); dContext->flushAndSubmit();
} }

View File

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