From 3ebd354730ea9590bf233deccfc24982ffe48a98 Mon Sep 17 00:00:00 2001 From: Brian Osman Date: Mon, 30 Jul 2018 14:36:53 -0400 Subject: For TextureOp + Alpha texture, xform paint color to dest color space This is an unfortunate amount of plumbing for this, but benchmarks confirm that we're better off doing this work in the vertex shader (with a ubyte attribute) than using a float4 attribute. Change-Id: I358d330ee452ea0a89cdd725019c8df2686036a0 Reviewed-on: https://skia-review.googlesource.com/144351 Reviewed-by: Brian Salomon Commit-Queue: Brian Osman --- src/gpu/GrRenderTargetContext.cpp | 6 +- src/gpu/GrRenderTargetContext.h | 2 +- src/gpu/SkGpuDevice_drawTexture.cpp | 18 ++++-- src/gpu/ops/GrTextureOp.cpp | 110 ++++++++++++++++++++++++------------ src/gpu/ops/GrTextureOp.h | 3 +- 5 files changed, 93 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index 7d88bc4936..a67e19a9d9 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -764,7 +764,8 @@ void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_sp colorSpaceXform) { + sk_sp textureColorSpaceXform, + sk_sp paintColorSpaceXform) { ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) @@ -790,7 +791,8 @@ void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_spaddDrawOp(clip, GrTextureOp::Make(fContext, std::move(proxy), filter, color, clippedSrcRect, clippedDstRect, aaType, constraint, - viewMatrix, std::move(colorSpaceXform))); + viewMatrix, std::move(textureColorSpaceXform), + std::move(paintColorSpaceXform))); } void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip, diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h index 565a2b8c08..4e31a1a45d 100644 --- a/src/gpu/GrRenderTargetContext.h +++ b/src/gpu/GrRenderTargetContext.h @@ -148,7 +148,7 @@ public: void drawTexture(const GrClip& clip, sk_sp, GrSamplerState::Filter, GrColor, const SkRect& srcRect, const SkRect& dstRect, GrAA aa, SkCanvas::SrcRectConstraint, const SkMatrix& viewMatrix, - sk_sp); + sk_sp texXform, sk_sp colorXform); /** * Draw a roundrect using a paint. diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp index af397cd431..9b2641ea83 100644 --- a/src/gpu/SkGpuDevice_drawTexture.cpp +++ b/src/gpu/SkGpuDevice_drawTexture.cpp @@ -99,7 +99,6 @@ static bool can_use_draw_texture(const SkPaint& paint) { static void draw_texture(const SkPaint& paint, const SkMatrix& ctm, const SkRect* src, 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()); @@ -111,7 +110,7 @@ static void draw_texture(const SkPaint& paint, const SkMatrix& ctm, const SkRect SkAssertResult(srcRect.intersect(SkRect::MakeIWH(proxy->width(), proxy->height()))); srcToDst.mapRect(&dstRect, srcRect); } - auto csxf = GrColorSpaceXform::Make(colorSpace, rtc->colorSpaceInfo().colorSpace()); + auto textureXform = GrColorSpaceXform::Make(colorSpace, rtc->colorSpaceInfo().colorSpace()); GrSamplerState::Filter filter; switch (paint.getFilterQuality()) { case kNone_SkFilterQuality: @@ -124,11 +123,18 @@ static void draw_texture(const SkPaint& paint, const SkMatrix& ctm, const SkRect case kHigh_SkFilterQuality: SK_ABORT("Quality level not allowed."); } - GrColor color = GrPixelConfigIsAlphaOnly(proxy->config()) - ? SkColorToPremulGrColor(paint.getColor()) - : SkColorAlphaToGrColor(paint.getColor()); + GrColor color; + sk_sp paintColorXform = nullptr; + if (GrPixelConfigIsAlphaOnly(proxy->config())) { + // Leave the color unpremul if we're going to transform it in the vertex shader + paintColorXform = rtc->colorSpaceInfo().refColorSpaceXformFromSRGB(); + color = paintColorXform ? SkColorToUnpremulGrColor(paint.getColor()) + : SkColorToPremulGrColor(paint.getColor()); + } else { + color = SkColorAlphaToGrColor(paint.getColor()); + } rtc->drawTexture(clip, std::move(proxy), filter, color, srcRect, dstRect, aa, constraint, ctm, - std::move(csxf)); + std::move(textureXform), std::move(paintColorXform)); } ////////////////////////////////////////////////////////////////////////////// diff --git a/src/gpu/ops/GrTextureOp.cpp b/src/gpu/ops/GrTextureOp.cpp index 99ecdf8101..516cee628f 100644 --- a/src/gpu/ops/GrTextureOp.cpp +++ b/src/gpu/ops/GrTextureOp.cpp @@ -105,7 +105,9 @@ public: } static sk_sp Make(sk_sp proxies[], int proxyCnt, - sk_sp csxf, bool coverageAA, + sk_sp textureColorSpaceXform, + sk_sp paintColorSpaceXform, + bool coverageAA, bool perspective, Domain domain, const GrSamplerState::Filter filters[], const GrShaderCaps& caps) { @@ -115,7 +117,9 @@ public: size_t size = sizeof(TextureGeometryProcessor) + sizeof(TextureSampler) * (samplerCnt - 1); void* mem = GrGeometryProcessor::operator new(size); return sk_sp( - new (mem) TextureGeometryProcessor(proxies, proxyCnt, samplerCnt, std::move(csxf), + new (mem) TextureGeometryProcessor(proxies, proxyCnt, samplerCnt, + std::move(textureColorSpaceXform), + std::move(paintColorSpaceXform), coverageAA, perspective, domain, filters, caps)); } @@ -129,7 +133,8 @@ public: const char* name() const override { return "TextureGeometryProcessor"; } void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { - b->add32(GrColorSpaceXform::XformKey(fColorSpaceXform.get())); + b->add32(GrColorSpaceXform::XformKey(fTextureColorSpaceXform.get())); + b->add32(GrColorSpaceXform::XformKey(fPaintColorSpaceXform.get())); uint32_t x = this->usesCoverageEdgeAA() ? 0 : 1; x |= kFloat3_GrVertexAttribType == fPositions.type() ? 0 : 2; x |= fDomain.isInitialized() ? 4 : 0; @@ -143,15 +148,20 @@ public: FPCoordTransformIter&& transformIter) override { const auto& textureGP = proc.cast(); this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter); - fColorSpaceXformHelper.setData(pdman, textureGP.fColorSpaceXform.get()); + fTextureColorSpaceXformHelper.setData( + pdman, textureGP.fTextureColorSpaceXform.get()); + fPaintColorSpaceXformHelper.setData(pdman, textureGP.fPaintColorSpaceXform.get()); } private: void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { using Interpolation = GrGLSLVaryingHandler::Interpolation; const auto& textureGP = args.fGP.cast(); - fColorSpaceXformHelper.emitCode( - args.fUniformHandler, textureGP.fColorSpaceXform.get()); + fTextureColorSpaceXformHelper.emitCode( + args.fUniformHandler, textureGP.fTextureColorSpaceXform.get()); + fPaintColorSpaceXformHelper.emitCode( + args.fUniformHandler, textureGP.fPaintColorSpaceXform.get(), + kVertex_GrShaderFlag); if (kFloat2_GrVertexAttribType == textureGP.fPositions.type()) { args.fVaryingHandler->setNoPerspective(); } @@ -163,8 +173,20 @@ public: args.fUniformHandler, textureGP.fTextureCoords.asShaderVar(), args.fFPCoordTransformHandler); - args.fVaryingHandler->addPassThroughAttribute( - textureGP.fColors, args.fOutputColor, Interpolation::kCanBeFlat); + if (fPaintColorSpaceXformHelper.isNoop()) { + args.fVaryingHandler->addPassThroughAttribute( + textureGP.fColors, args.fOutputColor, Interpolation::kCanBeFlat); + } else { + GrGLSLVarying varying(kHalf4_GrSLType); + args.fVaryingHandler->addVarying("color", &varying); + args.fVertBuilder->codeAppend("half4 color = "); + args.fVertBuilder->appendColorGamutXform(textureGP.fColors.name(), + &fPaintColorSpaceXformHelper); + args.fVertBuilder->codeAppend(";"); + args.fVertBuilder->codeAppendf("%s = half4(color.rgb * color.a, color.a);", + varying.vsOut()); + args.fFragBuilder->codeAppendf("%s = %s;", args.fOutputColor, varying.fsIn()); + } args.fFragBuilder->codeAppend("float2 texCoord;"); args.fVaryingHandler->addPassThroughAttribute(textureGP.fTextureCoords, "texCoord"); if (textureGP.fDomain.isInitialized()) { @@ -185,21 +207,17 @@ public: args.fFragBuilder->codeAppend("switch (texIdx) {"); for (int i = 0; i < textureGP.numTextureSamplers(); ++i) { args.fFragBuilder->codeAppendf("case %d: %s = ", i, args.fOutputColor); - args.fFragBuilder->appendTextureLookupAndModulate(args.fOutputColor, - args.fTexSamplers[i], - "texCoord", - kFloat2_GrSLType, - &fColorSpaceXformHelper); + args.fFragBuilder->appendTextureLookupAndModulate( + args.fOutputColor, args.fTexSamplers[i], "texCoord", + kFloat2_GrSLType, &fTextureColorSpaceXformHelper); args.fFragBuilder->codeAppend("; break;"); } args.fFragBuilder->codeAppend("}"); } else { args.fFragBuilder->codeAppendf("%s = ", args.fOutputColor); - args.fFragBuilder->appendTextureLookupAndModulate(args.fOutputColor, - args.fTexSamplers[0], - "texCoord", - kFloat2_GrSLType, - &fColorSpaceXformHelper); + args.fFragBuilder->appendTextureLookupAndModulate( + args.fOutputColor, args.fTexSamplers[0], "texCoord", + kFloat2_GrSLType, &fTextureColorSpaceXformHelper); } args.fFragBuilder->codeAppend(";"); if (textureGP.usesCoverageEdgeAA()) { @@ -244,7 +262,8 @@ public: args.fFragBuilder->codeAppendf("%s = float4(1);", args.fOutputCoverage); } } - GrGLSLColorSpaceXformHelper fColorSpaceXformHelper; + GrGLSLColorSpaceXformHelper fTextureColorSpaceXformHelper; + GrGLSLColorSpaceXformHelper fPaintColorSpaceXformHelper; }; return new GLSLProcessor; } @@ -268,10 +287,13 @@ private: } TextureGeometryProcessor(sk_sp proxies[], int proxyCnt, int samplerCnt, - sk_sp csxf, bool coverageAA, bool perspective, - Domain domain, const GrSamplerState::Filter filters[], - const GrShaderCaps& caps) - : INHERITED(kTextureGeometryProcessor_ClassID), fColorSpaceXform(std::move(csxf)) { + sk_sp textureColorSpaceXform, + sk_sp paintColorSpaceXform, + bool coverageAA, bool perspective, Domain domain, + const GrSamplerState::Filter filters[], const GrShaderCaps& caps) + : INHERITED(kTextureGeometryProcessor_ClassID) + , fTextureColorSpaceXform(std::move(textureColorSpaceXform)) + , fPaintColorSpaceXform(std::move(paintColorSpaceXform)) { SkASSERT(proxyCnt > 0 && samplerCnt >= proxyCnt); fSamplers[0].reset(std::move(proxies[0]), filters[0]); this->addTextureSampler(&fSamplers[0]); @@ -328,7 +350,8 @@ private: Attribute fTextureIdx; Attribute fDomain; Attribute fAAEdges[4]; - sk_sp fColorSpaceXform; + sk_sp fTextureColorSpaceXform; + sk_sp fPaintColorSpaceXform; TextureSampler fSamplers[1]; typedef GrGeometryProcessor INHERITED; @@ -597,12 +620,14 @@ public: GrAAType aaType, SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix, - sk_sp csxf) { + sk_sp textureColorSpaceXform, + sk_sp paintColorSpaceXform) { GrOpMemoryPool* pool = context->contextPriv().opMemoryPool(); return pool->allocate(std::move(proxy), filter, color, srcRect, dstRect, aaType, constraint, - viewMatrix, std::move(csxf)); + viewMatrix, std::move(textureColorSpaceXform), + std::move(paintColorSpaceXform)); } ~TextureOp() override { @@ -685,9 +710,11 @@ __attribute__((no_sanitize("float-cast-overflow"))) TextureOp(sk_sp proxy, GrSamplerState::Filter filter, GrColor color, const SkRect& srcRect, const SkRect& dstRect, GrAAType aaType, SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix, - sk_sp csxf) + sk_sp textureColorSpaceXform, + sk_sp paintColorSpaceXform) : INHERITED(ClassID()) - , fColorSpaceXform(std::move(csxf)) + , fTextureColorSpaceXform(std::move(textureColorSpaceXform)) + , fPaintColorSpaceXform(std::move(paintColorSpaceXform)) , fProxy0(proxy.release()) , fFilter0(filter) , fProxyCnt(1) @@ -750,7 +777,8 @@ __attribute__((no_sanitize("float-cast-overflow"))) 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, + proxiesSPs, fProxyCnt, std::move(fTextureColorSpaceXform), + std::move(fPaintColorSpaceXform), coverageAA, fPerspective, domain, filters, *target->caps().shaderCaps()); GrPipeline::InitArgs args; args.fProxy = target->proxy(); @@ -842,7 +870,12 @@ __attribute__((no_sanitize("float-cast-overflow"))) bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { const auto* that = t->cast(); const auto& shaderCaps = *caps.shaderCaps(); - if (!GrColorSpaceXform::Equals(fColorSpaceXform.get(), that->fColorSpaceXform.get())) { + if (!GrColorSpaceXform::Equals(fTextureColorSpaceXform.get(), + that->fTextureColorSpaceXform.get())) { + return false; + } + if (!GrColorSpaceXform::Equals(fPaintColorSpaceXform.get(), + that->fPaintColorSpaceXform.get())) { return false; } if (this->aaType() != that->aaType()) { @@ -850,7 +883,8 @@ __attribute__((no_sanitize("float-cast-overflow"))) } // 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 && + if (TextureGeometryProcessor::SupportsMultitexture(shaderCaps) && + !fTextureColorSpaceXform && fMaxApproxDstPixelArea <= shaderCaps.disableImageMultitexturingDstRectAreaThreshold() && that->fMaxApproxDstPixelArea <= shaderCaps.disableImageMultitexturingDstRectAreaThreshold()) { @@ -999,7 +1033,8 @@ __attribute__((no_sanitize("float-cast-overflow"))) GrColor fColor; }; SkSTArray<1, Draw, true> fDraws; - sk_sp fColorSpaceXform; + sk_sp fTextureColorSpaceXform; + sk_sp fPaintColorSpaceXform; // Initially we store a single proxy ptr and a single filter. If we grow to have more than // one proxy we instead store pointers to dynamically allocated arrays of size kMaxTextures // followed by kMaxTextures filters. @@ -1035,9 +1070,11 @@ std::unique_ptr Make(GrContext* context, GrAAType aaType, SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix, - sk_sp csxf) { + sk_sp textureColorSpaceXform, + sk_sp paintColorSpaceXform) { return TextureOp::Make(context, std::move(proxy), filter, color, srcRect, dstRect, aaType, - constraint, viewMatrix, std::move(csxf)); + constraint, viewMatrix, std::move(textureColorSpaceXform), + std::move(paintColorSpaceXform)); } } // namespace GrTextureOp @@ -1078,7 +1115,8 @@ GR_DRAW_OP_TEST_DEFINE(TextureOp) { filter = (GrSamplerState::Filter)random->nextULessThan( static_cast(GrSamplerState::Filter::kMipMap) + 1); } - auto csxf = GrTest::TestColorXform(random); + auto texXform = GrTest::TestColorXform(random); + auto paintXform = GrTest::TestColorXform(random); GrAAType aaType = GrAAType::kNone; if (random->nextBool()) { aaType = (fsaaType == GrFSAAType::kUnifiedMSAA) ? GrAAType::kMSAA : GrAAType::kCoverage; @@ -1086,7 +1124,7 @@ GR_DRAW_OP_TEST_DEFINE(TextureOp) { auto constraint = random->nextBool() ? SkCanvas::kStrict_SrcRectConstraint : SkCanvas::kFast_SrcRectConstraint; return GrTextureOp::Make(context, std::move(proxy), filter, color, srcRect, rect, aaType, - constraint, viewMatrix, std::move(csxf)); + constraint, viewMatrix, std::move(texXform), std::move(paintXform)); } #endif diff --git a/src/gpu/ops/GrTextureOp.h b/src/gpu/ops/GrTextureOp.h index 7211b5edc2..96cbc70cb8 100644 --- a/src/gpu/ops/GrTextureOp.h +++ b/src/gpu/ops/GrTextureOp.h @@ -34,5 +34,6 @@ std::unique_ptr Make(GrContext*, GrAAType, SkCanvas::SrcRectConstraint, const SkMatrix& viewMatrix, - sk_sp); + sk_sp textureXform, + sk_sp paintXform); } -- cgit v1.2.3