diff options
Diffstat (limited to 'src/shaders')
-rw-r--r-- | src/shaders/gradients/Sk4fGradientBase.cpp | 47 | ||||
-rw-r--r-- | src/shaders/gradients/SkGradientShader.cpp | 167 | ||||
-rw-r--r-- | src/shaders/gradients/SkGradientShaderPriv.h | 57 | ||||
-rw-r--r-- | src/shaders/gradients/SkLinearGradient.cpp | 2 | ||||
-rw-r--r-- | src/shaders/gradients/SkRadialGradient.cpp | 2 | ||||
-rw-r--r-- | src/shaders/gradients/SkSweepGradient.cpp | 2 | ||||
-rw-r--r-- | src/shaders/gradients/SkTwoPointConicalGradient.cpp | 2 | ||||
-rw-r--r-- | src/shaders/gradients/SkTwoPointConicalGradient_gpu.cpp | 2 |
8 files changed, 130 insertions, 151 deletions
diff --git a/src/shaders/gradients/Sk4fGradientBase.cpp b/src/shaders/gradients/Sk4fGradientBase.cpp index 19eabcfd91..0f6da52d1a 100644 --- a/src/shaders/gradients/Sk4fGradientBase.cpp +++ b/src/shaders/gradients/Sk4fGradientBase.cpp @@ -21,19 +21,19 @@ Sk4f pack_color(const SkColor4f& c4f, bool premul, const Sk4f& component_scale) class IntervalIterator { public: - IntervalIterator(const SkGradientShaderBase& shader, SkColorSpace* dstCS, bool reverse) + IntervalIterator(const SkGradientShaderBase& shader, bool reverse) : fShader(shader) - , fDstCS(dstCS) , fFirstPos(reverse ? SK_Scalar1 : 0) , fBegin(reverse ? shader.fColorCount - 1 : 0) , fAdvance(reverse ? -1 : 1) { SkASSERT(shader.fColorCount > 0); } - void iterate(std::function<void(const SkColor4f&, const SkColor4f&, + void iterate(const SkColor4f* colors, + std::function<void(const SkColor4f&, const SkColor4f&, SkScalar, SkScalar)> func) const { if (!fShader.fOrigPos) { - this->iterateImplicitPos(func); + this->iterateImplicitPos(colors, func); return; } @@ -48,8 +48,7 @@ public: const SkScalar currPos = fShader.fOrigPos[curr]; if (currPos != prevPos) { SkASSERT((currPos - prevPos > 0) == (fAdvance > 0)); - func(fShader.getXformedColor(prev, fDstCS), fShader.getXformedColor(curr, fDstCS), - prevPos, currPos); + func(colors[prev], colors[curr], prevPos, currPos); } prev = curr; @@ -58,7 +57,8 @@ public: } private: - void iterateImplicitPos(std::function<void(const SkColor4f&, const SkColor4f&, + void iterateImplicitPos(const SkColor4f* colors, + std::function<void(const SkColor4f&, const SkColor4f&, SkScalar, SkScalar)> func) const { // When clients don't provide explicit color stop positions (fPos == nullptr), // the color stops are distributed evenly across the unit interval @@ -73,33 +73,28 @@ private: SkASSERT(curr >= 0 && curr < fShader.fColorCount); const SkScalar currPos = prevPos + dt; - func(fShader.getXformedColor(prev, fDstCS), - fShader.getXformedColor(curr, fDstCS), - prevPos, currPos); + func(colors[prev], colors[curr], prevPos, currPos); prev = curr; prevPos = currPos; } // emit the last interval with a pinned end position, to avoid precision issues - func(fShader.getXformedColor(prev, fDstCS), - fShader.getXformedColor(prev + fAdvance, fDstCS), - prevPos, 1 - fFirstPos); + func(colors[prev], colors[prev + fAdvance], prevPos, 1 - fFirstPos); } const SkGradientShaderBase& fShader; - SkColorSpace* fDstCS; const SkScalar fFirstPos; const int fBegin; const int fAdvance; }; void addMirrorIntervals(const SkGradientShaderBase& shader, - SkColorSpace* dstCS, + const SkColor4f* colors, const Sk4f& componentScale, bool premulColors, bool reverse, Sk4fGradientIntervalBuffer::BufferType* buffer) { - const IntervalIterator iter(shader, dstCS, reverse); - iter.iterate([&] (const SkColor4f& c0, const SkColor4f& c1, SkScalar t0, SkScalar t1) { + const IntervalIterator iter(shader, reverse); + iter.iterate(colors, [&] (const SkColor4f& c0, const SkColor4f& c1, SkScalar t0, SkScalar t1) { SkASSERT(buffer->empty() || buffer->back().fT1 == 2 - t0); const auto mirror_t0 = 2 - t0; @@ -193,20 +188,25 @@ void Sk4fGradientIntervalBuffer::init(const SkGradientShaderBase& shader, SkColo const SkScalar first_pos = reverse ? SK_Scalar1 : 0; const SkScalar last_pos = SK_Scalar1 - first_pos; + // Transform all of the colors to destination color space + SkColor4fXformer xformedColors(shader.fOrigColors4f, count, shader.fColorSpace.get(), dstCS); + if (tileMode == SkShader::kClamp_TileMode) { // synthetic edge interval: -/+inf .. P0 - const Sk4f clamp_color = pack_color(shader.getXformedColor(first_index, dstCS), + const Sk4f clamp_color = pack_color(xformedColors.fColors[first_index], premulColors, componentScale); const SkScalar clamp_pos = reverse ? SK_ScalarInfinity : SK_ScalarNegativeInfinity; fIntervals.emplace_back(clamp_color, clamp_pos, clamp_color, first_pos); } else if (tileMode == SkShader::kMirror_TileMode && reverse) { // synthetic mirror intervals injected before main intervals: (2 .. 1] - addMirrorIntervals(shader, dstCS, componentScale, premulColors, false, &fIntervals); + addMirrorIntervals(shader, xformedColors.fColors, componentScale, premulColors, false, + &fIntervals); } - const IntervalIterator iter(shader, dstCS, reverse); - iter.iterate([&] (const SkColor4f& c0, const SkColor4f& c1, SkScalar t0, SkScalar t1) { + const IntervalIterator iter(shader, reverse); + iter.iterate(xformedColors.fColors, + [&] (const SkColor4f& c0, const SkColor4f& c1, SkScalar t0, SkScalar t1) { SkASSERT(fIntervals.empty() || fIntervals.back().fT1 == t0); fIntervals.emplace_back(pack_color(c0, premulColors, componentScale), t0, @@ -215,14 +215,15 @@ void Sk4fGradientIntervalBuffer::init(const SkGradientShaderBase& shader, SkColo if (tileMode == SkShader::kClamp_TileMode) { // synthetic edge interval: Pn .. +/-inf - const Sk4f clamp_color = pack_color(shader.getXformedColor(last_index, dstCS), + const Sk4f clamp_color = pack_color(xformedColors.fColors[last_index], premulColors, componentScale); const SkScalar clamp_pos = reverse ? SK_ScalarNegativeInfinity : SK_ScalarInfinity; fIntervals.emplace_back(clamp_color, last_pos, clamp_color, clamp_pos); } else if (tileMode == SkShader::kMirror_TileMode && !reverse) { // synthetic mirror intervals injected after main intervals: [1 .. 2) - addMirrorIntervals(shader, dstCS, componentScale, premulColors, true, &fIntervals); + addMirrorIntervals(shader, xformedColors.fColors, componentScale, premulColors, true, + &fIntervals); } } diff --git a/src/shaders/gradients/SkGradientShader.cpp b/src/shaders/gradients/SkGradientShader.cpp index cfcd335f42..fd97bc8925 100644 --- a/src/shaders/gradients/SkGradientShader.cpp +++ b/src/shaders/gradients/SkGradientShader.cpp @@ -22,7 +22,7 @@ #include "SkTwoPointConicalGradient.h" #include "SkWriteBuffer.h" #include "../../jumper/SkJumper.h" - +#include "../../third_party/skcms/skcms.h" enum GradientSerializationFlags { // Bits 29:31 used for various boolean flags @@ -126,7 +126,7 @@ bool SkGradientShaderBase::DescriptorScope::unflatten(SkReadBuffer& buffer) { SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit) : INHERITED(desc.fLocalMatrix) , fPtsToUnit(ptsToUnit) - , fColorSpace(desc.fColorSpace ? desc.fColorSpace : SkColorSpace::MakeSRGBLinear()) + , fColorSpace(desc.fColorSpace ? desc.fColorSpace : SkColorSpace::MakeSRGB()) , fColorsAreOpaque(true) { fPtsToUnit.getType(); // Precache so reads are threadsafe. @@ -277,7 +277,6 @@ static void init_stop_pos( bool SkGradientShaderBase::onAppendStages(const StageRec& rec) const { SkRasterPipeline* p = rec.fPipeline; SkArenaAlloc* alloc = rec.fAlloc; - SkColorSpace* dstCS = rec.fDstCS; SkJumper_DecalTileCtx* decal_ctx = nullptr; SkMatrix matrix; @@ -313,8 +312,12 @@ bool SkGradientShaderBase::onAppendStages(const StageRec& rec) const { } const bool premulGrad = fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag; - auto prepareColor = [premulGrad, dstCS, this](int i) { - SkColor4f c = this->getXformedColor(i, dstCS); + + // Transform all of the colors to destination color space + SkColor4fXformer xformedColors(fOrigColors4f, fColorCount, fColorSpace.get(), rec.fDstCS); + + auto prepareColor = [premulGrad, &xformedColors](int i) { + SkColor4f c = xformedColors.fColors[i]; return premulGrad ? c.premul() : SkPM4f::From4f(Sk4f::Load(&c)); }; @@ -454,9 +457,37 @@ SkGradientShaderBase::AutoXformColors::AutoXformColors(const SkGradientShaderBas xformer->apply(fColors.get(), origColors.get(), grad.fColorCount); } +SkColor4fXformer::SkColor4fXformer(const SkColor4f* colors, int colorCount, + SkColorSpace* src, SkColorSpace* dst) { + // Transform all of the colors to destination color space + fColors = colors; + if (!dst) { + return; + } + + // Treat null sources as sRGB (safe because sRGB is a global singleton) + if (!src) { + src = SkColorSpace::MakeSRGB().get(); + } + + if (!SkColorSpace::Equals(src, dst)) { + skcms_ICCProfile srcProfile, dstProfile; + src->toProfile(&srcProfile); + dst->toProfile(&dstProfile); + fStorage.reset(colorCount); + const skcms_PixelFormat rgba_f32 = skcms_PixelFormat_RGBA_ffff; + const skcms_AlphaFormat unpremul = skcms_AlphaFormat_Unpremul; + SkAssertResult(skcms_Transform(colors, rgba_f32, unpremul, &srcProfile, + fStorage.begin(), rgba_f32, unpremul, &dstProfile, + colorCount)); + fColors = fStorage.begin(); + } +} + static constexpr int kGradientTextureSize = 256; -void SkGradientShaderBase::initLinearBitmap(SkBitmap* bitmap, GradientBitmapType bitmapType) const { +void SkGradientShaderBase::initLinearBitmap(const SkColor4f* colors, SkBitmap* bitmap, + SkColorType colorType) const { const bool interpInPremul = SkToBool(fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag); SkHalf* pixelsF16 = reinterpret_cast<SkHalf*>(bitmap->getPixels()); @@ -471,26 +502,18 @@ void SkGradientShaderBase::initLinearBitmap(SkBitmap* bitmap, GradientBitmapType pixelsF16[4*index+2] = c[2]; pixelsF16[4*index+3] = c[3]; }; - pixelWriteFn_t writeS32Pixel = [&](const Sk4f& c, int index) { - pixels32[index] = Sk4f_toS32(c); - }; - pixelWriteFn_t writeL32Pixel = [&](const Sk4f& c, int index) { + pixelWriteFn_t write8888Pixel = [&](const Sk4f& c, int index) { pixels32[index] = Sk4f_toL32(c); }; pixelWriteFn_t writeSizedPixel = - (bitmapType == GradientBitmapType::kHalfFloat) ? writeF16Pixel : - (bitmapType == GradientBitmapType::kSRGB ) ? writeS32Pixel : writeL32Pixel; + (colorType == kRGBA_F16_SkColorType) ? writeF16Pixel : write8888Pixel; pixelWriteFn_t writeUnpremulPixel = [&](const Sk4f& c, int index) { writeSizedPixel(c * Sk4f(c[3], c[3], c[3], 1.0f), index); }; pixelWriteFn_t writePixel = interpInPremul ? writeSizedPixel : writeUnpremulPixel; - // When not in legacy mode, we just want the original 4f colors - so we pass in - // our own CS for identity/no transform. - auto* cs = bitmapType != GradientBitmapType::kLegacy ? fColorSpace.get() : nullptr; - int prevIndex = 0; for (int i = 1; i < fColorCount; i++) { // Historically, stops have been mapped to [0, 256], with 256 then nudged to the @@ -500,10 +523,8 @@ void SkGradientShaderBase::initLinearBitmap(SkBitmap* bitmap, GradientBitmapType SkIntToScalar(kGradientTextureSize - 1)); if (nextIndex > prevIndex) { - SkColor4f color0 = this->getXformedColor(i - 1, cs), - color1 = this->getXformedColor(i , cs); - Sk4f c0 = Sk4f::Load(color0.vec()), - c1 = Sk4f::Load(color1.vec()); + Sk4f c0 = Sk4f::Load(colors[i - 1].vec()), + c1 = Sk4f::Load(colors[i ].vec()); if (interpInPremul) { c0 = c0 * Sk4f(c0[3], c0[3], c0[3], 1.0f); @@ -523,18 +544,6 @@ void SkGradientShaderBase::initLinearBitmap(SkBitmap* bitmap, GradientBitmapType SkASSERT(prevIndex == kGradientTextureSize - 1); } -SkColor4f SkGradientShaderBase::getXformedColor(size_t i, SkColorSpace* dstCS) const { - if (dstCS) { - return to_colorspace(fOrigColors4f[i], fColorSpace.get(), dstCS); - } - - // Legacy/srgb color. - // We quantize upfront to ensure stable SkColor round-trips. - auto rgb255 = sk_linear_to_srgb(Sk4f::Load(fOrigColors4f[i].vec())); - auto rgb = SkNx_cast<float>(rgb255) * (1/255.0f); - return { rgb[0], rgb[1], rgb[2], fOrigColors4f[i].fA }; -} - SK_DECLARE_STATIC_MUTEX(gGradientCacheMutex); /* * Because our caller might rebuild the same (logically the same) gradient @@ -543,8 +552,8 @@ SK_DECLARE_STATIC_MUTEX(gGradientCacheMutex); * To do that, we maintain a private cache of built-bitmaps, based on our * colors and positions. */ -void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap, - GradientBitmapType bitmapType) const { +void SkGradientShaderBase::getGradientTableBitmap(const SkColor4f* colors, SkBitmap* bitmap, + SkColorType colorType) const { // build our key: [numColors + colors[] + {positions[]} + flags + colorType ] static_assert(sizeof(SkColor4f) % sizeof(int32_t) == 0, ""); const int colorsAsIntCount = fColorCount * sizeof(SkColor4f) / sizeof(int32_t); @@ -557,7 +566,7 @@ void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap, int32_t* buffer = storage.get(); *buffer++ = fColorCount; - memcpy(buffer, fOrigColors4f, fColorCount * sizeof(SkColor4f)); + memcpy(buffer, colors, fColorCount * sizeof(SkColor4f)); buffer += colorsAsIntCount; if (fColorCount > 2) { for (int i = 1; i < fColorCount; i++) { @@ -565,13 +574,13 @@ void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap, } } *buffer++ = fGradFlags; - *buffer++ = static_cast<int32_t>(bitmapType); + *buffer++ = static_cast<int32_t>(colorType); SkASSERT(buffer - storage.get() == count); /////////////////////////////////// static SkGradientBitmapCache* gCache; - // each cache cost 1K or 2K of RAM, since each bitmap will be 1x256 at either 32bpp or 64bpp + // Each cache entry costs 1K or 2K of RAM. Each bitmap will be 1x256 at either 32bpp or 64bpp. static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32; SkAutoMutexAcquire ama(gGradientCacheMutex); @@ -581,27 +590,10 @@ void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap, size_t size = count * sizeof(int32_t); if (!gCache->find(storage.get(), size, bitmap)) { - // For these cases we use the bitmap cache, but not the GradientShaderCache. So just - // allocate and populate the bitmap's data directly. - - SkImageInfo info; - switch (bitmapType) { - case GradientBitmapType::kLegacy: - info = SkImageInfo::Make(kGradientTextureSize, 1, kRGBA_8888_SkColorType, - kPremul_SkAlphaType); - break; - case GradientBitmapType::kSRGB: - info = SkImageInfo::Make(kGradientTextureSize, 1, kRGBA_8888_SkColorType, - kPremul_SkAlphaType, SkColorSpace::MakeSRGB()); - break; - case GradientBitmapType::kHalfFloat: - info = SkImageInfo::Make(kGradientTextureSize, 1, kRGBA_F16_SkColorType, - kPremul_SkAlphaType, SkColorSpace::MakeSRGBLinear()); - break; - } - + SkImageInfo info = SkImageInfo::Make(kGradientTextureSize, 1, colorType, + kPremul_SkAlphaType); bitmap->allocPixels(info); - this->initLinearBitmap(bitmap, bitmapType); + this->initLinearBitmap(colors, bitmap, colorType); bitmap->setImmutable(); gCache->add(storage.get(), size, *bitmap); } @@ -709,8 +701,13 @@ struct ColorStopOptimizer { struct ColorConverter { ColorConverter(const SkColor* colors, int count) { + const float ONE_OVER_255 = 1.f / 255; for (int i = 0; i < count; ++i) { - fColors4f.push_back(SkColor4f::FromColor(colors[i])); + fColors4f.push_back({ + SkColorGetR(colors[i]) * ONE_OVER_255, + SkColorGetG(colors[i]) * ONE_OVER_255, + SkColorGetB(colors[i]) * ONE_OVER_255, + SkColorGetA(colors[i]) * ONE_OVER_255 }); } } @@ -1127,11 +1124,11 @@ inline GrFragmentProcessor::OptimizationFlags GrGradientEffect::OptFlags(bool is : kCompatibleWithCoverageAsAlpha_OptimizationFlag; } -void GrGradientEffect::addInterval(const SkGradientShaderBase& shader, size_t idx0, size_t idx1, - SkColorSpace* dstCS) { +void GrGradientEffect::addInterval(const SkGradientShaderBase& shader, const SkColor4f* colors, + size_t idx0, size_t idx1) { SkASSERT(idx0 <= idx1); - const auto c4f0 = shader.getXformedColor(idx0, dstCS), - c4f1 = shader.getXformedColor(idx1, dstCS); + const auto c4f0 = colors[idx0], + c4f1 = colors[idx1]; const auto c0 = (fPremulType == kBeforeInterp_PremulType) ? c4f0.premul().to4f() : Sk4f::Load(c4f0.vec()), c1 = (fPremulType == kBeforeInterp_PremulType) @@ -1163,12 +1160,16 @@ GrGradientEffect::GrGradientEffect(ClassID classID, const CreateArgs& args, bool fPremulType = (args.fShader->getGradFlags() & SkGradientShader::kInterpolateColorsInPremul_Flag) ? kBeforeInterp_PremulType : kAfterInterp_PremulType; + // Transform all of the colors to destination color space + SkColor4fXformer xformedColors(shader.fOrigColors4f, shader.fColorCount, + shader.fColorSpace.get(), args.fDstColorSpaceInfo->colorSpace()); + // First, determine the interpolation strategy and params. switch (shader.fColorCount) { case 2: SkASSERT(!shader.fOrigPos); fStrategy = InterpolationStrategy::kSingle; - this->addInterval(shader, 0, 1, args.fDstColorSpace); + this->addInterval(shader, xformedColors.fColors, 0, 1); break; case 3: fThreshold = shader.getPos(1); @@ -1181,22 +1182,22 @@ GrGradientEffect::GrGradientEffect(ClassID classID, const CreateArgs& args, bool if (fWrapMode == GrSamplerState::WrapMode::kClamp) { fStrategy = InterpolationStrategy::kThresholdClamp1; // Clamp interval (scale == 0, bias == colors[0]). - this->addInterval(shader, 0, 0, args.fDstColorSpace); + this->addInterval(shader, xformedColors.fColors, 0, 0); } else { // We can ignore the hard stop when not clamping. fStrategy = InterpolationStrategy::kSingle; } - this->addInterval(shader, 1, 2, args.fDstColorSpace); + this->addInterval(shader, xformedColors.fColors, 1, 2); break; } if (SkScalarNearlyEqual(shader.fOrigPos[1], 1)) { // hard stop on the right edge. - this->addInterval(shader, 0, 1, args.fDstColorSpace); + this->addInterval(shader, xformedColors.fColors, 0, 1); if (fWrapMode == GrSamplerState::WrapMode::kClamp) { fStrategy = InterpolationStrategy::kThresholdClamp0; // Clamp interval (scale == 0, bias == colors[2]). - this->addInterval(shader, 2, 2, args.fDstColorSpace); + this->addInterval(shader, xformedColors.fColors, 2, 2); } else { // We can ignore the hard stop when not clamping. fStrategy = InterpolationStrategy::kSingle; @@ -1207,8 +1208,8 @@ GrGradientEffect::GrGradientEffect(ClassID classID, const CreateArgs& args, bool // Two arbitrary interpolation intervals. fStrategy = InterpolationStrategy::kThreshold; - this->addInterval(shader, 0, 1, args.fDstColorSpace); - this->addInterval(shader, 1, 2, args.fDstColorSpace); + this->addInterval(shader, xformedColors.fColors, 0, 1); + this->addInterval(shader, xformedColors.fColors, 1, 2); break; case 4: if (shader.fOrigPos && SkScalarNearlyEqual(shader.fOrigPos[1], shader.fOrigPos[2])) { @@ -1218,8 +1219,8 @@ GrGradientEffect::GrGradientEffect(ClassID classID, const CreateArgs& args, bool // Single hard stop => two arbitrary interpolation intervals. fStrategy = InterpolationStrategy::kThreshold; fThreshold = shader.getPos(1); - this->addInterval(shader, 0, 1, args.fDstColorSpace); - this->addInterval(shader, 2, 3, args.fDstColorSpace); + this->addInterval(shader, xformedColors.fColors, 0, 1); + this->addInterval(shader, xformedColors.fColors, 2, 3); } break; default: @@ -1231,23 +1232,16 @@ GrGradientEffect::GrGradientEffect(ClassID classID, const CreateArgs& args, bool // Analytical cases. fCoordTransform.reset(*args.fMatrix); } else { - SkGradientShaderBase::GradientBitmapType bitmapType = - SkGradientShaderBase::GradientBitmapType::kLegacy; - auto caps = args.fContext->contextPriv().caps(); - if (args.fDstColorSpace) { - // Try to use F16 if we can - if (caps->isConfigTexturable(kRGBA_half_GrPixelConfig)) { - bitmapType = SkGradientShaderBase::GradientBitmapType::kHalfFloat; - } else if (caps->isConfigTexturable(kSRGBA_8888_GrPixelConfig)) { - bitmapType = SkGradientShaderBase::GradientBitmapType::kSRGB; - } else { - // This can happen, but only if someone explicitly creates an unsupported - // (eg sRGB) surface. Just fall back to legacy behavior. - } + // Use 8888 or F16, depending on the destination config. + // TODO: Use 1010102 for opaque gradients, at least if destination is 1010102? + SkColorType colorType = kRGBA_8888_SkColorType; + if (kLow_GrSLPrecision != GrSLSamplerPrecision(args.fDstColorSpaceInfo->config()) && + args.fContext->contextPriv().caps()->isConfigTexturable(kRGBA_half_GrPixelConfig)) { + colorType = kRGBA_F16_SkColorType; } SkBitmap bitmap; - shader.getGradientTableBitmap(&bitmap, bitmapType); + shader.getGradientTableBitmap(xformedColors.fColors, &bitmap, colorType); SkASSERT(1 == bitmap.height() && SkIsPow2(bitmap.width())); auto atlasManager = args.fContext->contextPriv().textureStripAtlasManager(); @@ -1371,9 +1365,6 @@ GrGradientEffect::RandomGradientParams::RandomGradientParams(SkRandom* random) { // if using SkColor4f, attach a random (possibly null) color space (with linear gamma) if (fUseColors4f) { fColorSpace = GrTest::TestColorSpace(random); - if (fColorSpace) { - fColorSpace = fColorSpace->makeLinearGamma(); - } } SkScalar stop = 0.f; diff --git a/src/shaders/gradients/SkGradientShaderPriv.h b/src/shaders/gradients/SkGradientShaderPriv.h index 9a565a8d4a..0f3e73603a 100644 --- a/src/shaders/gradients/SkGradientShaderPriv.h +++ b/src/shaders/gradients/SkGradientShaderPriv.h @@ -12,6 +12,7 @@ #include "SkArenaAlloc.h" #include "SkMatrix.h" +#include "SkPM4fPriv.h" #include "SkShaderBase.h" #include "SkTArray.h" #include "SkTemplates.h" @@ -63,18 +64,10 @@ public: bool isOpaque() const override; - enum class GradientBitmapType : uint8_t { - kLegacy, - kSRGB, - kHalfFloat, - }; - - void getGradientTableBitmap(SkBitmap*, GradientBitmapType bitmapType) const; + void getGradientTableBitmap(const SkColor4f* colors, SkBitmap*, SkColorType) const; uint32_t getGradFlags() const { return fGradFlags; } - SkColor4f getXformedColor(size_t index, SkColorSpace*) const; - protected: class GradientShaderBase4fContext; @@ -85,7 +78,7 @@ protected: bool onAsLuminanceColor(SkColor*) const override; - void initLinearBitmap(SkBitmap* bitmap, GradientBitmapType) const; + void initLinearBitmap(const SkColor4f* colors, SkBitmap* bitmap, SkColorType colorType) const; bool onAppendStages(const StageRec&) const override; @@ -119,7 +112,7 @@ public: SkColor getLegacyColor(int i) const { SkASSERT(i < fColorCount); - return fOrigColors4f[i].toSkColor(); + return Sk4f_toL32(swizzle_rb(Sk4f::Load(fOrigColors4f[i].vec()))); } SkColor4f* fOrigColors4f; // original colors, as linear floats @@ -145,6 +138,15 @@ private: /////////////////////////////////////////////////////////////////////////////// +struct SkColor4fXformer { + SkColor4fXformer(const SkColor4f* colors, int colorCount, SkColorSpace* src, SkColorSpace* dst); + + const SkColor4f* fColors; + SkSTArray<4, SkColor4f, true> fStorage; +}; + +/////////////////////////////////////////////////////////////////////////////// + #if SK_SUPPORT_GPU #include "GrColorSpaceInfo.h" @@ -188,11 +190,11 @@ public: const SkGradientShaderBase* shader, const SkMatrix* matrix, SkShader::TileMode tileMode, - SkColorSpace* dstColorSpace) + const GrColorSpaceInfo* dstColorSpaceInfo) : fContext(context) , fShader(shader) , fMatrix(matrix) - , fDstColorSpace(dstColorSpace) { + , fDstColorSpaceInfo(dstColorSpaceInfo) { switch (tileMode) { case SkShader::kClamp_TileMode: fWrapMode = GrSamplerState::WrapMode::kClamp; @@ -214,18 +216,18 @@ public: const SkGradientShaderBase* shader, const SkMatrix* matrix, GrSamplerState::WrapMode wrapMode, - SkColorSpace* dstColorSpace) + const GrColorSpaceInfo* dstColorSpaceInfo) : fContext(context) , fShader(shader) , fMatrix(matrix) , fWrapMode(wrapMode) - , fDstColorSpace(dstColorSpace) {} + , fDstColorSpaceInfo(dstColorSpaceInfo) {} GrContext* fContext; const SkGradientShaderBase* fShader; const SkMatrix* fMatrix; GrSamplerState::WrapMode fWrapMode; - SkColorSpace* fDstColorSpace; + const GrColorSpaceInfo* fDstColorSpaceInfo; }; class GLSLProcessor; @@ -255,29 +257,13 @@ protected: void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; - // Helper function used by derived class factories to handle color space transformation and - // modulation by input alpha. + // Helper function used by derived class factories to handle modulation by input alpha. static std::unique_ptr<GrFragmentProcessor> AdjustFP( std::unique_ptr<GrGradientEffect> gradientFP, const CreateArgs& args) { if (!gradientFP->isValid()) { return nullptr; } - std::unique_ptr<GrFragmentProcessor> fp; - // With analytic gradients, we pre-convert the stops to the destination color space, so no - // xform is needed. With texture-based gradients, we leave the data in the source color - // space (to avoid clamping if we can't use F16)... Add an extra FP to do the xform. - if (gradientFP->fStrategy == InterpolationStrategy::kTexture) { - // Our texture is always either F16 or sRGB, so the data is "linear" in the shader. - // Create our xform assuming float inputs, which will suppress any extra sRGB work. - // We do support having a transfer function on the color space of the stops, so - // this FP may include that transformation. - fp = GrColorSpaceXformEffect::Make(std::move(gradientFP), - args.fShader->fColorSpace.get(), - args.fDstColorSpace); - } else { - fp = std::move(gradientFP); - } - return GrFragmentProcessor::MulChildByInputAlpha(std::move(fp)); + return GrFragmentProcessor::MulChildByInputAlpha(std::move(gradientFP)); } #if GR_TEST_UTILS @@ -313,7 +299,8 @@ protected: } private: - void addInterval(const SkGradientShaderBase&, size_t idx0, size_t idx1, SkColorSpace*); + void addInterval(const SkGradientShaderBase&, const SkColor4f* colors, + size_t idx0, size_t idx1); static OptimizationFlags OptFlags(bool isOpaque); diff --git a/src/shaders/gradients/SkLinearGradient.cpp b/src/shaders/gradients/SkLinearGradient.cpp index 34cac269f5..9ad768b270 100644 --- a/src/shaders/gradients/SkLinearGradient.cpp +++ b/src/shaders/gradients/SkLinearGradient.cpp @@ -201,7 +201,7 @@ std::unique_ptr<GrFragmentProcessor> SkLinearGradient::asFragmentProcessor( matrix.postConcat(fPtsToUnit); return GrLinearGradient::Make(GrGradientEffect::CreateArgs( - args.fContext, this, &matrix, fTileMode, args.fDstColorSpaceInfo->colorSpace())); + args.fContext, this, &matrix, fTileMode, args.fDstColorSpaceInfo)); } diff --git a/src/shaders/gradients/SkRadialGradient.cpp b/src/shaders/gradients/SkRadialGradient.cpp index ec0f8a0f95..70edb65c6d 100644 --- a/src/shaders/gradients/SkRadialGradient.cpp +++ b/src/shaders/gradients/SkRadialGradient.cpp @@ -169,7 +169,7 @@ std::unique_ptr<GrFragmentProcessor> SkRadialGradient::asFragmentProcessor( matrix.postConcat(fPtsToUnit); return GrRadialGradient::Make(GrGradientEffect::CreateArgs( - args.fContext, this, &matrix, fTileMode, args.fDstColorSpaceInfo->colorSpace())); + args.fContext, this, &matrix, fTileMode, args.fDstColorSpaceInfo)); } #endif diff --git a/src/shaders/gradients/SkSweepGradient.cpp b/src/shaders/gradients/SkSweepGradient.cpp index cfce5fe025..89c5cb162c 100644 --- a/src/shaders/gradients/SkSweepGradient.cpp +++ b/src/shaders/gradients/SkSweepGradient.cpp @@ -224,7 +224,7 @@ std::unique_ptr<GrFragmentProcessor> SkSweepGradient::asFragmentProcessor( return GrSweepGradient::Make( GrGradientEffect::CreateArgs(args.fContext, this, &matrix, fTileMode, - args.fDstColorSpaceInfo->colorSpace()), + args.fDstColorSpaceInfo), fTBias, fTScale); } diff --git a/src/shaders/gradients/SkTwoPointConicalGradient.cpp b/src/shaders/gradients/SkTwoPointConicalGradient.cpp index 5739a8003a..1bc6a9b8bc 100644 --- a/src/shaders/gradients/SkTwoPointConicalGradient.cpp +++ b/src/shaders/gradients/SkTwoPointConicalGradient.cpp @@ -190,7 +190,7 @@ std::unique_ptr<GrFragmentProcessor> SkTwoPointConicalGradient::asFragmentProces return Gr2PtConicalGradientEffect::Make( GrGradientEffect::CreateArgs(args.fContext, this, &matrix, fTileMode, - args.fDstColorSpaceInfo->colorSpace())); + args.fDstColorSpaceInfo)); } #endif diff --git a/src/shaders/gradients/SkTwoPointConicalGradient_gpu.cpp b/src/shaders/gradients/SkTwoPointConicalGradient_gpu.cpp index 9d447785ed..c346f35327 100644 --- a/src/shaders/gradients/SkTwoPointConicalGradient_gpu.cpp +++ b/src/shaders/gradients/SkTwoPointConicalGradient_gpu.cpp @@ -390,7 +390,7 @@ std::unique_ptr<GrFragmentProcessor> Gr2PtConicalGradientEffect::Make( SkMatrix matrix = *args.fMatrix; GrGradientEffect::CreateArgs newArgs(args.fContext, args.fShader, &matrix, args.fWrapMode, - args.fDstColorSpace); + args.fDstColorSpaceInfo); // Data and matrix has to be prepared before constructing TwoPointConicalEffect so its parent // class can have the right matrix to work with during construction. TwoPointConicalEffect::Data data(shader, matrix); |