From a0047bcff704a9121a6d82a6f97d6124463a2e54 Mon Sep 17 00:00:00 2001 From: Brian Salomon Date: Wed, 23 May 2018 16:39:39 -0400 Subject: [PATCH] Add support for SkCanvas::kStrict_SrcRectConstraint to GrTextureOp. Change-Id: I8faa2838b3110b8080ac48bbe223240e3fb22998 Reviewed-on: https://skia-review.googlesource.com/129762 Reviewed-by: Brian Osman Commit-Queue: Brian Salomon --- gm/perspimages.cpp | 34 ++-- src/gpu/GrQuad.h | 2 +- src/gpu/GrRenderTargetContext.cpp | 7 +- src/gpu/GrRenderTargetContext.h | 3 +- src/gpu/SkGpuDevice_drawTexture.cpp | 29 ++-- src/gpu/ops/GrTextureOp.cpp | 242 +++++++++++++++++++--------- src/gpu/ops/GrTextureOp.h | 6 +- 7 files changed, 219 insertions(+), 104 deletions(-) diff --git a/gm/perspimages.cpp b/gm/perspimages.cpp index a4242cf6f2..b4ad5eb9ae 100644 --- a/gm/perspimages.cpp +++ b/gm/perspimages.cpp @@ -28,7 +28,7 @@ public: protected: SkString onShortName() override { return SkString("persp_images"); } - SkISize onISize() override { return SkISize::Make(1150, 880); } + SkISize onISize() override { return SkISize::Make(1150, 1280); } void onOnceBeforeDraw() override { fImages.push_back(make_image1()); @@ -60,7 +60,13 @@ protected: } canvas->translate(-bounds.fLeft + 10.f, -bounds.fTop + 10.f); canvas->save(); - for (auto subrect : {false, true}) { + enum class DrawType { + kDrawImage, + kDrawImageRectStrict, + kDrawImageRectFast, + }; + for (auto type : + {DrawType::kDrawImage, DrawType::kDrawImageRectStrict, DrawType::kDrawImageRectFast}) { for (const auto& m : matrices) { for (auto aa : {false, true}) { paint.setAntiAlias(aa); @@ -70,14 +76,22 @@ protected: paint.setFilterQuality(filter); canvas->save(); canvas->concat(m); - if (subrect) { - SkRect src = {img->width() / 4.f, img->height() / 4.f, - 3.f * img->width() / 4.f, 3.f * img->height() / 4}; - SkRect dst = {0, 0, - 3.f / 4.f * img->width(), 3.f / 4.f * img->height()}; - canvas->drawImageRect(img, src, dst, &paint); - } else { - canvas->drawImage(img, 0, 0, &paint); + SkRect src = {img->width() / 4.f, img->height() / 4.f, + 3.f * img->width() / 4.f, 3.f * img->height() / 4}; + SkRect dst = {0, 0, + 3.f / 4.f * img->width(), 3.f / 4.f * img->height()}; + switch (type) { + case DrawType::kDrawImage: + canvas->drawImage(img, 0, 0, &paint); + break; + case DrawType::kDrawImageRectStrict: + canvas->drawImageRect(img, src, dst, &paint, + SkCanvas::kStrict_SrcRectConstraint); + break; + case DrawType::kDrawImageRectFast: + canvas->drawImageRect(img, src, dst, &paint, + SkCanvas::kFast_SrcRectConstraint); + break; } canvas->restore(); ++n; diff --git a/src/gpu/GrQuad.h b/src/gpu/GrQuad.h index 74e235646b..4a104aa94c 100644 --- a/src/gpu/GrQuad.h +++ b/src/gpu/GrQuad.h @@ -64,7 +64,7 @@ public: SkPoint3 point(int i) const { return {fX[i], fY[i], fW[i]}; } - SkRect bounds() { + SkRect bounds() const { auto x = this->x4f() * this->iw4f(); auto y = this->y4f() * this->iw4f(); return {x.min(), y.min(), x.max(), y.max()}; diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index 86d1dde356..1f9e4da3f2 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -766,6 +766,7 @@ static bool must_filter(const SkRect& src, const SkRect& dst, const SkMatrix& ct void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_sp proxy, GrSamplerState::Filter filter, GrColor color, const SkRect& srcRect, const SkRect& dstRect, GrAA aa, + SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix, sk_sp colorSpaceXform) { ASSERT_SINGLE_OWNER @@ -783,9 +784,9 @@ void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_spchooseAAType(aa, GrAllowMixedSamples::kNo); bool allowSRGB = SkToBool(this->colorSpaceInfo().colorSpace()); - this->addDrawOp( - clip, GrTextureOp::Make(std::move(proxy), filter, color, clippedSrcRect, clippedDstRect, - aaType, viewMatrix, std::move(colorSpaceXform), allowSRGB)); + this->addDrawOp(clip, GrTextureOp::Make(std::move(proxy), filter, color, clippedSrcRect, + clippedDstRect, aaType, constraint, viewMatrix, + std::move(colorSpaceXform), allowSRGB)); } void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip, diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h index b237d489cc..acbf963c06 100644 --- a/src/gpu/GrRenderTargetContext.h +++ b/src/gpu/GrRenderTargetContext.h @@ -150,7 +150,8 @@ public: */ void drawTexture(const GrClip& clip, sk_sp, GrSamplerState::Filter, GrColor, const SkRect& srcRect, const SkRect& dstRect, GrAA aa, - const SkMatrix& viewMatrix, sk_sp); + SkCanvas::SrcRectConstraint, const SkMatrix& viewMatrix, + sk_sp); /** * Draw a roundrect using a paint. diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp index 70c89b5776..96472814c5 100644 --- a/src/gpu/SkGpuDevice_drawTexture.cpp +++ b/src/gpu/SkGpuDevice_drawTexture.cpp @@ -87,20 +87,19 @@ static bool can_ignore_bilerp_constraint(const GrTextureProducer& producer, } /** - * Checks whether the paint, matrix, and constraint are compatible with using - * GrRenderTargetContext::drawTexture. It is more efficient than the GrTextureProducer - * general case. + * Checks whether the paint is compatible with using GrRenderTargetContext::drawTexture. It is more + * efficient than the GrTextureProducer general case. */ -static bool can_use_draw_texture(const SkPaint& paint, GrAA aa, const SkMatrix& ctm, - SkCanvas::SrcRectConstraint constraint) { +static bool can_use_draw_texture(const SkPaint& paint) { return (!paint.getColorFilter() && !paint.getShader() && !paint.getMaskFilter() && !paint.getImageFilter() && paint.getFilterQuality() < kMedium_SkFilterQuality && - paint.getBlendMode() == SkBlendMode::kSrcOver && - SkCanvas::kFast_SrcRectConstraint == constraint); + paint.getBlendMode() == SkBlendMode::kSrcOver); } static void draw_texture(const SkPaint& paint, const SkMatrix& ctm, const SkRect* src, - const SkRect* dst, GrAA aa, sk_sp proxy, + const SkRect* dst, GrAA aa, SkCanvas::SrcRectConstraint constraint, + sk_sp proxy, + SkColorSpace* colorSpace, const GrClip& clip, GrRenderTargetContext* rtc) { SkASSERT(!(SkToBool(src) && !SkToBool(dst))); SkRect srcRect = src ? *src : SkRect::MakeWH(proxy->width(), proxy->height()); @@ -129,7 +128,7 @@ static void draw_texture(const SkPaint& paint, const SkMatrix& ctm, const SkRect GrColor color = GrPixelConfigIsAlphaOnly(proxy->config()) ? SkColorToPremulGrColor(paint.getColor()) : SkColorAlphaToGrColor(paint.getColor()); - rtc->drawTexture(clip, std::move(proxy), filter, color, srcRect, dstRect, aa, ctm, + rtc->drawTexture(clip, std::move(proxy), filter, color, srcRect, dstRect, aa, constraint, ctm, std::move(csxf)); } @@ -141,9 +140,9 @@ void SkGpuDevice::drawPinnedTextureProxy(sk_sp proxy, uint32_t p SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix, const SkPaint& paint) { GrAA aa = GrAA(paint.isAntiAlias()); - if (can_use_draw_texture(paint, aa, this->ctm(), constraint)) { - draw_texture(paint, viewMatrix, srcRect, dstRect, aa, std::move(proxy), colorSpace, - this->clip(), fRenderTargetContext.get()); + if (can_use_draw_texture(paint)) { + draw_texture(paint, viewMatrix, srcRect, dstRect, aa, constraint, std::move(proxy), + colorSpace, this->clip(), fRenderTargetContext.get()); return; } GrTextureAdjuster adjuster(this->context(), std::move(proxy), alphaType, pinnedUniqueID, @@ -156,7 +155,7 @@ void SkGpuDevice::drawTextureMaker(GrTextureMaker* maker, int imageW, int imageH SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix, const SkPaint& paint) { GrAA aa = GrAA(paint.isAntiAlias()); - if (can_use_draw_texture(paint, aa, viewMatrix, constraint)) { + if (can_use_draw_texture(paint)) { sk_sp cs; // We've done enough checks above to allow us to pass ClampNearest() and not check for // scaling adjustments. @@ -166,8 +165,8 @@ void SkGpuDevice::drawTextureMaker(GrTextureMaker* maker, int imageW, int imageH if (!proxy) { return; } - draw_texture(paint, viewMatrix, srcRect, dstRect, aa, std::move(proxy), cs.get(), - this->clip(), fRenderTargetContext.get()); + draw_texture(paint, viewMatrix, srcRect, dstRect, aa, constraint, std::move(proxy), + cs.get(), this->clip(), fRenderTargetContext.get()); return; } this->drawTextureProducer(maker, srcRect, dstRect, constraint, viewMatrix, paint); diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp index a2cd4eb79f..933a17393e 100644 --- a/src/gpu/ops/GrTextureOp.cpp +++ b/src/gpu/ops/GrTextureOp.cpp @@ -33,6 +33,8 @@ namespace { enum class MultiTexture : bool { kNo = false, kYes = true }; +enum class Domain : bool { kNo = false, kYes = true }; + /** * Geometry Processor that draws a texture modulated by a vertex color (though, this is meant to be * the same value across all vertices of a quad and uses flat interpolation when available). This is @@ -58,19 +60,30 @@ public: int fTextureIdx; }; - template struct OptionalAAVertex; + template struct OptionalDomainVertex; template - struct OptionalAAVertex : OptionalMultiTextureVertex { - static constexpr GrAA kAA = GrAA::kNo; + struct OptionalDomainVertex : OptionalMultiTextureVertex { + static constexpr Domain kDomain = Domain::kNo; }; template - struct OptionalAAVertex : OptionalMultiTextureVertex { + struct OptionalDomainVertex : OptionalMultiTextureVertex { + static constexpr Domain kDomain = Domain::kYes; + SkRect fTextureDomain; + }; + + template struct OptionalAAVertex; + template + struct OptionalAAVertex : OptionalDomainVertex { + static constexpr GrAA kAA = GrAA::kNo; + }; + template + struct OptionalAAVertex : OptionalDomainVertex { static constexpr GrAA kAA = GrAA::kYes; SkPoint3 fEdges[4]; }; - template - using Vertex = OptionalAAVertex; + template + using Vertex = OptionalAAVertex; // Maximum number of textures supported by this op. Must also be checked against the caps // limit. These numbers were based on some limited experiments on a HP Z840 and Pixel XL 2016 @@ -87,7 +100,8 @@ public: static sk_sp Make(sk_sp proxies[], int proxyCnt, sk_sp csxf, bool coverageAA, - bool perspective, const GrSamplerState::Filter filters[], + bool perspective, Domain domain, + const GrSamplerState::Filter filters[], const GrShaderCaps& caps) { // We use placement new to avoid always allocating space for kMaxTextures TextureSampler // instances. @@ -96,7 +110,7 @@ public: void* mem = GrGeometryProcessor::operator new(size); return sk_sp( new (mem) TextureGeometryProcessor(proxies, proxyCnt, samplerCnt, std::move(csxf), - coverageAA, perspective, filters, caps)); + coverageAA, perspective, domain, filters, caps)); } ~TextureGeometryProcessor() override { @@ -112,6 +126,7 @@ public: b->add32(GrColorSpaceXform::XformKey(fColorSpaceXform.get())); uint32_t x = this->usesCoverageEdgeAA() ? 0 : 1; x |= kFloat3_GrVertexAttribType == fPositions.fType ? 0 : 2; + x |= fDomain.isInitialized() ? 4 : 0; b->add32(x); } @@ -150,6 +165,14 @@ public: args.fFragBuilder->codeAppend("float2 texCoord;"); args.fVaryingHandler->addPassThroughAttribute(&textureGP.fTextureCoords, "texCoord"); + if (textureGP.fDomain.isInitialized()) { + args.fFragBuilder->codeAppend("float4 domain;"); + args.fVaryingHandler->addPassThroughAttribute( + &textureGP.fDomain, "domain", + GrGLSLVaryingHandler::Interpolation::kCanBeFlat); + args.fFragBuilder->codeAppend( + "texCoord = clamp(texCoord, domain.xy, domain.zw);"); + } if (textureGP.numTextureSamplers() > 1) { // If this changes to float, reconsider Interpolation::kMustBeFlat. SkASSERT(kInt_GrVertexAttribType == textureGP.fTextureIdx.fType); @@ -275,7 +298,8 @@ private: TextureGeometryProcessor(sk_sp proxies[], int proxyCnt, int samplerCnt, sk_sp csxf, bool coverageAA, bool perspective, - const GrSamplerState::Filter filters[], const GrShaderCaps& caps) + Domain domain, const GrSamplerState::Filter filters[], + const GrShaderCaps& caps) : INHERITED(kTextureGeometryProcessor_ClassID), fColorSpaceXform(std::move(csxf)) { SkASSERT(proxyCnt > 0 && samplerCnt >= proxyCnt); fSamplers[0].reset(std::move(proxies[0]), filters[0]); @@ -306,7 +330,9 @@ private: SkASSERT(caps.integerSupport()); fTextureIdx = this->addVertexAttrib("textureIdx", kInt_GrVertexAttribType); } - + if (domain == Domain::kYes) { + fDomain = this->addVertexAttrib("domain", kFloat4_GrVertexAttribType); + } if (coverageAA) { fAAEdges[0] = this->addVertexAttrib("aaEdge0", kFloat3_GrVertexAttribType); fAAEdges[1] = this->addVertexAttrib("aaEdge1", kFloat3_GrVertexAttribType); @@ -319,6 +345,7 @@ private: Attribute fColors; Attribute fTextureCoords; Attribute fTextureIdx; + Attribute fDomain; Attribute fAAEdges[4]; sk_sp fColorSpaceXform; TextureSampler fSamplers[1]; @@ -509,12 +536,52 @@ template struct TexIdAssigner { template struct TexIdAssigner { static void Assign(V* vertices, int textureIdx) {} }; + +template struct DomainAssigner; + +template struct DomainAssigner { + static void Assign(V* vertices, Domain domain, GrSamplerState::Filter filter, + const SkRect& srcRect, GrSurfaceOrigin origin, float iw, float ih) { + static constexpr SkRect kLargeRect = {-2, -2, 2, 2}; + SkRect domainRect; + if (domain == Domain::kYes) { + auto ltrb = Sk4f::Load(&srcRect); + if (filter == GrSamplerState::Filter::kBilerp) { + auto rblt = SkNx_shuffle<2, 3, 0, 1>(ltrb); + auto whwh = (rblt - ltrb).abs(); + auto c = (rblt + ltrb) * 0.5f; + static const Sk4f kOffsets = {0.5f, 0.5f, -0.5f, -0.5f}; + ltrb = (whwh < 1.f).thenElse(c, ltrb + kOffsets); + } + ltrb *= Sk4f(iw, ih, iw, ih); + if (origin == kBottomLeft_GrSurfaceOrigin) { + static const Sk4f kMul = {1.f, -1.f, 1.f, -1.f}; + static const Sk4f kAdd = {0.f, 1.f, 0.f, 1.f}; + ltrb = SkNx_shuffle<0, 3, 2, 1>(kMul * ltrb + kAdd); + } + ltrb.store(&domainRect); + } else { + domainRect = kLargeRect; + } + for (int i = 0; i < 4; ++i) { + vertices[i].fTextureDomain = domainRect; + } + } +}; + +template struct DomainAssigner { + static void Assign(V*, Domain domain, GrSamplerState::Filter, const SkRect&, GrSurfaceOrigin, + float iw, float ih) { + SkASSERT(domain == Domain::kNo); + } +}; + } // anonymous namespace template static void tessellate_quad(const GrPerspQuad& devQuad, const SkRect& srcRect, GrColor color, - GrSurfaceOrigin origin, V* vertices, SkScalar iw, SkScalar ih, - int textureIdx) { + GrSurfaceOrigin origin, GrSamplerState::Filter filter, V* vertices, + SkScalar iw, SkScalar ih, int textureIdx, Domain domain) { SkRect texRect = { iw * srcRect.fLeft, ih * srcRect.fTop, @@ -531,6 +598,7 @@ static void tessellate_quad(const GrPerspQuad& devQuad, const SkRect& srcRect, G vertices[2].fColor = color; vertices[3].fColor = color; TexIdAssigner::Assign(vertices, textureIdx); + DomainAssigner::Assign(vertices, domain, filter, srcRect, origin, iw, ih); } /** @@ -542,11 +610,12 @@ public: static std::unique_ptr Make(sk_sp proxy, GrSamplerState::Filter filter, GrColor color, const SkRect& srcRect, const SkRect& dstRect, - GrAAType aaType, const SkMatrix& viewMatrix, - sk_sp csxf, bool allowSRBInputs) { + GrAAType aaType, SkCanvas::SrcRectConstraint constraint, + const SkMatrix& viewMatrix, sk_sp csxf, + bool allowSRBInputs) { return std::unique_ptr(new TextureOp(std::move(proxy), filter, color, srcRect, - dstRect, aaType, viewMatrix, std::move(csxf), - allowSRBInputs)); + dstRect, aaType, constraint, viewMatrix, + std::move(csxf), allowSRBInputs)); } ~TextureOp() override { @@ -587,11 +656,11 @@ public: str.appendf( "%d: Color: 0x%08x, ProxyIdx: %d, TexRect [L: %.2f, T: %.2f, R: %.2f, B: %.2f] " "Quad [(%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f), (%.2f, %.2f)]\n", - i, draw.fColor, draw.fTextureIdx, draw.fSrcRect.fLeft, draw.fSrcRect.fTop, - draw.fSrcRect.fRight, draw.fSrcRect.fBottom, draw.fQuad.point(0).fX, - draw.fQuad.point(0).fY, draw.fQuad.point(1).fX, draw.fQuad.point(1).fY, - draw.fQuad.point(2).fX, draw.fQuad.point(2).fY, draw.fQuad.point(3).fX, - draw.fQuad.point(3).fY); + i, draw.color(), draw.textureIdx(), draw.srcRect().fLeft, draw.srcRect().fTop, + draw.srcRect().fRight, draw.srcRect().fBottom, draw.quad().point(0).fX, + draw.quad().point(0).fY, draw.quad().point(1).fX, draw.quad().point(1).fY, + draw.quad().point(2).fX, draw.quad().point(2).fY, draw.quad().point(3).fX, + draw.quad().point(3).fY); } str += INHERITED::dumpInfo(); return str; @@ -629,7 +698,8 @@ __attribute__((no_sanitize("float-cast-overflow"))) TextureOp(sk_sp proxy, GrSamplerState::Filter filter, GrColor color, const SkRect& srcRect, const SkRect& dstRect, GrAAType aaType, - const SkMatrix& viewMatrix, sk_sp csxf, bool allowSRGBInputs) + SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix, + sk_sp csxf, bool allowSRGBInputs) : INHERITED(ClassID()) , fColorSpaceXform(std::move(csxf)) , fProxy0(proxy.release()) @@ -639,29 +709,36 @@ __attribute__((no_sanitize("float-cast-overflow"))) , fFinalized(0) , fAllowSRGBInputs(allowSRGBInputs ? 1 : 0) { SkASSERT(aaType != GrAAType::kMixedSamples); - Draw& draw = fDraws.push_back(); - draw.fSrcRect = srcRect; - draw.fTextureIdx = 0; - draw.fColor = color; + // No need to use a texture domain with nearest filtering unless there is AA bloating. + if (constraint == SkCanvas::kStrict_SrcRectConstraint && + filter == GrSamplerState::Filter::kNearest && GrAAType::kCoverage != aaType) { + constraint = SkCanvas::kFast_SrcRectConstraint; + } + + const Draw& draw = fDraws.emplace_back(srcRect, 0, GrPerspQuad(dstRect, viewMatrix), + constraint, color); fPerspective = viewMatrix.hasPerspective(); + fDomain = (bool)draw.domain(); SkRect bounds; - draw.fQuad = GrPerspQuad(dstRect, viewMatrix); - bounds = draw.fQuad.bounds(); + bounds = draw.quad().bounds(); this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo); fMaxApproxDstPixelArea = RectSizeAsSizeT(bounds); } - template + template void tess(void* v, const float iw[], const float ih[], const GrGeometryProcessor* gp) { - using Vertex = TextureGeometryProcessor::Vertex; + using Vertex = TextureGeometryProcessor::Vertex; SkASSERT(gp->getVertexStride() == sizeof(Vertex)); auto vertices = static_cast(v); auto proxies = this->proxies(); + auto filters = this->filters(); for (const auto& draw : fDraws) { - auto origin = proxies[draw.fTextureIdx]->origin(); - tessellate_quad(draw.fQuad, draw.fSrcRect, draw.fColor, origin, vertices, - iw[draw.fTextureIdx], ih[draw.fTextureIdx], draw.fTextureIdx); + auto textureIdx = draw.textureIdx(); + auto origin = proxies[textureIdx]->origin(); + tessellate_quad(draw.quad(), draw.srcRect(), draw.color(), origin, + filters[textureIdx], vertices, iw[textureIdx], ih[textureIdx], + textureIdx, draw.domain()); vertices += 4; } } @@ -677,10 +754,11 @@ __attribute__((no_sanitize("float-cast-overflow"))) proxiesSPs[i] = sk_ref_sp(proxies[i]); } + Domain domain = fDomain ? Domain::kYes : Domain::kNo; bool coverageAA = GrAAType::kCoverage == this->aaType(); sk_sp gp = TextureGeometryProcessor::Make( proxiesSPs, fProxyCnt, std::move(fColorSpaceXform), coverageAA, fPerspective, - filters, *target->caps().shaderCaps()); + domain, filters, *target->caps().shaderCaps()); GrPipeline::InitArgs args; args.fProxy = target->proxy(); args.fCaps = &target->caps(); @@ -712,35 +790,33 @@ __attribute__((no_sanitize("float-cast-overflow"))) ih[t] = 1.f / texture->height(); } - if (fPerspective) { - if (fProxyCnt > 1) { - if (coverageAA) { - this->tess(vdata, iw, ih, gp.get()); - } else { - this->tess(vdata, iw, ih, gp.get()); - } - } else { - if (coverageAA) { - this->tess(vdata, iw, ih, gp.get()); - } else { - this->tess(vdata, iw, ih, gp.get()); - } - } - } else { - if (fProxyCnt > 1) { - if (coverageAA) { - this->tess(vdata, iw, ih, gp.get()); - } else { - this->tess(vdata, iw, ih, gp.get()); - } - } else { - if (coverageAA) { - this->tess(vdata, iw, ih, gp.get()); - } else { - this->tess(vdata, iw, ih, gp.get()); - } - } - } + using TessFn = + decltype(&TextureOp::tess); + static constexpr TessFn kTessFns[] = { + &TextureOp::tess, + &TextureOp::tess, + &TextureOp::tess, + &TextureOp::tess, + &TextureOp::tess, + &TextureOp::tess, + &TextureOp::tess, + &TextureOp::tess, + &TextureOp::tess, + &TextureOp::tess, + &TextureOp::tess, + &TextureOp::tess, + &TextureOp::tess, + &TextureOp::tess, + &TextureOp::tess, + &TextureOp::tess, + }; + int tessFnIdx = 0; + tessFnIdx |= coverageAA ? 0x1 : 0x0; + tessFnIdx |= fDomain ? 0x2 : 0x0; + tessFnIdx |= (fProxyCnt > 1) ? 0x4 : 0x0; + tessFnIdx |= fPerspective ? 0x8 : 0x0; + (this->*(kTessFns[tessFnIdx]))(vdata, iw, ih, gp.get()); + GrPrimitiveType primitiveType = fDraws.count() > 1 ? GrPrimitiveType::kTriangles : GrPrimitiveType::kTriangleStrip; GrMesh mesh(primitiveType); @@ -806,7 +882,7 @@ __attribute__((no_sanitize("float-cast-overflow"))) int firstNewDraw = fDraws.count(); fDraws.push_back_n(that->fDraws.count(), that->fDraws.begin()); for (int i = firstNewDraw; i < fDraws.count(); ++i) { - fDraws[i].fTextureIdx = map[fDraws[i].fTextureIdx]; + fDraws[i].setTextureIdx(map[fDraws[i].textureIdx()]); } } else { // We can get here when one of the ops is already multitextured but the other cannot @@ -822,6 +898,7 @@ __attribute__((no_sanitize("float-cast-overflow"))) this->joinBounds(*that); fMaxApproxDstPixelArea = SkTMax(that->fMaxApproxDstPixelArea, fMaxApproxDstPixelArea); fPerspective |= that->fPerspective; + fDomain |= that->fDomain; return true; } @@ -894,9 +971,26 @@ __attribute__((no_sanitize("float-cast-overflow"))) return &fFilter0; } - struct Draw { + class Draw { + public: + Draw(const SkRect& srcRect, int textureIdx, const GrPerspQuad& quad, + SkCanvas::SrcRectConstraint constraint, GrColor color) + : fSrcRect(srcRect) + , fHasDomain(constraint == SkCanvas::kStrict_SrcRectConstraint) + , fTextureIdx(SkToUInt(textureIdx)) + , fQuad(quad) + , fColor(color) {} + const GrPerspQuad& quad() const { return fQuad; } + int textureIdx() const { return SkToInt(fTextureIdx); } + const SkRect& srcRect() const { return fSrcRect; } + GrColor color() const { return fColor; } + Domain domain() const { return Domain(fHasDomain); } + void setTextureIdx(int i) { fTextureIdx = SkToUInt(i); } + + private: SkRect fSrcRect; - int fTextureIdx; + unsigned fHasDomain : 1; + unsigned fTextureIdx : 31; GrPerspQuad fQuad; GrColor fColor; }; @@ -914,6 +1008,7 @@ __attribute__((no_sanitize("float-cast-overflow"))) uint8_t fProxyCnt; unsigned fAAType : 2; unsigned fPerspective : 1; + unsigned fDomain : 1; // Used to track whether fProxy is ref'ed or has a pending IO after finalize() is called. unsigned fFinalized : 1; unsigned fAllowSRGBInputs : 1; @@ -930,10 +1025,11 @@ namespace GrTextureOp { std::unique_ptr Make(sk_sp proxy, GrSamplerState::Filter filter, GrColor color, const SkRect& srcRect, const SkRect& dstRect, - GrAAType aaType, const SkMatrix& viewMatrix, - sk_sp csxf, bool allowSRGBInputs) { - return TextureOp::Make(std::move(proxy), filter, color, srcRect, dstRect, aaType, viewMatrix, - std::move(csxf), allowSRGBInputs); + GrAAType aaType, SkCanvas::SrcRectConstraint constraint, + const SkMatrix& viewMatrix, sk_sp csxf, + bool allowSRGBInputs) { + return TextureOp::Make(std::move(proxy), filter, color, srcRect, dstRect, aaType, constraint, + viewMatrix, std::move(csxf), allowSRGBInputs); } } // namespace GrTextureOp @@ -970,8 +1066,10 @@ GR_DRAW_OP_TEST_DEFINE(TextureOp) { if (random->nextBool()) { aaType = (fsaaType == GrFSAAType::kUnifiedMSAA) ? GrAAType::kMSAA : GrAAType::kCoverage; } - return GrTextureOp::Make(std::move(proxy), filter, color, srcRect, rect, aaType, viewMatrix, - std::move(csxf), allowSRGBInputs); + auto constraint = random->nextBool() ? SkCanvas::kStrict_SrcRectConstraint + : SkCanvas::kFast_SrcRectConstraint; + return GrTextureOp::Make(std::move(proxy), filter, color, srcRect, rect, aaType, constraint, + viewMatrix, std::move(csxf), allowSRGBInputs); } #endif diff --git a/src/gpu/ops/GrTextureOp.h b/src/gpu/ops/GrTextureOp.h index a6c1a4fd06..d61b36e978 100644 --- a/src/gpu/ops/GrTextureOp.h +++ b/src/gpu/ops/GrTextureOp.h @@ -8,6 +8,7 @@ #include "GrColor.h" #include "GrSamplerState.h" #include "GrTypesPriv.h" +#include "SkCanvas.h" #include "SkRefCnt.h" class GrColorSpaceXform; @@ -17,6 +18,7 @@ struct SkRect; class SkMatrix; namespace GrTextureOp { + /** * Creates an op that draws a sub-rectangle of a texture. The passed color is modulated by the * texture's color. 'srcRect' specifies the rectangle of the texture to draw. 'dstRect' specifies @@ -25,6 +27,6 @@ namespace GrTextureOp { */ std::unique_ptr Make(sk_sp, GrSamplerState::Filter, GrColor, const SkRect& srcRect, const SkRect& dstRect, GrAAType, - const SkMatrix& viewMatrix, sk_sp, - bool allowSRGBInputs); + SkCanvas::SrcRectConstraint, const SkMatrix& viewMatrix, + sk_sp, bool allowSRGBInputs); }