diff options
-rw-r--r-- | bench/MultitextureImageBench.cpp | 52 | ||||
-rw-r--r-- | src/gpu/GrPrimitiveProcessor.h | 6 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetContext.cpp | 8 | ||||
-rw-r--r-- | src/gpu/GrRenderTargetContext.h | 5 | ||||
-rw-r--r-- | src/gpu/SkGpuDevice_drawTexture.cpp | 15 | ||||
-rw-r--r-- | src/gpu/ops/GrTextureOp.cpp | 318 | ||||
-rw-r--r-- | src/gpu/ops/GrTextureOp.h | 2 |
7 files changed, 300 insertions, 106 deletions
diff --git a/bench/MultitextureImageBench.cpp b/bench/MultitextureImageBench.cpp index d001cac774..2c87efb414 100644 --- a/bench/MultitextureImageBench.cpp +++ b/bench/MultitextureImageBench.cpp @@ -16,12 +16,16 @@ class MultitextureImages : public Benchmark { public: - MultitextureImages(int imageSize, int dstRectSize, bool disableMultitexturing) + MultitextureImages(int imageSize, int dstRectSize, bool disableMultitexturing, bool aa) : fImageSize(imageSize) , fDstRectSize(dstRectSize) - , fDisableMultitexturing(disableMultitexturing) { + , fDisableMultitexturing(disableMultitexturing) + , fAA(aa) { fName.appendf("multitexture_images_%dx%d_image_%dx%d_rect", imageSize, imageSize, dstRectSize, dstRectSize); + if (aa) { + fName.append("_aa"); + } if (disableMultitexturing) { fName.append("_disable_multitexturing"); } @@ -60,6 +64,7 @@ protected: SkPaint paint; paint.setAlpha(0x40); paint.setFilterQuality(kLow_SkFilterQuality); + paint.setAntiAlias(fAA); for (int i = 0; i < loops; i++) { for (int j = 0; j < kNumImages; ++j) { SkVector translate = this->translation(i * kNumImages + j); @@ -87,8 +92,9 @@ private: SkVector translation(int i) const { SkVector offset; - offset.fX = i % kNumColumns * kTranslate; - offset.fY = (i / kNumColumns) % kNumRows * kTranslate; + // Fractional offsets to ensure we can't ignore antialiasing. + offset.fX = i % kNumColumns * kTranslate + 0.1f; + offset.fY = (i / kNumColumns) % kNumRows * kTranslate + 0.1f; return offset; } @@ -102,24 +108,32 @@ private: int fImageSize; int fDstRectSize; bool fDisableMultitexturing; + bool fAA; typedef Benchmark INHERITED; }; -DEF_BENCH(return new MultitextureImages(128, 32, false)); -DEF_BENCH(return new MultitextureImages(128, 32, true)); -DEF_BENCH(return new MultitextureImages(128, 128, false)); -DEF_BENCH(return new MultitextureImages(128, 128, true)); -DEF_BENCH(return new MultitextureImages(128, 256, false)); -DEF_BENCH(return new MultitextureImages(128, 256, true)); - -DEF_BENCH(return new MultitextureImages(512, 32, false)); -DEF_BENCH(return new MultitextureImages(512, 32, true)); -DEF_BENCH(return new MultitextureImages(512, 128, false)); -DEF_BENCH(return new MultitextureImages(512, 128, true)); -DEF_BENCH(return new MultitextureImages(512, 256, false)); -DEF_BENCH(return new MultitextureImages(512, 256, true)); -DEF_BENCH(return new MultitextureImages(512, 512, false)); -DEF_BENCH(return new MultitextureImages(512, 512, true)); +// Non-AA +DEF_BENCH(return new MultitextureImages(128, 32, false, false)); +DEF_BENCH(return new MultitextureImages(128, 32, true, false)); +DEF_BENCH(return new MultitextureImages(128, 128, false, false)); +DEF_BENCH(return new MultitextureImages(128, 128, true, false)); +DEF_BENCH(return new MultitextureImages(128, 256, false, false)); +DEF_BENCH(return new MultitextureImages(128, 256, true, false)); + +DEF_BENCH(return new MultitextureImages(512, 32, false, false)); +DEF_BENCH(return new MultitextureImages(512, 32, true, false)); +DEF_BENCH(return new MultitextureImages(512, 128, false, false)); +DEF_BENCH(return new MultitextureImages(512, 128, true, false)); +DEF_BENCH(return new MultitextureImages(512, 256, false, false)); +DEF_BENCH(return new MultitextureImages(512, 256, true, false)); +DEF_BENCH(return new MultitextureImages(512, 512, false, false)); +DEF_BENCH(return new MultitextureImages(512, 512, true, false)); + +// AA +DEF_BENCH(return new MultitextureImages(512, 512, true, true)); +DEF_BENCH(return new MultitextureImages(512, 512, false, true)); +DEF_BENCH(return new MultitextureImages(128, 32, true, true)); +DEF_BENCH(return new MultitextureImages(128, 32, false, true)); #endif diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h index f480110df5..22c65fa249 100644 --- a/src/gpu/GrPrimitiveProcessor.h +++ b/src/gpu/GrPrimitiveProcessor.h @@ -49,7 +49,11 @@ public: return GrShaderVar(fName, GrVertexAttribTypeToSLType(fType), GrShaderVar::kIn_TypeModifier); } - const char* fName; + bool isInitialized() const { return SkToBool(fName); } + Attribute() = default; + Attribute(const char* name, GrVertexAttribType type, int offset, InputRate rate) + : fName(name), fType(type), fOffsetInRecord(offset), fInputRate(rate) {} + const char* fName = nullptr; GrVertexAttribType fType; int fOffsetInRecord; InputRate fInputRate; diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index c985e964e8..b0b117f914 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -766,7 +766,7 @@ static bool must_filter(const SkRect& src, const SkRect& dst, const SkMatrix& ct void GrRenderTargetContext::drawTextureAffine(const GrClip& clip, sk_sp<GrTextureProxy> proxy, GrSamplerState::Filter filter, GrColor color, - const SkRect& srcRect, const SkRect& dstRect, + const SkRect& srcRect, const SkRect& dstRect, GrAA aa, const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform> colorSpaceXform) { ASSERT_SINGLE_OWNER @@ -785,9 +785,9 @@ void GrRenderTargetContext::drawTextureAffine(const GrClip& clip, sk_sp<GrTextur } bool allowSRGB = SkToBool(this->colorSpaceInfo().colorSpace()); - this->addDrawOp(clip, GrTextureOp::Make(std::move(proxy), filter, color, clippedSrcRect, - clippedDstRect, viewMatrix, std::move(colorSpaceXform), - allowSRGB)); + this->addDrawOp( + clip, GrTextureOp::Make(std::move(proxy), filter, color, clippedSrcRect, clippedDstRect, + aa, viewMatrix, std::move(colorSpaceXform), allowSRGB)); } void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip, diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h index 6215262177..2ae52b922c 100644 --- a/src/gpu/GrRenderTargetContext.h +++ b/src/gpu/GrRenderTargetContext.h @@ -145,11 +145,10 @@ public: * Creates an op that draws a subrectangle of a texture. The passed color is modulated by the * texture's color. 'srcRect' specifies the rectangle of the texture to draw. 'dstRect' * specifies the rectangle to draw in local coords which will be transformed by 'viewMatrix' to - * device space. The edges of the rendered rectangle are not antialiased. This asserts that the - * view matrix does not have perspective. + * device space. This asserts that the view matrix does not have perspective. */ void drawTextureAffine(const GrClip& clip, sk_sp<GrTextureProxy>, GrSamplerState::Filter, - GrColor, const SkRect& srcRect, const SkRect& dstRect, + GrColor, const SkRect& srcRect, const SkRect& dstRect, GrAA aa, const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform>); /** diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp index bedd292a58..f8e5f74311 100644 --- a/src/gpu/SkGpuDevice_drawTexture.cpp +++ b/src/gpu/SkGpuDevice_drawTexture.cpp @@ -94,14 +94,13 @@ static bool can_ignore_bilerp_constraint(const GrTextureProducer& producer, static bool can_use_draw_texture_affine(const SkPaint& paint, const SkMatrix& ctm, SkCanvas::SrcRectConstraint constraint) { return (!paint.getColorFilter() && !paint.getShader() && !paint.getMaskFilter() && - !paint.getImageFilter() && !paint.isAntiAlias() && - paint.getFilterQuality() < kMedium_SkFilterQuality && + !paint.getImageFilter() && paint.getFilterQuality() < kMedium_SkFilterQuality && paint.getBlendMode() == SkBlendMode::kSrcOver && !ctm.hasPerspective() && SkCanvas::kFast_SrcRectConstraint == constraint); } static void draw_texture_affine(const SkPaint& paint, const SkMatrix& ctm, const SkRect* src, - const SkRect* dst, sk_sp<GrTextureProxy> proxy, + const SkRect* dst, GrAA aa, sk_sp<GrTextureProxy> proxy, SkColorSpace* colorSpace, const GrClip& clip, GrRenderTargetContext* rtc) { SkASSERT(!(SkToBool(src) && !SkToBool(dst))); @@ -131,7 +130,7 @@ static void draw_texture_affine(const SkPaint& paint, const SkMatrix& ctm, const GrColor color = GrPixelConfigIsAlphaOnly(proxy->config()) ? SkColorToPremulGrColor(paint.getColor()) : SkColorAlphaToGrColor(paint.getColor()); - rtc->drawTextureAffine(clip, std::move(proxy), filter, color, srcRect, dstRect, ctm, + rtc->drawTextureAffine(clip, std::move(proxy), filter, color, srcRect, dstRect, aa, ctm, std::move(csxf)); } @@ -143,8 +142,8 @@ void SkGpuDevice::drawPinnedTextureProxy(sk_sp<GrTextureProxy> proxy, uint32_t p SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix, const SkPaint& paint) { if (can_use_draw_texture_affine(paint, this->ctm(), constraint)) { - draw_texture_affine(paint, viewMatrix, srcRect, dstRect, std::move(proxy), colorSpace, - this->clip(), fRenderTargetContext.get()); + draw_texture_affine(paint, viewMatrix, srcRect, dstRect, GrAA(paint.isAntiAlias()), + std::move(proxy), colorSpace, this->clip(), fRenderTargetContext.get()); return; } GrTextureAdjuster adjuster(this->context(), std::move(proxy), alphaType, pinnedUniqueID, @@ -166,8 +165,8 @@ void SkGpuDevice::drawTextureMaker(GrTextureMaker* maker, int imageW, int imageH if (!proxy) { return; } - draw_texture_affine(paint, viewMatrix, srcRect, dstRect, std::move(proxy), cs.get(), - this->clip(), fRenderTargetContext.get()); + draw_texture_affine(paint, viewMatrix, srcRect, dstRect, GrAA(paint.isAntiAlias()), + 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 5ed02cc1a5..6d735f51af 100644 --- a/src/gpu/ops/GrTextureOp.cpp +++ b/src/gpu/ops/GrTextureOp.cpp @@ -20,9 +20,13 @@ #include "GrTextureProxy.h" #include "SkGr.h" #include "SkMathPriv.h" +#include "SkPoint.h" +#include "SkPoint3.h" #include "glsl/GrGLSLColorSpaceXformHelper.h" +#include "glsl/GrGLSLFragmentShaderBuilder.h" #include "glsl/GrGLSLGeometryProcessor.h" #include "glsl/GrGLSLVarying.h" +#include "glsl/GrGLSLVertexGeoBuilder.h" namespace { @@ -38,12 +42,25 @@ public: SkPoint fTextureCoords; GrColor fColor; }; + struct AAVertex { + SkPoint fPosition; + SkPoint fTextureCoords; + SkPoint3 fEdges[4]; + GrColor fColor; + }; struct MultiTextureVertex { SkPoint fPosition; int fTextureIdx; SkPoint fTextureCoords; GrColor fColor; }; + struct AAMultiTextureVertex { + SkPoint fPosition; + int fTextureIdx; + SkPoint fTextureCoords; + SkPoint3 fEdges[4]; + GrColor fColor; + }; // 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 @@ -59,7 +76,7 @@ public: } static sk_sp<GrGeometryProcessor> Make(sk_sp<GrTextureProxy> proxies[], int proxyCnt, - sk_sp<GrColorSpaceXform> csxf, + sk_sp<GrColorSpaceXform> csxf, GrAA aa, const GrSamplerState::Filter filters[], const GrShaderCaps& caps) { // We use placement new to avoid always allocating space for kMaxTextures TextureSampler @@ -68,7 +85,7 @@ public: size_t size = sizeof(TextureGeometryProcessor) + sizeof(TextureSampler) * (samplerCnt - 1); void* mem = GrGeometryProcessor::operator new(size); return sk_sp<TextureGeometryProcessor>(new (mem) TextureGeometryProcessor( - proxies, proxyCnt, samplerCnt, std::move(csxf), filters, caps)); + proxies, proxyCnt, samplerCnt, std::move(csxf), aa, filters, caps)); } ~TextureGeometryProcessor() override { @@ -82,6 +99,7 @@ public: void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { b->add32(GrColorSpaceXform::XformKey(fColorSpaceXform.get())); + b->add32(static_cast<uint32_t>(this->aa())); } GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps& caps) const override { @@ -149,13 +167,36 @@ public: &fColorSpaceXformHelper); } args.fFragBuilder->codeAppend(";"); - args.fFragBuilder->codeAppendf("%s = float4(1);", args.fOutputCoverage); + if (GrAA::kYes == textureGP.aa()) { + GrGLSLVarying aaDistVarying(kFloat4_GrSLType, + GrGLSLVarying::Scope::kVertToFrag); + args.fVaryingHandler->addVarying("aaDists", &aaDistVarying); + args.fVertBuilder->codeAppendf( + R"(%s = float4(dot(aaEdge0.xy, %s.xy) + aaEdge0.z, + dot(aaEdge1.xy, %s.xy) + aaEdge1.z, + dot(aaEdge2.xy, %s.xy) + aaEdge2.z, + dot(aaEdge3.xy, %s.xy) + aaEdge3.z);)", + aaDistVarying.vsOut(), textureGP.fPositions.fName, + textureGP.fPositions.fName, textureGP.fPositions.fName, + textureGP.fPositions.fName); + + args.fFragBuilder->codeAppendf( + "float mindist = min(min(%s.x, %s.y), min(%s.z, %s.w));", + aaDistVarying.fsIn(), aaDistVarying.fsIn(), aaDistVarying.fsIn(), + aaDistVarying.fsIn()); + args.fFragBuilder->codeAppendf("%s = float4(clamp(mindist, 0, 1));", + args.fOutputCoverage); + } else { + args.fFragBuilder->codeAppendf("%s = float4(1);", args.fOutputCoverage); + } } GrGLSLColorSpaceXformHelper fColorSpaceXformHelper; }; return new GLSLProcessor; } + GrAA aa() const { return GrAA(fAAEdges[0].isInitialized()); } + private: // This exists to reduce the number of shaders generated. It does some rounding of sampler // counts. @@ -173,10 +214,9 @@ private: } TextureGeometryProcessor(sk_sp<GrTextureProxy> proxies[], int proxyCnt, int samplerCnt, - sk_sp<GrColorSpaceXform> csxf, const GrSamplerState::Filter filters[], - const GrShaderCaps& caps) - : INHERITED(kTextureGeometryProcessor_ClassID) - , fColorSpaceXform(std::move(csxf)) { + sk_sp<GrColorSpaceXform> csxf, GrAA aa, + const GrSamplerState::Filter filters[], const GrShaderCaps& caps) + : INHERITED(kTextureGeometryProcessor_ClassID), fColorSpaceXform(std::move(csxf)) { SkASSERT(proxyCnt > 0 && samplerCnt >= proxyCnt); fPositions = this->addVertexAttrib("position", kFloat2_GrVertexAttribType); fSamplers[0].reset(std::move(proxies[0]), filters[0]); @@ -200,6 +240,12 @@ private: } fTextureCoords = this->addVertexAttrib("textureCoords", kFloat2_GrVertexAttribType); + if (GrAA::kYes == aa) { + fAAEdges[0] = this->addVertexAttrib("aaEdge0", kFloat3_GrVertexAttribType); + fAAEdges[1] = this->addVertexAttrib("aaEdge1", kFloat3_GrVertexAttribType); + fAAEdges[2] = this->addVertexAttrib("aaEdge2", kFloat3_GrVertexAttribType); + fAAEdges[3] = this->addVertexAttrib("aaEdge3", kFloat3_GrVertexAttribType); + } fColors = this->addVertexAttrib("color", kUByte4_norm_GrVertexAttribType); } @@ -207,12 +253,148 @@ private: Attribute fTextureIdx; Attribute fTextureCoords; Attribute fColors; + Attribute fAAEdges[4]; sk_sp<GrColorSpaceXform> fColorSpaceXform; TextureSampler fSamplers[1]; typedef GrGeometryProcessor INHERITED; }; +namespace { +// This is a class soley so it can be partially specialized (functions cannot be). +template<GrAA, typename Vertex> class VertexAAHandler; + +template<typename Vertex> class VertexAAHandler<GrAA::kNo, Vertex> { +public: + static void AssignPositionsAndTexCoords(Vertex* vertices, const GrQuad& quad, + const SkRect& texRect) { + vertices[0].fPosition = quad.point(0); + vertices[0].fTextureCoords = {texRect.fLeft, texRect.fTop}; + vertices[1].fPosition = quad.point(1); + vertices[1].fTextureCoords = {texRect.fLeft, texRect.fBottom}; + vertices[2].fPosition = quad.point(2); + vertices[2].fTextureCoords = {texRect.fRight, texRect.fTop}; + vertices[3].fPosition = quad.point(3); + vertices[3].fTextureCoords = {texRect.fRight, texRect.fBottom}; + } +}; + +template<typename Vertex> class VertexAAHandler<GrAA::kYes, Vertex> { +public: + static void AssignPositionsAndTexCoords(Vertex* vertices, const GrQuad& quad, + const SkRect& texRect) { + // We compute the four edge equations for quad, then outset them and compute a new quad + // as the intersection points of the outset edges. + + // GrQuad is in tristip order but we want the points to be in a fan order, so swap 2 and 3. + Sk4f xs(quad.point(0).fX, quad.point(1).fX, quad.point(3).fX, quad.point(2).fX); + Sk4f ys(quad.point(0).fY, quad.point(1).fY, quad.point(3).fY, quad.point(2).fY); + Sk4f xsrot = SkNx_shuffle<1, 2, 3, 0>(xs); + Sk4f ysrot = SkNx_shuffle<1, 2, 3, 0>(ys); + Sk4f normXs = ysrot - ys; + Sk4f normYs = xs - xsrot; + Sk4f ds = xsrot * ys - ysrot * xs; + Sk4f invNormLengths = (normXs * normXs + normYs * normYs).rsqrt(); + float test = normXs[0] * xs[2] + normYs[0] * ys[2] + ds[0]; + // Make sure the edge equations have their normals facing into the quad in device space + if (test < 0) { + invNormLengths = -invNormLengths; + } + normXs *= invNormLengths; + normYs *= invNormLengths; + ds *= invNormLengths; + + // Here is the bloat. This makes our edge equations compute coverage without requiring a + // half pixel offset and is also used to compute the bloated quad that will cover all + // pixels. + ds += Sk4f(0.5f); + + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + vertices[j].fEdges[i].fX = normXs[i]; + vertices[j].fEdges[i].fY = normYs[i]; + vertices[j].fEdges[i].fZ = ds[i]; + } + } + + // Reverse the process to compute the points of the bloated quad from the edge equations. + // This time the inputs don't have 1s as their third coord and we want to homogenize rather + // than normalize the output since we need a GrQuad with 2D points. + xsrot = SkNx_shuffle<3, 0, 1, 2>(normXs); + ysrot = SkNx_shuffle<3, 0, 1, 2>(normYs); + Sk4f dsrot = SkNx_shuffle<3, 0, 1, 2>(ds); + xs = ysrot * ds - normYs * dsrot; + ys = normXs * dsrot - xsrot * ds; + ds = xsrot * normYs - ysrot * normXs; + ds = ds.invert(); + xs *= ds; + ys *= ds; + + // Go back to tri strip order when writing out the bloated quad to vertex positions. + vertices[0].fPosition = {xs[0], ys[0]}; + vertices[1].fPosition = {xs[1], ys[1]}; + vertices[3].fPosition = {xs[2], ys[2]}; + vertices[2].fPosition = {xs[3], ys[3]}; + + AssignTexCoords(vertices, quad, texRect); + } + +private: + static void AssignTexCoords(Vertex* vertices, const GrQuad& quad, const SkRect& tex) { + SkMatrix q = SkMatrix::MakeAll(quad.point(0).fX, quad.point(1).fX, quad.point(2).fX, + quad.point(0).fY, quad.point(1).fY, quad.point(2).fY, + 1.f, 1.f, 1.f); + SkMatrix qinv; + if (!q.invert(&qinv)) { + return; + } + SkMatrix t = SkMatrix::MakeAll(tex.fLeft, tex.fLeft, tex.fRight, + tex.fTop, tex.fBottom, tex.fTop, + 1.f, 1.f, 1.f); + SkMatrix map; + map.setConcat(t, qinv); + SkMatrixPriv::MapPointsWithStride(map, &vertices[0].fTextureCoords, sizeof(Vertex), + &vertices[0].fPosition, sizeof(Vertex), 4); + } +}; + +template <typename Vertex, bool IsMultiTex> struct TexIdAssigner; + +template <typename Vertex> struct TexIdAssigner<Vertex, true> { + static void Assign(Vertex* vertices, int textureIdx) { + vertices[0].fTextureIdx = textureIdx; + vertices[1].fTextureIdx = textureIdx; + vertices[2].fTextureIdx = textureIdx; + vertices[3].fTextureIdx = textureIdx; + } +}; + +template <typename Vertex> struct TexIdAssigner<Vertex, false> { + static void Assign(Vertex* vertices, int textureIdx) {} +}; +} // anonymous namespace + +template <typename Vertex, bool IsMultiTex, GrAA AA> +static void tessellate_quad(const GrQuad& devQuad, const SkRect& srcRect, GrColor color, + GrSurfaceOrigin origin, Vertex* vertices, SkScalar iw, SkScalar ih, + int textureIdx) { + SkRect texRect = { + iw * srcRect.fLeft, + ih * srcRect.fTop, + iw * srcRect.fRight, + ih * srcRect.fBottom + }; + if (origin == kBottomLeft_GrSurfaceOrigin) { + texRect.fTop = 1.f - texRect.fTop; + texRect.fBottom = 1.f - texRect.fBottom; + } + VertexAAHandler<AA, Vertex>::AssignPositionsAndTexCoords(vertices, devQuad, texRect); + vertices[0].fColor = color; + vertices[1].fColor = color; + vertices[2].fColor = color; + vertices[3].fColor = color; + TexIdAssigner<Vertex, IsMultiTex>::Assign(vertices, textureIdx); +} /** * Op that implements GrTextureOp::Make. It draws textured quads. Each quad can modulate against a * the texture by color. The blend with the destination is always src-over. The edges are non-AA. @@ -221,11 +403,11 @@ class TextureOp final : public GrMeshDrawOp { public: static std::unique_ptr<GrDrawOp> Make(sk_sp<GrTextureProxy> proxy, GrSamplerState::Filter filter, GrColor color, - const SkRect srcRect, const SkRect dstRect, + const SkRect& srcRect, const SkRect& dstRect, GrAA aa, const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform> csxf, bool allowSRBInputs) { return std::unique_ptr<GrDrawOp>(new TextureOp(std::move(proxy), filter, color, srcRect, - dstRect, viewMatrix, std::move(csxf), + dstRect, aa, viewMatrix, std::move(csxf), allowSRBInputs)); } @@ -298,22 +480,23 @@ private: #if defined(__clang__) && (__clang_major__ * 1000 + __clang_minor__) >= 3007 __attribute__((no_sanitize("float-cast-overflow"))) #endif - size_t RectSizeAsSizeT(const SkRect &rect) {; + size_t RectSizeAsSizeT(const SkRect& rect) {; return static_cast<size_t>(SkTMax(rect.width(), 1.f) * SkTMax(rect.height(), 1.f)); } static constexpr int kMaxTextures = TextureGeometryProcessor::kMaxTextures; TextureOp(sk_sp<GrTextureProxy> proxy, GrSamplerState::Filter filter, GrColor color, - const SkRect& srcRect, const SkRect& dstRect, const SkMatrix& viewMatrix, + const SkRect& srcRect, const SkRect& dstRect, GrAA aa, const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform> csxf, bool allowSRGBInputs) : INHERITED(ClassID()) , fColorSpaceXform(std::move(csxf)) , fProxy0(proxy.release()) , fFilter0(filter) , fProxyCnt(1) - , fFinalized(false) - , fAllowSRGBInputs(allowSRGBInputs) { + , fAA(aa == GrAA::kYes ? 1 : 0) + , fFinalized(0) + , fAllowSRGBInputs(allowSRGBInputs ? 1 : 0) { Draw& draw = fDraws.push_back(); draw.fSrcRect = srcRect; draw.fTextureIdx = 0; @@ -339,7 +522,7 @@ __attribute__((no_sanitize("float-cast-overflow"))) sk_sp<GrGeometryProcessor> gp = TextureGeometryProcessor::Make(proxiesSPs, fProxyCnt, std::move(fColorSpaceXform), - filters, *target->caps().shaderCaps()); + this->aa(), filters, *target->caps().shaderCaps()); GrPipeline::InitArgs args; args.fProxy = target->proxy(); args.fCaps = &target->caps(); @@ -356,35 +539,28 @@ __attribute__((no_sanitize("float-cast-overflow"))) return; } if (1 == fProxyCnt) { - SkASSERT(gp->getVertexStride() == sizeof(TextureGeometryProcessor::Vertex)); - for (int i = 0; i < fDraws.count(); ++i) { + GrSurfaceOrigin origin = proxies[0]->origin(); + GrTexture* texture = proxies[0]->priv().peekTexture(); + float iw = 1.f / texture->width(); + float ih = 1.f / texture->height(); + if (GrAA::kYes == this->aa()) { + SkASSERT(gp->getVertexStride() == sizeof(TextureGeometryProcessor::AAVertex)); + auto vertices = static_cast<TextureGeometryProcessor::AAVertex*>(vdata); + for (int i = 0; i < fDraws.count(); ++i) { + tessellate_quad<TextureGeometryProcessor::AAVertex, false, GrAA::kYes>( + fDraws[i].fQuad, fDraws[i].fSrcRect, fDraws[i].fColor, origin, + vertices + 4 * i, iw, ih, 0); + } + } else { + SkASSERT(gp->getVertexStride() == sizeof(TextureGeometryProcessor::Vertex)); auto vertices = static_cast<TextureGeometryProcessor::Vertex*>(vdata); - GrTexture* texture = proxies[0]->priv().peekTexture(); - float iw = 1.f / texture->width(); - float ih = 1.f / texture->height(); - float tl = iw * fDraws[i].fSrcRect.fLeft; - float tr = iw * fDraws[i].fSrcRect.fRight; - float tt = ih * fDraws[i].fSrcRect.fTop; - float tb = ih * fDraws[i].fSrcRect.fBottom; - if (proxies[0]->origin() == kBottomLeft_GrSurfaceOrigin) { - tt = 1.f - tt; - tb = 1.f - tb; + for (int i = 0; i < fDraws.count(); ++i) { + tessellate_quad<TextureGeometryProcessor::Vertex, false, GrAA::kNo>( + fDraws[i].fQuad, fDraws[i].fSrcRect, fDraws[i].fColor, origin, + vertices + 4 * i, iw, ih, 0); } - vertices[0 + 4 * i].fPosition = fDraws[i].fQuad.points()[0]; - vertices[0 + 4 * i].fTextureCoords = {tl, tt}; - vertices[0 + 4 * i].fColor = fDraws[i].fColor; - vertices[1 + 4 * i].fPosition = fDraws[i].fQuad.points()[1]; - vertices[1 + 4 * i].fTextureCoords = {tl, tb}; - vertices[1 + 4 * i].fColor = fDraws[i].fColor; - vertices[2 + 4 * i].fPosition = fDraws[i].fQuad.points()[2]; - vertices[2 + 4 * i].fTextureCoords = {tr, tt}; - vertices[2 + 4 * i].fColor = fDraws[i].fColor; - vertices[3 + 4 * i].fPosition = fDraws[i].fQuad.points()[3]; - vertices[3 + 4 * i].fTextureCoords = {tr, tb}; - vertices[3 + 4 * i].fColor = fDraws[i].fColor; } } else { - SkASSERT(gp->getVertexStride() == sizeof(TextureGeometryProcessor::MultiTextureVertex)); GrTexture* textures[kMaxTextures]; float iw[kMaxTextures]; float ih[kMaxTextures]; @@ -393,33 +569,29 @@ __attribute__((no_sanitize("float-cast-overflow"))) iw[t] = 1.f / textures[t]->width(); ih[t] = 1.f / textures[t]->height(); } - for (int i = 0; i < fDraws.count(); ++i) { - int t = fDraws[i].fTextureIdx; + if (GrAA::kYes == this->aa()) { + SkASSERT(gp->getVertexStride() == + sizeof(TextureGeometryProcessor::AAMultiTextureVertex)); + auto vertices = static_cast<TextureGeometryProcessor::AAMultiTextureVertex*>(vdata); + for (int i = 0; i < fDraws.count(); ++i) { + auto tidx = fDraws[i].fTextureIdx; + GrSurfaceOrigin origin = proxies[tidx]->origin(); + tessellate_quad<TextureGeometryProcessor::AAMultiTextureVertex, true, + GrAA::kYes>(fDraws[i].fQuad, fDraws[i].fSrcRect, + fDraws[i].fColor, origin, vertices + 4 * i, + iw[tidx], ih[tidx], tidx); + } + } else { + SkASSERT(gp->getVertexStride() == + sizeof(TextureGeometryProcessor::MultiTextureVertex)); auto vertices = static_cast<TextureGeometryProcessor::MultiTextureVertex*>(vdata); - float tl = iw[t] * fDraws[i].fSrcRect.fLeft; - float tr = iw[t] * fDraws[i].fSrcRect.fRight; - float tt = ih[t] * fDraws[i].fSrcRect.fTop; - float tb = ih[t] * fDraws[i].fSrcRect.fBottom; - if (proxies[t]->origin() == kBottomLeft_GrSurfaceOrigin) { - tt = 1.f - tt; - tb = 1.f - tb; + for (int i = 0; i < fDraws.count(); ++i) { + auto tidx = fDraws[i].fTextureIdx; + GrSurfaceOrigin origin = proxies[tidx]->origin(); + tessellate_quad<TextureGeometryProcessor::MultiTextureVertex, true, GrAA::kNo>( + fDraws[i].fQuad, fDraws[i].fSrcRect, fDraws[i].fColor, origin, + vertices + 4 * i, iw[tidx], ih[tidx], tidx); } - vertices[0 + 4 * i].fPosition = fDraws[i].fQuad.points()[0]; - vertices[0 + 4 * i].fTextureIdx = t; - vertices[0 + 4 * i].fTextureCoords = {tl, tt}; - vertices[0 + 4 * i].fColor = fDraws[i].fColor; - vertices[1 + 4 * i].fPosition = fDraws[i].fQuad.points()[1]; - vertices[1 + 4 * i].fTextureIdx = t; - vertices[1 + 4 * i].fTextureCoords = {tl, tb}; - vertices[1 + 4 * i].fColor = fDraws[i].fColor; - vertices[2 + 4 * i].fPosition = fDraws[i].fQuad.points()[2]; - vertices[2 + 4 * i].fTextureIdx = t; - vertices[2 + 4 * i].fTextureCoords = {tr, tt}; - vertices[2 + 4 * i].fColor = fDraws[i].fColor; - vertices[3 + 4 * i].fPosition = fDraws[i].fQuad.points()[3]; - vertices[3 + 4 * i].fTextureIdx = t; - vertices[3 + 4 * i].fTextureCoords = {tr, tb}; - vertices[3 + 4 * i].fColor = fDraws[i].fColor; } } GrPrimitiveType primitiveType = @@ -446,6 +618,9 @@ __attribute__((no_sanitize("float-cast-overflow"))) if (!GrColorSpaceXform::Equals(fColorSpaceXform.get(), that->fColorSpaceXform.get())) { return false; } + if (this->fAA != that->fAA) { + return false; + } // Because of an issue where GrColorSpaceXform adds the same function every time it is used // in a texture lookup, we only allow multiple textures when there is no transform. if (TextureGeometryProcessor::SupportsMultitexture(shaderCaps) && !fColorSpaceXform && @@ -560,6 +735,8 @@ __attribute__((no_sanitize("float-cast-overflow"))) return newProxyCnt; } + GrAA aa() const { return static_cast<GrAA>(fAA); } + GrTextureProxy* const* proxies() const { return fProxyCnt > 1 ? fProxyArray : &fProxy0; } const GrSamplerState::Filter* filters() const { @@ -585,12 +762,12 @@ __attribute__((no_sanitize("float-cast-overflow"))) GrTextureProxy** fProxyArray; }; size_t fMaxApproxDstPixelArea; - // The next four members should pack. GrSamplerState::Filter fFilter0; uint8_t fProxyCnt; + unsigned fAA : 1; // Used to track whether fProxy is ref'ed or has a pending IO after finalize() is called. - uint8_t fFinalized; - uint8_t fAllowSRGBInputs; + unsigned fFinalized : 1; + unsigned fAllowSRGBInputs : 1; typedef GrMeshDrawOp INHERITED; }; @@ -603,11 +780,11 @@ constexpr int TextureOp::kMaxTextures; namespace GrTextureOp { std::unique_ptr<GrDrawOp> Make(sk_sp<GrTextureProxy> proxy, GrSamplerState::Filter filter, - GrColor color, const SkRect& srcRect, const SkRect& dstRect, + GrColor color, const SkRect& srcRect, const SkRect& dstRect, GrAA aa, const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform> csxf, bool allowSRGBInputs) { SkASSERT(!viewMatrix.hasPerspective()); - return TextureOp::Make(std::move(proxy), filter, color, srcRect, dstRect, viewMatrix, + return TextureOp::Make(std::move(proxy), filter, color, srcRect, dstRect, aa, viewMatrix, std::move(csxf), allowSRGBInputs); } @@ -639,7 +816,8 @@ GR_DRAW_OP_TEST_DEFINE(TextureOp) { static_cast<uint32_t>(GrSamplerState::Filter::kMipMap) + 1); auto csxf = GrTest::TestColorXform(random); bool allowSRGBInputs = random->nextBool(); - return GrTextureOp::Make(std::move(proxy), filter, color, srcRect, rect, viewMatrix, + GrAA aa = GrAA(random->nextBool()); + return GrTextureOp::Make(std::move(proxy), filter, color, srcRect, rect, aa, viewMatrix, std::move(csxf), allowSRGBInputs); } diff --git a/src/gpu/ops/GrTextureOp.h b/src/gpu/ops/GrTextureOp.h index d5a766b30f..9a03c8c6e1 100644 --- a/src/gpu/ops/GrTextureOp.h +++ b/src/gpu/ops/GrTextureOp.h @@ -23,7 +23,7 @@ namespace GrTextureOp { * space. 'viewMatrix' must be affine. */ std::unique_ptr<GrDrawOp> Make(sk_sp<GrTextureProxy>, GrSamplerState::Filter, GrColor, - const SkRect& srcRect, const SkRect& dstRect, + const SkRect& srcRect, const SkRect& dstRect, GrAA aa, const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform>, bool allowSRGBInputs); } |