Handle F16Norm clamping in SkPaint->GrPaint conversion.

Previously this clamping was inserted by the program builder.

Adds GrSaturateProcessor to handle saturating in the fragment shader.

Clamp the GrPaint color rather than using a fp when possible.

Has to be plumbed through GrTextureOp because that skips SkPaint
conversion.

Removes a usage of GrPixelConfig.

Bug: skia:6718
Change-Id: Ifa6544496d34677f17e797433e6ef3a97be5c2b2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/242558
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Brian Salomon 2019-09-18 15:54:26 -04:00 committed by Skia Commit-Bot
parent ea869c6c5d
commit f19f9caab2
16 changed files with 253 additions and 83 deletions

View File

@ -388,6 +388,8 @@ skia_gpu_sources = [
"$_src/gpu/effects/generated/GrRectBlurEffect.h",
"$_src/gpu/effects/generated/GrRRectBlurEffect.cpp",
"$_src/gpu/effects/generated/GrRRectBlurEffect.h",
"$_src/gpu/effects/generated/GrSaturateProcessor.cpp",
"$_src/gpu/effects/generated/GrSaturateProcessor.h",
"$_src/gpu/effects/generated/GrSimpleTextureEffect.cpp",
"$_src/gpu/effects/generated/GrSimpleTextureEffect.h",

View File

@ -55,6 +55,7 @@ skia_gpu_processor_sources = [
"$_src/gpu/effects/GrPremulInputFragmentProcessor.fp",
"$_src/gpu/effects/GrRectBlurEffect.fp",
"$_src/gpu/effects/GrRRectBlurEffect.fp",
"$_src/gpu/effects/GrSaturateProcessor.fp",
"$_src/gpu/effects/GrSimpleTextureEffect.fp",
"$_src/gpu/gradients/GrDualIntervalGradientColorizer.fp",
"$_src/gpu/gradients/GrSingleIntervalGradientColorizer.fp",

View File

@ -57,7 +57,7 @@ SkTArray<GrXPFactoryTestFactory*, true>* GrXPFactoryTestFactory::GetFactories()
* manually adjusted.
*/
#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
static const int kFPFactoryCount = 36;
static const int kFPFactoryCount = 37;
static const int kGPFactoryCount = 14;
static const int kXPFactoryCount = 4;
#else

View File

@ -77,14 +77,12 @@ public:
kDefaultGeoProc_ClassID,
kDIEllipseGeometryProcessor_ClassID,
kDisableColorXP_ClassID,
kTwoPointConicalEffect_ClassID,
kEllipseGeometryProcessor_ClassID,
kEllipticalRRectEffect_ClassID,
kGP_ClassID,
kVertexColorSpaceBenchGP_ClassID,
kGrAARectEffect_ClassID,
kGrAlphaThresholdFragmentProcessor_ClassID,
kGrArithmeticFP_ClassID,
kGrBicubicEffect_ClassID,
kGrBitmapTextGeoProc_ClassID,
kGrBlurredEdgeFragmentProcessor_ClassID,
@ -107,16 +105,12 @@ public:
kGrDistanceFieldA8TextGeoProc_ClassID,
kGrDistanceFieldLCDTextGeoProc_ClassID,
kGrDistanceFieldPathGeoProc_ClassID,
kGrDitherEffect_ClassID,
kGrDualIntervalGradientColorizer_ClassID,
kGrEllipseEffect_ClassID,
kGrFillRRectOp_Processor_ClassID,
kGrGaussianConvolutionFragmentProcessor_ClassID,
kGrGSCoverageProcessor_ClassID,
kGrImprovedPerlinNoiseEffect_ClassID,
kGrIncrDecrWindingCountXP_ClassID,
kGrLightingEffect_ClassID,
kGrLinearGradient_ClassID,
kGrLinearGradientLayout_ClassID,
kGrLumaColorFilterEffect_ClassID,
kGrMagnifierEffect_ClassID,
@ -124,47 +118,38 @@ public:
kGrMeshTestProcessor_ClassID,
kGrMorphologyEffect_ClassID,
kGrMixerEffect_ClassID,
kGrOverdrawFragmentProcessor_ClassID,
kGrOverrideInputFragmentProcessor_ClassID,
kGrPathProcessor_ClassID,
kGrPerlinNoise2Effect_ClassID,
kGrPipelineDynamicStateTestProcessor_ClassID,
kGrPremulInputFragmentProcessor_ClassID,
kGrQuadEffect_ClassID,
kGrRadialGradient_ClassID,
kGrRadialGradientLayout_ClassID,
kGrRectBlurEffect_ClassID,
kGrRRectBlurEffect_ClassID,
kGrRRectShadowGeoProc_ClassID,
kGrResolveWindingCountXP_ClassID,
kGrSimpleTextureEffect_ClassID,
kGrSingleIntervalGradientColorizer_ClassID,
kGrSkSLFP_ClassID,
kGrSpecularLightingEffect_ClassID,
kGrSRGBEffect_ClassID,
kGrSampleMaskProcessor_ClassID,
kGrSweepGradient_ClassID,
kGrSaturateProcessor_ClassID,
kGrSweepGradientLayout_ClassID,
kGrTextureDomainEffect_ClassID,
kGrTextureGradientColorizer_ClassID,
kGrTiledGradientEffect_ClassID,
kGrTwoPointConicalGradientLayout_ClassID,
kGrUnpremulInputFragmentProcessor_ClassID,
kGrUnrolledBinaryGradientColorizer_ClassID,
kGrVSCoverageProcessor_ClassID,
kGrYUVtoRGBEffect_ClassID,
kHighContrastFilterEffect_ClassID,
kInstanceProcessor_ClassID,
kLatticeGP_ClassID,
kLumaColorFilterEffect_ClassID,
kMSAAQuadProcessor_ClassID,
kPDLCDXferProcessor_ClassID,
kPorterDuffXferProcessor_ClassID,
kPremulFragmentProcessor_ClassID,
kQuadEdgeEffect_ClassID,
kQuadPerEdgeAAGeometryProcessor_ClassID,
kReplaceInputFragmentProcessor_ClassID,
kRRectsGaussianEdgeFP_ClassID,
kSampleLocationsTestProcessor_ClassID,
kSeriesFragmentProcessor_ClassID,
kShaderPDXferProcessor_ClassID,
@ -172,7 +157,6 @@ public:
kFwidthSquircleTestProcessor_ClassID,
kSwizzleFragmentProcessor_ClassID,
kTestFP_ClassID,
kTextureGeometryProcessor_ClassID,
kFlatNormalsFP_ClassID,
kMappedNormalsFP_ClassID,
kLightingFP_ClassID,

View File

@ -261,7 +261,5 @@ bool GrProgramDesc::Build(
SkASSERT(header->processorFeatures() == processorFeatures); // Ensure enough bits.
header->fSnapVerticesToPixelCenters = pipeline.snapVerticesToPixelCenters();
header->fHasPointSize = hasPointSize ? 1 : 0;
header->fClampBlendInput =
GrClampType::kManual == GrPixelConfigClampType(renderTarget->config()) ? 1 : 0;
return true;
}

View File

@ -112,8 +112,7 @@ public:
uint8_t fProcessorFeatures : 1;
bool fSnapVerticesToPixelCenters : 1;
bool fHasPointSize : 1;
bool fClampBlendInput : 1;
uint8_t fPad : 2;
uint8_t fPad : 3;
};
GR_STATIC_ASSERT(sizeof(KeyHeader) == 6);

View File

@ -5,6 +5,8 @@
* found in the LICENSE file.
*/
#include "src/gpu/GrRenderTargetContext.h"
#include "include/core/SkDrawable.h"
#include "include/gpu/GrBackendSemaphore.h"
#include "include/private/GrRecordingContext.h"
@ -32,7 +34,6 @@
#include "src/gpu/GrPathRenderer.h"
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrRenderTarget.h"
#include "src/gpu/GrRenderTargetContext.h"
#include "src/gpu/GrRenderTargetContextPriv.h"
#include "src/gpu/GrResourceProvider.h"
#include "src/gpu/GrStencilAttachment.h"
@ -676,6 +677,7 @@ void GrRenderTargetContext::drawTexturedQuad(const GrClip& clip,
ASSERT_SINGLE_OWNER
RETURN_IF_ABANDONED
SkDEBUGCODE(this->validate();)
SkASSERT(proxy);
GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "drawTexturedQuad", fContext);
AutoCheckFlush acf(this->drawingManager());
@ -693,12 +695,15 @@ void GrRenderTargetContext::drawTexturedQuad(const GrClip& clip,
const GrClip& finalClip = opt == QuadOptimization::kClipApplied ? GrFixedClip::Disabled()
: clip;
GrAAType aaType = this->chooseAAType(aa);
auto clampType = GrColorTypeClampType(this->colorSpaceInfo().colorType());
auto saturate = clampType == GrClampType::kManual ? GrTextureOp::Saturate::kYes
: GrTextureOp::Saturate::kNo;
// Use the provided domain, although hypothetically we could detect that the cropped local
// quad is sufficiently inside the domain and the constraint could be dropped.
this->addDrawOp(finalClip, GrTextureOp::Make(fContext, std::move(proxy),
std::move(textureXform), filter, color,
blendMode, aaType, edgeFlags,
croppedDeviceQuad, croppedLocalQuad, domain));
this->addDrawOp(finalClip,
GrTextureOp::Make(fContext, std::move(proxy), std::move(textureXform),
filter, color, saturate, blendMode, aaType, edgeFlags,
croppedDeviceQuad, croppedLocalQuad, domain));
}
}
@ -956,8 +961,11 @@ void GrRenderTargetContext::drawTextureSet(const GrClip& clip, const TextureSetE
// Can use a single op, avoiding GrPaint creation, and can batch across proxies
AutoCheckFlush acf(this->drawingManager());
GrAAType aaType = this->chooseAAType(aa);
auto op = GrTextureOp::MakeSet(fContext, set, cnt, filter, aaType, constraint, viewMatrix,
std::move(texXform));
auto clampType = GrColorTypeClampType(this->colorSpaceInfo().colorType());
auto saturate = clampType == GrClampType::kManual ? GrTextureOp::Saturate::kYes
: GrTextureOp::Saturate::kNo;
auto op = GrTextureOp::MakeSet(fContext, set, cnt, filter, saturate, aaType, constraint,
viewMatrix, std::move(texXform));
this->addDrawOp(clip, std::move(op));
}
}

View File

@ -5,6 +5,8 @@
* found in the LICENSE file.
*/
#include "src/gpu/SkGr.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkColorFilter.h"
#include "include/core/SkData.h"
@ -33,16 +35,15 @@
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrTextureProxy.h"
#include "src/gpu/GrXferProcessor.h"
#include "src/gpu/SkGr.h"
#include "src/gpu/effects/GrBicubicEffect.h"
#include "src/gpu/effects/GrPorterDuffXferProcessor.h"
#include "src/gpu/effects/GrSkSLFP.h"
#include "src/gpu/effects/GrXfermodeFragmentProcessor.h"
#include "src/gpu/effects/generated/GrConstColorProcessor.h"
#include "src/gpu/effects/generated/GrSaturateProcessor.h"
#include "src/image/SkImage_Base.h"
#include "src/shaders/SkShaderBase.h"
#if SK_SUPPORT_GPU
GR_FP_SRC_STRING SKSL_DITHER_SRC = R"(
// This controls the range of values added to color channels
layout(key) in int rangeType;
@ -82,7 +83,6 @@ void main(float x, float y, inout half4 color) {
color = half4(clamp(color.rgb + value * range, 0.0, color.a), color.a);
}
)";
#endif
GrSurfaceDesc GrImageInfoToSurfaceDesc(const SkImageInfo& info) {
GrSurfaceDesc desc;
@ -472,6 +472,17 @@ static inline bool skpaint_to_grpaint_impl(GrRecordingContext* context,
}
}
#endif
if (GrColorTypeClampType(colorSpaceInfo.colorType()) == GrClampType::kManual) {
if (grPaint->numColorFragmentProcessors()) {
grPaint->addColorFragmentProcessor(GrSaturateProcessor::Make());
} else {
auto color = grPaint->getColor4f();
grPaint->setColor4f({SkTPin(color.fR, 0.f, 1.f),
SkTPin(color.fG, 0.f, 1.f),
SkTPin(color.fB, 0.f, 1.f),
SkTPin(color.fA, 0.f, 1.f)});
}
}
return true;
}

View File

@ -0,0 +1,25 @@
/*
* Copyright 2019 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
@optimizationFlags {
kConstantOutputForConstantInput_OptimizationFlag |
kPreservesOpaqueInput_OptimizationFlag
}
void main() { sk_OutColor = saturate(sk_InColor); }
@class {
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
return {SkTPin(input.fR, 0.f, 1.f),
SkTPin(input.fG, 0.f, 1.f),
SkTPin(input.fB, 0.f, 1.f),
SkTPin(input.fA, 0.f, 1.f)};
}
}
@test(d) { return GrSaturateProcessor::Make(); }

View File

@ -0,0 +1,54 @@
/*
* Copyright 2019 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/**************************************************************************************************
*** This file was autogenerated from GrSaturateProcessor.fp; do not modify.
**************************************************************************************************/
#include "GrSaturateProcessor.h"
#include "include/gpu/GrTexture.h"
#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
#include "src/sksl/SkSLCPP.h"
#include "src/sksl/SkSLUtil.h"
class GrGLSLSaturateProcessor : public GrGLSLFragmentProcessor {
public:
GrGLSLSaturateProcessor() {}
void emitCode(EmitArgs& args) override {
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
const GrSaturateProcessor& _outer = args.fFp.cast<GrSaturateProcessor>();
(void)_outer;
fragBuilder->codeAppendf("%s = clamp(%s, 0.0, 1.0);\n", args.fOutputColor,
args.fInputColor);
}
private:
void onSetData(const GrGLSLProgramDataManager& pdman,
const GrFragmentProcessor& _proc) override {}
};
GrGLSLFragmentProcessor* GrSaturateProcessor::onCreateGLSLInstance() const {
return new GrGLSLSaturateProcessor();
}
void GrSaturateProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps,
GrProcessorKeyBuilder* b) const {}
bool GrSaturateProcessor::onIsEqual(const GrFragmentProcessor& other) const {
const GrSaturateProcessor& that = other.cast<GrSaturateProcessor>();
(void)that;
return true;
}
GrSaturateProcessor::GrSaturateProcessor(const GrSaturateProcessor& src)
: INHERITED(kGrSaturateProcessor_ClassID, src.optimizationFlags()) {}
std::unique_ptr<GrFragmentProcessor> GrSaturateProcessor::clone() const {
return std::unique_ptr<GrFragmentProcessor>(new GrSaturateProcessor(*this));
}
GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSaturateProcessor);
#if GR_TEST_UTILS
std::unique_ptr<GrFragmentProcessor> GrSaturateProcessor::TestCreate(GrProcessorTestData* d) {
return GrSaturateProcessor::Make();
}
#endif

View File

@ -0,0 +1,41 @@
/*
* Copyright 2019 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/**************************************************************************************************
*** This file was autogenerated from GrSaturateProcessor.fp; do not modify.
**************************************************************************************************/
#ifndef GrSaturateProcessor_DEFINED
#define GrSaturateProcessor_DEFINED
#include "include/core/SkTypes.h"
#include "src/gpu/GrCoordTransform.h"
#include "src/gpu/GrFragmentProcessor.h"
class GrSaturateProcessor : public GrFragmentProcessor {
public:
SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
return {SkTPin(input.fR, 0.f, 1.f), SkTPin(input.fG, 0.f, 1.f), SkTPin(input.fB, 0.f, 1.f),
SkTPin(input.fA, 0.f, 1.f)};
}
static std::unique_ptr<GrFragmentProcessor> Make() {
return std::unique_ptr<GrFragmentProcessor>(new GrSaturateProcessor());
}
GrSaturateProcessor(const GrSaturateProcessor& src);
std::unique_ptr<GrFragmentProcessor> clone() const override;
const char* name() const override { return "SaturateProcessor"; }
private:
GrSaturateProcessor()
: INHERITED(kGrSaturateProcessor_ClassID,
(OptimizationFlags)kConstantOutputForConstantInput_OptimizationFlag |
kPreservesOpaqueInput_OptimizationFlag) {}
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
bool onIsEqual(const GrFragmentProcessor&) const override;
GR_DECLARE_FRAGMENT_PROCESSOR_TEST
typedef GrFragmentProcessor INHERITED;
};
#endif

View File

@ -255,16 +255,7 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const SkString& colorIn,
SkASSERT(dstTexture->texturePriv().textureType() != GrTextureType::kExternal);
}
SkString finalInColor;
if (colorIn.size()) {
if (this->desc()->header().fClampBlendInput) {
finalInColor.printf("saturate(%s)", colorIn.c_str());
} else {
finalInColor = colorIn;
}
} else {
finalInColor = "float4(1)";
}
SkString finalInColor = colorIn.size() ? colorIn : SkString("float4(1)");
GrGLSLXferProcessor::EmitArgs args(&fFS,
this->uniformHandler(),

View File

@ -850,6 +850,7 @@ int VertexSpec::localDimensionality() const {
class QuadPerEdgeAAGeometryProcessor : public GrGeometryProcessor {
public:
using Saturate = GrTextureOp::Saturate;
static sk_sp<GrGeometryProcessor> Make(const VertexSpec& spec) {
return sk_sp<QuadPerEdgeAAGeometryProcessor>(new QuadPerEdgeAAGeometryProcessor(spec));
@ -859,33 +860,36 @@ public:
GrTextureType textureType,
const GrSamplerState& samplerState,
const GrSwizzle& swizzle, uint32_t extraSamplerKey,
sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
Saturate saturate) {
return sk_sp<QuadPerEdgeAAGeometryProcessor>(new QuadPerEdgeAAGeometryProcessor(
vertexSpec, caps, textureType, samplerState, swizzle, extraSamplerKey,
std::move(textureColorSpaceXform)));
std::move(textureColorSpaceXform), saturate));
}
const char* name() const override { return "QuadPerEdgeAAGeometryProcessor"; }
void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
// texturing, device-dimensions are single bit flags
uint32_t x = fTexDomain.isInitialized() ? 0 : 1;
x |= fSampler.isInitialized() ? 0 : 2;
x |= fNeedsPerspective ? 0 : 4;
uint32_t x = (fTexDomain.isInitialized() ? 0 : 0x1)
| (fSampler.isInitialized() ? 0 : 0x2)
| (fNeedsPerspective ? 0 : 0x4)
| (fSaturate == Saturate::kNo ? 0 : 0x8);
// local coords require 2 bits (3 choices), 00 for none, 01 for 2d, 10 for 3d
if (fLocalCoord.isInitialized()) {
x |= kFloat3_GrVertexAttribType == fLocalCoord.cpuType() ? 8 : 16;
x |= kFloat3_GrVertexAttribType == fLocalCoord.cpuType() ? 0x10 : 0x20;
}
// similar for colors, 00 for none, 01 for bytes, 10 for half-floats
if (fColor.isInitialized()) {
x |= kUByte4_norm_GrVertexAttribType == fColor.cpuType() ? 32 : 64;
x |= kUByte4_norm_GrVertexAttribType == fColor.cpuType() ? 0x40 : 0x80;
}
// and coverage mode, 00 for none, 01 for withposition, 10 for withcolor, 11 for
// position+geomdomain
SkASSERT(!fGeomDomain.isInitialized() || fCoverageMode == CoverageMode::kWithPosition);
if (fCoverageMode != CoverageMode::kNone) {
x |= fGeomDomain.isInitialized() ?
384 : (CoverageMode::kWithPosition == fCoverageMode ? 128 : 256);
x |= fGeomDomain.isInitialized()
? 0x300
: (CoverageMode::kWithPosition == fCoverageMode ? 0x100 : 0x200);
}
b->add32(GrColorSpaceXform::XformKey(fTextureColorSpaceXform.get()));
@ -990,6 +994,14 @@ public:
args.fOutputColor, args.fTexSamplers[0], "texCoord", kFloat2_GrSLType,
&fTextureColorSpaceXformHelper);
args.fFragBuilder->codeAppend(";");
if (gp.fSaturate == Saturate::kYes) {
args.fFragBuilder->codeAppendf("%s = saturate(%s);",
args.fOutputColor, args.fOutputColor);
}
} else {
// Saturate is only intended for use with a proxy to account for the fact
// that GrTextureOp skips SkPaint conversion, which normally handles this.
SkASSERT(gp.fSaturate == Saturate::kNo);
}
// And lastly, output the coverage calculation code
@ -1056,8 +1068,10 @@ private:
const GrSamplerState& samplerState,
const GrSwizzle& swizzle,
uint32_t extraSamplerKey,
sk_sp<GrColorSpaceXform> textureColorSpaceXform)
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
Saturate saturate)
: INHERITED(kQuadPerEdgeAAGeometryProcessor_ClassID)
, fSaturate(saturate)
, fTextureColorSpaceXform(std::move(textureColorSpaceXform))
, fSampler(textureType, samplerState, swizzle, extraSamplerKey) {
SkASSERT(spec.hasLocalCoords());
@ -1122,6 +1136,8 @@ private:
// The positions attribute may have coverage built into it, so float3 is an ambiguous type
// and may mean 2d with coverage, or 3d with no coverage
bool fNeedsPerspective;
// Should saturate() be called on the color? Only relevant when created with a texture.
Saturate fSaturate = Saturate::kNo;
CoverageMode fCoverageMode;
// Color space will be null and fSampler.isInitialized() returns false when the GP is configured
@ -1140,9 +1156,11 @@ sk_sp<GrGeometryProcessor> MakeTexturedProcessor(const VertexSpec& spec, const G
GrTextureType textureType,
const GrSamplerState& samplerState,
const GrSwizzle& swizzle, uint32_t extraSamplerKey,
sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
Saturate saturate) {
return QuadPerEdgeAAGeometryProcessor::Make(spec, caps, textureType, samplerState, swizzle,
extraSamplerKey, std::move(textureColorSpaceXform));
extraSamplerKey, std::move(textureColorSpaceXform),
saturate);
}
} // namespace GrQuadPerEdgeAA

View File

@ -16,12 +16,14 @@
#include "src/gpu/GrSamplerState.h"
#include "src/gpu/geometry/GrQuad.h"
#include "src/gpu/ops/GrMeshDrawOp.h"
#include "src/gpu/ops/GrTextureOp.h"
class GrCaps;
class GrColorSpaceXform;
class GrShaderCaps;
namespace GrQuadPerEdgeAA {
using Saturate = GrTextureOp::Saturate;
enum class Domain : bool { kNo = false, kYes = true };
enum class ColorType { kNone, kByte, kHalf, kLast = kHalf };
@ -84,7 +86,7 @@ namespace GrQuadPerEdgeAA {
sk_sp<GrGeometryProcessor> MakeTexturedProcessor(
const VertexSpec& spec, const GrShaderCaps& caps, GrTextureType textureType,
const GrSamplerState& samplerState, const GrSwizzle& swizzle, uint32_t extraSamplerKey,
sk_sp<GrColorSpaceXform> textureColorSpaceXform);
sk_sp<GrColorSpaceXform> textureColorSpaceXform, Saturate saturate);
// Fill vertices with the vertex data needed to represent the given quad. The device position,
// local coords, vertex color, domain, and edge coefficients will be written and/or computed

View File

@ -5,8 +5,8 @@
* found in the LICENSE file.
*/
#include "src/gpu/ops/GrTextureOp.h"
#include <new>
#include "include/core/SkPoint.h"
#include "include/core/SkPoint3.h"
#include "include/gpu/GrTexture.h"
@ -31,6 +31,7 @@
#include "src/gpu/GrTextureProxy.h"
#include "src/gpu/SkGr.h"
#include "src/gpu/effects/GrTextureDomain.h"
#include "src/gpu/effects/generated/GrSaturateProcessor.h"
#include "src/gpu/geometry/GrQuad.h"
#include "src/gpu/geometry/GrQuadBuffer.h"
#include "src/gpu/geometry/GrQuadUtils.h"
@ -38,6 +39,7 @@
#include "src/gpu/ops/GrFillRectOp.h"
#include "src/gpu/ops/GrMeshDrawOp.h"
#include "src/gpu/ops/GrQuadPerEdgeAA.h"
#include "src/gpu/ops/GrTextureOp.h"
namespace {
@ -146,28 +148,31 @@ public:
sk_sp<GrColorSpaceXform> textureXform,
GrSamplerState::Filter filter,
const SkPMColor4f& color,
GrTextureOp::Saturate saturate,
GrAAType aaType,
GrQuadAAFlags aaFlags,
const GrQuad& deviceQuad,
const GrQuad& localQuad,
const SkRect* domain) {
GrOpMemoryPool* pool = context->priv().opMemoryPool();
return pool->allocate<TextureOp>(
std::move(proxy), std::move(textureXform), filter, color, aaType, aaFlags,
deviceQuad, localQuad, domain);
return pool->allocate<TextureOp>(std::move(proxy), std::move(textureXform), filter, color,
saturate, aaType, aaFlags, deviceQuad, localQuad, domain);
}
static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
const GrRenderTargetContext::TextureSetEntry set[],
int cnt, GrSamplerState::Filter filter, GrAAType aaType,
int cnt,
GrSamplerState::Filter filter,
GrTextureOp::Saturate saturate,
GrAAType aaType,
SkCanvas::SrcRectConstraint constraint,
const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
size_t size = sizeof(TextureOp) + sizeof(Proxy) * (cnt - 1);
GrOpMemoryPool* pool = context->priv().opMemoryPool();
void* mem = pool->allocate(size);
return std::unique_ptr<GrDrawOp>(new (mem) TextureOp(
set, cnt, filter, aaType, constraint, viewMatrix,
std::move(textureColorSpaceXform)));
return std::unique_ptr<GrDrawOp>(new (mem) TextureOp(set, cnt, filter, saturate, aaType,
constraint, viewMatrix,
std::move(textureColorSpaceXform)));
}
~TextureOp() override {
@ -263,13 +268,20 @@ private:
// dstQuad should be the geometry transformed by the view matrix. If domainRect
// is not null it will be used to apply the strict src rect constraint.
TextureOp(sk_sp<GrTextureProxy> proxy, sk_sp<GrColorSpaceXform> textureColorSpaceXform,
GrSamplerState::Filter filter, const SkPMColor4f& color,
GrAAType aaType, GrQuadAAFlags aaFlags,
const GrQuad& dstQuad, const GrQuad& srcQuad, const SkRect* domainRect)
TextureOp(sk_sp<GrTextureProxy> proxy,
sk_sp<GrColorSpaceXform> textureColorSpaceXform,
GrSamplerState::Filter filter,
const SkPMColor4f& color,
GrTextureOp::Saturate saturate,
GrAAType aaType,
GrQuadAAFlags aaFlags,
const GrQuad& dstQuad,
const GrQuad& srcQuad,
const SkRect* domainRect)
: INHERITED(ClassID())
, fQuads(1, true /* includes locals */)
, fTextureColorSpaceXform(std::move(textureColorSpaceXform))
, fSaturate(static_cast<unsigned>(saturate))
, fFilter(static_cast<unsigned>(filter)) {
// Clean up disparities between the overall aa type and edge configuration and apply
// optimizations based on the rect and matrix when appropriate
@ -295,13 +307,18 @@ private:
IsZeroArea::kNo);
fDomain = static_cast<unsigned>(domainRect != nullptr);
}
TextureOp(const GrRenderTargetContext::TextureSetEntry set[], int cnt,
GrSamplerState::Filter filter, GrAAType aaType,
SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix,
TextureOp(const GrRenderTargetContext::TextureSetEntry set[],
int cnt,
GrSamplerState::Filter filter,
GrTextureOp::Saturate saturate,
GrAAType aaType,
SkCanvas::SrcRectConstraint constraint,
const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> textureColorSpaceXform)
: INHERITED(ClassID())
, fQuads(cnt, true /* includes locals */)
, fTextureColorSpaceXform(std::move(textureColorSpaceXform))
, fSaturate(static_cast<unsigned>(saturate))
, fFilter(static_cast<unsigned>(filter)) {
fProxyCnt = SkToUInt(cnt);
SkRect bounds = SkRectPriv::MakeLargestInverted();
@ -454,9 +471,10 @@ private:
uint32_t extraSamplerKey = gpu->getExtraSamplerKeyForProgram(
samplerState, fProxies[0].fProxy->backendFormat());
auto saturate = static_cast<GrTextureOp::Saturate>(fSaturate);
sk_sp<GrGeometryProcessor> gp = GrQuadPerEdgeAA::MakeTexturedProcessor(
vertexSpec, *target->caps().shaderCaps(), textureType, samplerState, swizzle,
extraSamplerKey, std::move(fTextureColorSpaceXform));
extraSamplerKey, std::move(fTextureColorSpaceXform), saturate);
// We'll use a dynamic state array for the GP textures when there are multiple ops.
// Otherwise, we use fixed dynamic state to specify the single op's proxy.
@ -554,6 +572,9 @@ private:
}
upgradeToCoverageAAOnMerge = true;
}
if (fSaturate != that->fSaturate) {
return CombineResult::kCannotCombine;
}
if (fFilter != that->fFilter) {
return CombineResult::kCannotCombine;
}
@ -587,12 +608,13 @@ private:
GrQuadBuffer<ColorDomainAndAA> fQuads;
sk_sp<GrColorSpaceXform> fTextureColorSpaceXform;
unsigned fSaturate : 1;
unsigned fFilter : 2;
unsigned fAAType : 2;
unsigned fDomain : 1;
unsigned fColorType : 2;
GR_STATIC_ASSERT(GrQuadPerEdgeAA::kColorTypeCount <= 4);
unsigned fProxyCnt : 32 - 7;
unsigned fProxyCnt : 32 - 8;
Proxy fProxies[1];
static_assert(GrQuad::kTypeCount <= 4, "GrQuad::Type does not fit in 2 bits");
@ -609,6 +631,7 @@ std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
sk_sp<GrColorSpaceXform> textureXform,
GrSamplerState::Filter filter,
const SkPMColor4f& color,
Saturate saturate,
SkBlendMode blendMode,
GrAAType aaType,
GrQuadAAFlags aaFlags,
@ -627,7 +650,7 @@ std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
if (blendMode == SkBlendMode::kSrcOver) {
return TextureOp::Make(context, std::move(proxy), std::move(textureXform), filter, color,
aaType, aaFlags, deviceQuad, localQuad, domain);
saturate, aaType, aaFlags, deviceQuad, localQuad, domain);
} else {
// Emulate complex blending using GrFillRectOp
GrPaint paint;
@ -649,6 +672,9 @@ std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
}
fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(textureXform));
paint.addColorFragmentProcessor(std::move(fp));
if (saturate == GrTextureOp::Saturate::kYes) {
paint.addColorFragmentProcessor(GrSaturateProcessor::Make());
}
return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags,
deviceQuad, localQuad);
@ -659,11 +685,12 @@ std::unique_ptr<GrDrawOp> MakeSet(GrRecordingContext* context,
const GrRenderTargetContext::TextureSetEntry set[],
int cnt,
GrSamplerState::Filter filter,
Saturate saturate,
GrAAType aaType,
SkCanvas::SrcRectConstraint constraint,
const SkMatrix& viewMatrix,
sk_sp<GrColorSpaceXform> textureColorSpaceXform) {
return TextureOp::Make(context, set, cnt, filter, aaType, constraint, viewMatrix,
return TextureOp::Make(context, set, cnt, filter, saturate, aaType, constraint, viewMatrix,
std::move(textureColorSpaceXform));
}
@ -719,8 +746,9 @@ GR_DRAW_OP_TEST_DEFINE(TextureOp) {
aaFlags |= random->nextBool() ? GrQuadAAFlags::kRight : GrQuadAAFlags::kNone;
aaFlags |= random->nextBool() ? GrQuadAAFlags::kBottom : GrQuadAAFlags::kNone;
bool useDomain = random->nextBool();
auto saturate = random->nextBool() ? GrTextureOp::Saturate::kYes : GrTextureOp::Saturate::kNo;
return GrTextureOp::Make(context, std::move(proxy), std::move(texXform), filter, color,
SkBlendMode::kSrcOver, aaType, aaFlags,
saturate, SkBlendMode::kSrcOver, aaType, aaFlags,
GrQuad::MakeFromRect(rect, viewMatrix), GrQuad(srcRect),
useDomain ? &srcRect : nullptr);
}

View File

@ -22,6 +22,12 @@ class SkMatrix;
namespace GrTextureOp {
/**
* Controls whether saturate() is called after the texture is color-converted to ensure all
* color values are in 0..1 range.
*/
enum class Saturate : bool { kNo = false, kYes = true };
/**
* Creates an op that draws a sub-quadrilateral of a texture. The passed color is modulated by the
* texture's color. 'deviceQuad' specifies the device-space coordinates to draw, using 'localQuad'
@ -33,14 +39,15 @@ namespace GrTextureOp {
* deconstructed into the texture, filter, modulating color, and blend mode. When blend mode is
* src over, this will return a GrFillRectOp with a paint that samples the proxy.
*/
std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
sk_sp<GrTextureProxy> proxy,
sk_sp<GrColorSpaceXform> textureXform,
GrSamplerState::Filter filter,
const SkPMColor4f& color,
SkBlendMode blendMode,
GrAAType aaType,
GrQuadAAFlags aaFlags,
std::unique_ptr<GrDrawOp> Make(GrRecordingContext*,
sk_sp<GrTextureProxy>,
sk_sp<GrColorSpaceXform>,
GrSamplerState::Filter,
const SkPMColor4f&,
Saturate,
SkBlendMode,
GrAAType,
GrQuadAAFlags,
const GrQuad& deviceQuad,
const GrQuad& localQuad,
const SkRect* domain = nullptr);
@ -50,6 +57,7 @@ std::unique_ptr<GrDrawOp> MakeSet(GrRecordingContext*,
const GrRenderTargetContext::TextureSetEntry[],
int cnt,
GrSamplerState::Filter,
Saturate,
GrAAType,
SkCanvas::SrcRectConstraint,
const SkMatrix& viewMatrix,